@jscad/modeling 2.6.0 → 2.7.2
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 +56 -0
- package/dist/jscad-modeling.min.js +97 -94
- package/package.json +2 -2
- package/src/colors/colorize.js +35 -1
- package/src/colors/colorize.test.js +19 -4
- package/src/colors/hslToRgb.js +1 -1
- package/src/colors/hueToColorComponent.js +1 -0
- package/src/curves/bezier/create.js +3 -8
- package/src/curves/bezier/tangentAt.js +2 -2
- package/src/curves/index.js +1 -1
- package/src/geometries/geom2/clone.js +2 -12
- package/src/geometries/geom2/toOutlines.js +6 -11
- package/src/geometries/geom2/transform.js +0 -2
- package/src/geometries/geom3/clone.js +2 -14
- package/src/geometries/geom3/clone.test.js +0 -2
- package/src/geometries/geom3/create.js +1 -3
- package/src/geometries/geom3/create.test.js +0 -2
- package/src/geometries/geom3/fromCompactBinary.js +4 -6
- package/src/geometries/geom3/fromToCompactBinary.test.js +0 -6
- package/src/geometries/geom3/invert.js +2 -2
- package/src/geometries/geom3/invert.test.js +0 -2
- package/src/geometries/geom3/toCompactBinary.js +8 -10
- package/src/geometries/geom3/toPoints.js +1 -0
- package/src/geometries/geom3/transform.js +0 -2
- package/src/geometries/geom3/transform.test.js +0 -1
- package/src/geometries/geom3/type.d.ts +0 -1
- package/src/geometries/path2/clone.js +2 -13
- package/src/geometries/path2/transform.js +0 -2
- package/src/geometries/poly3/isConvex.js +1 -1
- package/src/geometries/poly3/measureArea.js +12 -13
- package/src/geometries/poly3/measureArea.test.js +15 -0
- package/src/geometries/poly3/plane.js +1 -2
- package/src/maths/line3/create.js +2 -1
- package/src/maths/mat4/fromRotation.js +1 -1
- package/src/maths/mat4/isIdentity.test.js +0 -2
- package/src/maths/mat4/isOnlyTransformScale.js +5 -4
- package/src/maths/mat4/rotate.js +1 -1
- package/src/maths/plane/fromPoints.js +32 -10
- package/src/maths/plane/fromPoints.test.js +4 -0
- package/src/maths/vec2/length.test.js +10 -0
- package/src/maths/vec3/angle.js +2 -2
- package/src/maths/vec3/angle.test.js +17 -0
- package/src/maths/vec3/length.test.js +10 -0
- package/src/measurements/measureBoundingBox.js +37 -121
- package/src/measurements/measureBoundingBox.test.js +8 -0
- package/src/measurements/measureCenterOfMass.js +0 -1
- package/src/measurements/measureEpsilon.js +3 -9
- package/src/operations/booleans/reTesselateCoplanarPolygons.js +1 -1
- package/src/operations/booleans/retessellate.js +1 -3
- package/src/operations/booleans/trees/PolygonTreeNode.js +0 -1
- package/src/operations/expansions/expand.js +2 -0
- package/src/operations/expansions/expand.test.js +1 -1
- package/src/operations/expansions/offset.js +1 -0
- package/src/operations/extrusions/extrudeLinear.js +1 -1
- package/src/operations/extrusions/extrudeRectangular.js +2 -1
- package/src/operations/extrusions/extrudeRotate.test.js +18 -10
- package/src/operations/hulls/quickhull/QuickHull.js +2 -2
- package/src/operations/modifiers/edges.js +1 -3
- package/src/operations/modifiers/generalize.js +3 -7
- package/src/operations/modifiers/snapPolygons.js +2 -2
- package/src/operations/modifiers/snapPolygons.test.js +13 -5
- package/src/operations/transforms/mirror.js +1 -1
- package/src/primitives/ellipse.js +1 -1
- package/src/primitives/geodesicSphere.js +2 -2
- package/src/primitives/index.d.ts +1 -0
- package/src/primitives/index.js +2 -1
- package/src/primitives/roundedCylinder.js +1 -1
- package/src/primitives/triangle.d.ts +10 -0
- package/src/primitives/triangle.js +164 -0
- package/src/primitives/triangle.test.js +95 -0
- package/src/utils/insertSorted.js +1 -0
- package/test/helpers/comparePolygons.js +1 -3
- package/test/helpers/nearlyEqual.js +2 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/modeling",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.2",
|
|
4
4
|
"description": "Constructive Solid Geometry (CSG) Library for JSCAD",
|
|
5
5
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"nyc": "15.1.0",
|
|
61
61
|
"uglifyify": "5.0.2"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "b6c5675d2d9a292e0ba24896bf22d0e9dc5d4270"
|
|
64
64
|
}
|
package/src/colors/colorize.js
CHANGED
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
const flatten = require('../utils/flatten')
|
|
2
2
|
|
|
3
|
+
const geom2 = require('../geometries/geom2')
|
|
4
|
+
const geom3 = require('../geometries/geom3')
|
|
5
|
+
const path2 = require('../geometries/path2')
|
|
6
|
+
const poly3 = require('../geometries/poly3')
|
|
7
|
+
|
|
8
|
+
const colorGeom2 = (color, object) => {
|
|
9
|
+
const newgeom2 = geom2.clone(object)
|
|
10
|
+
newgeom2.color = color
|
|
11
|
+
return newgeom2
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const colorGeom3 = (color, object) => {
|
|
15
|
+
const newgeom3 = geom3.clone(object)
|
|
16
|
+
newgeom3.color = color
|
|
17
|
+
return newgeom3
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const colorPath2 = (color, object) => {
|
|
21
|
+
const newpath2 = path2.clone(object)
|
|
22
|
+
newpath2.color = color
|
|
23
|
+
return newpath2
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const colorPoly3 = (color, object) => {
|
|
27
|
+
const newpoly = poly3.clone(object)
|
|
28
|
+
newpoly.color = color
|
|
29
|
+
return newpoly
|
|
30
|
+
}
|
|
31
|
+
|
|
3
32
|
/**
|
|
4
33
|
* Assign the given color to the given objects.
|
|
5
34
|
* @param {Array} color - RGBA color values, where each value is between 0 and 1.0
|
|
6
35
|
* @param {Object|Array} objects - the objects of which to apply the given color
|
|
7
|
-
* @return {Object|Array}
|
|
36
|
+
* @return {Object|Array} new object, or list of new objects with an additional attribute 'color'
|
|
8
37
|
* @alias module:modeling/colors.colorize
|
|
9
38
|
*
|
|
10
39
|
* @example
|
|
@@ -22,6 +51,11 @@ const colorize = (color, ...objects) => {
|
|
|
22
51
|
if (objects.length === 0) throw new Error('wrong number of arguments')
|
|
23
52
|
|
|
24
53
|
const results = objects.map((object) => {
|
|
54
|
+
if (geom2.isA(object)) return colorGeom2(color, object)
|
|
55
|
+
if (geom3.isA(object)) return colorGeom3(color, object)
|
|
56
|
+
if (path2.isA(object)) return colorPath2(color, object)
|
|
57
|
+
if (poly3.isA(object)) return colorPoly3(color, object)
|
|
58
|
+
|
|
25
59
|
object.color = color
|
|
26
60
|
return object
|
|
27
61
|
})
|
|
@@ -43,15 +43,30 @@ test('color (rgba on geometry)', (t) => {
|
|
|
43
43
|
const obs = colorize([1, 1, 0.5, 0.8], obj0, obj1, obj2, obj3)
|
|
44
44
|
t.is(obs.length, 4)
|
|
45
45
|
|
|
46
|
-
t.
|
|
46
|
+
t.not(obj0, obs[0])
|
|
47
47
|
t.deepEqual(obs[0].color, [1, 1, 0.5, 0.8])
|
|
48
48
|
|
|
49
|
-
t.
|
|
49
|
+
t.not(obj1, obs[1])
|
|
50
50
|
t.deepEqual(obs[1].color, [1, 1, 0.5, 0.8])
|
|
51
51
|
|
|
52
|
-
t.
|
|
52
|
+
t.not(obj2, obs[2])
|
|
53
53
|
t.deepEqual(obs[2].color, [1, 1, 0.5, 0.8])
|
|
54
54
|
|
|
55
|
-
t.
|
|
55
|
+
t.not(obj3, obs[3])
|
|
56
56
|
t.deepEqual(obs[3].color, [1, 1, 0.5, 0.8])
|
|
57
57
|
})
|
|
58
|
+
|
|
59
|
+
test('color (returns new object)', (t) => {
|
|
60
|
+
const obj0 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
61
|
+
// const obj1 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
62
|
+
// const obj2 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
63
|
+
const obj3 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
64
|
+
|
|
65
|
+
const obs = colorize([1, 1, 1, 0.8], obj0, obj3)
|
|
66
|
+
t.not(obj0, obs[0])
|
|
67
|
+
t.deepEqual(obs[0].color, [1, 1, 1, 0.8])
|
|
68
|
+
t.is(obj0.color, undefined)
|
|
69
|
+
t.not(obj3, obs[1])
|
|
70
|
+
t.deepEqual(obs[1].color, [1, 1, 1, 0.8])
|
|
71
|
+
t.is(obj3.color, undefined)
|
|
72
|
+
})
|
package/src/colors/hslToRgb.js
CHANGED
|
@@ -5,7 +5,7 @@ const hueToColorComponent = require('./hueToColorComponent')
|
|
|
5
5
|
/**
|
|
6
6
|
* Converts HSL color values to RGB color values.
|
|
7
7
|
*
|
|
8
|
-
* @see http://en.wikipedia.org/wiki/HSL_color_space
|
|
8
|
+
* @see http://en.wikipedia.org/wiki/HSL_color_space
|
|
9
9
|
* @param {...Number|Array} values - HSL or HSLA color values
|
|
10
10
|
* @return {Array} RGB or RGBA color values
|
|
11
11
|
* @alias module:modeling/colors.hslToRgb
|
|
@@ -7,14 +7,6 @@
|
|
|
7
7
|
* @property {Array} permutations - A pre-calculation of the bezier algorithm's co-efficients
|
|
8
8
|
* @property {Array} tangentPermutations - A pre-calculation of the bezier algorithm's tangent co-efficients
|
|
9
9
|
*
|
|
10
|
-
* @example
|
|
11
|
-
* const b = bezier.create([0,10]) // a linear progression from 0 to 10
|
|
12
|
-
* const b = bezier.create([0, 0, 10, 10]) // a symmetrical cubic easing curve that starts slowly and ends slowly from 0 to 10
|
|
13
|
-
* const b = bezier.create([0,0,0], [0,5,10], [10,0,-5], [10,10,10]]) // a cubic 3 dimensional easing curve that can generate position arrays for modelling
|
|
14
|
-
* Usage:
|
|
15
|
-
* let position = bezier.valueAt(t,b) // where 0 < t < 1
|
|
16
|
-
* let tangent = bezier.tangentAt(t,b) // where 0 < t < 1
|
|
17
|
-
*
|
|
18
10
|
*/
|
|
19
11
|
|
|
20
12
|
/**
|
|
@@ -25,6 +17,9 @@
|
|
|
25
17
|
* const b = bezier.create([0,10]) // a linear progression from 0 to 10
|
|
26
18
|
* const b = bezier.create([0, 0, 10, 10]) // a symmetrical cubic easing curve that starts slowly and ends slowly from 0 to 10
|
|
27
19
|
* const b = bezier.create([0,0,0], [0,5,10], [10,0,-5], [10,10,10]]) // a cubic 3 dimensional easing curve that can generate position arrays for modelling
|
|
20
|
+
* // Usage
|
|
21
|
+
* let position = bezier.valueAt(t,b) // where 0 < t < 1
|
|
22
|
+
* let tangent = bezier.tangentAt(t,b) // where 0 < t < 1
|
|
28
23
|
*
|
|
29
24
|
* @param {Array} points An array with at least 2 elements of either all numbers, or all arrays of numbers that are the same size.
|
|
30
25
|
* @returns {bezier} a new bezier data object
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* See the example called extrudeAlongPath.js
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
|
-
* const b = bezier.create([0,0,0], [0,5,10], [10,0,-5], [10,10,10]]) // a cubic 3 dimensional easing curve that can generate position arrays for modelling
|
|
7
|
+
* const b = bezier.create([[0,0,0], [0,5,10], [10,0,-5], [10,10,10]]) // a cubic 3 dimensional easing curve that can generate position arrays for modelling
|
|
8
8
|
* let tangent = bezier.tangentAt(t, b)
|
|
9
9
|
*
|
|
10
10
|
* @param {number} t : the position of which to calculate the bezier's tangent value; 0 < t < 1
|
|
11
11
|
* @param {Object} bezier : an array with at least 2 elements of either all numbers, or all arrays of numbers that are the same size.
|
|
12
|
-
* @
|
|
12
|
+
* @return {array | number} the tangent at the requested position.
|
|
13
13
|
* @alias module:modeling/curves/bezier.tangentAt
|
|
14
14
|
*/
|
|
15
15
|
const tangentAt = (t, bezier) => {
|
package/src/curves/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Curves are n-dimensional mathematical constructs that define a path from point 0 to point 1
|
|
2
|
+
* Curves are n-dimensional mathematical constructs that define a path from point 0 to point 1.
|
|
3
3
|
* @module modeling/curves
|
|
4
4
|
* @example
|
|
5
5
|
* const { bezier } = require('@jscad/modeling').curves
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
const mat4 = require('../../maths/mat4')
|
|
2
|
-
const vec2 = require('../../maths/vec2')
|
|
3
|
-
|
|
4
|
-
const create = require('./create')
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
|
-
* Performs a
|
|
2
|
+
* Performs a shallow clone of the given geometry.
|
|
8
3
|
* @param {geom2} geometry - the geometry to clone
|
|
9
4
|
* @returns {geom2} new geometry
|
|
10
5
|
* @alias module:modeling/geometries/geom2.clone
|
|
11
6
|
*/
|
|
12
|
-
const clone = (geometry) => {
|
|
13
|
-
const out = create()
|
|
14
|
-
out.sides = geometry.sides.map((side) => [vec2.clone(side[0]), vec2.clone(side[1])])
|
|
15
|
-
out.transforms = mat4.clone(geometry.transforms)
|
|
16
|
-
return out
|
|
17
|
-
}
|
|
7
|
+
const clone = (geometry) => Object.assign({}, geometry)
|
|
18
8
|
|
|
19
9
|
module.exports = clone
|
|
@@ -7,21 +7,16 @@ const toSides = require('./toSides')
|
|
|
7
7
|
* This allows the edges to be traversed in order.
|
|
8
8
|
*/
|
|
9
9
|
const toEdges = (sides) => {
|
|
10
|
-
const
|
|
10
|
+
const vertices = {}
|
|
11
11
|
const getUniqueVertex = (vertex) => {
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
return vertex
|
|
12
|
+
const key = vertex.toString()
|
|
13
|
+
if (!vertices[key]) {
|
|
14
|
+
vertices[key] = vertex
|
|
16
15
|
}
|
|
17
|
-
return
|
|
16
|
+
return vertices[key]
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
sides.forEach((side) => {
|
|
22
|
-
edges.push([getUniqueVertex(side[0]), getUniqueVertex(side[1])])
|
|
23
|
-
})
|
|
24
|
-
return edges
|
|
19
|
+
return sides.map((side) => side.map(getUniqueVertex))
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
/**
|
|
@@ -1,21 +1,9 @@
|
|
|
1
|
-
const mat4 = require('../../maths/mat4')
|
|
2
|
-
|
|
3
|
-
const poly3 = require('../poly3')
|
|
4
|
-
|
|
5
|
-
const create = require('./create')
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
|
-
* Performs a
|
|
2
|
+
* Performs a shallow clone of the given geometry.
|
|
9
3
|
* @param {geom3} geometry - the geometry to clone
|
|
10
4
|
* @returns {geom3} a new geometry
|
|
11
5
|
* @alias module:modeling/geometries/geom3.clone
|
|
12
6
|
*/
|
|
13
|
-
const clone = (geometry) => {
|
|
14
|
-
const out = create()
|
|
15
|
-
out.polygons = geometry.polygons.map((polygon) => poly3.clone(polygon))
|
|
16
|
-
out.isRetesselated = geometry.isRetesselated
|
|
17
|
-
out.transforms = mat4.clone(geometry.transforms)
|
|
18
|
-
return out
|
|
19
|
-
}
|
|
7
|
+
const clone = (geometry) => Object.assign({}, geometry)
|
|
20
8
|
|
|
21
9
|
module.exports = clone
|
|
@@ -7,7 +7,6 @@ const { comparePolygons, compareVectors } = require('../../../test/helpers/')
|
|
|
7
7
|
test('clone: Creates a clone on an empty geom3', (t) => {
|
|
8
8
|
const expected = {
|
|
9
9
|
polygons: [],
|
|
10
|
-
isRetesselated: false,
|
|
11
10
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
12
11
|
}
|
|
13
12
|
const geometry = create()
|
|
@@ -22,7 +21,6 @@ test('clone: Creates a clone of a populated geom3', (t) => {
|
|
|
22
21
|
polygons: [
|
|
23
22
|
{ vertices: [[0, 0, 0], [1, 0, 0], [1, 0, 1]] }
|
|
24
23
|
],
|
|
25
|
-
isRetesselated: false,
|
|
26
24
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
27
25
|
}
|
|
28
26
|
const geometry = fromPoints(points)
|
|
@@ -4,8 +4,7 @@ const mat4 = require('../../maths/mat4')
|
|
|
4
4
|
* Represents a 3D geometry consisting of a list of polygons.
|
|
5
5
|
* @typedef {Object} geom3
|
|
6
6
|
* @property {Array} polygons - list of polygons, each polygon containing three or more points
|
|
7
|
-
* @property {
|
|
8
|
-
* @property {mat4} transforms - transforms to apply to the sides, see transform()
|
|
7
|
+
* @property {mat4} transforms - transforms to apply to the polygons, see transform()
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -20,7 +19,6 @@ const create = (polygons) => {
|
|
|
20
19
|
}
|
|
21
20
|
return {
|
|
22
21
|
polygons: polygons,
|
|
23
|
-
isRetesselated: false,
|
|
24
22
|
transforms: mat4.create()
|
|
25
23
|
}
|
|
26
24
|
}
|
|
@@ -7,7 +7,6 @@ const { create } = require('./index')
|
|
|
7
7
|
test('create: Creates an empty geom3', (t) => {
|
|
8
8
|
const expected = {
|
|
9
9
|
polygons: [],
|
|
10
|
-
isRetesselated: false,
|
|
11
10
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
12
11
|
}
|
|
13
12
|
t.deepEqual(create(), expected)
|
|
@@ -20,7 +19,6 @@ test('create: Creates a populated geom3', (t) => {
|
|
|
20
19
|
const polygons = [polygon]
|
|
21
20
|
const expected = {
|
|
22
21
|
polygons: polygons,
|
|
23
|
-
isRetesselated: false,
|
|
24
22
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
25
23
|
}
|
|
26
24
|
t.deepEqual(create(polygons), expected)
|
|
@@ -18,10 +18,8 @@ const fromCompactBinary = (data) => {
|
|
|
18
18
|
|
|
19
19
|
created.transforms = mat4.clone(data.slice(1, 17))
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const numberOfVertices = data[22]
|
|
24
|
-
let ci = 23
|
|
21
|
+
const numberOfVertices = data[21]
|
|
22
|
+
let ci = 22
|
|
25
23
|
let vi = data.length - (numberOfVertices * 3)
|
|
26
24
|
while (vi < data.length) {
|
|
27
25
|
const verticesPerPolygon = data[ci]
|
|
@@ -36,8 +34,8 @@ const fromCompactBinary = (data) => {
|
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
// transfer known properities, i.e. color
|
|
39
|
-
if (data[
|
|
40
|
-
created.color = [data[
|
|
37
|
+
if (data[17] >= 0) {
|
|
38
|
+
created.color = [data[17], data[18], data[19], data[20]]
|
|
41
39
|
}
|
|
42
40
|
// TODO: how about custom properties or fields ?
|
|
43
41
|
return created
|
|
@@ -12,7 +12,6 @@ test('toCompactBinary: converts geom3 (default)', (t) => {
|
|
|
12
12
|
0, 1, 0, 0,
|
|
13
13
|
0, 0, 1, 0,
|
|
14
14
|
0, 0, 0, 1,
|
|
15
|
-
0, // isRetesselated flag
|
|
16
15
|
-1, -1, -1, -1, // color
|
|
17
16
|
0 // number of vertices
|
|
18
17
|
]
|
|
@@ -32,7 +31,6 @@ test('toCompactBinary: converts geom3 into a compact form', (t) => {
|
|
|
32
31
|
0, 1, 0, 0,
|
|
33
32
|
0, 0, 1, 0,
|
|
34
33
|
0, 0, 0, 1,
|
|
35
|
-
0, // isRetesselated flag
|
|
36
34
|
-1, -1, -1, -1, // color
|
|
37
35
|
7, // number of vertices
|
|
38
36
|
3, // number of vertices per polygon (2)
|
|
@@ -59,7 +57,6 @@ test('toCompactBinary: converts geom3 into a compact form', (t) => {
|
|
|
59
57
|
0, 1, 0, 0,
|
|
60
58
|
0, 0, 1, 0,
|
|
61
59
|
0, 0, 0, 1,
|
|
62
|
-
0, // isRetesselated flag
|
|
63
60
|
1, 2, 3, 4, // color
|
|
64
61
|
7, // number of vertices
|
|
65
62
|
3, // number of vertices per polygon (2)
|
|
@@ -84,7 +81,6 @@ test('fromCompactBinary: convert a compact form into a geom3', (t) => {
|
|
|
84
81
|
0, 1, 0, 0,
|
|
85
82
|
0, 0, 1, 0,
|
|
86
83
|
0, 0, 0, 1,
|
|
87
|
-
0, // isRetesselated flag
|
|
88
84
|
-1, -1, -1, -1, // color
|
|
89
85
|
0 // number of vertices
|
|
90
86
|
]
|
|
@@ -99,7 +95,6 @@ test('fromCompactBinary: convert a compact form into a geom3', (t) => {
|
|
|
99
95
|
0, 1, 0, 0,
|
|
100
96
|
0, 0, 1, 0,
|
|
101
97
|
0, 0, 0, 1,
|
|
102
|
-
0, // isRetesselated flag
|
|
103
98
|
-1, -1, -1, -1, // color
|
|
104
99
|
7, // number of vertices
|
|
105
100
|
3, // number of vertices per polygon (2)
|
|
@@ -125,7 +120,6 @@ test('fromCompactBinary: convert a compact form into a geom3', (t) => {
|
|
|
125
120
|
0, 1, 0, 0,
|
|
126
121
|
0, 0, 1, 0,
|
|
127
122
|
0, 0, 0, 1,
|
|
128
|
-
0, // isRetesselated flag
|
|
129
123
|
4, 5, 6, 7, // color
|
|
130
124
|
7, // number of vertices
|
|
131
125
|
3, // number of vertices per polygon (2)
|
|
@@ -5,8 +5,8 @@ const toPolygons = require('./toPolygons')
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Invert the given geometry, transposing solid and empty space.
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
8
|
+
* @param {geom3} geometry - the geometry to invert
|
|
9
|
+
* @return {geom3} a new geometry
|
|
10
10
|
* @alias module:modeling/geometries/geom3.invert
|
|
11
11
|
*/
|
|
12
12
|
const invert = (geometry) => {
|
|
@@ -7,7 +7,6 @@ const { comparePolygons, compareVectors } = require('../../../test/helpers/')
|
|
|
7
7
|
test('invert: Creates a invert on an empty geom3', (t) => {
|
|
8
8
|
const expected = {
|
|
9
9
|
polygons: [],
|
|
10
|
-
isRetesselated: false,
|
|
11
10
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
12
11
|
}
|
|
13
12
|
const geometry = create()
|
|
@@ -22,7 +21,6 @@ test('invert: Creates a invert of a populated geom3', (t) => {
|
|
|
22
21
|
polygons: [
|
|
23
22
|
{ vertices: [[1, 0, 1], [1, 0, 0], [0, 0, 0]] }
|
|
24
23
|
],
|
|
25
|
-
isRetesselated: false,
|
|
26
24
|
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
27
25
|
}
|
|
28
26
|
const geometry = fromPoints(points)
|
|
@@ -16,8 +16,8 @@ const toCompactBinary = (geom) => {
|
|
|
16
16
|
if (geom.color) color = geom.color
|
|
17
17
|
|
|
18
18
|
// FIXME why Float32Array?
|
|
19
|
-
const compacted = new Float32Array(1 + 16 +
|
|
20
|
-
// type + transforms +
|
|
19
|
+
const compacted = new Float32Array(1 + 16 + 4 + 1 + numberOfPolygons + (numberOfVertices * 3))
|
|
20
|
+
// type + transforms + color + numberOfPolygons + numberOfVerticesPerPolygon[] + vertices data[]
|
|
21
21
|
|
|
22
22
|
compacted[0] = 1 // type code: 0 => geom2, 1 => geom3 , 2 => path2
|
|
23
23
|
|
|
@@ -38,16 +38,14 @@ const toCompactBinary = (geom) => {
|
|
|
38
38
|
compacted[15] = transforms[14]
|
|
39
39
|
compacted[16] = transforms[15]
|
|
40
40
|
|
|
41
|
-
compacted[17] =
|
|
41
|
+
compacted[17] = color[0]
|
|
42
|
+
compacted[18] = color[1]
|
|
43
|
+
compacted[19] = color[2]
|
|
44
|
+
compacted[20] = color[3]
|
|
42
45
|
|
|
43
|
-
compacted[
|
|
44
|
-
compacted[19] = color[1]
|
|
45
|
-
compacted[20] = color[2]
|
|
46
|
-
compacted[21] = color[3]
|
|
46
|
+
compacted[21] = numberOfVertices
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
let ci = 23
|
|
48
|
+
let ci = 22
|
|
51
49
|
let vi = ci + numberOfPolygons
|
|
52
50
|
polygons.forEach((polygon) => {
|
|
53
51
|
const points = poly3.toPoints(polygon)
|
|
@@ -5,6 +5,7 @@ const toPolygons = require('./toPolygons')
|
|
|
5
5
|
/**
|
|
6
6
|
* Return the given geometry as a list of points, after applying transforms.
|
|
7
7
|
* The returned array should not be modified as the points are shared with the geometry.
|
|
8
|
+
* @param {geom3} geometry - the geometry
|
|
8
9
|
* @return {Array} list of points, where each sub-array represents a polygon
|
|
9
10
|
* @alias module:modeling/geometries/geom3.toPoints
|
|
10
11
|
*/
|
|
@@ -18,7 +18,6 @@ test('transform: Adjusts the transforms of a populated geom3', (t) => {
|
|
|
18
18
|
polygons: [
|
|
19
19
|
{ vertices: [[0, 0, 0], [1, 0, 0], [1, 0, 1]] }
|
|
20
20
|
],
|
|
21
|
-
isRetesselated: false,
|
|
22
21
|
transforms: [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
|
23
22
|
}
|
|
24
23
|
const geometry = fromPoints(points)
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
const mat4 = require('../../maths/mat4')
|
|
2
|
-
const vec2 = require('../../maths/vec2')
|
|
3
|
-
|
|
4
|
-
const create = require('./create')
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
|
-
* Performs a
|
|
2
|
+
* Performs a shallow clone of the give geometry.
|
|
8
3
|
* @param {path2} geometry - the geometry to clone
|
|
9
4
|
* @returns {path2} a new path
|
|
10
5
|
* @alias module:modeling/geometries/path2.clone
|
|
11
6
|
*/
|
|
12
|
-
const clone = (geometry) => {
|
|
13
|
-
const out = create()
|
|
14
|
-
out.points = geometry.points.map((point) => vec2.clone(point))
|
|
15
|
-
out.isClosed = geometry.isClosed
|
|
16
|
-
out.transforms = mat4.clone(geometry.transforms)
|
|
17
|
-
return out
|
|
18
|
-
}
|
|
7
|
+
const clone = (geometry) => Object.assign({}, geometry)
|
|
19
8
|
|
|
20
9
|
module.exports = clone
|
|
@@ -13,7 +13,7 @@ const areVerticesConvex = (vertices) => {
|
|
|
13
13
|
const numvertices = vertices.length
|
|
14
14
|
if (numvertices > 2) {
|
|
15
15
|
// note: plane ~= normal point
|
|
16
|
-
const normal = plane.fromPoints(plane.create(), vertices
|
|
16
|
+
const normal = plane.fromPoints(plane.create(), ...vertices)
|
|
17
17
|
let prevprevpos = vertices[numvertices - 2]
|
|
18
18
|
let prevpos = vertices[numvertices - 1]
|
|
19
19
|
for (let i = 0; i < numvertices; i++) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const plane = require('./plane')
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Measure the area of the given polygon.
|
|
@@ -14,19 +14,18 @@ const measureArea = (poly3) => {
|
|
|
14
14
|
}
|
|
15
15
|
const vertices = poly3.vertices
|
|
16
16
|
|
|
17
|
-
// calculate a
|
|
18
|
-
const
|
|
19
|
-
const b = vertices[1]
|
|
20
|
-
const c = vertices[2]
|
|
21
|
-
const ba = vec3.subtract(vec3.create(), b, a)
|
|
22
|
-
const ca = vec3.subtract(vec3.create(), c, a)
|
|
23
|
-
const normal = vec3.cross(ba, ba, ca)
|
|
17
|
+
// calculate a normal vector
|
|
18
|
+
const normal = plane(poly3)
|
|
24
19
|
|
|
25
|
-
//
|
|
20
|
+
// determine direction of projection
|
|
26
21
|
const ax = Math.abs(normal[0])
|
|
27
22
|
const ay = Math.abs(normal[1])
|
|
28
23
|
const az = Math.abs(normal[2])
|
|
29
|
-
|
|
24
|
+
|
|
25
|
+
if (ax + ay + az === 0) {
|
|
26
|
+
// normal does not exist
|
|
27
|
+
return 0
|
|
28
|
+
}
|
|
30
29
|
|
|
31
30
|
let coord = 3 // ignore Z coordinates
|
|
32
31
|
if ((ax > ay) && (ax > az)) {
|
|
@@ -50,7 +49,7 @@ const measureArea = (poly3) => {
|
|
|
50
49
|
}
|
|
51
50
|
area += (vertices[0][1] * (vertices[1][2] - vertices[n - 1][2]))
|
|
52
51
|
// scale to get area
|
|
53
|
-
area
|
|
52
|
+
area /= (2 * normal[0])
|
|
54
53
|
break
|
|
55
54
|
|
|
56
55
|
case 2: // ignore Y coordinates
|
|
@@ -62,7 +61,7 @@ const measureArea = (poly3) => {
|
|
|
62
61
|
}
|
|
63
62
|
area += (vertices[0][2] * (vertices[1][0] - vertices[n - 1][0]))
|
|
64
63
|
// scale to get area
|
|
65
|
-
area
|
|
64
|
+
area /= (2 * normal[1])
|
|
66
65
|
break
|
|
67
66
|
|
|
68
67
|
case 3: // ignore Z coordinates
|
|
@@ -75,7 +74,7 @@ const measureArea = (poly3) => {
|
|
|
75
74
|
}
|
|
76
75
|
area += (vertices[0][0] * (vertices[1][1] - vertices[n - 1][1]))
|
|
77
76
|
// scale to get area
|
|
78
|
-
area
|
|
77
|
+
area /= (2 * normal[2])
|
|
79
78
|
break
|
|
80
79
|
}
|
|
81
80
|
return area
|
|
@@ -37,6 +37,21 @@ test('poly3: measureArea() should return correct values', (t) => {
|
|
|
37
37
|
let ret4 = measureArea(ply4)
|
|
38
38
|
t.is(ret4, 19.5)
|
|
39
39
|
|
|
40
|
+
// colinear vertices non-zero area
|
|
41
|
+
const ply5 = fromPoints([[0, 0, 0], [1, 0, 0], [2, 0, 0], [0, 1, 0]])
|
|
42
|
+
const ret5 = measureArea(ply5)
|
|
43
|
+
t.is(ret5, 1)
|
|
44
|
+
|
|
45
|
+
// colinear vertices empty area
|
|
46
|
+
const ply6 = fromPoints([[0, 0, 0], [1, 0, 0], [2, 0, 0]])
|
|
47
|
+
const ret6 = measureArea(ply6)
|
|
48
|
+
t.is(ret6, 0)
|
|
49
|
+
|
|
50
|
+
// duplicate vertices empty area
|
|
51
|
+
const ply7 = fromPoints([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
|
|
52
|
+
const ret7 = measureArea(ply7)
|
|
53
|
+
t.is(ret7, 0)
|
|
54
|
+
|
|
40
55
|
// rotated to various angles
|
|
41
56
|
let rotation = mat4.fromZRotation(mat4.create(), (45 * 0.017453292519943295))
|
|
42
57
|
ply1 = transform(rotation, ply1)
|
|
@@ -2,8 +2,7 @@ const mplane = require('../../maths/plane/')
|
|
|
2
2
|
|
|
3
3
|
const plane = (polygon) => {
|
|
4
4
|
if (!polygon.plane) {
|
|
5
|
-
|
|
6
|
-
polygon.plane = mplane.fromPoints(mplane.create(), vertices[0], vertices[1], vertices[2])
|
|
5
|
+
polygon.plane = mplane.fromPoints(mplane.create(), ...polygon.vertices)
|
|
7
6
|
}
|
|
8
7
|
return polygon.plane
|
|
9
8
|
}
|
|
@@ -3,7 +3,8 @@ const vec3 = require('../vec3')
|
|
|
3
3
|
/**
|
|
4
4
|
* Represents a unbounded line in 3D space, positioned at a point of origin.
|
|
5
5
|
* A line is parametrized by a point of origin and a directional vector.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* The array contents are two 3D vectors; origin [0,0,0] and directional vector [0,0,1].
|
|
7
8
|
* @see https://en.wikipedia.org/wiki/Hesse_normal_form
|
|
8
9
|
* @typedef {Array} line3
|
|
9
10
|
*/
|
|
@@ -19,7 +19,7 @@ const { EPSILON } = require('./constants')
|
|
|
19
19
|
*/
|
|
20
20
|
const fromRotation = (out, rad, axis) => {
|
|
21
21
|
let [x, y, z] = axis
|
|
22
|
-
let len = Math.
|
|
22
|
+
let len = Math.hypot(x, y, z)
|
|
23
23
|
|
|
24
24
|
if (Math.abs(len) < EPSILON) {
|
|
25
25
|
// axis is 0,0,0 or almost
|
|
@@ -2,8 +2,6 @@ const test = require('ava')
|
|
|
2
2
|
|
|
3
3
|
const { isIdentity, create, fromTranslation } = require('./index')
|
|
4
4
|
|
|
5
|
-
const { compareVectors } = require('../../../test/helpers/index')
|
|
6
|
-
|
|
7
5
|
test('mat4: isIdentity() should return correct values', (t) => {
|
|
8
6
|
const identity = create() // identity matrix
|
|
9
7
|
t.true(isIdentity(identity))
|