@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
@@ -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} edgeType
12
+ * @param {number} type OPTIONAL
13
13
  */
14
- constructor (point, left, otherEvent, isSubject, edgeType) {
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 = edgeType || NORMAL
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
  }
@@ -2,7 +2,6 @@ import { EPS } from '../../maths/constants.js'
2
2
 
3
3
  import { measureBoundingBox } from '../../measurements/measureBoundingBox.js'
4
4
 
5
-
6
5
  /*
7
6
  * Determine if the given geometries overlap by comparing min and max bounds.
8
7
  * NOTE: This is used in union for performance gains.
@@ -0,0 +1,5 @@
1
+ import type { Geom3 } from '../../geometries/geom3/type.d.ts'
2
+ import type { RecursiveArray } from '../../utils/recursiveArray.d.ts'
3
+
4
+ export function scission(...geometries: RecursiveArray<Geom3>): Geom3
5
+ export function scission(...geometries: RecursiveArray<Geom3>): Array<Geom3>
@@ -1,5 +1,3 @@
1
- import { flatten } from '../../utils/flatten.js'
2
-
3
1
  import * as geom3 from '../../geometries/geom3/index.js'
4
2
 
5
3
  import { scissionGeom3 } from './scissionGeom3.js'
@@ -7,6 +5,8 @@ import { scissionGeom3 } from './scissionGeom3.js'
7
5
  /**
8
6
  * Scission (divide) the given geometry into the component pieces.
9
7
  *
8
+ * NOTE: Currently only 3D geometries are supported.
9
+ *
10
10
  * @param {...Object} objects - list of geometries
11
11
  * @returns {Array} list of pieces from each geometry
12
12
  * @alias module:modeling/booleans.scission
@@ -26,13 +26,11 @@ import { scissionGeom3 } from './scissionGeom3.js'
26
26
  * +-------+ +-------+
27
27
  */
