BufferInputLineSimplifier.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import CoordinateList from '../../geom/CoordinateList'
  2. import Orientation from '../../algorithm/Orientation'
  3. import Distance from '../../algorithm/Distance'
  4. export default class BufferInputLineSimplifier {
  5. constructor() {
  6. BufferInputLineSimplifier.constructor_.apply(this, arguments)
  7. }
  8. static constructor_() {
  9. this._inputLine = null
  10. this._distanceTol = null
  11. this._isDeleted = null
  12. this._angleOrientation = Orientation.COUNTERCLOCKWISE
  13. const inputLine = arguments[0]
  14. this._inputLine = inputLine
  15. }
  16. static simplify(inputLine, distanceTol) {
  17. const simp = new BufferInputLineSimplifier(inputLine)
  18. return simp.simplify(distanceTol)
  19. }
  20. isDeletable(i0, i1, i2, distanceTol) {
  21. const p0 = this._inputLine[i0]
  22. const p1 = this._inputLine[i1]
  23. const p2 = this._inputLine[i2]
  24. if (!this.isConcave(p0, p1, p2)) return false
  25. if (!this.isShallow(p0, p1, p2, distanceTol)) return false
  26. return this.isShallowSampled(p0, p1, i0, i2, distanceTol)
  27. }
  28. deleteShallowConcavities() {
  29. let index = 1
  30. let midIndex = this.findNextNonDeletedIndex(index)
  31. let lastIndex = this.findNextNonDeletedIndex(midIndex)
  32. let isChanged = false
  33. while (lastIndex < this._inputLine.length) {
  34. let isMiddleVertexDeleted = false
  35. if (this.isDeletable(index, midIndex, lastIndex, this._distanceTol)) {
  36. this._isDeleted[midIndex] = BufferInputLineSimplifier.DELETE
  37. isMiddleVertexDeleted = true
  38. isChanged = true
  39. }
  40. if (isMiddleVertexDeleted) index = lastIndex; else index = midIndex
  41. midIndex = this.findNextNonDeletedIndex(index)
  42. lastIndex = this.findNextNonDeletedIndex(midIndex)
  43. }
  44. return isChanged
  45. }
  46. isShallowConcavity(p0, p1, p2, distanceTol) {
  47. const orientation = Orientation.index(p0, p1, p2)
  48. const isAngleToSimplify = orientation === this._angleOrientation
  49. if (!isAngleToSimplify) return false
  50. const dist = Distance.pointToSegment(p1, p0, p2)
  51. return dist < distanceTol
  52. }
  53. isShallowSampled(p0, p2, i0, i2, distanceTol) {
  54. let inc = Math.trunc((i2 - i0) / BufferInputLineSimplifier.NUM_PTS_TO_CHECK)
  55. if (inc <= 0) inc = 1
  56. for (let i = i0; i < i2; i += inc)
  57. if (!this.isShallow(p0, p2, this._inputLine[i], distanceTol)) return false
  58. return true
  59. }
  60. isConcave(p0, p1, p2) {
  61. const orientation = Orientation.index(p0, p1, p2)
  62. const isConcave = orientation === this._angleOrientation
  63. return isConcave
  64. }
  65. simplify(distanceTol) {
  66. this._distanceTol = Math.abs(distanceTol)
  67. if (distanceTol < 0) this._angleOrientation = Orientation.CLOCKWISE
  68. this._isDeleted = new Array(this._inputLine.length).fill(null)
  69. let isChanged = false
  70. do
  71. isChanged = this.deleteShallowConcavities()
  72. while (isChanged)
  73. return this.collapseLine()
  74. }
  75. findNextNonDeletedIndex(index) {
  76. let next = index + 1
  77. while (next < this._inputLine.length && this._isDeleted[next] === BufferInputLineSimplifier.DELETE) next++
  78. return next
  79. }
  80. isShallow(p0, p1, p2, distanceTol) {
  81. const dist = Distance.pointToSegment(p1, p0, p2)
  82. return dist < distanceTol
  83. }
  84. collapseLine() {
  85. const coordList = new CoordinateList()
  86. for (let i = 0; i < this._inputLine.length; i++)
  87. if (this._isDeleted[i] !== BufferInputLineSimplifier.DELETE) coordList.add(this._inputLine[i])
  88. return coordList.toCoordinateArray()
  89. }
  90. }
  91. BufferInputLineSimplifier.INIT = 0
  92. BufferInputLineSimplifier.DELETE = 1
  93. BufferInputLineSimplifier.KEEP = 1
  94. BufferInputLineSimplifier.NUM_PTS_TO_CHECK = 10