@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
|
@@ -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 vertices.
|
|
7
|
+
*
|
|
8
|
+
* @param {Array} uniqueVertices - list of vertices to construct convex 3D geometry
|
|
9
|
+
* @returns {geom3} a new geometry
|
|
10
|
+
* @alias module:modeling/geom3.fromVerticesConvex
|
|
11
|
+
*/
|
|
12
|
+
export const fromVerticesConvex = (uniqueVertices) => {
|
|
13
|
+
if (!Array.isArray(uniqueVertices)) {
|
|
14
|
+
throw new Error('the given vertices must be an array')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const faces = runner(uniqueVertices, { skipTriangulation: true })
|
|
18
|
+
|
|
19
|
+
const polygons = faces.map((face) => {
|
|
20
|
+
const vertices = face.map((index) => uniqueVertices[index])
|
|
21
|
+
return poly3.create(vertices)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
return create(polygons)
|
|
25
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { fromVerticesConvex, validate } from './index.js'
|
|
4
4
|
|
|
5
|
-
test('
|
|
5
|
+
test('fromVerticesConvex (uniqueVertices)', (t) => {
|
|
6
6
|
const out = []
|
|
7
7
|
for (let x = -9; x <= 9; ++x) {
|
|
8
8
|
for (let y = -9; y <= 9; ++y) {
|
|
@@ -14,7 +14,7 @@ test('fromPointsConvex (uniquePoints)', (t) => {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const obs =
|
|
17
|
+
const obs = fromVerticesConvex(out)
|
|
18
18
|
validate(obs)
|
|
19
19
|
t.is(obs.polygons.length, 170)
|
|
20
20
|
t.true(obs.polygons.every((f) => ([3, 4, 8, 9].indexOf(f.vertices.length) !== -1)))
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
export { clone } from './clone.js'
|
|
2
2
|
export { create } from './create.js'
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export { fromCompactBinary } from './fromCompactBinary.js'
|
|
3
|
+
export { fromVertices } from './fromVertices.js'
|
|
4
|
+
export { fromVerticesConvex } from './fromVerticesConvex.js'
|
|
6
5
|
export { invert } from './invert.js'
|
|
7
6
|
export { isA } from './isA.js'
|
|
8
|
-
export {
|
|
7
|
+
export { isConvex } from './isConvex.js'
|
|
9
8
|
export { toPolygons } from './toPolygons.js'
|
|
10
9
|
export { toString } from './toString.js'
|
|
11
|
-
export {
|
|
10
|
+
export { toVertices } from './toVertices.js'
|
|
12
11
|
export { transform } from './transform.js'
|
|
13
12
|
export { validate } from './validate.js'
|
|
14
13
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Represents a 3D geometry consisting of a list of polygons.
|
|
3
|
-
*
|
|
4
|
-
* @
|
|
3
|
+
*
|
|
4
|
+
* @see {@link Geom3} for data structure information
|
|
5
|
+
* @module modeling/geom3
|
|
5
6
|
*
|
|
6
7
|
* @example
|
|
7
|
-
* import {
|
|
8
|
-
* const myShape =
|
|
8
|
+
* import { geom3 } from '@jscad/modeling'
|
|
9
|
+
* const myShape = geom3.fromVertices([
|
|
9
10
|
* [[-1,-1,-1], [-1,-1,1], [-1,1,1], [-1,1,-1]],
|
|
10
11
|
* [[1,-1,-1], [1,1,-1], [1,1,1], [1,-1,1]],
|
|
11
12
|
* [[-1,-1,-1], [1,-1,-1], [1,-1,1], [-1,-1,1]]
|
|
@@ -14,16 +15,35 @@
|
|
|
14
15
|
* [[-1,-1,1], [1,-1,1], [1,1,1], [-1,1,1]]
|
|
15
16
|
* ])
|
|
16
17
|
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef Geom3
|
|
21
|
+
* @type {Object}
|
|
22
|
+
* @property {Array} polygons - list of polygons, each polygon containing three or more vertices
|
|
23
|
+
* @property {Mat4} transforms - transforms to apply to the polygons, see transform()
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* {
|
|
27
|
+
* "polygons": [
|
|
28
|
+
* {"vertices": [[-1,-1,-1], [-1,-1,1], [-1,1,1], [-1,1,-1]]},
|
|
29
|
+
* {"vertices": [[1,-1,-1], [1,1,-1], [1,1,1], [1,-1,1]]},
|
|
30
|
+
* {"vertices": [[-1,-1,-1], [1,-1,-1], [1,-1,1], [-1,-1,1]]},
|
|
31
|
+
* {"vertices": [[-1,1,-1], [-1,1,1], [1,1,1], [1,1,-1]]},
|
|
32
|
+
* {"vertices": [[-1,-1,-1], [-1,1,-1], [1,1,-1], [1,-1,-1]]},
|
|
33
|
+
* {"vertices": [[-1,-1,1], [1,-1,1], [1,1,1], [-1,1,1]]}
|
|
34
|
+
* ],
|
|
35
|
+
* "transforms": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],
|
|
36
|
+
* }
|
|
37
|
+
*/
|
|
17
38
|
export { clone } from './clone.js'
|
|
18
39
|
export { create } from './create.js'
|
|
19
|
-
export {
|
|
20
|
-
export {
|
|
21
|
-
export { fromCompactBinary } from './fromCompactBinary.js'
|
|
40
|
+
export { fromVertices } from './fromVertices.js'
|
|
41
|
+
export { fromVerticesConvex } from './fromVerticesConvex.js'
|
|
22
42
|
export { invert } from './invert.js'
|
|
23
43
|
export { isA } from './isA.js'
|
|
24
|
-
export {
|
|
44
|
+
export { isConvex } from './isConvex.js'
|
|
25
45
|
export { toPolygons } from './toPolygons.js'
|
|
26
46
|
export { toString } from './toString.js'
|
|
27
|
-
export {
|
|
47
|
+
export { toVertices } from './toVertices.js'
|
|
28
48
|
export { transform } from './transform.js'
|
|
29
49
|
export { validate } from './validate.js'
|
|
@@ -5,9 +5,13 @@ import { toPolygons } from './toPolygons.js'
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Invert the given geometry, transposing solid and empty space.
|
|
8
|
+
*
|
|
8
9
|
* @param {Geom3} geometry - the geometry to invert
|
|
9
10
|
* @returns {Geom3} a new geometry
|
|
10
|
-
* @alias module:modeling/
|
|
11
|
+
* @alias module:modeling/geom3.invert
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* let inverted = geom3.invert(geometry)
|
|
11
15
|
*/
|
|
12
16
|
export const invert = (geometry) => {
|
|
13
17
|
const polygons = toPolygons(geometry)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
-
import { invert, create,
|
|
3
|
+
import { invert, create, fromVertices } from './index.js'
|
|
4
4
|
|
|
5
5
|
import { comparePolygons, compareVectors } from '../../../test/helpers/index.js'
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ test('invert: Creates a invert of a populated geom3', (t) => {
|
|
|
23
23
|
],
|
|
24
24
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
25
25
|
}
|
|
26
|
-
const geometry =
|
|
26
|
+
const geometry = fromVertices(vertices)
|
|
27
27
|
const another = invert(geometry)
|
|
28
28
|
t.not(another, geometry)
|
|
29
29
|
t.true(comparePolygons(another.polygons[0], expected.polygons[0]))
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Determine if the given object is a 3D geometry.
|
|
3
|
+
*
|
|
3
4
|
* @param {object} object - the object to interrogate
|
|
4
5
|
* @returns {Boolean} true if the object matches a geom3
|
|
5
|
-
* @alias module:modeling/
|
|
6
|
+
* @alias module:modeling/geom3.isA
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* if (geom3.isA(geometry)) { ... }
|
|
6
10
|
*/
|
|
7
11
|
export const isA = (object) => {
|
|
8
12
|
if (object && typeof object === 'object') {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
-
import { isA, create,
|
|
3
|
+
import { isA, create, fromVertices } from './index.js'
|
|
4
4
|
|
|
5
5
|
test('isA: identifies created geom3', (t) => {
|
|
6
6
|
const p1 = create()
|
|
7
|
-
const p2 =
|
|
7
|
+
const p2 = fromVertices([[[0, 0, 0], [1, 0, 0], [1, 0, 1]]])
|
|
8
8
|
t.true(isA(p1))
|
|
9
9
|
t.true(isA(p2))
|
|
10
10
|
})
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { EPS } from '../../maths/constants.js'
|
|
2
|
+
import { dot } from '../../maths/vec3/dot.js'
|
|
3
|
+
import { plane } from '../poly3/plane.js'
|
|
4
|
+
|
|
5
|
+
import { isA } from './isA.js'
|
|
6
|
+
import { toPolygons } from './toPolygons.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Test if a 3D geometry is convex.
|
|
10
|
+
*
|
|
11
|
+
* A polyhedron is convex if every vertex lies on or behind every face plane
|
|
12
|
+
* (i.e., on the interior side of the plane).
|
|
13
|
+
*
|
|
14
|
+
* @param {geom3} geometry - the geometry to test
|
|
15
|
+
* @returns {boolean} true if the geometry is convex
|
|
16
|
+
* @alias module:modeling/geom3.isConvex
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const cube = cuboid()
|
|
20
|
+
* console.log(geom3.isConvex(cube)) // true
|
|
21
|
+
*/
|
|
22
|
+
export const isConvex = (geometry) => {
|
|
23
|
+
if (!isA(geometry)) {
|
|
24
|
+
throw new Error('isConvex requires a geom3 geometry')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const polygons = toPolygons(geometry)
|
|
28
|
+
|
|
29
|
+
if (polygons.length === 0) {
|
|
30
|
+
return true // Empty geometry is trivially convex
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Collect all unique vertices
|
|
34
|
+
const vertices = []
|
|
35
|
+
const found = new Set()
|
|
36
|
+
for (let i = 0; i < polygons.length; i++) {
|
|
37
|
+
const verts = polygons[i].vertices
|
|
38
|
+
for (let j = 0; j < verts.length; j++) {
|
|
39
|
+
const v = verts[j]
|
|
40
|
+
const key = `${v[0]},${v[1]},${v[2]}`
|
|
41
|
+
if (!found.has(key)) {
|
|
42
|
+
found.add(key)
|
|
43
|
+
vertices.push(v)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// For each face plane, check that all vertices are on or behind it
|
|
49
|
+
for (let i = 0; i < polygons.length; i++) {
|
|
50
|
+
const p = plane(polygons[i])
|
|
51
|
+
|
|
52
|
+
for (let j = 0; j < vertices.length; j++) {
|
|
53
|
+
const v = vertices[j]
|
|
54
|
+
// Distance from point to plane: dot(normal, point) - w
|
|
55
|
+
const distance = dot(p, v) - p[3]
|
|
56
|
+
|
|
57
|
+
// If any vertex is in front of any face (positive distance), not convex
|
|
58
|
+
if (distance > EPS) {
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import test from 'ava'
|
|
2
|
+
|
|
3
|
+
import { geom3, cylinderElliptic, sphere, cuboid, subtract } from '../../index.js'
|
|
4
|
+
|
|
5
|
+
test('isConvex: throws for non-geom3 input', (t) => {
|
|
6
|
+
t.throws(() => geom3.isConvex('invalid'), { message: /requires a geom3/ })
|
|
7
|
+
t.throws(() => geom3.isConvex(null), { message: /requires a geom3/ })
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test('isConvex: empty geometry is convex', (t) => {
|
|
11
|
+
const empty = geom3.create()
|
|
12
|
+
t.true(geom3.isConvex(empty))
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('isConvex: cuboid is convex', (t) => {
|
|
16
|
+
const cube = cuboid({ size: [10, 10, 10] })
|
|
17
|
+
t.true(geom3.isConvex(cube))
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('isConvex: sphere is convex', (t) => {
|
|
21
|
+
const sph = sphere({ radius: 5, segments: 16 })
|
|
22
|
+
t.true(geom3.isConvex(sph))
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('isConvex: cylinder is convex', (t) => {
|
|
26
|
+
const cyl = cylinderElliptic({ height: 10, startRadius: [3, 3], endRadius: [3, 3], segments: 16 })
|
|
27
|
+
t.true(geom3.isConvex(cyl))
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('isConvex: cube with hole is not convex', (t) => {
|
|
31
|
+
const cube = cuboid({ size: [10, 10, 10] })
|
|
32
|
+
const hole = cuboid({ size: [4, 4, 20] }) // Hole through the cube
|
|
33
|
+
|
|
34
|
+
const withHole = subtract(cube, hole)
|
|
35
|
+
t.false(geom3.isConvex(withHole))
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('isConvex: L-shaped solid is not convex', (t) => {
|
|
39
|
+
const big = cuboid({ size: [10, 10, 10], center: [0, 0, 0] })
|
|
40
|
+
const corner = cuboid({ size: [6, 6, 12], center: [3, 3, 0] })
|
|
41
|
+
|
|
42
|
+
const lShape = subtract(big, corner)
|
|
43
|
+
t.false(geom3.isConvex(lShape))
|
|
44
|
+
})
|
|
@@ -2,12 +2,14 @@ import { applyTransforms } from './applyTransforms.js'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Produces an array of polygons from the given geometry, after applying transforms.
|
|
5
|
+
*
|
|
5
6
|
* The returned array should not be modified as the polygons are shared with the geometry.
|
|
7
|
+
*
|
|
6
8
|
* @param {Geom3} geometry - the geometry
|
|
7
9
|
* @returns {Array} an array of polygons
|
|
8
|
-
* @alias module:modeling/
|
|
10
|
+
* @alias module:modeling/geom3.toPolygons
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
|
-
* let sharedPolygons = toPolygons(geometry)
|
|
13
|
+
* let sharedPolygons = geom3.toPolygons(geometry)
|
|
12
14
|
*/
|
|
13
15
|
export const toPolygons = (geometry) => applyTransforms(geometry).polygons
|
|
@@ -4,12 +4,13 @@ import { toPolygons } from './toPolygons.js'
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Create a string representing the contents of the given geometry.
|
|
7
|
+
*
|
|
7
8
|
* @param {Geom3} geometry - the geometry
|
|
8
9
|
* @returns {string} a representative string
|
|
9
|
-
* @alias module:modeling/
|
|
10
|
+
* @alias module:modeling/geom3.toString
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
|
-
* console.out(toString(geometry))
|
|
13
|
+
* console.out(geom3.toString(geometry))
|
|
13
14
|
*/
|
|
14
15
|
export const toString = (geometry) => {
|
|
15
16
|
const polygons = toPolygons(geometry)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
-
import { create,
|
|
3
|
+
import { create, fromVertices, toString } from './index.js'
|
|
4
4
|
|
|
5
5
|
test('toString: serialize empty geom3 into a string', (t) => {
|
|
6
6
|
const geometry = create()
|
|
@@ -10,7 +10,7 @@ test('toString: serialize empty geom3 into a string', (t) => {
|
|
|
10
10
|
})
|
|
11
11
|
|
|
12
12
|
test('toString: serialize geom3 into a string', (t) => {
|
|
13
|
-
const geometry =
|
|
13
|
+
const geometry = fromVertices([[[0, 0, 3], [0, 1, 3], [2, 0, 3]]])
|
|
14
14
|
const result = toString(geometry)
|
|
15
15
|
const expected = 'geom3 (1 polygons):\n poly3: [[0.0000000, 0.0000000, 3.0000000], [0.0000000, 1.0000000, 3.0000000], [2.0000000, 0.0000000, 3.0000000]]\n'
|
|
16
16
|
t.is(result, expected)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as poly3 from '../poly3/index.js'
|
|
2
|
+
|
|
3
|
+
import { toPolygons } from './toPolygons.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Return the given geometry as a list of vertices, after applying transforms.
|
|
7
|
+
*
|
|
8
|
+
* The returned array should not be modified as the vertices are shared with the geometry.
|
|
9
|
+
*
|
|
10
|
+
* @param {Geom3} geometry - the geometry
|
|
11
|
+
* @return {Array} list of vertices, where each sub-array represents a polygon
|
|
12
|
+
* @alias module:modeling/geom3.toVertices
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* let sharedVertices = geom3.toVertices(geometry)
|
|
16
|
+
*/
|
|
17
|
+
export const toVertices = (geometry) => {
|
|
18
|
+
const polygons = toPolygons(geometry)
|
|
19
|
+
return polygons.map((polygon) => poly3.toVertices(polygon))
|
|
20
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { toVertices, fromVertices, toString } from './index.js'
|
|
4
4
|
|
|
5
5
|
import { comparePolygonsAsPoints } from '../../../test/helpers/index.js'
|
|
6
6
|
|
|
7
|
-
test('
|
|
7
|
+
test('toVertices: Creates an array of vertices from a populated geom3', (t) => {
|
|
8
8
|
const vertices = [[[0, 0, 0], [1, 0, 0], [1, 0, 1]]]
|
|
9
|
-
const geometry =
|
|
9
|
+
const geometry = fromVertices(vertices)
|
|
10
10
|
|
|
11
11
|
toString(geometry)
|
|
12
12
|
|
|
13
13
|
const expected = [[[0, 0, 0], [1, 0, 0], [1, 0, 1]]]
|
|
14
|
-
const vertexList =
|
|
14
|
+
const vertexList = toVertices(geometry)
|
|
15
15
|
t.deepEqual(vertexList, expected)
|
|
16
16
|
t.true(comparePolygonsAsPoints(vertexList, expected))
|
|
17
17
|
|
|
@@ -2,15 +2,18 @@ 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 polygons, as this function only adjusts the transforms.
|
|
7
|
+
*
|
|
6
8
|
* See applyTransforms() for the actual application of the transforms to the polygons.
|
|
9
|
+
*
|
|
7
10
|
* @param {Mat4} matrix - the matrix to transform with
|
|
8
11
|
* @param {Geom3} geometry - the geometry to transform
|
|
9
12
|
* @returns {Geom3} a new geometry
|
|
10
|
-
* @alias module:modeling/
|
|
13
|
+
* @alias module:modeling/geom3.transform
|
|
11
14
|
*
|
|
12
15
|
* @example
|
|
13
|
-
* let newGeometry = transform(fromXRotation(TAU / 4), geometry)
|
|
16
|
+
* let newGeometry = geom3.transform(fromXRotation(TAU / 4), geometry)
|
|
14
17
|
*/
|
|
15
18
|
export const transform = (matrix, geometry) => {
|
|
16
19
|
const transforms = mat4.multiply(mat4.create(), matrix, geometry.transforms)
|
|
@@ -2,7 +2,7 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { mat4 } from '../../maths/index.js'
|
|
4
4
|
|
|
5
|
-
import { transform,
|
|
5
|
+
import { transform, fromVertices, toPolygons } from './index.js'
|
|
6
6
|
|
|
7
7
|
import { comparePolygons, compareVectors } from '../../../test/helpers/index.js'
|
|
8
8
|
|
|
@@ -20,7 +20,7 @@ test('transform: Adjusts the transforms of a populated geom3', (t) => {
|
|
|
20
20
|
],
|
|
21
21
|
transforms: [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
22
22
|
}
|
|
23
|
-
const geometry =
|
|
23
|
+
const geometry = fromVertices(vertices)
|
|
24
24
|
let another = transform(rotate90, geometry)
|
|
25
25
|
t.not(geometry, another)
|
|
26
26
|
t.true(comparePolygons(another.polygons[0], expected.polygons[0]))
|
|
@@ -4,13 +4,17 @@ import { isA } from './isA.js'
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Determine if the given object is a valid 3D geometry.
|
|
7
|
+
*
|
|
7
8
|
* Checks for valid data structure, convex polygon faces, and manifold edges.
|
|
8
9
|
*
|
|
9
|
-
* **If the geometry is not valid, an exception will be thrown with details of the geometry error.**
|
|
10
|
+
* **NOTE: 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/geom3.validate
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* if (geom3.validate(geometry)) { ... }
|
|
14
18
|
*/
|
|
15
19
|
export const validate = (object) => {
|
|
16
20
|
if (!isA(object)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
3
|
import * as vec3 from '../../maths/vec3/index.js'
|
|
4
|
-
import {
|
|
4
|
+
import { fromVertices, validate } from './index.js'
|
|
5
5
|
|
|
6
6
|
// tetrahedron
|
|
7
7
|
const a = vec3.fromValues(-1, -1, 1)
|
|
@@ -11,16 +11,16 @@ const d = vec3.fromValues(1, 1, 1)
|
|
|
11
11
|
|
|
12
12
|
test('validate: allow valid geom3', (t) => {
|
|
13
13
|
// simplest valid geometry
|
|
14
|
-
const geometry =
|
|
14
|
+
const geometry = fromVertices([[a, b, c], [d, b, a], [d, a, c], [c, b, d]])
|
|
15
15
|
t.notThrows(() => validate(geometry))
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
test('validate: throw exception for nan', (t) => {
|
|
19
|
-
const geometry =
|
|
19
|
+
const geometry = fromVertices([[a, b, c], [d, b, a], [d, a, c], [c, b, [1, 1, NaN]]])
|
|
20
20
|
t.throws(() => validate(geometry))
|
|
21
21
|
})
|
|
22
22
|
|
|
23
23
|
test('validate: throw exception for infinity', (t) => {
|
|
24
|
-
const geometry =
|
|
24
|
+
const geometry = fromVertices([[a, b, c], [d, b, a], [d, a, c], [c, b, [1, 1, Infinity]]])
|
|
25
25
|
t.throws(() => validate(geometry))
|
|
26
26
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * as geom2 from './geom2/index.js'
|
|
2
2
|
export * as geom3 from './geom3/index.js'
|
|
3
3
|
export * as path2 from './path2/index.js'
|
|
4
|
+
export * as path3 from './path3/index.js'
|
|
4
5
|
export * as poly2 from './poly2/index.js'
|
|
5
6
|
export * as poly3 from './poly3/index.js'
|
|
6
7
|
export * as slice from './slice/index.js'
|
package/src/geometries/index.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Geometries are objects that represent the contents of primitives or the results of operations.
|
|
3
|
+
*
|
|
3
4
|
* Note: Geometries are considered immutable, so never change the contents directly.
|
|
4
5
|
*
|
|
5
|
-
* @see {@link geom2} - 2D geometry consisting of 2D outlines
|
|
6
|
-
* @see {@link geom3} - 3D geometry consisting of polygons
|
|
7
|
-
* @see {@link path2} - 2D geometry consisting of ordered points
|
|
8
|
-
* @see {@link
|
|
9
|
-
* @see {@link
|
|
10
|
-
* @see {@link
|
|
6
|
+
* @see [Geom2]{@link module:modeling/geom2} - 2D geometry consisting of 2D outlines
|
|
7
|
+
* @see [Geom3]{@link module:modeling/geom3} - 3D geometry consisting of polygons
|
|
8
|
+
* @see [Path2]{@link module:modeling/path2} - 2D geometry consisting of ordered 2D points
|
|
9
|
+
* @see [Path3]{@link module:modeling/path3} - 3D geometry consisting of ordered 3D vertices
|
|
10
|
+
* @see [Poly2]{@link module:modeling/poly2} - 2D polygon consisting of 2D points
|
|
11
|
+
* @see [Poly3]{@link module:modeling/poly3} - 3D polygon consisting of 3D vertices
|
|
12
|
+
* @see [Slice]{@link module:modeling/slice} - 3D geometry consisting of 3D contours
|
|
13
|
+
* @alias module:modeling.geometry
|
|
11
14
|
*
|
|
12
|
-
* @module modeling/geometries
|
|
13
15
|
* @example
|
|
14
16
|
* import { geom2, geom3, path2, poly2, poly3, slice } from '@jscad/modeling'
|
|
15
17
|
*/
|
|
16
18
|
export * as geom2 from './geom2/index.js'
|
|
17
19
|
export * as geom3 from './geom3/index.js'
|
|
18
20
|
export * as path2 from './path2/index.js'
|
|
21
|
+
export * as path3 from './path3/index.js'
|
|
19
22
|
export * as poly2 from './poly2/index.js'
|
|
20
23
|
export * as poly3 from './poly3/index.js'
|
|
21
24
|
export * as slice from './slice/index.js'
|
|
@@ -6,8 +6,10 @@ import { toPoints } from './toPoints.js'
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Append a series of points to the given geometry that represent an arc.
|
|
9
|
+
*
|
|
9
10
|
* This implementation follows the SVG specifications.
|
|
10
11
|
* @see http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
|
12
|
+
*
|
|
11
13
|
* @param {object} options - options for construction
|
|
12
14
|
* @param {Vec2} options.endpoint - end point of arc (REQUIRED)
|
|
13
15
|
* @param {Vec2} [options.radius=[0,0]] - radius of arc (X and Y)
|
|
@@ -17,12 +19,12 @@ import { toPoints } from './toPoints.js'
|
|
|
17
19
|
* @param {number} [options.segments=16] - number of segments per full rotation
|
|
18
20
|
* @param {Path2} geometry - the path of which to append the arc
|
|
19
21
|
* @returns {Path2} a new path with the appended points
|
|
20
|
-
* @alias module:modeling/
|
|
22
|
+
* @alias module:modeling/path2.appendArc
|
|
21
23
|
*
|
|
22
24
|
* @example
|
|
23
|
-
* let myShape = fromPoints({}, [[27.5,-22.96875]]);
|
|
24
|
-
* myShape = appendPoints([[27.5,-3.28125]], myShape);
|
|
25
|
-
* myShape = appendArc({endpoint: [12.5, -22.96875], radius: [15, -19.6875]}, myShape);
|
|
25
|
+
* let myShape = path2.fromPoints({}, [[27.5,-22.96875]]);
|
|
26
|
+
* myShape = path2.appendPoints([[27.5,-3.28125]], myShape);
|
|
27
|
+
* myShape = path2.appendArc({endpoint: [12.5, -22.96875], radius: [15, -19.6875]}, myShape);
|
|
26
28
|
*/
|
|
27
29
|
export const appendArc = (options, geometry) => {
|
|
28
30
|
const defaults = {
|
|
@@ -120,7 +122,7 @@ export const appendArc = (options, geometry) => {
|
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
// Ok, we have the center point and angle range (from theta1, deltatheta radians) so we can create the ellipse
|
|
123
|
-
let numSteps = Math.
|
|
125
|
+
let numSteps = Math.floor(segments * (Math.abs(deltatheta) / TAU))
|
|
124
126
|
if (numSteps < 1) numSteps = 1
|
|
125
127
|
for (let step = 1; step < numSteps; step++) {
|
|
126
128
|
const theta = theta1 + step / numSteps * deltatheta
|
|
@@ -23,12 +23,12 @@ test('appendArc: appending to a path produces a new path', (t) => {
|
|
|
23
23
|
const p2 = fromPoints({}, [[27, -22], [27, -3]])
|
|
24
24
|
obs = appendArc({ endpoint: [12, -22], radius: [15, -20] }, p2)
|
|
25
25
|
pts = toPoints(obs)
|
|
26
|
-
t.is(pts.length,
|
|
26
|
+
t.is(pts.length, 5)
|
|
27
27
|
|
|
28
28
|
// test segments
|
|
29
29
|
obs = appendArc({ endpoint: [12, -22], radius: [15, -20], segments: 64 }, p2)
|
|
30
30
|
pts = toPoints(obs)
|
|
31
|
-
t.is(pts.length,
|
|
31
|
+
t.is(pts.length, 17)
|
|
32
32
|
|
|
33
33
|
// test clockwise
|
|
34
34
|
obs = appendArc({ endpoint: [12, -22], radius: [15, -20], clockwise: true }, p2)
|
|
@@ -36,19 +36,17 @@ test('appendArc: appending to a path produces a new path', (t) => {
|
|
|
36
36
|
let exp = [
|
|
37
37
|
[27, -22],
|
|
38
38
|
[27, -3],
|
|
39
|
-
[
|
|
40
|
-
[
|
|
41
|
-
[
|
|
42
|
-
[16.49674848226545, -21.0880050920699],
|
|
43
|
-
[11.999999999999998, -22]
|
|
39
|
+
[24.7485593841743, -12.579008396887021],
|
|
40
|
+
[19.29019838402471, -19.492932330409836],
|
|
41
|
+
[12, -22]
|
|
44
42
|
]
|
|
45
|
-
t.is(pts.length,
|
|
43
|
+
t.is(pts.length, 5)
|
|
46
44
|
t.true(comparePoints(pts, exp))
|
|
47
45
|
|
|
48
46
|
// test large
|
|
49
47
|
obs = appendArc({ endpoint: [12, -22], radius: [15, -20], large: true }, p2)
|
|
50
48
|
pts = toPoints(obs)
|
|
51
|
-
t.is(pts.length,
|
|
49
|
+
t.is(pts.length, 14)
|
|
52
50
|
|
|
53
51
|
// test xaxisRotation
|
|
54
52
|
obs = appendArc({ endpoint: [12, -22], radius: [15, -20], xaxisRotation: TAU / 4 }, p2)
|
|
@@ -56,14 +54,12 @@ test('appendArc: appending to a path produces a new path', (t) => {
|
|
|
56
54
|
exp = [
|
|
57
55
|
[27, -22],
|
|
58
56
|
[27, -3],
|
|
59
|
-
[
|
|
60
|
-
[17.364704977487236, -6.805886946199115],
|
|
57
|
+
[19.486852090983938, -5.488140907400943],
|
|
61
58
|
[13.940501387124588, -10.031143708098092],
|
|
62
|
-
[11.
|
|
63
|
-
[
|
|
64
|
-
[12, -22.000000000000004]
|
|
59
|
+
[11.296247566821858, -15.862906638006239],
|
|
60
|
+
[12, -22]
|
|
65
61
|
]
|
|
66
|
-
t.is(pts.length,
|
|
62
|
+
t.is(pts.length, 6)
|
|
67
63
|
t.true(comparePoints(pts, exp))
|
|
68
64
|
|
|
69
65
|
// test small arc between far points
|