28
28
  export const scission = (...objects) => {
29
- objects = flatten(objects)
30
- if (objects.length === 0) throw new Error('wrong number of arguments')
31
-
32
29
  const results = objects.map((object) => {
33
30
  // if (path2.isA(object)) return path2.transform(matrix, object)
34
31
  // if (geom2.isA(object)) return geom2.transform(matrix, object)
35
32
  if (geom3.isA(object)) return scissionGeom3(object)
33
+ if (Array.isArray(object)) return scission(...object)
36
34
  return object
37
35
  })
38
36
  return results.length === 1 ? results[0] : results
@@ -2,6 +2,8 @@ import test from 'ava'
2
2
 
3
3
  import { geom3 } from '../../geometries/index.js'
4
4
 
5
+ import { measureArea, measureVolume } from '../../measurements/index.js'
6
+
5
7
  import { cube, torus } from '../../primitives/index.js'
6
8
 
7
9
  import { scission, union } from './index.js'
@@ -42,6 +44,10 @@ test('scission: scission of complex geom3 produces expected geometry', (t) => {
42
44
  t.is(result1.length, 2)
43
45
  t.notThrows.skip(() => geom3.validate(result1[0]))
44
46
  t.notThrows.skip(() => geom3.validate(result1[1]))
47
+ t.is(measureArea(result1[0]), 7720.0306508548)
48
+ t.is(measureArea(result1[1]), 3860.0153254273987)
49
+ t.is(measureVolume(result1[0]), 18745.166004060953)
50
+ t.is(measureVolume(result1[1]), 9372.583002030477)
45
51
 
46
52
  const rc1 = geom3.toPolygons(result1[0]).length
47
53
  const rc2 = geom3.toPolygons(result1[1]).length
@@ -1,5 +1,5 @@
1
1
  import { areAllShapesTheSameType } from '../../utils/areAllShapesTheSameType.js'
2
- import { flatten } from '../../utils/flatten.js'
2
+ import { coalesce } from '../../utils/coalesce.js'
3
3
 
4
4
  import * as geom2 from '../../geometries/geom2/index.js'
5
5
  import * as geom3 from '../../geometries/geom3/index.js'
@@ -13,11 +13,11 @@ import { subtractGeom3 } from './subtractGeom3.js'
13
13
  * The given geometries should be of the same type, either geom2 or geom3.
14
14
  *
15
15
  * @param {...Object} geometries - list of geometries
16
- * @returns {Geom2|geom3} a new geometry
16
+ * @returns {Geom2|Geom3} a new geometry
17
17
  * @alias module:modeling/booleans.subtract
18
18
  *
19
19
  * @example
20
- * let myshape = subtract(cuboid({size: [5,5,5]}), cuboid({size: [5,5,5], center: [5,5,5]}))
20
+ * let myshape = subtract(cuboid({size: 5}), cuboid({size: 5, center: [3,3,3]}))
21
21
  *
22
22
  * @example
23
23
  * +-------+ +-------+
@@ -30,9 +30,9 @@ import { subtractGeom3 } from './subtractGeom3.js'
30
30
  * +-------+
31
31
  */
32
32
  export const subtract = (...geometries) => {
33
- geometries = flatten(geometries)
34
- if (geometries.length === 0) throw new Error('subtract wrong number of arguments')
33
+ geometries = coalesce(geometries)
35
34
 
35
+ if (geometries.length === 0) return undefined
36
36
  if (!areAllShapesTheSameType(geometries)) {
37
37
  throw new Error('subtract arguments must be the same geometry type')
38
38
  }
@@ -4,11 +4,11 @@ import { geom2, geom3 } from '../../geometries/index.js'
4
4
 
5
5
  import { subtract } from './index.js'
6
6
 
7
- test('subtract error wrong number of arguments', (t) => {
8
- const message = 'subtract wrong number of arguments'
9
- t.throws(() => subtract(), { message })
10
- t.throws(() => subtract([]), { message })
11
- t.throws(() => subtract([[], []]), { message })
7
+ test('subtract empty arguments', (t) => {
8
+ t.is(subtract(), undefined)
9
+ t.is(subtract([]), undefined)
10
+ t.is(subtract([[], []]), undefined)
11
+ t.is(subtract(null, null), undefined)
12
12
  })
13
13
 
14
14
  test('subtract error different geometry types', (t) => {
@@ -20,6 +20,5 @@ test('subtract error non-geometries', (t) => {
20
20
  const message = 'subtract unsupported geometry type'
21
21
  t.throws(() => subtract([1, 2, 3], [4, 5, 6]), { message })
22
22
  t.throws(() => subtract([], [123]), { message })
23
- t.throws(() => subtract("one", "two"), { message })
24
- t.throws(() => subtract(null, null), { message })
23
+ t.throws(() => subtract('one', 'two'), { message })
25
24
  })
@@ -1,17 +1,13 @@
1
- import { flatten } from '../../utils/flatten.js'
2
-
3
1
  import { DIFFERENCE } from './martinez/operation.js'
4
2
  import { boolean } from './martinez/index.js'
5
3
 
6
4
  /*
7
5
  * Return a new 2D geometry representing space in the first geometry but
8
6
  * not in the subsequent geometries. None of the given geometries are modified.
9
- * @param {...geom2} geometries - list of geometries
7
+ * @param {Geom2[]} geometries - a flat list of 2D geometries
10
8
  * @returns {Geom2} new 2D geometry
11
9
  */
12
- export const subtractGeom2 = (...geometries) => {
13
- geometries = flatten(geometries)
14
-
10
+ export const subtractGeom2 = (geometries) => {
15
11
  let newGeometry = geometries.shift()
16
12
  geometries.forEach((geometry) => {
17
13
  newGeometry = boolean(newGeometry, geometry, DIFFERENCE)
@@ -6,7 +6,7 @@ import { geom2 } from '../../geometries/index.js'
6
6
 
7
7
  import { measureArea } from '../../measurements/index.js'
8
8
 
9
- import { circle, rectangle } from '../../primitives/index.js'
9
+ import { circle, rectangle, square } from '../../primitives/index.js'
10
10
 
11
11
  import { center } from '../transforms/index.js'
12
12
 
@@ -75,3 +75,27 @@ test('subtract: subtract of one or more geom2 objects produces expected geometry
75
75
  t.is(obs.length, 0)
76
76
  t.deepEqual(obs, exp)
77
77
  })
78
+
79
+ test('subtract with undefined/null values', (t) => {
80
+ const square1 = square({ size: 8 })
81
+ const square2 = square({ size: 6 })
82
+ const square3 = square({ size: 4 })
83
+ const geometries = [square1, undefined, square2, null, square3]
84
+
85
+ const obs = subtract(...geometries)
86
+ const pts = geom2.toPoints(obs)
87
+ t.notThrows(() => geom2.validate(obs))
88
+ t.is(pts.length, 8)
89
+ })
90
+
91
+ test('subtract of nested arrays', (t) => {
92
+ const square1 = square({ size: 8 })
93
+ const square2 = square({ size: 6 })
94
+ const square3 = square({ size: 4 })
95
+ const geometries = [square1, [square2, [square3]]]
96
+
97
+ const obs = subtract(...geometries)
98
+ const pts = geom2.toPoints(obs)
99
+ t.notThrows(() => geom2.validate(obs))
100
+ t.is(pts.length, 8)
101
+ })
@@ -1,5 +1,3 @@
1
- import { flatten } from '../../utils/flatten.js'
2
-
3
1
  import { retessellate } from '../modifiers/retessellate.js'
4
2
 
5
3
  import { subtractGeom3Sub } from './subtractGeom3Sub.js'
@@ -7,12 +5,10 @@ import { subtractGeom3Sub } from './subtractGeom3Sub.js'
7
5
  /*
8
6
  * Return a new 3D geometry representing space in this geometry but not in the given geometries.
9
7
  * Neither this geometry nor the given geometries are modified.
10
- * @param {...geom3} geometries - list of geometries
8
+ * @param {Geom3[]} geometries - a flat list of 3D geometries
11
9
  * @returns {Geom3} new 3D geometry
12
10
  */
13
- export const subtractGeom3 = (...geometries) => {
14
- geometries = flatten(geometries)
15
-
11
+ export const subtractGeom3 = (geometries) => {
16
12
  let newGeometry = geometries.shift()
17
13
  geometries.forEach((geometry) => {
18
14
  newGeometry = subtractGeom3Sub(newGeometry, geometry)
@@ -4,7 +4,7 @@ import { comparePolygonsAsPoints } from '../../../test/helpers/index.js'
4
4
 
5
5
  import { geom3 } from '../../geometries/index.js'
6
6
 
7
- import { measureVolume } from '../../measurements/index.js'
7
+ import { measureArea, measureVolume } from '../../measurements/index.js'
8
8
 
9
9
  import { sphere, cuboid } from '../../primitives/index.js'
10
10
 
@@ -69,6 +69,7 @@ test('subtract: subtract of one or more geom3 objects produces expected geometry
69
69
  [[8.65956056235493e-17, 8.659560562354935e-17, 2], [1.4142135623730951, 3.4638242249419736e-16, 1.414213562373095], [0.9999999999999998, 1.0000000000000002, 1.414213562373095]]
70
70
  ]
71
71
  t.notThrows.skip(() => geom3.validate(result1))
72
+ t.is(measureArea(result1), 44.053756306589825)
72
73
  t.is(measureVolume(result1), 25.751611331979678)
73
74
  t.is(obs.length, 32)
74
75
  t.true(comparePolygonsAsPoints(obs, exp))
@@ -79,6 +80,7 @@ test('subtract: subtract of one or more geom3 objects produces expected geometry
79
80
  const result2 = subtract(geometry1, geometry2)
80
81
  obs = geom3.toPoints(result2)
81
82
  t.notThrows.skip(() => geom3.validate(result2))
83
+ t.is(measureArea(result2), 44.053756306589825)
82
84
  t.is(measureVolume(result2), 25.751611331979678)
83
85
  t.is(obs.length, 32)
84
86
 
@@ -102,6 +104,7 @@ test('subtract: subtract of one or more geom3 objects produces expected geometry
102
104
  [[12, 9, 8], [12, 8, 8], [9, 8, 8], [9, 9, 8]]
103
105
  ]
104
106
  t.notThrows.skip(() => geom3.validate(result3))
107
+ t.is(measureArea(result3), 96)
105
108
  t.is(measureVolume(result3), 63)
106
109
  t.is(obs.length, 12)
107
110
  t.true(comparePolygonsAsPoints(obs, exp))
@@ -110,6 +113,7 @@ test('subtract: subtract of one or more geom3 objects produces expected geometry
110
113
  const result4 = subtract(geometry1, geometry3)
111
114
  obs = geom3.toPoints(result4)
112
115
  t.notThrows(() => geom3.validate(result4))
116
+ t.is(measureArea(result4), 0)
113
117
  t.is(measureVolume(result4), 0)
114
118
  t.is(obs.length, 0)
115
119
  })
@@ -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()