@jscad/modeling 2.9.6 → 2.10.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 (67) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +12 -2
  3. package/dist/jscad-modeling.min.js +28 -28
  4. package/package.json +2 -2
  5. package/src/geometries/path2/appendArc.js +6 -5
  6. package/src/geometries/path2/appendArc.test.js +3 -1
  7. package/src/geometries/path2/appendBezier.js +2 -1
  8. package/src/geometries/path2/transform.js +1 -1
  9. package/src/index.d.ts +1 -0
  10. package/src/maths/constants.js +10 -0
  11. package/src/maths/mat4/fromRotation.js +1 -1
  12. package/src/maths/mat4/fromTaitBryanRotation.js +1 -1
  13. package/src/maths/mat4/fromXRotation.js +1 -1
  14. package/src/maths/mat4/fromYRotation.js +1 -1
  15. package/src/maths/mat4/fromZRotation.js +1 -1
  16. package/src/maths/mat4/invert.test.js +5 -2
  17. package/src/maths/mat4/isOnlyTransformScale.js +1 -1
  18. package/src/maths/mat4/isOnlyTransformScale.test.js +3 -1
  19. package/src/maths/rotation.test.js +5 -2
  20. package/src/maths/utils/trigonometry.js +6 -6
  21. package/src/maths/utils/trigonometry.test.js +10 -8
  22. package/src/maths/vec2/fromAngleDegrees.js +1 -1
  23. package/src/maths/vec2/fromAngleRadians.test.js +4 -1
  24. package/src/maths/vec2/normal.js +3 -1
  25. package/src/maths/vec2/rotate.test.js +4 -1
  26. package/src/maths/vec3/rotateX.test.js +4 -1
  27. package/src/maths/vec3/rotateY.test.js +4 -1
  28. package/src/maths/vec3/rotateZ.test.js +4 -1
  29. package/src/operations/expansions/expand.test.js +3 -1
  30. package/src/operations/expansions/expandShell.js +4 -4
  31. package/src/operations/expansions/offsetFromPoints.js +2 -2
  32. package/src/operations/extrusions/extrudeFromSlices.test.js +3 -2
  33. package/src/operations/extrusions/extrudeLinear.test.js +5 -3
  34. package/src/operations/extrusions/extrudeRectangular.js +1 -1
  35. package/src/operations/extrusions/extrudeRectangular.test.js +5 -3
  36. package/src/operations/extrusions/extrudeRotate.js +14 -13
  37. package/src/operations/extrusions/extrudeRotate.test.js +7 -5
  38. package/src/operations/extrusions/slice/calculatePlane.test.js +3 -2
  39. package/src/operations/extrusions/slice/index.js +2 -0
  40. package/src/operations/modifiers/generalize.d.ts +12 -0
  41. package/src/operations/modifiers/generalize.test.js +3 -1
  42. package/src/operations/modifiers/index.d.ts +2 -0
  43. package/src/operations/modifiers/snap.d.ts +6 -0
  44. package/src/operations/modifiers/snap.test.js +5 -3
  45. package/src/operations/transforms/rotate.js +1 -1
  46. package/src/operations/transforms/rotate.test.js +13 -11
  47. package/src/operations/transforms/transform.js +1 -1
  48. package/src/primitives/arc.js +8 -8
  49. package/src/primitives/arc.test.js +9 -8
  50. package/src/primitives/circle.js +4 -2
  51. package/src/primitives/circle.test.js +6 -5
  52. package/src/primitives/cylinderElliptic.js +11 -11
  53. package/src/primitives/cylinderElliptic.test.js +3 -2
  54. package/src/primitives/ellipse.js +10 -10
  55. package/src/primitives/ellipse.test.js +6 -5
  56. package/src/primitives/ellipsoid.js +3 -2
  57. package/src/primitives/roundedCuboid.js +6 -6
  58. package/src/primitives/roundedCylinder.js +3 -3
  59. package/src/primitives/roundedRectangle.js +5 -5
  60. package/src/primitives/star.js +3 -2
  61. package/src/primitives/torus.js +4 -2
  62. package/src/primitives/torus.test.js +5 -3
  63. package/src/primitives/triangle.test.js +2 -1
  64. package/src/utils/degToRad.test.js +5 -5
  65. package/src/utils/radToDeg.test.js +6 -6
  66. package/src/utils/radiusToSegments.js +6 -4
  67. package/src/utils/radiusToSegments.test.js +5 -3
@@ -1,5 +1,7 @@
1
1
  const test = require('ava')
2
2
 
3
+ const { TAU } = require('../../maths/constants')
4
+
3
5
  const { geom2, geom3, path2 } = require('../../geometries')
4
6
 
5
7
  const { rotate, rotateX, rotateY, rotateZ } = require('./index')
