HalfEdge.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import WKTWriter from '../io/WKTWriter'
  2. import Coordinate from '../geom/Coordinate'
  3. import Orientation from '../algorithm/Orientation'
  4. import Quadrant from '../geomgraph/Quadrant'
  5. import Assert from '../util/Assert'
  6. import StringBuilder from '../../../../java/lang/StringBuilder'
  7. export default class HalfEdge {
  8. constructor() {
  9. HalfEdge.constructor_.apply(this, arguments)
  10. }
  11. static constructor_() {
  12. this._orig = null
  13. this._sym = null
  14. this._next = null
  15. const orig = arguments[0]
  16. this._orig = orig
  17. }
  18. static create(p0, p1) {
  19. const e0 = new HalfEdge(p0)
  20. const e1 = new HalfEdge(p1)
  21. e0.link(e1)
  22. return e0
  23. }
  24. find(dest) {
  25. let oNext = this
  26. do {
  27. if (oNext === null) return null
  28. if (oNext.dest().equals2D(dest)) return oNext
  29. oNext = oNext.oNext()
  30. } while (oNext !== this)
  31. return null
  32. }
  33. dest() {
  34. return this._sym._orig
  35. }
  36. isEdgesSorted() {
  37. const lowest = this.findLowest()
  38. let e = lowest
  39. do {
  40. const eNext = e.oNext()
  41. if (eNext === lowest) break
  42. const isSorted = eNext.compareTo(e) > 0
  43. if (!isSorted)
  44. return false
  45. e = eNext
  46. } while (e !== lowest)
  47. return true
  48. }
  49. oNext() {
  50. return this._sym._next
  51. }
  52. directionY() {
  53. return this.directionPt().getY() - this._orig.getY()
  54. }
  55. insert(eAdd) {
  56. if (this.oNext() === this) {
  57. this.insertAfter(eAdd)
  58. return null
  59. }
  60. const ePrev = this.insertionEdge(eAdd)
  61. ePrev.insertAfter(eAdd)
  62. }
  63. insertAfter(e) {
  64. Assert.equals(this._orig, e.orig())
  65. const save = this.oNext()
  66. this._sym.setNext(e)
  67. e.sym().setNext(save)
  68. }
  69. degree() {
  70. let degree = 0
  71. let e = this
  72. do {
  73. degree++
  74. e = e.oNext()
  75. } while (e !== this)
  76. return degree
  77. }
  78. equals() {
  79. if (arguments.length === 2 && (arguments[1] instanceof Coordinate && arguments[0] instanceof Coordinate)) {
  80. const p0 = arguments[0], p1 = arguments[1]
  81. return this._orig.equals2D(p0) && this._sym._orig.equals(p1)
  82. }
  83. }
  84. findLowest() {
  85. let lowest = this
  86. let e = this.oNext()
  87. do {
  88. if (e.compareTo(lowest) < 0) lowest = e
  89. e = e.oNext()
  90. } while (e !== this)
  91. return lowest
  92. }
  93. directionPt() {
  94. return this.dest()
  95. }
  96. sym() {
  97. return this._sym
  98. }
  99. prev() {
  100. return this._sym.next()._sym
  101. }
  102. compareAngularDirection(e) {
  103. const dx = this.directionX()
  104. const dy = this.directionY()
  105. const dx2 = e.directionX()
  106. const dy2 = e.directionY()
  107. if (dx === dx2 && dy === dy2) return 0
  108. const quadrant = Quadrant.quadrant(dx, dy)
  109. const quadrant2 = Quadrant.quadrant(dx2, dy2)
  110. if (quadrant > quadrant2) return 1
  111. if (quadrant < quadrant2) return -1
  112. const dir1 = this.directionPt()
  113. const dir2 = e.directionPt()
  114. return Orientation.index(e._orig, dir2, dir1)
  115. }
  116. prevNode() {
  117. let e = this
  118. while (e.degree() === 2) {
  119. e = e.prev()
  120. if (e === this) return null
  121. }
  122. return e
  123. }
  124. directionX() {
  125. return this.directionPt().getX() - this._orig.getX()
  126. }
  127. insertionEdge(eAdd) {
  128. let ePrev = this
  129. do {
  130. const eNext = ePrev.oNext()
  131. if (eNext.compareTo(ePrev) > 0 && eAdd.compareTo(ePrev) >= 0 && eAdd.compareTo(eNext) <= 0)
  132. return ePrev
  133. if (eNext.compareTo(ePrev) <= 0 && (eAdd.compareTo(eNext) <= 0 || eAdd.compareTo(ePrev) >= 0))
  134. return ePrev
  135. ePrev = eNext
  136. } while (ePrev !== this)
  137. Assert.shouldNeverReachHere()
  138. return null
  139. }
  140. compareTo(obj) {
  141. const e = obj
  142. const comp = this.compareAngularDirection(e)
  143. return comp
  144. }
  145. toStringNode() {
  146. const orig = this.orig()
  147. const dest = this.dest()
  148. const sb = new StringBuilder()
  149. sb.append('Node( ' + WKTWriter.format(orig) + ' )' + '\n')
  150. let e = this
  151. do {
  152. sb.append(' -> ' + e)
  153. sb.append('\n')
  154. e = e.oNext()
  155. } while (e !== this)
  156. return sb.toString()
  157. }
  158. link(sym) {
  159. this.setSym(sym)
  160. sym.setSym(this)
  161. this.setNext(sym)
  162. sym.setNext(this)
  163. }
  164. next() {
  165. return this._next
  166. }
  167. setSym(e) {
  168. this._sym = e
  169. }
  170. orig() {
  171. return this._orig
  172. }
  173. toString() {
  174. return 'HE(' + this._orig.x + ' ' + this._orig.y + ', ' + this._sym._orig.x + ' ' + this._sym._orig.y + ')'
  175. }
  176. toStringNodeEdge() {
  177. return ' -> (' + WKTWriter.format(this.dest())
  178. }
  179. setNext(e) {
  180. this._next = e
  181. }
  182. }