OffsetCurveBuilder.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import BufferParameters from './BufferParameters'
  2. import Position from '../../geomgraph/Position'
  3. import Coordinate from '../../geom/Coordinate'
  4. import BufferInputLineSimplifier from './BufferInputLineSimplifier'
  5. import CoordinateArrays from '../../geom/CoordinateArrays'
  6. import OffsetSegmentGenerator from './OffsetSegmentGenerator'
  7. export default class OffsetCurveBuilder {
  8. constructor() {
  9. OffsetCurveBuilder.constructor_.apply(this, arguments)
  10. }
  11. static constructor_() {
  12. this._distance = 0.0
  13. this._precisionModel = null
  14. this._bufParams = null
  15. const precisionModel = arguments[0], bufParams = arguments[1]
  16. this._precisionModel = precisionModel
  17. this._bufParams = bufParams
  18. }
  19. static copyCoordinates(pts) {
  20. const copy = new Array(pts.length).fill(null)
  21. for (let i = 0; i < copy.length; i++)
  22. copy[i] = new Coordinate(pts[i])
  23. return copy
  24. }
  25. getOffsetCurve(inputPts, distance) {
  26. this._distance = distance
  27. if (distance === 0.0) return null
  28. const isRightSide = distance < 0.0
  29. const posDistance = Math.abs(distance)
  30. const segGen = this.getSegGen(posDistance)
  31. if (inputPts.length <= 1)
  32. this.computePointCurve(inputPts[0], segGen)
  33. else
  34. this.computeOffsetCurve(inputPts, isRightSide, segGen)
  35. const curvePts = segGen.getCoordinates()
  36. if (isRightSide) CoordinateArrays.reverse(curvePts)
  37. return curvePts
  38. }
  39. computeSingleSidedBufferCurve(inputPts, isRightSide, segGen) {
  40. const distTol = this.simplifyTolerance(this._distance)
  41. if (isRightSide) {
  42. segGen.addSegments(inputPts, true)
  43. const simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol)
  44. const n2 = simp2.length - 1
  45. segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT)
  46. segGen.addFirstSegment()
  47. for (let i = n2 - 2; i >= 0; i--)
  48. segGen.addNextSegment(simp2[i], true)
  49. } else {
  50. segGen.addSegments(inputPts, false)
  51. const simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol)
  52. const n1 = simp1.length - 1
  53. segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT)
  54. segGen.addFirstSegment()
  55. for (let i = 2; i <= n1; i++)
  56. segGen.addNextSegment(simp1[i], true)
  57. }
  58. segGen.addLastSegment()
  59. segGen.closeRing()
  60. }
  61. computeRingBufferCurve(inputPts, side, segGen) {
  62. let distTol = this.simplifyTolerance(this._distance)
  63. if (side === Position.RIGHT) distTol = -distTol
  64. const simp = BufferInputLineSimplifier.simplify(inputPts, distTol)
  65. const n = simp.length - 1
  66. segGen.initSideSegments(simp[n - 1], simp[0], side)
  67. for (let i = 1; i <= n; i++) {
  68. const addStartPoint = i !== 1
  69. segGen.addNextSegment(simp[i], addStartPoint)
  70. }
  71. segGen.closeRing()
  72. }
  73. computeLineBufferCurve(inputPts, segGen) {
  74. const distTol = this.simplifyTolerance(this._distance)
  75. const simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol)
  76. const n1 = simp1.length - 1
  77. segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT)
  78. for (let i = 2; i <= n1; i++)
  79. segGen.addNextSegment(simp1[i], true)
  80. segGen.addLastSegment()
  81. segGen.addLineEndCap(simp1[n1 - 1], simp1[n1])
  82. const simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol)
  83. const n2 = simp2.length - 1
  84. segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT)
  85. for (let i = n2 - 2; i >= 0; i--)
  86. segGen.addNextSegment(simp2[i], true)
  87. segGen.addLastSegment()
  88. segGen.addLineEndCap(simp2[1], simp2[0])
  89. segGen.closeRing()
  90. }
  91. computePointCurve(pt, segGen) {
  92. switch (this._bufParams.getEndCapStyle()) {
  93. case BufferParameters.CAP_ROUND:
  94. segGen.createCircle(pt)
  95. break
  96. case BufferParameters.CAP_SQUARE:
  97. segGen.createSquare(pt)
  98. break
  99. }
  100. }
  101. getLineCurve(inputPts, distance) {
  102. this._distance = distance
  103. if (this.isLineOffsetEmpty(distance)) return null
  104. const posDistance = Math.abs(distance)
  105. const segGen = this.getSegGen(posDistance)
  106. if (inputPts.length <= 1) {
  107. this.computePointCurve(inputPts[0], segGen)
  108. } else
  109. if (this._bufParams.isSingleSided()) {
  110. const isRightSide = distance < 0.0
  111. this.computeSingleSidedBufferCurve(inputPts, isRightSide, segGen)
  112. } else {
  113. this.computeLineBufferCurve(inputPts, segGen)
  114. }
  115. const lineCoord = segGen.getCoordinates()
  116. return lineCoord
  117. }
  118. getBufferParameters() {
  119. return this._bufParams
  120. }
  121. simplifyTolerance(bufDistance) {
  122. return bufDistance * this._bufParams.getSimplifyFactor()
  123. }
  124. getRingCurve(inputPts, side, distance) {
  125. this._distance = distance
  126. if (inputPts.length <= 2) return this.getLineCurve(inputPts, distance)
  127. if (distance === 0.0)
  128. return OffsetCurveBuilder.copyCoordinates(inputPts)
  129. const segGen = this.getSegGen(distance)
  130. this.computeRingBufferCurve(inputPts, side, segGen)
  131. return segGen.getCoordinates()
  132. }
  133. computeOffsetCurve(inputPts, isRightSide, segGen) {
  134. const distTol = this.simplifyTolerance(this._distance)
  135. if (isRightSide) {
  136. const simp2 = BufferInputLineSimplifier.simplify(inputPts, -distTol)
  137. const n2 = simp2.length - 1
  138. segGen.initSideSegments(simp2[n2], simp2[n2 - 1], Position.LEFT)
  139. segGen.addFirstSegment()
  140. for (let i = n2 - 2; i >= 0; i--)
  141. segGen.addNextSegment(simp2[i], true)
  142. } else {
  143. const simp1 = BufferInputLineSimplifier.simplify(inputPts, distTol)
  144. const n1 = simp1.length - 1
  145. segGen.initSideSegments(simp1[0], simp1[1], Position.LEFT)
  146. segGen.addFirstSegment()
  147. for (let i = 2; i <= n1; i++)
  148. segGen.addNextSegment(simp1[i], true)
  149. }
  150. segGen.addLastSegment()
  151. }
  152. isLineOffsetEmpty(distance) {
  153. if (distance === 0.0) return true
  154. if (distance < 0.0 && !this._bufParams.isSingleSided()) return true
  155. return false
  156. }
  157. getSegGen(distance) {
  158. return new OffsetSegmentGenerator(this._precisionModel, this._bufParams, distance)
  159. }
  160. }