@jscad/modeling 3.0.1-alpha.0 → 3.0.3-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.
- package/CHANGELOG.md +22 -0
- package/dist/jscad-modeling.es.js +2 -2
- package/dist/jscad-modeling.min.js +2 -2
- package/package.json +2 -2
- package/src/colors/colorize.test.js +1 -1
- package/src/geometries/geom2/index.d.ts +0 -2
- package/src/geometries/geom2/index.js +0 -2
- package/src/geometries/geom3/applyTransforms.test.js +2 -2
- package/src/geometries/geom3/clone.test.js +2 -2
- package/src/geometries/geom3/create.js +1 -9
- package/src/geometries/geom3/{fromPoints.d.ts → fromVertices.d.ts} +1 -1
- package/src/geometries/geom3/{fromPoints.js → fromVertices.js} +3 -2
- package/src/geometries/geom3/{fromPoints.test.js → fromVertices.test.js} +6 -6
- package/src/geometries/geom3/{fromPointsConvex.d.ts → fromVerticesConvex.d.ts} +1 -1
- package/src/geometries/geom3/fromVerticesConvex.js +25 -0
- package/src/geometries/geom3/{fromPointsConvex.test.js → fromVerticesConvex.test.js} +3 -3
- package/src/geometries/geom3/index.d.ts +3 -5
- package/src/geometries/geom3/index.js +4 -6
- package/src/geometries/geom3/invert.test.js +2 -2
- package/src/geometries/geom3/isA.test.js +2 -2
- package/src/geometries/geom3/toString.test.js +2 -2
- package/src/geometries/geom3/{toPoints.d.ts → toVertices.d.ts} +1 -1
- package/src/geometries/geom3/{toPoints.js → toVertices.js} +3 -2
- package/src/geometries/geom3/{toPoints.test.js → toVertices.test.js} +4 -4
- package/src/geometries/geom3/transform.test.js +2 -2
- package/src/geometries/geom3/validate.test.js +4 -4
- package/src/geometries/index.d.ts +1 -0
- package/src/geometries/index.js +1 -0
- package/src/geometries/path2/appendBezier.js +1 -1
- package/src/geometries/path2/create.js +1 -10
- package/src/geometries/path2/index.d.ts +0 -2
- package/src/geometries/path2/index.js +0 -2
- package/src/geometries/path3/applyTransforms.js +22 -0
- package/src/geometries/path3/applyTransforms.test.js +28 -0
- package/src/geometries/path3/close.d.ts +3 -0
- package/src/geometries/path3/close.js +31 -0
- package/src/geometries/path3/close.test.js +43 -0
- package/src/geometries/path3/concat.d.ts +3 -0
- package/src/geometries/path3/concat.js +36 -0
- package/src/geometries/path3/concat.test.js +35 -0
- package/src/geometries/path3/create.d.ts +4 -0
- package/src/geometries/path3/create.js +30 -0
- package/src/geometries/path3/create.test.js +8 -0
- package/src/geometries/path3/equals.d.ts +3 -0
- package/src/geometries/path3/equals.js +48 -0
- package/src/geometries/path3/equals.test.js +38 -0
- package/src/geometries/path3/fromVertices.d.ts +8 -0
- package/src/geometries/path3/fromVertices.js +45 -0
- package/src/geometries/path3/fromVertices.test.js +33 -0
- package/src/geometries/path3/index.d.ts +13 -0
- package/src/geometries/path3/index.js +21 -0
- package/src/geometries/path3/isA.d.ts +3 -0
- package/src/geometries/path3/isA.js +20 -0
- package/src/geometries/path3/isA.test.js +19 -0
- package/src/geometries/path3/reverse.d.ts +3 -0
- package/src/geometries/path3/reverse.js +19 -0
- package/src/geometries/path3/reverse.test.js +9 -0
- package/src/geometries/path3/toString.d.ts +3 -0
- package/src/geometries/path3/toString.js +24 -0
- package/src/geometries/path3/toVertices.d.ts +4 -0
- package/src/geometries/path3/toVertices.js +16 -0
- package/src/geometries/path3/toVertices.test.js +13 -0
- package/src/geometries/path3/transform.d.ts +4 -0
- package/src/geometries/path3/transform.js +21 -0
- package/src/geometries/path3/transform.test.js +50 -0
- package/src/geometries/path3/type.d.ts +10 -0
- package/src/geometries/path3/validate.d.ts +1 -0
- package/src/geometries/path3/validate.js +41 -0
- package/src/geometries/poly2/create.js +1 -6
- package/src/geometries/poly3/create.js +1 -6
- package/src/geometries/poly3/index.js +1 -1
- package/src/geometries/poly3/measureBoundingBox.js +2 -0
- package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
- package/src/geometries/poly3/measureBoundingSphere.js +25 -8
- package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
- package/src/index.js +41 -0
- package/src/measurements/measureBoundingSphere.js +2 -6
- package/src/operations/booleans/intersectGeom3.test.js +4 -4
- package/src/operations/booleans/martinez/compareEvents.js +2 -7
- package/src/operations/booleans/martinez/connectEdges.js +30 -41
- package/src/operations/booleans/martinez/contour.js +1 -1
- package/src/operations/booleans/martinez/divideSegment.js +12 -11
- package/src/operations/booleans/martinez/fillQueue.js +24 -28
- package/src/operations/booleans/martinez/index.js +2 -1
- package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
- package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
- package/src/operations/booleans/martinez/splaytree.js +59 -457
- package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
- package/src/operations/booleans/martinez/sweepEvent.js +3 -17
- package/src/operations/booleans/subtractGeom3.test.js +4 -4
- package/src/operations/booleans/trees/Node.js +25 -27
- package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
- package/src/operations/booleans/trees/Tree.js +9 -4
- package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
- package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
- package/src/operations/booleans/unionGeom3.test.js +5 -5
- package/src/operations/extrusions/extrudeFromSlices.test.js +6 -6
- package/src/operations/extrusions/extrudeLinear.test.js +8 -8
- package/src/operations/extrusions/extrudeRotate.test.js +12 -12
- package/src/operations/extrusions/extrudeWalls.js +3 -1
- package/src/operations/hulls/hull.test.js +5 -5
- package/src/operations/hulls/hullChain.test.js +5 -5
- package/src/operations/hulls/hullPoints2.js +20 -28
- package/src/operations/hulls/toUniquePoints.js +2 -2
- package/src/operations/modifiers/generalize.test.js +6 -6
- package/src/operations/modifiers/insertTjunctions.test.js +2 -2
- package/src/operations/modifiers/mergePolygons.js +2 -3
- package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
- package/src/operations/modifiers/retessellate.test.js +10 -10
- package/src/operations/modifiers/snap.test.js +4 -4
- package/src/operations/offsets/offsetGeom3.test.js +4 -4
- package/src/operations/transforms/center.test.js +7 -7
- package/src/operations/transforms/mirror.test.js +7 -7
- package/src/operations/transforms/rotate.test.js +7 -7
- package/src/operations/transforms/scale.test.js +7 -7
- package/src/operations/transforms/transform.test.js +2 -2
- package/src/operations/transforms/translate.test.js +7 -7
- package/src/primitives/cube.test.js +4 -4
- package/src/primitives/cuboid.test.js +4 -4
- package/src/primitives/cylinder.test.js +5 -5
- package/src/primitives/cylinderElliptic.test.js +9 -9
- package/src/primitives/ellipsoid.test.js +5 -5
- package/src/primitives/geodesicSphere.test.js +4 -4
- package/src/primitives/polyhedron.test.js +2 -2
- package/src/primitives/roundedCuboid.test.js +7 -7
- package/src/primitives/roundedCylinder.test.js +9 -9
- package/src/primitives/sphere.test.js +5 -5
- package/src/primitives/torus.test.js +4 -4
- package/src/geometries/geom2/fromCompactBinary.d.ts +0 -3
- package/src/geometries/geom2/fromCompactBinary.js +0 -40
- package/src/geometries/geom2/fromToCompactBinary.test.js +0 -100
- package/src/geometries/geom2/toCompactBinary.d.ts +0 -3
- package/src/geometries/geom2/toCompactBinary.js +0 -56
- package/src/geometries/geom3/fromCompactBinary.d.ts +0 -3
- package/src/geometries/geom3/fromCompactBinary.js +0 -42
- package/src/geometries/geom3/fromPointsConvex.js +0 -25
- package/src/geometries/geom3/fromToCompactBinary.test.js +0 -139
- package/src/geometries/geom3/toCompactBinary.d.ts +0 -3
- package/src/geometries/geom3/toCompactBinary.js +0 -66
- package/src/geometries/path2/fromCompactBinary.d.ts +0 -3
- package/src/geometries/path2/fromCompactBinary.js +0 -31
- package/src/geometries/path2/fromToCompactBinary.test.js +0 -114
- package/src/geometries/path2/toCompactBinary.d.ts +0 -3
- package/src/geometries/path2/toCompactBinary.js +0 -50
|
@@ -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 = (
|
|
24
|
+
const splay = (key, t, comparator) => {
|
|
25
25
|
const N = new Node(null, null)
|
|
26
|
-
let
|
|
27
|
-
let
|
|
26
|
+
let left = N
|
|
27
|
+
let right = N
|
|
28
28
|
|
|
29
29
|
while (true) {
|
|
30
|
-
const cmp = comparator(
|
|
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
|
-
|
|
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
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
-
|
|
52
|
+
left.right = t /* link left */
|
|
53
|
+
left = t
|
|
58
54
|
t = t.right
|
|
59
55
|
} else break
|
|
60
56
|
}
|
|
61
57
|
/* assemble */
|
|
62
|
-
|
|
63
|
-
|
|
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 = (
|
|
70
|
-
const node = new Node(
|
|
66
|
+
const insert = (key, data, root, comparator) => {
|
|
67
|
+
const node = new Node(key, data)
|
|
71
68
|
|
|
72
|
-
if (
|
|
73
|
-
node.left = node.right = null
|
|
69
|
+
if (root === null) {
|
|
74
70
|
return node
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
const cmp = comparator(
|
|
73
|
+
root = splay(key, root, comparator)
|
|
74
|
+
const cmp = comparator(key, root.key)
|
|
79
75
|
if (cmp < 0) {
|
|
80
|
-
node.left =
|
|
81
|
-
node.right =
|
|
82
|
-
|
|
76
|
+
node.left = root.left
|
|
77
|
+
node.right = root
|
|
78
|
+
root.left = null
|
|
83
79
|
} else if (cmp >= 0) {
|
|
84
|
-
node.right =
|
|
85
|
-
node.left =
|
|
86
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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 (
|
|
112
|
+
_remove (key) {
|
|
113
|
+
if (this._root === null) return null
|
|
114
|
+
|
|
196
115
|
let x
|
|
197
|
-
|
|
198
|
-
|
|
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(
|
|
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.
|
|
245
|
-
if (this.
|
|
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
|
-
*
|
|
148
|
+
/*
|
|
149
|
+
* Return next node from the given.
|
|
350
150
|
*/
|
|
351
|
-
|
|
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 (
|
|
378
|
-
successor =
|
|
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
|
-
|
|
160
|
+
let root = this._root
|
|
384
161
|
while (root) {
|
|
385
|
-
const cmp = comparator(
|
|
162
|
+
const cmp = this.comparator(node.key, root.key)
|
|
386
163
|
if (cmp === 0) break
|
|
387
|
-
|
|
164
|
+
|
|
165
|
+
if (cmp < 0) {
|
|
388
166
|
successor = root
|
|
389
167
|
root = root.left
|
|
390
|
-
} else
|
|
168
|
+
} else {
|
|
169
|
+
root = root.right
|
|
170
|
+
}
|
|
391
171
|
}
|
|
392
|
-
|
|
393
172
|
return successor
|
|
394
173
|
}
|
|
395
174
|
|
|
396
|
-
|
|
397
|
-
|
|
175
|
+
/*
|
|
176
|
+
* Return previous node from the given.
|
|
177
|
+
*/
|
|
178
|
+
prev (node) {
|
|
398
179
|
let predecessor = null
|
|
399
180
|
|
|
400
|
-
if (
|
|
401
|
-
predecessor =
|
|
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
|
-
|
|
187
|
+
let root = this._root
|
|
407
188
|
while (root) {
|
|
408
|
-
const cmp = comparator(
|
|
189
|
+
const cmp = this.comparator(node.key, root.key)
|
|
409
190
|
if (cmp === 0) break
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
@@ -9,9 +9,9 @@ export class SweepEvent {
|
|
|
9
9
|
* @param {boolean} left
|
|
10
10
|
* @param {SweepEvent=} otherEvent
|
|
11
11
|
* @param {boolean} isSubject
|
|
12
|
-
* @param {number}
|
|
12
|
+
* @param {number} type OPTIONAL
|
|
13
13
|
*/
|
|
14
|
-
constructor (point, left, otherEvent, isSubject,
|
|
14
|
+
constructor (point, left, otherEvent, isSubject, type = NORMAL) {
|
|
15
15
|
/**
|
|
16
16
|
* Is left endpoint?
|
|
17
17
|
* @type {Boolean}
|
|
@@ -39,7 +39,7 @@ export class SweepEvent {
|
|
|
39
39
|
* Edge contribution type
|
|
40
40
|
* @type {Number}
|
|
41
41
|
*/
|
|
42
|
-
this.type =
|
|
42
|
+
this.type = type
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* In-out transition for the sweepline crossing polygon
|
|
@@ -115,18 +115,4 @@ export class SweepEvent {
|
|
|
115
115
|
get inResult () {
|
|
116
116
|
return this.resultTransition !== 0
|
|
117
117
|
}
|
|
118
|
-
|
|
119
|
-
clone () {
|
|
120
|
-
const copy = new SweepEvent(
|
|
121
|
-
this.point, this.left, this.otherEvent, this.isSubject, this.type)
|
|
122
|
-
|
|
123
|
-
copy.contourId = this.contourId
|
|
124
|
-
copy.resultTransition = this.resultTransition
|
|
125
|
-
copy.prevInResult = this.prevInResult
|
|
126
|
-
copy.isExteriorRing = this.isExteriorRing
|
|
127
|
-
copy.inOut = this.inOut
|
|
128
|
-
copy.otherInOut = this.otherInOut
|
|
129
|
-
|
|
130
|
-
return copy
|
|
131
|
-
}
|
|
132
118
|
}
|