@jscad/modeling 2.5.3 → 2.7.1

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 (63) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/jscad-modeling.min.js +341 -323
  3. package/package.json +2 -2
  4. package/src/colors/colorize.js +4 -5
  5. package/src/colors/colorize.test.js +19 -12
  6. package/src/curves/bezier/create.js +3 -8
  7. package/src/curves/index.js +1 -1
  8. package/src/geometries/geom2/applyTransforms.js +1 -1
  9. package/src/geometries/geom2/clone.js +2 -12
  10. package/src/geometries/geom2/transform.js +2 -6
  11. package/src/geometries/geom3/applyTransforms.js +1 -1
  12. package/src/geometries/geom3/clone.js +2 -14
  13. package/src/geometries/geom3/clone.test.js +0 -2
  14. package/src/geometries/geom3/create.js +1 -3
  15. package/src/geometries/geom3/create.test.js +0 -2
  16. package/src/geometries/geom3/fromCompactBinary.js +4 -6
  17. package/src/geometries/geom3/fromToCompactBinary.test.js +0 -6
  18. package/src/geometries/geom3/invert.test.js +0 -2
  19. package/src/geometries/geom3/toCompactBinary.js +8 -10
  20. package/src/geometries/geom3/transform.js +2 -7
  21. package/src/geometries/geom3/transform.test.js +0 -1
  22. package/src/geometries/geom3/type.d.ts +0 -1
  23. package/src/geometries/path2/applyTransforms.js +1 -1
  24. package/src/geometries/path2/clone.js +2 -13
  25. package/src/geometries/path2/transform.js +2 -7
  26. package/src/geometries/poly3/isConvex.js +1 -1
  27. package/src/geometries/poly3/measureArea.js +12 -13
  28. package/src/geometries/poly3/measureArea.test.js +15 -0
  29. package/src/geometries/poly3/plane.js +1 -2
  30. package/src/maths/line3/create.js +2 -1
  31. package/src/maths/mat4/index.js +1 -0
  32. package/src/maths/mat4/isOnlyTransformScale.js +22 -0
  33. package/src/maths/mat4/isOnlyTransformScale.test.js +27 -0
  34. package/src/maths/plane/fromPoints.js +32 -10
  35. package/src/maths/plane/fromPoints.test.js +4 -0
  36. package/src/measurements/index.js +4 -1
  37. package/src/measurements/measureBoundingBox.test.js +8 -0
  38. package/src/measurements/measureBoundingSphere.js +146 -0
  39. package/src/measurements/measureBoundingSphere.test.js +59 -0
  40. package/src/measurements/measureCenter.js +28 -0
  41. package/src/measurements/measureCenter.test.js +58 -0
  42. package/src/measurements/measureCenterOfMass.js +106 -0
  43. package/src/measurements/measureCenterOfMass.test.js +58 -0
  44. package/src/measurements/measureDimensions.js +28 -0
  45. package/src/measurements/measureDimensions.test.js +58 -0
  46. package/src/measurements/measureEpsilon.js +3 -9
  47. package/src/operations/booleans/reTesselateCoplanarPolygons.js +1 -1
  48. package/src/operations/booleans/trees/PolygonTreeNode.js +0 -1
  49. package/src/operations/expansions/expand.js +2 -0
  50. package/src/operations/expansions/expand.test.js +1 -1
  51. package/src/operations/expansions/offset.js +1 -0
  52. package/src/operations/extrusions/extrudeRectangular.js +2 -1
  53. package/src/operations/extrusions/extrudeRotate.test.js +18 -10
  54. package/src/operations/modifiers/generalize.js +0 -1
  55. package/src/operations/modifiers/snapPolygons.js +2 -2
  56. package/src/operations/modifiers/snapPolygons.test.js +13 -5
  57. package/src/primitives/ellipse.js +1 -1
  58. package/src/primitives/index.d.ts +1 -0
  59. package/src/primitives/index.js +2 -1
  60. package/src/primitives/triangle.d.ts +10 -0
  61. package/src/primitives/triangle.js +164 -0
  62. package/src/primitives/triangle.test.js +95 -0
  63. package/src/utils/insertSorted.js +1 -0
@@ -20,7 +20,6 @@ const splitPolygonByPlane = require('./splitPolygonByPlane')
20
20
  // remove() removes a polygon from the tree. Once a polygon is removed, the parent polygons are invalidated
21
21
  // since they are no longer intact.
