@jscad/modeling 2.7.2 → 2.9.1

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 (238) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/jscad-modeling.min.js +443 -398
  3. package/package.json +2 -2
  4. package/src/curves/bezier/tangentAt.test.js +1 -1
  5. package/src/curves/bezier/valueAt.test.js +1 -1
  6. package/src/geometries/geom2/index.d.ts +1 -0
  7. package/src/geometries/geom2/index.js +12 -1
  8. package/src/geometries/geom2/isA.js +2 -2
  9. package/src/geometries/geom2/toCompactBinary.js +4 -4
  10. package/src/geometries/geom2/toString.js +1 -1
  11. package/src/geometries/geom2/transform.test.js +1 -1
  12. package/src/geometries/geom2/validate.d.ts +3 -0
  13. package/src/geometries/geom2/validate.js +36 -0
  14. package/src/geometries/geom3/fromCompactBinary.js +1 -1
  15. package/src/geometries/geom3/index.d.ts +1 -0
  16. package/src/geometries/geom3/index.js +19 -1
  17. package/src/geometries/geom3/isA.js +2 -2
  18. package/src/geometries/geom3/toCompactBinary.js +4 -4
  19. package/src/geometries/geom3/toString.js +1 -1
  20. package/src/geometries/geom3/transform.test.js +1 -1
  21. package/src/geometries/geom3/validate.d.ts +3 -0
  22. package/src/geometries/geom3/validate.js +62 -0
  23. package/src/geometries/index.js +8 -1
  24. package/src/geometries/path2/eachPoint.js +3 -3
  25. package/src/geometries/path2/index.d.ts +1 -0
  26. package/src/geometries/path2/index.js +13 -1
  27. package/src/geometries/path2/isA.js +2 -2
  28. package/src/geometries/path2/reverse.js +4 -4
  29. package/src/geometries/path2/toCompactBinary.js +6 -6
  30. package/src/geometries/path2/toString.js +1 -1
  31. package/src/geometries/path2/transform.test.js +1 -1
  32. package/src/geometries/path2/validate.d.ts +3 -0
  33. package/src/geometries/path2/validate.js +41 -0
  34. package/src/geometries/poly2/arePointsInside.js +0 -35
  35. package/src/geometries/poly2/arePointsInside.test.js +1 -1
  36. package/src/geometries/poly2/index.js +6 -0
  37. package/src/geometries/poly3/index.d.ts +1 -0
  38. package/src/geometries/poly3/index.js +9 -2
  39. package/src/geometries/poly3/invert.js +7 -1
  40. package/src/geometries/poly3/isA.js +2 -2
  41. package/src/geometries/poly3/isConvex.js +2 -2
  42. package/src/geometries/poly3/measureArea.js +4 -4
  43. package/src/geometries/poly3/measureArea.test.js +16 -16
  44. package/src/geometries/poly3/measureBoundingBox.js +2 -2
  45. package/src/geometries/poly3/measureBoundingSphere.js +2 -2
  46. package/src/geometries/poly3/measureBoundingSphere.test.js +8 -8
  47. package/src/geometries/poly3/measureSignedVolume.js +4 -4
  48. package/src/geometries/poly3/toPoints.js +2 -2
  49. package/src/geometries/poly3/toString.js +2 -2
  50. package/src/geometries/poly3/transform.js +2 -2
  51. package/src/geometries/poly3/validate.d.ts +4 -0
  52. package/src/geometries/poly3/validate.js +50 -0
  53. package/src/maths/index.js +1 -1
  54. package/src/maths/line2/equals.js +2 -2
  55. package/src/maths/line2/fromValues.js +2 -2
  56. package/src/maths/line2/intersectPointOfLines.js +1 -1
  57. package/src/maths/line2/intersectPointOfLines.test.js +1 -1
  58. package/src/maths/line2/reverse.test.js +1 -1
  59. package/src/maths/line2/transform.test.js +1 -1
  60. package/src/maths/line3/equals.js +2 -2
  61. package/src/maths/line3/reverse.test.js +1 -1
  62. package/src/maths/line3/transform.test.js +1 -1
  63. package/src/maths/mat4/fromVectorRotation.js +1 -1
  64. package/src/maths/mat4/fromVectorRotation.test.js +1 -1
  65. package/src/maths/mat4/identity.test.js +1 -1
  66. package/src/maths/mat4/invert.js +18 -18
  67. package/src/maths/mat4/isIdentity.js +1 -1
  68. package/src/maths/mat4/isMirroring.js +4 -4
  69. package/src/maths/mat4/isMirroring.test.js +1 -1
  70. package/src/maths/mat4/leftMultiplyVec3.js +2 -2
  71. package/src/maths/mat4/toString.js +2 -2
  72. package/src/maths/mat4/translate.test.js +1 -1
  73. package/src/maths/plane/flip.test.js +1 -1
  74. package/src/maths/plane/fromPoints.d.ts +1 -1
  75. package/src/maths/plane/fromPoints.js +1 -3
  76. package/src/maths/plane/signedDistanceToPoint.js +1 -1
  77. package/src/maths/plane/transform.test.js +1 -1
  78. package/src/maths/utils/aboutEqualNormals.js +2 -2
  79. package/src/maths/vec2/abs.d.ts +1 -1
  80. package/src/maths/vec2/add.test.js +1 -1
  81. package/src/maths/vec2/angleDegrees.d.ts +1 -1
  82. package/src/maths/vec2/angleRadians.d.ts +1 -1
  83. package/src/maths/vec2/create.js +1 -1
  84. package/src/maths/vec2/cross.test.js +1 -1
  85. package/src/maths/vec2/divide.test.js +1 -1
  86. package/src/maths/vec2/fromAngleDegrees.js +1 -1
  87. package/src/maths/vec2/fromScalar.js +1 -1
  88. package/src/maths/vec2/length.d.ts +1 -1
  89. package/src/maths/vec2/length.js +1 -1
  90. package/src/maths/vec2/lerp.test.js +1 -1
  91. package/src/maths/vec2/multiply.test.js +1 -1
  92. package/src/maths/vec2/negate.test.js +1 -1
  93. package/src/maths/vec2/normal.js +1 -1
  94. package/src/maths/vec2/normalize.d.ts +1 -1
  95. package/src/maths/vec2/normalize.test.js +1 -1
  96. package/src/maths/vec2/rotate.test.js +1 -1
  97. package/src/maths/vec2/squaredLength.d.ts +1 -1
  98. package/src/maths/vec2/squaredLength.js +3 -3
  99. package/src/maths/vec2/subtract.test.js +1 -1
  100. package/src/maths/vec2/toString.js +1 -1
  101. package/src/maths/vec2/transform.test.js +1 -1
  102. package/src/maths/vec3/abs.d.ts +1 -1
  103. package/src/maths/vec3/add.test.js +1 -1
  104. package/src/maths/vec3/cross.test.js +1 -1
  105. package/src/maths/vec3/divide.test.js +1 -1
  106. package/src/maths/vec3/fromScalar.js +1 -1
  107. package/src/maths/vec3/fromVec2.d.ts +1 -1
  108. package/src/maths/vec3/fromVec2.js +3 -3
  109. package/src/maths/vec3/length.d.ts +1 -1
  110. package/src/maths/vec3/length.js +4 -4
  111. package/src/maths/vec3/lerp.test.js +1 -1
  112. package/src/maths/vec3/multiply.test.js +1 -1
  113. package/src/maths/vec3/negate.d.ts +1 -1
  114. package/src/maths/vec3/negate.test.js +1 -1
  115. package/src/maths/vec3/normalize.d.ts +1 -1
  116. package/src/maths/vec3/normalize.test.js +1 -1
  117. package/src/maths/vec3/rotateX.test.js +1 -1
  118. package/src/maths/vec3/rotateY.test.js +1 -1
  119. package/src/maths/vec3/rotateZ.test.js +1 -1
  120. package/src/maths/vec3/scale.test.js +1 -1
  121. package/src/maths/vec3/squaredLength.d.ts +1 -1
  122. package/src/maths/vec3/squaredLength.js +4 -4
  123. package/src/maths/vec3/subtract.test.js +1 -1
  124. package/src/maths/vec3/toString.js +1 -1
  125. package/src/maths/vec3/transform.test.js +1 -1
  126. package/src/maths/vec4/toString.js +1 -1
  127. package/src/maths/vec4/transform.test.js +1 -1
  128. package/src/measurements/measureBoundingSphere.js +4 -4
  129. package/src/measurements/measureCenterOfMass.js +1 -1
  130. package/src/measurements/measureCenterOfMass.test.js +2 -2
  131. package/src/operations/booleans/intersect.test.js +8 -0
  132. package/src/operations/booleans/mayOverlap.js +3 -3
  133. package/src/operations/booleans/retessellate.js +2 -2
  134. package/src/operations/booleans/scission.js +1 -1
  135. package/src/operations/booleans/scission.test.js +4 -4
  136. package/src/operations/booleans/subtract.js +1 -1
  137. package/src/operations/booleans/subtract.test.js +8 -0
  138. package/src/operations/booleans/trees/Node.js +10 -16
  139. package/src/operations/booleans/trees/PolygonTreeNode.js +13 -14
  140. package/src/operations/booleans/trees/Tree.js +1 -2
  141. package/src/operations/booleans/trees/splitPolygonByPlane.js +2 -3
  142. package/src/operations/booleans/union.test.js +28 -1
  143. package/src/operations/booleans/unionGeom3Sub.js +1 -1
  144. package/src/operations/expansions/expand.js +2 -2
  145. package/src/operations/expansions/expand.test.js +32 -55
  146. package/src/operations/expansions/expandShell.js +24 -18
  147. package/src/operations/expansions/offset.js +1 -1
  148. package/src/operations/expansions/offset.test.js +50 -89
  149. package/src/operations/expansions/offsetFromPoints.js +11 -6
  150. package/src/operations/extrusions/earcut/assignHoles.js +91 -0
  151. package/src/operations/extrusions/earcut/assignHoles.test.js +74 -0
  152. package/src/operations/extrusions/earcut/eliminateHoles.js +131 -0
  153. package/src/operations/extrusions/earcut/index.js +252 -0
  154. package/src/operations/extrusions/earcut/linkedList.js +58 -0
  155. package/src/operations/extrusions/earcut/linkedListSort.js +54 -0
  156. package/src/operations/extrusions/earcut/linkedPolygon.js +197 -0
  157. package/src/operations/extrusions/earcut/polygonHierarchy.js +64 -0
  158. package/src/operations/extrusions/earcut/triangle.js +16 -0
  159. package/src/operations/extrusions/extrudeFromSlices.js +10 -3
  160. package/src/operations/extrusions/extrudeFromSlices.test.js +47 -31
  161. package/src/operations/extrusions/extrudeLinear.js +10 -5
  162. package/src/operations/extrusions/extrudeLinear.test.js +91 -35
  163. package/src/operations/extrusions/extrudeLinearGeom2.js +5 -2
  164. package/src/operations/extrusions/extrudeLinearPath2.js +24 -0
  165. package/src/operations/extrusions/extrudeRectangular.js +1 -1
  166. package/src/operations/extrusions/extrudeRectangular.test.js +22 -15
  167. package/src/operations/extrusions/extrudeRotate.test.js +31 -27
  168. package/src/operations/extrusions/project.js +1 -1
  169. package/src/operations/extrusions/project.test.js +5 -5
  170. package/src/operations/extrusions/slice/calculatePlane.js +7 -4
  171. package/src/operations/extrusions/slice/isA.js +2 -2
  172. package/src/operations/extrusions/slice/repairSlice.js +47 -0
  173. package/src/operations/extrusions/slice/toPolygons.js +24 -60
  174. package/src/operations/hulls/hull.test.js +25 -2
  175. package/src/operations/hulls/hullChain.js +1 -1
  176. package/src/operations/hulls/hullChain.test.js +6 -4
  177. package/src/operations/hulls/hullGeom2.js +1 -1
  178. package/src/operations/hulls/hullPath2.js +6 -4
  179. package/src/operations/hulls/hullPath2.test.js +16 -0
  180. package/src/operations/hulls/hullPoints2.test.js +1 -1
  181. package/src/operations/modifiers/edges.js +1 -1
  182. package/src/operations/modifiers/generalize.js +1 -1
  183. package/src/operations/modifiers/generalize.test.js +6 -0
  184. package/src/operations/modifiers/snap.test.js +3 -3
  185. package/src/operations/transforms/align.d.ts +1 -1
  186. package/src/operations/transforms/align.test.js +12 -0
  187. package/src/operations/transforms/center.js +17 -17
  188. package/src/operations/transforms/center.test.js +12 -0
  189. package/src/operations/transforms/mirror.js +12 -12
  190. package/src/operations/transforms/mirror.test.js +16 -0
  191. package/src/operations/transforms/rotate.js +12 -12
  192. package/src/operations/transforms/rotate.test.js +10 -0
  193. package/src/operations/transforms/scale.js +19 -19
  194. package/src/operations/transforms/scale.test.js +15 -0
  195. package/src/operations/transforms/transform.js +3 -3
  196. package/src/operations/transforms/transform.test.js +5 -0
  197. package/src/operations/transforms/translate.js +14 -14
  198. package/src/operations/transforms/translate.test.js +16 -0
  199. package/src/primitives/arc.js +1 -1
  200. package/src/primitives/arc.test.js +11 -0
  201. package/src/primitives/circle.test.js +15 -9
  202. package/src/primitives/cube.test.js +3 -0
  203. package/src/primitives/cuboid.test.js +9 -24
  204. package/src/primitives/cylinder.test.js +7 -4
  205. package/src/primitives/cylinderElliptic.js +13 -6
  206. package/src/primitives/cylinderElliptic.test.js +72 -52
  207. package/src/primitives/ellipse.js +3 -1
  208. package/src/primitives/ellipse.test.js +14 -8
  209. package/src/primitives/ellipsoid.js +7 -5
  210. package/src/primitives/ellipsoid.test.js +84 -82
  211. package/src/primitives/geodesicSphere.d.ts +0 -1
  212. package/src/primitives/geodesicSphere.test.js +3 -0
  213. package/src/primitives/line.test.js +1 -0
  214. package/src/primitives/polygon.test.js +15 -10
  215. package/src/primitives/polyhedron.js +1 -1
  216. package/src/primitives/polyhedron.test.js +14 -42
  217. package/src/primitives/rectangle.test.js +3 -0
  218. package/src/primitives/roundedCuboid.test.js +5 -0
  219. package/src/primitives/roundedCylinder.js +6 -4
  220. package/src/primitives/roundedCylinder.test.js +40 -36
  221. package/src/primitives/roundedRectangle.test.js +5 -0
  222. package/src/primitives/sphere.test.js +52 -73
  223. package/src/primitives/square.test.js +3 -0
  224. package/src/primitives/star.test.js +6 -0
  225. package/src/primitives/torus.d.ts +0 -1
  226. package/src/primitives/torus.test.js +8 -1
  227. package/src/primitives/triangle.js +1 -1
  228. package/src/primitives/triangle.test.js +7 -0
  229. package/src/text/vectorText.js +2 -2
  230. package/src/utils/areAllShapesTheSameType.js +2 -2
  231. package/src/utils/areAllShapesTheSameType.test.js +17 -0
  232. package/src/utils/index.d.ts +1 -0
  233. package/src/utils/index.js +3 -1
  234. package/src/utils/padArrayToLength.js +1 -1
  235. package/src/utils/trigonometry.d.ts +2 -0
  236. package/src/utils/trigonometry.js +35 -0
  237. package/src/utils/trigonometry.test.js +25 -0
  238. package/test/helpers/nearlyEqual.js +4 -1
