@jscad/modeling 2.6.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/jscad-modeling.min.js +81 -78
- package/package.json +2 -2
- package/src/colors/colorize.test.js +2 -2
- package/src/geometries/geom2/transform.js +0 -2
- package/src/geometries/geom3/transform.js +0 -2
- package/src/geometries/path2/transform.js +0 -2
- package/src/geometries/poly3/isConvex.js +1 -1
- package/src/geometries/poly3/measureArea.js +12 -13
- package/src/geometries/poly3/measureArea.test.js +15 -0
- package/src/geometries/poly3/plane.js +1 -2
- package/src/maths/plane/fromPoints.js +32 -10
- package/src/maths/plane/fromPoints.test.js +4 -0
- package/src/measurements/measureBoundingBox.js +14 -27
- package/src/measurements/measureCenterOfMass.js +0 -1
- package/src/measurements/measureEpsilon.js +3 -9
- package/src/operations/booleans/reTesselateCoplanarPolygons.js +1 -1
- package/src/operations/booleans/trees/PolygonTreeNode.js +0 -1
- package/src/operations/expansions/expand.test.js +1 -1
- package/src/operations/extrusions/extrudeRotate.test.js +18 -10
- package/src/operations/modifiers/generalize.js +0 -1
- package/src/operations/modifiers/snapPolygons.js +1 -1
- package/src/operations/modifiers/snapPolygons.test.js +10 -10
- package/src/primitives/index.d.ts +1 -0
- package/src/primitives/index.js +2 -1
- package/src/primitives/triangle.d.ts +10 -0
- package/src/primitives/triangle.js +164 -0
- package/src/primitives/triangle.test.js +95 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jscad/modeling",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Constructive Solid Geometry (CSG) Library for JSCAD",
|
|
5
5
|
"repository": "https://github.com/jscad/OpenJSCAD.org",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"nyc": "15.1.0",
|
|
61
61
|
"uglifyify": "5.0.2"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "fbc9b90f0ae02bea4e6e7b974c65e751c3858269"
|
|
64
64
|
}
|
|
@@ -58,8 +58,8 @@ test('color (rgba on geometry)', (t) => {
|
|
|
58
58
|
|
|
59
59
|
test('color (returns new object)', (t) => {
|
|
60
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]])
|
|
61
|
+
// const obj1 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
62
|
+
// const obj2 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
63
63
|
const obj3 = geom2.fromPoints([[0, 0], [1, 0], [0, 1]])
|
|
64
64
|
|
|
65
65
|
const obs = colorize([1, 1, 1, 0.8], obj0, obj3)
|
|
@@ -13,7 +13,7 @@ const areVerticesConvex = (vertices) => {
|
|
|
13
13
|
const numvertices = vertices.length
|
|
14
14
|
if (numvertices > 2) {
|
|
15
15
|
// note: plane ~= normal point
|
|
16
|
-
const normal = plane.fromPoints(plane.create(), vertices
|
|
16
|
+
const normal = plane.fromPoints(plane.create(), ...vertices)
|
|
17
17
|
let prevprevpos = vertices[numvertices - 2]
|
|
18
18
|
let prevpos = vertices[numvertices - 1]
|
|
19
19
|
for (let i = 0; i < numvertices; i++) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const plane = require('./plane')
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Measure the area of the given polygon.
|
|
@@ -14,19 +14,18 @@ const measureArea = (poly3) => {
|
|
|
14
14
|
}
|
|
15
15
|
const vertices = poly3.vertices
|
|
16
16
|
|
|
17
|
-
// calculate a
|
|
18
|
-
const
|
|
19
|
-
const b = vertices[1]
|
|
20
|
-
const c = vertices[2]
|
|
21
|
-
const ba = vec3.subtract(vec3.create(), b, a)
|
|
22
|
-
const ca = vec3.subtract(vec3.create(), c, a)
|
|
23
|
-
const normal = vec3.cross(ba, ba, ca)
|
|
17
|
+
// calculate a normal vector
|
|
18
|
+
const normal = plane(poly3)
|
|
24
19
|
|
|
25
|
-
//
|
|
20
|
+
// determine direction of projection
|
|
26
21
|
const ax = Math.abs(normal[0])
|
|
27
22
|
const ay = Math.abs(normal[1])
|
|
28
23
|
const az = Math.abs(normal[2])
|
|
29
|
-
|
|
24
|
+
|
|
25
|
+
if (ax + ay + az === 0) {
|
|
26
|
+
// normal does not exist
|
|
27
|
+
return 0
|
|
28
|
+
}
|
|
30
29
|
|
|
31
30
|
let coord = 3 // ignore Z coordinates
|
|
32
31
|
if ((ax > ay) && (ax > az)) {
|
|
@@ -50,7 +49,7 @@ const measureArea = (poly3) => {
|
|
|
50
49
|
}
|
|
51
50
|
area += (vertices[0][1] * (vertices[1][2] - vertices[n - 1][2]))
|
|
52
51
|
// scale to get area
|
|
53
|
-
area
|
|
52
|
+
area /= (2 * normal[0])
|
|
54
53
|
break
|
|
55
54
|
|
|
56
55
|
case 2: // ignore Y coordinates
|
|
@@ -62,7 +61,7 @@ const measureArea = (poly3) => {
|
|
|
62
61
|
}
|
|
63
62
|
area += (vertices[0][2] * (vertices[1][0] - vertices[n - 1][0]))
|
|
64
63
|
// scale to get area
|
|
65
|
-
area
|
|
64
|
+
area /= (2 * normal[1])
|
|
66
65
|
break
|
|
67
66
|
|
|
68
67
|
case 3: // ignore Z coordinates
|
|
@@ -75,7 +74,7 @@ const measureArea = (poly3) => {
|
|
|
75
74
|
}
|
|
76
75
|
area += (vertices[0][0] * (vertices[1][1] - vertices[n - 1][1]))
|
|
77
76
|
// scale to get area
|
|
78
|
-
area
|
|
77
|
+
area /= (2 * normal[2])
|
|
79
78
|
break
|
|
80
79
|
}
|
|
81
80
|
return area
|
|
@@ -37,6 +37,21 @@ test('poly3: measureArea() should return correct values', (t) => {
|
|
|
37
37
|
let ret4 = measureArea(ply4)
|
|
38
38
|
t.is(ret4, 19.5)
|
|
39
39
|
|
|
40
|
+
// colinear vertices non-zero area
|
|
41
|
+
const ply5 = fromPoints([[0, 0, 0], [1, 0, 0], [2, 0, 0], [0, 1, 0]])
|
|
42
|
+
const ret5 = measureArea(ply5)
|
|
43
|
+
t.is(ret5, 1)
|
|
44
|
+
|
|
45
|
+
// colinear vertices empty area
|
|
46
|
+
const ply6 = fromPoints([[0, 0, 0], [1, 0, 0], [2, 0, 0]])
|
|
47
|
+
const ret6 = measureArea(ply6)
|
|
48
|
+
t.is(ret6, 0)
|
|
49
|
+
|
|
50
|
+
// duplicate vertices empty area
|
|
51
|
+
const ply7 = fromPoints([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
|
|
52
|
+
const ret7 = measureArea(ply7)
|
|
53
|
+
t.is(ret7, 0)
|
|
54
|
+
|
|
40
55
|
// rotated to various angles
|
|
41
56
|
let rotation = mat4.fromZRotation(mat4.create(), (45 * 0.017453292519943295))
|
|
42
57
|
ply1 = transform(rotation, ply1)
|
|
@@ -2,8 +2,7 @@ const mplane = require('../../maths/plane/')
|
|
|
2
2
|
|
|
3
3
|
const plane = (polygon) => {
|
|
4
4
|
if (!polygon.plane) {
|
|
5
|
-
|
|
6
|
-
polygon.plane = mplane.fromPoints(mplane.create(), vertices[0], vertices[1], vertices[2])
|
|
5
|
+
polygon.plane = mplane.fromPoints(mplane.create(), ...polygon.vertices)
|
|
7
6
|
}
|
|
8
7
|
return polygon.plane
|
|
9
8
|
}
|
|
@@ -10,17 +10,39 @@ const vec3 = require('../vec3')
|
|
|
10
10
|
* @returns {plane} out
|
|
11
11
|
* @alias module:modeling/maths/plane.fromPoints
|
|
12
12
|
*/
|
|
13
|
-
const fromPoints = (out,
|
|
14
|
-
const
|
|
15
|
-
const ca = vec3.subtract(vec3.create(), c, a)
|
|
16
|
-
vec3.cross(ba, ba, ca)
|
|
17
|
-
vec3.normalize(ba, ba) // normal part
|
|
18
|
-
const w = vec3.dot(ba, a)
|
|
13
|
+
const fromPoints = (out, ...vertices) => {
|
|
14
|
+
const len = vertices.length
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
// Calculate normal vector for a single vertex
|
|
17
|
+
// Inline to avoid allocations
|
|
18
|
+
const ba = vec3.create()
|
|
19
|
+
const ca = vec3.create()
|
|
20
|
+
const vertexNormal = (index) => {
|
|
21
|
+
const a = vertices[index]
|
|
22
|
+
const b = vertices[(index + 1) % len]
|
|
23
|
+
const c = vertices[(index + 2) % len]
|
|
24
|
+
vec3.subtract(ba, b, a) // ba = b - a
|
|
25
|
+
vec3.subtract(ca, c, a) // ca = c - a
|
|
26
|
+
vec3.cross(ba, ba, ca) // ba = ba x ca
|
|
27
|
+
vec3.normalize(ba, ba)
|
|
28
|
+
return ba
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
out[0] = 0
|
|
32
|
+
out[1] = 0
|
|
33
|
+
out[2] = 0
|
|
34
|
+
if (len === 3) {
|
|
35
|
+
// optimization for triangles, which are always coplanar
|
|
36
|
+
vec3.copy(out, vertexNormal(0))
|
|
37
|
+
} else {
|
|
38
|
+
// sum of vertex normals
|
|
39
|
+
vertices.forEach((v, i) => {
|
|
40
|
+
vec3.add(out, out, vertexNormal(i))
|
|
41
|
+
})
|
|
42
|
+
// renormalize normal vector
|
|
43
|
+
vec3.normalize(out, out)
|
|
44
|
+
}
|
|
45
|
+
out[3] = vec3.dot(out, vertices[0])
|
|
24
46
|
return out
|
|
25
47
|
}
|
|
26
48
|
|
|
@@ -13,4 +13,8 @@ test('plane: fromPoints() should return a new plane with correct values', (t) =>
|
|
|
13
13
|
// planes created from the same points results in an invalid plane
|
|
14
14
|
const obs3 = fromPoints(obs1, [0, 6, 0], [0, 6, 0], [0, 6, 0])
|
|
15
15
|
t.true(compareVectors(obs3, [0 / 0, 0 / 0, 0 / 0, 0 / 0]))
|
|
16
|
+
|
|
17
|
+
// polygon with co-linear vertices
|
|
18
|
+
const obs4 = fromPoints(obs1, [0, 0, 0], [1, 0, 0], [2, 0, 0], [0, 1, 0])
|
|
19
|
+
t.true(compareVectors(obs4, [0, 0, 1, 0]))
|
|
16
20
|
})
|
|
@@ -31,10 +31,9 @@ const measureBoundingBoxOfPath2Points = (points) => {
|
|
|
31
31
|
vec2.min(minpoint, minpoint, point)
|
|
32
32
|
vec2.max(maxpoint, maxpoint, point)
|
|
33
33
|
})
|
|
34
|
-
|
|
35
34
|
boundingBox = [[minpoint[0], minpoint[1], 0], [maxpoint[0], maxpoint[1], 0]]
|
|
36
|
-
cache.set(points, boundingBox)
|
|
37
35
|
|
|
36
|
+
cache.set(points, boundingBox)
|
|
38
37
|
return boundingBox
|
|
39
38
|
}
|
|
40
39
|
|
|
@@ -55,7 +54,6 @@ const measureBoundingBoxOfPath2 = (geometry) => {
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
cache.set(geometry, boundingBox)
|
|
58
|
-
|
|
59
57
|
return boundingBox
|
|
60
58
|
}
|
|
61
59
|
|
|
@@ -65,6 +63,7 @@ const measureBoundingBoxOfPath2 = (geometry) => {
|
|
|
65
63
|
*/
|
|
66
64
|
const measureBoundingBoxOfGeom2Points = ({ points, sides }) => {
|
|
67
65
|
const cacheKey = points || sides
|
|
66
|
+
|
|
68
67
|
let boundingBox = cache.get(cacheKey)
|
|
69
68
|
if (boundingBox) return boundingBox
|
|
70
69
|
|
|
@@ -96,11 +95,9 @@ const measureBoundingBoxOfGeom2Points = ({ points, sides }) => {
|
|
|
96
95
|
vec2.max(maxpoint, maxpoint, side[0])
|
|
97
96
|
})
|
|
98
97
|
}
|
|
99
|
-
|
|
100
98
|
boundingBox = [[minpoint[0], minpoint[1], 0], [maxpoint[0], maxpoint[1], 0]]
|
|
101
99
|
|
|
102
100
|
cache.set(cacheKey, boundingBox)
|
|
103
|
-
|
|
104
101
|
return boundingBox
|
|
105
102
|
}
|
|
106
103
|
|
|
@@ -121,7 +118,6 @@ const measureBoundingBoxOfGeom2 = (geometry) => {
|
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
cache.set(geometry, boundingBox)
|
|
124
|
-
|
|
125
121
|
return boundingBox
|
|
126
122
|
}
|
|
127
123
|
|
|
@@ -150,7 +146,6 @@ const measureBoundingBoxOfGeom3Polygons = (polygons) => {
|
|
|
150
146
|
boundingBox = [[minpoint[0], minpoint[1], minpoint[2]], [maxpoint[0], maxpoint[1], maxpoint[2]]]
|
|
151
147
|
|
|
152
148
|
cache.set(polygons, boundingBox)
|
|
153
|
-
|
|
154
149
|
return boundingBox
|
|
155
150
|
}
|
|
156
151
|
|
|
@@ -171,13 +166,13 @@ const measureBoundingBoxOfGeom3 = (geometry) => {
|
|
|
171
166
|
}
|
|
172
167
|
|
|
173
168
|
cache.set(geometry, boundingBox)
|
|
174
|
-
|
|
175
169
|
return boundingBox
|
|
176
170
|
}
|
|
177
171
|
|
|
178
|
-
/*
|
|
172
|
+
/*
|
|
173
|
+
* swap values if specific axis value in the second vector has lower value than the axis value in first vector
|
|
174
|
+
*/
|
|
179
175
|
const fixBound = (i, v1, v2) => {
|
|
180
|
-
// this function will likely be inlined by the JS optimization compiler
|
|
181
176
|
if (v1[i] > v2[i]) {
|
|
182
177
|
const tmp = v1[i]
|
|
183
178
|
v1[i] = v2[i]
|
|
@@ -185,18 +180,21 @@ const fixBound = (i, v1, v2) => {
|
|
|
185
180
|
}
|
|
186
181
|
}
|
|
187
182
|
|
|
183
|
+
/*
|
|
184
|
+
* Transform the given bounding box
|
|
185
|
+
*/
|
|
188
186
|
const transformBoundingBox = (boundingBox, transforms) => {
|
|
189
|
-
if (
|
|
190
|
-
|
|
187
|
+
if (!mat4.isIdentity(transforms)) {
|
|
188
|
+
vec3.transform(boundingBox[0], boundingBox[0], transforms)
|
|
189
|
+
vec3.transform(boundingBox[1], boundingBox[1], transforms)
|
|
191
190
|
|
|
192
191
|
// we now have a new 2 vectors: [v1,v2] => [ [x1,y1,z1], [x2,y2,z2] ]
|
|
193
192
|
// transform can move bounding box corner in such way that it is no longer true that
|
|
194
193
|
// - v1 = [min(x1,x2),min(y1,y2),min(z1,z2)]
|
|
195
194
|
// - v2 = [max(x1,x2),max(y1,y2),max(z1,z2)]
|
|
196
|
-
fixBound(0, ...
|
|
197
|
-
fixBound(1, ...
|
|
198
|
-
fixBound(2, ...
|
|
199
|
-
return out
|
|
195
|
+
fixBound(0, ...boundingBox) // swap x, if higher value is in first vector
|
|
196
|
+
fixBound(1, ...boundingBox) // swap y, if higher value is in first vector
|
|
197
|
+
fixBound(2, ...boundingBox) // swap z, if higher value is in first vector
|
|
200
198
|
}
|
|
201
199
|
return boundingBox
|
|
202
200
|
}
|
|
@@ -223,15 +221,4 @@ const measureBoundingBox = (...geometries) => {
|
|
|
223
221
|
return results.length === 1 ? results[0] : results
|
|
224
222
|
}
|
|
225
223
|
|
|
226
|
-
/**
|
|
227
|
-
* Shortcut for geometries that are complex but have a fast way to calculate bounding box.
|
|
228
|
-
* Ellipsoid, or cylinder can provide boundingBox that pre-calculated based on parameters without traversing points.
|
|
229
|
-
*
|
|
230
|
-
* Another option is to calculate boundingBox durint toPoints (so the boundingBox could be calculated during transform)
|
|
231
|
-
*
|
|
232
|
-
* NOTE: It seems that measureBoundingBox is used all over the place, and it would be wise to allow
|
|
233
|
-
* shortcuts for calculating it, as default implementation goes through all points in geometry which is bound to be slow.
|
|
234
|
-
*/
|
|
235
|
-
measureBoundingBox.setCache = (geometry, boundingBox) => cache.set(geometry, boundingBox)
|
|
236
|
-
|
|
237
224
|
module.exports = measureBoundingBox
|
|
@@ -8,25 +8,19 @@ const measureBoundingBox = require('./measureBoundingBox')
|
|
|
8
8
|
* Measure the epsilon of the given (path2) geometry.
|
|
9
9
|
* @return {Number} the epsilon (precision) of the geometry
|
|
10
10
|
*/
|
|
11
|
-
const measureEpsilonOfPath2 = (geometry) =>
|
|
12
|
-
return calculateEpsilonFromBounds(measureBoundingBox(geometry), 2)
|
|
13
|
-
}
|
|
11
|
+
const measureEpsilonOfPath2 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox(geometry), 2)
|
|
14
12
|
|
|
15
13
|
/*
|
|
16
14
|
* Measure the epsilon of the given (geom2) geometry.
|
|
17
15
|
* @return {Number} the epsilon (precision) of the geometry
|
|
18
16
|
*/
|
|
19
|
-
const measureEpsilonOfGeom2 = (geometry) =>
|
|
20
|
-
return calculateEpsilonFromBounds(measureBoundingBox(geometry), 2)
|
|
21
|
-
}
|
|
17
|
+
const measureEpsilonOfGeom2 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox(geometry), 2)
|
|
22
18
|
|
|
23
19
|
/*
|
|
24
20
|
* Measure the epsilon of the given (geom3) geometry.
|
|
25
21
|
* @return {Float} the epsilon (precision) of the geometry
|
|
26
22
|
*/
|
|
27
|
-
const measureEpsilonOfGeom3 = (geometry) =>
|
|
28
|
-
return calculateEpsilonFromBounds(measureBoundingBox(geometry), 3)
|
|
29
|
-
}
|
|
23
|
+
const measureEpsilonOfGeom3 = (geometry) => calculateEpsilonFromBounds(measureBoundingBox(geometry), 3)
|
|
30
24
|
|
|
31
25
|
/**
|
|
32
26
|
* Measure the epsilon of the given geometries.
|
|
@@ -309,7 +309,7 @@ const reTesselateCoplanarPolygons = (sourcepolygons) => {
|
|
|
309
309
|
const polygon = poly3.fromPointsAndPlane(vertices3d, plane) // TODO support shared
|
|
310
310
|
|
|
311
311
|
// if we let empty polygon out, next retesselate will crash
|
|
312
|
-
if(polygon.vertices.length) destpolygons.push(polygon)
|
|
312
|
+
if (polygon.vertices.length) destpolygons.push(polygon)
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
} // if(yindex > 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
|
|
@@ -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,
|
|
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) => {
|
|
@@ -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
|
-
[
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
[
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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))
|
|
@@ -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 (!
|
|
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,28 +34,28 @@ 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
51
|
// inverted polygon
|
|
52
52
|
poly3.fromPoints([
|
|
53
|
-
[
|
|
54
|
-
[
|
|
55
|
-
[
|
|
56
|
-
[
|
|
57
|
-
[
|
|
58
|
-
])
|
|
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
|
+
])
|
|
59
59
|
]
|
|
60
60
|
|
|
61
61
|
const results = snapPolygons(0.0001, polygons)
|
|
@@ -66,5 +66,5 @@ test('snapPolygons: snap of polygons produces expected results', (t) => {
|
|
|
66
66
|
[-24.4445, 19.3468, 46.475100000000005],
|
|
67
67
|
[-23.7054, 18.7986, 39.5645]
|
|
68
68
|
])
|
|
69
|
-
t.deepEqual(results[3], exp3)
|
|
69
|
+
t.deepEqual(results[3].vertices, exp3.vertices)
|
|
70
70
|
})
|
|
@@ -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
|
package/src/primitives/index.js
CHANGED
|
@@ -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
|