22
22
  class PolygonTreeNode {
23
-
24
23
  // constructor creates the root node
25
24
  constructor () {
26
25
  this.parent = null
@@ -10,6 +10,8 @@ const expandPath2 = require('./expandPath2')
10
10
 
11
11
  /**
12
12
  * Expand the given geometry using the given options.
13
+ * Both interal and external space is expanded for 2D and 3D shapes.
14
+ *
13
15
  * Note: Contract is expand using a negative delta.
14
16
  * @param {Object} options - options for expand
15
17
  * @param {Number} [options.delta=1] - delta (+/-) of expansion
@@ -120,7 +120,7 @@ test('expand: expanding of a geom3 produces expected changes to polygons', (t) =
120
120
  const geometry2 = sphere({ radius: 5, segments: 8 })
121
121
  const obs2 = expand({ delta: 5 }, geometry2)
122
122
  const pts2 = geom3.toPoints(obs2)
123
- t.is(pts2.length, 2059)
123
+ t.is(pts2.length, 2065)
124
124
  })
125
125
 
126
126
  test('expand (options): offsetting of a complex geom2 produces expected offset geom2', (t) => {
@@ -8,6 +8,7 @@ const offsetPath2 = require('./offsetPath2')
8
8
 
9
9
  /**
10
10
  * Create offset geometry from the given geometry using the given options.
11
+ * Offsets from internal and external space are created.
11
12
  * @param {Object} options - options for offset
12
13
  * @param {Float} [options.delta=1] - delta of offset (+ to exterior, - from interior)
13
14
  * @param {String} [options.corners='edge'] - type of corner to create after offseting; edge, chamfer, round
@@ -17,7 +17,8 @@ const extrudeRectangularGeom2 = require('./extrudeRectangularGeom2')
17
17
  * @alias module:modeling/extrusions.extrudeRectangular
18
18
  *
19
19
  * @example
20
- * let mywalls = extrudeRectangular({offset: [0,0,10]}, square())
20
+ * let mywalls = extrudeRectangular({size: 1, height: 3}, square({size: 20}))
21
+ * let mywalls = extrudeRectangular({size: 1, height: 300, twistAngle: Math.PI}, square({size: 20}))
21
22
  */
22
23
  const extrudeRectangular = (options, ...objects) => {
23
24
  const defaults = {
@@ -107,10 +107,14 @@ test('extrudeRotate: (overlap +/-) extruding of a geom2 produces an expected geo
107
107
  [[7, -4.898587196589413e-16, -8], [4.898587196589413e-16, -2.999519565323715e-32, -8], [9.184850993605148e-16, 7, -8]],
108
108
  [[7, 4.898587196589413e-16, 8], [7, -4.898587196589413e-16, -8], [9.184850993605148e-16, 7, -8]],
109
109
  [[7, 4.898587196589413e-16, 8], [9.184850993605148e-16, 7, -8], [-6.123233995736767e-17, 7, 8]],
110
- [[-4.898587196589414e-16, 0, 8], [-6.123233995736777e-17, 6.999999999999999, 8],
111
- [9.18485099360515e-16, 7.000000000000001, -8], [4.898587196589413e-16, 0, -8]],
112
- [[7, 4.898587196589413e-16, 8], [0, 4.898587196589413e-16, 8],
113
- [0, -4.898587196589413e-16, -8], [7, -4.898587196589413e-16, -8]]
110
+ [
111
+ [-4.898587196589414e-16, 0, 8], [-6.123233995736777e-17, 6.999999999999999, 8],
112
+ [9.18485099360515e-16, 7.000000000000001, -8], [4.898587196589413e-16, 0, -8]
113
+ ],
114
+ [
115
+ [7, 4.898587196589413e-16, 8], [0, 4.898587196589413e-16, 8],
116
+ [0, -4.898587196589413e-16, -8], [7, -4.898587196589413e-16, -8]
117
+ ]
114
118
  ]
115
119
  t.is(pts.length, 6)
116
120
  t.true(comparePolygonsAsPoints(pts, exp))
@@ -133,12 +137,16 @@ test('extrudeRotate: (overlap +/-) extruding of a geom2 produces an expected geo
133
137
  [[0.7071067811865472, 0.7071067811865478, 8], [1.414213562373095, 1.4142135623730951, 4], [-1.2246467991473532e-16, 2, 4]],
134
138
  [[0.7071067811865472, 0.7071067811865478, 8], [-1.2246467991473532e-16, 2, 4], [-4.286263797015736e-16, 1, 8]],
135
139
  [[-3.4638242249419727e-16, 3.4638242249419736e-16, 8], [0.7071067811865472, 0.7071067811865478, 8], [-4.286263797015736e-16, 1, 8]],
136
- [[-4.898587196589412e-16, 0, 8], [-4.2862637970157346e-16, 0.9999999999999998, 8],
137
- [-1.2246467991473475e-16, 2.0000000000000004, 3.9999999999999964], [5.510910596163092e-16, 1.0000000000000004, -8],
138
- [ 4.898587196589414e-16, 0, -8]],
139
- [[0, -4.898587196589413e-16, -8.000000000000002], [1.0000000000000027, -4.898587196589413e-16, -8.000000000000002],
140
- [2.000000000000001, 2.449293598294702e-16, 3.9999999999999964], [1.0000000000000004, 4.898587196589411e-16, 8],
141
- [0, 4.898587196589411e-16, 8]]
140
+ [
141
+ [-4.898587196589412e-16, 0, 8], [-4.2862637970157346e-16, 0.9999999999999998, 8],
142
+ [-1.2246467991473475e-16, 2.0000000000000004, 3.9999999999999964], [5.510910596163092e-16, 1.0000000000000004, -8],
143
+ [4.898587196589414e-16, 0, -8]
144
+ ],
145
+ [
146
+ [0, -4.898587196589413e-16, -8.000000000000002], [1.0000000000000027, -4.898587196589413e-16, -8.000000000000002],
147
+ [2.000000000000001, 2.449293598294702e-16, 3.9999999999999964], [1.0000000000000004, 4.898587196589411e-16, 8],
148
+ [0, 4.898587196589411e-16, 8]
149
+ ]
142
150
  ]
143
151
  t.is(pts.length, 14)
144
152
  t.true(comparePolygonsAsPoints(pts, exp))
@@ -19,7 +19,6 @@ const generalizePath2 = (options, geometry) => {
19
19
  return geometry
20
20
  }
21
21
 
22
-
23
22
  /*
24
23
  */
25
24
  const generalizeGeom2 = (options, geometry) => {
@@ -3,7 +3,7 @@ const vec3 = require('../../maths/vec3')
3
3
  const poly3 = require('../../geometries/poly3')
4
4
 
5
5
  const isValidPoly3 = (epsilon, polygon) => {
6
- const area = poly3.measureArea(polygon)
6
+ const area = Math.abs(poly3.measureArea(polygon))
7
7
  return (Number.isFinite(area) && area > epsilon)
8
8
  }
9
9
 
@@ -17,7 +17,7 @@ const snapPolygons = (epsilon, polygons) => {
17
17
  const newvertices = []
18
18
  for (let i = 0; i < snapvertices.length; i++) {
19
19
  const j = (i + 1) % snapvertices.length
20
- if (! vec3.equals(snapvertices[i], snapvertices[j])) newvertices.push(snapvertices[i])
20
+ if (!vec3.equals(snapvertices[i], snapvertices[j])) newvertices.push(snapvertices[i])
21
21
  }
22
22
  const newpolygon = poly3.create(newvertices)
23
23
  if (polygon.color) newpolygon.color = polygon.color
@@ -34,29 +34,37 @@ test('snapPolygons: snap of polygons produces expected results', (t) => {
34
34
  [-24.445112000000115, 19.346837333333426, 46.47572533333356],
35
35
  [-24.44446933333345, 19.346837333333426, 46.47508266666689],
36
36
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
37
- [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234],
37
+ [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234]
38
38
  ]), // OK
39
39
  poly3.fromPoints([
40
40
  [-24.445112000000115, 19.346837333333426, 46.47572533333356],
41
41
  [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234],
42
42
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
43
- [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234],
43
+ [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234]
44
44
  ]),
45
45
  poly3.fromPoints([
46
46
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
47
47
  [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234],
48
48
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
49
- [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234],
49
+ [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234]
50
50
  ]),
51
+ // inverted polygon
52
+ poly3.fromPoints([
53
+ [20.109133333333336, -4.894033333333335, -1.0001266666666668],
54
+ [20.021120000000003, -5.1802133333333344, -1.0001266666666668],
55
+ [20.020300000000002, -5.182946666666668, -1.0001266666666668],
56
+ [10.097753333333335, -5.182946666666668, -1.0001266666666668],
57
+ [10.287720000000002, -4.894033333333335, -1.0001266666666668]
58
+ ])
51
59
  ]
52
60
 
53
61
  const results = snapPolygons(0.0001, polygons)
54
- t.is(results.length, 4)
62
+ t.is(results.length, 5)
55
63
 
56
64
  const exp3 = poly3.fromPoints([
57
65
  [-24.4451, 19.3468, 46.4757],
58
66
  [-24.4445, 19.3468, 46.475100000000005],
59
67
  [-23.7054, 18.7986, 39.5645]
60
68
  ])
61
- t.deepEqual(results[3], exp3)
69
+ t.deepEqual(results[3].vertices, exp3.vertices)
62
70
  })
@@ -7,7 +7,7 @@ const geom2 = require('../geometries/geom2')
7
7
  const { isGTE, isNumberArray } = require('./commonChecks')
8
8
 
9
9
  /**
10
- * Construct an axis-aligned ellispe in two dimensional space.
10
+ * Construct an axis-aligned ellipse in two dimensional space.
11
11
  * @see https://en.wikipedia.org/wiki/Ellipse
12
12
  * @param {Object} [options] - options for construction
13
13
  * @param {Array} [options.center=[0,0]] - center of ellipse
@@ -18,5 +18,6 @@ export { default as sphere, SphereOptions } from './sphere'
18
18
  export { default as square, SquareOptions } from './square'
19
19
  export { default as star, StarOptions } from './star'
20
20
  export { default as torus, TorusOptions } from './torus'
21
+ export { default as triangle, TriangleOptions } from './triangle'
21
22
 
22
23
  export as namespace primitives
@@ -26,5 +26,6 @@ module.exports = {
26
26
  sphere: require('./sphere'),
27
27
  square: require('./square'),
28
28
  star: require('./star'),
29
- torus: require('./torus')
29
+ torus: require('./torus'),
30
+ triangle: require('./triangle')
30
31
  }
@@ -0,0 +1,10 @@
1
+ import Geom2 from '../geometries/geom2/type'
2
+
3
+ export default triangle
4
+
5
+ export interface TriangleOptions {
6
+ type?: 'AAA' | 'AAS' | 'ASA' | 'SAS' | 'SSA' | 'SSS'
7
+ values?: [number, number, number]
8
+ }
9
+
10
+ declare function triangle(options?: TriangleOptions): Geom2
@@ -0,0 +1,164 @@
1
+ const vec2 = require('../maths/vec2')
2
+
3
+ const geom2 = require('../geometries/geom2')
4
+
5
+ const { isNumberArray } = require('./commonChecks')
6
+
7
+ const NEPS = 1e-13
8
+
9
+ // returns angle C
10
+ const solveAngleFromSSS = (a, b, c) => Math.acos(((a * a) + (b * b) - (c * c)) / (2 * a * b))
11
+
12
+ // returns side c
13
+ const solveSideFromSAS = (a, C, b) => {
14
+ if (C > NEPS) {
15
+ return Math.sqrt(a * a + b * b - 2 * a * b * Math.cos(C))
16
+ }
17
+
18
+ // Explained in https://www.nayuki.io/page/numerically-stable-law-of-cosines
19
+ return Math.sqrt((a - b) * (a - b) + a * b * C * C * (1 - C * C / 12))
20
+ }
21
+
22
+ // AAA is when three angles of a triangle, but no sides
23
+ const solveAAA = (angles) => {
24
+ const eps = Math.abs(angles[0] + angles[1] + angles[2] - Math.PI)
25
+ if (eps > NEPS) throw new Error('AAA triangles require angles that sum to PI')
26
+
27
+ const A = angles[0]
28
+ const B = angles[1]
29
+ const C = Math.PI - A - B
30
+
31
+ // Note: This is not 100% proper but...
32
+ // default the side c length to 1
33
+ // solve the other lengths
34
+ const c = 1
35
+ const a = (c / Math.sin(C)) * Math.sin(A)
36
+ const b = (c / Math.sin(C)) * Math.sin(B)
37
+ return createTriangle(A, B, C, a, b, c)
38
+ }
39
+
40
+ // AAS is when two angles and one side are known, and the side is not between the angles
41
+ const solveAAS = (values) => {
42
+ const A = values[0]
43
+ const B = values[1]
44
+ const C = Math.PI + NEPS - A - B
45
+
46
+ if (C < NEPS) throw new Error('AAS triangles require angles that sum to PI')
47
+
48
+ const a = values[2]
49
+ const b = (a / Math.sin(A)) * Math.sin(B)
50
+ const c = (a / Math.sin(A)) * Math.sin(C)
51
+ return createTriangle(A, B, C, a, b, c)
52
+ }
53
+
54
+ // ASA is when two angles and the side between the angles are known
55
+ const solveASA = (values) => {
56
+ const A = values[0]
57
+ const B = values[2]
58
+ const C = Math.PI + NEPS - A - B
59
+
60
+ if (C < NEPS) throw new Error('ASA triangles require angles that sum to PI')
61
+
62
+ const c = values[1]
63
+ const a = (c / Math.sin(C)) * Math.sin(A)
64
+ const b = (c / Math.sin(C)) * Math.sin(B)
65
+ return createTriangle(A, B, C, a, b, c)
66
+ }
67
+
68
+ // SAS is when two sides and the angle between them are known
69
+ const solveSAS = (values) => {
70
+ const c = values[0]
71
+ const B = values[1]
72
+ const a = values[2]
73
+
74
+ const b = solveSideFromSAS(c, B, a)
75
+
76
+ const A = solveAngleFromSSS(b, c, a) // solve for A
77
+ const C = Math.PI - A - B
78
+ return createTriangle(A, B, C, a, b, c)
79
+ }
80
+
81
+ // SSA is when two sides and an angle that is not the angle between the sides are known
82
+ const solveSSA = (values) => {
83
+ const c = values[0]
84
+ const a = values[1]
85
+ const C = values[2]
86
+
87
+ const A = Math.asin(a * Math.sin(C) / c)
88
+ const B = Math.PI - A - C
89
+
90
+ const b = (c / Math.sin(C)) * Math.sin(B)
91
+ return createTriangle(A, B, C, a, b, c)
92
+ }
93
+
94
+ // SSS is when we know three sides of the triangle
95
+ const solveSSS = (lengths) => {
96
+ const a = lengths[1]
97
+ const b = lengths[2]
98
+ const c = lengths[0]
99
+ if (((a + b) <= c) || ((b + c) <= a) || ((c + a) <= b)) {
100
+ throw new Error('SSS triangle is incorrect, as the longest side is longer than the sum of the other sides')
101
+ }
102
+
103
+ const A = solveAngleFromSSS(b, c, a) // solve for A
104
+ const B = solveAngleFromSSS(c, a, b) // solve for B
105
+ const C = Math.PI - A - B
106
+ return createTriangle(A, B, C, a, b, c)
107
+ }
108
+
109
+ const createTriangle = (A, B, C, a, b, c) => {
110
+ const p0 = vec2.fromValues(0, 0) // everything starts from 0, 0
111
+ const p1 = vec2.fromValues(c, 0)
112
+ const p2 = vec2.fromValues(a, 0)
113
+ vec2.add(p2, vec2.rotate(p2, p2, [0, 0], Math.PI - B), p1)
114
+ return geom2.fromPoints([p0, p1, p2])
115
+ }
116
+
117
+ /**
118
+ * Construct a triangle in two dimensional space from the given options.
119
+ * The triangle is always constructed CCW from the origin, [0, 0, 0].
120
+ * @see https://www.mathsisfun.com/algebra/trig-solving-triangles.html
121
+ * @param {Object} [options] - options for construction
122
+ * @param {String} [options.type='SSS' - type of triangle to construct; A ~ angle, S ~ side
123
+ * @param {Array} [options.values=[1,1,1]] - angle (radians) of corners or length of sides
124
+ * @returns {geom2} new 2D geometry
125
+ * @alias module:modeling/primitives.triangle
126
+ *
127
+ * @example
128
+ * let myshape = triangle({type: 'AAS', values: [degToRad(62), degToRad(35), 7]})
129
+ */
130
+ const triangle = (options) => {
131
+ const defaults = {
132
+ type: 'SSS',
133
+ values: [1, 1, 1]
134
+ }
135
+ let { type, values } = Object.assign({}, defaults, options)
136
+
137
+ if (typeof (type) !== 'string') throw new Error('triangle type must be a string')
138
+ type = type.toUpperCase()
139
+ if (!((type[0] === 'A' || type[0] === 'S') &&
140
+ (type[1] === 'A' || type[1] === 'S') &&
141
+ (type[2] === 'A' || type[2] === 'S'))) throw new Error('triangle type must contain three letters; A or S')
142
+
143
+ if (!isNumberArray(values, 3)) throw new Error('triangle values must contain three values')
144
+ if (!values.every((n) => n > 0)) throw new Error('triangle values must be greater than zero')
145
+
146
+ switch (type) {
147
+ case 'AAA':
148
+ return solveAAA(values)
149
+ case 'AAS':
150
+ return solveAAS(values)
151
+ case 'ASA':
152
+ return solveASA(values)
153
+ case 'SAS':
154
+ return solveSAS(values)
155
+ case 'SSA':
156
+ return solveSSA(values)
157
+ case 'SSS':
158
+ return solveSSS(values)
159
+ default:
160
+ throw new Error('invalid triangle type, try again')
161
+ }
162
+ }
163
+
164
+ module.exports = triangle
@@ -0,0 +1,95 @@
1
+ const test = require('ava')
2
+
3
+ const { triangle } = require('./index')
4
+
5
+ const degToRad = require('../utils/degToRad')
6
+ const geom2 = require('../geometries/geom2')
7
+
8
+ const comparePoints = require('../../test/helpers/comparePoints')
9
+
10
+ test('triangle (defaults)', (t) => {
11
+ const geometry = triangle()
12
+ const obs = geom2.toPoints(geometry)
13
+ const exp = [
14
+ [0, 0],
15
+ [1, 0],
16
+ [0.5000000000000002, 0.8660254037844387]
17
+ ]
18
+
19
+ t.deepEqual(obs.length, 3)
20
+ t.true(comparePoints(obs, exp))
21
+ })
22
+
23
+ test('triangle (options)', (t) => {
24
+ // test SSS
25
+ let geometry = triangle({ type: 'SSS', values: [7, 8, 6] })
26
+ let obs = geom2.toPoints(geometry)
27
+ let exp = [
28
+ [0, 0],
29
+ [7, 0],
30
+ [1.5, 5.809475019311125]
31
+ ]
32
+
33
+ t.deepEqual(obs.length, 3)
34
+ t.true(comparePoints(obs, exp))
35
+
36
+ // test AAA
37
+ geometry = triangle({ type: 'AAA', values: [Math.PI / 2, Math.PI / 4, Math.PI / 4] })
38
+ obs = geom2.toPoints(geometry)
39
+ exp = [
40
+ [0, 0],
41
+ [1, 0],
42
+ [0, 1.0000000000000002]
43
+ ]
44
+
45
+ t.deepEqual(obs.length, 3)
46
+ t.true(comparePoints(obs, exp))
47
+
48
+ // test AAS
49
+ geometry = triangle({ type: 'AAS', values: [degToRad(62), degToRad(35), 7] })
50
+ obs = geom2.toPoints(geometry)
51
+ exp = [
52
+ [0, 0],
53
+ [7.86889631692936, 0],
54
+ [2.1348320069064197, 4.015035054457325]
55
+ ]
56
+
57
+ t.deepEqual(obs.length, 3)
58
+ t.true(comparePoints(obs, exp))
59
+
60
+ // test ASA
61
+ geometry = triangle({ type: 'ASA', values: [degToRad(76), 9, degToRad(34)] })
62
+ obs = geom2.toPoints(geometry)
63
+ exp = [
64
+ [0, 0],
65
+ [9, 0],
66
+ [1.295667368233083, 5.196637976713814]
67
+ ]
68
+
69
+ t.deepEqual(obs.length, 3)
70
+ t.true(comparePoints(obs, exp))
71
+
72
+ // test SAS
73
+ geometry = triangle({ type: 'SAS', values: [5, degToRad(49), 7] })
74
+ obs = geom2.toPoints(geometry)
75
+ exp = [
76
+ [0, 0],
77
+ [5, 0],
78
+ [0.4075867970664495, 5.282967061559405]
79
+ ]
80
+
81
+ t.deepEqual(obs.length, 3)
82
+ t.true(comparePoints(obs, exp))
83
+
84
+ // test SSA
85
+ geometry = triangle({ type: 'SSA', values: [8, 13, degToRad(31)] })
86
+ obs = geom2.toPoints(geometry)
87
+ exp = [
88
+ [0, 0],
89
+ [8, 0],
90
+ [8.494946725906148, 12.990574573070846]
91
+ ]
92
+
93
+ t.deepEqual(obs.length, 3)
94
+ t.true(comparePoints(obs, exp))
95
+ })
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * Insert the given element into the give array using the compareFunction.
2
3
  * @alias module:modeling/utils.insertSorted
3
4
  */
4
5
  const insertSorted = (array, element, comparefunc) => {