@jscad/modeling 2.9.6 → 2.11.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 (78) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +12 -2
  3. package/dist/jscad-modeling.min.js +154 -151
  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/measurements/index.d.ts +4 -0
  30. package/src/measurements/measureBoundingSphere.d.ts +9 -0
  31. package/src/measurements/measureCenter.d.ts +7 -0
  32. package/src/measurements/measureCenterOfMass.d.ts +7 -0
  33. package/src/measurements/measureDimensions.d.ts +7 -0
  34. package/src/operations/expansions/expand.test.js +3 -1
  35. package/src/operations/expansions/expandShell.js +4 -4
  36. package/src/operations/expansions/offsetFromPoints.js +2 -2
  37. package/src/operations/extrusions/extrudeFromSlices.test.js +3 -2
  38. package/src/operations/extrusions/extrudeHelical.d.ts +14 -0
  39. package/src/operations/extrusions/extrudeHelical.js +114 -0
  40. package/src/operations/extrusions/extrudeHelical.test.js +62 -0
  41. package/src/operations/extrusions/extrudeLinear.test.js +5 -3
  42. package/src/operations/extrusions/extrudeRectangular.js +1 -1
  43. package/src/operations/extrusions/extrudeRectangular.test.js +5 -3
  44. package/src/operations/extrusions/extrudeRotate.js +14 -13
  45. package/src/operations/extrusions/extrudeRotate.test.js +7 -5
  46. package/src/operations/extrusions/index.js +1 -0
  47. package/src/operations/extrusions/slice/calculatePlane.test.js +3 -2
  48. package/src/operations/extrusions/slice/index.js +2 -0
  49. package/src/operations/modifiers/generalize.d.ts +12 -0
  50. package/src/operations/modifiers/generalize.test.js +3 -1
  51. package/src/operations/modifiers/index.d.ts +2 -0
  52. package/src/operations/modifiers/snap.d.ts +6 -0
  53. package/src/operations/modifiers/snap.test.js +5 -3
  54. package/src/operations/transforms/rotate.js +1 -1
  55. package/src/operations/transforms/rotate.test.js +13 -11
  56. package/src/operations/transforms/transform.js +1 -1
  57. package/src/primitives/arc.js +8 -8
  58. package/src/primitives/arc.test.js +9 -8
  59. package/src/primitives/circle.js +4 -2
  60. package/src/primitives/circle.test.js +6 -5
  61. package/src/primitives/cuboid.js +1 -1
  62. package/src/primitives/cylinderElliptic.js +11 -11
  63. package/src/primitives/cylinderElliptic.test.js +3 -2
  64. package/src/primitives/ellipse.js +10 -10
  65. package/src/primitives/ellipse.test.js +6 -5
  66. package/src/primitives/ellipsoid.js +3 -2
  67. package/src/primitives/roundedCuboid.js +6 -6
  68. package/src/primitives/roundedCylinder.js +3 -3
  69. package/src/primitives/roundedRectangle.js +5 -5
  70. package/src/primitives/star.js +3 -2
  71. package/src/primitives/torus.js +4 -2
  72. package/src/primitives/torus.test.js +5 -3
  73. package/src/primitives/triangle.test.js +2 -1
  74. package/src/utils/degToRad.test.js +5 -5
  75. package/src/utils/insertSorted.js +1 -1
  76. package/src/utils/radToDeg.test.js +6 -6
  77. package/src/utils/radiusToSegments.js +6 -4
  78. package/src/utils/radiusToSegments.test.js +5 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jscad/modeling",
3
- "version": "2.9.6",
3
+ "version": "2.11.0",
4
4
  "description": "Constructive Solid Geometry (CSG) Library for JSCAD",
5
5
  "homepage": "https://openjscad.xyz/",
6
6
  "repository": "https://github.com/jscad/OpenJSCAD.org",
@@ -61,5 +61,5 @@
61
61
  "nyc": "15.1.0",
