@jscad/modeling 3.0.3-alpha.0 → 3.0.5-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 (214) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/jscad-modeling.es.js +2 -7
  3. package/dist/jscad-modeling.min.js +2 -7
  4. package/package.json +8 -9
  5. package/rollup.config.js +8 -4
  6. package/src/colors/colorize.js +17 -1
  7. package/src/curves/bezier/arcLengthToT.js +1 -1
  8. package/src/curves/bezier/create.js +1 -1
  9. package/src/curves/bezier/index.js +7 -7
  10. package/src/curves/bezier/length.js +1 -1
  11. package/src/curves/bezier/lengths.js +2 -1
  12. package/src/curves/bezier/tangentAt.js +1 -1
  13. package/src/curves/bezier/valueAt.js +1 -1
  14. package/src/curves/index.js +3 -3
  15. package/src/geometries/geom2/applyTransforms.js +3 -1
  16. package/src/geometries/geom2/clone.js +5 -1
  17. package/src/geometries/geom2/create.js +4 -14
  18. package/src/geometries/geom2/fromPoints.d.ts +4 -0
  19. package/src/geometries/geom2/fromPoints.js +28 -0
  20. package/src/geometries/geom2/fromPoints.test.js +22 -0
  21. package/src/geometries/geom2/fromSides.js +4 -2
  22. package/src/geometries/geom2/index.d.ts +1 -0
  23. package/src/geometries/geom2/index.js +22 -5
  24. package/src/geometries/geom2/isA.js +5 -1
  25. package/src/geometries/geom2/reverse.js +4 -2
  26. package/src/geometries/geom2/toOutlines.js +2 -1
  27. package/src/geometries/geom2/toPoints.js +5 -2
  28. package/src/geometries/geom2/toSides.js +4 -3
  29. package/src/geometries/geom2/toString.js +3 -2
  30. package/src/geometries/geom2/transform.js +4 -2
  31. package/src/geometries/geom2/validate.js +6 -2
  32. package/src/geometries/geom3/clone.js +5 -1
  33. package/src/geometries/geom3/create.js +5 -19
  34. package/src/geometries/geom3/fromVertices.js +13 -1
  35. package/src/geometries/geom3/fromVerticesConvex.js +1 -1
  36. package/src/geometries/geom3/index.d.ts +1 -0
  37. package/src/geometries/geom3/index.js +26 -4
  38. package/src/geometries/geom3/invert.js +5 -1
  39. package/src/geometries/geom3/isA.js +5 -1
  40. package/src/geometries/geom3/isConvex.d.ts +3 -0
  41. package/src/geometries/geom3/isConvex.js +65 -0
  42. package/src/geometries/geom3/isConvex.test.js +44 -0
  43. package/src/geometries/geom3/toPolygons.js +4 -2
  44. package/src/geometries/geom3/toString.js +3 -2
  45. package/src/geometries/geom3/toVertices.js +8 -4
  46. package/src/geometries/geom3/transform.js +5 -2
  47. package/src/geometries/geom3/validate.js +6 -2
  48. package/src/geometries/index.js +9 -7
  49. package/src/geometries/path2/appendArc.js +7 -5
  50. package/src/geometries/path2/appendArc.test.js +11 -15
  51. package/src/geometries/path2/appendBezier.js +6 -4
  52. package/src/geometries/path2/appendPoints.js +4 -2
  53. package/src/geometries/path2/applyTransforms.js +3 -0
  54. package/src/geometries/path2/clone.js +5 -1
  55. package/src/geometries/path2/close.js +5 -1
  56. package/src/geometries/path2/concat.js +3 -2
  57. package/src/geometries/path2/create.js +4 -15
  58. package/src/geometries/path2/equals.js +12 -7
  59. package/src/geometries/path2/fromPoints.js +5 -3
  60. package/src/geometries/path2/index.js +21 -4
  61. package/src/geometries/path2/isA.js +5 -1
  62. package/src/geometries/path2/reverse.js +4 -2
  63. package/src/geometries/path2/toPoints.js +5 -3
  64. package/src/geometries/path2/toString.js +3 -2
  65. package/src/geometries/path2/transform.js +4 -2
  66. package/src/geometries/path2/validate.js +5 -1
  67. package/src/geometries/path3/applyTransforms.js +1 -1
  68. package/src/geometries/path3/clone.d.ts +3 -0
  69. package/src/geometries/path3/clone.js +11 -0
  70. package/src/geometries/path3/close.js +4 -2
  71. package/src/geometries/path3/concat.js +2 -3
  72. package/src/geometries/path3/create.js +4 -20
  73. package/src/geometries/path3/equals.js +4 -2
  74. package/src/geometries/path3/fromVertices.js +2 -3
  75. package/src/geometries/path3/index.d.ts +1 -0
  76. package/src/geometries/path3/index.js +18 -1
  77. package/src/geometries/path3/isA.js +4 -2
  78. package/src/geometries/path3/reverse.js +2 -3
  79. package/src/geometries/path3/toString.js +2 -3
  80. package/src/geometries/path3/toVertices.js +2 -3
  81. package/src/geometries/path3/transform.js +2 -3
  82. package/src/geometries/path3/validate.js +6 -3
  83. package/src/geometries/poly2/arePointsInside.js +4 -1
  84. package/src/geometries/poly2/clone.js +4 -1
  85. package/src/geometries/poly2/create.js +2 -9
  86. package/src/geometries/poly2/index.js +16 -4
  87. package/src/geometries/poly2/isA.js +5 -1
  88. package/src/geometries/poly2/isConvex.js +5 -1
  89. package/src/geometries/poly2/isSimple.js +5 -1
  90. package/src/geometries/poly2/measureArea.js +4 -1
  91. package/src/geometries/poly2/measureBoundingBox.js +6 -1
  92. package/src/geometries/poly2/reverse.js +4 -1
  93. package/src/geometries/poly2/toPoints.js +6 -1
  94. package/src/geometries/poly2/toString.js +5 -1
  95. package/src/geometries/poly2/transform.js +5 -1
  96. package/src/geometries/poly2/type.d.ts +1 -5
  97. package/src/geometries/poly2/validate.js +6 -2
  98. package/src/geometries/poly3/clone.js +4 -1
  99. package/src/geometries/poly3/create.js +3 -11
  100. package/src/geometries/poly3/fromVerticesAndPlane.js +3 -1
  101. package/src/geometries/poly3/index.js +19 -4
  102. package/src/geometries/poly3/invert.js +4 -1
  103. package/src/geometries/poly3/isA.js +5 -1
  104. package/src/geometries/poly3/isConvex.js +5 -1
  105. package/src/geometries/poly3/measureArea.js +5 -1
  106. package/src/geometries/poly3/measureBoundingBox.js +4 -1
  107. package/src/geometries/poly3/measureBoundingSphere.js +4 -3
  108. package/src/geometries/poly3/measureSignedVolume.js +6 -1
  109. package/src/geometries/poly3/plane.js +6 -0
  110. package/src/geometries/poly3/toString.js +5 -1
  111. package/src/geometries/poly3/toVertices.js +6 -1
  112. package/src/geometries/poly3/transform.js +5 -1
  113. package/src/geometries/poly3/validate.js +6 -2
  114. package/src/geometries/slice/calculatePlane.js +3 -3
  115. package/src/geometries/slice/clone.js +4 -1
  116. package/src/geometries/slice/create.js +5 -10
  117. package/src/geometries/slice/equals.js +5 -1
  118. package/src/geometries/slice/fromOutlines.d.ts +5 -0
  119. package/src/geometries/slice/fromOutlines.js +16 -0
  120. package/src/geometries/slice/fromOutlines.test.js +17 -0
  121. package/src/geometries/slice/fromVertices.js +3 -3
  122. package/src/geometries/slice/index.d.ts +1 -1
  123. package/src/geometries/slice/index.js +20 -5
  124. package/src/geometries/slice/isA.js +5 -1
  125. package/src/geometries/slice/reverse.js +5 -2
  126. package/src/geometries/slice/toEdges.js +5 -3
  127. package/src/geometries/slice/toPolygons.js +5 -1
  128. package/src/geometries/slice/toString.js +5 -1
  129. package/src/geometries/slice/toVertices.js +5 -3
  130. package/src/geometries/slice/transform.js +4 -3
  131. package/src/geometries/slice/validate.js +3 -2
  132. package/src/index.d.ts +1 -0
  133. package/src/index.js +4 -0
  134. package/src/maths/constants.js +11 -7
  135. package/src/maths/index.js +2 -1
  136. package/src/maths/mat4/isOnlyTransformScale.js +1 -1
  137. package/src/maths/plane/fromNormalAndPoint.js +4 -6
  138. package/src/maths/plane/fromPoints.js +8 -7
  139. package/src/maths/plane/fromPointsRandom.js +13 -13
  140. package/src/measurements/measureAggregateEpsilon.js +3 -1
  141. package/src/measurements/measureAggregateEpsilon.test.js +1 -1
  142. package/src/measurements/measureArea.js +6 -4
  143. package/src/measurements/measureArea.test.js +4 -1
  144. package/src/measurements/measureBoundingBox.js +16 -2
  145. package/src/measurements/measureBoundingBox.test.js +4 -1
  146. package/src/measurements/measureBoundingSphere.js +38 -29
  147. package/src/measurements/measureBoundingSphere.test.js +4 -1
  148. package/src/measurements/measureCenterOfMass.js +3 -2
  149. package/src/measurements/measureEpsilon.js +4 -2
  150. package/src/operations/booleans/index.js +2 -0
  151. package/src/operations/booleans/intersect.js +0 -1
  152. package/src/operations/booleans/scission.js +0 -1
  153. package/src/operations/booleans/trees/splitLineSegmentByPlane.js +1 -4
  154. package/src/operations/booleans/trees/splitPolygonByPlane.d.ts +1 -3
  155. package/src/operations/booleans/trees/splitPolygonByPlane.test.js +138 -0
  156. package/src/operations/booleans/union.js +1 -1
  157. package/src/operations/booleans/unionGeom3.test.js +35 -0
  158. package/src/operations/extrusions/extrudeFromSlices.js +16 -6
  159. package/src/operations/extrusions/extrudeFromSlices.test.js +1 -1
  160. package/src/operations/extrusions/extrudeHelical.js +2 -1
  161. package/src/operations/extrusions/extrudeLinear.js +1 -1
  162. package/src/operations/extrusions/extrudeLinearGeom2.js +2 -1
  163. package/src/operations/extrusions/extrudeRotate.js +3 -2
  164. package/src/operations/extrusions/extrudeRotate.test.js +34 -0
  165. package/src/operations/extrusions/extrudeWalls.test.js +60 -0
  166. package/src/operations/hulls/hull.js +3 -2
  167. package/src/operations/hulls/toUniquePoints.js +3 -0
  168. package/src/operations/minkowski/index.d.ts +1 -0
  169. package/src/operations/minkowski/index.js +15 -0
  170. package/src/operations/minkowski/minkowskiSum.d.ts +4 -0
  171. package/src/operations/minkowski/minkowskiSum.js +223 -0
  172. package/src/operations/minkowski/minkowskiSum.test.js +199 -0
  173. package/src/operations/modifiers/generalize.js +9 -2
  174. package/src/operations/modifiers/reTesselateCoplanarPolygons.js +10 -3
  175. package/src/operations/modifiers/reTesselateCoplanarPolygons.test.js +36 -1
  176. package/src/operations/modifiers/retessellate.js +4 -2
  177. package/src/operations/modifiers/snap.js +22 -3
  178. package/src/operations/modifiers/snap.test.js +24 -15
  179. package/src/operations/offsets/offsetGeom3.test.js +5 -7
  180. package/src/operations/transforms/align.js +2 -1
  181. package/src/operations/transforms/align.test.js +1 -1
  182. package/src/operations/transforms/mirror.js +6 -2
  183. package/src/operations/transforms/rotate.js +6 -2
  184. package/src/operations/transforms/scale.js +6 -2
  185. package/src/operations/transforms/transform.js +6 -2
  186. package/src/operations/transforms/transform.test.js +16 -5
  187. package/src/operations/transforms/translate.js +6 -2
  188. package/src/primitives/arc.js +13 -12
  189. package/src/primitives/arc.test.js +104 -113
  190. package/src/primitives/circle.js +10 -9
  191. package/src/primitives/cube.js +5 -6
  192. package/src/primitives/cuboid.js +6 -6
  193. package/src/primitives/cylinder.js +8 -8
  194. package/src/primitives/cylinderElliptic.js +11 -11
  195. package/src/primitives/ellipse.js +10 -9
  196. package/src/primitives/ellipsoid.js +8 -8
  197. package/src/primitives/geodesicSphere.js +6 -6
  198. package/src/primitives/line.js +2 -0
  199. package/src/primitives/polygon.js +6 -7
  200. package/src/primitives/polyhedron.js +7 -8
  201. package/src/primitives/rectangle.js +6 -6
  202. package/src/primitives/roundedCuboid.js +8 -8
  203. package/src/primitives/roundedCylinder.js +9 -9
  204. package/src/primitives/roundedRectangle.js +8 -8
  205. package/src/primitives/sphere.js +7 -8
  206. package/src/primitives/square.js +6 -6
  207. package/src/primitives/star.js +10 -10
  208. package/src/primitives/torus.js +11 -11
  209. package/src/primitives/triangle.js +7 -6
  210. package/src/utils/areAllShapesTheSameType.js +4 -0
  211. package/src/utils/flatten.js +1 -1
  212. package/src/utils/flatten.test.js +94 -0
  213. package/src/geometries/slice/fromGeom2.d.ts +0 -5
  214. package/src/geometries/slice/fromGeom2.js +0 -17
