PolygonBuilder.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import PointLocation from '../../algorithm/PointLocation'
  2. import TopologyException from '../../geom/TopologyException'
  3. import MaximalEdgeRing from './MaximalEdgeRing'
  4. import CoordinateArrays from '../../geom/CoordinateArrays'
  5. import ArrayList from '../../../../../java/util/ArrayList'
  6. import Assert from '../../util/Assert'
  7. import PlanarGraph from '../../geomgraph/PlanarGraph'
  8. export default class PolygonBuilder {
  9. constructor() {
  10. PolygonBuilder.constructor_.apply(this, arguments)
  11. }
  12. static constructor_() {
  13. this._geometryFactory = null
  14. this._shellList = new ArrayList()
  15. const geometryFactory = arguments[0]
  16. this._geometryFactory = geometryFactory
  17. }
  18. static findEdgeRingContaining(testEr, shellList) {
  19. const testRing = testEr.getLinearRing()
  20. const testEnv = testRing.getEnvelopeInternal()
  21. let testPt = testRing.getCoordinateN(0)
  22. let minShell = null
  23. let minShellEnv = null
  24. for (let it = shellList.iterator(); it.hasNext(); ) {
  25. const tryShell = it.next()
  26. const tryShellRing = tryShell.getLinearRing()
  27. const tryShellEnv = tryShellRing.getEnvelopeInternal()
  28. if (tryShellEnv.equals(testEnv)) continue
  29. if (!tryShellEnv.contains(testEnv)) continue
  30. testPt = CoordinateArrays.ptNotInList(testRing.getCoordinates(), tryShellRing.getCoordinates())
  31. let isContained = false
  32. if (PointLocation.isInRing(testPt, tryShellRing.getCoordinates())) isContained = true
  33. if (isContained)
  34. if (minShell === null || minShellEnv.contains(tryShellEnv)) {
  35. minShell = tryShell
  36. minShellEnv = minShell.getLinearRing().getEnvelopeInternal()
  37. }
  38. }
  39. return minShell
  40. }
  41. sortShellsAndHoles(edgeRings, shellList, freeHoleList) {
  42. for (let it = edgeRings.iterator(); it.hasNext(); ) {
  43. const er = it.next()
  44. if (er.isHole())
  45. freeHoleList.add(er)
  46. else
  47. shellList.add(er)
  48. }
  49. }
  50. computePolygons(shellList) {
  51. const resultPolyList = new ArrayList()
  52. for (let it = shellList.iterator(); it.hasNext(); ) {
  53. const er = it.next()
  54. const poly = er.toPolygon(this._geometryFactory)
  55. resultPolyList.add(poly)
  56. }
  57. return resultPolyList
  58. }
  59. placeFreeHoles(shellList, freeHoleList) {
  60. for (let it = freeHoleList.iterator(); it.hasNext(); ) {
  61. const hole = it.next()
  62. if (hole.getShell() === null) {
  63. const shell = PolygonBuilder.findEdgeRingContaining(hole, shellList)
  64. if (shell === null) throw new TopologyException('unable to assign hole to a shell', hole.getCoordinate(0))
  65. hole.setShell(shell)
  66. }
  67. }
  68. }
  69. buildMinimalEdgeRings(maxEdgeRings, shellList, freeHoleList) {
  70. const edgeRings = new ArrayList()
  71. for (let it = maxEdgeRings.iterator(); it.hasNext(); ) {
  72. const er = it.next()
  73. if (er.getMaxNodeDegree() > 2) {
  74. er.linkDirectedEdgesForMinimalEdgeRings()
  75. const minEdgeRings = er.buildMinimalRings()
  76. const shell = this.findShell(minEdgeRings)
  77. if (shell !== null) {
  78. this.placePolygonHoles(shell, minEdgeRings)
  79. shellList.add(shell)
  80. } else {
  81. freeHoleList.addAll(minEdgeRings)
  82. }
  83. } else {
  84. edgeRings.add(er)
  85. }
  86. }
  87. return edgeRings
  88. }
  89. buildMaximalEdgeRings(dirEdges) {
  90. const maxEdgeRings = new ArrayList()
  91. for (let it = dirEdges.iterator(); it.hasNext(); ) {
  92. const de = it.next()
  93. if (de.isInResult() && de.getLabel().isArea())
  94. if (de.getEdgeRing() === null) {
  95. const er = new MaximalEdgeRing(de, this._geometryFactory)
  96. maxEdgeRings.add(er)
  97. er.setInResult()
  98. }
  99. }
  100. return maxEdgeRings
  101. }
  102. placePolygonHoles(shell, minEdgeRings) {
  103. for (let it = minEdgeRings.iterator(); it.hasNext(); ) {
  104. const er = it.next()
  105. if (er.isHole())
  106. er.setShell(shell)
  107. }
  108. }
  109. getPolygons() {
  110. const resultPolyList = this.computePolygons(this._shellList)
  111. return resultPolyList
  112. }
  113. findShell(minEdgeRings) {
  114. let shellCount = 0
  115. let shell = null
  116. for (let it = minEdgeRings.iterator(); it.hasNext(); ) {
  117. const er = it.next()
  118. if (!er.isHole()) {
  119. shell = er
  120. shellCount++
  121. }
  122. }
  123. Assert.isTrue(shellCount <= 1, 'found two shells in MinimalEdgeRing list')
  124. return shell
  125. }
  126. add() {
  127. if (arguments.length === 1) {
  128. const graph = arguments[0]
  129. this.add(graph.getEdgeEnds(), graph.getNodes())
  130. } else if (arguments.length === 2) {
  131. const dirEdges = arguments[0], nodes = arguments[1]
  132. PlanarGraph.linkResultDirectedEdges(nodes)
  133. const maxEdgeRings = this.buildMaximalEdgeRings(dirEdges)
  134. const freeHoleList = new ArrayList()
  135. const edgeRings = this.buildMinimalEdgeRings(maxEdgeRings, this._shellList, freeHoleList)
  136. this.sortShellsAndHoles(edgeRings, this._shellList, freeHoleList)
  137. this.placeFreeHoles(this._shellList, freeHoleList)
  138. }
  139. }
  140. }