@jscad/modeling 2.11.1 → 2.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/jscad-modeling.min.js +338 -335
  3. package/package.json +2 -2
  4. package/src/curves/bezier/arcLengthToT.js +6 -6
  5. package/src/curves/bezier/arcLengthToT.test.js +25 -25
  6. package/src/curves/bezier/length.js +3 -5
  7. package/src/curves/bezier/length.test.js +2 -2
  8. package/src/curves/bezier/lengths.js +10 -10
  9. package/src/curves/bezier/lengths.test.js +3 -3
  10. package/src/geometries/geom2/transform.js +9 -1
  11. package/src/geometries/geom2/transform.test.js +58 -1
  12. package/src/geometries/poly2/arePointsInside.js +0 -7
  13. package/src/geometries/poly3/measureBoundingSphere.js +1 -2
  14. package/src/maths/plane/fromNoisyPoints.d.ts +6 -0
  15. package/src/maths/plane/fromNoisyPoints.js +106 -0
  16. package/src/maths/plane/fromNoisyPoints.test.js +24 -0
  17. package/src/maths/plane/index.d.ts +1 -0
  18. package/src/maths/plane/index.js +1 -0
  19. package/src/operations/booleans/trees/PolygonTreeNode.js +1 -1
  20. package/src/operations/expansions/expand.test.js +1 -1
  21. package/src/operations/extrusions/extrudeHelical.js +6 -7
  22. package/src/operations/extrusions/extrudeHelical.test.js +35 -37
  23. package/src/operations/extrusions/extrudeRotate.js +1 -1
  24. package/src/operations/extrusions/index.d.ts +1 -0
  25. package/src/operations/hulls/hullPoints2.js +3 -2
  26. package/src/operations/modifiers/index.js +1 -1
  27. package/src/operations/modifiers/retessellate.js +66 -27
  28. package/src/operations/transforms/mirror.test.js +9 -3
  29. package/src/primitives/circle.js +2 -2
  30. package/src/primitives/circle.test.js +7 -0
  31. package/src/primitives/cube.js +2 -2
  32. package/src/primitives/cube.test.js +7 -0
  33. package/src/primitives/cuboid.js +4 -1
  34. package/src/primitives/cuboid.test.js +7 -0
  35. package/src/primitives/cylinder.js +7 -2
  36. package/src/primitives/cylinder.test.js +14 -0
  37. package/src/primitives/ellipse.js +4 -1
  38. package/src/primitives/ellipse.test.js +7 -0
  39. package/src/primitives/ellipsoid.js +4 -1
  40. package/src/primitives/ellipsoid.test.js +7 -0
  41. package/src/primitives/geodesicSphere.js +5 -2
  42. package/src/primitives/geodesicSphere.test.js +7 -0
  43. package/src/primitives/polygon.d.ts +1 -0
  44. package/src/primitives/polygon.js +15 -4
  45. package/src/primitives/polygon.test.js +10 -0
  46. package/src/primitives/rectangle.js +4 -1
  47. package/src/primitives/rectangle.test.js +7 -0
  48. package/src/primitives/roundedCuboid.js +10 -3
  49. package/src/primitives/roundedCuboid.test.js +14 -0
  50. package/src/primitives/roundedCylinder.js +12 -5
  51. package/src/primitives/roundedCylinder.test.js +21 -0
  52. package/src/primitives/roundedRectangle.js +10 -3
  53. package/src/primitives/roundedRectangle.test.js +14 -0
  54. package/src/primitives/sphere.js +2 -2
  55. package/src/primitives/sphere.test.js +7 -0
  56. package/src/primitives/square.js +2 -2
  57. package/src/primitives/square.test.js +7 -0
@@ -8,7 +8,8 @@ const poly3 = require('../geometries/poly3')
8
8
 
9
9
  const { sin, cos } = require('../maths/utils/trigonometry')
10
10
 
11
- const { isGT, isGTE, isNumberArray } = require('./commonChecks')
11
+ const { isGTE, isNumberArray } = require('./commonChecks')
12
+ const cuboid = require('./cuboid')
12
13
 