62
62
  "uglifyify": "5.0.2"
63
63
  },
64
- "gitHead": "9768af96e5da00cd113c00ddeb0f6046707819b1"
64
+ "gitHead": "5899622c5ffc640001da7261d7c06a1223064ccc"
65
65
  }
@@ -1,3 +1,4 @@
1
+ const { TAU } = require('../../maths/constants')
1
2
  const vec2 = require('../../maths/vec2')
2
3
 
3
4
  const fromPoints = require('./fromPoints')
@@ -12,7 +13,7 @@ const toPoints = require('./toPoints')
12
13
  * @param {vec2} [options.radius=[0,0]] - radius of arc (X and Y)
13
14
  * @param {Number} [options.xaxisrotation=0] - rotation (RADIANS) of the X axis of the arc with respect to the X axis of the coordinate system
14
15
  * @param {Boolean} [options.clockwise=false] - draw an arc clockwise with respect to the center point
15
- * @param {Boolean} [options.large=false] - draw an arc longer than PI radians
16
+ * @param {Boolean} [options.large=false] - draw an arc longer than TAU / 2 radians
16
17
  * @param {Number} [options.segments=16] - number of segments per full rotation
17
18
  * @param {path2} geometry - the path of which to append the arc
18
19
  * @returns {path2} a new path with the appended points
