@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
@@ -26,14 +26,14 @@ test('project (defaults)', (t) => {
26
26
  t.notThrows(() => geom2.validate(result))
27
27
  const pts = geom2.toPoints(result)
28
28
  const exp = [
29
- [0, -2.9999933333333333],
30
29
  [0, -5.000013333333333],
31
- [0, 5.000013333333333],
32
30
  [5.000013333333333, 0],
33
- [0, 2.9999933333333333],
31
+ [-5.000013333333333, 0],
34
32
  [-2.9999933333333333, 0],
35
33
  [2.9999933333333333, 0],
36
- [-5.000013333333333, 0]
34
+ [0, 2.9999933333333333],
35
+ [0, -2.9999933333333333],
36
+ [0, 5.000013333333333]
37
37
  ]
38
38
  t.true(comparePoints(pts, exp))
39
39
  })
@@ -43,40 +43,40 @@ test('project (X and Y axis)', (t) => {
43
43
  t.notThrows(() => geom2.validate(result))
44
44
  let pts = geom2.toPoints(result)
45
45
  let exp = [
46
- [-1.0000200000000001, -3.999986666666667],
47
- [-0.8314600000000001, 4.555553333333334],
48
- [-0.9807933333333334, -4.1951],
49
- [-0.7070933333333335, 4.707126666666667],
50
- [-0.9238600000000001, -4.382700000000001],
51
- [-0.5555666666666668, 4.831446666666667],
52
- [-0.8314600000000001, -4.555553333333334],
53
- [-0.3826666666666667, 4.923893333333334],
54
- [-0.7070933333333335, -4.707126666666667],
55
- [-0.19511333333333336, 4.98078],
56
- [-0.5555666666666668, -4.831446666666667],
57
- [0, 5.000006666666668],
58
- [-0.3826666666666667, -4.923893333333334],
59
- [0.19511333333333336, 4.98078],
60
46
  [-0.19511333333333336, -4.98078],
61
- [0.3826666666666667, 4.923893333333334],
62
47
  [0, -5.000006666666668],
63
- [0.5555666666666668, 4.831446666666667],
48
+ [0, 5.000006666666668],
49
+ [0.3826666666666667, 4.923893333333334],
50
+ [-0.3826666666666667, -4.923893333333334],
64
51
  [0.19511333333333336, -4.98078],
65
- [0.7070933333333335, 4.707126666666667],
52
+ [-0.19511333333333336, 4.98078],
53
+ [-0.5555666666666668, -4.831446666666667],
54
+ [0.5555666666666668, 4.831446666666667],
55
+ [-0.3826666666666667, 4.923893333333334],
66
56
  [0.3826666666666667, -4.923893333333334],
67
- [0.8314600000000001, 4.555553333333334],
57
+ [0.7070933333333335, 4.707126666666667],
58
+ [-0.7070933333333335, -4.707126666666667],
68
59
  [0.5555666666666668, -4.831446666666667],
69
- [0.9238600000000001, 4.382700000000001],
60
+ [-0.5555666666666668, 4.831446666666667],
61
+ [0.8314600000000001, 4.555553333333334],
62
+ [-0.8314600000000001, -4.555553333333334],
70
63
  [0.7070933333333335, -4.707126666666667],
71
- [0.9807933333333334, 4.1951],
64
+ [-0.7070933333333335, 4.707126666666667],
65
+ [-0.9238600000000001, -4.382700000000001],
66
+ [0.9238600000000001, 4.382700000000001],
67
+ [-0.8314600000000001, 4.555553333333334],
72
68
  [0.8314600000000001, -4.555553333333334],
69
+ [0.9807933333333334, 4.1951],
70
+ [-0.9807933333333334, -4.1951],
71
+ [0.9238600000000001, -4.382700000000001],
72
+ [-0.9238600000000001, 4.382700000000001],
73
73
  [1.0000200000000001, 3.999986666666667],
74
+ [-1.0000200000000001, -3.999986666666667],
74
75
  [1.0000200000000001, -3.999986666666667],
75
- [0.9238600000000001, -4.382700000000001],
76
- [0.9807933333333334, -4.1951],
77
76
  [-1.0000200000000001, 3.999986666666667],
78
77
  [-0.9807933333333334, 4.1951],
79
- [-0.9238600000000001, 4.382700000000001]
78
+ [0.9807933333333334, -4.1951],
79
+ [0.19511333333333336, 4.98078]
80
80
  ]
81
81
  t.true(comparePoints(pts, exp))
82
82
 
@@ -84,40 +84,40 @@ test('project (X and Y axis)', (t) => {
84
84
  t.notThrows(() => geom2.validate(result))
85
85
  pts = geom2.toPoints(result)
86
86
  exp = [
87
- [3.999986666666667, -1.0000200000000001],
88
- [-4.555553333333334, -0.8314600000000001],
89
- [4.1951, -0.9807933333333334],
90
- [-4.707126666666667, -0.7070933333333335],
91
- [4.382700000000001, -0.9238600000000001],
92
- [-4.831446666666667, -0.5555666666666668],
93
- [4.555553333333334, -0.8314600000000001],
94
- [-4.923893333333334, -0.3826666666666667],
95
- [4.707126666666667, -0.7070933333333335],
96
- [-4.98078, -0.19511333333333336],
97
- [4.831446666666667, -0.5555666666666668],
98
- [-5.000006666666668, 0],
99
- [4.923893333333334, -0.3826666666666667],
100
- [-4.98078, 0.19511333333333336],
101
87
  [4.98078, -0.19511333333333336],
102
- [-4.923893333333334, 0.3826666666666667],
103
88
  [5.000006666666668, 0],
104
- [-4.831446666666667, 0.5555666666666668],
89
+ [-5.000006666666668, 0],
90
+ [-4.923893333333334, 0.3826666666666667],
91
+ [4.923893333333334, -0.3826666666666667],
105
92
  [4.98078, 0.19511333333333336],
106
- [-4.707126666666667, 0.7070933333333335],
93
+ [-4.98078, -0.19511333333333336],
94
+ [4.831446666666667, -0.5555666666666668],
95
+ [-4.831446666666667, 0.5555666666666668],
96
+ [-4.923893333333334, -0.3826666666666667],
107
97
  [4.923893333333334, 0.3826666666666667],
108
- [-4.555553333333334, 0.8314600000000001],
98
+ [-4.707126666666667, 0.7070933333333335],
99
+ [4.707126666666667, -0.7070933333333335],
109
100
  [4.831446666666667, 0.5555666666666668],
110
- [-4.382700000000001, 0.9238600000000001],
101
+ [-4.831446666666667, -0.5555666666666668],
102
+ [4.555553333333334, -0.8314600000000001],
103
+ [-4.555553333333334, 0.8314600000000001],
111
104
  [4.707126666666667, 0.7070933333333335],
112
- [-4.1951, 0.9807933333333334],
105
+ [-4.707126666666667, -0.7070933333333335],
106
+ [4.382700000000001, -0.9238600000000001],
107
+ [-4.382700000000001, 0.9238600000000001],
108
+ [-4.555553333333334, -0.8314600000000001],
113
109
  [4.555553333333334, 0.8314600000000001],
110
+ [-4.1951, 0.9807933333333334],
111
+ [4.1951, -0.9807933333333334],
112
+ [4.382700000000001, 0.9238600000000001],
113
+ [-4.382700000000001, -0.9238600000000001],
114
+ [3.999986666666667, -1.0000200000000001],
114
115
  [-3.999986666666667, 1.0000200000000001],
115
116
  [3.999986666666667, 1.0000200000000001],
116
- [4.382700000000001, 0.9238600000000001],
117
- [4.1951, 0.9807933333333334],
118
117
  [-3.999986666666667, -1.0000200000000001],
118
+ [4.1951, 0.9807933333333334],
119
119
  [-4.1951, -0.9807933333333334],
120
- [-4.382700000000001, -0.9238600000000001]
120
+ [-4.98078, 0.19511333333333336]
121
121
  ]
122
122
  t.true(comparePoints(pts, exp))
123
123
  })
@@ -12,14 +12,14 @@ test('hullChain (two, geom2)', (t) => {
12
12
  let obs = hullChain(geometry1, geometry1)
13
13
  let pts = geom2.toPoints(obs)
14
14
 
15
- t.notThrows(() => geom2.validate(obs))
15
+ t.notThrows(() => geom2.validate(obs))
16
16
  t.is(pts.length, 4)
17
17
 
18
18
  // different
19
19
  obs = hullChain(geometry1, geometry2)
20
20
  pts = geom2.toPoints(obs)
21
21
 
22
- t.notThrows(() => geom2.validate(obs))
22
+ t.notThrows(() => geom2.validate(obs))
23
23
  t.is(pts.length, 6)
24
24
  })
25
25
 
@@ -33,7 +33,7 @@ test('hullChain (three, geom2)', (t) => {
33
33
  let pts = geom2.toPoints(obs)
34
34
 
35
35
  // the sides change based on the bestplane chosen in trees/Node.js
36
- t.notThrows(() => geom2.validate(obs))
36
+ t.notThrows(() => geom2.validate(obs))
37
37
  t.is(pts.length, 10)
38
38
 
39
39
  // closed
@@ -41,7 +41,7 @@ test('hullChain (three, geom2)', (t) => {
41
41
  pts = geom2.toPoints(obs)
42
42
 
43
43
  // the sides change based on the bestplane chosen in trees/Node.js
44
- t.notThrows(() => geom2.validate(obs))
44
+ t.notThrows(() => geom2.validate(obs))
45
45
  t.is(pts.length, 10)
46
46
  })
47
47
 
@@ -3,6 +3,7 @@ const flatten = require('../../utils/flatten')
3
3
  const geom2 = require('../../geometries/geom2')
4
4
 
5
5
  const hullPoints2 = require('./hullPoints2')
6
+ const toUniquePoints = require('./toUniquePoints')
6
7
 
7
8
  /*
8
9
  * Create a convex hull of the given geom2 geometries.
@@ -13,28 +14,15 @@ const hullGeom2 = (...geometries) => {
13
14
  geometries = flatten(geometries)
14
15
 
15
16
  // extract the unique points from the geometries
16
- const uniquepoints = []
17
- const found = new Map()
18
- for (let g = 0; g < geometries.length; g++) {
19
- const sides = geom2.toSides(geometries[g])
20
- for (let s = 0; s < sides.length; s++) {
21
- const side = sides[s]
22
- const point = side[0]
23
- const id = `${point[0]},${point[1]}`
24
- if (found.has(id)) continue
25
- uniquepoints.push(point)
26
- found.set(id, true)
27
- }
28
- }
29
- found.clear()
30
-
31
- const hullpoints = hullPoints2(uniquepoints)
17
+ const unique = toUniquePoints(geometries)
18
+
19
+ const hullPoints = hullPoints2(unique)
32
20
 
33
21
  // NOTE: more than three points are required to create a new geometry
34
- if (hullpoints.length < 3) return geom2.create()
22
+ if (hullPoints.length < 3) return geom2.create()
35
23
 
36
24
  // assemble a new geometry from the list of points
37
- return geom2.fromPoints(hullpoints)
25
+ return geom2.fromPoints(hullPoints)
38
26
  }
39
27
 
40
28
  module.exports = hullGeom2
@@ -4,6 +4,7 @@ const geom3 = require('../../geometries/geom3')
4
4
  const poly3 = require('../../geometries/poly3')
5
5
 
6
6
  const quickhull = require('./quickhull')
7
+ const toUniquePoints = require('./toUniquePoints')
7
8
 
8
9
  /*
9
10
  * Create a convex hull of the given geometries (geom3).
@@ -16,26 +17,12 @@ const hullGeom3 = (...geometries) => {
16
17
  if (geometries.length === 1) return geometries[0]
17
18
 
18
19
  // extract the unique vertices from the geometries
19
- const uniquevertices = []
20
- const found = new Map()
21
- for (let g = 0; g < geometries.length; ++g) {
22
- const polygons = geom3.toPolygons(geometries[g])
23
- for (let p = 0; p < polygons.length; ++p) {
24
- const vertices = polygons[p].vertices
25
- for (let v = 0; v < vertices.length; ++v) {
26
- const id = `${vertices[v]}`
27
- if (found.has(id)) continue
28
- uniquevertices.push(vertices[v])
29
- found.set(id, true)
30
- }
31
- }
32
- }
33
- found.clear()
34
-
35
- const faces = quickhull(uniquevertices, { skipTriangulation: true })
20
+ const unique = toUniquePoints(geometries)
21
+
22
+ const faces = quickhull(unique, { skipTriangulation: true })
36
23
 
37
24
  const polygons = faces.map((face) => {
38
- const vertices = face.map((index) => uniquevertices[index])
25
+ const vertices = face.map((index) => unique[index])
39
26
  return poly3.create(vertices)
40
27
  })
41
28
 
@@ -3,6 +3,7 @@ const flatten = require('../../utils/flatten')
3
3
  const path2 = require('../../geometries/path2')
4
4
 
5
5
  const hullPoints2 = require('./hullPoints2')
6
+ const toUniquePoints = require('./toUniquePoints')
6
7
 
7
8
  /*
8
9
  * Create a convex hull of the given geometries (path2).
@@ -13,23 +14,12 @@ const hullPath2 = (...geometries) => {
13
14
  geometries = flatten(geometries)
14
15
 
15
16
  // extract the unique points from the geometries
16
- const uniquepoints = []
17
- const found = new Set()
18
- geometries.forEach((geometry) => {
19
- const points = path2.toPoints(geometry)
20
- points.forEach((point) => {
21
- const key = point.toString()
22
- if (!found.has(key)) {
23
- uniquepoints.push(point)
24
- found.add(key)
25
- }
26
- })
27
- })
17
+ const unique = toUniquePoints(geometries)
28
18
 
29
- const hullpoints = hullPoints2(uniquepoints)
19
+ const hullPoints = hullPoints2(unique)
30
20
 
31
21
  // assemble a new geometry from the list of points
32
- return path2.fromPoints({ closed: true }, hullpoints)
22
+ return path2.fromPoints({ closed: true }, hullPoints)
33
23
  }
34
24
 
35
25
  module.exports = hullPath2
@@ -1,108 +1,59 @@
1
1
  const vec2 = require('../../maths/vec2')
2
2
 
3
- const angleBetweenPoints = (p0, p1) => Math.atan2((p1[1] - p0[1]), (p1[0] - p0[0]))
4
-
5
- const compareIndex = (index1, index2) => {
6
- if (index1.angle < index2.angle) {
7
- return -1
8
- } else if (index1.angle > index2.angle) {
9
- return 1
10
- } else {
11
- if (index1.distance < index2.distance) {
12
- return -1
13
- } else if (index1.distance > index2.distance) {
14
- return 1
15
- }
16
- }
17
- return 0
18
- }
19
-
20
- // Ported from https://github.com/bkiers/GrahamScan
21
- const compute = (points) => {
22
- if (points.length < 3) {
23
- return points
24
- }
25
-
26
- // Find the lowest point
27
- let min = 0
28
- points.forEach((point, i) => {
29
- const minpoint = points[min]
30
- if (point[1] === minpoint[1]) {
31
- if (point[0] < minpoint[0]) {
32
- min = i
33
- }
34
- } else if (point[1] < minpoint[1]) {
35
- min = i
3
+ /*
4
+ * Create a convex hull of the given set of points, where each point is an array of [x,y].
5
+ * Uses https://en.wikipedia.org/wiki/Graham_scan
6
+ * @param {Array} uniquePoints - list of UNIQUE points from which to create a hull
7
+ * @returns {Array} a list of points that form the hull
8
+ */
9
+ const hullPoints2 = (uniquePoints) => {
10
+ // find min point
11
+ let min = vec2.fromValues(Infinity, Infinity)
12
+ uniquePoints.forEach((point) => {
13
+ if (point[1] < min[1] || (point[1] === min[1] && point[0] < min[0])) {
14
+ min = point
36
15
  }
37
16
  })
38
17
 
39
- // Calculate angles and distances from the lowest point
40
- const al = []
41
- let angle = 0.0
42
- let dist = 0.0
43
- for (let i = 0; i < points.length; i++) {
44
- if (i === min) {
45
- continue
46
- }
47
- angle = angleBetweenPoints(points[min], points[i])
48
- if (angle < 0) {
49
- angle += Math.PI
50
- }
51
- dist = vec2.squaredDistance(points[min], points[i])
52
- al.push({ index: i, angle: angle, distance: dist })
53
- }
54
-
55
- al.sort((a, b) => compareIndex(a, b))
56
-
57
- // Wind around the points CCW, removing interior points
58
- const stack = new Array(points.length + 1)
59
- let j = 2
60
- for (let i = 0; i < points.length; i++) {
61
- if (i === min) {
62
- continue
63
- }
64
- stack[j] = al[j - 2].index
65
- j++
66
- }
67
- stack[0] = stack[points.length]
68
- stack[1] = min
18
+ // gather information for sorting by polar coordinates (point, angle, distSq)
19
+ const points = []
20
+ uniquePoints.forEach((point) => {
21
+ // use faster fakeAtan2 instead of Math.atan2
22
+ const angle = fakeAtan2(point[1] - min[1], point[0] - min[0])
23
+ const distSq = vec2.squaredDistance(point, min)
24
+ points.push({ point, angle, distSq })
25
+ })
69
26
 
70
- // clockwise < 0, colinear = 0, counter clockwise > 0
71
- const ccw = (i1, i2, i3) => (points[i2][0] - points[i1][0]) * (points[i3][1] - points[i1][1]) - (points[i2][1] - points[i1][1]) * (points[i3][0] - points[i1][0])
27
+ // sort by polar coordinates
28
+ points.sort((pt1, pt2) => pt1.angle < pt2.angle ? -1 : pt1.angle > pt2.angle ? 1 :
29
+ pt1.distSq < pt2.distSq ? -1 : pt1.distSq > pt2.distSq ? 1 : 0)
72
30
 
73
- let tmp
74
- let M = 2
75
- for (let i = 3; i <= points.length; i++) {
76
- while (ccw(stack[M - 1], stack[M], stack[i]) < Number.EPSILON) {
77
- M--
31
+ const stack = [] // start with empty stack
32
+ points.forEach((point) => {
33
+ let cnt = stack.length
34
+ while (cnt > 1 && ccw(stack[cnt - 2], stack[cnt - 1], point.point) <= Number.EPSILON) {
35
+ stack.pop() // get rid of colinear and interior (clockwise) points
36
+ cnt = stack.length
78
37
  }
79
- M++
80
- tmp = stack[i]
81
- stack[i] = stack[M]
82
- stack[M] = tmp
83
- }
38
+ stack.push(point.point)
39
+ })
84
40
 
85
- // Return the indices to the points
86
- const indices = new Array(M)
87
- for (let i = 0; i < M; i++) {
88
- indices[i] = stack[i + 1]
89
- }
90
- return indices
41
+ return stack
91
42
  }
92
43
 
93
- /*
94
- * Create a convex hull of the given set of points, where each point is an array of [x,y].
95
- * @param {Array} uniquepoints - list of UNIQUE points from which to create a hull
96
- * @returns {Array} a list of points that form the hull
97
- */
98
- const hullPoints2 = (uniquepoints) => {
99
- const indices = compute(uniquepoints)
44
+ // returns: < 0 clockwise, 0 colinear, > 0 counter-clockwise
45
+ const ccw = (v1, v2, v3) => (v2[0] - v1[0]) * (v3[1] - v1[1]) - (v2[1] - v1[1]) * (v3[0] - v1[0])
100
46
 
101
- let hullpoints = []
102
- if (Array.isArray(indices)) {
103
- hullpoints = indices.map((index) => uniquepoints[index])
47
+ // Returned "angle" is really 1/tan (inverse of slope) made negative to increase with angle.
48
+ // This function is strictly for sorting in this algorithm.
49
+ const fakeAtan2 = (y, x) => {
50
+ // The "if" is a special case for when the minimum vector found in loop above is present.
51
+ // We need to ensure that it sorts as the minimum point. Otherwise, this becomes NaN.
52
+ if (y === 0 && x === 0) {
53
+ return -Infinity
54
+ } else {
55
+ return -x / y
104
56
  }
105
- return hullpoints
106
57
  }
107
58
 
108
59
  module.exports = hullPoints2
@@ -0,0 +1,34 @@
1
+ const geom2 = require('../../geometries/geom2')
2
+ const geom3 = require('../../geometries/geom3')
3
+ const path2 = require('../../geometries/path2')
4
+
5
+ /*
6
+ * Return the unique vertices of a geometry
7
+ */
8
+ const toUniquePoints = (geometries) => {
9
+ const found = new Set()
10
+ const uniquePoints = []
11
+
12
+ const addPoint = (point) => {
13
+ const key = point.toString()
14
+ if (!found.has(key)) {
15
+ uniquePoints.push(point)
16
+ found.add(key)
17
+ }
18
+ }
19
+
20
+ geometries.forEach((geometry) => {
21
+ if (geom2.isA(geometry)) {
22
+ geom2.toPoints(geometry).forEach(addPoint)
23
+ } else if (geom3.isA(geometry)) {
24
+ // points are grouped by polygon
25
+ geom3.toPoints(geometry).forEach((points) => points.forEach(addPoint))
26
+ } else if (path2.isA(geometry)) {
27
+ path2.toPoints(geometry).forEach(addPoint)
28
+ }
29
+ })
30
+
31
+ return uniquePoints
32
+ }
33
+
34
+ module.exports = toUniquePoints
@@ -11,8 +11,6 @@ const mergePolygons = require('./mergePolygons')
11
11
  const insertTjunctions = require('./insertTjunctions')
12
12
  const triangulatePolygons = require('./triangulatePolygons')
13
13
 
14
- const repairTjunctions = require('./repairTjunctions')
15
-
16
14
  /*
17
15
  */
18
16
  const generalizePath2 = (options, geometry) => geometry
@@ -27,10 +25,9 @@ const generalizeGeom3 = (options, geometry) => {
27
25
  const defaults = {
28
26
  snap: false,
29
27
  simplify: false,
30
- triangulate: false,
31
- repair: false
28
+ triangulate: false
32
29
  }
33
- const { snap, simplify, triangulate, repair } = Object.assign({}, defaults, options)
30
+ const { snap, simplify, triangulate } = Object.assign({}, defaults, options)
34
31
 
35
32
  const epsilon = measureEpsilon(geometry)
36
33
  let polygons = geom3.toPolygons(geometry)
@@ -52,13 +49,6 @@ const generalizeGeom3 = (options, geometry) => {
52
49
  polygons = triangulatePolygons(epsilon, polygons)
53
50
  }
54
51
 
55
- // repair the polygons (possibly triangles) if requested
56
- if (repair) {
57
- // fix T junctions
58
- polygons = repairTjunctions(epsilon, polygons)
59
- // TODO fill holes
60
- }
61
-
62
52
  // FIXME replace with geom3.cloneShallow() when available
63
53
  const clone = Object.assign({}, geometry)
64
54
  clone.polygons = polygons
@@ -72,7 +62,6 @@ const generalizeGeom3 = (options, geometry) => {
72
62
  * @param {Boolean} [options.snap=false] the geometries should be snapped to epsilons
73
63
  * @param {Boolean} [options.simplify=false] the geometries should be simplified
74
64
  * @param {Boolean} [options.triangulate=false] the geometries should be triangulated
75
- * @param {Boolean} [options.repair=false] the geometries should be repaired
76
65
  * @param {...Object} geometries - the geometries to generalize
77
66
  * @return {Object|Array} the modified geometry, or a list of modified geometries
78
67
  * @alias module:modeling/modifiers.generalize
@@ -104,38 +104,6 @@ test('generalize: generalize of a geom3 produces an expected geom3', (t) => {
104
104
  ]
105
105
  t.notThrows(() => geom3.validate(result))
106
106
  t.true(comparePolygonsAsPoints(pts, exp))
107
-
108
- // apply repairs only (triangles)
109
- result = generalize({ repair: true }, geometry2)
110
- pts = geom3.toPoints(result)
111
- exp = [
112
- [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [-1.5707963267948966, -0.7853981633974483, 3.141592653589793],
113
- [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]],
114
- [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [-1.5707963267948966, 0.7853981633974483, 3.141592653589793],
115
- [-1.5707963267948966, 0.7853981633974483, -3.141592653589793]],
116
- [[1.5707963267948966, -0.7853981633974483, -3.141592653589793], [1.5707963267948966, 0.7853981633974483, -3.141592653589793],
117
- [1.5707963267948966, 0.7853981633974483, 3.141592653589793]],
118
- [[1.5707963267948966, -0.7853981633974483, -3.141592653589793], [1.5707963267948966, 0.7853981633974483, 3.141592653589793],
119
- [1.5707963267948966, -0.7853981633974483, 3.141592653589793]],
120
- [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [1.5707963267948966, -0.7853981633974483, -3.141592653589793],
121
- [1.5707963267948966, -0.7853981633974483, 3.141592653589793]],
122
- [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [1.5707963267948966, -0.7853981633974483, 3.141592653589793],
123
- [-1.5707963267948966, -0.7853981633974483, 3.141592653589793]],
124
- [[-1.5707963267948966, 0.7853981633974483, -3.141592653589793], [-1.5707963267948966, 0.7853981633974483, 3.141592653589793],
125
- [1.5707963267948966, 0.7853981633974483, 3.141592653589793]],
126
- [[-1.5707963267948966, 0.7853981633974483, -3.141592653589793], [1.5707963267948966, 0.7853981633974483, 3.141592653589793],
127
- [1.5707963267948966, 0.7853981633974483, -3.141592653589793]],
128
- [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [-1.5707963267948966, 0.7853981633974483, -3.141592653589793],
129
- [1.5707963267948966, 0.7853981633974483, -3.141592653589793]],
130
- [[-1.5707963267948966, -0.7853981633974483, -3.141592653589793], [1.5707963267948966, 0.7853981633974483, -3.141592653589793],
131
- [1.5707963267948966, -0.7853981633974483, -3.141592653589793]],
132
- [[-1.5707963267948966, -0.7853981633974483, 3.141592653589793], [1.5707963267948966, -0.7853981633974483, 3.141592653589793],
133
- [1.5707963267948966, 0.7853981633974483, 3.141592653589793]],
134
- [[-1.5707963267948966, -0.7853981633974483, 3.141592653589793], [1.5707963267948966, 0.7853981633974483, 3.141592653589793],
135
- [-1.5707963267948966, 0.7853981633974483, 3.141592653589793]]
136
- ]
137
- t.notThrows(() => geom3.validate(result))
138
- t.true(comparePolygonsAsPoints(pts, exp))
139
107
  })
140
108
 
141
109
  test('generalize: generalize of a geom3 with T junctions produces an expected geom3', (t) => {
@@ -259,7 +259,7 @@ const insertTjunctions = (polygons) => {
259
259
  // split the side by inserting the vertex:
260
260
  const newvertices = polygon.vertices.slice(0)
261
261
  newvertices.splice(insertionvertextagindex, 0, endvertex)
262
- const newpolygon = poly3.fromPoints(newvertices)
262
+ const newpolygon = poly3.create(newvertices)
263
263
 
264
264
  newpolygons[polygonindex] = newpolygon
265
265
 
@@ -56,33 +56,33 @@ test('insertTjunctions: insertTjunctions produces expected polygons', (t) => {
56
56
 
57
57
  const result3 = insertTjunctions(geom3.toPolygons(geometry3))
58
58
  let exp = [
59
- poly3.fromPoints([[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]]),
60
- poly3.fromPoints([[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, -1, 1]]),
61
- poly3.fromPoints([[-1, -1, -1], [1, -1, -1], [1, -1, 1], [-1, -1, 1]]),
62
- poly3.fromPoints([[-1, 1, -1], [-1, 1, 1], [1, 1, 1], [1, 1, -1]]),
63
- poly3.fromPoints([[-1, -1, -1], [-1, 1, -1], [1, 1, -1], [1, -1, -1]]),
64
- poly3.fromPoints([[0, 0, 1], [-1, -1, 1], [1, -1, 1], [1, 1, 1]]),
65
- poly3.fromPoints([[1, 1, 1], [-1, 1, 1], [0, 0, 1]]),
66
- poly3.fromPoints([[-1, 1, 1], [-1, -1, 1], [0, 0, 1]])
59
+ poly3.create([[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [-1, 1, -1]]),
60
+ poly3.create([[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, -1, 1]]),
61
+ poly3.create([[-1, -1, -1], [1, -1, -1], [1, -1, 1], [-1, -1, 1]]),
62
+ poly3.create([[-1, 1, -1], [-1, 1, 1], [1, 1, 1], [1, 1, -1]]),
63
+ poly3.create([[-1, -1, -1], [-1, 1, -1], [1, 1, -1], [1, -1, -1]]),
64
+ poly3.create([[0, 0, 1], [-1, -1, 1], [1, -1, 1], [1, 1, 1]]),
65
+ poly3.create([[1, 1, 1], [-1, 1, 1], [0, 0, 1]]),
66
+ poly3.create([[-1, 1, 1], [-1, -1, 1], [0, 0, 1]])
67
67
  ]
68
68
  t.not(result3, geom3.toPolygons(geometry3))
69
69
  t.true(comparePolygonLists(result3, exp))
70
70
 
71
71
  const result4 = insertTjunctions(geom3.toPolygons(geometry4))
72
72
  exp = [
73
- poly3.fromPoints([[-1, -1, -1], [-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [-1, 1, -1]]),
74
- poly3.fromPoints([[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, 0, 1], [1, -1, 1]]),
75
- poly3.fromPoints([[-1, -1, -1], [1, -1, -1], [1, -1, 1], [0, -1, 1], [-1, -1, 1]]),
76
- poly3.fromPoints([[-1, 1, -1], [-1, 1, 1], [0, 1, 1], [1, 1, 1], [1, 1, -1]]),
77
- poly3.fromPoints([[-1, -1, -1], [-1, 1, -1], [1, 1, -1], [1, -1, -1]]),
78
- poly3.fromPoints([[-1, -1, 1], [0, -1, 1], [0, 0, 1]]),
79
- poly3.fromPoints([[-1, 0, 1], [-1, -1, 1], [0, 0, 1]]),
80
- poly3.fromPoints([[0, -1, 1], [1, -1, 1], [0, 0, 1]]),
81
- poly3.fromPoints([[1, -1, 1], [1, 0, 1], [0, 0, 1]]),
82
- poly3.fromPoints([[1, 0, 1], [1, 1, 1], [0, 0, 1]]),
83
- poly3.fromPoints([[1, 1, 1], [0, 1, 1], [0, 0, 1]]),
84
- poly3.fromPoints([[0, 1, 1], [-1, 1, 1], [0, 0, 1]]),
85
- poly3.fromPoints([[-1, 1, 1], [-1, 0, 1], [0, 0, 1]])
73
+ poly3.create([[-1, -1, -1], [-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [-1, 1, -1]]),
74
+ poly3.create([[1, -1, -1], [1, 1, -1], [1, 1, 1], [1, 0, 1], [1, -1, 1]]),
75
+ poly3.create([[-1, -1, -1], [1, -1, -1], [1, -1, 1], [0, -1, 1], [-1, -1, 1]]),
76
+ poly3.create([[-1, 1, -1], [-1, 1, 1], [0, 1, 1], [1, 1, 1], [1, 1, -1]]),
77
+ poly3.create([[-1, -1, -1], [-1, 1, -1], [1, 1, -1], [1, -1, -1]]),
78
+ poly3.create([[-1, -1, 1], [0, -1, 1], [0, 0, 1]]),
79
+ poly3.create([[-1, 0, 1], [-1, -1, 1], [0, 0, 1]]),
80
+ poly3.create([[0, -1, 1], [1, -1, 1], [0, 0, 1]]),
81
+ poly3.create([[1, -1, 1], [1, 0, 1], [0, 0, 1]]),
82
+ poly3.create([[1, 0, 1], [1, 1, 1], [0, 0, 1]]),
83
+ poly3.create([[1, 1, 1], [0, 1, 1], [0, 0, 1]]),
84
+ poly3.create([[0, 1, 1], [-1, 1, 1], [0, 0, 1]]),
85
+ poly3.create([[-1, 1, 1], [-1, 0, 1], [0, 0, 1]])
86
86
  ]
87
87
  t.not(result4, geometry4)
88
88
  t.true(comparePolygonLists(result4, exp))