@jscad/modeling 2.9.2 → 2.9.3

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 (61) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +4 -4
  3. package/dist/jscad-modeling.min.js +411 -417
  4. package/package.json +3 -2
  5. package/src/colors/colorize.test.js +1 -1
  6. package/src/geometries/geom2/toOutlines.js +66 -52
  7. package/src/geometries/geom3/create.js +1 -1
  8. package/src/geometries/geom3/create.test.js +1 -1
  9. package/src/geometries/geom3/fromPoints.js +1 -1
  10. package/src/geometries/path2/index.d.ts +0 -1
  11. package/src/geometries/path2/index.js +0 -1
  12. package/src/geometries/poly3/create.js +1 -1
  13. package/src/geometries/poly3/validate.js +14 -0
  14. package/src/maths/constants.d.ts +1 -0
  15. package/src/maths/constants.js +11 -0
  16. package/src/maths/utils/aboutEqualNormals.js +1 -5
  17. package/src/operations/booleans/intersectGeom3.js +2 -1
  18. package/src/operations/booleans/subtractGeom3.js +2 -1
  19. package/src/operations/booleans/to3DWalls.js +1 -1
  20. package/src/operations/booleans/unionGeom3.js +2 -1
  21. package/src/operations/expansions/expandGeom3.test.js +14 -14
  22. package/src/operations/expansions/expandShell.js +5 -4
  23. package/src/operations/expansions/extrudePolygon.js +7 -7
  24. package/src/operations/extrusions/extrudeFromSlices.test.js +2 -2
  25. package/src/operations/extrusions/extrudeRotate.js +5 -1
  26. package/src/operations/extrusions/extrudeRotate.test.js +5 -5
  27. package/src/operations/extrusions/extrudeWalls.js +2 -2
  28. package/src/operations/extrusions/project.js +11 -14
  29. package/src/operations/extrusions/project.test.js +50 -50
  30. package/src/operations/hulls/hullChain.test.js +4 -4
  31. package/src/operations/hulls/hullGeom2.js +6 -18
  32. package/src/operations/hulls/hullGeom3.js +5 -18
  33. package/src/operations/hulls/hullPath2.js +4 -14
  34. package/src/operations/hulls/hullPoints2.js +43 -92
  35. package/src/operations/hulls/toUniquePoints.js +34 -0
  36. package/src/operations/modifiers/generalize.js +2 -13
  37. package/src/operations/modifiers/generalize.test.js +0 -32
  38. package/src/operations/modifiers/insertTjunctions.js +1 -1
  39. package/src/operations/modifiers/insertTjunctions.test.js +21 -21
  40. package/src/operations/modifiers/mergePolygons.js +11 -14
  41. package/src/operations/{booleans → modifiers}/reTesselateCoplanarPolygons.js +1 -1
  42. package/src/operations/{booleans → modifiers}/reTesselateCoplanarPolygons.test.js +5 -5
  43. package/src/operations/{booleans → modifiers}/retessellate.js +2 -9
  44. package/src/operations/{booleans → modifiers}/retessellate.test.js +0 -0
  45. package/src/operations/modifiers/snapPolygons.test.js +12 -12
  46. package/src/operations/modifiers/triangulatePolygons.js +3 -3
  47. package/src/operations/transforms/center.js +1 -1
  48. package/src/primitives/cuboid.js +1 -1
  49. package/src/primitives/cylinderElliptic.js +1 -1
  50. package/src/primitives/ellipsoid.js +2 -2
  51. package/src/primitives/polyhedron.js +1 -1
  52. package/src/primitives/roundedCuboid.js +6 -6
  53. package/src/primitives/roundedCylinder.js +1 -1
  54. package/src/primitives/torus.test.js +6 -6
  55. package/src/primitives/triangle.js +1 -2
  56. package/src/utils/trigonometry.js +1 -2
  57. package/src/geometries/path2/eachPoint.d.ts +0 -9
  58. package/src/geometries/path2/eachPoint.js +0 -17
  59. package/src/geometries/path2/eachPoint.test.js +0 -11
  60. package/src/operations/modifiers/edges.js +0 -195
  61. package/src/operations/modifiers/repairTjunctions.js +0 -44
@@ -1,3 +1,4 @@
1
+ const aboutEqualNormals = require('../../maths/utils/aboutEqualNormals')
1
2
  const vec3 = require('../../maths/vec3')
2
3
 
3
4
  const poly3 = require('../../geometries/poly3')
