@jscad/modeling 3.0.0-alpha.0 → 3.0.2-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +1 -1
  3. package/dist/jscad-modeling.es.js +2 -2
  4. package/dist/jscad-modeling.min.js +2 -2
  5. package/package.json +2 -2
  6. package/rollup.config.js +1 -1
  7. package/src/colors/colorize.js +1 -5
  8. package/src/colors/colorize.test.js +8 -8
  9. package/src/geometries/geom2/transform.js +9 -1
  10. package/src/geometries/geom2/transform.test.js +57 -0
  11. package/src/geometries/geom3/fromPointsConvex.d.ts +4 -0
  12. package/src/geometries/geom3/fromPointsConvex.js +25 -0
  13. package/src/geometries/geom3/fromPointsConvex.test.js +32 -0
  14. package/src/geometries/geom3/index.d.ts +1 -0
  15. package/src/geometries/geom3/index.js +1 -0
  16. package/src/geometries/index.js +3 -4
  17. package/src/geometries/path2/appendBezier.js +1 -1
  18. package/src/geometries/poly3/index.js +1 -1
  19. package/src/geometries/poly3/measureBoundingBox.js +2 -0
  20. package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
  21. package/src/geometries/poly3/measureBoundingSphere.js +25 -8
  22. package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
  23. package/src/geometries/poly3/type.d.ts +1 -1
  24. package/src/geometries/slice/validate.js +1 -2
  25. package/src/index.js +41 -0
  26. package/src/maths/index.js +1 -0
  27. package/src/maths/mat4/isOnlyTransformScale.js +1 -1
  28. package/src/measurements/measureAggregateArea.js +0 -1
  29. package/src/measurements/measureAggregateBoundingBox.js +0 -1
  30. package/src/measurements/measureAggregateEpsilon.js +0 -1
  31. package/src/measurements/measureAggregateVolume.js +0 -1
  32. package/src/measurements/measureArea.js +0 -1
  33. package/src/measurements/measureBoundingBox.js +0 -1
  34. package/src/measurements/measureBoundingSphere.js +2 -6
  35. package/src/measurements/measureEpsilon.js +0 -1
  36. package/src/measurements/measureVolume.js +0 -1
  37. package/src/operations/booleans/index.d.ts +1 -0
  38. package/src/operations/booleans/intersect.js +5 -5
  39. package/src/operations/booleans/intersect.test.js +6 -7
  40. package/src/operations/booleans/intersectGeom2.js +2 -6
  41. package/src/operations/booleans/intersectGeom2.test.js +25 -1
  42. package/src/operations/booleans/intersectGeom3.js +2 -6
  43. package/src/operations/booleans/intersectGeom3.test.js +5 -1
  44. package/src/operations/booleans/martinez/compareEvents.js +2 -7
  45. package/src/operations/booleans/martinez/connectEdges.js +30 -41
  46. package/src/operations/booleans/martinez/contour.js +1 -1
  47. package/src/operations/booleans/martinez/divideSegment.js +12 -11
  48. package/src/operations/booleans/martinez/fillQueue.js +24 -28
  49. package/src/operations/booleans/martinez/index.js +2 -1
  50. package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
  51. package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
  52. package/src/operations/booleans/martinez/splaytree.js +59 -457
  53. package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
  54. package/src/operations/booleans/martinez/sweepEvent.js +3 -17
  55. package/src/operations/booleans/mayOverlap.js +0 -1
  56. package/src/operations/booleans/scission.d.ts +5 -0
  57. package/src/operations/booleans/scission.js +3 -5
  58. package/src/operations/booleans/scission.test.js +6 -0
  59. package/src/operations/booleans/subtract.js +5 -5
  60. package/src/operations/booleans/subtract.test.js +6 -7
  61. package/src/operations/booleans/subtractGeom2.js +2 -6
  62. package/src/operations/booleans/subtractGeom2.test.js +25 -1
  63. package/src/operations/booleans/subtractGeom3.js +2 -6
  64. package/src/operations/booleans/subtractGeom3.test.js +5 -1
  65. package/src/operations/booleans/trees/Node.js +25 -27
  66. package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
  67. package/src/operations/booleans/trees/Tree.js +9 -4
  68. package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
  69. package/src/operations/booleans/trees/splitPolygonByPlane.d.ts +33 -0
  70. package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
  71. package/src/operations/booleans/union.js +5 -5
  72. package/src/operations/booleans/union.test.js +6 -7
  73. package/src/operations/booleans/unionGeom2.js +2 -6
  74. package/src/operations/booleans/unionGeom2.test.js +25 -1
  75. package/src/operations/booleans/unionGeom3.js +2 -6
  76. package/src/operations/booleans/unionGeom3.test.js +6 -1
  77. package/src/operations/extrusions/extrudeFromSlices.test.js +8 -1
  78. package/src/operations/extrusions/extrudeHelical.js +2 -8
  79. package/src/operations/extrusions/extrudeLinear.js +1 -5
  80. package/src/operations/extrusions/extrudeLinear.test.js +7 -1
  81. package/src/operations/extrusions/extrudeRotate.js +3 -2
  82. package/src/operations/extrusions/extrudeRotate.test.js +13 -1
  83. package/src/operations/extrusions/extrudeWalls.js +3 -1
  84. package/src/operations/extrusions/project.js +1 -5
  85. package/src/operations/hulls/hull.js +6 -5
  86. package/src/operations/hulls/hull.test.js +56 -3
  87. package/src/operations/hulls/hullChain.js +11 -6
  88. package/src/operations/hulls/hullChain.test.js +12 -2
  89. package/src/operations/hulls/hullGeom2.js +5 -6
  90. package/src/operations/hulls/hullGeom3.js +9 -18
  91. package/src/operations/hulls/hullPath2.js +6 -7
  92. package/src/operations/hulls/hullPath2.test.js +1 -1
  93. package/src/operations/hulls/hullPoints2.d.ts +3 -0
  94. package/src/operations/hulls/hullPoints2.js +24 -30
  95. package/src/operations/hulls/hullPoints3.d.ts +4 -0
  96. package/src/operations/hulls/hullPoints3.js +21 -0
  97. package/src/operations/hulls/index.d.ts +2 -0
  98. package/src/operations/hulls/index.js +3 -1
  99. package/src/operations/modifiers/generalize.js +2 -6
  100. package/src/operations/modifiers/index.js +1 -1
  101. package/src/operations/modifiers/mergePolygons.js +2 -3
  102. package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
  103. package/src/operations/modifiers/snap.js +2 -6
  104. package/src/operations/offsets/offset.js +1 -5
  105. package/src/operations/offsets/offsetFromPoints.test.js +0 -1
  106. package/src/operations/offsets/offsetGeom2.test.js +1 -0
  107. package/src/operations/offsets/offsetGeom3.js +0 -2
  108. package/src/operations/offsets/offsetGeom3.test.js +9 -1
  109. package/src/operations/offsets/offsetPath2.js +3 -3
  110. package/src/operations/transforms/align.js +8 -7
  111. package/src/operations/transforms/align.test.js +2 -2
  112. package/src/operations/transforms/center.js +6 -9
  113. package/src/operations/transforms/center.test.js +19 -1
  114. package/src/operations/transforms/mirror.js +5 -8
  115. package/src/operations/transforms/mirror.test.js +7 -7
  116. package/src/operations/transforms/rotate.js +5 -8
  117. package/src/operations/transforms/scale.js +5 -8
  118. package/src/operations/transforms/transform.js +2 -5
  119. package/src/operations/transforms/translate.js +5 -8
  120. package/src/primitives/arc.js +2 -0
  121. package/src/primitives/arc.test.js +11 -11
  122. package/src/primitives/circle.test.js +18 -8
  123. package/src/primitives/cube.test.js +10 -0
  124. package/src/primitives/cuboid.test.js +10 -0
  125. package/src/primitives/cylinder.test.js +12 -0
  126. package/src/primitives/cylinderElliptic.test.js +21 -1
  127. package/src/primitives/ellipse.test.js +18 -8
  128. package/src/primitives/ellipsoid.test.js +12 -0
  129. package/src/primitives/geodesicSphere.test.js +8 -0
  130. package/src/primitives/line.test.js +1 -1
  131. package/src/primitives/polygon.d.ts +1 -0
  132. package/src/primitives/polygon.js +13 -4
  133. package/src/primitives/polygon.test.js +15 -0
  134. package/src/primitives/polyhedron.js +1 -0
  135. package/src/primitives/polyhedron.test.js +8 -2
  136. package/src/primitives/rectangle.test.js +9 -3
  137. package/src/primitives/roundedCuboid.js +1 -1
  138. package/src/primitives/roundedCuboid.test.js +20 -4
  139. package/src/primitives/roundedCylinder.js +1 -1
  140. package/src/primitives/roundedCylinder.test.js +20 -0
  141. package/src/primitives/roundedRectangle.js +1 -1
  142. package/src/primitives/roundedRectangle.test.js +15 -6
  143. package/src/primitives/sphere.test.js +12 -0
  144. package/src/primitives/square.test.js +10 -4
  145. package/src/primitives/star.test.js +14 -6
  146. package/src/primitives/torus.js +1 -1
  147. package/src/primitives/torus.test.js +11 -1
  148. package/src/primitives/triangle.test.js +17 -9
  149. package/src/utils/coalesce.d.ts +3 -0
  150. package/src/utils/coalesce.js +20 -0
  151. package/src/utils/index.js +2 -2
  152. package/src/maths/mat4/leftMultiplyVec2.d.ts +0 -4
  153. package/src/maths/mat4/leftMultiplyVec2.js +0 -26
  154. package/src/maths/mat4/leftMultiplyVec3.d.ts +0 -4
  155. package/src/maths/mat4/leftMultiplyVec3.js +0 -27
  156. package/src/maths/mat4/mirror.d.ts +0 -4
  157. package/src/maths/mat4/mirror.js +0 -32
  158. package/src/maths/mat4/rightMultiplyVec2.d.ts +0 -4
  159. package/src/maths/mat4/rightMultiplyVec2.js +0 -27
  160. package/src/maths/mat4/rightMultiplyVec3.d.ts +0 -4
  161. package/src/maths/mat4/rightMultiplyVec3.js +0 -28
