@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.
Files changed (73) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/jscad-modeling.min.js +97 -94
  3. package/package.json +2 -2
  4. package/src/colors/colorize.js +35 -1
  5. package/src/colors/colorize.test.js +19 -4
  6. package/src/colors/hslToRgb.js +1 -1
  7. package/src/colors/hueToColorComponent.js +1 -0
  8. package/src/curves/bezier/create.js +3 -8
  9. package/src/curves/bezier/tangentAt.js +2 -2
  10. package/src/curves/index.js +1 -1
  11. package/src/geometries/geom2/clone.js +2 -12
  12. package/src/geometries/geom2/toOutlines.js +6 -11
  13. package/src/geometries/geom2/transform.js +0 -2
  14. package/src/geometries/geom3/clone.js +2 -14
  15. package/src/geometries/geom3/clone.test.js +0 -2
  16. package/src/geometries/geom3/create.js +1 -3
  17. package/src/geometries/geom3/create.test.js +0 -2
  18. package/src/geometries/geom3/fromCompactBinary.js +4 -6
  19. package/src/geometries/geom3/fromToCompactBinary.test.js +0 -6
  20. package/src/geometries/geom3/invert.js +2 -2
  21. package/src/geometries/geom3/invert.test.js +0 -2
  22. package/src/geometries/geom3/toCompactBinary.js +8 -10
  23. package/src/geometries/geom3/toPoints.js +1 -0
  24. package/src/geometries/geom3/transform.js +0 -2
  25. package/src/geometries/geom3/transform.test.js +0 -1
  26. package/src/geometries/geom3/type.d.ts +0 -1
  27. package/src/geometries/path2/clone.js +2 -13
  28. package/src/geometries/path2/transform.js +0 -2
  29. package/src/geometries/poly3/isConvex.js +1 -1
  30. package/src/geometries/poly3/measureArea.js +12 -13
  31. package/src/geometries/poly3/measureArea.test.js +15 -0
  32. package/src/geometries/poly3/plane.js +1 -2
  33. package/src/maths/line3/create.js +2 -1
  34. package/src/maths/mat4/fromRotation.js +1 -1
  35. package/src/maths/mat4/isIdentity.test.js +0 -2
  36. package/src/maths/mat4/isOnlyTransformScale.js +5 -4
  37. package/src/maths/mat4/rotate.js +1 -1
  38. package/src/maths/plane/fromPoints.js +32 -10
  39. package/src/maths/plane/fromPoints.test.js +4 -0
  40. package/src/maths/vec2/length.test.js +10 -0
  41. package/src/maths/vec3/angle.js +2 -2
  42. package/src/maths/vec3/angle.test.js +17 -0
  43. package/src/maths/vec3/length.test.js +10 -0
  44. package/src/measurements/measureBoundingBox.js +37 -121
  45. package/src/measurements/measureBoundingBox.test.js +8 -0
  46. package/src/measurements/measureCenterOfMass.js +0 -1
  47. package/src/measurements/measureEpsilon.js +3 -9
  48. package/src/operations/booleans/reTesselateCoplanarPolygons.js +1 -1
  49. package/src/operations/booleans/retessellate.js +1 -3
  50. package/src/operations/booleans/trees/PolygonTreeNode.js +0 -1
  51. package/src/operations/expansions/expand.js +2 -0
  52. package/src/operations/expansions/expand.test.js +1 -1
  53. package/src/operations/expansions/offset.js +1 -0
  54. package/src/operations/extrusions/extrudeLinear.js +1 -1
  55. package/src/operations/extrusions/extrudeRectangular.js +2 -1
  56. package/src/operations/extrusions/extrudeRotate.test.js +18 -10
  57. package/src/operations/hulls/quickhull/QuickHull.js +2 -2
  58. package/src/operations/modifiers/edges.js +1 -3
  59. package/src/operations/modifiers/generalize.js +3 -7
  60. package/src/operations/modifiers/snapPolygons.js +2 -2
  61. package/src/operations/modifiers/snapPolygons.test.js +13 -5
  62. package/src/operations/transforms/mirror.js +1 -1
  63. package/src/primitives/ellipse.js +1 -1
  64. package/src/primitives/geodesicSphere.js +2 -2
  65. package/src/primitives/index.d.ts +1 -0
  66. package/src/primitives/index.js +2 -1
  67. package/src/primitives/roundedCylinder.js +1 -1
  68. package/src/primitives/triangle.d.ts +10 -0
  69. package/src/primitives/triangle.js +164 -0
  70. package/src/primitives/triangle.test.js +95 -0
  71. package/src/utils/insertSorted.js +1 -0
  72. package/test/helpers/comparePolygons.js +1 -3
  73. 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.6.0",
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": "3d1d02f2863c65fd95406c7098c09297b3be1c10"
63
+ "gitHead": "b6c5675d2d9a292e0ba24896bf22d0e9dc5d4270"
64
64
  }
