@jscad/modeling 3.0.0-alpha.0 → 3.0.2-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.
- package/CHANGELOG.md +49 -0
- package/LICENSE +1 -1
- package/dist/jscad-modeling.es.js +2 -2
- package/dist/jscad-modeling.min.js +2 -2
- package/package.json +2 -2
- package/rollup.config.js +1 -1
- package/src/colors/colorize.js +1 -5
- package/src/colors/colorize.test.js +8 -8
- package/src/geometries/geom2/transform.js +9 -1
- package/src/geometries/geom2/transform.test.js +57 -0
- package/src/geometries/geom3/fromPointsConvex.d.ts +4 -0
- package/src/geometries/geom3/fromPointsConvex.js +25 -0
- package/src/geometries/geom3/fromPointsConvex.test.js +32 -0
- package/src/geometries/geom3/index.d.ts +1 -0
- package/src/geometries/geom3/index.js +1 -0
- package/src/geometries/index.js +3 -4
- package/src/geometries/path2/appendBezier.js +1 -1
- package/src/geometries/poly3/index.js +1 -1
- package/src/geometries/poly3/measureBoundingBox.js +2 -0
- package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
- package/src/geometries/poly3/measureBoundingSphere.js +25 -8
- package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
- package/src/geometries/poly3/type.d.ts +1 -1
- package/src/geometries/slice/validate.js +1 -2
- package/src/index.js +41 -0
- package/src/maths/index.js +1 -0
- package/src/maths/mat4/isOnlyTransformScale.js +1 -1
- package/src/measurements/measureAggregateArea.js +0 -1
- package/src/measurements/measureAggregateBoundingBox.js +0 -1
- package/src/measurements/measureAggregateEpsilon.js +0 -1
- package/src/measurements/measureAggregateVolume.js +0 -1
- package/src/measurements/measureArea.js +0 -1
- package/src/measurements/measureBoundingBox.js +0 -1
- package/src/measurements/measureBoundingSphere.js +2 -6
- package/src/measurements/measureEpsilon.js +0 -1
- package/src/measurements/measureVolume.js +0 -1
- package/src/operations/booleans/index.d.ts +1 -0
- package/src/operations/booleans/intersect.js +5 -5
- package/src/operations/booleans/intersect.test.js +6 -7
- package/src/operations/booleans/intersectGeom2.js +2 -6
- package/src/operations/booleans/intersectGeom2.test.js +25 -1
- package/src/operations/booleans/intersectGeom3.js +2 -6
- package/src/operations/booleans/intersectGeom3.test.js +5 -1
- package/src/operations/booleans/martinez/compareEvents.js +2 -7
- package/src/operations/booleans/martinez/connectEdges.js +30 -41
- package/src/operations/booleans/martinez/contour.js +1 -1
- package/src/operations/booleans/martinez/divideSegment.js +12 -11
- package/src/operations/booleans/martinez/fillQueue.js +24 -28
- package/src/operations/booleans/martinez/index.js +2 -1
- package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
- package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
- package/src/operations/booleans/martinez/splaytree.js +59 -457
- package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
- package/src/operations/booleans/martinez/sweepEvent.js +3 -17
- package/src/operations/booleans/mayOverlap.js +0 -1
- package/src/operations/booleans/scission.d.ts +5 -0
- package/src/operations/booleans/scission.js +3 -5
- package/src/operations/booleans/scission.test.js +6 -0
- package/src/operations/booleans/subtract.js +5 -5
- package/src/operations/booleans/subtract.test.js +6 -7
- package/src/operations/booleans/subtractGeom2.js +2 -6
- package/src/operations/booleans/subtractGeom2.test.js +25 -1
- package/src/operations/booleans/subtractGeom3.js +2 -6
- package/src/operations/booleans/subtractGeom3.test.js +5 -1
- package/src/operations/booleans/trees/Node.js +25 -27
- package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
- package/src/operations/booleans/trees/Tree.js +9 -4
- package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
- package/src/operations/booleans/trees/splitPolygonByPlane.d.ts +33 -0
- package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
- package/src/operations/booleans/union.js +5 -5
- package/src/operations/booleans/union.test.js +6 -7
- package/src/operations/booleans/unionGeom2.js +2 -6
- package/src/operations/booleans/unionGeom2.test.js +25 -1
- package/src/operations/booleans/unionGeom3.js +2 -6
- package/src/operations/booleans/unionGeom3.test.js +6 -1
- package/src/operations/extrusions/extrudeFromSlices.test.js +8 -1
- package/src/operations/extrusions/extrudeHelical.js +2 -8
- package/src/operations/extrusions/extrudeLinear.js +1 -5
- package/src/operations/extrusions/extrudeLinear.test.js +7 -1
- package/src/operations/extrusions/extrudeRotate.js +3 -2
- package/src/operations/extrusions/extrudeRotate.test.js +13 -1
- package/src/operations/extrusions/extrudeWalls.js +3 -1
- package/src/operations/extrusions/project.js +1 -5
- package/src/operations/hulls/hull.js +6 -5
- package/src/operations/hulls/hull.test.js +56 -3
- package/src/operations/hulls/hullChain.js +11 -6
- package/src/operations/hulls/hullChain.test.js +12 -2
- package/src/operations/hulls/hullGeom2.js +5 -6
- package/src/operations/hulls/hullGeom3.js +9 -18
- package/src/operations/hulls/hullPath2.js +6 -7
- package/src/operations/hulls/hullPath2.test.js +1 -1
- package/src/operations/hulls/hullPoints2.d.ts +3 -0
- package/src/operations/hulls/hullPoints2.js +24 -30
- package/src/operations/hulls/hullPoints3.d.ts +4 -0
- package/src/operations/hulls/hullPoints3.js +21 -0
- package/src/operations/hulls/index.d.ts +2 -0
- package/src/operations/hulls/index.js +3 -1
- package/src/operations/modifiers/generalize.js +2 -6
- package/src/operations/modifiers/index.js +1 -1
- package/src/operations/modifiers/mergePolygons.js +2 -3
- package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
- package/src/operations/modifiers/snap.js +2 -6
- package/src/operations/offsets/offset.js +1 -5
- package/src/operations/offsets/offsetFromPoints.test.js +0 -1
- package/src/operations/offsets/offsetGeom2.test.js +1 -0
- package/src/operations/offsets/offsetGeom3.js +0 -2
- package/src/operations/offsets/offsetGeom3.test.js +9 -1
- package/src/operations/offsets/offsetPath2.js +3 -3
- package/src/operations/transforms/align.js +8 -7
- package/src/operations/transforms/align.test.js +2 -2
- package/src/operations/transforms/center.js +6 -9
- package/src/operations/transforms/center.test.js +19 -1
- package/src/operations/transforms/mirror.js +5 -8
- package/src/operations/transforms/mirror.test.js +7 -7
- package/src/operations/transforms/rotate.js +5 -8
- package/src/operations/transforms/scale.js +5 -8
- package/src/operations/transforms/transform.js +2 -5
- package/src/operations/transforms/translate.js +5 -8
- package/src/primitives/arc.js +2 -0
- package/src/primitives/arc.test.js +11 -11
- package/src/primitives/circle.test.js +18 -8
- package/src/primitives/cube.test.js +10 -0
- package/src/primitives/cuboid.test.js +10 -0
- package/src/primitives/cylinder.test.js +12 -0
- package/src/primitives/cylinderElliptic.test.js +21 -1
- package/src/primitives/ellipse.test.js +18 -8
- package/src/primitives/ellipsoid.test.js +12 -0
- package/src/primitives/geodesicSphere.test.js +8 -0
- package/src/primitives/line.test.js +1 -1
- package/src/primitives/polygon.d.ts +1 -0
- package/src/primitives/polygon.js +13 -4
- package/src/primitives/polygon.test.js +15 -0
- package/src/primitives/polyhedron.js +1 -0
- package/src/primitives/polyhedron.test.js +8 -2
- package/src/primitives/rectangle.test.js +9 -3
- package/src/primitives/roundedCuboid.js +1 -1
- package/src/primitives/roundedCuboid.test.js +20 -4
- package/src/primitives/roundedCylinder.js +1 -1
- package/src/primitives/roundedCylinder.test.js +20 -0
- package/src/primitives/roundedRectangle.js +1 -1
- package/src/primitives/roundedRectangle.test.js +15 -6
- package/src/primitives/sphere.test.js +12 -0
- package/src/primitives/square.test.js +10 -4
- package/src/primitives/star.test.js +14 -6
- package/src/primitives/torus.js +1 -1
- package/src/primitives/torus.test.js +11 -1
- package/src/primitives/triangle.test.js +17 -9
- package/src/utils/coalesce.d.ts +3 -0
- package/src/utils/coalesce.js +20 -0
- package/src/utils/index.js +2 -2
- package/src/maths/mat4/leftMultiplyVec2.d.ts +0 -4
- package/src/maths/mat4/leftMultiplyVec2.js +0 -26
- package/src/maths/mat4/leftMultiplyVec3.d.ts +0 -4
- package/src/maths/mat4/leftMultiplyVec3.js +0 -27
- package/src/maths/mat4/mirror.d.ts +0 -4
- package/src/maths/mat4/mirror.js +0 -32
- package/src/maths/mat4/rightMultiplyVec2.d.ts +0 -4
- package/src/maths/mat4/rightMultiplyVec2.js +0 -27
- package/src/maths/mat4/rightMultiplyVec3.d.ts +0 -4
- package/src/maths/mat4/rightMultiplyVec3.js +0 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/modeling",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2-alpha.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",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"rollup": "^2.79.1",
|
|
65
65
|
"rollup-plugin-banner": "^0.2.1"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "ac80d1a7cb0a8efb21aff9193d4a8bccb6e31f1c"
|
|
68
68
|
}
|
package/rollup.config.js
CHANGED
|
@@ -16,6 +16,6 @@ export default {
|
|
|
16
16
|
],
|
|
17
17
|
plugins: [
|
|
18
18
|
banner('<%= pkg.description %>\n@module <%= pkg.name %>\n@version <%= pkg.version %>\n@license <%= pkg.license %>'),
|
|
19
|
-
terser({ compress: { module: true }, mangle: false, format: { comments: 'some'} })
|
|
19
|
+
terser({ compress: { module: true }, mangle: false, format: { comments: 'some' } })
|
|
20
20
|
]
|
|
21
21
|
}
|
package/src/colors/colorize.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { flatten } from '../utils/flatten.js'
|
|
2
|
-
|
|
3
1
|
import * as geom2 from '../geometries/geom2/index.js'
|
|
4
2
|
import * as geom3 from '../geometries/geom3/index.js'
|
|
5
3
|
import * as path2 from '../geometries/path2/index.js'
|
|
@@ -47,14 +45,12 @@ export const colorize = (color, ...objects) => {
|
|
|
47
45
|
if (color.length < 3) throw new Error('color must contain R, G and B values')
|
|
48
46
|
if (color.length === 3) color = [color[0], color[1], color[2], 1.0] // add alpha
|
|
49
47
|
|
|
50
|
-
objects = flatten(objects)
|
|
51
|
-
if (objects.length === 0) throw new Error('wrong number of arguments')
|
|
52
|
-
|
|
53
48
|
const results = objects.map((object) => {
|
|
54
49
|
if (geom2.isA(object)) return colorGeom2(color, object)
|
|
55
50
|
if (geom3.isA(object)) return colorGeom3(color, object)
|
|
56
51
|
if (path2.isA(object)) return colorPath2(color, object)
|
|
57
52
|
if (poly3.isA(object)) return colorPoly3(color, object)
|
|
53
|
+
if (Array.isArray(object)) return colorize(color, ...object)
|
|
58
54
|
|
|
59
55
|
object.color = color
|
|
60
56
|
return object
|
|
@@ -11,14 +11,12 @@ test('color (rgb on objects)', (t) => {
|
|
|
11
11
|
const obs = colorize([1, 0, 0], obj1, obj2)
|
|
12
12
|
const exp1 = { color: [1, 0, 0, 1] }
|
|
13
13
|
const exp2 = { id: 'a', color: [1, 0, 0, 1] }
|
|
14
|
+
const exp3 = { id: 'b', color: [1, 0, 0, 1] }
|
|
14
15
|
|
|
15
|
-
t.is(obs.length,
|
|
16
|
+
t.is(obs.length, 2)
|
|
16
17
|
t.deepEqual(obs[0], exp1)
|
|
17
|
-
t.deepEqual(obs[1], exp2)
|
|
18
|
-
|
|
19
|
-
const obs3 = colorize([1, 0, 0], obj1)
|
|
20
|
-
const exp3 = { color: [1, 0, 0, 1] }
|
|
21
|
-
t.deepEqual(obs3, exp3)
|
|
18
|
+
t.deepEqual(obs[1][0], exp2)
|
|
19
|
+
t.deepEqual(obs[1][1], exp3)
|
|
22
20
|
})
|
|
23
21
|
|
|
24
22
|
test('color (rgba on objects)', (t) => {
|
|
@@ -28,10 +26,12 @@ test('color (rgba on objects)', (t) => {
|
|
|
28
26
|
const obs = colorize([1, 1, 0.5, 0.8], obj1, obj2)
|
|
29
27
|
const exp1 = { color: [1, 1, 0.5, 0.8] }
|
|
30
28
|
const exp2 = { id: 'a', color: [1, 1, 0.5, 0.8] }
|
|
29
|
+
const exp3 = { id: 'b', color: [1, 1, 0.5, 0.8] }
|
|
31
30
|
|
|
32
|
-
t.is(obs.length,
|
|
31
|
+
t.is(obs.length, 2)
|
|
33
32
|
t.deepEqual(obs[0], exp1)
|
|
34
|
-
t.deepEqual(obs[1], exp2)
|
|
33
|
+
t.deepEqual(obs[1][0], exp2)
|
|
34
|
+
t.deepEqual(obs[1][1], exp3)
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
test('color (rgba on geometry)', (t) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as mat4 from '../../maths/mat4/index.js'
|
|
2
2
|
|
|
3
|
+
import { reverse } from './reverse.js'
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Transform the given geometry using the given matrix.
|
|
5
7
|
* This is a lazy transform of the outlines, as this function only adjusts the transforms.
|
|
@@ -14,5 +16,11 @@ import * as mat4 from '../../maths/mat4/index.js'
|
|
|
14
16
|
*/
|
|
15
17
|
export const transform = (matrix, geometry) => {
|
|
16
18
|
const transforms = mat4.multiply(mat4.create(), matrix, geometry.transforms)
|
|
17
|
-
|
|
19
|
+
const transformed = Object.assign({}, geometry, { transforms })
|
|
20
|
+
// determine if the transform is mirroring in 2D
|
|
21
|
+
if (matrix[0] * matrix[5] - matrix[4] * matrix[1] < 0) {
|
|
22
|
+
// reverse the order to preserve the orientation
|
|
23
|
+
return reverse(transformed)
|
|
24
|
+
}
|
|
25
|
+
return transformed
|
|
18
26
|
}
|
|
@@ -2,6 +2,12 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { mat4 } from '../../maths/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea } from '../../measurements/index.js'
|
|
6
|
+
|
|
7
|
+
import { mirrorX, mirrorY, mirrorZ } from '../../operations/transforms/index.js'
|
|
8
|
+
|
|
9
|
+
import { square } from '../../primitives/index.js'
|
|
10
|
+
|
|
5
11
|
import { create, transform, toOutlines, toSides } from './index.js'
|
|
6
12
|
|
|
7
13
|
import { comparePoints, compareVectors } from '../../../test/helpers/index.js'
|
|
@@ -50,3 +56,54 @@ test('transform: adjusts the transforms of geom2', (t) => {
|
|
|
50
56
|
t.true(comparePoints(another.outlines[0], expected.outlines[0]))
|
|
51
57
|
t.true(compareVectors(another.transforms, expected.transforms))
|
|
52
58
|
})
|
|
59
|
+
|
|
60
|
+
test('transform: geom2 mirrorX', (t) => {
|
|
61
|
+
const geometry = square()
|
|
62
|
+
const transformed = mirrorX(geometry)
|
|
63
|
+
t.is(measureArea(geometry), 4)
|
|
64
|
+
// area will be negative unless we reversed the points
|
|
65
|
+
t.is(measureArea(transformed), 4)
|
|
66
|
+
const pts = toOutlines(transformed)[0]
|
|
67
|
+
const exp = [[1, 1], [-1, 1], [-1, -1], [1, -1]]
|
|
68
|
+
t.true(comparePoints(pts, exp))
|
|
69
|
+
t.deepEqual(toSides(transformed), [
|
|
70
|
+
[[1, 1], [-1, 1]],
|
|
71
|
+
[[-1, 1], [-1, -1]],
|
|
72
|
+
[[-1, -1], [1, -1]],
|
|
73
|
+
[[1, -1], [1, 1]]
|
|
74
|
+
])
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('transform: geom2 mirrorY', (t) => {
|
|
78
|
+
const geometry = square()
|
|
79
|
+
const transformed = mirrorY(geometry)
|
|
80
|
+
t.is(measureArea(geometry), 4)
|
|
81
|
+
// area will be negative unless we reversed the points
|
|
82
|
+
t.is(measureArea(transformed), 4)
|
|
83
|
+
const pts = toOutlines(transformed)[0]
|
|
84
|
+
const exp = [[-1, -1], [1, -1], [1, 1], [-1, 1]]
|
|
85
|
+
t.true(comparePoints(pts, exp))
|
|
86
|
+
t.deepEqual(toSides(transformed), [
|
|
87
|
+
[[-1, -1], [1, -1]],
|
|
88
|
+
[[1, -1], [1, 1]],
|
|
89
|
+
[[1, 1], [-1, 1]],
|
|
90
|
+
[[-1, 1], [-1, -1]]
|
|
91
|
+
])
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('transform: geom2 mirrorZ', (t) => {
|
|
95
|
+
const geometry = square()
|
|
96
|
+
const transformed = mirrorZ(geometry)
|
|
97
|
+
t.is(measureArea(geometry), 4)
|
|
98
|
+
// area will be negative unless we DIDN'T reverse the points
|
|
99
|
+
t.is(measureArea(transformed), 4)
|
|
100
|
+
const pts = toOutlines(transformed)[0]
|
|
101
|
+
const exp = [[-1, -1], [1, -1], [1, 1], [-1, 1]]
|
|
102
|
+
t.true(comparePoints(pts, exp))
|
|
103
|
+
t.deepEqual(toSides(transformed), [
|
|
104
|
+
[[-1, -1], [1, -1]],
|
|
105
|
+
[[1, -1], [1, 1]],
|
|
106
|
+
[[1, 1], [-1, 1]],
|
|
107
|
+
[[-1, 1], [-1, -1]]
|
|
108
|
+
])
|
|
109
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { runner } from '../../operations/hulls/quickhull/index.js'
|
|
2
|
+
import { create } from './create.js'
|
|
3
|
+
import * as poly3 from '../poly3/index.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Construct a new convex 3D geometry from a list of unique points.
|
|
7
|
+
*
|
|
8
|
+
* @param {Array} uniquePoints - list of points to construct convex 3D geometry
|
|
9
|
+
* @returns {geom3} a new geometry
|
|
10
|
+
* @alias module:modeling/geometries/geom3.fromPointsConvex
|
|
11
|
+
*/
|
|
12
|
+
export const fromPointsConvex = (uniquePoints) => {
|
|
13
|
+
if (!Array.isArray(uniquePoints)) {
|
|
14
|
+
throw new Error('the given points must be an array')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const faces = runner(uniquePoints, { skipTriangulation: true })
|
|
18
|
+
|
|
19
|
+
const polygons = faces.map((face) => {
|
|
20
|
+
const vertices = face.map((index) => uniquePoints[index])
|
|
21
|
+
return poly3.create(vertices)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
return create(polygons)
|
|
25
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import test from 'ava'
|
|
2
|
+
|
|
3
|
+
import { fromPointsConvex, validate } from './index.js'
|
|
4
|
+
|
|
5
|
+
test('fromPointsConvex (uniquePoints)', (t) => {
|
|
6
|
+
const out = []
|
|
7
|
+
for (let x = -9; x <= 9; ++x) {
|
|
8
|
+
for (let y = -9; y <= 9; ++y) {
|
|
9
|
+
for (let z = -9; z <= 9; ++z) {
|
|
10
|
+
if (x * x + y * y + z * z <= 96) {
|
|
11
|
+
out.push([x, y, z])
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const obs = fromPointsConvex(out)
|
|
18
|
+
validate(obs)
|
|
19
|
+
t.is(obs.polygons.length, 170)
|
|
20
|
+
t.true(obs.polygons.every((f) => ([3, 4, 8, 9].indexOf(f.vertices.length) !== -1)))
|
|
21
|
+
|
|
22
|
+
const c = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
23
|
+
obs.polygons.forEach((f) => c[f.vertices.length]++)
|
|
24
|
+
t.is(c[3], 120)
|
|
25
|
+
t.is(c[4], 24)
|
|
26
|
+
t.is(c[8], 18)
|
|
27
|
+
t.is(c[9], 8)
|
|
28
|
+
|
|
29
|
+
let edges2 = 336 * 2
|
|
30
|
+
obs.polygons.forEach((f) => { edges2 -= f.vertices.length })
|
|
31
|
+
t.is(edges2, 0)
|
|
32
|
+
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { clone } from './clone.js'
|
|
2
2
|
export { create } from './create.js'
|
|
3
3
|
export { fromPoints } from './fromPoints.js'
|
|
4
|
+
export { fromPointsConvex } from './fromPointsConvex.js'
|
|
4
5
|
export { fromCompactBinary } from './fromCompactBinary.js'
|
|
5
6
|
export { invert } from './invert.js'
|
|
6
7
|
export { isA } from './isA.js'
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
export { clone } from './clone.js'
|
|
18
18
|
export { create } from './create.js'
|
|
19
19
|
export { fromPoints } from './fromPoints.js'
|
|
20
|
+
export { fromPointsConvex } from './fromPointsConvex.js'
|
|
20
21
|
export { fromCompactBinary } from './fromCompactBinary.js'
|
|
21
22
|
export { invert } from './invert.js'
|
|
22
23
|
export { isA } from './isA.js'
|
package/src/geometries/index.js
CHANGED
|
@@ -5,14 +5,13 @@
|
|
|
5
5
|
* @see {@link geom2} - 2D geometry consisting of 2D outlines
|
|
6
6
|
* @see {@link geom3} - 3D geometry consisting of polygons
|
|
7
7
|
* @see {@link path2} - 2D geometry consisting of ordered points
|
|
8
|
-
* @see {@link poly2} - 2D polygon consisting of ordered
|
|
8
|
+
* @see {@link poly2} - 2D polygon consisting of ordered points
|
|
9
9
|
* @see {@link poly3} - 3D polygon consisting of ordered vertices
|
|
10
|
-
* @see {@link slice} - 3D geometry consisting of 3D
|
|
10
|
+
* @see {@link slice} - 3D geometry consisting of 3D contours
|
|
11
11
|
*
|
|
12
12
|
* @module modeling/geometries
|
|
13
13
|
* @example
|
|
14
|
-
* import {
|
|
15
|
-
* const { geom2, geom3, path2, poly2, poly3 } = geometries
|
|
14
|
+
* import { geom2, geom3, path2, poly2, poly3, slice } from '@jscad/modeling'
|
|
16
15
|
*/
|
|
17
16
|
export * as geom2 from './geom2/index.js'
|
|
18
17
|
export * as geom3 from './geom3/index.js'
|
|
@@ -14,7 +14,7 @@ import { toPoints } from './toPoints.js'
|
|
|
14
14
|
* In other words, the trailing gradient of the geometry matches the new gradient of the curve.
|
|
15
15
|
* @param {object} options - options for construction
|
|
16
16
|
* @param {Array} options.controlPoints - list of control points (2D) for the Bézier curve
|
|
17
|
-
* @param {number} [options.
|
|
17
|
+
* @param {number} [options.segments=16] - number of segments per 360 rotation
|
|
18
18
|
* @param {Path2} geometry - the path of which to append points
|
|
19
19
|
* @returns {Path2} a new path with the appended points
|
|
20
20
|
* @alias module:modeling/geometries/path2.appendBezier
|
|
@@ -15,7 +15,7 @@ export { isA } from './isA.js'
|
|
|
15
15
|
export { isConvex } from './isConvex.js'
|
|
16
16
|
export { measureArea } from './measureArea.js'
|
|
17
17
|
export { measureBoundingBox } from './measureBoundingBox.js'
|
|
18
|
-
export { measureBoundingSphere } from './measureBoundingSphere.js'
|
|
18
|
+
export { measureBoundingSphere, measureBoundingSphereAndCache } from './measureBoundingSphere.js'
|
|
19
19
|
export { measureSignedVolume } from './measureSignedVolume.js'
|
|
20
20
|
export { plane } from './plane.js'
|
|
21
21
|
export { toVertices } from './toVertices.js'
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as vec3 from '../../maths/vec3/index.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
+
* Measure the bounding box of the given polygon.
|
|
5
|
+
*
|
|
4
6
|
* @param {Poly3} polygon - the polygon to measure
|
|
5
7
|
* @returns {Array} an array of two vectors (3D); minimum and maximum coordinates
|
|
6
8
|
* @alias module:modeling/geometries/poly3.measureBoundingBox
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Poly3 } from './type.d.ts'
|
|
2
2
|
import type { Vec4 } from '../../maths/vec4/type.d.ts'
|
|
3
3
|
|
|
4
|
-
export function measureBoundingSphere(polygon: Poly3): Vec4
|
|
4
|
+
export function measureBoundingSphere(out: Vec4, polygon: Poly3): Vec4
|
|
5
|
+
export function measureBoundingSphereAndCache(polygon: Poly3): Vec4
|
|
@@ -4,16 +4,14 @@ const cache = new WeakMap()
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Measure the bounding sphere of the given polygon.
|
|
7
|
+
*
|
|
8
|
+
* @param {Vec4} out - receiving vector
|
|
7
9
|
* @param {Poly3} polygon - the polygon to measure
|
|
8
10
|
* @returns {Vec4} the computed bounding sphere; center vertex (3D) and radius
|
|
9
11
|
* @alias module:modeling/geometries/poly3.measureBoundingSphere
|
|
10
12
|
*/
|
|
11
|
-
export const measureBoundingSphere = (polygon) => {
|
|
12
|
-
const boundingSphere = cache.get(polygon)
|
|
13
|
-
if (boundingSphere) return boundingSphere
|
|
14
|
-
|
|
13
|
+
export const measureBoundingSphere = (out, polygon) => {
|
|
15
14
|
const vertices = polygon.vertices
|
|
16
|
-
const out = vec4.create()
|
|
17
15
|
|
|
18
16
|
if (vertices.length === 0) {
|
|
19
17
|
out[0] = 0
|
|
@@ -31,14 +29,15 @@ export const measureBoundingSphere = (polygon) => {
|
|
|
31
29
|
let maxy = minx
|
|
32
30
|
let maxz = minx
|
|
33
31
|
|
|
34
|
-
vertices.
|
|
32
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
33
|
+
const v = vertices[i]
|
|
35
34
|
if (minx[0] > v[0]) minx = v
|
|
36
35
|
if (miny[1] > v[1]) miny = v
|
|
37
36
|
if (minz[2] > v[2]) minz = v
|
|
38
37
|
if (maxx[0] < v[0]) maxx = v
|
|
39
38
|
if (maxy[1] < v[1]) maxy = v
|
|
40
39
|
if (maxz[2] < v[2]) maxz = v
|
|
41
|
-
}
|
|
40
|
+
}
|
|
42
41
|
|
|
43
42
|
out[0] = (minx[0] + maxx[0]) * 0.5 // center of sphere
|
|
44
43
|
out[1] = (miny[1] + maxy[1]) * 0.5
|
|
@@ -48,7 +47,25 @@ export const measureBoundingSphere = (polygon) => {
|
|
|
48
47
|
const z = out[2] - maxz[2]
|
|
49
48
|
out[3] = Math.sqrt(x * x + y * y + z * z) // radius of sphere
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
return out
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Measure the bounding sphere of the given polygon.
|
|
55
|
+
*
|
|
56
|
+
* This version maintains a cache, retrievning previously calculated bounds if found.
|
|
57
|
+
*
|
|
58
|
+
* @param {Poly3} polygon - the polygon to measure
|
|
59
|
+
* @returns {Vec4} the computed bounding sphere; center vertex (3D) and radius
|
|
60
|
+
* @alias module:modeling/geometries/poly3.measureBoundingSphere
|
|
61
|
+
*/
|
|
62
|
+
export const measureBoundingSphereAndCache = (polygon) => {
|
|
63
|
+
const boundingSphere = cache.get(polygon)
|
|
64
|
+
if (boundingSphere) return boundingSphere
|
|
52
65
|
|
|
66
|
+
const out = [0, 0, 0, 0]
|
|
67
|
+
measureBoundingSphere(out, polygon)
|
|
68
|
+
|
|
69
|
+
cache.set(polygon, out)
|
|
53
70
|
return out
|
|
54
71
|
}
|
|
@@ -7,19 +7,22 @@ import { measureBoundingSphere, create, transform } from './index.js'
|
|
|
7
7
|
test('poly3: measureBoundingSphere() should return correct values', (t) => {
|
|
8
8
|
let ply1 = create()
|
|
9
9
|
let exp1 = [0, 0, 0, 0]
|
|
10
|
-
let ret1 =
|
|
10
|
+
let ret1 = [0, 0, 0, 0]
|
|
11
|
+
ret1 = measureBoundingSphere(ret1, ply1)
|
|
11
12
|
t.deepEqual(ret1, exp1)
|
|
12
13
|
|
|
13
14
|
// simple triangle
|
|
14
15
|
let ply2 = create([[0, 0, 0], [0, 10, 0], [0, 10, 10]])
|
|
15
16
|
let exp2 = [0, 5, 5, 7.0710678118654755]
|
|
16
|
-
let ret2 =
|
|
17
|
+
let ret2 = [0, 0, 0, 0]
|
|
18
|
+
ret2 = measureBoundingSphere(ret2, ply2)
|
|
17
19
|
t.deepEqual(ret2, exp2)
|
|
18
20
|
|
|
19
21
|
// simple square
|
|
20
22
|
let ply3 = create([[0, 0, 0], [0, 10, 0], [0, 10, 10], [0, 0, 10]])
|
|
21
23
|
let exp3 = [0, 5, 5, 7.0710678118654755]
|
|
22
|
-
let ret3 =
|
|
24
|
+
let ret3 = [0, 0, 0, 0]
|
|
25
|
+
ret3 = measureBoundingSphere(ret3, ply3)
|
|
23
26
|
t.deepEqual(ret3, exp3)
|
|
24
27
|
|
|
25
28
|
// V-shape
|
|
@@ -37,7 +40,8 @@ test('poly3: measureBoundingSphere() should return correct values', (t) => {
|
|
|
37
40
|
]
|
|
38
41
|
let ply4 = create(vertices)
|
|
39
42
|
let exp4 = [0, 4.5, 3, 4.6097722286464435]
|
|
40
|
-
let ret4 =
|
|
43
|
+
let ret4 = [0, 0, 0, 0]
|
|
44
|
+
ret4 = measureBoundingSphere(ret4, ply4)
|
|
41
45
|
t.deepEqual(ret4, exp4)
|
|
42
46
|
|
|
43
47
|
// rotated to various angles
|
|
@@ -46,10 +50,10 @@ test('poly3: measureBoundingSphere() should return correct values', (t) => {
|
|
|
46
50
|
ply2 = transform(rotation, ply2)
|
|
47
51
|
ply3 = transform(rotation, ply3)
|
|
48
52
|
ply4 = transform(rotation, ply4)
|
|
49
|
-
ret1 = measureBoundingSphere(ply1)
|
|
50
|
-
ret2 = measureBoundingSphere(ply2)
|
|
51
|
-
ret3 = measureBoundingSphere(ply3)
|
|
52
|
-
ret4 = measureBoundingSphere(ply4)
|
|
53
|
+
ret1 = measureBoundingSphere(ret1, ply1)
|
|
54
|
+
ret2 = measureBoundingSphere(ret2, ply2)
|
|
55
|
+
ret3 = measureBoundingSphere(ret3, ply3)
|
|
56
|
+
ret4 = measureBoundingSphere(ret4, ply4)
|
|
53
57
|
exp1 = [0, 0, 0, 0]
|
|
54
58
|
t.deepEqual(ret1, exp1)
|
|
55
59
|
exp2 = [-3.5355339059327373, 3.5355339059327378, 5, 7.0710678118654755]
|
|
@@ -28,10 +28,9 @@ export const validate = (object) => {
|
|
|
28
28
|
// contours must be coplanar
|
|
29
29
|
const contourPlane = poly3.plane(poly3.create(contour))
|
|
30
30
|
if (!plane.equals(slicePlane, contourPlane)) {
|
|
31
|
-
throw new Error(
|
|
31
|
+
throw new Error('slice contours must be coplanar')
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
for (let i = 0; i < contour.length; i++) {
|
|
36
35
|
const vertex = contour[i]
|
|
37
36
|
// check for infinity, nan
|
package/src/index.js
CHANGED
|
@@ -13,3 +13,44 @@ export * from './operations/hulls/index.js'
|
|
|
13
13
|
export * from './operations/modifiers/index.js'
|
|
14
14
|
export * from './operations/offsets/index.js'
|
|
15
15
|
export * from './operations/transforms/index.js'
|
|
16
|
+
|
|
17
|
+
// V2 API compatibility:
|
|
18
|
+
export * as colors from './colors/index.js'
|
|
19
|
+
export * as curves from './curves/index.js'
|
|
20
|
+
import { geom2, geom3, path2, poly2, poly3 } from './geometries/index.js'
|
|
21
|
+
export const geometries = {
|
|
22
|
+
geom2: {
|
|
23
|
+
...geom2,
|
|
24
|
+
create: (sides) => geom2.fromSides(sides),
|
|
25
|
+
fromPoints: (points) => geometries.geom2.create([points])
|
|
26
|
+
},
|
|
27
|
+
geom3,
|
|
28
|
+
path2,
|
|
29
|
+
poly2,
|
|
30
|
+
poly3: {
|
|
31
|
+
...poly3,
|
|
32
|
+
fromPoints: (points) => poly3.create([points]),
|
|
33
|
+
fromPointsAndPlane: poly3.fromVerticesAndPlane,
|
|
34
|
+
toPoints: poly3.toVertices
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export * as maths from './maths/index.js'
|
|
38
|
+
export * as measurements from './measurements/index.js'
|
|
39
|
+
export * as primitives from './primitives/index.js'
|
|
40
|
+
export * as text from './text/index.js'
|
|
41
|
+
export * as booleans from './operations/booleans/index.js'
|
|
42
|
+
import * as extrusion from './operations/extrusions/index.js'
|
|
43
|
+
import * as offsets from './operations/offsets/index.js'
|
|
44
|
+
export const extrusions = {
|
|
45
|
+
...extrusion,
|
|
46
|
+
extrudeRectangular: (opt, geom) => extrusions.extrudeLinear(opt, offsets.offset(opt, geom)),
|
|
47
|
+
slice: geometries.slice
|
|
48
|
+
}
|
|
49
|
+
export * as hulls from './operations/hulls/index.js'
|
|
50
|
+
export * as modifiers from './operations/modifiers/index.js'
|
|
51
|
+
export const expansions = {
|
|
52
|
+
...offsets,
|
|
53
|
+
expand: offsets.offset
|
|
54
|
+
}
|
|
55
|
+
export * as transforms from './operations/transforms/index.js'
|
|
56
|
+
export * as utils from './utils/index.js'
|
package/src/maths/index.js
CHANGED
|
@@ -14,7 +14,6 @@ import { measureArea } from './measureArea.js'
|
|
|
14
14
|
*/
|
|
15
15
|
export const measureAggregateArea = (...geometries) => {
|
|
16
16
|
geometries = flatten(geometries)
|
|
17
|
-
if (geometries.length === 0) throw new Error('measureAggregateArea: no geometries supplied')
|
|
18
17
|
const areas = measureArea(geometries)
|
|
19
18
|
if (geometries.length === 1) {
|
|
20
19
|
return areas
|
|
@@ -15,7 +15,6 @@ import { measureBoundingBox } from './measureBoundingBox.js'
|
|
|
15
15
|
*/
|
|
16
16
|
export const measureAggregateBoundingBox = (...geometries) => {
|
|
17
17
|
geometries = flatten(geometries)
|
|
18
|
-
if (geometries.length === 0) throw new Error('measureAggregateBoundingBox: no geometries supplied')
|
|
19
18
|
const bounds = measureBoundingBox(geometries)
|
|
20
19
|
if (geometries.length === 1) {
|
|
21
20
|
return bounds
|
|
@@ -18,7 +18,6 @@ import { calculateEpsilonFromBounds } from './calculateEpsilonFromBounds.js'
|
|
|
18
18
|
*/
|
|
19
19
|
export const measureAggregateEpsilon = (...geometries) => {
|
|
20
20
|
geometries = flatten(geometries)
|
|
21
|
-
if (geometries.length === 0) throw new Error('measureAggregateEpsilon: no geometries supplied')
|
|
22
21
|
const bounds = measureAggregateBoundingBox(geometries)
|
|
23
22
|
|
|
24
23
|
let dimensions = 0
|
|
@@ -14,7 +14,6 @@ import { measureVolume } from './measureVolume.js'
|
|
|
14
14
|
*/
|
|
15
15
|
export const measureAggregateVolume = (...geometries) => {
|
|
16
16
|
geometries = flatten(geometries)
|
|
17
|
-
if (geometries.length === 0) throw new Error('measureAggregateVolume: no geometries supplied')
|
|
18
17
|
const volumes = measureVolume(geometries)
|
|
19
18
|
if (geometries.length === 1) {
|
|
20
19
|
return volumes
|
|
@@ -85,7 +85,6 @@ const measureAreaOfSlice = (geometry) => {
|
|
|
85
85
|
*/
|
|
86
86
|
export const measureArea = (...geometries) => {
|
|
87
87
|
geometries = flatten(geometries)
|
|
88
|
-
if (geometries.length === 0) throw new Error('wrong number of arguments')
|
|
89
88
|
|
|
90
89
|
const results = geometries.map((geometry) => {
|
|
91
90
|
if (path2.isA(geometry)) return measureAreaOfPath2(geometry)
|
|
@@ -121,7 +121,6 @@ const measureBoundingBoxOfSlice = (geometry) => {
|
|
|
121
121
|
*/
|
|
122
122
|
export const measureBoundingBox = (...geometries) => {
|
|
123
123
|
geometries = flatten(geometries)
|
|
124
|
-
if (geometries.length === 0) throw new Error('wrong number of arguments')
|
|
125
124
|
|
|
126
125
|
const results = geometries.map((geometry) => {
|
|
127
126
|
if (path2.isA(geometry)) return measureCached(geometry, measureBoundingBoxOfPath2)
|
|
@@ -64,17 +64,13 @@ const measureBoundingSphereOfPoints = (points) => {
|
|
|
64
64
|
* Measure the bounding sphere of the given (path2) geometry.
|
|
65
65
|
* @return {[[x, y, z], radius]} the bounding sphere for the geometry
|
|
66
66
|
*/
|
|
67
|
-
const measureBoundingSphereOfPath2 = (
|
|
68
|
-
return measureBoundingSphereOfPoints(path2.toPoints(points))
|
|
69
|
-
}
|
|
67
|
+
const measureBoundingSphereOfPath2 = (geometry) => measureBoundingSphereOfPoints(path2.toPoints(geometry))
|
|
70
68
|
|
|
71
69
|
/*
|
|
72
70
|
* Measure the bounding sphere of the given (geom2) geometry.
|
|
73
71
|
* @return {[[x, y, z], radius]} the bounding sphere for the geometry
|
|
74
72
|
*/
|
|
75
|
-
const measureBoundingSphereOfGeom2 = (geometry) =>
|
|
76
|
-
return measureBoundingSphereOfPoints(geom2.toPoints(geometry))
|
|
77
|
-
}
|
|
73
|
+
const measureBoundingSphereOfGeom2 = (geometry) => measureBoundingSphereOfPoints(geom2.toPoints(geometry))
|
|
78
74
|
|
|
79
75
|
/*
|
|
80
76
|
* Measure the bounding sphere of the given (geom3) geometry.
|
|
@@ -20,7 +20,6 @@ import { measureBoundingBox } from './measureBoundingBox.js'
|
|
|
20
20
|
*/
|
|
21
21
|
export const measureEpsilon = (...geometries) => {
|
|
22
22
|
geometries = flatten(geometries)
|
|
23
|
-
if (geometries.length === 0) throw new Error('wrong number of arguments')
|
|
24
23
|
|
|
25
24
|
const results = geometries.map((geometry) => {
|
|
26
25
|
if (path2.isA(geometry)) return calculateEpsilonFromBounds(measureBoundingBox(geometry), 2)
|
|
@@ -34,7 +34,6 @@ const measureVolumeOfGeom3 = (geometry) => {
|
|
|
34
34
|
*/
|
|
35
35
|
export const measureVolume = (...geometries) => {
|
|
36
36
|
geometries = flatten(geometries)
|
|
37
|
-
if (geometries.length === 0) throw new Error('wrong number of arguments')
|
|
38
37
|
|
|
39
38
|
const results = geometries.map((geometry) => {
|
|
40
39
|
if (geom3.isA(geometry)) return measureVolumeOfGeom3(geometry)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { areAllShapesTheSameType } from '../../utils/areAllShapesTheSameType.js'
|
|
2
|
-
import {
|
|
2
|
+
import { coalesce } from '../../utils/coalesce.js'
|
|
3
3
|
|
|
4
4
|
import * as geom2 from '../../geometries/geom2/index.js'
|
|
5
5
|
import * as geom3 from '../../geometries/geom3/index.js'
|
|
@@ -13,11 +13,11 @@ import { intersectGeom3 } from './intersectGeom3.js'
|
|
|
13
13
|
* The given geometries should be of the same type, either geom2 or geom3.
|
|
14
14
|
*
|
|
15
15
|
* @param {...Object} geometries - list of geometries
|
|
16
|
-
* @returns {Geom2|
|
|
16
|
+
* @returns {Geom2|Geom3} a new geometry
|
|
17
17
|
* @alias module:modeling/booleans.intersect
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
|
-
* let myshape = intersect(cube({size:
|
|
20
|
+
* let myshape = intersect(cube({size: 5}), cube({size: 5, center: [3,3,3]}))
|
|
21
21
|
*
|
|
22
22
|
* @example
|
|
23
23
|
* +-------+
|
|
@@ -30,9 +30,9 @@ import { intersectGeom3 } from './intersectGeom3.js'
|
|
|
30
30
|
* +-------+
|
|
31
31
|
*/
|
|
32
32
|
export const intersect = (...geometries) => {
|
|
33
|
-
geometries =
|
|
34
|
-
if (geometries.length === 0) throw new Error('intersect wrong number of arguments')
|
|
33
|
+
geometries = coalesce(geometries)
|
|
35
34
|
|
|
35
|
+
if (geometries.length === 0) return undefined
|
|
36
36
|
if (!areAllShapesTheSameType(geometries)) {
|
|
37
37
|
throw new Error('intersect arguments must be the same geometry type')
|
|
38
38
|
}
|