@@ -16,14 +16,14 @@ test('project (defaults)', (t) => {
16
16
 
17
17
  const results = project({ }, geometry0, geometry1, geometry2, geometry3, geometry4)
18
18
  t.is(results.length, 5)
19
- t.true(geom2.isA(results[0]))
20
- t.true(geom2.isA(results[1]))
19
+ t.notThrows(() => geom2.validate(results[0]))
20
+ t.notThrows(() => geom2.validate(results[1]))
21
21
  t.is(results[2], geometry2)
22
22
  t.is(results[3], geometry3)
23
23
  t.is(results[4], geometry4)
24
24
 
25
25
  const result = project({ }, torus({ outerSegments: 4 }))
26
- t.true(geom2.isA(result))
26
+ t.notThrows(() => geom2.validate(result))
27
27
  const pts = geom2.toPoints(result)
28
28
  const exp = [
29
29
  [0, -2.9999933333333333],
@@ -40,7 +40,7 @@ test('project (defaults)', (t) => {
40
40
 
41
41
  test('project (X and Y axis)', (t) => {
42
42
  let result = project({ axis: [1, 0, 0], origin: [1, 0, 0] }, torus({ outerSegments: 4 }))
43
- t.true(geom2.isA(result))
43
+ t.notThrows(() => geom2.validate(result))
44
44
  let pts = geom2.toPoints(result)
45
45
  let exp = [
46
46
  [-1.0000200000000001, -3.999986666666667],
@@ -81,7 +81,7 @@ test('project (X and Y axis)', (t) => {
81
81
  t.true(comparePoints(pts, exp))
82
82
 
83
83
  result = project({ axis: [0, 1, 0], origin: [0, -1, 0] }, torus({ outerSegments: 4 }))
84
- t.true(geom2.isA(result))
84
+ t.notThrows(() => geom2.validate(result))
85
85
  pts = geom2.toPoints(result)
86
86
  exp = [
87
87
  [3.999986666666667, -1.0000200000000001],
@@ -23,10 +23,13 @@ const calculatePlane = (slice) => {
23
23
  let farthestEdge
24
24
  let distance = 0
25
25
  edges.forEach((edge) => {
26
- const d = vec3.squaredDistance(midpoint, edge[0])
27
- if (d > distance) {
28
- farthestEdge = edge
29
- distance = d
26
+ // Make sure that the farthest edge is not a self-edge
27
+ if (!vec3.equals(edge[0], edge[1])) {
28
+ const d = vec3.squaredDistance(midpoint, edge[0])
29
+ if (d > distance) {
30
+ farthestEdge = edge
31
+ distance = d
32
+ }
30
33
  }
31
34
  })
32
35
  // find the before edge
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Determin if the given object is a slice.
3
- * @param {slice} object - the object to interogate
2
+ * Determine if the given object is a slice.
3
+ * @param {slice} object - the object to interrogate
4
4
  * @returns {Boolean} true if the object matches a slice
5
5
  * @alias module:modeling/extrusions/slice.isA
6
6
  */
@@ -0,0 +1,47 @@
1
+ const vec3 = require('../../../maths/vec3')
2
+
3
+ /*
4
+ * Mend gaps in a 2D slice to make it a closed polygon
5
+ */
6
+ const repairSlice = (slice) => {
7
+ if (!slice.edges) return slice
8
+ const vertexMap = {} // string key to vertex map
9
+ const edgeCount = {} // count of (in - out) edges
10
+ slice.edges.forEach((edge) => {
11
+ const inKey = edge[0].toString()
12
+ const outKey = edge[1].toString()
13
+ vertexMap[inKey] = edge[0]
14
+ vertexMap[outKey] = edge[1]
15
+ edgeCount[inKey] = (edgeCount[inKey] || 0) + 1 // in
16
+ edgeCount[outKey] = (edgeCount[outKey] || 0) - 1 // out
17
+ })
18
+ // find vertices which are missing in or out edges
19
+ const missingIn = Object.keys(edgeCount).filter((e) => edgeCount[e] < 0)
20
+ const missingOut = Object.keys(edgeCount).filter((e) => edgeCount[e] > 0)
21
+ // pairwise distance of bad vertices
22
+ missingIn.forEach((key1) => {
23
+ const v1 = vertexMap[key1]
24
+ // find the closest vertex that is missing an out edge
25
+ let bestDistance = Infinity
26
+ let bestReplacement
27
+ missingOut.forEach((key2) => {
28
+ const v2 = vertexMap[key2]
29
+ const distance = Math.hypot(v1[0] - v2[0], v1[1] - v2[1])
30
+ if (distance < bestDistance) {
31
+ bestDistance = distance
32
+ bestReplacement = v2
33
+ }
34
+ })
35
+ console.warn(`repairSlice: repairing vertex gap ${v1} to ${bestReplacement} distance ${bestDistance}`)
36
+ // merge broken vertices
37
+ slice.edges.forEach((edge) => {
38
+ if (edge[0].toString() === key1) edge[0] = bestReplacement
39
+ if (edge[1].toString() === key1) edge[1] = bestReplacement
40
+ })
41
+ })
42
+ // Remove self-edges
43
+ slice.edges = slice.edges.filter((e) => !vec3.equals(e[0], e[1]))
44
+ return slice
45
+ }
46
+
47
+ module.exports = repairSlice
@@ -1,21 +1,6 @@
1
- const vec3 = require('../../../maths/vec3')
2
-
3
- const geom3 = require('../../../geometries/geom3')
4
1
  const poly3 = require('../../../geometries/poly3')
5
-
6
- const intersectGeom3Sub = require('../../booleans/intersectGeom3Sub')
7
-
8
- const calculatePlane = require('./calculatePlane')
9
-
10
- const toPolygon3D = (vector, edge) => {
11
- const points = [
12
- vec3.subtract(vec3.create(), edge[0], vector),
13
- vec3.subtract(vec3.create(), edge[1], vector),
14
- vec3.add(vec3.create(), edge[1], vector),
15
- vec3.add(vec3.create(), edge[0], vector)
16
- ]
17
- return poly3.fromPoints(points)
18
- }
2
+ const earcut = require('../earcut')
3
+ const PolygonHierarchy = require('../earcut/polygonHierarchy')
19
4
 
20
5
  /**
21
6
  * Return a list of polygons which are enclosed by the slice.
@@ -24,52 +9,31 @@ const toPolygon3D = (vector, edge) => {
24
9
  * @alias module:modeling/extrusions/slice.toPolygons
25
10
  */
26
11
  const toPolygons = (slice) => {
27
- const splane = calculatePlane(slice)
28
-
29
- // find the midpoint of the slice, which will lie on the plane by definition
30
- const edges = slice.edges
31
- const midpoint = edges.reduce((point, edge) => vec3.add(vec3.create(), point, edge[0]), vec3.create())
32
- vec3.scale(midpoint, midpoint, 1 / edges.length)
33
-
34
- // find the farthest edge from the midpoint, which will be on an outside edge
35
- let farthestEdge = [[NaN, NaN, NaN], [NaN, NaN, NaN]]
36
- let distance = 0
37
- edges.forEach((edge) => {
38
- const d = vec3.squaredDistance(midpoint, edge[0])
39
- if (d > distance) {
40
- farthestEdge = edge
41
- distance = d
12
+ const hierarchy = new PolygonHierarchy(slice)
13
+
14
+ const polygons = []
15
+ hierarchy.roots.forEach(({ solid, holes }) => {
16
+ // hole indices
17
+ let index = solid.length
18
+ const holesIndex = []
19
+ holes.forEach((hole, i) => {
20
+ holesIndex.push(index)
21
+ index += hole.length
22
+ })
23
+
24
+ // compute earcut triangulation for each solid
25
+ const vertices = [solid, ...holes].flat()
26
+ const data = vertices.flat()
27
+ // Get original 3D vertex by index
28
+ const getVertex = (i) => hierarchy.to3D(vertices[i])
29
+ const indices = earcut(data, holesIndex)
30
+ for (let i = 0; i < indices.length; i += 3) {
31
+ // Map back to original vertices
32
+ const tri = indices.slice(i, i + 3).map(getVertex)
33
+ polygons.push(poly3.fromPointsAndPlane(tri, hierarchy.plane))
42
34
  }
43
35
  })
44
36
 
45
- // create one LARGE polygon to encompass the side, i.e. base
46
- const direction = vec3.subtract(vec3.create(), farthestEdge[0], midpoint)
47
- const perpendicular = vec3.cross(vec3.create(), splane, direction)
48
-
49
- const p1 = vec3.add(vec3.create(), midpoint, direction)
50
- vec3.add(p1, p1, direction)
51
- const p2 = vec3.add(vec3.create(), midpoint, perpendicular)
52
- vec3.add(p2, p2, perpendicular)
53
- const p3 = vec3.subtract(vec3.create(), midpoint, direction)
54
- vec3.subtract(p3, p3, direction)
55
- const p4 = vec3.subtract(vec3.create(), midpoint, perpendicular)
56
- vec3.subtract(p4, p4, perpendicular)
57
- const poly1 = poly3.fromPoints([p1, p2, p3, p4])
58
- const base = geom3.create([poly1])
59
-
60
- const wallPolygons = edges.map((edge) => toPolygon3D(splane, edge))
61
- const walls = geom3.create(wallPolygons)
62
-
63
- // make an insection of the base and the walls, creating... a set of polygons!
64
- const geometry3 = intersectGeom3Sub(base, walls)
65
-
66
- // return only those polygons from the base
67
- let polygons = geom3.toPolygons(geometry3)
68
- polygons = polygons.filter((polygon) => {
69
- const a = vec3.angle(splane, poly3.plane(polygon))
70
- // walls should be PI / 2 radians rotated from the base
71
- return Math.abs(a) < (Math.PI / 90)
72
- })
73
37
  return polygons
74
38
  }
75
39
 
@@ -16,12 +16,14 @@ test('hull (single, geom2)', (t) => {
16
16
  let obs = hull(geometry)
17
17
  let pts = geom2.toPoints(obs)
18
18
 
19
+ t.notThrows(() => geom2.validate(geometry))
19
20
  t.is(pts.length, 0)
20
21
 
21
22
  geometry = geom2.fromPoints([[5, 5], [-5, 5], [-5, -5], [5, -5]])
22
23
  obs = hull(geometry)
23
24
  pts = geom2.toPoints(obs)
24
25
 
26
+ t.notThrows(() => geom2.validate(geometry))
25
27
  t.is(pts.length, 4)
26
28
 
27
29
  // convex C shape
@@ -40,10 +42,11 @@ test('hull (single, geom2)', (t) => {
40
42
  obs = hull(geometry)
41
43
  pts = geom2.toPoints(obs)
42
44
 
45
+ t.notThrows(() => geom2.validate(geometry))
43
46
  t.is(pts.length, 7)
44
47
  })
45
48
 
46
- test('hull (multiple, overlaping, geom2)', (t) => {
49
+ test('hull (multiple, overlapping, geom2)', (t) => {
47
50
  const geometry1 = geom2.fromPoints([[5, 5], [-5, 5], [-5, -5], [5, -5]])
48
51
  const geometry2 = geom2.fromPoints([[3, 3], [-3, 3], [-3, -3], [3, -3]])
49
52
  const geometry3 = geom2.fromPoints([[6, 3], [-6, 3], [-6, -3], [6, -3]])
@@ -66,23 +69,27 @@ test('hull (multiple, overlaping, geom2)', (t) => {
66
69
  let obs = hull(geometry1, geometry1)
67
70
  let pts = geom2.toPoints(obs)
68
71
 
72
+ t.notThrows(() => geom2.validate(obs))
69
73
  t.is(pts.length, 4)
70
74
 
71
75
  // one inside another
72
76
  obs = hull(geometry1, geometry2)
73
77
  pts = geom2.toPoints(obs)
74
78
 
79
+ t.notThrows(() => geom2.validate(obs))
75
80
  t.is(pts.length, 4)
76
81
 
77
82
  // one overlapping another
78
83
  obs = hull(geometry1, geometry3)
79
84
  pts = geom2.toPoints(obs)
80
85
 
86
+ t.notThrows(() => geom2.validate(obs))
81
87
  t.is(pts.length, 8)
82
88
 
83
89
  obs = hull(geometry2, geometry4)
84
90
  pts = geom2.toPoints(obs)
85
91
 
92
+ t.notThrows(() => geom2.validate(obs))
86
93
  t.is(pts.length, 7)
87
94
  })
88
95
 
@@ -108,22 +115,27 @@ test('hull (multiple, various, geom2)', (t) => {
108
115
 
109
116
  let obs = hull(geometry1, geometry2)
110
117
  let pts = geom2.toPoints(obs)
118
+ t.notThrows(() => geom2.validate(obs))
111
119
  t.is(pts.length, 5)
112
120
 
113
121
  obs = hull(geometry1, geometry3)
114
122
  pts = geom2.toPoints(obs)
123
+ t.notThrows(() => geom2.validate(obs))
115
124
  t.is(pts.length, 5)
116
125
 
117
126
  obs = hull(geometry2, geometry3)
118
127
  pts = geom2.toPoints(obs)
128
+ t.notThrows(() => geom2.validate(obs))
119
129
  t.is(pts.length, 5)
120
130
 
121
131
  obs = hull(geometry1, geometry2, geometry3)
122
132
  pts = geom2.toPoints(obs)
133
+ t.notThrows(() => geom2.validate(obs))
123
134
  t.is(pts.length, 6)
124
135
 
125
136
  obs = hull(geometry5, geometry4)
126
137
  pts = geom2.toPoints(obs)
138
+ t.notThrows(() => geom2.validate(obs))
127
139
  t.is(pts.length, 8)
128
140
  })
129
141
 
@@ -133,6 +145,7 @@ test('hull (single, path2)', (t) => {
133
145
  let obs = hull(geometry)
134
146
  let pts = path2.toPoints(obs)
135
147
 
148
+ t.notThrows(() => path2.validate(obs))
136
149
  t.is(pts.length, 0)
137
150
 
138
151
  geometry = path2.fromPoints({}, [[0, 0], [5, 0], [5, 10], [4, 1]])
@@ -140,6 +153,7 @@ test('hull (single, path2)', (t) => {
140
153
  obs = hull(geometry)
141
154
  pts = path2.toPoints(obs)
142
155
 
156
+ t.notThrows(() => path2.validate(obs))
143
157
  t.is(pts.length, 3)
144
158
  })
145
159
 
@@ -165,22 +179,27 @@ test('hull (multiple, various, path2)', (t) => {
165
179
 
166
180
  let obs = hull(geometry1, geometry2)
167
181
  let pts = path2.toPoints(obs)
182
+ t.notThrows(() => path2.validate(obs))
168
183
  t.is(pts.length, 5)
169
184
 
170
185
  obs = hull(geometry1, geometry3)
171
186
  pts = path2.toPoints(obs)
187
+ t.notThrows(() => path2.validate(obs))
172
188
  t.is(pts.length, 5)
173
189
 
174
190
  obs = hull(geometry2, geometry3)
175
191
  pts = path2.toPoints(obs)
192
+ t.notThrows(() => path2.validate(obs))
176
193
  t.is(pts.length, 5)
177
194
 
178
195
  obs = hull(geometry1, geometry2, geometry3)
179
196
  pts = path2.toPoints(obs)
197
+ t.notThrows(() => path2.validate(obs))
180
198
  t.is(pts.length, 6)
181
199
 
182
200
  obs = hull(geometry5, geometry4)
183
201
  pts = path2.toPoints(obs)
202
+ t.notThrows(() => path2.validate(obs))
184
203
  t.is(pts.length, 8)
185
204
  })
186
205
 
@@ -190,6 +209,7 @@ test('hull (single, geom3)', (t) => {
190
209
  let obs = hull(geometry)
191
210
  let pts = geom3.toPoints(obs)
192
211
 
212
+ t.notThrows(() => geom3.validate(obs))
193
213
  t.is(pts.length, 0)
194
214
 
195
215
  geometry = sphere({ radius: 2, segments: 8 })
@@ -197,6 +217,7 @@ test('hull (single, geom3)', (t) => {
197
217
  obs = hull(geometry)
198
218
  pts = geom3.toPoints(obs)
199
219
 
220
+ t.notThrows.skip(() => geom3.validate(obs))
200
221
  t.is(pts.length, 32)
201
222
  })
202
223
 
@@ -214,6 +235,7 @@ test('hull (multiple, geom3)', (t) => {
214
235
  [[1, -1, 1], [-1, -1, 1], [-1, -1, -1], [1, -1, -1]]
215
236
  ]
216
237
 
238
+ t.notThrows(() => geom3.validate(obs))
217
239
  t.is(pts.length, 6)
218
240
  t.true(comparePolygonsAsPoints(pts, exp))
219
241
 
@@ -236,6 +258,7 @@ test('hull (multiple, geom3)', (t) => {
236
258
  [[1, 1, -1], [6.5, 6.5, 3.5], [6.5, 3.5, 3.5], [1, -1, -1]]
237
259
  ]
238
260
 
261
+ t.notThrows(() => geom3.validate(obs))
239
262
  t.is(pts.length, 12)
240
263
  t.true(comparePolygonsAsPoints(pts, exp))
241
264
  })
@@ -248,6 +271,6 @@ test('hull (multiple, overlapping, geom3)', (t) => {
248
271
  const obs = hull(geometry1, geometry2, geometry3)
249
272
  const pts = geom3.toPoints(obs)
250
273
 
251
- // t.is(pts.length, 160)
274
+ t.notThrows(() => geom3.validate(obs))
252
275
  t.is(pts.length, 92)
253
276
  })
@@ -5,7 +5,7 @@ const union = require('../booleans/union')
5
5
  const hull = require('./hull')
6
6
 
7
7
  /**
8
- * Create a chain of hulled geometries from the given gemetries.
8
+ * Create a chain of hulled geometries from the given geometries.
9
9
  * Essentially hull A+B, B+C, C+D, etc., then union the results.
10
10
  * The given geometries should be of the same type, either geom2 or geom3 or path2.
11
11
  *
@@ -12,12 +12,14 @@ test('hullChain (two, geom2)', (t) => {
12
12
  let obs = hullChain(geometry1, geometry1)
13
13
  let pts = geom2.toPoints(obs)
14
14
 
15
+ t.notThrows(() => geom2.validate(obs))
15
16
  t.is(pts.length, 4)
16
17
 
17
18
  // different
18
19
  obs = hullChain(geometry1, geometry2)
19
20
  pts = geom2.toPoints(obs)
20
21
 
22
+ t.notThrows(() => geom2.validate(obs))
21
23
  t.is(pts.length, 6)
22
24
  })
23
25
 
@@ -31,16 +33,16 @@ test('hullChain (three, geom2)', (t) => {
31
33
  let pts = geom2.toPoints(obs)
32
34
 
33
35
  // the sides change based on the bestplane chosen in trees/Node.js
36
+ t.notThrows(() => geom2.validate(obs))
34
37
  t.is(pts.length, 10)
35
- // t.is(pts.length, 11)
36
38
 
37
39
  // closed
38
40
  obs = hullChain(geometry1, geometry2, geometry3, geometry1)
39
41
  pts = geom2.toPoints(obs)
40
42
 
41
43
  // the sides change based on the bestplane chosen in trees/Node.js
44
+ t.notThrows(() => geom2.validate(obs))
42
45
  t.is(pts.length, 10)
43
- // t.is(pts.length, 13)
44
46
  })
45
47
 
46
48
  test('hullChain (three, geom3)', (t) => {
@@ -73,13 +75,13 @@ test('hullChain (three, geom3)', (t) => {
73
75
  let obs = hullChain(geometry1, geometry2, geometry3)
74
76
  let pts = geom3.toPoints(obs)
75
77
 
76
- // t.is(pts.length, 27)
78
+ t.notThrows.skip(() => geom3.validate(obs))
77
79
  t.is(pts.length, 23)
78
80
 
79
81
  // closed
80
82
  obs = hullChain(geometry1, geometry2, geometry3, geometry1)
81
83
  pts = geom3.toPoints(obs)
82
84
 
83
- // t.is(pts.length, 45)
85
+ t.notThrows.skip(() => geom3.validate(obs))
84
86
  t.is(pts.length, 28)
85
87
  })
@@ -30,7 +30,7 @@ const hullGeom2 = (...geometries) => {
30
30
 
31
31
  const hullpoints = hullPoints2(uniquepoints)
32
32
 
33
- // NOTE: more then three points are required to create a new geometry
33
+ // NOTE: more than three points are required to create a new geometry
34
34
  if (hullpoints.length < 3) return geom2.create()
35
35
 
36
36
  // assemble a new geometry from the list of points
@@ -1,7 +1,5 @@
1
1
  const flatten = require('../../utils/flatten')
2
2
 
3
- const vec2 = require('../../maths/vec2')
4
-
5
3
  const path2 = require('../../geometries/path2')
6
4
 
7
5
  const hullPoints2 = require('./hullPoints2')
@@ -16,11 +14,15 @@ const hullPath2 = (...geometries) => {
16
14
 
17
15
  // extract the unique points from the geometries
18
16
  const uniquepoints = []
17
+ const found = new Set()
19
18
  geometries.forEach((geometry) => {
20
19
  const points = path2.toPoints(geometry)
21
20
  points.forEach((point) => {
22
- const index = uniquepoints.findIndex((unique) => vec2.equals(unique, point))
23
- if (index < 0) uniquepoints.push(point)
21
+ const key = point.toString()
22
+ if (!found.has(key)) {
23
+ uniquepoints.push(point)
24
+ found.add(key)
25
+ }
24
26
  })
25
27
  })
26
28
 
@@ -0,0 +1,16 @@
1
+ const test = require('ava')
2
+
3
+ const { path2 } = require('../../geometries')
4
+
5
+ const hullPath2 = require('./hullPath2')
6
+
7
+ test('hullPath2', (t) => {
8
+ const closed = true
9
+ const geometry1 = path2.fromPoints({ closed }, [[0, 0], [-4, 4], [-4, -4]])
10
+ const geometry2 = path2.fromPoints({ closed }, [[0, 0], [4, -4], [4, 4]])
11
+
12
+ const obs = hullPath2(geometry1, geometry2)
13
+ t.notThrows(() => path2.validate(obs))
14
+ const pts = path2.toPoints(obs)
15
+ t.is(pts.length, 4)
16
+ })
@@ -42,7 +42,7 @@ test('hullPoints2 bug #114 2 circles with 18 segments', (t) => {
42
42
  [7.298133329356933, -1.9283628290596186]
43
43
  ]
44
44
 
45
- // we just want to bwe sure no err happens for this case
45
+ // we just want to be sure no err happens for this case
46
46
  const out = hullPoints2(points)
47
47
  t.is(out.length, 19)
48
48
  })
@@ -149,7 +149,7 @@ const splitEdge = (openedges, edge, eps) => {
149
149
  */
150
150
  const cullOpenEdges = (edges) => {
151
151
  const openedges = []
152
- edges.forEach((edge, i) => {
152
+ edges.forEach((edge) => {
153
153
  const polygons = edge.polygons
154
154
  if (polygons.length === 1) {
155
155
  // console.log('open edge: ',edge[0],'<-->',edge[1])
@@ -81,7 +81,7 @@ const generalize = (options, ...geometries) => {
81
81
  geometries = flatten(geometries)
82
82
  if (geometries.length === 0) throw new Error('wrong number of arguments')
83
83
 
84
- const results = geometries.map((geometry, i) => {
84
+ const results = geometries.map((geometry) => {
85
85
  if (path2.isA(geometry)) return generalizePath2(options, geometry)
86
86
  if (geom2.isA(geometry)) return generalizeGeom2(options, geometry)
87
87
  if (geom3.isA(geometry)) return generalizeGeom3(options, geometry)
@@ -28,6 +28,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
28
28
  [[-1.5707963267948966, -0.7853981633974483, 3.141592653589793], [1.5707963267948966, -0.7853981633974483, 3.141592653589793],
29
29
  [1.5707963267948966, 0.7853981633974483, 3.141592653589793], [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]]
30
30
  ]
31
+ t.notThrows(() => geom3.validate(result))
31
32
  t.true(comparePolygonsAsPoints(pts, exp))
32
33
 
33
34
  // apply snap only
@@ -47,6 +48,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
47
48
  [[-1.5707910908071407, -0.7854138713607164, 3.1415821816142815], [1.5707910908071407, -0.7854138713607164, 3.1415821816142815],
48
49
  [1.5707910908071407, 0.7854138713607164, 3.1415821816142815], [-1.5707910908071407, 0.7854138713607164, 3.1415821816142815]]
49
50
  ]
51
+ t.notThrows(() => geom3.validate(result))
50
52
  t.true(comparePolygonsAsPoints(pts, exp))
51
53
 
52
54
  // apply triangulate only
@@ -78,6 +80,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
78
80
  [[-1.5707963267948966, -0.7853981633974483, 3.141592653589793], [1.5707963267948966, 0.7853981633974483, 3.141592653589793],
79
81
  [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]]
80
82
  ]
83
+ t.notThrows(() => geom3.validate(result))
81
84
  t.true(comparePolygonsAsPoints(pts, exp))
82
85
 
83
86
  const geometry2 = result // save the triangles for another test
@@ -99,6 +102,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
99
102
  [[-1.5707963267948966, -0.7853981633974483, 3.141592653589793], [1.5707963267948966, -0.7853981633974483, 3.141592653589793],
100
103
  [1.5707963267948966, 0.7853981633974483, 3.141592653589793], [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]]
101
104
  ]
105
+ t.notThrows(() => geom3.validate(result))
102
106
  t.true(comparePolygonsAsPoints(pts, exp))
103
107
 
104
108
  // apply repairs only (triangles)
@@ -130,6 +134,7 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
130
134
  [[-1.5707963267948966, -0.7853981633974483, 3.141592653589793], [1.5707963267948966, 0.7853981633974483, 3.141592653589793],
131
135
  [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]]
132
136
  ]
137
+ t.notThrows(() => geom3.validate(result))
133
138
  t.true(comparePolygonsAsPoints(pts, exp))
134
139
  })
135
140
 
@@ -190,5 +195,6 @@ test('generalize: generalize of a geom3 with T junctions produces an expected ge
190
195
  [[0, 1, 1], [-1, 1, 1], [0, 0, 1]],
191
196
  [[-1, 1, 1], [-1, 0, 1], [0, 0, 1]]
192
197
  ]
198
+ t.notThrows(() => geom3.validate(result))
193
199
  t.true(comparePolygonsAsPoints(pts, exp))
194
200
  })
@@ -11,7 +11,7 @@ const { snap } = require('./index')
11
11
  test('snap: snap of a path2 produces an expected path2', (t) => {
12
12
  const geometry1 = path2.create()
13
13
  const geometry2 = arc({ radius: 1 / 2, segments: 8 })
14
- const geometry3 = arc({ radius: 1.3333333333333333333 / 2, segments: 8 })
14
+ const geometry3 = arc({ radius: 1.3333333333333333 / 2, segments: 8 })
15
15
  const geometry4 = arc({ radius: Math.PI * 1000 / 2, segments: 8 })
16
16
 
17
17
  const results = snap(geometry1, geometry2, geometry3, geometry4)
@@ -55,7 +55,7 @@ test('snap: snap of a path2 produces an expected path2', (t) => {
55
55
  test('snap: snap of a geom2 produces an expected geom2', (t) => {
56
56
  const geometry1 = geom2.create()
57
57
  const geometry2 = rectangle({ size: [1, 1, 1] })
58
- const geometry3 = rectangle({ size: [1.3333333333333333333, 1.3333333333333333333, 1.3333333333333333333] })
58
+ const geometry3 = rectangle({ size: [1.3333333333333333, 1.3333333333333333, 1.3333333333333333] })
59
59
  const geometry4 = rectangle({ size: [Math.PI * 1000, Math.PI * 1000, Math.PI * 1000] })
60
60
 
61
61
  const results = snap(geometry1, geometry2, geometry3, geometry4)
@@ -87,7 +87,7 @@ test('snap: snap of a geom2 produces an expected geom2', (t) => {
87
87
  test('snap: snap of a geom3 produces an expected geom3', (t) => {
88
88
  const geometry1 = geom3.create()
89
89
  const geometry2 = cuboid({ size: [1, 1, 1] })
90
- const geometry3 = cuboid({ size: [1.3333333333333333333, 1.3333333333333333333, 1.3333333333333333333] })
90
+ const geometry3 = cuboid({ size: [1.3333333333333333, 1.3333333333333333, 1.3333333333333333] })
91
91
  const geometry4 = cuboid({ size: [Math.PI * 1000, Math.PI * 1000, Math.PI * 1000] })
92
92
 
93
93
  const results = snap(geometry1, geometry2, geometry3, geometry4)
@@ -7,7 +7,7 @@ type NullableNumber = null | number
7
7
 
8
8
  export interface AlignOptions {
9
9
  modes?: Array<'center' | 'max' | 'min' | 'none'>
10
- relativeTo?: [NullableNumber] | [NullableNumber | NullableNumber] | [NullableNumber | NullableNumber | NullableNumber]
10
+ relativeTo?: [NullableNumber] | [NullableNumber, NullableNumber] | [NullableNumber, NullableNumber, NullableNumber]
11
11
  grouped?: boolean
12
12
  }
13
13
 
@@ -1,6 +1,7 @@
1
1
  const test = require('ava')
2
2
 
3
3
  const { comparePoints } = require('../../../test/helpers')
4
+ const { geom3 } = require('../../geometries')
4
5
  const { measureBoundingBox, measureAggregateBoundingBox } = require('../../measurements')
5
6
  const { cube } = require('../../primitives')
6
7
 
@@ -11,6 +12,7 @@ test('align: single object returns geometry unchanged if all axes are none', (t)
11
12
  const aligned = align({ modes: ['none', 'none', 'none'] }, original)
12
13
  const bounds = measureBoundingBox(aligned)
13
14
  const expectedBounds = [[8, 8, 8], [12, 12, 12]]
15
+ t.notThrows(() => geom3.validate(aligned))
14
16
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
15
17
  })
16
18
 
@@ -19,6 +21,7 @@ test('align: single objects returns geometry aligned, different modes on each ax
19
21
  const aligned = align({ modes: ['center', 'min', 'max'] }, original)
20
22
  const bounds = measureBoundingBox(aligned)
21
23
  const expectedBounds = [[-2, 0, -4], [2, 4, 0]]
24
+ t.notThrows(() => geom3.validate(aligned))
22
25
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
23
26
  })
24
27
 
@@ -27,6 +30,7 @@ test('align: unfilled modes and relativeTo arrays return results with expected v
27
30
  const aligned = align({ modes: ['center'], relativeTo: [0] }, original)
28
31
  const bounds = measureBoundingBox(aligned)
29
32
  const expectedBounds = [[-2, 8, 8], [2, 12, 12]]
33
+ t.notThrows(() => geom3.validate(aligned))
30
34
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
31
35
  })
32
36
 
@@ -38,6 +42,8 @@ test('align: multiple objects grouped returns geometry aligned, different modes
38
42
  const aligned = align({ modes: ['center', 'min', 'max'], relativeTo: [6, -10, 0], grouped: true }, original)
39
43
  const bounds = measureAggregateBoundingBox(aligned)
40
44
  const expectedBounds = [[1.5, -10, -9], [10.5, -1, 0]]
45
+ t.notThrows(() => geom3.validate(aligned[0]))
46
+ t.notThrows(() => geom3.validate(aligned[1]))
41
47
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
42
48
  })
43
49
 
@@ -49,6 +55,8 @@ test('align: multiple objects ungrouped returns geometry aligned, different mode
49
55
  const aligned = align({ modes: ['center', 'min', 'max'], relativeTo: [30, 30, 30] }, original)
50
56
  const bounds = measureAggregateBoundingBox(aligned)
51
57
  const expectedBounds = [[28, 30, 26], [32, 34, 30]]
58
+ t.notThrows(() => geom3.validate(aligned[0]))
59
+ t.notThrows(() => geom3.validate(aligned[1]))
52
60
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
53
61
  })
54
62
 
@@ -60,6 +68,8 @@ test('align: multiple objects grouped, relativeTo is nulls, returns geometry unc
60
68
  const aligned = align({ modes: ['center', 'min', 'max'], relativeTo: [null, null, null], grouped: true }, original)
61
69
  const bounds = measureAggregateBoundingBox(aligned)
62
70
  const expectedBounds = [[3, 3, 3], [12, 12, 12]]
71
+ t.notThrows(() => geom3.validate(aligned[0]))
72
+ t.notThrows(() => geom3.validate(aligned[1]))
63
73
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
64
74
  })
65
75
 
@@ -71,6 +81,8 @@ test('align: multiple objects ungrouped, relativeTo is nulls, returns geometry a
71
81
  const aligned = align({ modes: ['center', 'min', 'max'], relativeTo: [null, null, null], grouped: false }, original)
72
82
  const bounds = measureAggregateBoundingBox(aligned)
73
83
  const expectedBounds = [[5.5, 3, 8], [9.5, 7, 12]]
84
+ t.notThrows(() => geom3.validate(aligned[0]))
85
+ t.notThrows(() => geom3.validate(aligned[1]))
74
86
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected. Result: ' + JSON.stringify(bounds))
75
87
  })
76
88