@@ -34,7 +34,7 @@ const crossProduct = (a, b) => (a[0] * b[1]) - (a[1] * b[0])
34
34
  * intersection. If they overlap, the two end points of the overlapping segment.
35
35
  * Otherwise, null.
36
36
  */
37
- export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
37
+ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch = false) => {
38
38
  // The algorithm expects our lines in the form P + sd, where P is a point,
39
39
  // s is on the interval [0, 1], and d is a vector.
40
40
  // We are passed two points. P can be the first point of each pair. The
@@ -51,11 +51,9 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
51
51
  ]
52
52
 
53
53
  // The rest is pretty much a straight port of the algorithm.
54
- const e = [b1[0] - a1[0], b1[1] - a1[1]]
54
+ const v1 = [b1[0] - a1[0], b1[1] - a1[1]]
55
55
  let kross = crossProduct(va, vb)
56
56
  let sqrKross = kross * kross
57
- const sqrLenA = dotProduct(va, va)
58
- // const sqrLenB = dotProduct(vb, vb)
59
57
 
60
58
  // Check for line intersection. This works because of the properties of the
61
59
  // cross product -- specifically, two vectors are parallel if and only if the
@@ -66,12 +64,12 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
66
64
  // If they're not parallel, then (because these are line segments) they
67
65
  // still might not actually intersect. This code checks that the
