@jscad/modeling 3.0.1-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 (32) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/jscad-modeling.es.js +2 -2
  3. package/dist/jscad-modeling.min.js +2 -2
  4. package/package.json +2 -2
  5. package/src/geometries/path2/appendBezier.js +1 -1
  6. package/src/geometries/poly3/index.js +1 -1
  7. package/src/geometries/poly3/measureBoundingBox.js +2 -0
  8. package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
  9. package/src/geometries/poly3/measureBoundingSphere.js +25 -8
  10. package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
  11. package/src/index.js +41 -0
  12. package/src/measurements/measureBoundingSphere.js +2 -6
  13. package/src/operations/booleans/martinez/compareEvents.js +2 -7
  14. package/src/operations/booleans/martinez/connectEdges.js +30 -41
  15. package/src/operations/booleans/martinez/contour.js +1 -1
  16. package/src/operations/booleans/martinez/divideSegment.js +12 -11
  17. package/src/operations/booleans/martinez/fillQueue.js +24 -28
  18. package/src/operations/booleans/martinez/index.js +2 -1
  19. package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
  20. package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
  21. package/src/operations/booleans/martinez/splaytree.js +59 -457
  22. package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
  23. package/src/operations/booleans/martinez/sweepEvent.js +3 -17
  24. package/src/operations/booleans/trees/Node.js +25 -27
  25. package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
  26. package/src/operations/booleans/trees/Tree.js +9 -4
  27. package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
  28. package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
  29. package/src/operations/extrusions/extrudeWalls.js +3 -1
  30. package/src/operations/hulls/hullPoints2.js +20 -28
  31. package/src/operations/modifiers/mergePolygons.js +2 -3
  32. package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
@@ -5,7 +5,7 @@ import * as poly3 from '../../../geometries/poly3/index.js'
5
5
  // # class Node
6
6
  // Holds a node in a BSP tree.
7
7
  // A BSP tree is built from a collection of polygons by picking a polygon to split along.
8
- // Polygons are not stored directly in the tree, but in PolygonTreeNodes, stored in this.polygontreenodes.
8
+ // Polygons are not stored directly in the BSP tree, but in PolygonTreeNodes, stored in this.polygontreenodes.
9
9
  // Those PolygonTreeNodes are children of the owning Tree.polygonTree.
10
10
  // This is not a leafy BSP tree since there is no distinction between internal and leaf nodes.
