@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.
Files changed (144) hide show
  1. package/CHANGELOG.md +22 -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/colors/colorize.test.js +1 -1
  6. package/src/geometries/geom2/index.d.ts +0 -2
  7. package/src/geometries/geom2/index.js +0 -2
  8. package/src/geometries/geom3/applyTransforms.test.js +2 -2
  9. package/src/geometries/geom3/clone.test.js +2 -2
  10. package/src/geometries/geom3/create.js +1 -9
  11. package/src/geometries/geom3/{fromPoints.d.ts → fromVertices.d.ts} +1 -1
  12. package/src/geometries/geom3/{fromPoints.js → fromVertices.js} +3 -2
  13. package/src/geometries/geom3/{fromPoints.test.js → fromVertices.test.js} +6 -6
  14. package/src/geometries/geom3/{fromPointsConvex.d.ts → fromVerticesConvex.d.ts} +1 -1
  15. package/src/geometries/geom3/fromVerticesConvex.js +25 -0
  16. package/src/geometries/geom3/{fromPointsConvex.test.js → fromVerticesConvex.test.js} +3 -3
  17. package/src/geometries/geom3/index.d.ts +3 -5
  18. package/src/geometries/geom3/index.js +4 -6
  19. package/src/geometries/geom3/invert.test.js +2 -2
  20. package/src/geometries/geom3/isA.test.js +2 -2
  21. package/src/geometries/geom3/toString.test.js +2 -2
  22. package/src/geometries/geom3/{toPoints.d.ts → toVertices.d.ts} +1 -1
  23. package/src/geometries/geom3/{toPoints.js → toVertices.js} +3 -2
  24. package/src/geometries/geom3/{toPoints.test.js → toVertices.test.js} +4 -4
  25. package/src/geometries/geom3/transform.test.js +2 -2
  26. package/src/geometries/geom3/validate.test.js +4 -4
  27. package/src/geometries/index.d.ts +1 -0
  28. package/src/geometries/index.js +1 -0
  29. package/src/geometries/path2/appendBezier.js +1 -1
  30. package/src/geometries/path2/create.js +1 -10
  31. package/src/geometries/path2/index.d.ts +0 -2
  32. package/src/geometries/path2/index.js +0 -2
  33. package/src/geometries/path3/applyTransforms.js +22 -0
  34. package/src/geometries/path3/applyTransforms.test.js +28 -0
  35. package/src/geometries/path3/close.d.ts +3 -0
  36. package/src/geometries/path3/close.js +31 -0
  37. package/src/geometries/path3/close.test.js +43 -0
  38. package/src/geometries/path3/concat.d.ts +3 -0
  39. package/src/geometries/path3/concat.js +36 -0
  40. package/src/geometries/path3/concat.test.js +35 -0
  41. package/src/geometries/path3/create.d.ts +4 -0
  42. package/src/geometries/path3/create.js +30 -0
  43. package/src/geometries/path3/create.test.js +8 -0
  44. package/src/geometries/path3/equals.d.ts +3 -0
  45. package/src/geometries/path3/equals.js +48 -0
  46. package/src/geometries/path3/equals.test.js +38 -0
  47. package/src/geometries/path3/fromVertices.d.ts +8 -0
  48. package/src/geometries/path3/fromVertices.js +45 -0
  49. package/src/geometries/path3/fromVertices.test.js +33 -0
  50. package/src/geometries/path3/index.d.ts +13 -0
  51. package/src/geometries/path3/index.js +21 -0
  52. package/src/geometries/path3/isA.d.ts +3 -0
  53. package/src/geometries/path3/isA.js +20 -0
  54. package/src/geometries/path3/isA.test.js +19 -0
  55. package/src/geometries/path3/reverse.d.ts +3 -0
  56. package/src/geometries/path3/reverse.js +19 -0
  57. package/src/geometries/path3/reverse.test.js +9 -0
  58. package/src/geometries/path3/toString.d.ts +3 -0
  59. package/src/geometries/path3/toString.js +24 -0
  60. package/src/geometries/path3/toVertices.d.ts +4 -0
  61. package/src/geometries/path3/toVertices.js +16 -0
  62. package/src/geometries/path3/toVertices.test.js +13 -0
  63. package/src/geometries/path3/transform.d.ts +4 -0
  64. package/src/geometries/path3/transform.js +21 -0
  65. package/src/geometries/path3/transform.test.js +50 -0
  66. package/src/geometries/path3/type.d.ts +10 -0
  67. package/src/geometries/path3/validate.d.ts +1 -0
  68. package/src/geometries/path3/validate.js +41 -0
  69. package/src/geometries/poly2/create.js +1 -6
  70. package/src/geometries/poly3/create.js +1 -6
  71. package/src/geometries/poly3/index.js +1 -1
  72. package/src/geometries/poly3/measureBoundingBox.js +2 -0
  73. package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
  74. package/src/geometries/poly3/measureBoundingSphere.js +25 -8
  75. package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
  76. package/src/index.js +41 -0
  77. package/src/measurements/measureBoundingSphere.js +2 -6
  78. package/src/operations/booleans/intersectGeom3.test.js +4 -4
  79. package/src/operations/booleans/martinez/compareEvents.js +2 -7
  80. package/src/operations/booleans/martinez/connectEdges.js +30 -41
  81. package/src/operations/booleans/martinez/contour.js +1 -1
  82. package/src/operations/booleans/martinez/divideSegment.js +12 -11
  83. package/src/operations/booleans/martinez/fillQueue.js +24 -28
  84. package/src/operations/booleans/martinez/index.js +2 -1
  85. package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
  86. package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
  87. package/src/operations/booleans/martinez/splaytree.js +59 -457
  88. package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
  89. package/src/operations/booleans/martinez/sweepEvent.js +3 -17
  90. package/src/operations/booleans/subtractGeom3.test.js +4 -4
  91. package/src/operations/booleans/trees/Node.js +25 -27
  92. package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
  93. package/src/operations/booleans/trees/Tree.js +9 -4
  94. package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
  95. package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
  96. package/src/operations/booleans/unionGeom3.test.js +5 -5
  97. package/src/operations/extrusions/extrudeFromSlices.test.js +6 -6
  98. package/src/operations/extrusions/extrudeLinear.test.js +8 -8
  99. package/src/operations/extrusions/extrudeRotate.test.js +12 -12
  100. package/src/operations/extrusions/extrudeWalls.js +3 -1
  101. package/src/operations/hulls/hull.test.js +5 -5
  102. package/src/operations/hulls/hullChain.test.js +5 -5
  103. package/src/operations/hulls/hullPoints2.js +20 -28
  104. package/src/operations/hulls/toUniquePoints.js +2 -2
  105. package/src/operations/modifiers/generalize.test.js +6 -6
  106. package/src/operations/modifiers/insertTjunctions.test.js +2 -2
  107. package/src/operations/modifiers/mergePolygons.js +2 -3
  108. package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
  109. package/src/operations/modifiers/retessellate.test.js +10 -10
  110. package/src/operations/modifiers/snap.test.js +4 -4
  111. package/src/operations/offsets/offsetGeom3.test.js +4 -4
  112. package/src/operations/transforms/center.test.js +7 -7
  113. package/src/operations/transforms/mirror.test.js +7 -7
  114. package/src/operations/transforms/rotate.test.js +7 -7
  115. package/src/operations/transforms/scale.test.js +7 -7
  116. package/src/operations/transforms/transform.test.js +2 -2
  117. package/src/operations/transforms/translate.test.js +7 -7
  118. package/src/primitives/cube.test.js +4 -4
  119. package/src/primitives/cuboid.test.js +4 -4
  120. package/src/primitives/cylinder.test.js +5 -5
  121. package/src/primitives/cylinderElliptic.test.js +9 -9
  122. package/src/primitives/ellipsoid.test.js +5 -5
  123. package/src/primitives/geodesicSphere.test.js +4 -4
  124. package/src/primitives/polyhedron.test.js +2 -2
  125. package/src/primitives/roundedCuboid.test.js +7 -7
  126. package/src/primitives/roundedCylinder.test.js +9 -9
  127. package/src/primitives/sphere.test.js +5 -5
  128. package/src/primitives/torus.test.js +4 -4
  129. package/src/geometries/geom2/fromCompactBinary.d.ts +0 -3
  130. package/src/geometries/geom2/fromCompactBinary.js +0 -40
  131. package/src/geometries/geom2/fromToCompactBinary.test.js +0 -100
  132. package/src/geometries/geom2/toCompactBinary.d.ts +0 -3
  133. package/src/geometries/geom2/toCompactBinary.js +0 -56
  134. package/src/geometries/geom3/fromCompactBinary.d.ts +0 -3
  135. package/src/geometries/geom3/fromCompactBinary.js +0 -42
  136. package/src/geometries/geom3/fromPointsConvex.js +0 -25
  137. package/src/geometries/geom3/fromToCompactBinary.test.js +0 -139
  138. package/src/geometries/geom3/toCompactBinary.d.ts +0 -3
  139. package/src/geometries/geom3/toCompactBinary.js +0 -66
  140. package/src/geometries/path2/fromCompactBinary.d.ts +0 -3
  141. package/src/geometries/path2/fromCompactBinary.js +0 -31
  142. package/src/geometries/path2/fromToCompactBinary.test.js +0 -114
  143. package/src/geometries/path2/toCompactBinary.d.ts +0 -3
  144. package/src/geometries/path2/toCompactBinary.js +0 -50
