GeometryGraph.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import PointLocator from '../algorithm/PointLocator'
  2. import Location from '../geom/Location'
  3. import LineString from '../geom/LineString'
  4. import HashMap from '../../../../java/util/HashMap'
  5. import Geometry from '../geom/Geometry'
  6. import hasInterface from '../../../../hasInterface'
  7. import Position from './Position'
  8. import Coordinate from '../geom/Coordinate'
  9. import Point from '../geom/Point'
  10. import Polygon from '../geom/Polygon'
  11. import MultiPoint from '../geom/MultiPoint'
  12. import SimpleMCSweepLineIntersector from './index/SimpleMCSweepLineIntersector'
  13. import LinearRing from '../geom/LinearRing'
  14. import BoundaryNodeRule from '../algorithm/BoundaryNodeRule'
  15. import Orientation from '../algorithm/Orientation'
  16. import SegmentIntersector from './index/SegmentIntersector'
  17. import MultiPolygon from '../geom/MultiPolygon'
  18. import Label from './Label'
  19. import GeometryCollection from '../geom/GeometryCollection'
  20. import UnsupportedOperationException from '../../../../java/lang/UnsupportedOperationException'
  21. import CoordinateArrays from '../geom/CoordinateArrays'
  22. import Polygonal from '../geom/Polygonal'
  23. import IndexedPointInAreaLocator from '../algorithm/locate/IndexedPointInAreaLocator'
  24. import Assert from '../util/Assert'
  25. import Edge from './Edge'
  26. import MultiLineString from '../geom/MultiLineString'
  27. import PlanarGraph from './PlanarGraph'
  28. export default class GeometryGraph extends PlanarGraph {
  29. constructor() {
  30. super()
  31. GeometryGraph.constructor_.apply(this, arguments)
  32. }
  33. static constructor_() {
  34. this._parentGeom = null
  35. this._lineEdgeMap = new HashMap()
  36. this._boundaryNodeRule = null
  37. this._useBoundaryDeterminationRule = true
  38. this._argIndex = null
  39. this._boundaryNodes = null
  40. this._hasTooFewPoints = false
  41. this._invalidPoint = null
  42. this._areaPtLocator = null
  43. this._ptLocator = new PointLocator()
  44. if (arguments.length === 2) {
  45. const argIndex = arguments[0], parentGeom = arguments[1]
  46. GeometryGraph.constructor_.call(this, argIndex, parentGeom, BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE)
  47. } else if (arguments.length === 3) {
  48. const argIndex = arguments[0], parentGeom = arguments[1], boundaryNodeRule = arguments[2]
  49. this._argIndex = argIndex
  50. this._parentGeom = parentGeom
  51. this._boundaryNodeRule = boundaryNodeRule
  52. if (parentGeom !== null)
  53. this.add(parentGeom)
  54. }
  55. }
  56. static determineBoundary(boundaryNodeRule, boundaryCount) {
  57. return boundaryNodeRule.isInBoundary(boundaryCount) ? Location.BOUNDARY : Location.INTERIOR
  58. }
  59. insertBoundaryPoint(argIndex, coord) {
  60. const n = this._nodes.addNode(coord)
  61. const lbl = n.getLabel()
  62. let boundaryCount = 1
  63. let loc = Location.NONE
  64. loc = lbl.getLocation(argIndex, Position.ON)
  65. if (loc === Location.BOUNDARY) boundaryCount++
  66. const newLoc = GeometryGraph.determineBoundary(this._boundaryNodeRule, boundaryCount)
  67. lbl.setLocation(argIndex, newLoc)
  68. }
  69. computeSelfNodes() {
  70. if (arguments.length === 2) {
  71. const li = arguments[0], computeRingSelfNodes = arguments[1]
  72. return this.computeSelfNodes(li, computeRingSelfNodes, false)
  73. } else if (arguments.length === 3) {
  74. const li = arguments[0], computeRingSelfNodes = arguments[1], isDoneIfProperInt = arguments[2]
  75. const si = new SegmentIntersector(li, true, false)
  76. si.setIsDoneIfProperInt(isDoneIfProperInt)
  77. const esi = this.createEdgeSetIntersector()
  78. const isRings = this._parentGeom instanceof LinearRing || this._parentGeom instanceof Polygon || this._parentGeom instanceof MultiPolygon
  79. const computeAllSegments = computeRingSelfNodes || !isRings
  80. esi.computeIntersections(this._edges, si, computeAllSegments)
  81. this.addSelfIntersectionNodes(this._argIndex)
  82. return si
  83. }
  84. }
  85. computeSplitEdges(edgelist) {
  86. for (let i = this._edges.iterator(); i.hasNext(); ) {
  87. const e = i.next()
  88. e.eiList.addSplitEdges(edgelist)
  89. }
  90. }
  91. computeEdgeIntersections(g, li, includeProper) {
  92. const si = new SegmentIntersector(li, includeProper, true)
  93. si.setBoundaryNodes(this.getBoundaryNodes(), g.getBoundaryNodes())
  94. const esi = this.createEdgeSetIntersector()
  95. esi.computeIntersections(this._edges, g._edges, si)
  96. return si
  97. }
  98. getGeometry() {
  99. return this._parentGeom
  100. }
  101. getBoundaryNodeRule() {
  102. return this._boundaryNodeRule
  103. }
  104. hasTooFewPoints() {
  105. return this._hasTooFewPoints
  106. }
  107. addPoint() {
  108. if (arguments[0] instanceof Point) {
  109. const p = arguments[0]
  110. const coord = p.getCoordinate()
  111. this.insertPoint(this._argIndex, coord, Location.INTERIOR)
  112. } else if (arguments[0] instanceof Coordinate) {
  113. const pt = arguments[0]
  114. this.insertPoint(this._argIndex, pt, Location.INTERIOR)
  115. }
  116. }
  117. addPolygon(p) {
  118. this.addPolygonRing(p.getExteriorRing(), Location.EXTERIOR, Location.INTERIOR)
  119. for (let i = 0; i < p.getNumInteriorRing(); i++) {
  120. const hole = p.getInteriorRingN(i)
  121. this.addPolygonRing(hole, Location.INTERIOR, Location.EXTERIOR)
  122. }
  123. }
  124. addEdge(e) {
  125. this.insertEdge(e)
  126. const coord = e.getCoordinates()
  127. this.insertPoint(this._argIndex, coord[0], Location.BOUNDARY)
  128. this.insertPoint(this._argIndex, coord[coord.length - 1], Location.BOUNDARY)
  129. }
  130. addLineString(line) {
  131. const coord = CoordinateArrays.removeRepeatedPoints(line.getCoordinates())
  132. if (coord.length < 2) {
  133. this._hasTooFewPoints = true
  134. this._invalidPoint = coord[0]
  135. return null
  136. }
  137. const e = new Edge(coord, new Label(this._argIndex, Location.INTERIOR))
  138. this._lineEdgeMap.put(line, e)
  139. this.insertEdge(e)
  140. Assert.isTrue(coord.length >= 2, 'found LineString with single point')
  141. this.insertBoundaryPoint(this._argIndex, coord[0])
  142. this.insertBoundaryPoint(this._argIndex, coord[coord.length - 1])
  143. }
  144. getInvalidPoint() {
  145. return this._invalidPoint
  146. }
  147. getBoundaryPoints() {
  148. const coll = this.getBoundaryNodes()
  149. const pts = new Array(coll.size()).fill(null)
  150. let i = 0
  151. for (let it = coll.iterator(); it.hasNext(); ) {
  152. const node = it.next()
  153. pts[i++] = node.getCoordinate().copy()
  154. }
  155. return pts
  156. }
  157. getBoundaryNodes() {
  158. if (this._boundaryNodes === null) this._boundaryNodes = this._nodes.getBoundaryNodes(this._argIndex)
  159. return this._boundaryNodes
  160. }
  161. addSelfIntersectionNode(argIndex, coord, loc) {
  162. if (this.isBoundaryNode(argIndex, coord)) return null
  163. if (loc === Location.BOUNDARY && this._useBoundaryDeterminationRule) this.insertBoundaryPoint(argIndex, coord); else this.insertPoint(argIndex, coord, loc)
  164. }
  165. addPolygonRing(lr, cwLeft, cwRight) {
  166. if (lr.isEmpty()) return null
  167. const coord = CoordinateArrays.removeRepeatedPoints(lr.getCoordinates())
  168. if (coord.length < 4) {
  169. this._hasTooFewPoints = true
  170. this._invalidPoint = coord[0]
  171. return null
  172. }
  173. let left = cwLeft
  174. let right = cwRight
  175. if (Orientation.isCCW(coord)) {
  176. left = cwRight
  177. right = cwLeft
  178. }
  179. const e = new Edge(coord, new Label(this._argIndex, Location.BOUNDARY, left, right))
  180. this._lineEdgeMap.put(lr, e)
  181. this.insertEdge(e)
  182. this.insertPoint(this._argIndex, coord[0], Location.BOUNDARY)
  183. }
  184. insertPoint(argIndex, coord, onLocation) {
  185. const n = this._nodes.addNode(coord)
  186. const lbl = n.getLabel()
  187. if (lbl === null)
  188. n._label = new Label(argIndex, onLocation)
  189. else lbl.setLocation(argIndex, onLocation)
  190. }
  191. createEdgeSetIntersector() {
  192. return new SimpleMCSweepLineIntersector()
  193. }
  194. addSelfIntersectionNodes(argIndex) {
  195. for (let i = this._edges.iterator(); i.hasNext(); ) {
  196. const e = i.next()
  197. const eLoc = e.getLabel().getLocation(argIndex)
  198. for (let eiIt = e.eiList.iterator(); eiIt.hasNext(); ) {
  199. const ei = eiIt.next()
  200. this.addSelfIntersectionNode(argIndex, ei.coord, eLoc)
  201. }
  202. }
  203. }
  204. add() {
  205. if (arguments.length === 1 && arguments[0] instanceof Geometry) {
  206. const g = arguments[0]
  207. if (g.isEmpty()) return null
  208. if (g instanceof MultiPolygon) this._useBoundaryDeterminationRule = false
  209. if (g instanceof Polygon) this.addPolygon(g); else if (g instanceof LineString) this.addLineString(g); else if (g instanceof Point) this.addPoint(g); else if (g instanceof MultiPoint) this.addCollection(g); else if (g instanceof MultiLineString) this.addCollection(g); else if (g instanceof MultiPolygon) this.addCollection(g); else if (g instanceof GeometryCollection) this.addCollection(g); else throw new UnsupportedOperationException(g.getGeometryType())
  210. } else {
  211. return super.add.apply(this, arguments)
  212. }
  213. }
  214. addCollection(gc) {
  215. for (let i = 0; i < gc.getNumGeometries(); i++) {
  216. const g = gc.getGeometryN(i)
  217. this.add(g)
  218. }
  219. }
  220. locate(pt) {
  221. if (hasInterface(this._parentGeom, Polygonal) && this._parentGeom.getNumGeometries() > 50) {
  222. if (this._areaPtLocator === null)
  223. this._areaPtLocator = new IndexedPointInAreaLocator(this._parentGeom)
  224. return this._areaPtLocator.locate(pt)
  225. }
  226. return this._ptLocator.locate(pt, this._parentGeom)
  227. }
  228. findEdge() {
  229. if (arguments.length === 1 && arguments[0] instanceof LineString) {
  230. const line = arguments[0]
  231. return this._lineEdgeMap.get(line)
  232. } else {
  233. return super.findEdge.apply(this, arguments)
  234. }
  235. }
  236. }