@@ -111,15 +112,15 @@ const appendArc = (options, geometry) => {
111
112
  const theta1 = vec2.angleRadians(vector1)
112
113
  const theta2 = vec2.angleRadians(vector2)
113
114
  let deltatheta = theta2 - theta1
114
- deltatheta = deltatheta % (2 * Math.PI)
115
+ deltatheta = deltatheta % TAU
115
116
  if ((!sweepFlag) && (deltatheta > 0)) {
116
- deltatheta -= 2 * Math.PI
117
+ deltatheta -= TAU
117
118
  } else if ((sweepFlag) && (deltatheta < 0)) {
118
- deltatheta += 2 * Math.PI
119
+ deltatheta += TAU
119
120
  }
120
121
 
121
122
  // Ok, we have the center point and angle range (from theta1, deltatheta radians) so we can create the ellipse
122
- let numsteps = Math.ceil(Math.abs(deltatheta) / (2 * Math.PI) * segments) + 1
123
+ let numsteps = Math.ceil(Math.abs(deltatheta) / TAU * segments) + 1
123
124
  if (numsteps < 1) numsteps = 1
124
125
  for (let step = 1; step < numsteps; step++) {
125
126
  const theta = theta1 + step / numsteps * deltatheta
@@ -1,5 +1,7 @@
1
1
  const test = require('ava')
2
2
 
3
+ const { TAU } = require('../../maths/constants')
4
+
3
5
  const { appendArc, fromPoints, toPoints } = require('./index')
4
6
 
5
7
  const { comparePoints } = require('../../../test/helpers/')
@@ -48,7 +50,7 @@ test('appendArc: appending to a path produces a new path', (t) => {
48
50
  t.is(pts.length, 16)
49
51
 
50
52
  // test xaxisrotation
51
- obs = appendArc({ endpoint: [12, -22], radius: [15, -20], xaxisrotation: Math.PI / 2 }, p2)
53
+ obs = appendArc({ endpoint: [12, -22], radius: [15, -20], xaxisrotation: TAU / 4 }, p2)
52
54
  pts = toPoints(obs)
53
55
  exp = [
54
56
  [27, -22],
@@ -1,3 +1,4 @@
1
+ const { TAU } = require('../../maths/constants')
1
2
  const vec2 = require('../../maths/vec2')
2
3
  const vec3 = require('../../maths/vec2')
3
4
 
@@ -117,7 +118,7 @@ const appendBezier = (options, geometry) => {
117
118
 
118
119
  // subdivide each segment until the angle at each vertex becomes small enough:
119
120
  let subdivideBase = 1
120
- const maxangle = Math.PI * 2 / segments
121
+ const maxangle = TAU / segments
121
122
  const maxsinangle = Math.sin(maxangle)
122
123
  while (subdivideBase < newpoints.length - 1) {
123
124
  const dir1 = vec2.subtract(v0, newpoints[subdivideBase], newpoints[subdivideBase - 1])
@@ -10,7 +10,7 @@ const mat4 = require('../../maths/mat4')
10
10
  * @alias module:modeling/geometries/path2.transform
11
11
  *
12
12
  * @example
13
- * let newpath = transform(fromZRotation(Math.PI / 4), path)
13
+ * let newpath = transform(fromZRotation(TAU / 8), path)
14
14
  */
15
15
  const transform = (matrix, geometry) => {
16
16
  const transforms = mat4.multiply(mat4.create(), matrix, geometry.transforms)
package/src/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export * as booleans from './operations/booleans'
11
11
  export * as expansions from './operations/expansions'
12
12
  export * as extrusions from './operations/extrusions'
13
13
  export * as hulls from './operations/hulls'
14
+ export * as modifiers from './operations/modifiers'
14
15
  export * as transforms from './operations/transforms'
15
16
 
16
17
  export as namespace modeling
@@ -24,8 +24,18 @@ const NEPS = 1e-13
24
24
  // for comparing coplanar polygons, as provided by the sphere primitive at high
25
25
  // segmentation. NEPS is for 64 bit Number values.
26
26
 
27
+ /**
28
+ * The TAU property represents the ratio of the circumference of a circle to its radius.
29
+ * Approximately 6.28318530717958647692
30
+ * @default
31
+ * @example
32
+ * const { TAU } = require('@jscad/modeling').maths.constants
33
+ */
34
+ const TAU = Math.PI * 2
35
+
27
36
  module.exports = {
28
37
  EPS,
29
38
  NEPS,
39
+ TAU,
30
40
  spatialResolution
31
41
  }
@@ -17,7 +17,7 @@ const identity = require('./identity')
17
17
  * @returns {mat4} out
18
18
  * @alias module:modeling/maths/mat4.fromRotation
19
19
  * @example
20
- * let matrix = fromRotation(create(), Math.PI / 2, [0, 0, 3])
20
+ * let matrix = fromRotation(create(), TAU / 4, [0, 0, 3])
21
21
  */
22
22
  const fromRotation = (out, rad, axis) => {
23
23
  let [x, y, z] = axis
@@ -13,7 +13,7 @@ const { sin, cos } = require('../utils/trigonometry')
13
13
  * @returns {mat4} out
14
14
  * @alias module:modeling/maths/mat4.fromTaitBryanRotation
15
15
  * @example
16
- * let matrix = fromTaitBryanRotation(create(), Math.PI / 2, 0, Math.PI)
16
+ * let matrix = fromTaitBryanRotation(create(), TAU / 4, 0, TAU / 2)
17
17
  */
18
18
  const fromTaitBryanRotation = (out, yaw, pitch, roll) => {
19
19
  // precompute sines and cosines of Euler angles
@@ -12,7 +12,7 @@ const { sin, cos } = require('../utils/trigonometry')
12
12
  * @returns {mat4} out
13
13
  * @alias module:modeling/maths/mat4.fromXRotation
14
14
  * @example
15
- * let matrix = fromXRotation(create(), Math.PI / 2)
15
+ * let matrix = fromXRotation(create(), TAU / 4)
16
16
  */
17
17
  const fromXRotation = (out, radians) => {
18
18
  const s = sin(radians)
@@ -12,7 +12,7 @@ const { sin, cos } = require('../utils/trigonometry')
12
12
  * @returns {mat4} out
13
13
  * @alias module:modeling/maths/mat4.fromYRotation
14
14
  * @example
15
- * let matrix = fromYRotation(create(), Math.PI / 2)
15
+ * let matrix = fromYRotation(create(), TAU / 4)
16
16
  */
17
17
  const fromYRotation = (out, radians) => {
18
18
  const s = sin(radians)
@@ -12,7 +12,7 @@ const { sin, cos } = require('../utils/trigonometry')
12
12
  * @returns {mat4} out
13
13
  * @alias module:modeling/maths/mat4.fromZRotation
14
14
  * @example
15
- * let matrix = fromZRotation(create(), Math.PI / 2)
15
+ * let matrix = fromZRotation(create(), TAU / 4)
16
16
  */
17
17
  const fromZRotation = (out, radians) => {
18
18
  const s = sin(radians)
@@ -1,8 +1,11 @@
1
1
  const test = require('ava')
2
+
3
+ const { TAU } = require('../constants')
4
+ const vec3 = require('../vec3/index')
5
+
2
6
  const { create, invert, fromTranslation, fromXRotation } = require('./index')
3
7
 
4
8
  const { compareVectors } = require('../../../test/helpers/index')
5
- const vec3 = require('../vec3/index')
6
9
 
7
10
  test('mat4: invert() translate ', (t) => {
8
11
  const matrix = fromTranslation(create(), [10, 10, 0])
@@ -17,7 +20,7 @@ test('mat4: invert() translate ', (t) => {
17
20
  })
18
21
 
19
22
  test('mat4: invert() rotate ', (t) => {
20
- const matrix = fromXRotation(create(), Math.PI / 2)
23
+ const matrix = fromXRotation(create(), TAU / 4)
21
24
  const matrixInv = invert(create(), matrix)
22
25
 
23
26
  const vec1 = [10, 10, 10]
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  * Determine whether the given matrix is only translate and/or scale.
4
- * This code returns true for PI rotation as it can be interpreted as scale.
4
+ * This code returns true for TAU / 2 rotation as it can be interpreted as scale.
5
5
  *
6
6
  * @param {mat4} matrix - the matrix
7
7
  * @returns {Boolean} true if matrix is for translate and/or scale
@@ -1,9 +1,11 @@
1
1
  const test = require('ava')
2
2
 
3
+ const { TAU } = require('../constants')
4
+
3
5
  const { isOnlyTransformScale, create, fromTranslation, fromTaitBryanRotation, fromScaling, invert, multiply } = require('./index')
4
6
 
5
7
  test('mat4: isOnlyTransformScale() should return true for right angles', (t) => {
6
- let someRotation = fromTaitBryanRotation(create(), Math.PI, 0, 0)
8
+ let someRotation = fromTaitBryanRotation(create(), TAU / 2, 0, 0)
7
9
  t.true(isOnlyTransformScale(someRotation))
8
10
  t.true(isOnlyTransformScale(invert(create(), someRotation)))
9
11
 
@@ -2,15 +2,18 @@ const test = require('ava')
2
2
 
3
3
  const { compareVectors } = require('../../test/helpers/index')
4
4
 
5
- const { mat4, vec2, vec3 } = require('./index')
5
+ const { constants, mat4, vec2, vec3 } = require('./index')
6
6
 
7
7
  // ALL POSITIVE ROTATIONS ARE CLOCKWISE
8
8
  // see https://webglfundamentals.org/webgl/lessons/webgl-3d-orthographic.html
9
9
  // IN A LEFT-HANDED COORDINATE SYSTEM
10
10
 
11
+ // JSCAD IS RIGHT-HANDED COORDINATE SYSTEM
12
+ // WHERE POSITIVE ROTATIONS ARE COUNTER-CLOCKWISE
13
+
11
14
  // identity matrices for comparisons
12
15
 
13
- const rad90 = Math.PI / 2
16
+ const rad90 = constants.TAU / 4
14
17
 
15
18
  // +90 degree rotation about X
16
19
  const cwX90Matrix = [
@@ -6,28 +6,28 @@ const { NEPS } = require('../constants')
6
6
  const rezero = (n) => Math.abs(n) < NEPS ? 0 : n
7
7
 
8
8
  /**
9
- * Return Math.sin but accurate for 90 degree rotations.
9
+ * Return Math.sin but accurate for TAU / 4 rotations.
10
10
  * Fixes rounding errors when sin should be 0.
11
11
  *
12
12
  * @param {Number} radians - angle in radians
13
13
  * @returns {Number} sine of the given angle
14
14
  * @alias module:modeling/utils.sin
15
15
  * @example
16
- * sin(Math.PI) == 0
17
- * sin(2 * Math.PI) == 0
16
+ * sin(TAU / 2) == 0
17
+ * sin(TAU) == 0
18
18
  */
19
19
  const sin = (radians) => rezero(Math.sin(radians))
20
20
 
21
21
  /**
22
- * Return Math.cos but accurate for 90 degree rotations.
22
+ * Return Math.cos but accurate for TAU / 4 rotations.
23
23
  * Fixes rounding errors when cos should be 0.
24
24
  *
25
25
  * @param {Number} radians - angle in radians
26
26
  * @returns {Number} cosine of the given angle
27
27
  * @alias module:modeling/utils.cos
28
28
  * @example
29
- * cos(0.5 * Math.PI) == 0
30
- * cos(1.5 * Math.PI) == 0
29
+ * cos(TAU * 0.25) == 0
30
+ * cos(TAU * 0.75) == 0
31
31
  */
32
32
  const cos = (radians) => rezero(Math.cos(radians))
33
33
 
@@ -1,14 +1,16 @@
1
1
  const test = require('ava')
2
2
 
3
+ const { TAU } = require('../constants')
4
+
3
5
  const { cos, sin } = require('./trigonometry')
4
6
 
5
7
  test('utils: sin() should return rounded values', (t) => {
6
8
  t.is(sin(0), 0)
7
9
  t.is(sin(9), Math.sin(9))
8
- t.is(sin(0.5 * Math.PI), 1)
9
- t.is(sin(1.0 * Math.PI), 0)
10
- t.is(sin(1.5 * Math.PI), -1)
11
- t.is(sin(2.0 * Math.PI), 0)
10
+ t.is(sin(0.25 * TAU), 1)
11
+ t.is(sin(0.5 * TAU), 0)
12
+ t.is(sin(0.75 * TAU), -1)
13
+ t.is(sin(TAU), 0)
12
14
  t.is(sin(NaN), NaN)
13
15
  t.is(sin(Infinity), NaN)
14
16
  })
@@ -16,10 +18,10 @@ test('utils: sin() should return rounded values', (t) => {
16
18
  test('utils: cos() should return rounded values', (t) => {
17
19
  t.is(cos(0), 1)
18
20
  t.is(cos(9), Math.cos(9))
19
- t.is(cos(0.5 * Math.PI), 0)
20
- t.is(cos(1.0 * Math.PI), -1)
21
- t.is(cos(1.5 * Math.PI), 0)
22
- t.is(cos(2.0 * Math.PI), 1)
21
+ t.is(cos(0.25 * TAU), 0)
22
+ t.is(cos(0.5 * TAU), -1)
23
+ t.is(cos(0.75 * TAU), 0)
24
+ t.is(cos(TAU), 1)
23
25
  t.is(cos(NaN), NaN)
24
26
  t.is(cos(Infinity), NaN)
25
27
  })
@@ -8,6 +8,6 @@ const fromAngleRadians = require('./fromAngleRadians')
8
8
  * @returns {vec2} out
9
9
  * @alias module:modeling/maths/vec2.fromAngleDegrees
10
10
  */
11
- const fromAngleDegrees = (out, degrees) => fromAngleRadians(out, Math.PI * degrees / 180)
11
+ const fromAngleDegrees = (out, degrees) => fromAngleRadians(out, degrees * 0.017453292519943295)
12
12
 
13
13
  module.exports = fromAngleDegrees
@@ -1,4 +1,7 @@
1
1
  const test = require('ava')
2
+
3
+ const { TAU } = require('../constants')
4
+
2
5
  const { fromAngleRadians, create } = require('./index')
3
6
 
4
7
  const { compareVectors } = require('../../../test/helpers/index')
@@ -7,6 +10,6 @@ test('vec2: fromAngleRadians() should return a new vec2 with correct values', (t
7
10
  const obs1 = fromAngleRadians(create(), 0)
8
11
  t.true(compareVectors(obs1, [1.0, 0.0]))
9
12
 
10
- const obs2 = fromAngleRadians(obs1, Math.PI)
13
+ const obs2 = fromAngleRadians(obs1, TAU / 2)
11
14
  t.true(compareVectors(obs2, [-1, 1.2246468525851679e-16]))
12
15
  })
@@ -1,3 +1,5 @@
1
+ const { TAU } = require('../constants')
2
+
1
3
  const create = require('./create')
2
4
  const rotate = require('./rotate')
3
5
 
@@ -10,6 +12,6 @@ const rotate = require('./rotate')
10
12
  * @returns {vec2} out
11
13
  * @alias module:modeling/maths/vec2.normal
12
14
  */
13
- const normal = (out, vector) => rotate(out, vector, create(), (Math.PI / 2))
15
+ const normal = (out, vector) => rotate(out, vector, create(), (TAU / 4))
14
16
 
15
17
  module.exports = normal
@@ -1,10 +1,13 @@
1
1
  const test = require('ava')
2
+
3
+ const { TAU } = require('../constants')
4
+
2
5
  const { rotate, fromValues } = require('./index')
3
6
 
4
7
  const { compareVectors } = require('../../../test/helpers/index')
5
8
 
6
9
  test('vec2: rotate() called with three parameters should update a vec2 with correct values', (t) => {
7
- const radians = 90 * Math.PI / 180
10
+ const radians = TAU / 4
8
11
 
9
12
  const obs1 = fromValues(0, 0)
10
13
  const ret1 = rotate(obs1, [0, 0], [0, 0], 0)
@@ -1,10 +1,13 @@
1
1
  const test = require('ava')
2
+
3
+ const { TAU } = require('../constants')
4
+
2
5
  const { rotateX, fromValues } = require('./index')
3
6
 
4
7
  const { compareVectors } = require('../../../test/helpers/index')
5
8
 
6
9
  test('vec3: rotateX() called with four parameters should update a vec3 with correct values', (t) => {
7
- const radians = 90 * Math.PI / 180
10
+ const radians = TAU / 4
8
11
 
9
12
  const obs1 = fromValues(0, 0, 0)
10
13
  const ret1 = rotateX(obs1, [0, 0, 0], [0, 0, 0], 0)
@@ -1,10 +1,13 @@
1
1
  const test = require('ava')
2
+
3
+ const { TAU } = require('../constants')
4
+
2
5
  const { rotateY, fromValues } = require('./index')
3
6
 
4
7
  const { compareVectors } = require('../../../test/helpers/index')
5
8
 
6
9
  test('vec3: rotateY() called with three parameters should update a vec3 with correct values', (t) => {
7
- const radians = 90 * Math.PI / 180
10
+ const radians = TAU / 4
8
11
 
9
12
  const obs1 = fromValues(0, 0, 0)
10
13
  const ret1 = rotateY(obs1, [0, 0, 0], [0, 0, 0], 0)
@@ -1,10 +1,13 @@
1
1
  const test = require('ava')
2
+
3
+ const { TAU } = require('../constants')
4
+
2
5
  const { rotateZ, fromValues } = require('./index')
3
6
 
4
7
  const { compareVectors } = require('../../../test/helpers/index')
5
8
 
6
9
  test('vec3: rotateZ() called with four parameters should update a vec3 with correct values', (t) => {
7
- const radians = 90 * Math.PI / 180
10
+ const radians = TAU / 4
8
11
 
9
12
  const obs1 = fromValues(0, 0, 0)
10
13
  const ret1 = rotateZ(obs1, [0, 0, 0], [0, 0, 0], 0)
@@ -4,6 +4,10 @@ export { default as measureAggregateEpsilon } from './measureAggregateEpsilon'
4
4
  export { default as measureAggregateVolume } from './measureAggregateVolume'
5
5
  export { default as measureArea } from './measureArea'
6
6
  export { default as measureBoundingBox } from './measureBoundingBox'
7
+ export { default as measureBoundingSphere } from './measureBoundingSphere'
8
+ export { default as measureCenter } from './measureCenter'
9
+ export { default as measureCenterOfMass } from './measureCenterOfMass'
10
+ export { default as measureDimensions } from './measureDimensions'
7
11
  export { default as measureEpsilon } from './measureEpsilon'
8
12
  export { default as measureVolume } from './measureVolume'
9
13
 
@@ -0,0 +1,9 @@
1
+ import { Geometry } from '../geometries/types'
2
+ import RecursiveArray from '../utils/recursiveArray'
3
+
4
+ type Centroid = [number, number, number]
5
+
6
+ export default measureBoundingSphere
7
+
8
+ declare function measureBoundingSphere(geometry: Geometry): [Centroid, number]
9
+ declare function measureBoundingSphere(...geometries: RecursiveArray<Geometry>): [Centroid, number][]
@@ -0,0 +1,7 @@
1
+ import { Geometry } from '../geometries/types'
2
+ import RecursiveArray from '../utils/recursiveArray'
3
+
4
+ export default measureCenter
5
+
6
+ declare function measureCenter(geometry: Geometry): [number, number, number]
7
+ declare function measureCenter(...geometries: RecursiveArray<Geometry>): [number, number, number][]
@@ -0,0 +1,7 @@
1
+ import { Geometry } from '../geometries/types'
2
+ import RecursiveArray from '../utils/recursiveArray'
3
+
4
+ export default measureCenterOfMass
5
+
6
+ declare function measureCenterOfMass(geometry: Geometry): [number, number, number]
7
+ declare function measureCenterOfMass(...geometries: RecursiveArray<Geometry>): [number, number, number][]
@@ -0,0 +1,7 @@
1
+ import { Geometry } from '../geometries/types'
2
+ import RecursiveArray from '../utils/recursiveArray'
3
+
4
+ export default measureDimensions
5
+
6
+ declare function measureDimensions(geometry: Geometry): [number, number, number]
7
+ declare function measureDimensions(...geometries: RecursiveArray<Geometry>): [number, number, number][]
@@ -1,9 +1,11 @@
1
1
  const test = require('ava')
2
2
 
3
3
  const { comparePoints, nearlyEqual } = require('../../../test/helpers')
4
+
4
5
  const { geom2, geom3, path2 } = require('../../geometries')
5
6
  const measureBoundingBox = require('../../measurements/measureBoundingBox')
6
7
  const area = require('../../maths/utils/area')
8
+ const { TAU } = require('../../maths/constants')
7
9
  const sphere = require('../../primitives/sphere')
8
10
 
9
11
  const { expand } = require('./index')
@@ -51,7 +53,7 @@ test('expand: round-expanding a bent line produces expected geometry', (t) => {
51
53
  const expandedPoints = geom2.toPoints(expandedPathGeom2)
52
54
 
53
55
  t.notThrows(() => geom2.validate(expandedPathGeom2))
54
- const expectedArea = 56 + 2 * Math.PI * delta * 1.25 // shape will have 1 and 1/4 circles
56
+ const expectedArea = 56 + TAU * delta * 1.25 // shape will have 1 and 1/4 circles
55
57
  nearlyEqual(t, area(expandedPoints), expectedArea, 0.01, 'Measured area should be pretty close')
56
58
  const boundingBox = measureBoundingBox(expandedPathGeom2)
57
59
  t.true(comparePoints(boundingBox, [[-7, -2, 0], [2, 12, 0]]), 'Unexpected bounding box: ' + JSON.stringify(boundingBox))
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../../maths/constants')
1
+ const { EPS, TAU } = require('../../maths/constants')
2
2
 
3
3
  const mat4 = require('../../maths/mat4')
4
4
  const vec3 = require('../../maths/vec3')
@@ -120,7 +120,7 @@ const expandShell = (options, geometry) => {
120
120
 
121
121
  // first of all equally spaced around the cylinder:
122
122
  for (let i = 0; i < segments; i++) {
123
- addUniqueAngle(angles, (i * Math.PI * 2 / segments))
123
+ addUniqueAngle(angles, (i * TAU / segments))
124
124
  }
125
125
 
126
126
  // and also at every normal of all touching planes:
@@ -130,10 +130,10 @@ const expandShell = (options, geometry) => {
130
130
  const co = vec3.dot(xbase, planenormal)
131
131
  let angle = Math.atan2(si, co)
132
132
 
133
- if (angle < 0) angle += Math.PI * 2
133
+ if (angle < 0) angle += TAU
134
134
  addUniqueAngle(angles, angle)
135
135
  angle = Math.atan2(-si, -co)
136
- if (angle < 0) angle += Math.PI * 2
136
+ if (angle < 0) angle += TAU
137
137
  addUniqueAngle(angles, angle)
138
138
  }
139
139
 
@@ -1,4 +1,4 @@
1
- const { EPS } = require('../../maths/constants')
1
+ const { EPS, TAU } = require('../../maths/constants')
2
2
 
3
3
  const intersect = require('../../maths/utils/intersect')
4
4
  const line2 = require('../../maths/line2')
@@ -139,7 +139,7 @@ const offsetFromPoints = (options, points) => {
139
139
 
140
140
  if (rotation !== 0.0) {
141
141
  // generate the segments
142
- cornersegments = Math.floor(segments * (Math.abs(rotation) / (2 * Math.PI)))
142
+ cornersegments = Math.floor(segments * (Math.abs(rotation) / TAU))
143
143
  const step = rotation / cornersegments
144
144
  const start = vec2.angle(vec2.subtract(v0, corner.s0[1], corner.c))
145
145
  const cornerpoints = []
@@ -2,6 +2,7 @@ const test = require('ava')
2
2
 
3
3
  const comparePolygonsAsPoints = require('../../../test/helpers/comparePolygonsAsPoints')
4
4
 
5
+ const { TAU } = require('../../maths/constants')
5
6
  const mat4 = require('../../maths/mat4')
6
7
 
7
8
  const { geom2, geom3, poly3 } = require('../../geometries')
@@ -56,10 +57,10 @@ test('extrudeFromSlices (torus)', (t) => {
56
57
  hex = poly3.transform(mat4.fromTranslation(mat4.create(), [0, 20, 0]), hex)
57
58
  hex = slice.fromPoints(poly3.toPoints(hex))
58
59
 
59
- const angle = Math.PI / 4
60
+ const angle = TAU / 8
60
61
  const geometry3 = extrudeFromSlices(
61
62
  {
62
- numberOfSlices: Math.PI * 2 / angle,
63
+ numberOfSlices: TAU / angle,
63
64
  capStart: false,
64
65
  capEnd: false,
65
66
  close: true,
@@ -0,0 +1,14 @@
1
+ import { Geom2, Geom3 } from '../../geometries/types'
2
+
3
+ export default extrudeHelical
4
+
5
+ export interface ExtrudeHelicalOptions {
6
+ angle?: number
7
+ startAngle?: number
8
+ pitch?: number
9
+ height?: number
10
+ endOffset?: number
11
+ segmentsPerRotation?: number
12
+ }
13
+
14
+ declare function extrudeHelical(options: ExtrudeHelicalOptions, geometry: Geom2): Geom3