@jscad/modeling 3.0.2-alpha.0 → 3.0.4-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 +25 -0
- package/dist/jscad-modeling.es.js +2 -7
- package/dist/jscad-modeling.min.js +2 -7
- package/package.json +6 -7
- package/rollup.config.js +8 -4
- package/src/colors/colorize.test.js +1 -1
- package/src/curves/bezier/arcLengthToT.js +1 -1
- package/src/curves/bezier/create.js +1 -1
- package/src/curves/bezier/index.js +7 -7
- package/src/curves/bezier/length.js +1 -1
- package/src/curves/bezier/lengths.js +2 -1
- package/src/curves/bezier/tangentAt.js +1 -1
- package/src/curves/bezier/valueAt.js +1 -1
- package/src/curves/index.js +3 -3
- package/src/geometries/geom2/applyTransforms.js +3 -1
- package/src/geometries/geom2/clone.js +5 -1
- package/src/geometries/geom2/create.js +4 -14
- package/src/geometries/geom2/fromSides.js +4 -2
- package/src/geometries/geom2/index.d.ts +0 -2
- package/src/geometries/geom2/index.js +21 -7
- package/src/geometries/geom2/isA.js +5 -1
- package/src/geometries/geom2/reverse.js +4 -2
- package/src/geometries/geom2/toOutlines.js +2 -1
- package/src/geometries/geom2/toPoints.js +5 -2
- package/src/geometries/geom2/toSides.js +4 -3
- package/src/geometries/geom2/toString.js +3 -2
- package/src/geometries/geom2/transform.js +4 -2
- package/src/geometries/geom2/validate.js +6 -2
- package/src/geometries/geom3/applyTransforms.test.js +2 -2
- package/src/geometries/geom3/clone.js +5 -1
- package/src/geometries/geom3/clone.test.js +2 -2
- package/src/geometries/geom3/create.js +6 -28
- package/src/geometries/geom3/{fromPoints.d.ts → fromVertices.d.ts} +1 -1
- package/src/geometries/geom3/{fromPoints.js → fromVertices.js} +15 -2
- package/src/geometries/geom3/{fromPoints.test.js → fromVertices.test.js} +6 -6
- package/src/geometries/geom3/{fromPointsConvex.d.ts → fromVerticesConvex.d.ts} +1 -1
- package/src/geometries/geom3/fromVerticesConvex.js +25 -0
- package/src/geometries/geom3/{fromPointsConvex.test.js → fromVerticesConvex.test.js} +3 -3
- package/src/geometries/geom3/index.d.ts +4 -5
- package/src/geometries/geom3/index.js +29 -9
- package/src/geometries/geom3/invert.js +5 -1
- package/src/geometries/geom3/invert.test.js +2 -2
- package/src/geometries/geom3/isA.js +5 -1
- package/src/geometries/geom3/isA.test.js +2 -2
- package/src/geometries/geom3/isConvex.d.ts +3 -0
- package/src/geometries/geom3/isConvex.js +65 -0
- package/src/geometries/geom3/isConvex.test.js +44 -0
- package/src/geometries/geom3/toPolygons.js +4 -2
- package/src/geometries/geom3/toString.js +3 -2
- package/src/geometries/geom3/toString.test.js +2 -2
- package/src/geometries/geom3/{toPoints.d.ts → toVertices.d.ts} +1 -1
- package/src/geometries/geom3/toVertices.js +20 -0
- package/src/geometries/geom3/{toPoints.test.js → toVertices.test.js} +4 -4
- package/src/geometries/geom3/transform.js +5 -2
- package/src/geometries/geom3/transform.test.js +2 -2
- package/src/geometries/geom3/validate.js +6 -2
- package/src/geometries/geom3/validate.test.js +4 -4
- package/src/geometries/index.d.ts +1 -0
- package/src/geometries/index.js +10 -7
- package/src/geometries/path2/appendArc.js +7 -5
- package/src/geometries/path2/appendArc.test.js +11 -15
- package/src/geometries/path2/appendBezier.js +6 -4
- package/src/geometries/path2/appendPoints.js +4 -2
- package/src/geometries/path2/applyTransforms.js +3 -0
- package/src/geometries/path2/clone.js +5 -1
- package/src/geometries/path2/close.js +5 -1
- package/src/geometries/path2/concat.js +3 -2
- package/src/geometries/path2/create.js +5 -25
- package/src/geometries/path2/equals.js +12 -7
- package/src/geometries/path2/fromPoints.js +5 -3
- package/src/geometries/path2/index.d.ts +0 -2
- package/src/geometries/path2/index.js +21 -6
- package/src/geometries/path2/isA.js +5 -1
- package/src/geometries/path2/reverse.js +4 -2
- package/src/geometries/path2/toPoints.js +5 -3
- package/src/geometries/path2/toString.js +3 -2
- package/src/geometries/path2/transform.js +4 -2
- package/src/geometries/path2/validate.js +5 -1
- package/src/geometries/path3/applyTransforms.js +22 -0
- package/src/geometries/path3/applyTransforms.test.js +28 -0
- package/src/geometries/path3/close.d.ts +3 -0
- package/src/geometries/path3/close.js +33 -0
- package/src/geometries/path3/close.test.js +43 -0
- package/src/geometries/path3/concat.d.ts +3 -0
- package/src/geometries/path3/concat.js +35 -0
- package/src/geometries/path3/concat.test.js +35 -0
- package/src/geometries/path3/create.d.ts +4 -0
- package/src/geometries/path3/create.js +14 -0
- package/src/geometries/path3/create.test.js +8 -0
- package/src/geometries/path3/equals.d.ts +3 -0
- package/src/geometries/path3/equals.js +50 -0
- package/src/geometries/path3/equals.test.js +38 -0
- package/src/geometries/path3/fromVertices.d.ts +8 -0
- package/src/geometries/path3/fromVertices.js +44 -0
- package/src/geometries/path3/fromVertices.test.js +33 -0
- package/src/geometries/path3/index.d.ts +13 -0
- package/src/geometries/path3/index.js +37 -0
- package/src/geometries/path3/isA.d.ts +3 -0
- package/src/geometries/path3/isA.js +22 -0
- package/src/geometries/path3/isA.test.js +19 -0
- package/src/geometries/path3/reverse.d.ts +3 -0
- package/src/geometries/path3/reverse.js +18 -0
- package/src/geometries/path3/reverse.test.js +9 -0
- package/src/geometries/path3/toString.d.ts +3 -0
- package/src/geometries/path3/toString.js +23 -0
- package/src/geometries/path3/toVertices.d.ts +4 -0
- package/src/geometries/path3/toVertices.js +15 -0
- package/src/geometries/path3/toVertices.test.js +13 -0
- package/src/geometries/path3/transform.d.ts +4 -0
- package/src/geometries/path3/transform.js +20 -0
- package/src/geometries/path3/transform.test.js +50 -0
- package/src/geometries/path3/type.d.ts +10 -0
- package/src/geometries/path3/validate.d.ts +1 -0
- package/src/geometries/path3/validate.js +44 -0
- package/src/geometries/poly2/arePointsInside.js +4 -1
- package/src/geometries/poly2/clone.js +4 -1
- package/src/geometries/poly2/create.js +3 -15
- package/src/geometries/poly2/index.js +16 -4
- package/src/geometries/poly2/isA.js +5 -1
- package/src/geometries/poly2/isConvex.js +5 -1
- package/src/geometries/poly2/isSimple.js +5 -1
- package/src/geometries/poly2/measureArea.js +4 -1
- package/src/geometries/poly2/measureBoundingBox.js +6 -1
- package/src/geometries/poly2/reverse.js +4 -1
- package/src/geometries/poly2/toPoints.js +6 -1
- package/src/geometries/poly2/toString.js +5 -1
- package/src/geometries/poly2/transform.js +5 -1
- package/src/geometries/poly2/validate.js +6 -2
- package/src/geometries/poly3/clone.js +4 -1
- package/src/geometries/poly3/create.js +4 -17
- package/src/geometries/poly3/fromVerticesAndPlane.js +3 -1
- package/src/geometries/poly3/index.js +19 -4
- package/src/geometries/poly3/invert.js +4 -1
- package/src/geometries/poly3/isA.js +5 -1
- package/src/geometries/poly3/isConvex.js +5 -1
- package/src/geometries/poly3/measureArea.js +5 -1
- package/src/geometries/poly3/measureBoundingBox.js +4 -1
- package/src/geometries/poly3/measureBoundingSphere.js +4 -3
- package/src/geometries/poly3/measureSignedVolume.js +6 -1
- package/src/geometries/poly3/plane.js +6 -0
- package/src/geometries/poly3/toString.js +5 -1
- package/src/geometries/poly3/toVertices.js +6 -1
- package/src/geometries/poly3/transform.js +5 -1
- package/src/geometries/poly3/validate.js +6 -2
- package/src/geometries/slice/calculatePlane.js +3 -3
- package/src/geometries/slice/clone.js +4 -1
- package/src/geometries/slice/create.js +5 -10
- package/src/geometries/slice/equals.js +5 -1
- package/src/geometries/slice/fromGeom2.js +1 -1
- package/src/geometries/slice/fromVertices.js +3 -3
- package/src/geometries/slice/index.js +19 -4
- package/src/geometries/slice/isA.js +5 -1
- package/src/geometries/slice/reverse.js +5 -2
- package/src/geometries/slice/toEdges.js +5 -3
- package/src/geometries/slice/toPolygons.js +5 -1
- package/src/geometries/slice/toString.js +5 -1
- package/src/geometries/slice/toVertices.js +5 -3
- package/src/geometries/slice/transform.js +4 -3
- package/src/geometries/slice/validate.js +3 -2
- package/src/index.d.ts +1 -0
- package/src/index.js +4 -0
- package/src/maths/constants.js +11 -7
- package/src/maths/index.js +2 -1
- package/src/maths/mat4/isOnlyTransformScale.js +1 -1
- package/src/operations/booleans/index.js +2 -0
- package/src/operations/booleans/intersect.js +0 -1
- package/src/operations/booleans/intersectGeom3.test.js +4 -4
- package/src/operations/booleans/scission.js +0 -1
- package/src/operations/booleans/subtractGeom3.test.js +4 -4
- package/src/operations/booleans/trees/splitLineSegmentByPlane.js +1 -4
- package/src/operations/booleans/trees/splitPolygonByPlane.test.js +138 -0
- package/src/operations/booleans/unionGeom3.test.js +40 -5
- package/src/operations/extrusions/extrudeFromSlices.js +15 -5
- package/src/operations/extrusions/extrudeFromSlices.test.js +6 -6
- package/src/operations/extrusions/extrudeLinear.test.js +8 -8
- package/src/operations/extrusions/extrudeRotate.js +2 -1
- package/src/operations/extrusions/extrudeRotate.test.js +46 -12
- package/src/operations/extrusions/extrudeWalls.test.js +60 -0
- package/src/operations/hulls/hull.test.js +5 -5
- package/src/operations/hulls/hullChain.test.js +5 -5
- package/src/operations/hulls/toUniquePoints.js +2 -2
- package/src/operations/minkowski/index.d.ts +1 -0
- package/src/operations/minkowski/index.js +15 -0
- package/src/operations/minkowski/minkowskiSum.d.ts +4 -0
- package/src/operations/minkowski/minkowskiSum.js +223 -0
- package/src/operations/minkowski/minkowskiSum.test.js +199 -0
- package/src/operations/modifiers/generalize.test.js +6 -6
- package/src/operations/modifiers/insertTjunctions.test.js +2 -2
- package/src/operations/modifiers/reTesselateCoplanarPolygons.js +10 -3
- package/src/operations/modifiers/reTesselateCoplanarPolygons.test.js +36 -1
- package/src/operations/modifiers/retessellate.js +4 -2
- package/src/operations/modifiers/retessellate.test.js +10 -10
- package/src/operations/modifiers/snap.test.js +28 -19
- package/src/operations/offsets/offsetGeom3.test.js +9 -11
- package/src/operations/transforms/center.test.js +7 -7
- package/src/operations/transforms/mirror.test.js +7 -7
- package/src/operations/transforms/rotate.test.js +7 -7
- package/src/operations/transforms/scale.test.js +7 -7
- package/src/operations/transforms/transform.test.js +2 -2
- package/src/operations/transforms/translate.test.js +7 -7
- package/src/primitives/arc.js +2 -2
- package/src/primitives/arc.test.js +104 -113
- package/src/primitives/cube.test.js +4 -4
- package/src/primitives/cuboid.test.js +4 -4
- package/src/primitives/cylinder.test.js +5 -5
- package/src/primitives/cylinderElliptic.test.js +9 -9
- package/src/primitives/ellipsoid.test.js +5 -5
- package/src/primitives/geodesicSphere.test.js +4 -4
- package/src/primitives/polyhedron.test.js +2 -2
- package/src/primitives/roundedCuboid.test.js +7 -7
- package/src/primitives/roundedCylinder.test.js +9 -9
- package/src/primitives/sphere.test.js +5 -5
- package/src/primitives/torus.test.js +4 -4
- package/src/utils/flatten.js +1 -1
- package/src/utils/flatten.test.js +94 -0
- package/src/geometries/geom2/fromCompactBinary.d.ts +0 -3
- package/src/geometries/geom2/fromCompactBinary.js +0 -40
- package/src/geometries/geom2/fromToCompactBinary.test.js +0 -100
- package/src/geometries/geom2/toCompactBinary.d.ts +0 -3
- package/src/geometries/geom2/toCompactBinary.js +0 -56
- package/src/geometries/geom3/fromCompactBinary.d.ts +0 -3
- package/src/geometries/geom3/fromCompactBinary.js +0 -42
- package/src/geometries/geom3/fromPointsConvex.js +0 -25
- package/src/geometries/geom3/fromToCompactBinary.test.js +0 -139
- package/src/geometries/geom3/toCompactBinary.d.ts +0 -3
- package/src/geometries/geom3/toCompactBinary.js +0 -66
- package/src/geometries/geom3/toPoints.js +0 -15
- package/src/geometries/path2/fromCompactBinary.d.ts +0 -3
- package/src/geometries/path2/fromCompactBinary.js +0 -31
- package/src/geometries/path2/fromToCompactBinary.test.js +0 -114
- package/src/geometries/path2/toCompactBinary.d.ts +0 -3
- package/src/geometries/path2/toCompactBinary.js +0 -50
|
@@ -7,22 +7,24 @@ import { toPoints } from './toPoints.js'
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Append a series of points to the given geometry that represent a Bézier curve.
|
|
10
|
+
*
|
|
10
11
|
* The Bézier curve starts at the last point in the given geometry, and ends at the last control point.
|
|
11
12
|
* The other control points are intermediate control points to transition the curve from start to end points.
|
|
12
13
|
* The first control point may be null to ensure a smooth transition occurs. In this case,
|
|
13
14
|
* the second to last point of the given geometry is mirrored into the control points of the Bézier curve.
|
|
14
15
|
* In other words, the trailing gradient of the geometry matches the new gradient of the curve.
|
|
16
|
+
*
|
|
15
17
|
* @param {object} options - options for construction
|
|
16
18
|
* @param {Array} options.controlPoints - list of control points (2D) for the Bézier curve
|
|
17
19
|
* @param {number} [options.segments=16] - number of segments per 360 rotation
|
|
18
20
|
* @param {Path2} geometry - the path of which to append points
|
|
19
21
|
* @returns {Path2} a new path with the appended points
|
|
20
|
-
* @alias module:modeling/
|
|
22
|
+
* @alias module:modeling/path2.appendBezier
|
|
21
23
|
*
|
|
22
24
|
* @example
|
|
23
|
-
* let myShape = fromPoints({}, [[10,-20]])
|
|
24
|
-
* myShape = appendBezier({controlPoints: [[10,-10],[25,-10],[25,-20]]}, myShape);
|
|
25
|
-
* myShape = appendBezier({controlPoints: [null, [25,-30],[40,-30],[40,-20]]}, myShape)
|
|
25
|
+
* let myShape = path2.fromPoints({}, [[10,-20]])
|
|
26
|
+
* myShape = path2.appendBezier({controlPoints: [[10,-10],[25,-10],[25,-20]]}, myShape);
|
|
27
|
+
* myShape = path2.appendBezier({controlPoints: [null, [25,-30],[40,-30],[40,-20]]}, myShape)
|
|
26
28
|
*/
|
|
27
29
|
export const appendBezier = (options, geometry) => {
|
|
28
30
|
const defaults = {
|
|
@@ -3,11 +3,13 @@ import { create } from './create.js'
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Append the given list of points to the end of the given geometry.
|
|
6
|
+
*
|
|
6
7
|
* @param {Array} points - the points (2D) to append to the given path
|
|
7
8
|
* @param {Path2} geometry - the given path
|
|
8
9
|
* @returns {Path2} a new path with the appended points
|
|
9
|
-
* @alias module:modeling/
|
|
10
|
+
* @alias module:modeling/path2.appendPoints
|
|
11
|
+
*
|
|
10
12
|
* @example
|
|
11
|
-
* let newPath = appendPoints([[3, 4], [4, 5]], oldPath)
|
|
13
|
+
* let newPath = path2.appendPoints([[3, 4], [4, 5]], oldPath)
|
|
12
14
|
*/
|
|
13
15
|
export const appendPoints = (points, geometry) => concat(geometry, create(points))
|
|
@@ -3,9 +3,12 @@ import * as vec2 from '../../maths/vec2/index.js'
|
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* Apply the transforms of the given geometry.
|
|
6
|
+
*
|
|
6
7
|
* NOTE: This function must be called BEFORE exposing any data. See toPoints.
|
|
8
|
+
*
|
|
7
9
|
* @param {path} geometry - the geometry to transform
|
|
8
10
|
* @returns {path} the given geometry
|
|
11
|
+
*
|
|
9
12
|
* @example
|
|
10
13
|
* geometry = applyTransforms(geometry)
|
|
11
14
|
*/
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Performs a shallow clone of the give geometry.
|
|
3
|
+
*
|
|
3
4
|
* @param {Path2} geometry - the geometry to clone
|
|
4
5
|
* @returns {Path2} a new path
|
|
5
|
-
* @alias module:modeling/
|
|
6
|
+
* @alias module:modeling/path2.clone
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* let newPath = path2.clone(oldPath)
|
|
6
10
|
*/
|
|
7
11
|
export const clone = (geometry) => Object.assign({}, geometry)
|
|
@@ -6,9 +6,13 @@ import { clone } from './clone.js'
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Close the given geometry.
|
|
9
|
+
*
|
|
9
10
|
* @param {Path2} geometry - the path to close
|
|
10
11
|
* @returns {Path2} a new path
|
|
11
|
-
* @alias module:modeling/
|
|
12
|
+
* @alias module:modeling/path2.close
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* let newPath = path2.close(oldPath)
|
|
12
16
|
*/
|
|
13
17
|
export const close = (geometry) => {
|
|
14
18
|
if (geometry.isClosed) return geometry
|
|
@@ -10,12 +10,13 @@ import { toPoints } from './toPoints.js'
|
|
|
10
10
|
* A concatenation of zero paths is an empty, open path.
|
|
11
11
|
* A concatenation of one closed path to a series of open paths produces a closed path.
|
|
12
12
|
* A concatenation of a path to a closed path is an error.
|
|
13
|
+
*
|
|
13
14
|
* @param {...Path2} paths - the paths to concatenate
|
|
14
15
|
* @returns {Path2} a new path
|
|
15
|
-
* @alias module:modeling/
|
|
16
|
+
* @alias module:modeling/path2.concat
|
|
16
17
|
*
|
|
17
18
|
* @example
|
|
18
|
-
* let newPath = concat(fromPoints({}, [[1, 2]]), fromPoints({}, [[3, 4]]))
|
|
19
|
+
* let newPath = path2.concat(path2.fromPoints({}, [[1, 2]]), path2.fromPoints({}, [[3, 4]]))
|
|
19
20
|
*/
|
|
20
21
|
export const concat = (...paths) => {
|
|
21
22
|
// Only the last path can be closed, producing a closed path.
|
|
@@ -1,33 +1,13 @@
|
|
|
1
1
|
import * as mat4 from '../../maths/mat4/index.js'
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Represents a 2D geometry consisting of a list of ordered points.
|
|
5
|
-
* @property {Array} points - list of ordered points
|
|
6
|
-
* @property {boolean} isClosed - true if the path is closed where start and end points are the same
|
|
7
|
-
* @property {Mat4} transforms - transforms to apply to the points, see transform()
|
|
8
|
-
* @example
|
|
9
|
-
* {
|
|
10
|
-
* "points": [[0,0], [4,0], [4,3]],
|
|
11
|
-
* "isClosed": true,
|
|
12
|
-
* "transforms": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
|
|
13
|
-
* }
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
3
|
/**
|
|
17
4
|
* Create an empty, open path.
|
|
5
|
+
*
|
|
6
|
+
* @param {Array} [points] - a list of points of which to create the path
|
|
18
7
|
* @returns {Path2} a new path
|
|
19
|
-
* @alias module:modeling/
|
|
8
|
+
* @alias module:modeling/path2.create
|
|
20
9
|
*
|
|
21
10
|
* @example
|
|
22
|
-
* let newPath = create()
|
|
11
|
+
* let newPath = path2.create()
|
|
23
12
|
*/
|
|
24
|
-
export const create = (points) => {
|
|
25
|
-
if (points === undefined) {
|
|
26
|
-
points = []
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
points: points,
|
|
30
|
-
isClosed: false,
|
|
31
|
-
transforms: mat4.create()
|
|
32
|
-
}
|
|
33
|
-
}
|
|
13
|
+
export const create = (points = []) => ({ points: points, isClosed: false, transforms: mat4.create() })
|
|
@@ -3,13 +3,18 @@ import * as vec2 from '../../maths/vec2/index.js'
|
|
|
3
3
|
import { toPoints } from './toPoints.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
* Determine if the given paths are equal.
|
|
7
|
+
*
|
|
8
|
+
* For closed paths, this includes equality under point order rotation.
|
|
9
|
+
*
|
|
10
|
+
* @param {Path2} a - the first path to compare
|
|
11
|
+
* @param {Path2} b - the second path to compare
|
|
12
|
+
* @returns {Boolean}
|
|
13
|
+
* @alias module:modeling/path2.equals
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* if (path2.equals(pathA, pathB)) { ... }
|
|
17
|
+
*/
|
|
13
18
|
export const equals = (a, b) => {
|
|
14
19
|
if (a.isClosed !== b.isClosed) {
|
|
15
20
|
return false
|
|
@@ -7,16 +7,18 @@ import { create } from './create.js'
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Create a new path from the given points.
|
|
10
|
+
*
|
|
10
11
|
* The points must be provided an array of points,
|
|
11
12
|
* where each point is an array of two numbers.
|
|
13
|
+
*
|
|
12
14
|
* @param {object} options - options for construction
|
|
13
15
|
* @param {boolean} [options.closed=false] - if the path should be open or closed
|
|
14
16
|
* @param {Array} points - array of points (2D) from which to create the path
|
|
15
17
|
* @returns {Path2} a new path
|
|
16
|
-
* @alias module:modeling/
|
|
18
|
+
* @alias module:modeling/path2.fromPoints
|
|
17
19
|
*
|
|
18
|
-
* @example
|
|
19
|
-
* my newPath = fromPoints({closed: true}, [[10, 10], [-10, 10]])
|
|
20
|
+
* @example
|
|
21
|
+
* my newPath = path2.fromPoints({closed: true}, [[10, 10], [-10, 10]])
|
|
20
22
|
*/
|
|
21
23
|
export const fromPoints = (options, points) => {
|
|
22
24
|
const defaults = { closed: false }
|
|
@@ -7,12 +7,10 @@ export { concat } from './concat.js'
|
|
|
7
7
|
export { create } from './create.js'
|
|
8
8
|
export { equals } from './equals.js'
|
|
9
9
|
export { fromPoints, FromPointsOptions } from './fromPoints.js'
|
|
10
|
-
export { fromCompactBinary } from './fromCompactBinary.js'
|
|
11
10
|
export { isA } from './isA.js'
|
|
12
11
|
export { reverse } from './reverse.js'
|
|
13
12
|
export { toPoints } from './toPoints.js'
|
|
14
13
|
export { toString } from './toString.js'
|
|
15
|
-
export { toCompactBinary } from './toCompactBinary.js'
|
|
16
14
|
export { transform } from './transform.js'
|
|
17
15
|
export { validate } from './validate.js'
|
|
18
16
|
|
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Represents a 2D geometry consisting of a list of ordered points.
|
|
3
|
-
*
|
|
4
|
-
* @
|
|
3
|
+
*
|
|
4
|
+
* @see {@link Path2} for data structure information.
|
|
5
|
+
* @module modeling/path2
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { path2 } from '@jscad/modeling'
|
|
9
|
+
* let myShape = path2.fromPoints({ closed: true }, [[0,0], [4,0], [4,3]])
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef Path2
|
|
14
|
+
* @type {Object}
|
|
15
|
+
* @property {Array} points - list of ordered points
|
|
16
|
+
* @property {boolean} isClosed - true if the path is closed where start and end points are the same
|
|
17
|
+
* @property {Mat4} transforms - transforms to apply to the points, see transform()
|
|
5
18
|
*
|
|
6
19
|
* @example
|
|
7
|
-
*
|
|
8
|
-
*
|
|
20
|
+
* // data structure
|
|
21
|
+
* {
|
|
22
|
+
* "points": [[0,0], [4,0], [4,3]],
|
|
23
|
+
* "isClosed": true,
|
|
24
|
+
* "transforms": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
|
|
25
|
+
* }
|
|
9
26
|
*/
|
|
10
27
|
export { appendArc } from './appendArc.js'
|
|
11
28
|
export { appendBezier } from './appendBezier.js'
|
|
@@ -16,11 +33,9 @@ export { concat } from './concat.js'
|
|
|
16
33
|
export { create } from './create.js'
|
|
17
34
|
export { equals } from './equals.js'
|
|
18
35
|
export { fromPoints } from './fromPoints.js'
|
|
19
|
-
export { fromCompactBinary } from './fromCompactBinary.js'
|
|
20
36
|
export { isA } from './isA.js'
|
|
21
37
|
export { reverse } from './reverse.js'
|
|
22
38
|
export { toPoints } from './toPoints.js'
|
|
23
39
|
export { toString } from './toString.js'
|
|
24
|
-
export { toCompactBinary } from './toCompactBinary.js'
|
|
25
40
|
export { transform } from './transform.js'
|
|
26
41
|
export { validate } from './validate.js'
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Determine if the given object is a path2 geometry.
|
|
3
|
+
*
|
|
3
4
|
* @param {object} object - the object to interrogate
|
|
4
5
|
* @returns {Boolean} true if the object matches a path2
|
|
5
|
-
* @alias module:modeling/
|
|
6
|
+
* @alias module:modeling/path2.isA
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* if (path2.isA(geometry)) { ... }
|
|
6
10
|
*/
|
|
7
11
|
export const isA = (object) => {
|
|
8
12
|
if (object && typeof object === 'object') {
|
|
@@ -2,13 +2,15 @@ import { clone } from './clone.js'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Reverses the path so that the points are in the opposite order.
|
|
5
|
+
*
|
|
5
6
|
* This swaps the left (interior) and right (exterior) edges.
|
|
7
|
+
*
|
|
6
8
|
* @param {Path2} geometry - the path to reverse
|
|
7
9
|
* @returns {Path2} a new path
|
|
8
|
-
* @alias module:modeling/
|
|
10
|
+
* @alias module:modeling/path2.reverse
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
|
-
* let newPath = reverse(
|
|
13
|
+
* let newPath = path2.reverse(oldPath)
|
|
12
14
|
*/
|
|
13
15
|
export const reverse = (geometry) => {
|
|
14
16
|
// NOTE: this only updates the order of the points
|
|
@@ -2,12 +2,14 @@ import { applyTransforms } from './applyTransforms.js'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Produces an array of points from the given geometry.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* NOTE: The returned array should not be modified as the data is shared with the geometry.
|
|
7
|
+
*
|
|
6
8
|
* @param {Path2} geometry - the geometry
|
|
7
9
|
* @returns {Array} an array of points
|
|
8
|
-
* @alias module:modeling/
|
|
10
|
+
* @alias module:modeling/path2.toPoints
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
|
-
* let sharedPoints = toPoints(geometry)
|
|
13
|
+
* let sharedPoints = path2.toPoints(geometry)
|
|
12
14
|
*/
|
|
13
15
|
export const toPoints = (geometry) => applyTransforms(geometry).points
|
|
@@ -4,12 +4,13 @@ import { toPoints } from './toPoints.js'
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Create a string representing the contents of the given path.
|
|
7
|
+
*
|
|
7
8
|
* @param {Path2} geometry - the path
|
|
8
9
|
* @returns {string} a representative string
|
|
9
|
-
* @alias module:modeling/
|
|
10
|
+
* @alias module:modeling/path2.toString
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
|
-
* console.out(toString(path))
|
|
13
|
+
* console.out(path2.toString(path))
|
|
13
14
|
*/
|
|
14
15
|
export const toString = (geometry) => {
|
|
15
16
|
const points = toPoints(geometry)
|
|
@@ -2,15 +2,17 @@ import * as mat4 from '../../maths/mat4/index.js'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Transform the given geometry using the given matrix.
|
|
5
|
+
*
|
|
5
6
|
* This is a lazy transform of the points, as this function only adjusts the transforms.
|
|
6
7
|
* The transforms are applied when accessing the points via toPoints().
|
|
8
|
+
*
|
|
7
9
|
* @param {Mat4} matrix - the matrix to transform with
|
|
8
10
|
* @param {Path2} geometry - the geometry to transform
|
|
9
11
|
* @returns {Path2} a new path
|
|
10
|
-
* @alias module:modeling/
|
|
12
|
+
* @alias module:modeling/path2.transform
|
|
11
13
|
*
|
|
12
14
|
* @example
|
|
13
|
-
* let newPath = transform(fromZRotation(TAU / 8), path)
|
|
15
|
+
* let newPath = path2.transform(mat4.fromZRotation(TAU / 8), path)
|
|
14
16
|
*/
|
|
15
17
|
export const transform = (matrix, geometry) => {
|
|
16
18
|
const transforms = mat4.multiply(mat4.create(), matrix, geometry.transforms)
|
|
@@ -4,13 +4,17 @@ import { isA } from './isA.js'
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Determine if the given object is a valid path2.
|
|
7
|
+
*
|
|
7
8
|
* Checks for valid data points, and duplicate points.
|
|
8
9
|
*
|
|
9
10
|
* **If the geometry is not valid, an exception will be thrown with details of the geometry error.**
|
|
10
11
|
*
|
|
11
12
|
* @param {object} object - the object to interrogate
|
|
12
13
|
* @throws {Error} error if the geometry is not valid
|
|
13
|
-
* @alias module:modeling/
|
|
14
|
+
* @alias module:modeling/path2.validate
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* path2.validate(geometry)
|
|
14
18
|
*/
|
|
15
19
|
export const validate = (object) => {
|
|
16
20
|
if (!isA(object)) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as mat4 from '../../maths/mat4/index.js'
|
|
2
|
+
import * as vec3 from '../../maths/vec3/index.js'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Apply the transforms of the given geometry.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: This function must be called BEFORE exposing any data. See toVertices.
|
|
8
|
+
*
|
|
9
|
+
* @param {Path3} geometry - the geometry to transform
|
|
10
|
+
* @returns {Path3} the given geometry
|
|
11
|
+
* @function
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* geometry = path3.applyTransforms(geometry)
|
|
15
|
+
*/
|
|
16
|
+
export const applyTransforms = (geometry) => {
|
|
17
|
+
if (mat4.isIdentity(geometry.transforms)) return geometry
|
|
18
|
+
|
|
19
|
+
geometry.vertices = geometry.vertices.map((vertex) => vec3.transform(vec3.create(), vertex, geometry.transforms))
|
|
20
|
+
geometry.transforms = mat4.create()
|
|
21
|
+
return geometry
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import test from 'ava'
|
|
2
|
+
|
|
3
|
+
import { fromVertices } from './index.js'
|
|
4
|
+
|
|
5
|
+
import { applyTransforms } from './applyTransforms.js'
|
|
6
|
+
|
|
7
|
+
import { comparePoints, compareVectors } from '../../../test/helpers/index.js'
|
|
8
|
+
|
|
9
|
+
test('applyTransforms: Updates a populated path with transformed points', (t) => {
|
|
10
|
+
const vertices = [[0, 0, 0], [1, 0, 0], [0, 1, 0]]
|
|
11
|
+
const expected = {
|
|
12
|
+
vertices: [[0, 0, 0], [1, 0, 0], [0, 1, 0]],
|
|
13
|
+
isClosed: false,
|
|
14
|
+
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
15
|
+
}
|
|
16
|
+
const geometry = fromVertices({}, vertices)
|
|
17
|
+
const updated = applyTransforms(geometry)
|
|
18
|
+
t.is(geometry, updated)
|
|
19
|
+
t.true(comparePoints(updated.vertices, expected.vertices))
|
|
20
|
+
t.false(updated.isClosed)
|
|
21
|
+
t.true(compareVectors(updated.transforms, expected.transforms))
|
|
22
|
+
|
|
23
|
+
const updated2 = applyTransforms(updated)
|
|
24
|
+
t.is(updated, updated2)
|
|
25
|
+
t.true(comparePoints(updated2.vertices, expected.vertices))
|
|
26
|
+
t.false(updated2.isClosed)
|
|
27
|
+
t.true(compareVectors(updated2.transforms, expected.transforms))
|
|
28
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { EPS } from '../../maths/constants.js'
|
|
2
|
+
|
|
3
|
+
import * as vec3 from '../../maths/vec3/index.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Close the given geometry.
|
|
7
|
+
*
|
|
8
|
+
* @param {Path3} geometry - the path to close
|
|
9
|
+
* @returns {Path3} a new path
|
|
10
|
+
* @alias module:modeling/path3.close
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const newPath = path3.close(oldPath)
|
|
14
|
+
*/
|
|
15
|
+
export const close = (geometry) => {
|
|
16
|
+
if (geometry.isClosed) return geometry
|
|
17
|
+
|
|
18
|
+
const cloned = Object.assign({}, geometry)
|
|
19
|
+
cloned.isClosed = true
|
|
20
|
+
|
|
21
|
+
if (cloned.vertices.length > 1) {
|
|
22
|
+
// make sure the paths are formed properly
|
|
23
|
+
const vertices = cloned.vertices
|
|
24
|
+
const p0 = vertices[0]
|
|
25
|
+
let pn = vertices[vertices.length - 1]
|
|
26
|
+
while (vec3.distance(p0, pn) < (EPS * EPS)) {
|
|
27
|
+
vertices.pop()
|
|
28
|
+
if (vertices.length === 1) break
|
|
29
|
+
pn = vertices[vertices.length - 1]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return cloned
|
|
33
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import test from 'ava'
|
|
2
|
+
|
|
3
|
+
import { close, create, fromVertices } from './index.js'
|
|
4
|
+
|
|
5
|
+
test('close: closes an empty path', (t) => {
|
|
6
|
+
const p1 = create()
|
|
7
|
+
t.false(p1.isClosed)
|
|
8
|
+
|
|
9
|
+
const p2 = close(p1)
|
|
10
|
+
t.true(p2.isClosed)
|
|
11
|
+
t.not(p1, p2)
|
|
12
|
+
|
|
13
|
+
const p3 = close(p2)
|
|
14
|
+
t.true(p3.isClosed)
|
|
15
|
+
t.is(p2, p3)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('close: closes various paths', (t) => {
|
|
19
|
+
let p1 = create()
|
|
20
|
+
p1 = close(p1)
|
|
21
|
+
t.true(p1.isClosed)
|
|
22
|
+
t.is(0, p1.vertices.length)
|
|
23
|
+
|
|
24
|
+
let p2 = fromVertices({ closed: false }, [])
|
|
25
|
+
p2 = close(p2)
|
|
26
|
+
t.true(p2.isClosed)
|
|
27
|
+
t.is(0, p2.vertices.length)
|
|
28
|
+
|
|
29
|
+
let p3 = fromVertices({ closed: true }, [[0, 0, 0]])
|
|
30
|
+
p3 = close(p3)
|
|
31
|
+
t.true(p3.isClosed)
|
|
32
|
+
t.is(1, p3.vertices.length)
|
|
33
|
+
|
|
34
|
+
let p4 = fromVertices({ closed: true }, [[0, 0, 0], [0, 0, 0]])
|
|
35
|
+
p4 = close(p4)
|
|
36
|
+
t.true(p4.isClosed)
|
|
37
|
+
t.is(1, p4.vertices.length) // the last point is removed
|
|
38
|
+
|
|
39
|
+
let p5 = fromVertices({ closed: true }, [[0, 0, 0], [1, 1, 0], [0, 0, 0]])
|
|
40
|
+
p5 = close(p5)
|
|
41
|
+
t.true(p5.isClosed)
|
|
42
|
+
t.is(2, p5.vertices.length) // the last point is removed
|
|
43
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { equals } from '../../maths/vec3/index.js'
|
|
2
|
+
|
|
3
|
+
import { fromVertices } from './fromVertices.js'
|
|
4
|
+
import { toVertices } from './toVertices.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Concatenate the given paths.
|
|
8
|
+
*
|
|
9
|
+
* If both contain the same vertex at the junction, merge it into one.
|
|
10
|
+
* A concatenation of zero paths is an empty, open path.
|
|
11
|
+
* A concatenation of one closed path to a series of open paths produces a closed path.
|
|
12
|
+
* A concatenation of a path to a closed path is an error.
|
|
13
|
+
*
|
|
14
|
+
* @param {...Path3} paths - the paths to concatenate
|
|
15
|
+
* @returns {Path3} a new path
|
|
16
|
+
* @alias module:modeling/path3.concat
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* let newPath = path3.concat(path3.fromVertices({}, [[1, 2, 3]]), path3.fromVertices({}, [[4, 5, 6]]))
|
|
20
|
+
*/
|
|
21
|
+
export const concat = (...paths) => {
|
|
22
|
+
// Only the last path can be closed, producing a closed path.
|
|
23
|
+
let isClosed = false
|
|
24
|
+
let vertices = []
|
|
25
|
+
paths.forEach((path, i) => {
|
|
26
|
+
const tmp = toVertices(path).slice()
|
|
27
|
+
if (vertices.length > 0 && tmp.length > 0 && equals(tmp[0], vertices[vertices.length - 1])) tmp.shift()
|
|
28
|
+
if (tmp.length > 0 && isClosed) {
|
|
29
|
+
throw new Error(`Cannot concatenate to a closed path; check the ${i}th path`)
|
|
30
|
+
}
|
|
31
|
+
isClosed = path.isClosed
|
|
32
|
+
vertices = vertices.concat(tmp)
|
|
33
|
+
})
|
|
34
|
+
return fromVertices({ closed: isClosed }, vertices)
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import test from 'ava'
|
|
2
|
+
|
|
3
|
+
import { concat, equals, fromVertices } from './index.js'
|
|
4
|
+
|
|
5
|
+
test('concat: no paths produces an empty open path', (t) => {
|
|
6
|
+
t.true(equals(concat(), fromVertices({ closed: false }, [])))
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test('concat: empty paths produces an empty open path', (t) => {
|
|
10
|
+
t.true(equals(concat(fromVertices({}, []), fromVertices({}, [])), fromVertices({ closed: false }, [])))
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('concat: many open paths produces a open path', (t) => {
|
|
14
|
+
const p1 = fromVertices({ closed: false }, [[0, 0, 0]])
|
|
15
|
+
const p2 = fromVertices({ closed: false }, [[1, 1, 0]])
|
|
16
|
+
const p3 = fromVertices({ closed: false }, [[1, 1, 0], [3, 3, 0]])
|
|
17
|
+
|
|
18
|
+
const result = concat(p1, p2, p3)
|
|
19
|
+
t.true(equals(result, fromVertices({}, [[0, 0, 0], [1, 1, 0], [3, 3, 0]])))
|
|
20
|
+
t.is(p1.vertices.length, 1)
|
|
21
|
+
t.is(p2.vertices.length, 1)
|
|
22
|
+
t.is(p3.vertices.length, 2)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('concat: an open path and a closed path produces a closed path', (t) => {
|
|
26
|
+
t.true(equals(concat(fromVertices({ closed: false }, [[0, 0, 0]]),
|
|
27
|
+
fromVertices({ closed: true }, [[1, 1, 0]])),
|
|
28
|
+
fromVertices({ closed: true }, [[0, 0, 0], [1, 1, 0]])))
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('concat: a closed path and an open path throws an error', (t) => {
|
|
32
|
+
const p1 = fromVertices({ closed: true }, [[0, 0, 0]])
|
|
33
|
+
const p2 = fromVertices({ closed: false }, [[1, 1, 0]])
|
|
34
|
+
t.throws(() => concat(p1, p2), { message: 'Cannot concatenate to a closed path; check the 1th path' })
|
|
35
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as mat4 from '../../maths/mat4/index.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create an empty, open path.
|
|
5
|
+
*
|
|
6
|
+
* @param {Array} [vertices] - a list of vertices of which to create the path
|
|
7
|
+
* @returns {Path3} a new path
|
|
8
|
+
* @alias module:modeling/path3.create
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* let pathA = path3.create()
|
|
12
|
+
* let pathB = path3.create([[0,0,0], [4,0,0], [4,3,0]])
|
|
13
|
+
*/
|
|
14
|
+
export const create = (vertices = []) => ({ vertices: vertices, isClosed: false, transforms: mat4.create() })
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import test from 'ava'
|
|
2
|
+
|
|
3
|
+
import { create, equals, fromVertices } from './index.js'
|
|
4
|
+
|
|
5
|
+
test('create: Creates an empty path', (t) => {
|
|
6
|
+
t.true(equals(create(), fromVertices({ closed: false }, [])))
|
|
7
|
+
t.true(equals(create([[0, 0, 0], [1, 1, 1]]), fromVertices({ closed: false }, [[0, 0, 0], [1, 1, 1]])))
|
|
8
|
+
})
|