-
-
Notifications
You must be signed in to change notification settings - Fork 232
/
DistanceOp.js
231 lines (230 loc) · 10.1 KB
/
DistanceOp.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
import LineString from '../../geom/LineString.js'
import hasInterface from '../../../../../hasInterface.js'
import Polygon from '../../geom/Polygon.js'
import GeometryLocation from './GeometryLocation.js'
import LinearComponentExtracter from '../../geom/util/LinearComponentExtracter.js'
import Distance from '../../algorithm/Distance.js'
import PointLocator from '../../algorithm/PointLocator.js'
import PolygonExtracter from '../../geom/util/PolygonExtracter.js'
import Location from '../../geom/Location.js'
import IllegalArgumentException from '../../../../../java/lang/IllegalArgumentException.js'
import Point from '../../geom/Point.js'
import Double from '../../../../../java/lang/Double.js'
import PointExtracter from '../../geom/util/PointExtracter.js'
import ConnectedElementLocationFilter from './ConnectedElementLocationFilter.js'
import LineSegment from '../../geom/LineSegment.js'
import Envelope from '../../geom/Envelope.js'
import List from '../../../../../java/util/List.js'
export default class DistanceOp {
constructor() {
DistanceOp.constructor_.apply(this, arguments)
}
static constructor_() {
this._geom = null
this._terminateDistance = 0.0
this._ptLocator = new PointLocator()
this._minDistanceLocation = null
this._minDistance = Double.MAX_VALUE
if (arguments.length === 2) {
const g0 = arguments[0], g1 = arguments[1]
DistanceOp.constructor_.call(this, g0, g1, 0.0)
} else if (arguments.length === 3) {
const g0 = arguments[0], g1 = arguments[1], terminateDistance = arguments[2]
this._geom = new Array(2).fill(null)
this._geom[0] = g0
this._geom[1] = g1
this._terminateDistance = terminateDistance
}
}
static distance(g0, g1) {
const distOp = new DistanceOp(g0, g1)
return distOp.distance()
}
static isWithinDistance(g0, g1, distance) {
const envDist = g0.getEnvelopeInternal().distance(g1.getEnvelopeInternal())
if (envDist > distance) return false
const distOp = new DistanceOp(g0, g1, distance)
return distOp.distance() <= distance
}
static nearestPoints(g0, g1) {
const distOp = new DistanceOp(g0, g1)
return distOp.nearestPoints()
}
computeContainmentDistance() {
if (arguments.length === 0) {
const locPtPoly = new Array(2).fill(null)
this.computeContainmentDistance(0, locPtPoly)
if (this._minDistance <= this._terminateDistance) return null
this.computeContainmentDistance(1, locPtPoly)
} else if (arguments.length === 2) {
const polyGeomIndex = arguments[0], locPtPoly = arguments[1]
const polyGeom = this._geom[polyGeomIndex]
if (polyGeom.getDimension() < 2) return null
const locationsIndex = 1 - polyGeomIndex
const polys = PolygonExtracter.getPolygons(polyGeom)
if (polys.size() > 0) {
const insideLocs = ConnectedElementLocationFilter.getLocations(this._geom[locationsIndex])
this.computeContainmentDistance(insideLocs, polys, locPtPoly)
if (this._minDistance <= this._terminateDistance) {
this._minDistanceLocation[locationsIndex] = locPtPoly[0]
this._minDistanceLocation[polyGeomIndex] = locPtPoly[1]
return null
}
}
} else if (arguments.length === 3) {
if (arguments[2] instanceof Array && (hasInterface(arguments[0], List) && hasInterface(arguments[1], List))) {
const locs = arguments[0], polys = arguments[1], locPtPoly = arguments[2]
for (let i = 0; i < locs.size(); i++) {
const loc = locs.get(i)
for (let j = 0; j < polys.size(); j++) {
this.computeContainmentDistance(loc, polys.get(j), locPtPoly)
if (this._minDistance <= this._terminateDistance) return null
}
}
} else if (arguments[2] instanceof Array && (arguments[0] instanceof GeometryLocation && arguments[1] instanceof Polygon)) {
const ptLoc = arguments[0], poly = arguments[1], locPtPoly = arguments[2]
const pt = ptLoc.getCoordinate()
if (Location.EXTERIOR !== this._ptLocator.locate(pt, poly)) {
this._minDistance = 0.0
locPtPoly[0] = ptLoc
locPtPoly[1] = new GeometryLocation(poly, pt)
return null
}
}
}
}
computeMinDistanceLinesPoints(lines, points, locGeom) {
for (let i = 0; i < lines.size(); i++) {
const line = lines.get(i)
for (let j = 0; j < points.size(); j++) {
const pt = points.get(j)
this.computeMinDistance(line, pt, locGeom)
if (this._minDistance <= this._terminateDistance) return null
}
}
}
computeFacetDistance() {
const locGeom = new Array(2).fill(null)
const lines0 = LinearComponentExtracter.getLines(this._geom[0])
const lines1 = LinearComponentExtracter.getLines(this._geom[1])
const pts0 = PointExtracter.getPoints(this._geom[0])
const pts1 = PointExtracter.getPoints(this._geom[1])
this.computeMinDistanceLines(lines0, lines1, locGeom)
this.updateMinDistance(locGeom, false)
if (this._minDistance <= this._terminateDistance) return null
locGeom[0] = null
locGeom[1] = null
this.computeMinDistanceLinesPoints(lines0, pts1, locGeom)
this.updateMinDistance(locGeom, false)
if (this._minDistance <= this._terminateDistance) return null
locGeom[0] = null
locGeom[1] = null
this.computeMinDistanceLinesPoints(lines1, pts0, locGeom)
this.updateMinDistance(locGeom, true)
if (this._minDistance <= this._terminateDistance) return null
locGeom[0] = null
locGeom[1] = null
this.computeMinDistancePoints(pts0, pts1, locGeom)
this.updateMinDistance(locGeom, false)
}
nearestLocations() {
this.computeMinDistance()
return this._minDistanceLocation
}
updateMinDistance(locGeom, flip) {
if (locGeom[0] === null) return null
if (flip) {
this._minDistanceLocation[0] = locGeom[1]
this._minDistanceLocation[1] = locGeom[0]
} else {
this._minDistanceLocation[0] = locGeom[0]
this._minDistanceLocation[1] = locGeom[1]
}
}
nearestPoints() {
this.computeMinDistance()
const nearestPts = [this._minDistanceLocation[0].getCoordinate(), this._minDistanceLocation[1].getCoordinate()]
return nearestPts
}
computeMinDistance() {
if (arguments.length === 0) {
if (this._minDistanceLocation !== null) return null
this._minDistanceLocation = new Array(2).fill(null)
this.computeContainmentDistance()
if (this._minDistance <= this._terminateDistance) return null
this.computeFacetDistance()
} else if (arguments.length === 3) {
if (arguments[2] instanceof Array && (arguments[0] instanceof LineString && arguments[1] instanceof Point)) {
const line = arguments[0], pt = arguments[1], locGeom = arguments[2]
if (line.getEnvelopeInternal().distance(pt.getEnvelopeInternal()) > this._minDistance) return null
const coord0 = line.getCoordinates()
const coord = pt.getCoordinate()
for (let i = 0; i < coord0.length - 1; i++) {
const dist = Distance.pointToSegment(coord, coord0[i], coord0[i + 1])
if (dist < this._minDistance) {
this._minDistance = dist
const seg = new LineSegment(coord0[i], coord0[i + 1])
const segClosestPoint = seg.closestPoint(coord)
locGeom[0] = new GeometryLocation(line, i, segClosestPoint)
locGeom[1] = new GeometryLocation(pt, 0, coord)
}
if (this._minDistance <= this._terminateDistance) return null
}
} else if (arguments[2] instanceof Array && (arguments[0] instanceof LineString && arguments[1] instanceof LineString)) {
const line0 = arguments[0], line1 = arguments[1], locGeom = arguments[2]
if (line0.getEnvelopeInternal().distance(line1.getEnvelopeInternal()) > this._minDistance) return null
const coord0 = line0.getCoordinates()
const coord1 = line1.getCoordinates()
for (let i = 0; i < coord0.length - 1; i++) {
const segEnv0 = new Envelope(coord0[i], coord0[i + 1])
if (segEnv0.distance(line1.getEnvelopeInternal()) > this._minDistance) continue
for (let j = 0; j < coord1.length - 1; j++) {
const segEnv1 = new Envelope(coord1[j], coord1[j + 1])
if (segEnv0.distance(segEnv1) > this._minDistance) continue
const dist = Distance.segmentToSegment(coord0[i], coord0[i + 1], coord1[j], coord1[j + 1])
if (dist < this._minDistance) {
this._minDistance = dist
const seg0 = new LineSegment(coord0[i], coord0[i + 1])
const seg1 = new LineSegment(coord1[j], coord1[j + 1])
const closestPt = seg0.closestPoints(seg1)
locGeom[0] = new GeometryLocation(line0, i, closestPt[0])
locGeom[1] = new GeometryLocation(line1, j, closestPt[1])
}
if (this._minDistance <= this._terminateDistance) return null
}
}
}
}
}
computeMinDistancePoints(points0, points1, locGeom) {
for (let i = 0; i < points0.size(); i++) {
const pt0 = points0.get(i)
for (let j = 0; j < points1.size(); j++) {
const pt1 = points1.get(j)
const dist = pt0.getCoordinate().distance(pt1.getCoordinate())
if (dist < this._minDistance) {
this._minDistance = dist
locGeom[0] = new GeometryLocation(pt0, 0, pt0.getCoordinate())
locGeom[1] = new GeometryLocation(pt1, 0, pt1.getCoordinate())
}
if (this._minDistance <= this._terminateDistance) return null
}
}
}
distance() {
if (this._geom[0] === null || this._geom[1] === null) throw new IllegalArgumentException('null geometries are not supported')
if (this._geom[0].isEmpty() || this._geom[1].isEmpty()) return 0.0
this.computeMinDistance()
return this._minDistance
}
computeMinDistanceLines(lines0, lines1, locGeom) {
for (let i = 0; i < lines0.size(); i++) {
const line0 = lines0.get(i)
for (let j = 0; j < lines1.size(); j++) {
const line1 = lines1.get(j)
this.computeMinDistance(line0, line1, locGeom)
if (this._minDistance <= this._terminateDistance) return null
}
}
}
}