PolygonizeGraph.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import PolygonizeDirectedEdge from './PolygonizeDirectedEdge'
  2. import HashSet from '../../../../../java/util/HashSet'
  3. import Stack from '../../../../../java/util/Stack'
  4. import Node from '../../planargraph/Node'
  5. import PolygonizeEdge from './PolygonizeEdge'
  6. import EdgeRing from './EdgeRing'
  7. import CoordinateArrays from '../../geom/CoordinateArrays'
  8. import ArrayList from '../../../../../java/util/ArrayList'
  9. import Assert from '../../util/Assert'
  10. import PlanarGraph from '../../planargraph/PlanarGraph'
  11. export default class PolygonizeGraph extends PlanarGraph {
  12. constructor() {
  13. super()
  14. PolygonizeGraph.constructor_.apply(this, arguments)
  15. }
  16. static constructor_() {
  17. this._factory = null
  18. const factory = arguments[0]
  19. this._factory = factory
  20. }
  21. static findLabeledEdgeRings(dirEdges) {
  22. const edgeRingStarts = new ArrayList()
  23. let currLabel = 1
  24. for (let i = dirEdges.iterator(); i.hasNext(); ) {
  25. const de = i.next()
  26. if (de.isMarked()) continue
  27. if (de.getLabel() >= 0) continue
  28. edgeRingStarts.add(de)
  29. const edges = EdgeRing.findDirEdgesInRing(de)
  30. PolygonizeGraph.label(edges, currLabel)
  31. currLabel++
  32. }
  33. return edgeRingStarts
  34. }
  35. static getDegreeNonDeleted(node) {
  36. const edges = node.getOutEdges().getEdges()
  37. let degree = 0
  38. for (let i = edges.iterator(); i.hasNext(); ) {
  39. const de = i.next()
  40. if (!de.isMarked()) degree++
  41. }
  42. return degree
  43. }
  44. static deleteAllEdges(node) {
  45. const edges = node.getOutEdges().getEdges()
  46. for (let i = edges.iterator(); i.hasNext(); ) {
  47. const de = i.next()
  48. de.setMarked(true)
  49. const sym = de.getSym()
  50. if (sym !== null) sym.setMarked(true)
  51. }
  52. }
  53. static label(dirEdges, label) {
  54. for (let i = dirEdges.iterator(); i.hasNext(); ) {
  55. const de = i.next()
  56. de.setLabel(label)
  57. }
  58. }
  59. static computeNextCWEdges(node) {
  60. const deStar = node.getOutEdges()
  61. let startDE = null
  62. let prevDE = null
  63. for (let i = deStar.getEdges().iterator(); i.hasNext(); ) {
  64. const outDE = i.next()
  65. if (outDE.isMarked()) continue
  66. if (startDE === null) startDE = outDE
  67. if (prevDE !== null) {
  68. const sym = prevDE.getSym()
  69. sym.setNext(outDE)
  70. }
  71. prevDE = outDE
  72. }
  73. if (prevDE !== null) {
  74. const sym = prevDE.getSym()
  75. sym.setNext(startDE)
  76. }
  77. }
  78. static computeNextCCWEdges(node, label) {
  79. const deStar = node.getOutEdges()
  80. let firstOutDE = null
  81. let prevInDE = null
  82. const edges = deStar.getEdges()
  83. for (let i = edges.size() - 1; i >= 0; i--) {
  84. const de = edges.get(i)
  85. const sym = de.getSym()
  86. let outDE = null
  87. if (de.getLabel() === label) outDE = de
  88. let inDE = null
  89. if (sym.getLabel() === label) inDE = sym
  90. if (outDE === null && inDE === null) continue
  91. if (inDE !== null)
  92. prevInDE = inDE
  93. if (outDE !== null) {
  94. if (prevInDE !== null) {
  95. prevInDE.setNext(outDE)
  96. prevInDE = null
  97. }
  98. if (firstOutDE === null) firstOutDE = outDE
  99. }
  100. }
  101. if (prevInDE !== null) {
  102. Assert.isTrue(firstOutDE !== null)
  103. prevInDE.setNext(firstOutDE)
  104. }
  105. }
  106. static getDegree(node, label) {
  107. const edges = node.getOutEdges().getEdges()
  108. let degree = 0
  109. for (let i = edges.iterator(); i.hasNext(); ) {
  110. const de = i.next()
  111. if (de.getLabel() === label) degree++
  112. }
  113. return degree
  114. }
  115. static findIntersectionNodes(startDE, label) {
  116. let de = startDE
  117. let intNodes = null
  118. do {
  119. const node = de.getFromNode()
  120. if (PolygonizeGraph.getDegree(node, label) > 1) {
  121. if (intNodes === null) intNodes = new ArrayList()
  122. intNodes.add(node)
  123. }
  124. de = de.getNext()
  125. Assert.isTrue(de !== null, 'found null DE in ring')
  126. Assert.isTrue(de === startDE || !de.isInRing(), 'found DE already in ring')
  127. } while (de !== startDE)
  128. return intNodes
  129. }
  130. findEdgeRing(startDE) {
  131. const er = new EdgeRing(this._factory)
  132. er.build(startDE)
  133. return er
  134. }
  135. computeDepthParity() {
  136. if (arguments.length === 0) {
  137. while (true) {
  138. const de = null
  139. if (de === null) return null
  140. this.computeDepthParity(de)
  141. }
  142. } else if (arguments.length === 1) {
  143. const de = arguments[0]
  144. }
  145. }
  146. computeNextCWEdges() {
  147. for (let iNode = this.nodeIterator(); iNode.hasNext(); ) {
  148. const node = iNode.next()
  149. PolygonizeGraph.computeNextCWEdges(node)
  150. }
  151. }
  152. addEdge(line) {
  153. if (line.isEmpty())
  154. return null
  155. const linePts = CoordinateArrays.removeRepeatedPoints(line.getCoordinates())
  156. if (linePts.length < 2)
  157. return null
  158. const startPt = linePts[0]
  159. const endPt = linePts[linePts.length - 1]
  160. const nStart = this.getNode(startPt)
  161. const nEnd = this.getNode(endPt)
  162. const de0 = new PolygonizeDirectedEdge(nStart, nEnd, linePts[1], true)
  163. const de1 = new PolygonizeDirectedEdge(nEnd, nStart, linePts[linePts.length - 2], false)
  164. const edge = new PolygonizeEdge(line)
  165. edge.setDirectedEdges(de0, de1)
  166. this.add(edge)
  167. }
  168. deleteCutEdges() {
  169. this.computeNextCWEdges()
  170. PolygonizeGraph.findLabeledEdgeRings(this._dirEdges)
  171. const cutLines = new ArrayList()
  172. for (let i = this._dirEdges.iterator(); i.hasNext(); ) {
  173. const de = i.next()
  174. if (de.isMarked()) continue
  175. const sym = de.getSym()
  176. if (de.getLabel() === sym.getLabel()) {
  177. de.setMarked(true)
  178. sym.setMarked(true)
  179. const e = de.getEdge()
  180. cutLines.add(e.getLine())
  181. }
  182. }
  183. return cutLines
  184. }
  185. getEdgeRings() {
  186. this.computeNextCWEdges()
  187. PolygonizeGraph.label(this._dirEdges, -1)
  188. const maximalRings = PolygonizeGraph.findLabeledEdgeRings(this._dirEdges)
  189. this.convertMaximalToMinimalEdgeRings(maximalRings)
  190. const edgeRingList = new ArrayList()
  191. for (let i = this._dirEdges.iterator(); i.hasNext(); ) {
  192. const de = i.next()
  193. if (de.isMarked()) continue
  194. if (de.isInRing()) continue
  195. const er = this.findEdgeRing(de)
  196. edgeRingList.add(er)
  197. }
  198. return edgeRingList
  199. }
  200. getNode(pt) {
  201. let node = this.findNode(pt)
  202. if (node === null) {
  203. node = new Node(pt)
  204. this.add(node)
  205. }
  206. return node
  207. }
  208. convertMaximalToMinimalEdgeRings(ringEdges) {
  209. for (let i = ringEdges.iterator(); i.hasNext(); ) {
  210. const de = i.next()
  211. const label = de.getLabel()
  212. const intNodes = PolygonizeGraph.findIntersectionNodes(de, label)
  213. if (intNodes === null) continue
  214. for (let iNode = intNodes.iterator(); iNode.hasNext(); ) {
  215. const node = iNode.next()
  216. PolygonizeGraph.computeNextCCWEdges(node, label)
  217. }
  218. }
  219. }
  220. deleteDangles() {
  221. const nodesToRemove = this.findNodesOfDegree(1)
  222. const dangleLines = new HashSet()
  223. const nodeStack = new Stack()
  224. for (let i = nodesToRemove.iterator(); i.hasNext(); )
  225. nodeStack.push(i.next())
  226. while (!nodeStack.isEmpty()) {
  227. const node = nodeStack.pop()
  228. PolygonizeGraph.deleteAllEdges(node)
  229. const nodeOutEdges = node.getOutEdges().getEdges()
  230. for (let i = nodeOutEdges.iterator(); i.hasNext(); ) {
  231. const de = i.next()
  232. de.setMarked(true)
  233. const sym = de.getSym()
  234. if (sym !== null) sym.setMarked(true)
  235. const e = de.getEdge()
  236. dangleLines.add(e.getLine())
  237. const toNode = de.getToNode()
  238. if (PolygonizeGraph.getDegreeNonDeleted(toNode) === 1) nodeStack.push(toNode)
  239. }
  240. }
  241. return dangleLines
  242. }
  243. }