@@ -10,7 +12,7 @@ test('rotate: rotating of a path2 produces expected changes to points', (t) => {
10
12
  const geometry = path2.fromPoints({}, [[1, 0], [0, 1], [-1, 0]])
11
13
 
12
14
  // rotate about Z
13
- let rotated = rotate([0, 0, Math.PI / 2], geometry)
15
+ let rotated = rotate([0, 0, TAU / 4], geometry)
14
16
  let obs = path2.toPoints(rotated)
15
17
  const exp = [
16
18
  new Float32Array([0, 1]),
@@ -19,7 +21,7 @@ test('rotate: rotating of a path2 produces expected changes to points', (t) => {
19
21
  ]
20
22
  t.true(comparePoints(obs, exp))
21
23
 
22
- rotated = rotateZ(Math.PI / 2, geometry)
24
+ rotated = rotateZ(TAU / 4, geometry)
23
25
  obs = path2.toPoints(rotated)
24
26
  t.notThrows(() => path2.validate(rotated))
25
27
  t.true(comparePoints(obs, exp))
@@ -29,7 +31,7 @@ test('rotate: rotating of a geom2 produces expected changes to points', (t) => {
29
31
  const geometry = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
30
32
 
31
33
  // rotate about Z
32
- let rotated = rotate([0, 0, -Math.PI / 2], geometry)
34
+ let rotated = rotate([0, 0, -TAU / 4], geometry)
33
35
  let obs = geom2.toPoints(rotated)
34
36
  const exp = [
35
37
  new Float32Array([0, 0]),
@@ -39,7 +41,7 @@ test('rotate: rotating of a geom2 produces expected changes to points', (t) => {
39
41
  t.notThrows(() => geom2.validate(rotated))
40
42
  t.true(comparePoints(obs, exp))
41
43
 
42
- rotated = rotateZ(-Math.PI / 2, geometry)
44
+ rotated = rotateZ(-TAU / 4, geometry)
43
45
  obs = geom2.toPoints(rotated)
44
46
  t.notThrows(() => geom2.validate(rotated))
45
47
  t.true(comparePoints(obs, exp))
@@ -57,7 +59,7 @@ test('rotate: rotating of a geom3 produces expected changes to polygons', (t) =>
57
59
  const geometry = geom3.fromPoints(points)
58
60
 
59
61
  // rotate about X
60
- let rotated = rotate([Math.PI / 2], geometry)
62
+ let rotated = rotate([TAU / 4], geometry)
61
63
  let obs = geom3.toPoints(rotated)
62
64
  let exp = [
63
65
  [[-2, 12, -7.000000000000001], [-2, -18, -6.999999999999999],
@@ -76,13 +78,13 @@ test('rotate: rotating of a geom3 produces expected changes to polygons', (t) =>
76
78
  t.notThrows(() => geom3.validate(rotated))
77
79
  t.true(comparePolygonsAsPoints(obs, exp))
78
80
 
79
- rotated = rotateX(Math.PI / 2, geometry)
81
+ rotated = rotateX(TAU / 4, geometry)
80
82
  obs = geom3.toPoints(rotated)
81
83
  t.notThrows(() => geom3.validate(rotated))
82
84
  t.true(comparePolygonsAsPoints(obs, exp))
83
85
 
84
86
  // rotate about Y
85
- rotated = rotate([0, -Math.PI / 2], geometry)
87
+ rotated = rotate([0, -TAU / 4], geometry)
86
88
  obs = geom3.toPoints(rotated)
87
89
  exp = [
88
90
  [[12, -7, -2.000000000000001], [-18, -7, -1.999999999999999],
@@ -101,12 +103,12 @@ test('rotate: rotating of a geom3 produces expected changes to polygons', (t) =>
101
103
  t.notThrows(() => geom3.validate(rotated))
102
104
  t.true(comparePolygonsAsPoints(obs, exp))
103
105
 
104
- rotated = rotateY(-Math.PI / 2, geometry)
106
+ rotated = rotateY(-TAU / 4, geometry)
105
107
  obs = geom3.toPoints(rotated)
106
108
  t.true(comparePolygonsAsPoints(obs, exp))
107
109
 
108
110
  // rotate about Z
109
- rotated = rotate([0, 0, Math.PI], geometry)
111
+ rotated = rotate([0, 0, TAU / 2], geometry)
110
112
  obs = geom3.toPoints(rotated)
111
113
  exp = [
112
114
  [[2.000000000000001, 7, -12], [2.000000000000001, 7, 18],
@@ -125,7 +127,7 @@ test('rotate: rotating of a geom3 produces expected changes to polygons', (t) =>
125
127
  t.notThrows(() => geom3.validate(rotated))
126
128
  t.true(comparePolygonsAsPoints(obs, exp))
127
129
 
128
- rotated = rotateZ(Math.PI, geometry)
130
+ rotated = rotateZ(TAU / 2, geometry)
129
131
  obs = geom3.toPoints(rotated)
130
132
  t.notThrows(() => geom3.validate(rotated))
131
133
  t.true(comparePolygonsAsPoints(obs, exp))
@@ -136,7 +138,7 @@ test('rotate: rotating of multiple objects produces expected changes', (t) => {
136
138
  const geometry1 = path2.fromPoints({}, [[-5, 5], [5, 5], [-5, -5], [10, -5]])
137
139
  const geometry2 = geom2.fromPoints([[-5, -5], [0, 5], [10, -5]])
138
140
 
139
- const rotated = rotate([0, 0, Math.PI / 2], junk, geometry1, geometry2)
141
+ const rotated = rotate([0, 0, TAU / 4], junk, geometry1, geometry2)
140
142
 
141
143
  t.is(rotated[0], junk)
142
144
 
@@ -12,7 +12,7 @@ const path2 = require('../../geometries/path2')
12
12
  * @alias module:modeling/transforms.transform
13
13
  *
14
14
  * @example
15
- * const newsphere = transform(mat4.rotateX(Math.PI/4), sphere())
15
+ * const newsphere = transform(mat4.rotateX(TAU / 8), sphere())
16
16
  */
17
17
  const transform = (matrix, ...objects) => {
18
18
  // TODO how to check that the matrix is REAL?
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../maths/constants')
1
+ const { EPS, TAU } = require('../maths/constants')
2
2
 
3
3
  const vec2 = require('../maths/vec2')
4
4
 
@@ -12,7 +12,7 @@ const { isGT, isGTE, isNumberArray } = require('./commonChecks')
12
12
  * @param {Array} [options.center=[0,0]] - center of arc
13
13
  * @param {Number} [options.radius=1] - radius of arc
14
14
  * @param {Number} [options.startAngle=0] - starting angle of the arc, in radians
15
- * @param {Number} [options.endAngle=Math.PI*2] - ending angle of the arc, in radians
15
+ * @param {Number} [options.endAngle=TAU] - ending angle of the arc, in radians
16
16
  * @param {Number} [options.segments=32] - number of segments to create per full rotation
17
17
  * @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
18
  * @returns {path2} new 2D path
@@ -23,7 +23,7 @@ const arc = (options) => {
23
23
  center: [0, 0],
24
24
  radius: 1,
25
25
  startAngle: 0,
26
- endAngle: (Math.PI * 2),
26
+ endAngle: TAU,
27
27
  makeTangent: false,
28
28
  segments: 32
29
29
  }
@@ -35,15 +35,15 @@ const arc = (options) => {
35
35
  if (!isGTE(endAngle, 0)) throw new Error('endAngle must be positive')
36
36
  if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
37
37
 
38
- startAngle = startAngle % (Math.PI * 2)
39
- endAngle = endAngle % (Math.PI * 2)
38
+ startAngle = startAngle % TAU
39
+ endAngle = endAngle % TAU
40
40
 
41
- let rotation = (Math.PI * 2)
41
+ let rotation = TAU
42
42
  if (startAngle < endAngle) {
43
43
  rotation = endAngle - startAngle
44
44
  }
45
45
  if (startAngle > endAngle) {
46
- rotation = endAngle + ((Math.PI * 2) - startAngle)
46
+ rotation = endAngle + (TAU - startAngle)
47
47
  }
48
48
 
49
49
  const minangle = Math.acos(((radius * radius) + (radius * radius) - (EPS * EPS)) / (2 * radius * radius))
@@ -59,7 +59,7 @@ const arc = (options) => {
59
59
  pointArray.push(point)
60
60
  } else {
61
61
  // note: add one additional step to acheive full rotation
62
- const numsteps = Math.max(1, Math.floor(segments * (rotation / (Math.PI * 2)))) + 1
62
+ const numsteps = Math.max(1, Math.floor(segments * (rotation / TAU))) + 1
63
63
  let edgestepsize = numsteps * 0.5 / rotation // step size for half a degree
64
64
  if (edgestepsize > 0.25) edgestepsize = 0.25
65
65
 
@@ -1,11 +1,12 @@
1
1
  const test = require('ava')
2
2
 
3
- const { arc } = require('./index')
4
-
3
+ const { TAU } = require('../maths/constants')
5
4
  const path2 = require('../geometries/path2')
6
5
 
7
6
  const comparePoints = require('../../test/helpers/comparePoints')
8
7
 
8
+ const { arc } = require('./index')
9
+
9
10
  test('arc (defaults)', (t) => {
10
11
  const geometry = arc()
11
12
  const obs = path2.toPoints(geometry)
@@ -86,7 +87,7 @@ test('arc (options)', (t) => {
86
87
  [0.9350162426854147, -0.35460488704253595],
87
88
  [1, -2.4492935982947064e-16]
88
89
  ]
89
- geometry = arc({ startAngle: Math.PI / 2, segments: 16 })
90
+ geometry = arc({ startAngle: TAU / 4, segments: 16 })
90
91
  obs = path2.toPoints(geometry)
91
92
 
92
93
  t.notThrows(() => path2.validate(geometry))
@@ -102,7 +103,7 @@ test('arc (options)', (t) => {
102
103
  [0.30901699437494745, 0.9510565162951535],
103
104
  [6.123233995736766e-17, 1]
104
105
  ]
105
- geometry = arc({ endAngle: Math.PI / 2, segments: 16 })
106
+ geometry = arc({ endAngle: TAU / 4, segments: 16 })
106
107
  obs = path2.toPoints(geometry)
107
108
 
108
109
  t.notThrows(() => path2.validate(geometry))
@@ -167,7 +168,7 @@ test('arc (rotations)', (t) => {
167
168
  [-0.9510565162951535, 0.3090169943749475],
168
169
  [-1, 1.2246467991473532e-16]
169
170
  ]
170
- let geometry = arc({ startAngle: Math.PI / 2, endAngle: Math.PI, segments: 16 })
171
+ let geometry = arc({ startAngle: TAU / 4, endAngle: TAU / 2, segments: 16 })
171
172
  let obs = path2.toPoints(geometry)
172
173
 
173
174
  t.notThrows(() => path2.validate(geometry))
@@ -186,7 +187,7 @@ test('arc (rotations)', (t) => {
186
187
  [0.9396926207859084, -0.3420201433256686],
187
188
  [1, -2.4492935982947064e-16]
188
189
  ]
189
- geometry = arc({ startAngle: Math.PI, endAngle: Math.PI * 2, segments: 16 })
190
+ geometry = arc({ startAngle: TAU / 2, endAngle: TAU, segments: 16 })
190
191
  obs = path2.toPoints(geometry)
191
192
 
192
193
  t.notThrows(() => path2.validate(geometry))
@@ -205,7 +206,7 @@ test('arc (rotations)', (t) => {
205
206
  [0.34202014332566866, 0.9396926207859084],
206
207
  [3.061616997868383e-16, 1]
207
208
  ]
208
- geometry = arc({ startAngle: Math.PI * 2 * 0.75, endAngle: Math.PI / 2, segments: 16 })
209
+ geometry = arc({ startAngle: TAU * 0.75, endAngle: TAU / 4, segments: 16 })
209
210
  obs = path2.toPoints(geometry)
210
211
 
211
212
  t.notThrows(() => path2.validate(geometry))
@@ -213,7 +214,7 @@ test('arc (rotations)', (t) => {
213
214
  t.true(comparePoints(obs, exp))
214
215
 
215
216
  exp = [[-1.8369701987210297e-16, -1]]
216
- geometry = arc({ startAngle: Math.PI * 2 * 0.75, endAngle: 270.000000005 * 0.017453292519943295, segments: 16 })
217
+ geometry = arc({ startAngle: TAU * 0.75, endAngle: 270.000000005 * 0.017453292519943295, segments: 16 })
217
218
  obs = path2.toPoints(geometry)
218
219
 
219
220
  t.notThrows(() => path2.validate(geometry))
@@ -1,3 +1,5 @@
1
+ const { TAU } = require('../maths/constants')
2
+
1
3
  const ellipse = require('./ellipse')
2
4
 
3
5
  const { isGT } = require('./commonChecks')
@@ -9,7 +11,7 @@ const { isGT } = require('./commonChecks')
9
11
  * @param {Array} [options.center=[0,0]] - center of circle
10
12
  * @param {Number} [options.radius=1] - radius of circle
11
13
  * @param {Number} [options.startAngle=0] - start angle of circle, in radians
12
- * @param {Number} [options.endAngle=(Math.PI * 2)] - end angle of circle, in radians
14
+ * @param {Number} [options.endAngle=TAU] - end angle of circle, in radians
13
15
  * @param {Number} [options.segments=32] - number of segments to create per full rotation
14
16
  * @returns {geom2} new 2D geometry
15
17
  * @alias module:modeling/primitives.circle
@@ -21,7 +23,7 @@ const circle = (options) => {
21
23
  center: [0, 0],
22
24
  radius: 1,
23
25
  startAngle: 0,
24
- endAngle: (Math.PI * 2),
26
+ endAngle: TAU,
25
27
  segments: 32
26
28
  }
27
29
  let { center, radius, startAngle, endAngle, segments } = Object.assign({}, defaults, options)
@@ -1,11 +1,12 @@
1
1
  const test = require('ava')
2
2
 
3
- const { circle } = require('./index')
4
-
3
+ const { TAU } = require('../maths/constants')
5
4
  const geom2 = require('../geometries/geom2')
6
5
 
7
6
  const comparePoints = require('../../test/helpers/comparePoints')
8
7
 
8
+ const { circle } = require('./index')
9
+
9
10
  test('circle (defaults)', (t) => {
10
11
  const geometry = circle()
11
12
  const pts = geom2.toPoints(geometry)
@@ -84,7 +85,7 @@ test('circle (options)', (t) => {
84
85
  t.true(comparePoints(pts, exp))
85
86
 
86
87
  // test startAngle
87
- geometry = circle({ radius: 3.5, startAngle: Math.PI / 2, segments: 16 })
88
+ geometry = circle({ radius: 3.5, startAngle: TAU / 4, segments: 16 })
88
89
  pts = geom2.toPoints(geometry)
89
90
  exp = [
90
91
  [0, 3.5],
@@ -108,7 +109,7 @@ test('circle (options)', (t) => {
108
109
  t.true(comparePoints(pts, exp))
109
110
 
110
111
  // test endAngle
111
- geometry = circle({ radius: 3.5, endAngle: Math.PI / 2, segments: 16 })
112
+ geometry = circle({ radius: 3.5, endAngle: TAU / 4, segments: 16 })
112
113
  pts = geom2.toPoints(geometry)
113
114
  exp = [
114
115
  [3.5, 0],
@@ -124,7 +125,7 @@ test('circle (options)', (t) => {
124
125
  t.true(comparePoints(pts, exp))
125
126
 
126
127
  // test full rotation with non-zero startAngle
127
- geometry = circle({ startAngle: 1, endAngle: 1 + 2 * Math.PI })
128
+ geometry = circle({ startAngle: 1, endAngle: 1 + TAU })
128
129
  pts = geom2.toPoints(geometry)
129
130
 
130
131
  t.notThrows(() => geom2.validate(geometry))
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../maths/constants')
1
+ const { EPS, TAU } = require('../maths/constants')
2
2
 
3
3
  const vec3 = require('../maths/vec3')
4
4
 
@@ -17,7 +17,7 @@ const { isGT, isGTE, isNumberArray } = require('./commonChecks')
17
17
  * @param {Array} [options.startRadius=[1,1]] - radius of rounded start, must be two dimensional array
18
18
  * @param {Number} [options.startAngle=0] - start angle of cylinder, in radians
19
19
  * @param {Array} [options.endRadius=[1,1]] - radius of rounded end, must be two dimensional array
20
- * @param {Number} [options.endAngle=(Math.PI * 2)] - end angle of cylinder, in radians
20
+ * @param {Number} [options.endAngle=TAU] - end angle of cylinder, in radians
21
21
  * @param {Number} [options.segments=32] - number of segments to create per full rotation
22
22
  * @returns {geom3} new geometry
23
23
  * @alias module:modeling/primitives.cylinderElliptic
@@ -32,7 +32,7 @@ const cylinderElliptic = (options) => {
32
32
  startRadius: [1, 1],
33
33
  startAngle: 0,
34
34
  endRadius: [1, 1],
35
- endAngle: (Math.PI * 2),
35
+ endAngle: TAU,
36
36
  segments: 32
37
37
  }
38
38
  let { center, height, startRadius, startAngle, endRadius, endAngle, segments } = Object.assign({}, defaults, options)
@@ -48,15 +48,15 @@ const cylinderElliptic = (options) => {
48
48
  if (!isGTE(endAngle, 0)) throw new Error('endAngle must be positive')
49
49
  if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
50
50
 
51
- startAngle = startAngle % (Math.PI * 2)
52
- endAngle = endAngle % (Math.PI * 2)
51
+ startAngle = startAngle % TAU
52
+ endAngle = endAngle % TAU
53
53
 
54
- let rotation = (Math.PI * 2)
54
+ let rotation = TAU
55
55
  if (startAngle < endAngle) {
56
56
  rotation = endAngle - startAngle
57
57
  }
58
58
  if (startAngle > endAngle) {
59
- rotation = endAngle + ((Math.PI * 2) - startAngle)
59
+ rotation = endAngle + (TAU - startAngle)
60
60
  }
61
61
 
62
62
  const minradius = Math.min(startRadius[0], startRadius[1], endRadius[0], endRadius[1])
@@ -64,7 +64,7 @@ const cylinderElliptic = (options) => {
64
64
  (2 * minradius * minradius))
65
65
  if (rotation < minangle) throw new Error('startAngle and endAngle do not define a significant rotation')
66
66
 
67
- const slices = Math.floor(segments * (rotation / (Math.PI * 2)))
67
+ const slices = Math.floor(segments * (rotation / TAU))
68
68
 
69
69
  const start = vec3.fromValues(0, 0, -(height / 2))
70
70
  const end = vec3.fromValues(0, 0, height / 2)
@@ -97,8 +97,8 @@ const cylinderElliptic = (options) => {
97
97
  for (let i = 0; i < slices; i++) {
98
98
  const t0 = i / slices
99
99
  let t1 = (i + 1) / slices
100
- // fix rounding error when rotating 2 * PI radians
101
- if (rotation === 2 * Math.PI && i === slices - 1) t1 = 0
100
+ // fix rounding error when rotating TAU radians
101
+ if (rotation === TAU && i === slices - 1) t1 = 0
102
102
 
103
103
  if (endRadius[0] === startRadius[0] && endRadius[1] === startRadius[1]) {
104
104
  polygons.push(fromPoints(start, point(0, t1, endRadius), point(0, t0, endRadius)))
@@ -119,7 +119,7 @@ const cylinderElliptic = (options) => {
119
119
  }
120
120
  }
121
121
  }
122
- if (rotation < (Math.PI * 2)) {
122
+ if (rotation < TAU) {
123
123
  polygons.push(fromPoints(start, point(0, 0, startRadius), end))
124
124
  polygons.push(fromPoints(point(0, 0, startRadius), point(1, 0, endRadius), end))
125
125
  polygons.push(fromPoints(start, end, point(0, 1, startRadius)))
@@ -1,5 +1,6 @@
1
1
  const test = require('ava')
2
2
 
3
+ const { TAU } = require('../maths/constants')
3
4
  const geom3 = require('../geometries/geom3')
4
5
 
5
6
  const { cylinderElliptic } = require('./index')
@@ -132,14 +133,14 @@ test('cylinderElliptic (options)', (t) => {
132
133
  t.true(comparePolygonsAsPoints(pts, exp))
133
134
 
134
135
  // test startAngle and endAngle
135
- obs = cylinderElliptic({ startRadius: [1, 2], endRadius: [2, 1], startAngle: Math.PI / 2, endAngle: Math.PI * 2 * 0.75, segments: 12 })
136
+ obs = cylinderElliptic({ startRadius: [1, 2], endRadius: [2, 1], startAngle: TAU / 4, endAngle: TAU * 0.75, segments: 12 })
136
137
  pts = geom3.toPoints(obs)
137
138
 
138
139
  t.notThrows(() => geom3.validate(obs))
139
140
  t.is(pts.length, 28)
140
141
 
141
142
  // test startAngle and endAngle
142
- obs = cylinderElliptic({ startAngle: 1, endAngle: 1 + 2 * Math.PI })
143
+ obs = cylinderElliptic({ startAngle: 1, endAngle: 1 + TAU })
143
144
  pts = geom3.toPoints(obs)
144
145
 
145
146
  t.notThrows(() => geom3.validate(obs))
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../maths/constants')
1
+ const { EPS, TAU } = require('../maths/constants')
2
2
 
3
3
  const vec2 = require('../maths/vec2')
4
4
 
@@ -15,7 +15,7 @@ const { isGTE, isNumberArray } = require('./commonChecks')
15
15
  * @param {Array} [options.center=[0,0]] - center of ellipse
16
16
  * @param {Array} [options.radius=[1,1]] - radius of ellipse, along X and Y
17
17
  * @param {Number} [options.startAngle=0] - start angle of ellipse, in radians
18
- * @param {Number} [options.endAngle=(Math.PI * 2)] - end angle of ellipse, in radians
18
+ * @param {Number} [options.endAngle=TAU] - end angle of ellipse, in radians
19
19
  * @param {Number} [options.segments=32] - number of segments to create per full rotation
20
20
  * @returns {geom2} new 2D geometry
21
21
  * @alias module:modeling/primitives.ellipse
@@ -27,7 +27,7 @@ const ellipse = (options) => {
27
27
  center: [0, 0],
28
28
  radius: [1, 1],
29
29
  startAngle: 0,
30
- endAngle: (Math.PI * 2),
30
+ endAngle: TAU,
31
31
  segments: 32
32
32
  }
33
33
  let { center, radius, startAngle, endAngle, segments } = Object.assign({}, defaults, options)
@@ -39,15 +39,15 @@ const ellipse = (options) => {
39
39
  if (!isGTE(endAngle, 0)) throw new Error('endAngle must be positive')
40
40
  if (!isGTE(segments, 3)) throw new Error('segments must be three or more')
41
41
 
42
- startAngle = startAngle % (Math.PI * 2)
43
- endAngle = endAngle % (Math.PI * 2)
42
+ startAngle = startAngle % TAU
43
+ endAngle = endAngle % TAU
44
44
 
45
- let rotation = (Math.PI * 2)
45
+ let rotation = TAU
46
46
  if (startAngle < endAngle) {
47
47
  rotation = endAngle - startAngle
48
48
  }
49
49
  if (startAngle > endAngle) {
50
- rotation = endAngle + ((Math.PI * 2) - startAngle)
50
+ rotation = endAngle + (TAU - startAngle)
51
51
  }
52
52
 
53
53
  const minradius = Math.min(radius[0], radius[1])
@@ -55,20 +55,20 @@ const ellipse = (options) => {
55
55
  (2 * minradius * minradius))
56
56
  if (rotation < minangle) throw new Error('startAngle and endAngle do not define a significant rotation')
57
57
 
58
- segments = Math.floor(segments * (rotation / (Math.PI * 2)))
58
+ segments = Math.floor(segments * (rotation / TAU))
59
59
 
60
60
  const centerv = vec2.clone(center)
61
61
  const step = rotation / segments // radians per segment
62
62
 
63
63
  const points = []
64
- segments = (rotation < Math.PI * 2) ? segments + 1 : segments
64
+ segments = (rotation < TAU) ? segments + 1 : segments
65
65
  for (let i = 0; i < segments; i++) {
66
66
  const angle = (step * i) + startAngle
67
67
  const point = vec2.fromValues(radius[0] * cos(angle), radius[1] * sin(angle))
68
68
  vec2.add(point, centerv, point)
69
69
  points.push(point)
70
70
  }
71
- if (rotation < Math.PI * 2) points.push(centerv)
71
+ if (rotation < TAU) points.push(centerv)
72
72
  return geom2.fromPoints(points)
73
73
  }
74
74
 
@@ -1,11 +1,12 @@
1
1
  const test = require('ava')
2
2
 
3
- const { ellipse } = require('./index')
4
-
3
+ const { TAU } = require('../maths/constants')
5
4
  const geom2 = require('../geometries/geom2')
6
5
 
7
6
  const comparePoints = require('../../test/helpers/comparePoints')
8
7
 
8
+ const { ellipse } = require('./index')
9
+
9
10
  test('ellipse (defaults)', (t) => {
10
11
  const geometry = ellipse()
11
12
  const obs = geom2.toPoints(geometry)
@@ -84,7 +85,7 @@ test('ellipse (options)', (t) => {
84
85
  t.true(comparePoints(obs, exp))
85
86
 
86
87
  // test startAngle
87
- geometry = ellipse({ radius: [3, 5], startAngle: Math.PI / 2, segments: 16 })
88
+ geometry = ellipse({ radius: [3, 5], startAngle: TAU / 4, segments: 16 })
88
89
  obs = geom2.toPoints(geometry)
89
90
  exp = [
90
91
  [0, 5],
@@ -108,7 +109,7 @@ test('ellipse (options)', (t) => {
108
109
  t.true(comparePoints(obs, exp))
109
110
 
110
111
  // test endAngle
111
- geometry = ellipse({ radius: [3, 5], endAngle: Math.PI / 2, segments: 16 })
112
+ geometry = ellipse({ radius: [3, 5], endAngle: TAU / 4, segments: 16 })
112
113
  obs = geom2.toPoints(geometry)
113
114
  exp = [
114
115
  [3, 0],
@@ -124,7 +125,7 @@ test('ellipse (options)', (t) => {
124
125
  t.true(comparePoints(obs, exp))
125
126
 
126
127
  // test full rotation with non-zero startAngle
127
- geometry = ellipse({ startAngle: 1, endAngle: 1 + 2 * Math.PI })
128
+ geometry = ellipse({ startAngle: 1, endAngle: 1 + TAU })
128
129
  obs = geom2.toPoints(geometry)
129
130
 
130
131
  t.notThrows(() => geom2.validate(geometry))
@@ -1,3 +1,4 @@
1
+ const { TAU } = require('../maths/constants')
1
2
  const vec3 = require('../maths/vec3')
2
3
 
3
4
  const geom3 = require('../geometries/geom3')
@@ -44,12 +45,12 @@ const ellipsoid = (options) => {
44
45
  const p1 = vec3.create()
45
46
  const p2 = vec3.create()
46
47
  for (let slice1 = 0; slice1 <= segments; slice1++) {
47
- const angle = 2 * Math.PI * slice1 / segments
48
+ const angle = TAU * slice1 / segments
48
49
  const cylinderpoint = vec3.add(vec3.create(), vec3.scale(p1, xvector, cos(angle)), vec3.scale(p2, yvector, sin(angle)))
49
50
  if (slice1 > 0) {
50
51
  let prevcospitch, prevsinpitch
51
52
  for (let slice2 = 0; slice2 <= qsegments; slice2++) {
52
- const pitch = 0.5 * Math.PI * slice2 / qsegments
53
+ const pitch = TAU / 4 * slice2 / qsegments
53
54
  const cospitch = cos(pitch)
54
55
  const sinpitch = sin(pitch)
55
56
  if (slice2 > 0) {
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../maths/constants')
1
+ const { EPS, TAU } = require('../maths/constants')
2
2
 
3
3
  const vec2 = require('../maths/vec2')
4
4
  const vec3 = require('../maths/vec3')
@@ -11,7 +11,7 @@ const { sin, cos } = require('../maths/utils/trigonometry')
11
11
  const { isGT, isGTE, isNumberArray } = require('./commonChecks')
12
12
 
13
13
  const createCorners = (center, size, radius, segments, slice, positive) => {
14
- const pitch = (Math.PI / 2) * slice / segments
14
+ const pitch = (TAU / 4) * slice / segments
15
15
  const cospitch = cos(pitch)
16
16
  const sinpitch = sin(pitch)
17
17
 
@@ -31,16 +31,16 @@ const createCorners = (center, size, radius, segments, slice, positive) => {
31
31
  const corner2Points = []
32
32
  const corner3Points = []
33
33
  for (let i = 0; i <= layersegments; i++) {
34
- const radians = layersegments > 0 ? Math.PI / 2 * i / layersegments : 0
34
+ const radians = layersegments > 0 ? TAU / 4 * i / layersegments : 0
35
35
  const point2d = vec2.fromAngleRadians(vec2.create(), radians)
36
36
  vec2.scale(point2d, point2d, layerradius)
37
37
  const point3d = vec3.fromVec2(vec3.create(), point2d)
38
38
  corner0Points.push(vec3.add(vec3.create(), corner0, point3d))
39
- vec3.rotateZ(point3d, point3d, [0, 0, 0], Math.PI / 2)
39
+ vec3.rotateZ(point3d, point3d, [0, 0, 0], TAU / 4)
40
40
  corner1Points.push(vec3.add(vec3.create(), corner1, point3d))
41
- vec3.rotateZ(point3d, point3d, [0, 0, 0], Math.PI / 2)
41
+ vec3.rotateZ(point3d, point3d, [0, 0, 0], TAU / 4)
42
42
  corner2Points.push(vec3.add(vec3.create(), corner2, point3d))
43
- vec3.rotateZ(point3d, point3d, [0, 0, 0], Math.PI / 2)
43
+ vec3.rotateZ(point3d, point3d, [0, 0, 0], TAU / 4)
44
44
  corner3Points.push(vec3.add(vec3.create(), corner3, point3d))
45
45
  }
46
46
  if (!positive) {
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../maths/constants')
1
+ const { EPS, TAU } = require('../maths/constants')
2
2
 
3
3
  const vec3 = require('../maths/vec3')
4
4
 
@@ -74,7 +74,7 @@ const roundedCylinder = (options) => {
74
74
  const v2 = vec3.create()
75
75
  let prevcylinderpoint
76
76
  for (let slice1 = 0; slice1 <= segments; slice1++) {
77
- const angle = 2 * Math.PI * slice1 / segments
77
+ const angle = TAU * slice1 / segments
78
78
  const cylinderpoint = vec3.add(vec3.create(), vec3.scale(v1, xvector, cos(angle)), vec3.scale(v2, yvector, sin(angle)))
79
79
  if (slice1 > 0) {
80
80
  // cylinder wall
@@ -87,7 +87,7 @@ const roundedCylinder = (options) => {
87
87
 
88
88
  let prevcospitch, prevsinpitch
89
89
  for (let slice2 = 0; slice2 <= qsegments; slice2++) {
90
- const pitch = 0.5 * Math.PI * slice2 / qsegments
90
+ const pitch = TAU / 4 * slice2 / qsegments
91
91
  const cospitch = cos(pitch)
92
92
  const sinpitch = sin(pitch)
93
93
  if (slice2 > 0) {
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../maths/constants')
1
+ const { EPS, TAU } = require('../maths/constants')
2
2
 
3
3
  const vec2 = require('../maths/vec2')
4
4
 
@@ -51,15 +51,15 @@ const roundedRectangle = (options) => {
51
51
  const corner2Points = []
52
52
  const corner3Points = []
53
53
  for (let i = 0; i <= cornersegments; i++) {
54
- const radians = Math.PI / 2 * i / cornersegments
54
+ const radians = TAU / 4 * i / cornersegments
55
55
  const point = vec2.fromAngleRadians(vec2.create(), radians)
56
56
  vec2.scale(point, point, roundRadius)
57
57
  corner0Points.push(vec2.add(vec2.create(), corner0, point))
58
- vec2.rotate(point, point, vec2.create(), Math.PI / 2)
58
+ vec2.rotate(point, point, vec2.create(), TAU / 4)
59
59
  corner1Points.push(vec2.add(vec2.create(), corner1, point))
60
- vec2.rotate(point, point, vec2.create(), Math.PI / 2)
60
+ vec2.rotate(point, point, vec2.create(), TAU / 4)
61
61
  corner2Points.push(vec2.add(vec2.create(), corner2, point))
62
- vec2.rotate(point, point, vec2.create(), Math.PI / 2)
62
+ vec2.rotate(point, point, vec2.create(), TAU / 4)
63
63
  corner3Points.push(vec2.add(vec2.create(), corner3, point))
64
64
  }
65
65
 
@@ -1,3 +1,4 @@
1
+ const { TAU } = require('../maths/constants')
1
2
  const vec2 = require('../maths/vec2')
2
3
 
3
4
  const geom2 = require('../geometries/geom2')
@@ -13,7 +14,7 @@ const getRadiusRatio = (vertices, density) => {
13
14
  }
14
15
 
15
16
  const getPoints = (vertices, radius, startAngle, center) => {
16
- const a = (Math.PI * 2) / vertices
17
+ const a = TAU / vertices
17
18
 
18
19
  const points = []
19
20
  for (let i = 0; i < vertices; i++) {
@@ -63,7 +64,7 @@ const star = (options) => {
63
64
  vertices = Math.floor(vertices)
64
65
  density = Math.floor(density)
65
66
 
66
- startAngle = startAngle % (Math.PI * 2)
67
+ startAngle = startAngle % TAU
67
68
 
68
69
  if (innerRadius === 0) {
69
70
  if (!isGTE(density, 2)) throw new Error('density must be two or more')
@@ -1,3 +1,5 @@
1
+ const { TAU } = require('../maths/constants')
2
+
1
3
  const extrudeRotate = require('../operations/extrusions/extrudeRotate')
2
4
  const { rotate } = require('../operations/transforms/rotate')
3
5
  const { translate } = require('../operations/transforms/translate')
@@ -14,7 +16,7 @@ const { isGT, isGTE } = require('./commonChecks')
14
16
  * @param {Integer} [options.innerSegments=32] - number of segments to create per rotation
15
17
  * @param {Integer} [options.outerSegments=32] - number of segments to create per rotation
16
18
  * @param {Integer} [options.innerRotation=0] - rotation of small (inner) circle in radians
17
- * @param {Number} [options.outerRotation=(PI * 2)] - rotation (outer) of the torus (RADIANS)
19
+ * @param {Number} [options.outerRotation=TAU] - rotation (outer) of the torus (RADIANS)
18
20
  * @param {Number} [options.startAngle=0] - start angle of the torus (RADIANS)
19
21
  * @returns {geom3} new 3D geometry
20
22
  * @alias module:modeling/primitives.torus
@@ -30,7 +32,7 @@ const torus = (options) => {
30
32
  outerSegments: 32,
31
33
  innerRotation: 0,
32
34
  startAngle: 0,
33
- outerRotation: Math.PI * 2
35
+ outerRotation: TAU
34
36
  }
35
37
  const { innerRadius, innerSegments, outerRadius, outerSegments, innerRotation, startAngle, outerRotation } = Object.assign({}, defaults, options)
36
38