13
14
  const createCorners = (center, size, radius, segments, slice, positive) => {
14
15
  const pitch = (TAU / 4) * slice / segments
@@ -135,10 +136,16 @@ const roundedCuboid = (options) => {
135
136
 
136
137
  if (!isNumberArray(center, 3)) throw new Error('center must be an array of X, Y and Z values')
137
138
  if (!isNumberArray(size, 3)) throw new Error('size must be an array of X, Y and Z values')
138
- if (!size.every((n) => n > 0)) throw new Error('size values must be greater than zero')
139
- if (!isGT(roundRadius, 0)) throw new Error('roundRadius must be greater than zero')
139
+ if (!size.every((n) => n >= 0)) throw new Error('size values must be positive')
140
+ if (!isGTE(roundRadius, 0)) throw new Error('roundRadius must be positive')
140
141
  if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
141
142
 
143
+ // if any size is zero return empty geometry
144
+ if (size[0] === 0 || size[1] === 0 || size[2] === 0) return geom3.create()
145
+
146
+ // if roundRadius is zero, return cuboid
147
+ if (roundRadius === 0) return cuboid({ center, size })
148
+
142
149
  size = size.map((v) => v / 2) // convert to radius
143
150
 
144
151
  if (roundRadius > (size[0] - EPS) ||
@@ -14,6 +14,20 @@ test('roundedCuboid (defaults)', (t) => {
14
14
  t.deepEqual(pts.length, 614)
15
15
  })
16
16
 
17
+ test('roundedCuboid (zero size)', (t) => {
18
+ const obs = roundedCuboid({ size: [1, 1, 0] })
19
+ const pts = geom3.toPoints(obs)
20
+ t.notThrows(() => geom3.validate(obs))
21
+ t.is(pts.length, 0)
22
+ })
23
+
24
+ test('roundedCuboid (zero radius)', (t) => {
25
+ const obs = roundedCuboid({ roundRadius: 0 })
26
+ const pts = geom3.toPoints(obs)
27
+ t.notThrows(() => geom3.validate(obs))
28
+ t.deepEqual(pts.length, 6)
29
+ })
30
+
17
31
  test('roundedCuboid (options)', (t) => {
18
32
  // test segments
19
33
  let obs = roundedCuboid({ segments: 8 })
@@ -7,7 +7,8 @@ const poly3 = require('../geometries/poly3')
7
7
 
8
8
  const { sin, cos } = require('../maths/utils/trigonometry')
9
9
 
10
- const { isGT, isGTE, isNumberArray } = require('./commonChecks')
10
+ const { isGTE, isNumberArray } = require('./commonChecks')
11
+ const cylinder = require('./cylinder')
11
12
 
12
13
  /**
13
14
  * Construct a Z axis-aligned solid cylinder in three dimensional space with rounded ends.
@@ -34,12 +35,18 @@ const roundedCylinder = (options) => {
34
35
  const { center, height, radius, roundRadius, segments } = Object.assign({}, defaults, options)
35
36
 
36
37
  if (!isNumberArray(center, 3)) throw new Error('center must be an array of X, Y and Z values')
37
- if (!isGT(height, 0)) throw new Error('height must be greater then zero')
38
- if (!isGT(radius, 0)) throw new Error('radius must be greater then zero')
39
- if (!isGT(roundRadius, 0)) throw new Error('roundRadius must be greater then zero')
40
- if (roundRadius > (radius - EPS)) throw new Error('roundRadius must be smaller then the radius')
38
+ if (!isGTE(height, 0)) throw new Error('height must be positive')
39
+ if (!isGTE(radius, 0)) throw new Error('radius must be positive')
40
+ if (!isGTE(roundRadius, 0)) throw new Error('roundRadius must be positive')
41
+ if (roundRadius > radius) throw new Error('roundRadius must be smaller then the radius')
41
42
  if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
42
43
 
44
+ // if size is zero return empty geometry
45
+ if (height === 0 || radius === 0) return geom3.create()
46
+
47
+ // if roundRadius is zero, return cylinder
48
+ if (roundRadius === 0) return cylinder({ center, height, radius })
49
+
43
50
  const start = [0, 0, -(height / 2)]
44
51
  const end = [0, 0, height / 2]
45
52
  const direction = vec3.subtract(vec3.create(), end, start)
@@ -14,6 +14,27 @@ test('roundedCylinder (defaults)', (t) => {
14
14
  t.is(pts.length, 544)
15
15
  })
16
16
 
17
+ test('roundedCylinder (zero height)', (t) => {
18
+ const obs = roundedCylinder({ height: 0 })
19
+ const pts = geom3.toPoints(obs)
20
+ t.notThrows(() => geom3.validate(obs))
21
+ t.is(pts.length, 0)
22
+ })
23
+
24
+ test('roundedCylinder (zero radius)', (t) => {
25
+ const obs = roundedCylinder({ radius: 0, roundRadius: 0 })
26
+ const pts = geom3.toPoints(obs)
27
+ t.notThrows(() => geom3.validate(obs))
28
+ t.is(pts.length, 0)
29
+ })
30
+
31
+ test('roundedCylinder (zero roundRadius)', (t) => {
32
+ const obs = roundedCylinder({ roundRadius: 0 })
33
+ const pts = geom3.toPoints(obs)
34
+ t.notThrows(() => geom3.validate(obs))
35
+ t.is(pts.length, 96)
36
+ })
37
+
17
38
  test('roundedCylinder (options)', (t) => {
18
39
  // test segments
19
40
  let obs = roundedCylinder({ segments: 5 })
@@ -4,7 +4,8 @@ const vec2 = require('../maths/vec2')
4
4
 
5
5
  const geom2 = require('../geometries/geom2')
6
6
 
7
- const { isGT, isGTE, isNumberArray } = require('./commonChecks')
7
+ const { isGTE, isNumberArray } = require('./commonChecks')
8
+ const rectangle = require('./rectangle')
8
9
 
9
10
  /**
10
11
  * Construct an axis-aligned rectangle in two dimensional space with rounded corners.
@@ -30,10 +31,16 @@ const roundedRectangle = (options) => {
30
31
 
31
32
  if (!isNumberArray(center, 2)) throw new Error('center must be an array of X and Y values')
32
33
  if (!isNumberArray(size, 2)) throw new Error('size must be an array of X and Y values')
33
- if (!size.every((n) => n > 0)) throw new Error('size values must be greater than zero')
34
- if (!isGT(roundRadius, 0)) throw new Error('roundRadius must be greater than zero')
34
+ if (!size.every((n) => n >= 0)) throw new Error('size values must be positive')
35
+ if (!isGTE(roundRadius, 0)) throw new Error('roundRadius must be positive')
35
36
  if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
36
37
 
38
+ // if any size is zero return empty geometry
39
+ if (size[0] === 0 || size[1] === 0) return geom2.create()
40
+
41
+ // if roundRadius is zero, return rectangle
42
+ if (roundRadius === 0) return rectangle({ center, size })
43
+
37
44
  size = size.map((v) => v / 2) // convert to radius
38
45
 
39
46
  if (roundRadius > (size[0] - EPS) ||
@@ -14,6 +14,20 @@ test('roundedRectangle (defaults)', (t) => {
14
14
  t.deepEqual(obs.length, 36)
15
15
  })
16
16
 
17
+ test('roundedRectangle (zero size)', (t) => {
18
+ const obs = roundedRectangle({ size: [1, 0] })
19
+ const pts = geom2.toPoints(obs)
20
+ t.notThrows(() => geom2.validate(obs))
21
+ t.is(pts.length, 0)
22
+ })
23
+
24
+ test('roundedRectangle (zero radius)', (t) => {
25
+ const obs = roundedRectangle({ roundRadius: 0 })
26
+ const pts = geom2.toPoints(obs)
27
+ t.notThrows(() => geom2.validate(obs))
28
+ t.deepEqual(pts.length, 4)
29
+ })
30
+
17
31
  test('roundedRectangle (options)', (t) => {
18
32
  // test center
19
33
  let geometry = roundedRectangle({ center: [4, 5], segments: 16 })
@@ -1,6 +1,6 @@
1
1
  const ellipsoid = require('./ellipsoid')
2
2
 
3
- const { isGT } = require('./commonChecks')
3
+ const { isGTE } = require('./commonChecks')
4
4
 
5
5
  /**
6
6
  * Construct a sphere in three dimensional space where all points are at the same distance from the center.
@@ -25,7 +25,7 @@ const sphere = (options) => {
25
25
  }
26
26
  let { center, radius, segments, axes } = Object.assign({}, defaults, options)
27
27
 
28
- if (!isGT(radius, 0)) throw new Error('radius must be greater than zero')
28
+ if (!isGTE(radius, 0)) throw new Error('radius must be positive')
29
29
 
30
30
  radius = [radius, radius, radius]
31
31
 
@@ -163,3 +163,10 @@ test('sphere (options)', (t) => {
163
163
  t.is(pts.length, 32)
164
164
  t.true(comparePolygonsAsPoints(pts, exp))
165
165
  })
166
+
167
+ test('sphere (zero radius)', (t) => {
168
+ const obs = sphere({ radius: 0 })
169
+ const pts = geom3.toPoints(obs)
170
+ t.notThrows(() => geom3.validate(obs))
171
+ t.is(pts.length, 0)
172
+ })
@@ -1,6 +1,6 @@
1
1
  const rectangle = require('./rectangle')
2
2
 
3
- const { isGT } = require('./commonChecks')
3
+ const { isGTE } = require('./commonChecks')
4
4
 
5
5
  /**
6
6
  * Construct an axis-aligned square in two dimensional space with four equal sides at right angles.
@@ -21,7 +21,7 @@ const square = (options) => {
21
21
  }
22
22
  let { center, size } = Object.assign({}, defaults, options)
23
23
 
24
- if (!isGT(size, 0)) throw new Error('size must be greater than zero')
24
+ if (!isGTE(size, 0)) throw new Error('size must be positive')
25
25
 
26
26
  size = [size, size]
27
27
 
@@ -42,3 +42,10 @@ test('square (options)', (t) => {
42
42
  t.is(pts.length, 4)
43
43
  t.true(comparePoints(pts, exp))
44
44
  })
45
+
46
+ test('square (zero size)', (t) => {
47
+ const geometry = square({ size: 0 })
48
+ const obs = geom2.toPoints(geometry)
49
+ t.notThrows(() => geom2.validate(geometry))
50
+ t.is(obs.length, 0)
51
+ })