DistanceOp.js 10 KB

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