@@ -53,9 +54,12 @@ const calculateAnglesBetween = (current, opposite, normal) => {
53
54
  return [angle1, angle2]
54
55
  }
55
56
 
57
+ const v1 = vec3.create()
58
+ const v2 = vec3.create()
59
+
56
60
  const calculateAngle = (prevpoint, point, nextpoint, normal) => {
57
- const d0 = vec3.subtract(vec3.create(), point, prevpoint)
58
- const d1 = vec3.subtract(vec3.create(), nextpoint, point)
61
+ const d0 = vec3.subtract(v1, point, prevpoint)
62
+ const d1 = vec3.subtract(v2, nextpoint, point)
59
63
  vec3.cross(d0, d0, d1)
60
64
  return vec3.dot(d0, normal)
61
65
  }
@@ -76,7 +80,7 @@ const createPolygonAnd = (edge) => {
76
80
 
77
81
  edge = next
78
82
  }
79
- if (points.length > 0) polygon = poly3.fromPoints(points)
83
+ if (points.length > 0) polygon = poly3.create(points)
80
84
  return polygon
81
85
  }
82
86
 
@@ -85,7 +89,7 @@ const createPolygonAnd = (edge) => {
85
89
  * @param {poly3[]} sourcepolygons - list of polygons
86
90
  * @returns {poly3[]} new set of polygons
87
91
  */
88
- const mergeCoplanarPolygons = (epsilon, sourcepolygons) => {
92
+ const mergeCoplanarPolygons = (sourcepolygons) => {
89
93
  if (sourcepolygons.length < 2) return sourcepolygons
90
94
 
91
95
  const normal = sourcepolygons[0].plane
@@ -167,18 +171,11 @@ const mergeCoplanarPolygons = (epsilon, sourcepolygons) => {
167
171
  if (polygon) destpolygons.push(polygon)
168
172
  })
169
173
 
174
+ edgeList.clear()
175
+
170
176
  return destpolygons
171
177
  }
172
178
 
173
- // Normals are directional vectors with component values from 0 to 1.0, requiring specialized comparision
174
- // This EPS is derived from a serieas of tests to determine the optimal precision for comparing coplanar polygons,
175
- // as provided by the sphere primitive at high segmentation
176
- // This EPS is for 64 bit Number values
177
- const NEPS = 1e-13
178
-
179
- // Compare two normals (unit vectors) for equality.
180
- const aboutEqualNormals = (a, b) => (Math.abs(a[0] - b[0]) <= NEPS && Math.abs(a[1] - b[1]) <= NEPS && Math.abs(a[2] - b[2]) <= NEPS)
181
-
182
179
  const coplanar = (plane1, plane2) => {
183
180
  // expect the same distance from the origin, within tolerance
184
181
  if (Math.abs(plane1[3] - plane2[3]) < 0.00000015) {
@@ -202,7 +199,7 @@ const mergePolygons = (epsilon, polygons) => {
202
199
  let destpolygons = []
203
200
  polygonsPerPlane.forEach((mapping) => {
204
201
  const sourcepolygons = mapping[1]
205
- const retesselayedpolygons = mergeCoplanarPolygons(epsilon, sourcepolygons)
202
+ const retesselayedpolygons = mergeCoplanarPolygons(sourcepolygons)
206
203
  destpolygons = destpolygons.concat(retesselayedpolygons)
207
204
  })
208
205
  return destpolygons
@@ -31,7 +31,7 @@ const reTesselateCoplanarPolygons = (sourcepolygons) => {
31
31
  // convert all polygon vertices to 2D
32
32
  // Make a list of all encountered y coordinates
33
33
  // And build a map of all polygons that have a vertex at a certain y coordinate:
34
- const ycoordinateBinningFactor = 1.0 / EPS * 10
34
+ const ycoordinateBinningFactor = 10 / EPS
35
35
  for (let polygonindex = 0; polygonindex < numpolygons; polygonindex++) {
36
36
  const poly3d = sourcepolygons[polygonindex]
37
37
  let vertices2d = []
@@ -17,11 +17,11 @@ const rotatePoly3 = (angles, polygon) => {
17
17
  }
18
18
 
19
19
  test.only('retessellateCoplanarPolygons: should merge coplanar polygons', (t) => {
20
- const polyA = poly3.fromPoints([[-5, -5, 0], [5, -5, 0], [5, 5, 0], [-5, 5, 0]])
21
- const polyB = poly3.fromPoints([[5, -5, 0], [8, 0, 0], [5, 5, 0]])
22
- const polyC = poly3.fromPoints([[-5, 5, 0], [-8, 0, 0], [-5, -5, 0]])
23
- const polyD = poly3.fromPoints([[-5, 5, 0], [5, 5, 0], [0, 8, 0]])
24
- const polyE = poly3.fromPoints([[5, -5, 0], [-5, -5, 0], [0, -8, 0]])
20
+ const polyA = poly3.create([[-5, -5, 0], [5, -5, 0], [5, 5, 0], [-5, 5, 0]])
21
+ const polyB = poly3.create([[5, -5, 0], [8, 0, 0], [5, 5, 0]])
22
+ const polyC = poly3.create([[-5, 5, 0], [-8, 0, 0], [-5, -5, 0]])
23
+ const polyD = poly3.create([[-5, 5, 0], [5, 5, 0], [0, 8, 0]])
24
+ const polyE = poly3.create([[5, -5, 0], [-5, -5, 0], [0, -8, 0]])
25
25
 
26
26
  // combine polygons in each direction
27
27
  let obs = reTesselateCoplanarPolygons([polyA, polyB])
@@ -1,16 +1,9 @@
1
1
  const geom3 = require('../../geometries/geom3')
2
2
  const poly3 = require('../../geometries/poly3')
3
3
 
4
- const reTesselateCoplanarPolygons = require('./reTesselateCoplanarPolygons')
5
-
6
- // Normals are directional vectors with component values from 0 to 1.0, requiring specialized comparison
7
- // This EPS is derived from a series of tests to determine the optimal precision for comparing coplanar polygons,
8
- // as provided by the sphere primitive at high segmentation
9
- // This EPS is for 64 bit Number values
10
- const NEPS = 1e-13
4
+ const aboutEqualNormals = require('../../maths/utils/aboutEqualNormals')
11
5
 
12
- // Compare two normals (unit vectors) for equality.
13
- const aboutEqualNormals = (a, b) => (Math.abs(a[0] - b[0]) <= NEPS && Math.abs(a[1] - b[1]) <= NEPS && Math.abs(a[2] - b[2]) <= NEPS)
6
+ const reTesselateCoplanarPolygons = require('./reTesselateCoplanarPolygons')
14
7
 
15
8
  const coplanar = (plane1, plane2) => {
16
9
  // expect the same distance from the origin, within tolerance
@@ -7,49 +7,49 @@ const snapPolygons = require('./snapPolygons')
7
7
  test('snapPolygons: snap of polygons produces expected results', (t) => {
8
8
  const polygons = [
9
9
  // valid polygons
10
- poly3.fromPoints([[0, 0, 0], [0, 10, 0], [0, 10, 10]]), // OK
11
- poly3.fromPoints([[0, 0, 0], [0, 10, 0], [0, 10, 10], [0, 0, 10]]), // OK
10
+ poly3.create([[0, 0, 0], [0, 10, 0], [0, 10, 10]]), // OK
11
+ poly3.create([[0, 0, 0], [0, 10, 0], [0, 10, 10], [0, 0, 10]]), // OK
12
12
  // invalid polygons
13
13
  poly3.create(),
14
- poly3.fromPoints([[0, 0, 0]]),
15
- poly3.fromPoints([[0, 0, 0], [0, 10, 0]]),
14
+ poly3.create([[0, 0, 0]]),
15
+ poly3.create([[0, 0, 0], [0, 10, 0]]),
16
16
  // duplicated vertices
17
- poly3.fromPoints([
17
+ poly3.create([
18
18
  [-24.445112000000115, 19.346837333333426, 46.47572533333356],
19
19
  [-24.44446933333345, 19.346837333333426, 46.47508266666689],
20
20
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
21
21
  [-23.70540266666678, 18.79864266666676, 39.56448800000019]
22
22
  ]), // OK
23
- poly3.fromPoints([
23
+ poly3.create([
24
24
  [-24.445112000000115, 19.346837333333426, 46.47572533333356],
25
25
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
26
26
  [-23.70540266666678, 18.79864266666676, 39.56448800000019]
27
27
  ]),
28
- poly3.fromPoints([
28
+ poly3.create([
29
29
  [-23.70540266666678, 18.79864266666676, 39.56448800000019],
30
30
  [-23.70540266666678, 18.79864266666676, 39.56448800000019]
31
31
  ]),
32
32
  // duplicate vertices after snap
33
- poly3.fromPoints([
33
+ poly3.create([
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
37
  [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234]
38
38
  ]), // OK
39
- poly3.fromPoints([
39
+ poly3.create([
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
43
  [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234]
44
44
  ]),
45
- poly3.fromPoints([
45
+ poly3.create([
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
49
  [-23.70540266666678 - 0.00001234, 18.79864266666676 + 0.000001234, 39.56448800000019 + 0.00001234]
50
50
  ]),
51
51
  // inverted polygon
52
- poly3.fromPoints([
52
+ poly3.create([
53
53
  [20.109133333333336, -4.894033333333335, -1.0001266666666668],
54
54
  [20.021120000000003, -5.1802133333333344, -1.0001266666666668],
55
55
  [20.020300000000002, -5.182946666666668, -1.0001266666666668],
@@ -61,7 +61,7 @@ test('snapPolygons: snap of polygons produces expected results', (t) => {
61
61
  const results = snapPolygons(0.0001, polygons)
62
62
  t.is(results.length, 5)
63
63
 
64
- const exp3 = poly3.fromPoints([
64
+ const exp3 = poly3.create([
65
65
  [-24.4451, 19.3468, 46.4757],
66
66
  [-24.4445, 19.3468, 46.475100000000005],
67
67
  [-23.7054, 18.7986, 39.5645]
@@ -10,15 +10,15 @@ const triangulatePolygon = (epsilon, polygon, triangles) => {
10
10
  polygon.vertices.forEach((vertice) => vec3.add(midpoint, midpoint, vertice))
11
11
  vec3.snap(midpoint, vec3.divide(midpoint, midpoint, [nv, nv, nv]), epsilon)
12
12
  for (let i = 0; i < nv; i++) {
13
- const poly = poly3.fromPoints([midpoint, polygon.vertices[i], polygon.vertices[(i + 1) % nv]])
13
+ const poly = poly3.create([midpoint, polygon.vertices[i], polygon.vertices[(i + 1) % nv]])
14
14
  if (polygon.color) poly.color = polygon.color
15
15
  triangles.push(poly)
16
16
  }
17
17
  return
18
18
  }
19
19
  // exactly 4 vertices, use simple triangulation
20
- const poly0 = poly3.fromPoints([polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]])
21
- const poly1 = poly3.fromPoints([polygon.vertices[0], polygon.vertices[2], polygon.vertices[3]])
20
+ const poly0 = poly3.create([polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]])
21
+ const poly1 = poly3.create([polygon.vertices[0], polygon.vertices[2], polygon.vertices[3]])
22
22
  if (polygon.color) {
23
23
  poly0.color = polygon.color
24
24
  poly1.color = polygon.color
@@ -39,7 +39,7 @@ const center = (options, ...objects) => {
39
39
  const defaults = {
40
40
  axes: [true, true, true],
41
41
  relativeTo: [0, 0, 0]
42
- // TODO : Add addition 'methods' of centering; midpoint, centeriod
42
+ // TODO: Add additional 'methods' of centering: midpoint, centroid
43
43
  }
44
44
  const { axes, relativeTo } = Object.assign({}, defaults, options)
45
45
 
@@ -43,7 +43,7 @@ const cuboid = (options) => {
43
43
  ]
44
44
  return pos
45
45
  })
46
- return poly3.fromPoints(points)
46
+ return poly3.create(points)
47
47
  })
48
48
  )
49
49
  return result
@@ -90,7 +90,7 @@ const cylinderElliptic = (options) => {
90
90
  // adjust the points to center
91
91
  const fromPoints = (...points) => {
92
92
  const newpoints = points.map((point) => vec3.add(vec3.create(), point, center))
93
- return poly3.fromPoints(newpoints)
93
+ return poly3.create(newpoints)
94
94
  }
95
95
 
96
96
  const polygons = []
@@ -66,7 +66,7 @@ const ellipsoid = (options) => {
66
66
  point = vec3.subtract(vec3.create(), vec3.scale(p1, prevcylinderpoint, cospitch), vec3.scale(p2, zvector, sinpitch))
67
67
  points.push(vec3.add(point, point, center))
68
68
 
69
- polygons.push(poly3.fromPoints(points))
69
+ polygons.push(poly3.create(points))
70
70
 
71
71
  points = []
72
72
  point = vec3.add(vec3.create(), vec3.scale(p1, prevcylinderpoint, prevcospitch), vec3.scale(p2, zvector, prevsinpitch))
@@ -81,7 +81,7 @@ const ellipsoid = (options) => {
81
81
  points.push(vec3.add(vec3.create(), center, point))
82
82
  points.reverse()
83
83
 
84
- polygons.push(poly3.fromPoints(points))
84
+ polygons.push(poly3.create(points))
85
85
  }
86
86
  prevcospitch = cospitch
87
87
  prevsinpitch = sinpitch
@@ -60,7 +60,7 @@ const polyhedron = (options) => {
60
60
  }
61
61
 
62
62
  const polygons = faces.map((face, findex) => {
63
- const polygon = poly3.fromPoints(face.map((pindex) => points[pindex]))
63
+ const polygon = poly3.create(face.map((pindex) => points[pindex]))
64
64
  if (colors && colors[findex]) polygon.color = colors[findex]
65
65
  return polygon
66
66
  })
@@ -57,10 +57,10 @@ const stitchCorners = (previousCorners, currentCorners) => {
57
57
  const previous = previousCorners[i]
58
58
  const current = currentCorners[i]
59
59
  for (let j = 0; j < (previous.length - 1); j++) {
60
- polygons.push(poly3.fromPoints([previous[j], previous[j + 1], current[j]]))
60
+ polygons.push(poly3.create([previous[j], previous[j + 1], current[j]]))
61
61
 
62
62
  if (j < (current.length - 1)) {
63
- polygons.push(poly3.fromPoints([current[j], previous[j + 1], current[j + 1]]))
63
+ polygons.push(poly3.create([current[j], previous[j + 1], current[j + 1]]))
64
64
  }
65
65
  }
66
66
  }
@@ -81,7 +81,7 @@ const stitchWalls = (previousCorners, currentCorners) => {
81
81
  const p1 = previous[0]
82
82
  const c1 = current[0]
83
83
 
84
- polygons.push(poly3.fromPoints([p0, p1, c1, c0]))
84
+ polygons.push(poly3.create([p0, p1, c1, c0]))
85
85
  }
86
86
  return polygons
87
87
  }
@@ -104,7 +104,7 @@ const stitchSides = (bottomCorners, topCorners) => {
104
104
  const polygons = []
105
105
  for (let i = 0; i < topPoints.length; i++) {
106
106
  const j = (i + 1) % topPoints.length
107
- polygons.push(poly3.fromPoints([bottomPoints[i], bottomPoints[j], topPoints[j], topPoints[i]]))
107
+ polygons.push(poly3.create([bottomPoints[i], bottomPoints[j], topPoints[j], topPoints[i]]))
108
108
  }
109
109
  return polygons
110
110
  }
@@ -168,10 +168,10 @@ const roundedCuboid = (options) => {
168
168
  if (slice === segments) {
169
169
  // add the top
170
170
  let points = cornersPos.map((corner) => corner[0])
171
- polygons.push(poly3.fromPoints(points))
171
+ polygons.push(poly3.create(points))
172
172
  // add the bottom
173
173
  points = cornersNeg.map((corner) => corner[0])
174
- polygons.push(poly3.fromPoints(points))
174
+ polygons.push(poly3.create(points))
175
175
  }
176
176
 
177
177
  prevCornersPos = cornersPos
@@ -66,7 +66,7 @@ const roundedCylinder = (options) => {
66
66
  const fromPoints = (points) => {
67
67
  // adjust the points to center
68
68
  const newpoints = points.map((point) => vec3.add(point, point, center))
69
- return poly3.fromPoints(newpoints)
69
+ return poly3.create(newpoints)
70
70
  }
71
71
 
72
72
  const polygons = []
@@ -10,24 +10,24 @@ test('torus (defaults)', (t) => {
10
10
  const obs = torus()
11
11
  const pts = geom3.toPoints(obs)
12
12
 
13
- t.notThrows.skip(() => geom3.validate(obs))
13
+ t.notThrows(() => geom3.validate(obs))
14
14
  t.is(pts.length, 2048) // 32 * 32 * 2 (polys/segment) = 2048
15
15
 
16
16
  const bounds = measureBoundingBox(obs)
17
17
  const expectedBounds = [[-5, -5, -1], [5, 5, 1]]
18
- t.notThrows.skip(() => geom3.validate(obs))
18
+ t.notThrows(() => geom3.validate(obs))
19
19
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected: ' + JSON.stringify(bounds))
20
20
  })
21
21
 
22
- test('torus (Simple options)', (t) => {
22
+ test('torus (simple options)', (t) => {
23
23
  const obs = torus({ innerRadius: 0.5, innerSegments: 4, outerRadius: 5, outerSegments: 8 })
24
24
  const pts = geom3.toPoints(obs)
25
- t.notThrows.skip(() => geom3.validate(obs))
25
+ t.notThrows(() => geom3.validate(obs))
26
26
  t.is(pts.length, 64) // 4 * 8 * 2 (polys/segment) = 64
27
27
 
28
28
  const bounds = measureBoundingBox(obs)
29
29
  const expectedBounds = [[-5.5, -5.5, -0.5], [5.5, 5.5, 0.5]]
30
- t.notThrows.skip(() => geom3.validate(obs))
30
+ t.notThrows(() => geom3.validate(obs))
31
31
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected: ' + JSON.stringify(bounds))
32
32
  })
33
33
 
@@ -48,6 +48,6 @@ test('torus (square by square)', (t) => {
48
48
 
49
49
  const bounds = measureBoundingBox(obs)
50
50
  const expectedBounds = [[-5, -5, -1], [5, 5, 1]]
51
- t.notThrows.skip(() => geom3.validate(obs))
51
+ t.notThrows(() => geom3.validate(obs))
52
52
  t.true(comparePoints(bounds, expectedBounds), 'Bounding box was not as expected: ' + JSON.stringify(bounds))
53
53
  })
@@ -1,11 +1,10 @@
1
+ const { NEPS } = require('../maths/constants')
1
2
  const vec2 = require('../maths/vec2')
2
3
 
3
4
  const geom2 = require('../geometries/geom2')
4
5
 
5
6
  const { isNumberArray } = require('./commonChecks')
6
7
 
7
- const NEPS = 1e-13
8
-
9
8
  // returns angle C
10
9
  const solveAngleFromSSS = (a, b, c) => Math.acos(((a * a) + (b * b) - (c * c)) / (2 * a * b))
11
10
 
@@ -1,5 +1,4 @@
1
-
2
- const NEPS = 1e-13
1
+ const { NEPS } = require('../maths/constants')
3
2
 
4
3
  /*
5
4
  * Returns zero if n is within epsilon of zero, otherwise return n
@@ -1,9 +0,0 @@
1
- import Path2 from './type'
2
- import Vec2 from '../../maths/vec2/type'
3
-
4
- export default eachPoint
5
-
6
- export interface EachPointOptions {}
7
- export type EachPointThunk = (value: Vec2, index: number, array: Array<Vec2>) => void
8
-
9
- declare function eachPoint(options: EachPointOptions, thunk: EachPointThunk, path: Path2): void
@@ -1,17 +0,0 @@
1
- const toPoints = require('./toPoints')
2
-
3
- /**
4
- * Calls a function for each point in the path.
5
- * @param {Object} options - options
6
- * @param {Function} thunk - the function to call
7
- * @param {path2} path - the path to traverse
8
- * @alias module:modeling/geometries/path2.eachPoint
9
- *
10
- * @example
11
- * eachPoint({}, accumulate, path)
12
- */
13
- const eachPoint = (options, thunk, path) => {
14
- toPoints(path).forEach(thunk)
15
- }
16
-
17
- module.exports = eachPoint
@@ -1,11 +0,0 @@
1
- const test = require('ava')
2
-
3
- const vec2 = require('../../maths/vec2')
4
-
5
- const { eachPoint, fromPoints } = require('./index')
6
-
7
- test('eachPoint: Each point is emitted', (t) => {
8
- const collector = []
9
- eachPoint({}, (point) => collector.push(point), fromPoints({}, [[1, 1], [2, 2]]))
10
- t.deepEqual(collector, [vec2.fromValues(1, 1), vec2.fromValues(2, 2)])
11
- })
@@ -1,195 +0,0 @@
1
- const vec3 = require('../../maths/vec3')
2
- const line3 = require('../../maths/line3')
3
-
4
- const poly3 = require('../../geometries/poly3')
5
-
6
- /*
7
- * Add a unique edge to the given list of edges.
8
- * Each edge has a list of associated polygons.
9
- * Edges with two polygons are complete, while edges with one polygon are open, i.e hole or t-junction..
10
- */
11
- const addEdge = (edges, edge, polygon) => {
12
- const ei = edges.findIndex((element) => {
13
- if (element) {
14
- if (vec3.equals(element[0], edge[0]) && vec3.equals(element[1], edge[1])) return true
15
- if (vec3.equals(element[0], edge[1]) && vec3.equals(element[1], edge[0])) return true
16
- }
17
- return false
18
- })
19
- if (ei >= 0) {
20
- edge = edges[ei]
21
- edge.polygons.push(polygon)
22
- } else {
23
- edge.polygons = [polygon]
24
- edges.push(edge)
25
- }
26
- }
27
-
28
- /*
29
- * Remove the edge from the given list of edges.
30
- */
31
- const removeEdge = (edges, edge) => {
32
- const ei = edges.findIndex((element) => {
33
- if (element) {
34
- if (vec3.equals(element[0], edge[0]) && vec3.equals(element[1], edge[1])) return true
35
- if (vec3.equals(element[0], edge[1]) && vec3.equals(element[1], edge[0])) return true
36
- }
37
- return false
38
- })
39
- if (ei >= 0) {
40
- edges[ei].polygons = []
41
- edges[ei] = null
42
- }
43
- }
44
-
45
- /*
46
- * Add all edges of the polygon to the given list of edges.
47
- */
48
- const addPolygon = (edges, polygon) => {
49
- const vertices = polygon.vertices
50
- const nv = vertices.length
51
-
52
- let edge = [vertices[nv - 1], vertices[0]]
53
- addEdge(edges, edge, polygon)
54
-
55
- for (let i = 0; i < (nv - 1); i++) {
56
- edge = [vertices[i], vertices[i + 1]]
57
- addEdge(edges, edge, polygon)
58
- }
59
- }
60
-
61
- /*
62
- * Remove all polygons associated with the old edge from the given list of edges.
63
- */
64
- const removePolygons = (edges, oldedge) => {
65
- // console.log('removePolygons',oldedge)
66
- const polygons = oldedge.polygons
67
- polygons.forEach((polygon) => {
68
- const vertices = polygon.vertices
69
- const nv = vertices.length
70
-
71
- let edge = [vertices[nv - 1], vertices[0]]
72
- removeEdge(edges, edge)
73
-
74
- for (let i = 0; i < (nv - 1); i++) {
75
- edge = [vertices[i], vertices[i + 1]]
76
- removeEdge(edges, edge)
77
- }
78
- })
79
- }
80
-
81
- /*
82
- * Split the polygon, ensuring one polygon includes the open edge.
83
- */
84
- const splitPolygon = (openedge, polygon, eps) => {
85
- // console.log('splitPolygon',openedge,polygon)
86
- const vertices = polygon.vertices
87
- const i = vertices.findIndex((point) => almostEquals(eps, point, openedge[0]))
88
- const polygon1 = poly3.fromPoints([vertices[(i + 0) % 3], vertices[(i + 1) % 3], openedge[1]])
89
- const polygon2 = poly3.fromPoints([openedge[1], vertices[(i + 1) % 3], vertices[(i + 2) % 3]])
90
- if (polygon.color) {
91
- polygon1.color = polygon.color
92
- polygon2.color = polygon.color
93
- }
94
- // console.log('polygon1',polygon1)
95
- // console.log('polygon2',polygon2)
96
- return [polygon1, polygon2]
97
- }
98
-
99
- /*
100
- * TBD This should be part of vec3.
101
- */
102
- const almostEquals = (eps, v1, v2) => (Math.abs(v1[0] - v2[0]) <= eps && Math.abs(v1[1] - v2[1]) <= eps && Math.abs(v1[2] - v2[2]) <= eps)
103
-
104
- const enclosedEdge = (openedge, edge, eps) => {
105
- if (openedge.distance < edge.distance) {
106
- // only look for opposing edges
107
- if (vec3.equals(openedge[0], edge[1])) {
108
- // only opposing open edges enclosed by the edge
109
- const distanceE0O0 = vec3.squaredDistance(openedge[0], edge[0])
110
- const distanceE0O1 = vec3.squaredDistance(openedge[1], edge[0])
111
- const distanceE1O0 = vec3.squaredDistance(openedge[0], edge[1])
112
- const distanceE1O1 = vec3.squaredDistance(openedge[1], edge[1])
113
- if (distanceE0O0 <= edge.distance && distanceE0O1 < edge.distance && distanceE1O0 < edge.distance && distanceE1O1 < edge.distance) {
114
- // only look for paralell open edges
115
- const line3d = line3.fromPoints(edge[0], edge[1])
116
- const closest0 = vec3.snap(vec3.create(), eps, line3.closestPoint(openedge[0], line3d))
117
- const closest1 = vec3.snap(vec3.create(), eps, line3.closestPoint(openedge[1], line3d))
118
- if (almostEquals(eps, closest0, openedge[0]) && almostEquals(eps, closest1, openedge[1])) {
119
- return true
120
- }
121
- }
122
- }
123
- }
124
- return false
125
- }
126
-
127
- /*
128
- * Split the edge if posssible from the list of open edges.
129
- * Return a list of new polygons, or null if not possible
130
- */
131
- const splitEdge = (openedges, edge, eps) => {
132
- // console.log('splitEdge',edge)
133
- for (let i = 0; i < openedges.length; i++) {
134
- const openedge = openedges[i]
135
- if (openedge) {
136
- if (enclosedEdge(openedge, edge, eps)) {
137
- // spit the polygon associated with the edge
138
- const polygon = edge.polygons[0]
139
- const newpolygons = splitPolygon(openedge, polygon, eps)
140
- return newpolygons
141
- }
142
- }
143
- }
144
- return null
145
- }
146
-
147
- /*
148
- * Cull a list of open edges (see above) from the list of edges.
149
- */
150
- const cullOpenEdges = (edges) => {
151
- const openedges = []
152
- edges.forEach((edge) => {
153
- const polygons = edge.polygons
154
- if (polygons.length === 1) {
155
- // console.log('open edge: ',edge[0],'<-->',edge[1])
156
- edge.distance = vec3.squaredDistance(edge[0], edge[1])
157
- openedges.push(edge)
158
- }
159
- })
160
- // console.log('open edges:',openedges.length)
161
- // console.log('**********OPEN*********')
162
- // console.log(openedges)
163
- // console.log('**********OPEN*********')
164
- return openedges
165
- }
166
-
167
- /*
168
- * Convert the list of edges into a list of polygons.
169
- */
170
- const edgesToPolygons = (edges) => {
171
- const polygons = []
172
- edges.forEach((edge) => {
173
- if (edge && edge.polygons) {
174
- edge.polygons.forEach((polygon) => {
175
- if (polygon.visited) return
176
- polygon.visited = true
177
- polygons.push(polygon)
178
- })
179
- }
180
- })
181
- return polygons
182
- }
183
-
184
- /*
185
- * Convert the given list of polygons to a list of edges.
186
- */
187
- const polygonsToEdges = (polygons) => {
188
- const edges = []
189
- polygons.forEach((polygon) => {
190
- addPolygon(edges, polygon)
191
- })
192
- return edges
193
- }
194
-
195
- module.exports = { polygonsToEdges, edgesToPolygons, cullOpenEdges, splitEdge, removePolygons, addPolygon }
@@ -1,44 +0,0 @@
1
- const { polygonsToEdges, edgesToPolygons, cullOpenEdges, splitEdge, removePolygons, addPolygon } = require('./edges')
2
-
3
- /*
4
- */
5
- const repairTjunctions = (epsilon, polygons) => {
6
- const edges = polygonsToEdges(polygons)
7
- let openedges = cullOpenEdges(edges)
8
- if (openedges.length === 0) return polygons
9
-
10
- // split open edges until no longer possible
11
- let splitting = true
12
- while (splitting) {
13
- let splitcount = 0
14
- for (let i = 0; i < openedges.length; i++) {
15
- const edge = openedges[i]
16
- if (edge && edge.polygons && edge.polygons.length === 1) {
17
- const newpolygons = splitEdge(openedges, edge, epsilon)
18
- if (newpolygons) {
19
- openedges[i] = null
20
- addPolygon(openedges, newpolygons[0])
21
- addPolygon(openedges, newpolygons[1])
22
-
23
- // adjust the master list as well
24
- removePolygons(edges, edge)
25
- // add edges for each new polygon
26
- addPolygon(edges, newpolygons[0])
27
- addPolygon(edges, newpolygons[1])
28
-
29
- splitcount++
30
- break // start again
31
- }
32
- }
33
- }
34
- splitting = (splitcount > 0)
35
- }
36
- openedges = openedges.filter((edge) => (edge && edge.polygons && edge.polygons.length === 1))
37
- if (openedges.length > 0) console.warn('Repair of all T-junctions failed:', openedges.length)
38
-
39
- // rebuild the list of polygons from the edges
40
- polygons = edgesToPolygons(edges)
41
- return polygons
42
- }
43
-
44
- module.exports = repairTjunctions