68
66
  // intersection point of the lines is actually on both line segments.
69
- const s = crossProduct(e, vb) / kross
67
+ const s = crossProduct(v1, vb) / kross
70
68
  if (s < 0 || s > 1) {
71
69
  // not on line segment a
72
70
  return null
73
71
  }
74
- const t = crossProduct(e, va) / kross
72
+ const t = crossProduct(v1, va) / kross
75
73
  if (t < 0 || t > 1) {
76
74
  // not on line segment b
77
75
  return null
@@ -93,8 +91,7 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
93
91
  // the (vector) difference between the two initial points. If this is parallel
94
92
  // with the line itself, then the two lines are the same line, and there will
95
93
  // be overlap.
96
- // const sqrLenE = dotProduct(e, e)
97
- kross = crossProduct(e, va)
94
+ kross = crossProduct(v1, va)
98
95
  sqrKross = kross * kross
99
96
 
100
97
  if (sqrKross > 0 /* EPS * sqLenB * sqLenE */) {
@@ -102,7 +99,8 @@ export const segmentIntersection = (a1, a2, b1, b2, noEndpointTouch) => {
102
99
  return null
103
100
  }
104
101
 
105
- const sa = dotProduct(va, e) / sqrLenA
102
+ const sqrLenA = dotProduct(va, va)
103
+ const sa = dotProduct(va, v1) / sqrLenA
106
104
  const sb = sa + dotProduct(va, vb) / sqrLenA
107
105
  const smin = Math.min(sa, sb)
108
106
  const smax = Math.max(sa, sb)
@@ -21,163 +21,80 @@ class Node {
21
21
  /**
22
22
  * Simple top down splay, not requiring i to be in the tree t.
23
23
  */
24
- const splay = (i, t, comparator) => {
24
+ const splay = (key, t, comparator) => {
25
25
  const N = new Node(null, null)
26
- let l = N
27
- let r = N
26
+ let left = N
27
+ let right = N
28
28
 
29
29
  while (true) {
30
- const cmp = comparator(i, t.key)
31
- // if (i < t.key) {
30
+ const cmp = comparator(key, t.key)
32
31
  if (cmp < 0) {
33
32
  if (t.left === null) break
34
- // if (i < t.left.key) {
35
- if (comparator(i, t.left.key) < 0) {
33
+ if (comparator(key, t.left.key) < 0) {
36
34
  const y = t.left /* rotate right */
37
35
  t.left = y.right
38
36
  y.right = t
39
37
  t = y
40
38
  if (t.left === null) break
41
39
  }
42
- r.left = t /* link right */
43
- r = t
40
+ right.left = t /* link right */
41
+ right = t
44
42
  t = t.left
45
- // } else if (i > t.key) {
46
43
  } else if (cmp > 0) {
47
44
  if (t.right === null) break
48
- // if (i > t.right.key) {
49
- if (comparator(i, t.right.key) > 0) {
45
+ if (comparator(key, t.right.key) > 0) {
50
46
  const y = t.right /* rotate left */
51
47
  t.right = y.left
52
48
  y.left = t
53
49
  t = y
54
50
  if (t.right === null) break
55
51
  }
56
- l.right = t /* link left */
57
- l = t
52
+ left.right = t /* link left */
53
+ left = t
58
54
  t = t.right
59
55
  } else break
60
56
  }
61
57
  /* assemble */
62
- l.right = t.left
63
- r.left = t.right
58
+ left.right = t.left
59
+ right.left = t.right
60
+
64
61
  t.left = N.right
65
62
  t.right = N.left
66
63
  return t
67
64
  }
68
65
 
69
- const insert = (i, data, t, comparator) => {
70
- const node = new Node(i, data)
66
+ const insert = (key, data, root, comparator) => {
67
+ const node = new Node(key, data)
71
68
 
72
- if (t === null) {
73
- node.left = node.right = null
69
+ if (root === null) {
74
70
  return node
75
71
  }
76
72
 
77
- t = splay(i, t, comparator)
78
- const cmp = comparator(i, t.key)
73
+ root = splay(key, root, comparator)
74
+ const cmp = comparator(key, root.key)
79
75
  if (cmp < 0) {
80
- node.left = t.left
81
- node.right = t
82
- t.left = null
76
+ node.left = root.left
77
+ node.right = root
78
+ root.left = null
83
79
  } else if (cmp >= 0) {
84
- node.right = t.right
85
- node.left = t
86
- t.right = null
80
+ node.right = root.right
81
+ node.left = root
82
+ root.right = null
87
83
  }
88
84
  return node
89
85
  }
90
86
 
91
- const split = (key, v, comparator) => {
92
- let left = null
93
- let right = null
94
- if (v) {
95
- v = splay(key, v, comparator)
96
-
97
- const cmp = comparator(v.key, key)
98
- if (cmp === 0) {
99
- left = v.left
100
- right = v.right
101
- } else if (cmp < 0) {
102
- right = v.right
103
- v.right = null
104
- left = v
105
- } else {
106
- left = v.left
107
- v.left = null
108
- right = v
109
- }
110
- }
111
- return { left, right }
112
- }
113
-
114
- const merge = (left, right, comparator) => {
115
- if (right === null) return left
116
- if (left === null) return right
117
-
118
- right = splay(left.key, right, comparator)
119
- right.left = left
120
- return right
121
- }
122
-
123
- /**
124
- * Prints level of the tree
125
- */
126
- const printRow = (root, prefix, isTail, out, printNode) => {
127
- if (root) {
128
- out(`${prefix}${isTail ? '└── ' : '├── '}${printNode(root)}\n`)
129
- const indent = prefix + (isTail ? ' ' : '│ ')
130
- if (root.left) printRow(root.left, indent, false, out, printNode)
131
- if (root.right) printRow(root.right, indent, true, out, printNode)
132
- }
133
- }
134
-
135
87
  export class Tree {
136
88
  constructor (comparator = DEFAULT_COMPARE) {
137
- this._comparator = comparator
89
+ this.comparator = comparator
138
90
  this._root = null
139
- this._size = 0
140
91
  }
141
92
 
142
93
  /**
143
94
  * Inserts a key, allows duplicates
144
95
  */
145
96
  insert (key, data) {
146
- this._size++
147
- this._root = insert(key, data, this._root, this._comparator)
148
- return this._root
149
- }
150
-
151
- /**
152
- * Adds a key, if it is not present in the tree
153
- */
154
- add (key, data) {
155
- const node = new Node(key, data)
156
-
157
- if (this._root === null) {
158
- node.left = node.right = null
159
- this._size++
160
- this._root = node
161
- }
162
-
163
- const comparator = this._comparator
164
- const t = splay(key, this._root, comparator)
165
- const cmp = comparator(key, t.key)
166
- if (cmp === 0) this._root = t
167
- else {
168
- if (cmp < 0) {
169
- node.left = t.left
170
- node.right = t
171
- t.left = null
172
- } else if (cmp > 0) {
173
- node.right = t.right
174
- node.left = t
175
- t.right = null
176
- }
177
- this._size++
178
- this._root = node
179
- }
180
-
97
+ this._root = insert(key, data, this._root, this.comparator)
181
98
  return this._root
182
99
  }
183
100
 
@@ -186,155 +103,38 @@ export class Tree {
186
103
  * @return {Node|null}
187
104
  */
188
105
  remove (key) {
189
- this._root = this._remove(key, this._root, this._comparator)
106
+ this._root = this._remove(key)
190
107
  }
191
108
 
192
109
  /**
193
110
  * Deletes i from the tree if it's there
194
111
  */
195
- _remove (i, t, comparator) {
112
+ _remove (key) {
113
+ if (this._root === null) return null
114
+
196
115
  let x
197
- if (t === null) return null
198
- t = splay(i, t, comparator)
199
- const cmp = comparator(i, t.key)
116
+ const t = splay(key, this._root, this.comparator)
117
+ const cmp = this.comparator(key, t.key)
200
118
  if (cmp === 0) { /* found it */
201
119
  if (t.left === null) {
202
120
  x = t.right
203
121
  } else {
204
- x = splay(i, t.left, comparator)
122
+ x = splay(key, t.left, this.comparator)
205
123
  x.right = t.right
206
124
  }
207
- this._size--
208
125
  return x
209
126
  }
210
127
  return t /* It wasn't there */
211
128
  }
212
129
 
213
- /**
214
- * Removes and returns the node with smallest key
215
- */
216
- pop () {
217
- let node = this._root
218
- if (node) {
219
- while (node.left) node = node.left
220
- this._root = splay(node.key, this._root, this._comparator)
221
- this._root = this._remove(node.key, this._root, this._comparator)
222
- return { key: node.key, data: node.data }
223
- }
224
- return null
225
- }
226
-
227
- /**
228
- * Find without splaying
229
- */
230
- findStatic (key) {
231
- let current = this._root
232
- const compare = this._comparator
233
- while (current) {
234
- const cmp = compare(key, current.key)
235
- if (cmp === 0) return current
236
- else if (cmp < 0) current = current.left
237
- else current = current.right
238
- }
239
- return null
240
- }
241
-
242
130
  find (key) {
243
131
  if (this._root) {
244
- this._root = splay(key, this._root, this._comparator)
245
- if (this._comparator(key, this._root.key) !== 0) return null
132
+ this._root = splay(key, this._root, this.comparator)
133
+ if (this.comparator(key, this._root.key) !== 0) return null
246
134
  }
247
135
  return this._root
248
136
  }
249
137
 
250
- contains (key) {
251
- let current = this._root
252
- const compare = this._comparator
253
- while (current) {
254
- const cmp = compare(key, current.key)
255
- if (cmp === 0) return true
256
- else if (cmp < 0) current = current.left
257
- else current = current.right
258
- }
259
- return false
260
- }
261
-
262
- forEach (visitor, ctx) {
263
- let current = this._root
264
- const Q = [] /* Initialize stack s */
265
- let done = false
266
-
267
- while (!done) {
268
- if (current !== null) {
269
- Q.push(current)
270
- current = current.left
271
- } else {
272
- if (Q.length !== 0) {
273
- current = Q.pop()
274
- visitor.call(ctx, current)
275
-
276
- current = current.right
277
- } else done = true
278
- }
279
- }
280
- return this
281
- }
282
-
283
- /**
284
- * Walk key range from `low` to `high`. Stops if `fn` returns a value.
285
- */
286
- range (low, high, fn, ctx) {
287
- const Q = []
288
- const compare = this._comparator
289
- let node = this._root
290
- let cmp
291
-
292
- while (Q.length !== 0 || node) {
293
- if (node) {
294
- Q.push(node)
295
- node = node.left
296
- } else {
297
- node = Q.pop()
298
- cmp = compare(node.key, high)
299
- if (cmp > 0) {
300
- break
301
- } else if (compare(node.key, low) >= 0) {
302
- if (fn.call(ctx, node)) return this // stop if smth is returned
303
- }
304
- node = node.right
305
- }
306
- }
307
- return this
308
- }
309
-
310
- /**
311
- * Returns array of keys
312
- */
313
- keys () {
314
- const keys = []
315
- this.forEach(({ key }) => keys.push(key))
316
- return keys
317
- }
318
-
319
- /**
320
- * Returns array of all the data in the nodes
321
- */
322
- values () {
323
- const values = []
324
- this.forEach(({ data }) => values.push(data))
325
- return values
326
- }
327
-
328
- min () {
329
- if (this._root) return this.minNode(this._root).key
330
- return null
331
- }
332
-
333
- max () {
334
- if (this._root) return this.maxNode(this._root).key
335
- return null
336
- }
337
-
338
138
  minNode (t = this._root) {
339
139
  if (t) while (t.left) t = t.left
340
140
  return t
@@ -345,255 +145,57 @@ export class Tree {
345
145
  return t
346
146
  }
347
147
 
348
- /**
349
- * Returns node at given index
148
+ /*
149
+ * Return next node from the given.
350
150
  */
351
- at (index) {
352
- let current = this._root
353
- let done = false
354
- let i = 0
355
- const Q = []
356
-
357
- while (!done) {
358
- if (current) {
359
- Q.push(current)
360
- current = current.left
361
- } else {
362
- if (Q.length > 0) {
363
- current = Q.pop()
364
- if (i === index) return current
365
- i++
366
- current = current.right
367
- } else done = true
368
- }
369
- }
370
- return null
371
- }
372
-
373
- next (d) {
374
- let root = this._root
151
+ next (node) {
375
152
  let successor = null
376
153
 
377
- if (d.right) {
378
- successor = d.right
154
+ if (node.right) {
155
+ successor = node.right
379
156
  while (successor.left) successor = successor.left
380
157
  return successor
381
158
  }
382
159
 
383
- const comparator = this._comparator
160
+ let root = this._root
384
161
  while (root) {
385
- const cmp = comparator(d.key, root.key)
162
+ const cmp = this.comparator(node.key, root.key)
386
163
  if (cmp === 0) break
387
- else if (cmp < 0) {
164
+
165
+ if (cmp < 0) {
388
166
  successor = root
389
167
  root = root.left
390
- } else root = root.right
168
+ } else {
169
+ root = root.right
170
+ }
391
171
  }
392
-
393
172
  return successor
394
173
  }
395
174
 
396
- prev (d) {
397
- let root = this._root
175
+ /*
176
+ * Return previous node from the given.
177
+ */
178
+ prev (node) {
398
179
  let predecessor = null
399
180
 
400
- if (d.left !== null) {
401
- predecessor = d.left
181
+ if (node.left) {
182
+ predecessor = node.left
402
183
  while (predecessor.right) predecessor = predecessor.right
403
184
  return predecessor
404
185
  }
405
186
 
406
- const comparator = this._comparator
187
+ let root = this._root
407
188
  while (root) {
408
- const cmp = comparator(d.key, root.key)
189
+ const cmp = this.comparator(node.key, root.key)
409
190
  if (cmp === 0) break
410
- else if (cmp < 0) root = root.left
411
- else {
191
+
192
+ if (cmp < 0) {
193
+ root = root.left
194
+ } else {
412
195
  predecessor = root
413
196
  root = root.right
414
197
  }
415
198
  }
416
199
  return predecessor
417
200
  }
418
-
419
- clear () {
420
- this._root = null
421
- this._size = 0
422
- return this
423
- }
424
-
425
- toList () {
426
- return toList(this._root)
427
- }
428
-
429
- /**
430
- * Bulk-load items. Both array have to be same size
431
- */
432
- load (keys, values = [], presort = false) {
433
- let size = keys.length
434
- const comparator = this._comparator
435
-
436
- // sort if needed
437
- if (presort) sort(keys, values, 0, size - 1, comparator)
438
-
439
- if (this._root === null) { // empty tree
440
- this._root = loadRecursive(keys, values, 0, size)
441
- this._size = size
442
- } else { // that re-builds the whole tree from two in-order traversals
443
- const mergedList = mergeLists(this.toList(), createList(keys, values), comparator)
444
- size = this._size + size
445
- this._root = sortedListToBST({ head: mergedList }, 0, size)
446
- }
447
- return this
448
- }
449
-
450
- isEmpty () { return this._root === null }
451
-
452
- size () { return this._size }
453
- root () { return this._root }
454
-
455
- toString (printNode = (n) => String(n.key)) {
456
- const out = []
457
- printRow(this._root, '', true, (v) => out.push(v), printNode)
458
- return out.join('')
459
- }
460
-
461
- update (key, newKey, newData) {
462
- const comparator = this._comparator
463
- let { left, right } = split(key, this._root, comparator)
464
- if (comparator(key, newKey) < 0) {
465
- right = insert(newKey, newData, right, comparator)
466
- } else {
467
- left = insert(newKey, newData, left, comparator)
468
- }
469
- this._root = merge(left, right, comparator)
470
- }
471
-
472
- split (key) {
473
- return split(key, this._root, this._comparator)
474
- }
475
-
476
- * [Symbol.iterator] () {
477
- let n = this.minNode()
478
- while (n) {
479
- yield n
480
- n = this.next(n)
481
- }
482
- }
483
- }
484
-
485
- const loadRecursive = (keys, values, start, end) => {
486
- const size = end - start
487
- if (size > 0) {
488
- const middle = start + Math.floor(size / 2)
489
- const key = keys[middle]
490
- const data = values[middle]
491
- const node = new Node(key, data)
492
- node.left = loadRecursive(keys, values, start, middle)
493
- node.right = loadRecursive(keys, values, middle + 1, end)
494
- return node
495
- }
496
- return null
497
- }
498
-
499
- const createList = (keys, values) => {
500
- const head = new Node(null, null)
501
- let p = head
502
- for (let i = 0; i < keys.length; i++) {
503
- p = p.next = new Node(keys[i], values[i])
504
- }
505
- p.next = null
506
- return head.next
507
- }
508
-
509
- const toList = (root) => {
510
- let current = root
511
- const Q = []
512
- let done = false
513
-
514
- const head = new Node(null, null)
515
- let p = head
516
-
517
- while (!done) {
518
- if (current) {
519
- Q.push(current)
520
- current = current.left
521
- } else {
522
- if (Q.length > 0) {
523
- current = p = p.next = Q.pop()
524
- current = current.right
525
- } else done = true
526
- }
527
- }
528
- p.next = null // that'll work even if the tree was empty
529
- return head.next
530
- }
531
-
532
- const sortedListToBST = (list, start, end) => {
533
- const size = end - start
534
- if (size > 0) {
535
- const middle = start + Math.floor(size / 2)
536
- const left = sortedListToBST(list, start, middle)
537
-
538
- const root = list.head
539
- root.left = left
540
-
541
- list.head = list.head.next
542
-
543
- root.right = sortedListToBST(list, middle + 1, end)
544
- return root
545
- }
546
- return null
547
- }
548
-
549
- const mergeLists = (l1, l2, compare) => {
550
- const head = new Node(null, null) // dummy
551
- let p = head
552
-
553
- let p1 = l1
554
- let p2 = l2
555
-
556
- while (p1 !== null && p2 !== null) {
557
- if (compare(p1.key, p2.key) < 0) {
558
- p.next = p1
559
- p1 = p1.next
560
- } else {
561
- p.next = p2
562
- p2 = p2.next
563
- }
564
- p = p.next
565
- }
566
-
567
- if (p1 !== null) {
568
- p.next = p1
569
- } else if (p2 !== null) {
570
- p.next = p2
571
- }
572
-
573
- return head.next
574
- }
575
-
576
- const sort = (keys, values, left, right, compare) => {
577
- if (left >= right) return
578
-
579
- const pivot = keys[(left + right) >> 1]
580
- let i = left - 1
581
- let j = right + 1
582
-
583
- while (true) {
584
- do i++; while (compare(keys[i], pivot) < 0)
585
- do j--; while (compare(keys[j], pivot) > 0)
586
- if (i >= j) break
587
-
588
- let tmp = keys[i]
589
- keys[i] = keys[j]
590
- keys[j] = tmp
591
-
592
- tmp = values[i]
593
- values[i] = values[j]
594
- values[j] = tmp
595
- }
596
-
597
- sort(keys, values, left, j, compare)
598
- sort(keys, values, j + 1, right, compare)
599
201
  }
@@ -22,7 +22,7 @@ export const subdivideSegments = (eventQueue, subject, clipping, sbbox, cbbox, o
22
22
  let prev, next, begin
23
23
 
24
24
  while (eventQueue.length !== 0) {
25
- let event = eventQueue.pop()
25
+ const event = eventQueue.pop()
26
26
  sortedEvents.push(event)
27
27
 
28
28
  // optimization by bboxes for intersection and difference goes here
@@ -62,15 +62,15 @@ export const subdivideSegments = (eventQueue, subject, clipping, sbbox, cbbox, o
62
62
  }
63
63
  }
64
64
  } else {
65
- event = event.otherEvent
66
- next = prev = sweepLine.find(event)
65
+ next = prev = sweepLine.find(event.otherEvent)
67
66
 
68
67
  if (prev && next) {
68
+ // FIXME is this correct? begin is assigned if event.left, not every iterration
69
69
  if (prev !== begin) prev = sweepLine.prev(prev)
70
70
  else prev = null
71
71
 
72
72
  next = sweepLine.next(next)
73
- sweepLine.remove(event)
73
+ sweepLine.remove(event.otherEvent)
74
74
 
75
75
  if (next && prev) {
76
76
  possibleIntersection(prev.key, next.key, eventQueue)