@@ -8,6 +8,7 @@ import { isGT, isGTE, isNumberArray } from './commonChecks.js'
8
8
 
9
9
  /**
10
10
  * Construct an arc in two dimensional space where all points are at the same distance from the center.
11
+ *
11
12
  * @param {object} [options] - options for construction
12
13
  * @param {Array} [options.center=[0,0]] - center of arc
13
14
  * @param {number} [options.radius=1] - radius of arc
@@ -17,19 +18,19 @@ import { isGT, isGTE, isNumberArray } from './commonChecks.js'
17
18
  * @param {boolean} [options.makeTangent=false] - adds line segments at both ends of the arc to ensure that the gradients at the edges are tangent
18
19
  * @returns {Path2} new 2D path
19
20
  * @alias module:modeling/primitives.arc
21
+ *
20
22
  * @example
21
23
  * let myshape = arc({ center: [-1, -1], radius: 2, endAngle: (TAU / 4)})
22
24
  */
23
- export const arc = (options) => {
24
- const defaults = {
25
- center: [0, 0],
26
- radius: 1,
27
- startAngle: 0,
28
- endAngle: TAU,
29
- makeTangent: false,
30
- segments: 32
31
- }
32
- let { center, radius, startAngle, endAngle, makeTangent, segments } = Object.assign({}, defaults, options)
25
+ export const arc = (options = {}) => {
26
+ let {
27
+ center = [0, 0],
28
+ radius = 1,
29
+ startAngle = 0,
30
+ endAngle = TAU,
31
+ makeTangent = false,
32
+ segments = 32
33
+ } = options
33
34
 
34
35
  if (!isNumberArray(center, 2)) throw new Error('center must be an array of X and Y values')
35
36
  if (!isGT(radius, 0)) throw new Error('radius must be greater than zero')
@@ -60,8 +61,8 @@ export const arc = (options) => {
60
61
  vec2.add(point, point, centerV)
61
62
  pointArray.push(point)
62
63
  } else {
63
- // note: add one additional step to achieve full rotation
64
- const numSteps = Math.max(1, Math.floor(segments * (rotation / TAU))) + 1
64
+ const numSteps = Math.floor(segments * (Math.abs(rotation) / TAU))
65
+
65
66
  let edgeStepSize = numSteps * 0.5 / rotation // step size for half a degree
66
67
  if (edgeStepSize > 0.25) edgeStepSize = 0.25
67
68
 
@@ -13,205 +13,196 @@ test('arc (defaults)', (t) => {
13
13
  const obs = path2.toPoints(geometry)
14
14
 
15
15
  t.notThrows(() => path2.validate(geometry))
16
- t.is(obs.length, 33)
16
+ t.is(obs.length, 32)
17
17
  })
18
18
 
19
19
  test('arc (options)', (t) => {
20
20
  // test center
21
21
  let exp = [
22
22
  [3, 2],
23
- [2.9324722294043557, 2.361241666187153],
24
- [2.739008917220659, 2.6736956436465573],
25
- [2.4457383557765384, 2.8951632913550625],
26
- [2.092268359463302, 2.9957341762950342],
27
- [1.7263370099279172, 2.961825643172819],
28
- [1.3973653636207437, 2.7980172272802397],
29
- [1.1497828642703858, 2.526432162877356],
30
- [1.017026900316098, 2.1837495178165702],
31
- [1.017026900316098, 1.8162504821834298],
32
- [1.149782864270386, 1.4735678371226442],
33
- [1.3973653636207435, 1.2019827727197605],
34
- [1.726337009927917, 1.0381743568271808],
35
- [2.0922683594633016, 1.0042658237049653],
36
- [2.4457383557765384, 1.1048367086449378],
37
- [2.739008917220659, 1.326304356353443],
38
- [2.9324722294043557, 1.6387583338128469]
23
+ [2.923879532511287, 2.3826834323650896],
24
+ [2.7071067811865475, 2.7071067811865475],
25
+ [2.3826834323650896, 2.923879532511287],
26
+ [2, 3],
27
+ [1.6173165676349104, 2.923879532511287],
28
+ [1.2928932188134525, 2.7071067811865475],
29
+ [1.0761204674887133, 2.38268343236509],
30
+ [1, 2],
31
+ [1.076120467488713, 1.6173165676349104],
32
+ [1.2928932188134523, 1.2928932188134525],
33
+ [1.6173165676349097, 1.0761204674887135],
34
+ [2, 1],
35
+ [2.38268343236509, 1.0761204674887135],
36
+ [2.7071067811865475, 1.2928932188134523],
37
+ [2.9238795325112865, 1.6173165676349095]
39
38
  ]
40
39
  let geometry = arc({ center: [2, 2], segments: 16 })
41
40
  let obs = path2.toPoints(geometry)
42
41
 
43
42
  t.notThrows(() => path2.validate(geometry))
44
- t.is(obs.length, 17)
43
+ t.is(obs.length, 16)
45
44
  t.true(comparePoints(obs, exp))
46
45
 
47
46
  // test radius
48
47
  exp = [
49
48
  [2, 0],
50
- [1.8649444588087116, 0.7224833323743058],
51
- [1.4780178344413182, 1.3473912872931144],
52
- [0.8914767115530766, 1.7903265827101247],
53
- [0.18453671892660403, 1.991468352590069],
54
- [-0.5473259801441658, 1.923651286345638],
55
- [-1.2052692727585126, 1.5960344545604792],
56
- [-1.7004342714592284, 1.0528643257547114],
57
- [-1.9659461993678036, 0.36749903563314074],
58
- [-1.9659461993678036, -0.36749903563314024],
59
- [-1.7004342714592282, -1.0528643257547117],
60
- [-1.205269272758513, -1.596034454560479],
61
- [-0.5473259801441662, -1.923651286345638],
62
- [0.1845367189266031, -1.9914683525900692],
63
- [0.8914767115530771, -1.7903265827101245],
64
- [1.4780178344413184, -1.3473912872931142],
65
- [1.8649444588087116, -0.7224833323743061]
49
+ [1.8477590650225735, 0.7653668647301796],
50
+ [1.4142135623730951, 1.414213562373095],
51
+ [0.7653668647301797, 1.8477590650225735],
52
+ [0, 2],
53
+ [-0.7653668647301795, 1.8477590650225735],
54
+ [-1.414213562373095, 1.4142135623730951],
55
+ [-1.8477590650225735, 0.7653668647301798],
56
+ [-2, 0],
57
+ [-1.8477590650225737, -0.7653668647301793],
58
+ [-1.4142135623730954, -1.414213562373095],
59
+ [-0.7653668647301807, -1.847759065022573],
60
+ [0, -2],
61
+ [0.76536686473018, -1.8477590650225733],
62
+ [1.4142135623730947, -1.4142135623730954],
63
+ [1.847759065022573, -0.7653668647301808]
66
64
  ]
67
65
  geometry = arc({ radius: 2, segments: 16 })
68
66
  obs = path2.toPoints(geometry)
69
67
 
70
68
  t.notThrows(() => path2.validate(geometry))
71
- t.is(obs.length, 17)
69
+ t.is(obs.length, 16)
72
70
  t.true(comparePoints(obs, exp))
73
71
 
74
72
  // test startAngle
75
73
  exp = [
76
- [6.123233995736766e-17, 1],
77
- [-0.3546048870425357, 0.9350162426854148],
78
- [-0.6631226582407953, 0.748510748171101],
79
- [-0.8854560256532098, 0.4647231720437687],
80
- [-0.992708874098054, 0.12053668025532308],
81
- [-0.970941817426052, -0.23931566428755788],
82
- [-0.8229838658936566, -0.5680647467311556],
83
- [-0.5680647467311559, -0.8229838658936564],
84
- [-0.23931566428755774, -0.970941817426052],
85
- [0.1205366802553232, -0.992708874098054],
86
- [0.4647231720437688, -0.8854560256532098],
87
- [0.7485107481711007, -0.6631226582407955],
88
- [0.9350162426854147, -0.35460488704253595],
89
- [1, -2.4492935982947064e-16]
74
+ [0, 1],
75
+ [-0.3826834323650897, 0.9238795325112867],
76
+ [-0.7071067811865475, 0.7071067811865476],
77
+ [-0.9238795325112867, 0.3826834323650899],
78
+ [-1, 0],
79
+ [-0.9238795325112868, -0.38268343236508967],
80
+ [-0.7071067811865477, -0.7071067811865475],
81
+ [-0.38268343236509034, -0.9238795325112865],
82
+ [0, -1],
83
+ [0.38268343236509, -0.9238795325112866],
84
+ [0.7071067811865474, -0.7071067811865477],
85
+ [0.9238795325112865, -0.3826834323650904],
86
+ [1, 0]
90
87
  ]
91
88
  geometry = arc({ startAngle: TAU / 4, segments: 16 })
92
89
  obs = path2.toPoints(geometry)
93
90
 
94
91
  t.notThrows(() => path2.validate(geometry))
95
- t.is(obs.length, 14)
92
+ t.is(obs.length, 13)
96
93
  t.true(comparePoints(obs, exp))
97
94
 
98
95
  // test endAngle
99
96
  exp = [
100
97
  [1, 0],
101
- [0.9510565162951535, 0.3090169943749474],
102
- [0.8090169943749475, 0.5877852522924731],
103
- [0.5877852522924731, 0.8090169943749475],
104
- [0.30901699437494745, 0.9510565162951535],
105
- [6.123233995736766e-17, 1]
98
+ [0.9238795325112867, 0.3826834323650898],
99
+ [0.7071067811865476, 0.7071067811865475],
100
+ [0.38268343236508984, 0.9238795325112867],
101
+ [0, 1]
106
102
  ]
107
103
  geometry = arc({ endAngle: TAU / 4, segments: 16 })
108
104
  obs = path2.toPoints(geometry)
109
105
 
110
106
  t.notThrows(() => path2.validate(geometry))
111
- t.is(obs.length, 6)
107
+ t.is(obs.length, 5)
112
108
  t.true(comparePoints(obs, exp))
113
109
 
114
110
  // test makeTangent
115
111
  exp = [
116
112
  [1, 0],
117
- [0.9957341762950345, 0.09226835946330199],
118
- [0.8999557329057603, 0.43598128263728936],
119
- [0.6896020498551045, 0.7241885202318785],
120
- [0.391453692861967, 0.9201978082699006],
121
- [0.04346855052920052, 0.9990547958520045],
122
- [-0.31005066355011174, 0.9507200355689026],
123
- [-0.6240966815770753, 0.781347126470996],
124
- [-0.858687650595474, 0.5124992865505523],
125
- [-0.9839573055048071, 0.1784040945262181],
126
- [-0.9839573055048071, -0.1784040945262183],
127
- [-0.8586876505954741, -0.5124992865505521],
128
- [-0.6240966815770755, -0.7813471264709959],
129
- [-0.3100506635501122, -0.9507200355689025],
130
- [0.04346855052920005, -0.9990547958520045],
131
- [0.39145369286196696, -0.9201978082699006],
132
- [0.6896020498551043, -0.7241885202318787],
133
- [0.8999557329057604, -0.435981282637289],
134
- [0.9957341762950345, -0.09226835946330197]
113
+ [0.9951847266721969, 0.0980171403295606],
114
+ [0.8876396204028539, 0.46053871095824],
115
+ [0.6531728429537769, 0.7572088465064846],
116
+ [0.325310292162263, 0.9456073253805213],
117
+ [-0.04906767432741801, 0.9987954562051724],
118
+ [-0.416429560097637, 0.9091679830905225],
119
+ [-0.7242470829514668, 0.689540544737067],
120
+ [-0.9285060804732155, 0.3713171939518377],
121
+ [-1, 0],
122
+ [-0.9285060804732156, -0.37131719395183743],
123
+ [-0.724247082951467, -0.6895405447370668],
124
+ [-0.4164295600976372, -0.9091679830905224],
125
+ [-0.04906767432741803, -0.9987954562051724],
126
+ [0.3253102921622629, -0.9456073253805213],
127
+ [0.6531728429537768, -0.7572088465064846],
128
+ [0.8876396204028539, -0.46053871095823995],
129
+ [0.9951847266721969, -0.0980171403295605]
135
130
  ]
136
131
  geometry = arc({ makeTangent: true, segments: 16 })
137
132
  obs = path2.toPoints(geometry)
138
133
 
139
134
  t.notThrows(() => path2.validate(geometry))
140
- t.is(obs.length, 19)
135
+ t.is(obs.length, 18)
141
136
  t.true(comparePoints(obs, exp))
142
137
 
143
138
  // test segments
144
139
  exp = [
145
140
  [1, 0],
146
- [0.766044443118978, 0.6427876096865393],
147
- [0.17364817766693041, 0.984807753012208],
148
- [-0.4999999999999998, 0.8660254037844387],
149
- [-0.9396926207859083, 0.3420201433256689],
150
- [-0.9396926207859084, -0.34202014332566866],
151
- [-0.5000000000000004, -0.8660254037844385],
152
- [0.17364817766692997, -0.9848077530122081],
153
- [0.7660444431189778, -0.6427876096865396]
141
+ [0.7071067811865476, 0.7071067811865475],
142
+ [0, 1],
143
+ [-0.7071067811865475, 0.7071067811865476],
144
+ [-1, 0],
145
+ [-0.7071067811865477, -0.7071067811865475],
146
+ [0, -1],
147
+ [0.7071067811865474, -0.7071067811865477]
154
148
  ]
155
149
  geometry = arc({ segments: 8 })
156
150
  obs = path2.toPoints(geometry)
157
151
 
158
152
  t.notThrows(() => path2.validate(geometry))
159
- t.is(obs.length, 9)
153
+ t.is(obs.length, 8)
160
154
  t.true(comparePoints(obs, exp))
161
155
  })
162
156
 
163
157
  test('arc (rotations)', (t) => {
164
158
  let exp = [
165
- [6.123233995736766e-17, 1],
166
- [-0.30901699437494734, 0.9510565162951536],
167
- [-0.587785252292473, 0.8090169943749475],
168
- [-0.8090169943749473, 0.5877852522924732],
169
- [-0.9510565162951535, 0.3090169943749475],
170
- [-1, 1.2246467991473532e-16]
159
+ [0, 1],
160
+ [-0.3826834323650897, 0.9238795325112867],
161
+ [-0.7071067811865475, 0.7071067811865476],
162
+ [-0.9238795325112867, 0.3826834323650899],
163
+ [-1, 0]
171
164
  ]
172
165
  let geometry = arc({ startAngle: TAU / 4, endAngle: TAU / 2, segments: 16 })
173
166
  let obs = path2.toPoints(geometry)
174
167
 
175
168
  t.notThrows(() => path2.validate(geometry))
176
- t.is(obs.length, 6)
169
+ t.is(obs.length, 5)
177
170
  t.true(comparePoints(obs, exp))
178
171
 
179
172
  exp = [
180
- [-1, 1.2246467991473532e-16],
181
- [-0.9396926207859084, -0.34202014332566866],
182
- [-0.7660444431189781, -0.6427876096865393],
183
- [-0.5000000000000004, -0.8660254037844385],
184
- [-0.17364817766693033, -0.984807753012208],
185
- [0.17364817766692997, -0.9848077530122081],
186
- [0.49999999999999933, -0.866025403784439],
187
- [0.7660444431189778, -0.6427876096865396],
188
- [0.9396926207859084, -0.3420201433256686],
189
- [1, -2.4492935982947064e-16]
173
+ [-1, 0],
174
+ [-0.9238795325112868, -0.38268343236508967],
175
+ [-0.7071067811865477, -0.7071067811865475],
176
+ [-0.38268343236509034, -0.9238795325112865],
177
+ [0, -1],
178
+ [0.38268343236509, -0.9238795325112866],
179
+ [0.7071067811865474, -0.7071067811865477],
180
+ [0.9238795325112865, -0.3826834323650904],
181
+ [1, 0]
190
182
  ]
191
183
  geometry = arc({ startAngle: TAU / 2, endAngle: TAU, segments: 16 })
192
184
  obs = path2.toPoints(geometry)
193
185
 
194
186
  t.notThrows(() => path2.validate(geometry))
195
- t.is(obs.length, 10)
187
+ t.is(obs.length, 9)
196
188
  t.true(comparePoints(obs, exp))
197
189
 
198
190
  exp = [
199
- [-1.8369701987210297e-16, -1],
200
- [0.34202014332566816, -0.9396926207859085],
201
- [0.6427876096865393, -0.7660444431189781],
202
- [0.8660254037844384, -0.5000000000000004],
203
- [0.984807753012208, -0.1736481776669304],
204
- [0.9848077530122081, 0.17364817766692991],
205
- [0.866025403784439, 0.4999999999999993],
206
- [0.6427876096865396, 0.7660444431189778],
207
- [0.34202014332566866, 0.9396926207859084],
208
- [3.061616997868383e-16, 1]
191
+ [0, -1],
192
+ [0.38268343236509, -0.9238795325112866],
193
+ [0.7071067811865474, -0.7071067811865477],
194
+ [0.9238795325112865, -0.3826834323650904],
195
+ [1, 0],
196
+ [0.9238795325112867, 0.38268343236508995],
197
+ [0.7071067811865477, 0.7071067811865474],
198
+ [0.38268343236509045, 0.9238795325112865],
199
+ [0, 1]
209
200
  ]
210
201
  geometry = arc({ startAngle: TAU * 0.75, endAngle: TAU / 4, segments: 16 })
211
202
  obs = path2.toPoints(geometry)
212
203
 
213
204
  t.notThrows(() => path2.validate(geometry))
214
- t.is(obs.length, 10)
205
+ t.is(obs.length, 9)
215
206
  t.true(comparePoints(obs, exp))
216
207
 
217
208
  exp = [[-1.8369701987210297e-16, -1]]
@@ -6,6 +6,7 @@ import { isGTE } from './commonChecks.js'
6
6
 
7
7
  /**
8
8
  * Construct a circle in two dimensional space where all points are at the same distance from the center.
9
+ *
9
10
  * @see [ellipse]{@link module:modeling/primitives.ellipse} for more options
10
11
  * @param {object} [options] - options for construction
11
12
  * @param {Array} [options.center=[0,0]] - center of circle
@@ -15,18 +16,18 @@ import { isGTE } from './commonChecks.js'
15
16
  * @param {number} [options.segments=32] - number of segments to create per full rotation
16
17
  * @returns {Geom2} new 2D geometry
17
18
  * @alias module:modeling/primitives.circle
19
+ *
18
20
  * @example
19
21
  * let myshape = circle({radius: 10})
20
22
  */
21
- export const circle = (options) => {
22
- const defaults = {
23
- center: [0, 0],
24
- radius: 1,
25
- startAngle: 0,
26
- endAngle: TAU,
27
- segments: 32
28
- }
29
- let { center, radius, startAngle, endAngle, segments } = Object.assign({}, defaults, options)
23
+ export const circle = (options = {}) => {
24
+ let {
25
+ center = [0, 0],
26
+ radius = 1,
27
+ startAngle = 0,
28
+ endAngle = TAU,
29
+ segments = 32
30
+ } = options
30
31
 
31
32
  if (!isGTE(radius, 0)) throw new Error('radius must be positive')
32
33
 
@@ -12,12 +12,11 @@ import { isGTE } from './commonChecks.js'
12
12
  * @example
13
13
  * let myshape = cube({size: 10})
14
14
  */
15
- export const cube = (options) => {
16
- const defaults = {
17
- center: [0, 0, 0],
18
- size: 2
19
- }
20
- let { center, size } = Object.assign({}, defaults, options)
15
+ export const cube = (options = {}) => {
16
+ let {
17
+ center = [0, 0, 0],
18
+ size = 2
19
+ } = options
21
20
 
22
21
  if (!isGTE(size, 0)) throw new Error('size must be positive')
23
22
 
@@ -5,6 +5,7 @@ import { isNumberArray } from './commonChecks.js'
5
5
 
6
6
  /**
7
7
  * Construct an axis-aligned solid cuboid in three dimensional space.
8
+ *
8
9
  * @param {object} [options] - options for construction
9
10
  * @param {Array} [options.center=[0,0,0]] - center of cuboid
10
11
  * @param {Array} [options.size=[2,2,2]] - dimensions of cuboid; width, depth, height
@@ -14,12 +15,11 @@ import { isNumberArray } from './commonChecks.js'
14
15
  * @example
15
16
  * let myshape = cuboid({size: [5, 10, 5]})
16
17
  */
17
- export const cuboid = (options) => {
18
- const defaults = {
19
- center: [0, 0, 0],
20
- size: [2, 2, 2]
21
- }
22
- const { center, size } = Object.assign({}, defaults, options)
18
+ export const cuboid = (options = {}) => {
19
+ const {
20
+ center = [0, 0, 0],
21
+ size = [2, 2, 2]
22
+ } = options
23
23
 
24
24
  if (!isNumberArray(center, 3)) throw new Error('center must be an array of X, Y and Z values')
25
25
  if (!isNumberArray(size, 3)) throw new Error('size must be an array of width, depth and height values')
@@ -4,6 +4,7 @@ import * as geom3 from '../geometries/geom3/index.js'
4
4
 
5
5
  /**
6
6
  * Construct a Z axis-aligned cylinder in three dimensional space.
7
+ *
7
8
  * @see [cylinderElliptic]{@link module:modeling/primitives.cylinderElliptic} for more options
8
9
  * @param {object} [options] - options for construction
9
10
  * @param {Array} [options.center=[0,0,0]] - center of cylinder
@@ -16,14 +17,13 @@ import * as geom3 from '../geometries/geom3/index.js'
16
17
  * @example
17
18
  * let myshape = cylinder({height: 2, radius: 10})
18
19
  */
19
- export const cylinder = (options) => {
20
- const defaults = {
21
- center: [0, 0, 0],
22
- height: 2,
23
- radius: 1,
24
- segments: 32
25
- }
26
- const { center, height, radius, segments } = Object.assign({}, defaults, options)
20
+ export const cylinder = (options = {}) => {
21
+ const {
22
+ center = [0, 0, 0],
23
+ height = 2,
24
+ radius = 1,
25
+ segments = 32
26
+ } = options
27
27
 
28
28
  if (!isGTE(radius, 0)) throw new Error('radius must be positive')
29
29
 
@@ -11,6 +11,7 @@ import { isGT, isGTE, isNumberArray } from './commonChecks.js'
11
11
 
12
12
  /**
13
13
  * Construct a Z axis-aligned elliptic cylinder in three dimensional space.
14
+ *
14
15
  * @param {object} [options] - options for construction
15
16
  * @param {Array} [options.center=[0,0,0]] - center of cylinder
16
17
  * @param {number} [options.height=2] - height of cylinder
@@ -25,17 +26,16 @@ import { isGT, isGTE, isNumberArray } from './commonChecks.js'
25
26
  * @example
26
27
  * let myshape = cylinderElliptic({height: 2, startRadius: [10,5], endRadius: [8,3]})
27
28
  */
28
- export const cylinderElliptic = (options) => {
29
- const defaults = {
30
- center: [0, 0, 0],
31
- height: 2,
32
- startRadius: [1, 1],
33
- startAngle: 0,
34
- endRadius: [1, 1],
35
- endAngle: TAU,
36
- segments: 32
37
- }
38
- let { center, height, startRadius, startAngle, endRadius, endAngle, segments } = Object.assign({}, defaults, options)
29
+ export const cylinderElliptic = (options = {}) => {
30
+ let {
31
+ center = [0, 0, 0],
32
+ height = 2,
33
+ startRadius = [1, 1],
34
+ startAngle = 0,
35
+ endRadius = [1, 1],
36
+ endAngle = TAU,
37
+ segments = 32
38
+ } = options
39
39
 
40
40
  if (!isNumberArray(center, 3)) throw new Error('center must be an array of X, Y and Z values')
41
41
  if (!isGT(height, 0)) throw new Error('height must be greater then zero')
@@ -10,6 +10,7 @@ import { isGTE, isNumberArray } from './commonChecks.js'
10
10
 
11
11
  /**
12
12
  * Construct an axis-aligned ellipse in two dimensional space.
13
+ *
13
14
  * @see https://en.wikipedia.org/wiki/Ellipse
14
15
  * @param {object} [options] - options for construction
15
16
  * @param {Array} [options.center=[0,0]] - center of ellipse
@@ -19,18 +20,18 @@ import { isGTE, isNumberArray } from './commonChecks.js'
19
20
  * @param {number} [options.segments=32] - number of segments to create per full rotation
20
21
  * @returns {Geom2} new 2D geometry
21
22
  * @alias module:modeling/primitives.ellipse
23
+ *
22
24
  * @example
23
25
  * let myshape = ellipse({radius: [5,10]})
24
26
  */
25
- export const ellipse = (options) => {
26
- const defaults = {
27
- center: [0, 0],
28
- radius: [1, 1],
29
- startAngle: 0,
30
- endAngle: TAU,
31
- segments: 32
32
- }
33
- let { center, radius, startAngle, endAngle, segments } = Object.assign({}, defaults, options)
27
+ export const ellipse = (options = {}) => {
28
+ let {
29
+ center = [0, 0],
30
+ radius = [1, 1],
31
+ startAngle = 0,
32
+ endAngle = TAU,
33
+ segments = 32
34
+ } = options
34
35
 
35
36
  if (!isNumberArray(center, 2)) throw new Error('center must be an array of X and Y values')
36
37
  if (!isNumberArray(radius, 2)) throw new Error('radius must be an array of X and Y values')
@@ -9,6 +9,7 @@ import { isGTE, isNumberArray } from './commonChecks.js'
9
9
 
10
10
  /**
11
11
  * Construct an axis-aligned ellipsoid in three dimensional space.
12
+ *
12
13
  * @param {object} [options] - options for construction
13
14
  * @param {Array} [options.center=[0,0,0]] - center of ellipsoid
14
15
  * @param {Array} [options.radius=[1,1,1]] - radius of ellipsoid, along X, Y and Z
@@ -20,14 +21,13 @@ import { isGTE, isNumberArray } from './commonChecks.js'
20
21
  * @example
21
22
  * let myshape = ellipsoid({radius: [5, 10, 20]})
22
23
  */
23
- export const ellipsoid = (options) => {
24
- const defaults = {
25
- center: [0, 0, 0],
26
- radius: [1, 1, 1],
27
- segments: 32,
28
- axes: [[1, 0, 0], [0, -1, 0], [0, 0, 1]]
29
- }
30
- const { center, radius, segments, axes } = Object.assign({}, defaults, options)
24
+ export const ellipsoid = (options = {}) => {
25
+ const {
26
+ center = [0, 0, 0],
27
+ radius = [1, 1, 1],
28
+ segments = 32,
29
+ axes = [[1, 0, 0], [0, -1, 0], [0, 0, 1]]
30
+ } = options
31
31
 
32
32
  if (!isNumberArray(center, 3)) throw new Error('center must be an array of X, Y and Z values')
33
33
  if (!isNumberArray(radius, 3)) throw new Error('radius must be an array of X, Y and Z values')
@@ -8,6 +8,7 @@ import { isGTE } from './commonChecks.js'
8
8
 
9
9
  /**
10
10
  * Construct a geodesic sphere based on icosahedron symmetry.
11
+ *
11
12
  * @param {object} [options] - options for construction
12
13
  * @param {number} [options.radius=1] - target radius of sphere
13
14
  * @param {number} [options.frequency=6] - subdivision frequency per face, multiples of 6
@@ -17,12 +18,11 @@ import { isGTE } from './commonChecks.js'
17
18
  * @example
18
19
  * let myshape = geodesicSphere({radius: 15, frequency: 18})
19
20
  */
20
- export const geodesicSphere = (options) => {
21
- const defaults = {
22
- radius: 1,
23
- frequency: 6
24
- }
25
- let { radius, frequency } = Object.assign({}, defaults, options)
21
+ export const geodesicSphere = (options = {}) => {
22
+ let {
23
+ radius = 1,
24
+ frequency = 6
25
+ } = options
26
26
 
27
27
  if (!isGTE(radius, 0)) throw new Error('radius must be positive')
28
28
  if (!isGTE(frequency, 6)) throw new Error('frequency must be six or more')
@@ -2,7 +2,9 @@ import * as path2 from '../geometries/path2/index.js'
2
2
 
3
3
  /**
4
4
  * Construct a new line in two dimensional space from the given points.
5
+ *
5
6
  * The points must be provided as an array, where each element is a 2D point.
7
+ *
6
8
  * @param {Array} points - array of points from which to create the path
7
9
  * @returns {Path2} new 2D path
8
10
  * @alias module:modeling/primitives.line
@@ -24,13 +24,12 @@ import * as geom2 from '../geometries/geom2/index.js'
24
24
  * or
25
25
  * let poly = polygon({ points: [roof, wall], paths: [[0, 1, 2], [3, 4, 5, 6]] })
26
26
  */
27
- export const polygon = (options) => {
28
- const defaults = {
29
- points: [],
30
- paths: [],
31
- orientation: 'counterclockwise'
32
- }
33
- const { points, paths, orientation } = Object.assign({}, defaults, options)
27
+ export const polygon = (options = {}) => {
28
+ const {
29
+ points = [],
30
+ paths = [],
31
+ orientation = 'counterclockwise'
32
+ } = options
34
33
 
35
34
  if (!(Array.isArray(points) && Array.isArray(paths))) throw new Error('points and paths must be arrays')
36
35
 
@@ -21,14 +21,13 @@ import { isNumberArray } from './commonChecks.js'
21
21
  * let myFaces = [ [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4], [1, 0, 3], [2, 1, 3] ]
22
22
  * let myShape = polyhedron({points: myPoints, faces: myFaces, orientation: 'inward'})
23
23
  */
24
- export const polyhedron = (options) => {
25
- const defaults = {
26
- points: [],
27
- faces: [],
28
- colors: undefined,
29
- orientation: 'outward'
30
- }
31
- const { points, faces, colors, orientation } = Object.assign({}, defaults, options)
24
+ export const polyhedron = (options = {}) => {
25
+ const {
26
+ points = [],
27
+ faces = [],
28
+ colors = undefined,
29
+ orientation = 'outward'
30
+ } = options
32
31
 
33
32
  if (!(Array.isArray(points) && Array.isArray(faces))) {
34
33
  throw new Error('points and faces must be arrays')