OverlapUnion.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import HashSet from '../../../../../java/util/HashSet'
  2. import TopologyException from '../../geom/TopologyException'
  3. import GeometryCombiner from '../../geom/util/GeometryCombiner'
  4. import LineSegment from '../../geom/LineSegment'
  5. import ArrayList from '../../../../../java/util/ArrayList'
  6. import CoordinateSequenceFilter from '../../geom/CoordinateSequenceFilter'
  7. export default class OverlapUnion {
  8. constructor() {
  9. OverlapUnion.constructor_.apply(this, arguments)
  10. }
  11. static constructor_() {
  12. this._geomFactory = null
  13. this._g0 = null
  14. this._g1 = null
  15. this._isUnionSafe = null
  16. const g0 = arguments[0], g1 = arguments[1]
  17. this._g0 = g0
  18. this._g1 = g1
  19. this._geomFactory = g0.getFactory()
  20. }
  21. static containsProperly() {
  22. if (arguments.length === 2) {
  23. const env = arguments[0], p = arguments[1]
  24. if (env.isNull()) return false
  25. return p.getX() > env.getMinX() && p.getX() < env.getMaxX() && p.getY() > env.getMinY() && p.getY() < env.getMaxY()
  26. } else if (arguments.length === 3) {
  27. const env = arguments[0], p0 = arguments[1], p1 = arguments[2]
  28. return OverlapUnion.containsProperly(env, p0) && OverlapUnion.containsProperly(env, p1)
  29. }
  30. }
  31. static union(g0, g1) {
  32. const union = new OverlapUnion(g0, g1)
  33. return union.union()
  34. }
  35. static intersects(env, p0, p1) {
  36. return env.intersects(p0) || env.intersects(p1)
  37. }
  38. static overlapEnvelope(g0, g1) {
  39. const g0Env = g0.getEnvelopeInternal()
  40. const g1Env = g1.getEnvelopeInternal()
  41. const overlapEnv = g0Env.intersection(g1Env)
  42. return overlapEnv
  43. }
  44. static extractBorderSegments(geom, env, segs) {
  45. geom.apply(new (class {
  46. get interfaces_() {
  47. return [CoordinateSequenceFilter]
  48. }
  49. filter(seq, i) {
  50. if (i <= 0) return null
  51. const p0 = seq.getCoordinate(i - 1)
  52. const p1 = seq.getCoordinate(i)
  53. const isBorder = OverlapUnion.intersects(env, p0, p1) && !OverlapUnion.containsProperly(env, p0, p1)
  54. if (isBorder) {
  55. const seg = new LineSegment(p0, p1)
  56. segs.add(seg)
  57. }
  58. }
  59. isDone() {
  60. return false
  61. }
  62. isGeometryChanged() {
  63. return false
  64. }
  65. })())
  66. }
  67. static unionBuffer(g0, g1) {
  68. const factory = g0.getFactory()
  69. const gColl = factory.createGeometryCollection([g0, g1])
  70. const union = gColl.buffer(0.0)
  71. return union
  72. }
  73. isBorderSegmentsSame(result, env) {
  74. const segsBefore = this.extractBorderSegments(this._g0, this._g1, env)
  75. const segsAfter = new ArrayList()
  76. OverlapUnion.extractBorderSegments(result, env, segsAfter)
  77. return this.isEqual(segsBefore, segsAfter)
  78. }
  79. extractByEnvelope(env, geom, disjointGeoms) {
  80. const intersectingGeoms = new ArrayList()
  81. for (let i = 0; i < geom.getNumGeometries(); i++) {
  82. const elem = geom.getGeometryN(i)
  83. if (elem.getEnvelopeInternal().intersects(env)) {
  84. intersectingGeoms.add(elem)
  85. } else {
  86. const copy = elem.copy()
  87. disjointGeoms.add(copy)
  88. }
  89. }
  90. return this._geomFactory.buildGeometry(intersectingGeoms)
  91. }
  92. isEqual(segs0, segs1) {
  93. if (segs0.size() !== segs1.size()) return false
  94. const segIndex = new HashSet(segs0)
  95. for (const seg of segs1)
  96. if (!segIndex.contains(seg))
  97. return false
  98. return true
  99. }
  100. union() {
  101. const overlapEnv = OverlapUnion.overlapEnvelope(this._g0, this._g1)
  102. if (overlapEnv.isNull()) {
  103. const g0Copy = this._g0.copy()
  104. const g1Copy = this._g1.copy()
  105. return GeometryCombiner.combine(g0Copy, g1Copy)
  106. }
  107. const disjointPolys = new ArrayList()
  108. const g0Overlap = this.extractByEnvelope(overlapEnv, this._g0, disjointPolys)
  109. const g1Overlap = this.extractByEnvelope(overlapEnv, this._g1, disjointPolys)
  110. const unionGeom = this.unionFull(g0Overlap, g1Overlap)
  111. let result = null
  112. this._isUnionSafe = this.isBorderSegmentsSame(unionGeom, overlapEnv)
  113. if (!this._isUnionSafe)
  114. result = this.unionFull(this._g0, this._g1)
  115. else
  116. result = this.combine(unionGeom, disjointPolys)
  117. return result
  118. }
  119. combine(unionGeom, disjointPolys) {
  120. if (disjointPolys.size() <= 0) return unionGeom
  121. disjointPolys.add(unionGeom)
  122. const result = GeometryCombiner.combine(disjointPolys)
  123. return result
  124. }
  125. unionFull(geom0, geom1) {
  126. try {
  127. return geom0.union(geom1)
  128. } catch (ex) {
  129. if (ex instanceof TopologyException)
  130. return OverlapUnion.unionBuffer(geom0, geom1)
  131. else throw ex
  132. } finally {}
  133. }
  134. extractBorderSegments(geom0, geom1, env) {
  135. const segs = new ArrayList()
  136. OverlapUnion.extractBorderSegments(geom0, env, segs)
  137. if (geom1 !== null) OverlapUnion.extractBorderSegments(geom1, env, segs)
  138. return segs
  139. }
  140. isUnionOptimized() {
  141. return this._isUnionSafe
  142. }
  143. }