@@ -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} given object, or list of given objects with an additional attribute 'color'
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.is(obj0, obs[0])
46
+ t.not(obj0, obs[0])
47
47
  t.deepEqual(obs[0].color, [1, 1, 0.5, 0.8])
48
48
 
49
- t.is(obj1, obs[1])
49
+ t.not(obj1, obs[1])
50
50
  t.deepEqual(obs[1].color, [1, 1, 0.5, 0.8])
51
51
 
52
- t.is(obj2, obs[2])
52
+ t.not(obj2, obs[2])
53
53
  t.deepEqual(obs[2].color, [1, 1, 0.5, 0.8])
54
54
 
55
- t.is(obj3, obs[3])
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
+ })
@@ -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
@@ -3,6 +3,7 @@
3
3
  * @param {Number} p
4
4
  * @param {Number} q
5
5
  * @param {Number} t
6
+ * @return {Number} color component
6
7
  * @alias module:modeling/colors.hueToColorComponent
7
8
  */
8
9
  const hueToColorComponent = (p, q, t) => {
@@ -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
- * @returns {array | number} the tangent at the requested position.
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) => {
@@ -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 deep clone of the given geometry.
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 uniquevertices = []
10
+ const vertices = {}
11
11
  const getUniqueVertex = (vertex) => {
12
- const i = uniquevertices.findIndex((v) => vec2.equals(v, vertex))
13
- if (i < 0) {
14
- uniquevertices.push(vertex)
15
- return vertex
12
+ const key = vertex.toString()
13
+ if (!vertices[key]) {
14
+ vertices[key] = vertex
16
15
  }
17
- return uniquevertices[i]
16
+ return vertices[key]
18
17
  }
19
18
 
20
- const edges = []
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,7 +1,5 @@
1
1
  const mat4 = require('../../maths/mat4')
2
2
 
3
- const create = require('./create')
4
-
5
3
  /**
6
4
  * Transform the given geometry using the given matrix.
7
5
  * This is a lazy transform of the sides, as this function only adjusts the transforms.
@@ -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 deep clone of the given geometry.
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 {Boolean} isRetesselated - true if retesselation has been performed
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
- created.isRetesselated = !!data[17]
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[18] >= 0) {
40
- created.color = [data[18], data[19], data[20], data[21]]
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
- * @params {geom3} geometry - the geometry to invert
9
- * @returns {geom3} a new geometry
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 + 1 + 4 + 1 + numberOfPolygons + (numberOfVertices * 3))
20
- // type + transforms + isRetesselated + color + numberOfPolygons + numberOfVerticesPerPolygon[] + vertices data[]
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] = geom.isRetesselated ? 1 : 0
41
+ compacted[17] = color[0]
42
+ compacted[18] = color[1]
43
+ compacted[19] = color[2]
44
+ compacted[20] = color[3]
42
45
 
43
- compacted[18] = color[0]
44
- compacted[19] = color[1]
45
- compacted[20] = color[2]
46
- compacted[21] = color[3]
46
+ compacted[21] = numberOfVertices
47
47
 
48
- compacted[22] = numberOfVertices
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
  */
@@ -1,7 +1,5 @@
1
1
  const mat4 = require('../../maths/mat4')
2
2
 
3
- const create = require('./create')
4
-
5
3
  /**
6
4
  * Transform the given geometry using the given matrix.
7
5
  * This is a lazy transform of the polygons, as this function only adjusts the transforms.
@@ -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)
@@ -6,6 +6,5 @@ export default Geom3
6
6
 
7
7
  declare interface Geom3 extends Colored {
8
8
  polygons: Array<Poly3>
9
- isRetesselated: boolean
10
9
  transforms: Mat4
11
10
  }
@@ -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 deep clone of the give geometry.
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
@@ -1,7 +1,5 @@
1
1
  const mat4 = require('../../maths/mat4')
2
2
 
3
- const create = require('./create')
4
-
5
3
  /**
6
4
  * Transform the given geometry using the given matrix.
7
5
  * This is a lazy transform of the points, as this function only adjusts the transforms.
@@ -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[0], vertices[1], vertices[2])
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 vec3 = require('../../maths/vec3')
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 real normal
18
- const a = vertices[0]
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
- // determin direction of projection
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
- const an = Math.sqrt((ax * ax) + (ay * ay) + (az * az)) // length of normal
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 *= (an / (2 * normal[0]))
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 *= (an / (2 * normal[1]))
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 *= (an / (2 * normal[2]))
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
- const vertices = polygon.vertices
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
- * The array contents are two 3D vectors; origin and directional vector.
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.sqrt(x * x + y * y + z * z)
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))