11
11
  export class Node {
@@ -23,17 +23,16 @@ export class Node {
23
23
  let node
24
24
  for (let i = 0; i < queue.length; i++) {
25
25
  node = queue[i]
26
- if (node.plane) node.plane = plane.flip(plane.create(), node.plane)
27
- if (node.front) queue.push(node.front)
28
- if (node.back) queue.push(node.back)
26
+ if (node.plane !== null) node.plane = plane.flip(plane.create(), node.plane)
27
+ if (node.front !== null) queue.push(node.front)
28
+ if (node.back !== null) queue.push(node.back)
29
29
  const temp = node.front
30
30
  node.front = node.back
31
31
  node.back = temp
32
32
  }
33
33
  }
34
34
 
35
- // clip polygontreenodes to our plane
36
- // calls remove() for all clipped PolygonTreeNodes
35
+ // Clip the given tree nodes to our plane
37
36
  clipPolygons (polygonTreeNodes, alsoRemoveCoplanarFront) {
38
37
  let current = { node: this, polygonTreeNodes }
39
38
  let node
@@ -43,26 +42,27 @@ export class Node {
43
42
  node = current.node
44
43
  polygonTreeNodes = current.polygonTreeNodes
45
44
 
46
- if (node.plane) {
45
+ if (node.plane !== null) {
47
46
  const plane = node.plane
48
47
 
49
48
  const backNodes = []
50
49
  const frontNodes = []
51
50
  const coplanarFrontNodes = alsoRemoveCoplanarFront ? backNodes : frontNodes
52
- polygonTreeNodes.forEach((treeNode) => {
53
- if (!treeNode.isRemoved()) {
54
- // split this polygon tree node using the plane
55
- // NOTE: children are added to the tree if there are spanning polygons
51
+ for (let i = 0; i < polygonTreeNodes.length; i++) {
52
+ const treeNode = polygonTreeNodes[i]
53
+ if (treeNode.canSplit()) {
54
+ // split this tree node using the plane
55
+ // NOTE: children are added to the tree node if there are spanning polygons
56
56
  treeNode.splitByPlane(plane, coplanarFrontNodes, backNodes, frontNodes, backNodes)
57
57
  }
58
- })
58
+ }
59
59
 
60
- if (node.front && (frontNodes.length > 0)) {
60
+ if (node.front !== null && frontNodes.length > 0) {
61
61
  // add front node for further splitting
62
62
  stack.push({ node: node.front, polygonTreeNodes: frontNodes })
63
63
  }
64
64
  const numBackNodes = backNodes.length
65
- if (node.back && (numBackNodes > 0)) {
65
+ if (node.back !== null && numBackNodes > 0) {
66
66
  // add back node for further splitting
67
67
  stack.push({ node: node.back, polygonTreeNodes: backNodes })
68
68
  } else {
@@ -76,17 +76,16 @@ export class Node {
76
76
  } while (current !== undefined)
77
77
  }
78
78
 
79
- // Remove all polygons in this BSP tree that are inside the other BSP tree
80
- // `tree`.
81
- clipTo (tree, alsoRemoveCoplanarFront) {
79
+ // Remove all polygons in this BSP tree that are inside the given BSP tree
80
+ clipTo (bsptree, alsoRemoveCoplanarFront) {
82
81
  let node = this
83
82
  const stack = []
84
83
  do {
85
84
  if (node.polygontreenodes.length > 0) {
86
- tree.rootnode.clipPolygons(node.polygontreenodes, alsoRemoveCoplanarFront)
85
+ bsptree.clipPolygons(node.polygontreenodes, alsoRemoveCoplanarFront)
87
86
  }
88
- if (node.front) stack.push(node.front)
89
- if (node.back) stack.push(node.back)
87
+ if (node.front !== null) stack.push(node.front)
88
+ if (node.back !== null) stack.push(node.back)
90
89
  node = stack.pop()
91
90
  } while (node !== undefined)
92
91
  }
@@ -103,7 +102,7 @@ export class Node {
103
102
  current = stack.pop()
104
103
  continue
105
104
  }
106
- if (!node.plane) {
105
+ if (node.plane === null) {
107
106
  let index = 0 // default
108
107
  index = Math.floor(len / 2)
109
108
  // index = len >> 1
@@ -118,21 +117,20 @@ export class Node {
118
117
  }
119
118
 
120
119
  if (frontNodes.length > 0) {
121
- if (!node.front) node.front = new Node(node)
120
+ if (node.front === null) node.front = new Node(node)
122
121
 
123
122
  // unable to split by any of the current nodes
124
123
  const stopCondition = len === frontNodes.length && backNodes.length === 0
125
- if (stopCondition) node.front.polygontreenodes = frontNodes
126
- else stack.push({ node: node.front, polygonTreeNodes: frontNodes })
124
+
125
+ stopCondition ? node.front.polygontreenodes = frontNodes : stack.push({ node: node.front, polygonTreeNodes: frontNodes })
127
126
  }
128
127
  if (backNodes.length > 0) {
129
- if (!node.back) node.back = new Node(node)
128
+ if (node.back === null) node.back = new Node(node)
130
129
 
131
130
  // unable to split by any of the current nodes
132
131
  const stopCondition = len === backNodes.length && frontNodes.length === 0
133
132
 
134
- if (stopCondition) node.back.polygontreenodes = backNodes
135
- else stack.push({ node: node.back, polygonTreeNodes: backNodes })
133
+ stopCondition ? node.back.polygontreenodes = backNodes : stack.push({ node: node.back, polygonTreeNodes: backNodes })
136
134
  }
137
135
 
138
136
  current = stack.pop()
@@ -6,6 +6,9 @@ import * as poly3 from '../../../geometries/poly3/index.js'
6
6
 
7
7
  import { splitPolygonByPlane } from './splitPolygonByPlane.js'
8
8
 
9
+ // cached values to boost performance
10
+ const splitResult = { type: 0, front: null, back: null }
11
+
9
12
  // # class PolygonTreeNode
10
13
  // This class manages hierarchical splits of polygons.
11
14
  // At the top is a root node which does not hold a polygon, only child PolygonTreeNodes.
@@ -13,72 +16,72 @@ import { splitPolygonByPlane } from './splitPolygonByPlane.js'
13
16
  // The polygons can be in different planes.
14
17
  // splitByPlane() splits a node by a plane. If the plane intersects the polygon,
15
18
  // two new child nodes are created holding the split polygon.
16
- // getPolygons() retrieves the polygons from the tree. If for PolygonTreeNode the polygon is split but
19
+ // getPolygons() retrieves the polygons from the node. If for PolygonTreeNode the polygon is split but
17
20
  // the two split parts (child nodes) are still intact, then the unsplit polygon is returned.
18
21
  // This ensures that we can safely split a polygon into many fragments. If the fragments are untouched,
19
22
  // getPolygons() will return the original unsplit polygon instead of the fragments.
20
- // remove() removes a polygon from the tree. Once a polygon is removed, the parent polygons are invalidated
23
+ // remove() removes a polygon from the node. Once a polygon is removed, the parent polygons are invalidated
21
24
  // since they are no longer intact.
22
25
  export class PolygonTreeNode {
23
26
  // constructor creates the root node
24
27
  constructor (parent, polygon) {
25
28
  this.parent = parent
26
- this.children = []
27
29
  this.polygon = polygon
28
- this.removed = false // state of branch or leaf
30
+ this.children = []
29
31
  }
30
32
 
31
- // fill the tree with polygons. Should be called on the root node only; child nodes must
33
+ // fill the node with polygons. Should be called on the root node only; child nodes must
32
34
  // always be a derivate (split) of the parent node.
33
35
  addPolygons (polygons) {
34
36
  // new polygons can only be added to root node; children can only be split polygons
35
- if (!this.isRootNode()) {
36
- throw new Error('Assertion failed')
37
+ if (!this.isRootNode()) throw new Error('PolygonTreeNode01')
38
+
39
+ for (let i = 0; i < polygons.length; i++) {
40
+ this.addChild(polygons[i])
37
41
  }
38
- const _this = this
39
- polygons.forEach((polygon) => {
40
- _this.addChild(polygon)
41
- })
42
42
  }
43
43
 
44
44
  // remove a node
45
45
  // - the siblings become toplevel nodes
46
46
  // - the parent is removed recursively
47
47
  remove () {
48
- if (!this.removed) {
49
- this.removed = true
50
- this.polygon = null
48
+ this.polygon = null
51
49
 
52
- // remove ourselves from the parent's children list:
53
- const parentschildren = this.parent.children
54
- const i = parentschildren.indexOf(this)
55
- if (i < 0) throw new Error('Assertion failed')
56
- parentschildren.splice(i, 1)
50
+ // remove ourselves from the parent's children list:
51
+ const parentschildren = this.parent.children
52
+ const i = parentschildren.indexOf(this)
53
+ if (i < 0) throw new Error('PolyTreeNode02')
54
+ parentschildren.splice(i, 1)
57
55
 
58
- // invalidate the parent's polygon, and of all parents above it:
59
- this.parent.recursivelyInvalidatePolygon()
60
- }
56
+ // invalidate the parent's polygon, and of all parents above it:
57
+ this.parent._recursivelyInvalidatePolygon()
61
58
  }
62
59
 
63
- isRemoved () {
64
- return this.removed
60
+ /*
61
+ * Can the node be split, either base polygon or children
62
+ */
63
+ canSplit () {
64
+ return this.polygon != null || this.children.length > 0
65
65
  }
66
66
 
67
67
  isRootNode () {
68
68
  return !this.parent
69
69
  }
70
70
 
71
- // invert all polygons in the tree. Call on the root node
71
+ // invert all polygons in the node. Call on the root node
72
72
  invert () {
73
- if (!this.isRootNode()) throw new Error('Assertion failed') // can only call this on the root node
74
- this.invertSub()
73
+ if (!this.isRootNode()) throw new Error('PolyTreeNode03')
74
+ this._invertSub()
75
75
  }
76
76
 
77
77
  getPolygon () {
78
- if (!this.polygon) throw new Error('Assertion failed') // doesn't have a polygon, which means that it has been broken down
78
+ if (this.polygon === null) throw new Error('PolyTreeNode04')
79
79
  return this.polygon
80
80
  }
81
81
 
82
+ /*
83
+ * Get all polygons from the node, and add to the result
84
+ */
82
85
  getPolygons (result) {
83
86
  let children = [this]
84
87
  const queue = [children]
@@ -87,23 +90,37 @@ export class PolygonTreeNode {
87
90
  children = queue[i]
88
91
  for (j = 0, l = children.length; j < l; j++) { // ok to cache length
89
92
  node = children[j]
90
- if (node.polygon) {
91
- // the polygon hasn't been broken yet. We can ignore the children and return our polygon:
93
+ if (node.polygon !== null) {
94
+ // the polygon hasn't been broken yet. We can ignore the children and return our polygon
92
95
  result.push(node.polygon)
93
96
  } else {
94
- // our polygon has been split up and broken, so gather all subpolygons from the children
95
- if (node.children.length > 0) queue.push(node.children)
97
+ // our polygon has been split up and broken, so gather all subpolygons
98
+ if (node.children.length > 0) {
99
+ queue.push(node.children)
100
+ }
96
101
  }
97
102
  }
98
103
  }
99
104
  }
100
105
 
101
- // split the node by a plane; add the resulting nodes to the frontNodes and backNodes array
102
- // If the plane doesn't intersect the polygon, the 'this' object is added to one of the arrays
103
- // If the plane does intersect the polygon, two new child nodes are created for the front and back fragments,
104
- // and added to both arrays.
105
- splitByPlane (plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes) {
106
- if (this.children.length) {
106
+ // NOTE: This version of getPolygons() is much SLOWER.
107
+ getPolygonsNew (result) {
108
+ if (this.polygon !== null) {
109
+ // the polygon hasn't been broken yet, so return the original polygon
110
+ result.push(this.polygon)
111
+ } else {
112
+ // the polygon has been split, so gather all polygons from the children
113
+ for (let i = 0; i < this.children.length; i++) {
114
+ const node = this.children[i]
115
+ node.getPolygons(result)
116
+ }
117
+ }
118
+ }
119
+
120
+ // split the node by a plane, adding the resulting nodes to the frontNodes and backNodes array
121
+ // Also see canSplit()
122
+ splitByPlaneOld (plane, coplanarfrontnodes, coplanarbacknodes, frontnodes, backnodes) {
123
+ if (this.children.length > 0) {
107
124
  const queue = [this.children]
108
125
  let i
109
126
  let j
@@ -117,68 +134,90 @@ export class PolygonTreeNode {
117
134
  if (node.children.length > 0) {
118
135
  queue.push(node.children)
119
136
  } else {
120
- // no children. Split the polygon:
121
- node._splitByPlane(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes)
137
+ if (this.polygon !== null) {
138
+ // no children. Split the polygon:
139
+ node._splitByPlane(plane, coplanarfrontnodes, coplanarbacknodes, frontnodes, backnodes)
140
+ }
122
141
  }
123
142
  }
124
143
  }
125
144
  } else {
126
- this._splitByPlane(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes)
145
+ if (this.polygon !== null) {
146
+ this._splitByPlane(plane, coplanarfrontnodes, coplanarbacknodes, frontnodes, backnodes)
147
+ }
148
+ }
149
+ }
150
+
151
+ splitByPlane (plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes) {
152
+ if (this.children.length > 0) {
153
+ // the polygon has been split, so split the children by the given plane
154
+ for (let i = 0; i < this.children.length; i++) {
155
+ const node = this.children[i]
156
+ node.splitByPlane(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes)
157
+ }
158
+ } else {
159
+ if (this.polygon !== null) {
160
+ // the polygon hasn't been split, so split this node by the given plane
161
+ this._splitByPlane(plane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes)
162
+ }
127
163
  }
128
164
  }
129
165
 
166
+ // PRIVATE
167
+ // If the plane doesn't intersect the polygon, the 'this' object is added to one of the arrays
168
+ // If the plane does intersect the polygon, two new child nodes are created for the front and back fragments,
169
+ // and added to both arrays.
130
170
  // only to be called for nodes with no children
131
171
  _splitByPlane (splane, coplanarFrontNodes, coplanarBackNodes, frontNodes, backNodes) {
132
- const polygon = this.polygon
133
- if (polygon) {
134
- const bound = poly3.measureBoundingSphere(polygon)
135
- const sphereRadius = bound[3] + EPS // ensure radius is LARGER then polygon
136
- const sphereCenter = bound
137
- const d = vec3.dot(splane, sphereCenter) - splane[3]
138
- if (d > sphereRadius) {
139
- frontNodes.push(this)
140
- } else if (d < -sphereRadius) {
141
- backNodes.push(this)
142
- } else {
143
- const splitResult = splitPolygonByPlane(splane, polygon)
144
- switch (splitResult.type) {
145
- case 0:
146
- // coplanar front:
147
- coplanarFrontNodes.push(this)
148
- break
172
+ // perform a quick check to see the plane is outside the bounds of the polygon
173
+ const bounds = poly3.measureBoundingSphereAndCache(this.polygon)
174
+ const sphereRadius = bounds[3] + EPS // ensure radius is LARGER then polygon
175
+ const d = vec3.dot(splane, bounds) - splane[3]
176
+ if (d > sphereRadius) {
177
+ frontNodes.push(this)
178
+ return
179
+ } else if (d < -sphereRadius) {
180
+ backNodes.push(this)
181
+ return
182
+ }
149
183
 
150
- case 1:
151
- // coplanar back:
152
- coplanarBackNodes.push(this)
153
- break
184
+ // the plane may intersect the polyogn
185
+ splitPolygonByPlane(splitResult, splane, this.polygon)
186
+ switch (splitResult.type) {
187
+ case 0:
188
+ // coplanar front:
189
+ coplanarFrontNodes.push(this)
190
+ break
154
191
 
155
- case 2:
156
- // front:
157
- frontNodes.push(this)
158
- break
192
+ case 1:
193
+ // coplanar back:
194
+ coplanarBackNodes.push(this)
195
+ break
159
196
 
160
- case 3:
161
- // back:
162
- backNodes.push(this)
163
- break
197
+ case 2:
198
+ // front:
199
+ frontNodes.push(this)
200
+ break
164
201
 
165
- case 4:
166
- // spanning:
167
- if (splitResult.front) {
168
- const frontNode = this.addChild(splitResult.front)
169
- frontNodes.push(frontNode)
170
- }
171
- if (splitResult.back) {
172
- const backNode = this.addChild(splitResult.back)
173
- backNodes.push(backNode)
174
- }
175
- break
202
+ case 3:
203
+ // back:
204
+ backNodes.push(this)
205
+ break
206
+
207
+ case 4:
208
+ // spanning:
209
+ if (splitResult.front !== null) {
210
+ const frontNode = this.addChild(splitResult.front)
211
+ frontNodes.push(frontNode)
176
212
  }
177
- }
213
+ if (splitResult.back !== null) {
214
+ const backNode = this.addChild(splitResult.back)
215
+ backNodes.push(backNode)
216
+ }
217
+ break
178
218
  }
179
219
  }
180
220
 
181
- // PRIVATE methods from here:
182
221
  // add child to a node
183
222
  // this should be called whenever the polygon is split
184
223
  // a child should be created for every fragment of the split polygon
@@ -189,7 +228,9 @@ export class PolygonTreeNode {
189
228
  return newChild
190
229
  }
191
230
 
192
- invertSub () {
231
+ // PRIVATE
232
+ // See invert()
233
+ _invertSub () {
193
234
  let children = [this]
194
235
  const queue = [children]
195
236
  let i, j, l, node
@@ -197,7 +238,7 @@ export class PolygonTreeNode {
197
238
  children = queue[i]
198
239
  for (j = 0, l = children.length; j < l; j++) {
199
240
  node = children[j]
200
- if (node.polygon) {
241
+ if (node.polygon !== null) {
201
242
  node.polygon = poly3.invert(node.polygon)
202
243
  }
203
244
  if (node.children.length > 0) queue.push(node.children)
@@ -205,34 +246,40 @@ export class PolygonTreeNode {
205
246
  }
206
247
  }
207
248
 
208
- // private method
249
+ // NOTE: This verison is SLOWER
250
+ _invertSubNew () {
251
+ if (this.polygon !== null) {
252
+ this.polygon = poly3.invert(this.polygon)
253
+ }
254
+ for (let i = 0; i < this.children.length; i++) {
255
+ const node = this.children[i]
256
+ node._invertSub()
257
+ }
258
+ }
259
+
260
+ // PRIVATE
209
261
  // remove the polygon from the node, and all parent nodes above it
210
262
  // called to invalidate parents of removed nodes
211
- recursivelyInvalidatePolygon () {
263
+ _recursivelyInvalidatePolygon () {
212
264
  this.polygon = null
213
- if (this.parent) {
214
- this.parent.recursivelyInvalidatePolygon()
265
+ if (this.parent !== null) {
266
+ this.parent._recursivelyInvalidatePolygon()
215
267
  }
216
268
  }
217
269
 
218
270
  clear () {
219
- let children = [this]
220
- const queue = [children]
221
- for (let i = 0; i < queue.length; ++i) { // queue size can change in loop, don't cache length
222
- children = queue[i]
223
- const l = children.length
224
- for (let j = 0; j < l; j++) {
225
- const node = children[j]
226
- if (node.polygon) {
227
- node.polygon = null
228
- }
229
- if (node.parent) {
230
- node.parent = null
231
- }
232
- if (node.children.length > 0) queue.push(node.children)
233
- node.children = []
234
- }
271
+ // clear children
272
+ for (let i = 0; i < this.children.length; i++) {
273
+ const node = this.children[i]
274
+ node.clear()
275
+ }
276
+ this.children.length = 0
277
+ // unlink polygon
278
+ if (this.polygon !== null) {
279
+ this.polygon = null
235
280
  }
281
+ // unlink parent
282
+ this.parent = null
236
283
  }
237
284
 
238
285
  toString () {
@@ -246,7 +293,7 @@ export class PolygonTreeNode {
246
293
  for (j = 0, l = children.length; j < l; j++) { // ok to cache length
247
294
  node = children[j]
248
295
  result += `${prefix}PolygonTreeNode (${node.isRootNode()}): ${node.children.length}`
249
- if (node.polygon) {
296
+ if (node.polygon !== null) {
250
297
  result += `\n ${prefix}polygon: ${node.polygon.vertices}\n`
251
298
  } else {
252
299
  result += '\n'
@@ -7,7 +7,7 @@ import { PolygonTreeNode } from './PolygonTreeNode.js'
7
7
  // The actual tree is kept in this.rootnode
8
8
  export class Tree {
9
9
  constructor (polygons) {
10
- this.polygonTree = new PolygonTreeNode()
10
+ this.polygonTree = new PolygonTreeNode(null, null)
11
11
  this.rootnode = new Node(null)
12
12
  if (polygons) this.addPolygons(polygons)
13
13
  }
@@ -17,10 +17,9 @@ export class Tree {
17
17
  this.rootnode.invert()
18
18
  }
19
19
 
20
- // Remove all polygons in this BSP tree that are inside the other BSP tree
21
- // `tree`.
20
+ // Remove all polygons in this tree that are inside the given tree
22
21
  clipTo (tree, alsoRemoveCoplanarFront = false) {
23
- this.rootnode.clipTo(tree, alsoRemoveCoplanarFront)
22
+ this.rootnode.clipTo(tree.rootnode, alsoRemoveCoplanarFront)
24
23
  }
25
24
 
26
25
  allPolygons () {
@@ -37,6 +36,12 @@ export class Tree {
37
36
  this.rootnode.addPolygonTreeNodes(polygonTreeNodes)
38
37
  }
39
38
 
39
+ // NOTE: This version is SLOWER
40
+ addPolygonsNew (polygons) {
41
+ this.polygonTree.addPolygons(polygons)
42
+ this.rootnode.addPolygonTreeNodes(this.polygonTree.children)
43
+ }
44
+
40
45
  clear () {
41
46
  this.polygonTree.clear()
42
47
  }
@@ -3,9 +3,11 @@ import * as vec3 from '../../../maths/vec3/index.js'
3
3
  export const splitLineSegmentByPlane = (plane, p1, p2) => {
4
4
  const direction = vec3.subtract(vec3.create(), p2, p1)
5
5
  let lambda = (plane[3] - vec3.dot(plane, p1)) / vec3.dot(plane, direction)
6
- if (Number.isNaN(lambda)) lambda = 0
7
- if (lambda > 1) lambda = 1
8
- if (lambda < 0) lambda = 0
6
+
7
+ Number.isNaN(lambda) ? lambda = 0
8
+ : lambda > 1 ? lambda = 1
9
+ : lambda < 0 ? lambda = 0
10
+ : lambda
9
11
 
10
12
  vec3.scale(direction, direction, lambda)
11
13
  vec3.add(direction, p1, direction)