@@ -7,23 +7,27 @@ import * as poly3 from '../../../geometries/poly3/index.js'
7
7
 
8
8
  import { splitLineSegmentByPlane } from './splitLineSegmentByPlane.js'
9
9
 
10
- // Returns object:
11
- // .type:
12
- // 0: coplanar-front
13
- // 1: coplanar-back
14
- // 2: front
15
- // 3: back
16
- // 4: spanning
17
- // In case the polygon is spanning, returns:
18
- // .front: a Polygon3 of the front part
19
- // .back: a Polygon3 of the back part
20
- export const splitPolygonByPlane = (splane, polygon) => {
21
- const result = {
22
- type: null,
23
- front: null,
24
- back: null
25
- }
26
- // cache in local lets (speedup):
10
+ /*
11
+ * Split the given polygon by the given plane.
12
+ *
13
+ * @@param (Object} result - object of which to update with the result
14
+ * @param {Plane} splane - plane to split across
15
+ * @param {Poly3} ploygon - polygon of which to split
16
+ * @returns none
17
+ *
18
+ * The result is updated in place to improve performance (no allocation)
19
+ * result.type:
20
+ * 0: coplanar-front
21
+ * 1: coplanar-back
22
+ * 2: front
23
+ * 3: back
24
+ * 4: spanning
25
+ *
26
+ * In case the polygon is spanning (4)
27
+ * result.front contains null or a ploygon (front part)
28
+ * result.back contains null or a polygon (back part)
29
+ */
30
+ export const splitPolygonByPlane = (result, splane, polygon) => {
27
31
  const vertices = polygon.vertices
28
32
  const numVertices = vertices.length
29
33
  const pplane = poly3.plane(polygon)
@@ -41,17 +45,20 @@ export const splitPolygonByPlane = (splane, polygon) => {
41
45
  if (t > EPS) hasFront = true
42
46
  if (t < MINEPS) hasBack = true
43
47
  }
48
+
44
49
  if ((!hasFront) && (!hasBack)) {
45
50
  // all points coplanar
46
51
  const t = vec3.dot(splane, pplane)
47
52
  result.type = (t >= 0) ? 0 : 1
48
53
  } else if (!hasBack) {
54
+ // points only front of the plane
49
55
  result.type = 2
50
56
  } else if (!hasFront) {
57
+ // points only back of the plane
51
58
  result.type = 3
52
59
  } else {
53
- // spanning
54
- result.type = 4
60
+ // points span the plane
61
+ // split the line segments by the plane
55
62
  const frontVertices = []
56
63
  const backVertices = []
57
64
  let isback = vertexIsBack[0]
@@ -61,14 +68,10 @@ export const splitPolygonByPlane = (splane, polygon) => {
61
68
  if (nextVertexIndex >= numVertices) nextVertexIndex = 0
62
69
  const nextIsBack = vertexIsBack[nextVertexIndex]
63
70
  if (isback === nextIsBack) {
64
- // line segment is on one side of the plane:
65
- if (isback) {
66
- backVertices.push(vertex)
67
- } else {
68
- frontVertices.push(vertex)
69
- }
71
+ // line segment is on one side of the plane
72
+ isback ? backVertices.push(vertex) : frontVertices.push(vertex)
70
73
  } else {
71
- // line segment intersects plane:
74
+ // line segment spans the plane
72
75
  const nextPoint = vertices[nextVertexIndex]
73
76
  const intersectionPoint = splitLineSegmentByPlane(splane, vertex, nextPoint)
74
77
  if (isback) {
@@ -82,8 +85,9 @@ export const splitPolygonByPlane = (splane, polygon) => {
82
85
  }
83
86
  }
84
87
  isback = nextIsBack
85
- } // for vertexIndex
86
- // remove duplicate vertices:
88
+ }
89
+
90
+ // remove duplicate vertices
87
91
  const EPS_SQUARED = EPS * EPS
88
92
  if (backVertices.length >= 3) {
89
93
  let prevVertex = backVertices[backVertices.length - 1]
@@ -107,12 +111,13 @@ export const splitPolygonByPlane = (splane, polygon) => {
107
111
  prevVertex = vertex
108
112
  }
109
113
  }
110
- if (frontVertices.length >= 3) {
111
- result.front = poly3.fromVerticesAndPlane(frontVertices, pplane)
112
- }
113
- if (backVertices.length >= 3) {
114
- result.back = poly3.fromVerticesAndPlane(backVertices, pplane)
115
- }
114
+
115
+ // assemble the result
116
+ result.type = 4
117
+
118
+ result.front = frontVertices.length >= 3 ? poly3.fromVerticesAndPlane(frontVertices, pplane) : null
119
+
120
+ result.back = backVertices.length >= 3 ? poly3.fromVerticesAndPlane(backVertices, pplane) : null
116
121
  }
117
122
  }
118
123
  return result
@@ -17,7 +17,7 @@ test('union of one or more geom3 objects produces expected geometry', (t) => {
17
17
 
18
18
  // union of one object
19
19
  const result1 = union(geometry1)
20
- let obs = geom3.toPoints(result1)
20
+ let obs = geom3.toVertices(result1)
21
21
  let exp = [
22
22
  [[2, 0, 0], [1.4142135623730951, -1.414213562373095, 0],
23
23
  [1.0000000000000002, -1, -1.414213562373095], [1.4142135623730951, 0, -1.414213562373095]],
@@ -78,7 +78,7 @@ test('union of one or more geom3 objects produces expected geometry', (t) => {
78
78
  const geometry2 = center({ relativeTo: [10, 10, 10] }, cuboid({ size: [4, 4, 4] }))
79
79
 
80
80
  const result2 = union(geometry1, geometry2)
81
- obs = geom3.toPoints(result2)
81
+ obs = geom3.toVertices(result2)
82
82
  t.notThrows.skip(() => geom3.validate(result2))
83
83
  t.is(measureArea(result2), 140.05375630658983)
84
84
  t.is(measureVolume(result2), 89.75161133197969)
@@ -88,7 +88,7 @@ test('union of one or more geom3 objects produces expected geometry', (t) => {
88
88
  const geometry3 = cuboid({ size: [18, 18, 18] })
89
89
 
90
90
  const result3 = union(geometry2, geometry3)
91
- obs = geom3.toPoints(result3)
91
+ obs = geom3.toVertices(result3)
92
92
  exp = [
93
93
  [[12, 8, 8], [12, 12, 8], [12, 12, 12], [12, 8, 12]],
94
94
  [[8, 12, 8], [8, 12, 12], [12, 12, 12], [12, 12, 8]],
@@ -117,7 +117,7 @@ test('union of one or more geom3 objects produces expected geometry', (t) => {
117
117
 
118
118
  // union of two completely overlapping objects
119
119
  const result4 = union(geometry1, geometry3)
120
- obs = geom3.toPoints(result4)
120
+ obs = geom3.toVertices(result4)
121
121
  exp = [
122
122
  [[-9, -9, -9], [-9, -9, 9], [-9, 9, 9], [-9, 9, -9]],
123
123
  [[9, -9, -9], [9, 9, -9], [9, 9, 9], [9, -9, 9]],
@@ -138,7 +138,7 @@ test('union of geom3 with rounding issues #137', (t) => {
138
138
  const geometry2 = center({ relativeTo: [0, 0, -4.400001] }, cuboid({ size: [44, 26, 1.8] })) // introduce precision error
139
139
 
140
140
  const result = union(geometry1, geometry2)
141
- const pts = geom3.toPoints(result)
141
+ const pts = geom3.toVertices(result)
142
142
  t.notThrows(() => geom3.validate(result))
143
143
  t.is(measureArea(result), 3240.00014)
144
144
  t.is(measureVolume(result), 7779.201144000001)
@@ -17,7 +17,7 @@ test('extrudeFromSlices (defaults)', (t) => {
17
17
  const geometry2 = square({ size: 20 })
18
18
 
19
19
  let geometry3 = extrudeFromSlices({ }, geometry2)
20
- let pts = geom3.toPoints(geometry3)
20
+ let pts = geom3.toVertices(geometry3)
21
21
  const exp = [
22
22
  [[-10, -10, 0], [10, -10, 0], [10, -10, 1]],
23
23
  [[-10, -10, 0], [10, -10, 1], [-10, -10, 1]],
@@ -39,7 +39,7 @@ test('extrudeFromSlices (defaults)', (t) => {
39
39
 
40
40
  const poly2 = poly3.create([[-10, -10, 0], [10, -10, 0], [10, 10, 0], [-10, 10, 0]])
41
41
  geometry3 = extrudeFromSlices({ }, poly2)
42
- pts = geom3.toPoints(geometry3)
42
+ pts = geom3.toVertices(geometry3)
43
43
 
44
44
  t.notThrows(() => geom3.validate(geometry3))
45
45
  t.is(measureArea(geometry3), 880)
@@ -75,7 +75,7 @@ test('extrudeFromSlices (torus)', (t) => {
75
75
  }
76
76
  }, hex
77
77
  )
78
- const pts = geom3.toPoints(geometry3)
78
+ const pts = geom3.toVertices(geometry3)
79
79
  t.notThrows(() => geom3.validate(geometry3))
80
80
  t.is(measureArea(geometry3), 7070.694617452831)
81
81
  t.is(measureVolume(geometry3), 29393.876913398108)
@@ -96,7 +96,7 @@ test('extrudeFromSlices (same shape, changing dimensions)', (t) => {
96
96
  }
97
97
  }, base
98
98
  )
99
- const pts = geom3.toPoints(geometry3)
99
+ const pts = geom3.toVertices(geometry3)
100
100
  // expected to throw because capEnd is false (non-closed geometry)
101
101
  t.throws(() => geom3.validate(geometry3))
102
102
  t.is(measureArea(geometry3), 53.70100297794013)
@@ -117,7 +117,7 @@ test('extrudeFromSlices (changing shape, changing dimensions)', (t) => {
117
117
  }
118
118
  }, base
119
119
  )
120
- const pts = geom3.toPoints(geometry3)
120
+ const pts = geom3.toVertices(geometry3)
121
121
  t.notThrows.skip(() => geom3.validate(geometry3))
122
122
  t.is(measureArea(geometry3), 1965.8643589631802)
123
123
  t.is(measureVolume(geometry3), 5260.067107417433)
@@ -130,7 +130,7 @@ test('extrudeFromSlices (holes)', (t) => {
130
130
  [[-5, -5], [-5, 5], [5, 5], [5, -5]]
131
131
  ])
132
132
  const geometry3 = extrudeFromSlices({ }, geometry2)
133
- const pts = geom3.toPoints(geometry3)
133
+ const pts = geom3.toVertices(geometry3)
134
134
  const exp = [
135
135
  [[-10, 10, 0], [-10, -10, 0], [-10, -10, 1]],
136
136
  [[-10, 10, 0], [-10, -10, 1], [-10, 10, 1]],
@@ -18,7 +18,7 @@ test('extrudeLinear (defaults)', (t) => {
18
18
  const geometry2 = square({ size: 10 })
19
19
 
20
20
  const geometry3 = extrudeLinear({ }, geometry2)
21
- const pts = geom3.toPoints(geometry3)
21
+ const pts = geom3.toVertices(geometry3)
22
22
  const exp = [
23
23
  [[-5, -5, 0], [5, -5, 0], [5, -5, 1]],
24
24
  [[-5, -5, 0], [5, -5, 1], [-5, -5, 1]],
@@ -55,7 +55,7 @@ test('extrudeLinear (no twist)', (t) => {
55
55
  const geometry2 = square({ size: 10 })
56
56
 
57
57
  let geometry3 = extrudeLinear({ height: 15 }, geometry2)
58
- let pts = geom3.toPoints(geometry3)
58
+ let pts = geom3.toVertices(geometry3)
59
59
  let exp = [
60
60
  [[-5, -5, 0], [5, -5, 0], [5, -5, 15]],
61
61
  [[-5, -5, 0], [5, -5, 15], [-5, -5, 15]],
@@ -77,7 +77,7 @@ test('extrudeLinear (no twist)', (t) => {
77
77
  t.true(comparePolygonsAsPoints(pts, exp))
78
78
 
79
79
  geometry3 = extrudeLinear({ height: -15 }, geometry2)
80
- pts = geom3.toPoints(geometry3)
80
+ pts = geom3.toVertices(geometry3)
81
81
  exp = [
82
82
  [[-5, 5, 0], [5, 5, 0], [5, 5, -15]],
83
83
  [[-5, 5, 0], [5, 5, -15], [-5, 5, -15]],
@@ -103,7 +103,7 @@ test('extrudeLinear (twist)', (t) => {
103
103
  const geometry2 = square({ size: 10 })
104
104
 
105
105
  let geometry3 = extrudeLinear({ height: 15, twistAngle: -TAU / 8 }, geometry2)
106
- let pts = geom3.toPoints(geometry3)
106
+ let pts = geom3.toVertices(geometry3)
107
107
  let exp = [
108
108
  [[-5, -5, 0], [5, -5, 0], [4.440892098500626e-16, -7.0710678118654755, 15]],
109
109
  [[-5, -5, 0], [4.440892098500626e-16, -7.0710678118654755, 15], [-7.0710678118654755, -4.440892098500626e-16, 15]],
@@ -133,7 +133,7 @@ test('extrudeLinear (twist)', (t) => {
133
133
  t.true(comparePolygonsAsPoints(pts, exp))
134
134
 
135
135
  geometry3 = extrudeLinear({ height: 15, twistAngle: TAU / 4, twistSteps: 3 }, geometry2)
136
- pts = geom3.toPoints(geometry3)
136
+ pts = geom3.toVertices(geometry3)
137
137
  exp = [
138
138
  [[-5, -5, 0], [5, -5, 0], [6.830127018922193, -1.830127018922194, 5]],
139
139
  [[-5, -5, 0], [6.830127018922193, -1.830127018922194, 5], [-1.830127018922194, -6.830127018922193, 5]],
@@ -168,7 +168,7 @@ test('extrudeLinear (twist)', (t) => {
168
168
  t.true(comparePolygonsAsPoints(pts, exp))
169
169
 
170
170
  geometry3 = extrudeLinear({ height: 15, twistAngle: TAU / 2, twistSteps: 30 }, geometry2)
171
- pts = geom3.toPoints(geometry3)
171
+ pts = geom3.toVertices(geometry3)
172
172
  t.notThrows(() => geom3.validate(geometry3))
173
173
  t.is(measureArea(geometry3), 1091.9932843446968)
174
174
  t.is(measureVolume(geometry3), 1444.9967160503095)
@@ -181,7 +181,7 @@ test('extrudeLinear (holes)', (t) => {
181
181
  [[-2, -2], [-2, 2], [2, 2], [2, -2]]
182
182
  ])
183
183
  const geometry3 = extrudeLinear({ height: 15 }, geometry2)
184
- const pts = geom3.toPoints(geometry3)
184
+ const pts = geom3.toVertices(geometry3)
185
185
  const exp = [
186
186
  [[-5, 5, 0], [-5, -5, 0], [-5, -5, 15]],
187
187
  [[-5, 5, 0], [-5, -5, 15], [-5, 5, 15]],
@@ -227,7 +227,7 @@ test('extrudeLinear (path2)', (t) => {
227
227
  const geometry2 = path2.fromPoints({ closed: true }, [[6, 10], [0, 0], [12, 0]])
228
228
  const geometry3 = extrudeLinear({ height: 15 }, geometry2)
229
229
  t.notThrows(() => geom3.validate(geometry3))
230
- const pts = geom3.toPoints(geometry3)
230
+ const pts = geom3.toVertices(geometry3)
231
231
  const exp = [
232
232
  [[6, 10, 0], [0, 0, 0], [0, 0, 15]],
233
233
  [[6, 10, 0], [0, 0, 15], [6, 10, 15]],
@@ -18,7 +18,7 @@ test('extrudeRotate: (defaults) extruding of a geom2 produces an expected geom3'
18
18
  const geometry2 = geom2.create([[[10, 8], [10, -8], [26, -8], [26, 8]]])
19
19
 
20
20
  const geometry3 = extrudeRotate({ }, geometry2)
21
- const pts = geom3.toPoints(geometry3)
21
+ const pts = geom3.toVertices(geometry3)
22
22
  t.notThrows(() => geom3.validate(geometry3))
23
23
  t.is(measureArea(geometry3), 7033.914479497244)
24
24
  t.is(measureVolume(geometry3), 27648.000000000007)
@@ -36,7 +36,7 @@ test('extrudeRotate: (angle) extruding of a geom2 produces an expected geom3', (
36
36
 
37
37
  // test angle
38
38
  let geometry3 = extrudeRotate({ segments: 4, angle: TAU / 8 }, geometry2)
39
- let pts = geom3.toPoints(geometry3)
39
+ let pts = geom3.toVertices(geometry3)
40
40
  const exp = [
41
41
  [[26, 0, 8], [26, 0, -8], [18.38477631085024, 18.384776310850235, -8]],
42
42
  [[26, 0, 8], [18.38477631085024, 18.384776310850235, -8], [18.38477631085024, 18.384776310850235, 8]],
@@ -58,14 +58,14 @@ test('extrudeRotate: (angle) extruding of a geom2 produces an expected geom3', (
58
58
  t.true(comparePolygonsAsPoints(pts, exp))
59
59
 
60
60
  geometry3 = extrudeRotate({ segments: 4, angle: -250 * 0.017453292519943295 }, geometry2)
61
- pts = geom3.toPoints(geometry3)
61
+ pts = geom3.toVertices(geometry3)
62
62
  t.notThrows(() => geom3.validate(geometry3))
63
63
  t.is(measureArea(geometry3), 4525.850393739846)
64
64
  t.is(measureVolume(geometry3), 13730.527057424617)
65
65
  t.is(pts.length, 28)
66
66
 
67
67
  geometry3 = extrudeRotate({ segments: 4, angle: 250 * 0.017453292519943295 }, geometry2)
68
- pts = geom3.toPoints(geometry3)
68
+ pts = geom3.toVertices(geometry3)
69
69
  t.notThrows(() => geom3.validate(geometry3))
70
70
  t.is(measureArea(geometry3), 4525.8503937398455)
71
71
  t.is(measureVolume(geometry3), 13730.527057424617)
@@ -77,7 +77,7 @@ test('extrudeRotate: (startAngle) extruding of a geom2 produces an expected geom
77
77
 
78
78
  // test startAngle
79
79
  let geometry3 = extrudeRotate({ segments: 5, startAngle: TAU / 8 }, geometry2)
80
- let pts = geom3.toPoints(geometry3)
80
+ let pts = geom3.toVertices(geometry3)
81
81
  let exp = [
82
82
  [7.0710678118654755, 7.071067811865475, 8],
83
83
  [18.38477631085024, 18.384776310850235, 8],
@@ -90,7 +90,7 @@ test('extrudeRotate: (startAngle) extruding of a geom2 produces an expected geom
90
90
  t.true(comparePoints(pts[6], exp))
91
91
 
92
92
  geometry3 = extrudeRotate({ segments: 5, startAngle: -TAU / 8 }, geometry2)
93
- pts = geom3.toPoints(geometry3)
93
+ pts = geom3.toVertices(geometry3)
94
94
  exp = [
95
95
  [7.0710678118654755, -7.071067811865475, 8],
96
96
  [18.38477631085024, -18.384776310850235, 8],
@@ -108,14 +108,14 @@ test('extrudeRotate: (segments) extruding of a geom2 produces an expected geom3'
108
108
 
109
109
  // test segments
110
110
  let geometry3 = extrudeRotate({ segments: 4 }, geometry2)
111
- let pts = geom3.toPoints(geometry3)
111
+ let pts = geom3.toVertices(geometry3)
112
112
  t.notThrows(() => geom3.validate(geometry3))
113
113
  t.is(measureArea(geometry3), 5562.34804770761)
114
114
  t.is(measureVolume(geometry3), 18432)
115
115
  t.is(pts.length, 32)
116
116
 
117
117
  geometry3 = extrudeRotate({ segments: 64 }, geometry2)
118
- pts = geom3.toPoints(geometry3)
118
+ pts = geom3.toVertices(geometry3)
119
119
  t.notThrows(() => geom3.validate(geometry3))
120
120
  t.is(measureArea(geometry3), 7230.965353920782)
121
121
  t.is(measureVolume(geometry3), 28906.430888871357)
@@ -124,7 +124,7 @@ test('extrudeRotate: (segments) extruding of a geom2 produces an expected geom3'
124
124
  // test overlapping edges
125
125
  geometry2 = geom2.create([[[0, 0], [2, 1], [1, 2], [1, 3], [3, 4], [0, 5]]])
126
126
  geometry3 = extrudeRotate({ segments: 8 }, geometry2)
127
- pts = geom3.toPoints(geometry3)
127
+ pts = geom3.toVertices(geometry3)
128
128
  t.notThrows(() => geom3.validate(geometry3))
129
129
  t.is(measureArea(geometry3), 84.28200374166053)
130
130
  t.is(measureVolume(geometry3), 33.94112549695427)
@@ -133,7 +133,7 @@ test('extrudeRotate: (segments) extruding of a geom2 produces an expected geom3'
133
133
  // test overlapping edges that produce hollow shape
134
134
  geometry2 = geom2.create([[[30, 0], [30, 60], [0, 60], [0, 50], [10, 40], [10, 30], [0, 20], [0, 10], [10, 0]]])
135
135
  geometry3 = extrudeRotate({ segments: 8 }, geometry2)
136
- pts = geom3.toPoints(geometry3)
136
+ pts = geom3.toVertices(geometry3)
137
137
  t.notThrows(() => geom3.validate(geometry3))
138
138
  t.is(measureArea(geometry3), 17692.315375839215)
139
139
  t.is(measureVolume(geometry3), 147078.2104868019)
@@ -145,7 +145,7 @@ test('extrudeRotate: (overlap +/-) extruding of a geom2 produces an expected geo
145
145
  let geometry = geom2.create([[[-1, 8], [-1, -8], [7, -8], [7, 8]]])
146
146
 
147
147
  let obs = extrudeRotate({ segments: 4, angle: TAU / 4 }, geometry)
148
- let pts = geom3.toPoints(obs)
148
+ let pts = geom3.toVertices(obs)
149
149
  let exp = [
150
150
  [[0, 0, 8], [7, 0, 8], [0, 7, 8]],
151
151
  [[7, 0, 8], [7, 0, -8], [0, 7, -8]],
@@ -166,7 +166,7 @@ test('extrudeRotate: (overlap +/-) extruding of a geom2 produces an expected geo
166
166
  geometry = geom2.create([[[-1, 8], [-2, 4], [-1, -8], [7, -8], [7, 8]]])
167
167
 
168
168
  obs = extrudeRotate({ segments: 8, angle: TAU / 4 }, geometry)
169
- pts = geom3.toPoints(obs)
169
+ pts = geom3.toVertices(obs)
170
170
  exp = [
171
171
  [[2, 0, 4], [1, 0, -8], [0.7071067811865476, 0.7071067811865475, -8]],
172
172
  [[2, 0, 4], [0.7071067811865476, 0.7071067811865475, -8], [1.4142135623730951, 1.414213562373095, 4]],
@@ -25,10 +25,11 @@ const repartitionEdges = (newLength, edges) => {
25
25
  }
26
26
 
27
27
  const divisor = vec3.fromValues(multiple, multiple, multiple)
28
+ const increment = vec3.create()
28
29
 
29
30
  const newEdges = []
30
31
  edges.forEach((edge) => {
31
- const increment = vec3.subtract(vec3.create(), edge[1], edge[0])
32
+ vec3.subtract(increment, edge[1], edge[0])
32
33
  vec3.divide(increment, increment, divisor)
33
34
 
34
35
  // repartition the edge
@@ -48,6 +49,7 @@ const EPSAREA = (EPS * EPS / 2) * Math.sin(Math.PI / 3)
48
49
  * Extrude (build) walls between the given slices.
49
50
  * Each wall consists of two triangles, which may be invalid if slices are overlapping.
50
51
  */
52
+ // FIXME this function should take an eps parameter
51
53
  export const extrudeWalls = (slice0, slice1) => {
52
54
  let edges0 = slice.toEdges(slice0)
53
55
  let edges1 = slice.toEdges(slice1)
@@ -218,7 +218,7 @@ test('hull (single, geom3)', (t) => {
218
218
  let geometry = geom3.create()
219
219
 
220
220
  let obs = hull(geometry)
221
- let pts = geom3.toPoints(obs)
221
+ let pts = geom3.toVertices(obs)
222
222
 
223
223
  t.notThrows(() => geom3.validate(obs))
224
224
  t.is(pts.length, 0)
@@ -226,7 +226,7 @@ test('hull (single, geom3)', (t) => {
226
226
  geometry = sphere({ radius: 2, segments: 8 })
227
227
 
228
228
  obs = hull(geometry)
229
- pts = geom3.toPoints(obs)
229
+ pts = geom3.toVertices(obs)
230
230
 
231
231
  t.notThrows(() => geom3.validate(obs))
232
232
  t.is(measureArea(obs), 44.05375630658983)
@@ -238,7 +238,7 @@ test('hull (multiple, geom3)', (t) => {
238
238
  const geometry1 = cuboid({ size: [2, 2, 2] })
239
239
 
240
240
  let obs = hull(geometry1, geometry1) // same
241
- let pts = geom3.toPoints(obs)
241
+ let pts = geom3.toVertices(obs)
242
242
  let exp = [
243
243
  [[-1, 1, -1], [-1, 1, 1], [1, 1, 1], [1, 1, -1]],
244
244
  [[-1, 1, -1], [1, 1, -1], [1, -1, -1], [-1, -1, -1]],
@@ -257,7 +257,7 @@ test('hull (multiple, geom3)', (t) => {
257
257
  const geometry2 = center({ relativeTo: [5, 5, 5] }, cuboid({ size: [3, 3, 3] }))
258
258
 
259
259
  obs = hull(geometry1, geometry2)
260
- pts = geom3.toPoints(obs)
260
+ pts = geom3.toVertices(obs)
261
261
  exp = [
262
262
  [[1, -1, -1], [6.5, 3.5, 3.5], [6.5, 3.5, 6.5], [1, -1, 1]],
263
263
  [[-1, -1, 1], [-1, -1, -1], [1, -1, -1], [1, -1, 1]],
@@ -286,7 +286,7 @@ test('hull (multiple, overlapping, geom3)', (t) => {
286
286
  const geometry3 = center({ relativeTo: [-3, -3, -3] }, ellipsoid({ radius: [3, 3, 3], segments: 12 }))
287
287
 
288
288
  const obs = hull(geometry1, geometry2, geometry3)
289
- const pts = geom3.toPoints(obs)
289
+ const pts = geom3.toVertices(obs)
290
290
 
291
291
  t.notThrows(() => geom3.validate(obs))
292
292
  t.is(measureArea(obs), 282.26819685563686)
@@ -61,7 +61,7 @@ test('hullChain (three, geom2)', (t) => {
61
61
  })
62
62
 
63
63
  test('hullChain (three, geom3)', (t) => {
64
- const geometry1 = geom3.fromPoints(
64
+ const geometry1 = geom3.fromVertices(
65
65
  [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]],
66
66
  [[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, -1, 1]],
67
67
  [[-1, -1, -1], [1, -1, -1], [1, -1, 1], [-1, -1, 1]],
@@ -69,7 +69,7 @@ test('hullChain (three, geom3)', (t) => {
69
69
  [[-1, -1, -1], [-1, 1, -1], [1, 1, -1], [1, -1, -1]],
70
70
  [[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]]]
71
71
  )
72
- const geometry2 = geom3.fromPoints(
72
+ const geometry2 = geom3.fromVertices(
73
73
  [[[3.5, 3.5, 3.5], [3.5, 3.5, 6.5], [3.5, 6.5, 6.5], [3.5, 6.5, 3.5]],
74
74
  [[6.5, 3.5, 3.5], [6.5, 6.5, 3.5], [6.5, 6.5, 6.5], [6.5, 3.5, 6.5]],
75
75
  [[3.5, 3.5, 3.5], [6.5, 3.5, 3.5], [6.5, 3.5, 6.5], [3.5, 3.5, 6.5]],
@@ -77,7 +77,7 @@ test('hullChain (three, geom3)', (t) => {
77
77
  [[3.5, 3.5, 3.5], [3.5, 6.5, 3.5], [6.5, 6.5, 3.5], [6.5, 3.5, 3.5]],
78
78
  [[3.5, 3.5, 6.5], [6.5, 3.5, 6.5], [6.5, 6.5, 6.5], [3.5, 6.5, 6.5]]]
79
79
  )
80
- const geometry3 = geom3.fromPoints(
80
+ const geometry3 = geom3.fromVertices(
81
81
  [[[-4.5, 1.5, -4.5], [-4.5, 1.5, -1.5], [-4.5, 4.5, -1.5], [-4.5, 4.5, -4.5]],
82
82
  [[-1.5, 1.5, -4.5], [-1.5, 4.5, -4.5], [-1.5, 4.5, -1.5], [-1.5, 1.5, -1.5]],
83
83
  [[-4.5, 1.5, -4.5], [-1.5, 1.5, -4.5], [-1.5, 1.5, -1.5], [-4.5, 1.5, -1.5]],
@@ -88,7 +88,7 @@ test('hullChain (three, geom3)', (t) => {
88
88
 
89
89
  // open
90
90
  let obs = hullChain(geometry1, geometry2, geometry3)
91
- let pts = geom3.toPoints(obs)
91
+ let pts = geom3.toVertices(obs)
92
92
 
93
93
  t.notThrows.skip(() => geom3.validate(obs))
94
94
  t.is(measureArea(obs), 266.1454764345133)
@@ -97,7 +97,7 @@ test('hullChain (three, geom3)', (t) => {
97
97
 
98
98
  // closed
99
99
  obs = hullChain(geometry1, geometry2, geometry3, geometry1)
100
- pts = geom3.toPoints(obs)
100
+ pts = geom3.toVertices(obs)
101
101
 
102
102
  t.notThrows.skip(() => geom3.validate(obs))
103
103
  t.is(measureArea(obs), 272.2887171436021)
@@ -17,28 +17,32 @@ export const hullPoints2 = (uniquePoints) => {
17
17
  }
18
18
  })
19
19
 
20
- // gather information for sorting by polar coordinates (point, angle, distSq)
21
- const points = []
22
- uniquePoints.forEach((point) => {
23
- // use faster fakeAtan2 instead of Math.atan2
24
- const angle = fakeAtan2(point[1] - min[1], point[0] - min[0])
25
- const distSq = vec2.squaredDistance(point, min)
26
- points.push({ point, angle, distSq })
27
- })
20
+ // calculations relative to min point
21
+ const squaredDistance = (point) => vec2.squaredDistance(point, min)
22
+ const polarAngle = (point) => (point[0] === min[0] && point[1] === min[1]) ? -Infinity : -(point[0] - min[0]) / (point[1] - min[1])
28
23
 
29
- // sort by polar coordinates
30
- points.sort((pt1, pt2) => pt1.angle !== pt2.angle
31
- ? pt1.angle - pt2.angle
32
- : pt1.distSq - pt2.distSq)
24
+ // points are sorted by polar angle in clockwise order
25
+ const sorted = uniquePoints
26
+ sorted.sort((pt1, pt2) => {
27
+ const pa1 = polarAngle(pt1)
28
+ const pa2 = polarAngle(pt2)
29
+ if (pa1 === pa2) {
30
+ // sort by the relative distances to min point
31
+ return squaredDistance(pt1) - squaredDistance(pt2)
32
+ }
33
+ // sort by polar angles to min point
34
+ return pa1 - pa2
35
+ })
33
36
 
34
37
  const stack = [] // start with empty stack
35
- points.forEach((point) => {
38
+ sorted.forEach((point) => {
36
39
  let cnt = stack.length
37
- while (cnt > 1 && ccw(stack[cnt - 2], stack[cnt - 1], point.point) <= Number.EPSILON) {
38
- stack.pop() // get rid of colinear and interior (clockwise) points
40
+ while (cnt > 1 && ccw(stack[cnt - 2], stack[cnt - 1], point) <= Number.EPSILON) {
41
+ // get rid of colinear and interior (clockwise) points
42
+ stack.pop()
39
43
  cnt = stack.length
40
44
  }
41
- stack.push(point.point)
45
+ stack.push(point)
42
46
  })
43
47
 
44
48
  return stack
@@ -46,15 +50,3 @@ export const hullPoints2 = (uniquePoints) => {
46
50
 
47
51
  // returns: < 0 clockwise, 0 colinear, > 0 counter-clockwise
48
52
  const ccw = (v1, v2, v3) => (v2[0] - v1[0]) * (v3[1] - v1[1]) - (v2[1] - v1[1]) * (v3[0] - v1[0])
49
-
50
- // Returned "angle" is really 1/tan (inverse of slope) made negative to increase with angle.
51
- // This function is strictly for sorting in this algorithm.
52
- const fakeAtan2 = (y, x) => {
53
- // The "if" is a special case for when the minimum vector found in loop above is present.
54
- // We need to ensure that it sorts as the minimum point. Otherwise, this becomes NaN.
55
- if (y === 0 && x === 0) {
56
- return -Infinity
57
- } else {
58
- return -x / y
59
- }
60
- }
@@ -21,8 +21,8 @@ export const toUniquePoints = (geometries) => {
21
21
  if (geom2.isA(geometry)) {
22
22
  geom2.toPoints(geometry).forEach(addPoint)
23
23
  } else if (geom3.isA(geometry)) {
24
- // points are grouped by polygon
25
- geom3.toPoints(geometry).forEach((points) => points.forEach(addPoint))
24
+ // vertices are grouped by polygon
25
+ geom3.toVertices(geometry).forEach((vertices) => vertices.forEach(addPoint))
26
26
  } else if (path2.isA(geometry)) {
27
27
  path2.toPoints(geometry).forEach(addPoint)
28
28
  }
@@ -15,7 +15,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
15
15
 
16
16
  // apply no modifications
17
17
  let result = generalize({}, geometry1)
18
- let pts = geom3.toPoints(result)
18
+ let pts = geom3.toVertices(result)
19
19
  let exp = [
20
20
  [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [-1.5707963267948966, -0.7853981633974483, 3.141592653589793],
21
21
  [-1.5707963267948966, 0.7853981633974483, 3.141592653589793], [-1.5707963267948966, 0.7853981633974483, -3.141592653589793]],
@@ -35,7 +35,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
35
35
 
36
36
  // apply snap only
37
37
  result = generalize({ snap: true }, geometry1)
38
- pts = geom3.toPoints(result)
38
+ pts = geom3.toVertices(result)
39
39
  exp = [
40
40
  [[-1.5707910908071407, -0.7854138713607164, -3.1415821816142815], [-1.5707910908071407, -0.7854138713607164, 3.1415821816142815],
41
41
  [-1.5707910908071407, 0.7854138713607164, 3.1415821816142815], [-1.5707910908071407, 0.7854138713607164, -3.1415821816142815]],
@@ -55,7 +55,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
55
55
 
56
56
  // apply triangulate only
57
57
  result = generalize({ triangulate: true }, geometry1)
58
- pts = geom3.toPoints(result)
58
+ pts = geom3.toVertices(result)
59
59
  exp = [
60
60
  [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [-1.5707963267948966, -0.7853981633974483, 3.141592653589793],
61
61
  [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]],
@@ -89,7 +89,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
89
89
 
90
90
  // apply simplify only (triangles => quads)
91
91
  result = generalize({ simplify: true }, geometry2)
92
- pts = geom3.toPoints(result)
92
+ pts = geom3.toVertices(result)
93
93
  exp = [
94
94
  [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [-1.5707963267948966, -0.7853981633974483, 3.141592653589793],
95
95
  [-1.5707963267948966, 0.7853981633974483, 3.141592653589793], [-1.5707963267948966, 0.7853981633974483, -3.141592653589793]],
@@ -109,7 +109,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
109
109
  })
110
110
 
111
111
  test('generalize: generalize of a geom3 with T junctions produces an expected geom3', (t) => {
112
- const geometry1 = geom3.fromPoints(
112
+ const geometry1 = geom3.fromVertices(
113
113
  [
114
114
  [[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]],
115
115
  [[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, -1, 1]],
@@ -132,7 +132,7 @@ test('generalize: generalize of a geom3 with T junctions produces an expected ge
132
132
  )
133
133
 
134
134
  const result = generalize({ snap: true, triangulate: true }, geometry1)
135
- const pts = geom3.toPoints(result)
135
+ const pts = geom3.toVertices(result)
136
136
  const exp = [
137
137
  [[-1, 0, 0.2], [-1, -1, -1], [-1, -1, 1]],
138
138
  [[-1, 0, 0.2], [-1, -1, 1], [-1, 0, 1]],
@@ -11,7 +11,7 @@ import { insertTjunctions } from './insertTjunctions.js'
11
11
  test('insertTjunctions: insertTjunctions produces expected polygons', (t) => {
12
12
  const geometry1 = geom3.create()
13
13
  const geometry2 = cuboid({ size: [2, 2, 2] })
14
- const geometry3 = geom3.fromPoints(
14
+ const geometry3 = geom3.fromVertices(
15
15
  [
16
16
  [[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]],
17
17
  [[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, -1, 1]],
@@ -24,7 +24,7 @@ test('insertTjunctions: insertTjunctions produces expected polygons', (t) => {
24
24
  [[-1, 1, 1], [-1, -1, 1], [0, 0, 1]]
25
25
  ]
26
26
  )
27
- const geometry4 = geom3.fromPoints(
27
+ const geometry4 = geom3.fromVertices(
28
28
  [
29
29
  [[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]],
30
30
  [[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, -1, 1]],