BufferOp.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import BufferParameters from './BufferParameters'
  2. import Geometry from '../../geom/Geometry'
  3. import BufferBuilder from './BufferBuilder'
  4. import ScaledNoder from '../../noding/ScaledNoder'
  5. import TopologyException from '../../geom/TopologyException'
  6. import MathUtil from '../../math/MathUtil'
  7. import PrecisionModel from '../../geom/PrecisionModel'
  8. import RuntimeException from '../../../../../java/lang/RuntimeException'
  9. import MCIndexSnapRounder from '../../noding/snapround/MCIndexSnapRounder'
  10. export default class BufferOp {
  11. constructor() {
  12. BufferOp.constructor_.apply(this, arguments)
  13. }
  14. static constructor_() {
  15. this._argGeom = null
  16. this._distance = null
  17. this._bufParams = new BufferParameters()
  18. this._resultGeometry = null
  19. this._saveException = null
  20. if (arguments.length === 1) {
  21. const g = arguments[0]
  22. this._argGeom = g
  23. } else if (arguments.length === 2) {
  24. const g = arguments[0], bufParams = arguments[1]
  25. this._argGeom = g
  26. this._bufParams = bufParams
  27. }
  28. }
  29. static bufferOp() {
  30. if (arguments.length === 2) {
  31. const g = arguments[0], distance = arguments[1]
  32. const gBuf = new BufferOp(g)
  33. const geomBuf = gBuf.getResultGeometry(distance)
  34. return geomBuf
  35. } else if (arguments.length === 3) {
  36. if (Number.isInteger(arguments[2]) && (arguments[0] instanceof Geometry && typeof arguments[1] === 'number')) {
  37. const g = arguments[0], distance = arguments[1], quadrantSegments = arguments[2]
  38. const bufOp = new BufferOp(g)
  39. bufOp.setQuadrantSegments(quadrantSegments)
  40. const geomBuf = bufOp.getResultGeometry(distance)
  41. return geomBuf
  42. } else if (arguments[2] instanceof BufferParameters && (arguments[0] instanceof Geometry && typeof arguments[1] === 'number')) {
  43. const g = arguments[0], distance = arguments[1], params = arguments[2]
  44. const bufOp = new BufferOp(g, params)
  45. const geomBuf = bufOp.getResultGeometry(distance)
  46. return geomBuf
  47. }
  48. } else if (arguments.length === 4) {
  49. const g = arguments[0], distance = arguments[1], quadrantSegments = arguments[2], endCapStyle = arguments[3]
  50. const bufOp = new BufferOp(g)
  51. bufOp.setQuadrantSegments(quadrantSegments)
  52. bufOp.setEndCapStyle(endCapStyle)
  53. const geomBuf = bufOp.getResultGeometry(distance)
  54. return geomBuf
  55. }
  56. }
  57. static precisionScaleFactor(g, distance, maxPrecisionDigits) {
  58. const env = g.getEnvelopeInternal()
  59. const envMax = MathUtil.max(Math.abs(env.getMaxX()), Math.abs(env.getMaxY()), Math.abs(env.getMinX()), Math.abs(env.getMinY()))
  60. const expandByDistance = distance > 0.0 ? distance : 0.0
  61. const bufEnvMax = envMax + 2 * expandByDistance
  62. const bufEnvPrecisionDigits = Math.trunc(Math.log(bufEnvMax) / Math.log(10) + 1.0)
  63. const minUnitLog10 = maxPrecisionDigits - bufEnvPrecisionDigits
  64. const scaleFactor = Math.pow(10.0, minUnitLog10)
  65. return scaleFactor
  66. }
  67. bufferFixedPrecision(fixedPM) {
  68. const noder = new ScaledNoder(new MCIndexSnapRounder(new PrecisionModel(1.0)), fixedPM.getScale())
  69. const bufBuilder = new BufferBuilder(this._bufParams)
  70. bufBuilder.setWorkingPrecisionModel(fixedPM)
  71. bufBuilder.setNoder(noder)
  72. this._resultGeometry = bufBuilder.buffer(this._argGeom, this._distance)
  73. }
  74. bufferReducedPrecision() {
  75. if (arguments.length === 0) {
  76. for (let precDigits = BufferOp.MAX_PRECISION_DIGITS; precDigits >= 0; precDigits--) {
  77. try {
  78. this.bufferReducedPrecision(precDigits)
  79. } catch (ex) {
  80. if (ex instanceof TopologyException)
  81. this._saveException = ex
  82. else throw ex
  83. } finally {}
  84. if (this._resultGeometry !== null) return null
  85. }
  86. throw this._saveException
  87. } else if (arguments.length === 1) {
  88. const precisionDigits = arguments[0]
  89. const sizeBasedScaleFactor = BufferOp.precisionScaleFactor(this._argGeom, this._distance, precisionDigits)
  90. const fixedPM = new PrecisionModel(sizeBasedScaleFactor)
  91. this.bufferFixedPrecision(fixedPM)
  92. }
  93. }
  94. computeGeometry() {
  95. this.bufferOriginalPrecision()
  96. if (this._resultGeometry !== null) return null
  97. const argPM = this._argGeom.getFactory().getPrecisionModel()
  98. if (argPM.getType() === PrecisionModel.FIXED) this.bufferFixedPrecision(argPM); else this.bufferReducedPrecision()
  99. }
  100. setQuadrantSegments(quadrantSegments) {
  101. this._bufParams.setQuadrantSegments(quadrantSegments)
  102. }
  103. bufferOriginalPrecision() {
  104. try {
  105. const bufBuilder = new BufferBuilder(this._bufParams)
  106. this._resultGeometry = bufBuilder.buffer(this._argGeom, this._distance)
  107. } catch (ex) {
  108. if (ex instanceof RuntimeException)
  109. this._saveException = ex
  110. else throw ex
  111. } finally {}
  112. }
  113. getResultGeometry(distance) {
  114. this._distance = distance
  115. this.computeGeometry()
  116. return this._resultGeometry
  117. }
  118. setEndCapStyle(endCapStyle) {
  119. this._bufParams.setEndCapStyle(endCapStyle)
  120. }
  121. }
  122. BufferOp.CAP_ROUND = BufferParameters.CAP_ROUND
  123. BufferOp.CAP_BUTT = BufferParameters.CAP_FLAT
  124. BufferOp.CAP_FLAT = BufferParameters.CAP_FLAT
  125. BufferOp.CAP_SQUARE = BufferParameters.CAP_SQUARE
  126. BufferOp.MAX_PRECISION_DIGITS = 12