IsSimpleOp.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import TreeSet from '../../../../java/util/TreeSet'
  2. import LineString from '../geom/LineString'
  3. import hasInterface from '../../../../hasInterface'
  4. import MultiPoint from '../geom/MultiPoint'
  5. import GeometryGraph from '../geomgraph/GeometryGraph'
  6. import GeometryCollection from '../geom/GeometryCollection'
  7. import Polygonal from '../geom/Polygonal'
  8. import RobustLineIntersector from '../algorithm/RobustLineIntersector'
  9. import LinearComponentExtracter from '../geom/util/LinearComponentExtracter'
  10. import TreeMap from '../../../../java/util/TreeMap'
  11. import MultiLineString from '../geom/MultiLineString'
  12. export default class IsSimpleOp {
  13. constructor() {
  14. IsSimpleOp.constructor_.apply(this, arguments)
  15. }
  16. static constructor_() {
  17. this._inputGeom = null
  18. this._isClosedEndpointsInInterior = true
  19. this._nonSimpleLocation = null
  20. if (arguments.length === 1) {
  21. const geom = arguments[0]
  22. this._inputGeom = geom
  23. } else if (arguments.length === 2) {
  24. const geom = arguments[0], boundaryNodeRule = arguments[1]
  25. this._inputGeom = geom
  26. this._isClosedEndpointsInInterior = !boundaryNodeRule.isInBoundary(2)
  27. }
  28. }
  29. static isSimple() {
  30. if (arguments.length === 1) {
  31. const geom = arguments[0]
  32. const op = new IsSimpleOp(geom)
  33. return op.isSimple()
  34. } else if (arguments.length === 2) {
  35. const geom = arguments[0], boundaryNodeRule = arguments[1]
  36. const op = new IsSimpleOp(geom, boundaryNodeRule)
  37. return op.isSimple()
  38. }
  39. }
  40. isSimpleMultiPoint(mp) {
  41. if (mp.isEmpty()) return true
  42. const points = new TreeSet()
  43. for (let i = 0; i < mp.getNumGeometries(); i++) {
  44. const pt = mp.getGeometryN(i)
  45. const p = pt.getCoordinate()
  46. if (points.contains(p)) {
  47. this._nonSimpleLocation = p
  48. return false
  49. }
  50. points.add(p)
  51. }
  52. return true
  53. }
  54. isSimplePolygonal(geom) {
  55. const rings = LinearComponentExtracter.getLines(geom)
  56. for (let i = rings.iterator(); i.hasNext(); ) {
  57. const ring = i.next()
  58. if (!this.isSimpleLinearGeometry(ring)) return false
  59. }
  60. return true
  61. }
  62. hasClosedEndpointIntersection(graph) {
  63. const endPoints = new TreeMap()
  64. for (let i = graph.getEdgeIterator(); i.hasNext(); ) {
  65. const e = i.next()
  66. const isClosed = e.isClosed()
  67. const p0 = e.getCoordinate(0)
  68. this.addEndpoint(endPoints, p0, isClosed)
  69. const p1 = e.getCoordinate(e.getNumPoints() - 1)
  70. this.addEndpoint(endPoints, p1, isClosed)
  71. }
  72. for (let i = endPoints.values().iterator(); i.hasNext(); ) {
  73. const eiInfo = i.next()
  74. if (eiInfo.isClosed && eiInfo.degree !== 2) {
  75. this._nonSimpleLocation = eiInfo.getCoordinate()
  76. return true
  77. }
  78. }
  79. return false
  80. }
  81. getNonSimpleLocation() {
  82. return this._nonSimpleLocation
  83. }
  84. isSimpleLinearGeometry(geom) {
  85. if (geom.isEmpty()) return true
  86. const graph = new GeometryGraph(0, geom)
  87. const li = new RobustLineIntersector()
  88. const si = graph.computeSelfNodes(li, true)
  89. if (!si.hasIntersection()) return true
  90. if (si.hasProperIntersection()) {
  91. this._nonSimpleLocation = si.getProperIntersectionPoint()
  92. return false
  93. }
  94. if (this.hasNonEndpointIntersection(graph)) return false
  95. if (this._isClosedEndpointsInInterior)
  96. if (this.hasClosedEndpointIntersection(graph)) return false
  97. return true
  98. }
  99. hasNonEndpointIntersection(graph) {
  100. for (let i = graph.getEdgeIterator(); i.hasNext(); ) {
  101. const e = i.next()
  102. const maxSegmentIndex = e.getMaximumSegmentIndex()
  103. for (let eiIt = e.getEdgeIntersectionList().iterator(); eiIt.hasNext(); ) {
  104. const ei = eiIt.next()
  105. if (!ei.isEndPoint(maxSegmentIndex)) {
  106. this._nonSimpleLocation = ei.getCoordinate()
  107. return true
  108. }
  109. }
  110. }
  111. return false
  112. }
  113. addEndpoint(endPoints, p, isClosed) {
  114. let eiInfo = endPoints.get(p)
  115. if (eiInfo === null) {
  116. eiInfo = new EndpointInfo(p)
  117. endPoints.put(p, eiInfo)
  118. }
  119. eiInfo.addEndpoint(isClosed)
  120. }
  121. computeSimple(geom) {
  122. this._nonSimpleLocation = null
  123. if (geom.isEmpty()) return true
  124. if (geom instanceof LineString) return this.isSimpleLinearGeometry(geom)
  125. if (geom instanceof MultiLineString) return this.isSimpleLinearGeometry(geom)
  126. if (geom instanceof MultiPoint) return this.isSimpleMultiPoint(geom)
  127. if (hasInterface(geom, Polygonal)) return this.isSimplePolygonal(geom)
  128. if (geom instanceof GeometryCollection) return this.isSimpleGeometryCollection(geom)
  129. return true
  130. }
  131. isSimple() {
  132. this._nonSimpleLocation = null
  133. return this.computeSimple(this._inputGeom)
  134. }
  135. isSimpleGeometryCollection(geom) {
  136. for (let i = 0; i < geom.getNumGeometries(); i++) {
  137. const comp = geom.getGeometryN(i)
  138. if (!this.computeSimple(comp)) return false
  139. }
  140. return true
  141. }
  142. }
  143. class EndpointInfo {
  144. constructor() {
  145. EndpointInfo.constructor_.apply(this, arguments)
  146. }
  147. static constructor_() {
  148. this.pt = null
  149. this.isClosed = null
  150. this.degree = null
  151. const pt = arguments[0]
  152. this.pt = pt
  153. this.isClosed = false
  154. this.degree = 0
  155. }
  156. addEndpoint(isClosed) {
  157. this.degree++
  158. this.isClosed |= isClosed
  159. }
  160. getCoordinate() {
  161. return this.pt
  162. }
  163. }
  164. IsSimpleOp.EndpointInfo = EndpointInfo