@jscad/modeling 2.9.3 → 2.9.6
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 +46 -0
- package/dist/jscad-modeling.min.js +133 -136
- package/package.json +2 -2
- package/src/colors/colorize.d.ts +6 -5
- package/src/geometries/geom2/type.d.ts +3 -2
- package/src/geometries/geom3/applyTransforms.js +1 -2
- package/src/geometries/geom3/type.d.ts +3 -2
- package/src/geometries/path2/appendPoints.js +3 -12
- package/src/geometries/path2/appendPoints.test.js +16 -0
- package/src/geometries/path2/concat.js +9 -8
- package/src/geometries/path2/concat.test.js +13 -7
- package/src/geometries/path2/type.d.ts +3 -2
- package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -2
- package/src/geometries/poly3/measureBoundingSphere.js +46 -8
- package/src/geometries/poly3/measureBoundingSphere.test.js +16 -26
- package/src/geometries/poly3/type.d.ts +3 -2
- package/src/geometries/types.d.ts +4 -2
- package/src/maths/mat4/fromRotation.js +9 -7
- package/src/maths/mat4/fromTaitBryanRotation.js +8 -6
- package/src/maths/mat4/fromXRotation.js +4 -2
- package/src/maths/mat4/fromYRotation.js +4 -2
- package/src/maths/mat4/fromZRotation.js +4 -2
- package/src/maths/mat4/isMirroring.js +11 -11
- package/src/maths/mat4/rotate.js +9 -5
- package/src/maths/mat4/rotateX.js +4 -2
- package/src/maths/mat4/rotateY.js +4 -2
- package/src/maths/mat4/rotateZ.js +4 -2
- package/src/maths/mat4/translate.test.js +2 -3
- package/src/maths/utils/index.d.ts +1 -0
- package/src/maths/utils/index.js +2 -0
- package/src/{utils → maths/utils}/trigonometry.d.ts +0 -0
- package/src/{utils → maths/utils}/trigonometry.js +1 -1
- package/src/{utils → maths/utils}/trigonometry.test.js +0 -0
- package/src/maths/vec2/distance.js +1 -1
- package/src/maths/vec2/fromAngleRadians.js +4 -2
- package/src/maths/vec2/length.js +1 -1
- package/src/maths/vec2/length.test.js +0 -10
- package/src/maths/vec3/angle.js +2 -2
- package/src/maths/vec3/angle.test.js +0 -12
- package/src/maths/vec3/distance.js +1 -1
- package/src/maths/vec3/length.js +1 -1
- package/src/maths/vec3/length.test.js +0 -10
- package/src/operations/booleans/intersectGeom2.test.js +69 -0
- package/src/operations/booleans/{intersect.test.js → intersectGeom3.test.js} +3 -71
- package/src/operations/booleans/subtractGeom2.test.js +72 -0
- package/src/operations/booleans/{subtract.test.js → subtractGeom3.test.js} +3 -74
- package/src/operations/booleans/trees/PolygonTreeNode.js +2 -2
- package/src/operations/booleans/unionGeom2.test.js +166 -0
- package/src/operations/booleans/{union.test.js → unionGeom3.test.js} +3 -168
- package/src/operations/extrusions/extrudeFromSlices.js +3 -2
- package/src/operations/extrusions/extrudeRotate.test.js +42 -42
- package/src/operations/extrusions/project.test.js +2 -2
- package/src/operations/extrusions/slice/repair.js +62 -0
- package/src/operations/modifiers/insertTjunctions.js +34 -35
- package/src/operations/modifiers/reTesselateCoplanarPolygons.js +32 -31
- package/src/primitives/circle.test.js +7 -0
- package/src/primitives/cylinderElliptic.js +4 -2
- package/src/primitives/cylinderElliptic.test.js +7 -1
- package/src/primitives/ellipse.js +1 -1
- package/src/primitives/ellipse.test.js +7 -0
- package/src/primitives/ellipsoid.js +1 -1
- package/src/primitives/geodesicSphere.js +3 -2
- package/src/primitives/roundedCuboid.js +4 -2
- package/src/primitives/roundedCylinder.js +1 -1
- package/src/primitives/torus.test.js +7 -3
- package/src/utils/index.d.ts +0 -1
- package/src/utils/index.js +1 -3
- package/src/maths/mat4/constants.d.ts +0 -1
- package/src/maths/mat4/constants.js +0 -5
- package/src/operations/extrusions/slice/repairSlice.js +0 -47
|
File without changes
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { sin, cos } = require('../utils/trigonometry')
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Create a new vector in the direction of the given angle.
|
|
3
5
|
*
|
|
@@ -7,8 +9,8 @@
|
|
|
7
9
|
* @alias module:modeling/maths/vec2.fromAngleRadians
|
|
8
10
|
*/
|
|
9
11
|
const fromAngleRadians = (out, radians) => {
|
|
10
|
-
out[0] =
|
|
11
|
-
out[1] =
|
|
12
|
+
out[0] = cos(radians)
|
|
13
|
+
out[1] = sin(radians)
|
|
12
14
|
return out
|
|
13
15
|
}
|
|
14
16
|
|
package/src/maths/vec2/length.js
CHANGED
|
@@ -25,15 +25,5 @@ test('vec2: length() should return correct values', (t) => {
|
|
|
25
25
|
const length5 = length(vec5)
|
|
26
26
|
nearlyEqual(t, length5, 2.23606, EPS)
|
|
27
27
|
|
|
28
|
-
// huge vector
|
|
29
|
-
const vec6 = fromValues(1e200, 1e200)
|
|
30
|
-
const length6 = length(vec6)
|
|
31
|
-
nearlyEqual(t, length6, Math.SQRT2 * 1e200, EPS)
|
|
32
|
-
|
|
33
|
-
// tiny vector
|
|
34
|
-
const vec7 = fromValues(1e-200, 1e-200)
|
|
35
|
-
const length7 = length(vec7)
|
|
36
|
-
nearlyEqual(t, length7, Math.SQRT2 * 1e-200, EPS)
|
|
37
|
-
|
|
38
28
|
t.true(true)
|
|
39
29
|
})
|
package/src/maths/vec3/angle.js
CHANGED
|
@@ -15,8 +15,8 @@ const angle = (a, b) => {
|
|
|
15
15
|
const bx = b[0]
|
|
16
16
|
const by = b[1]
|
|
17
17
|
const bz = b[2]
|
|
18
|
-
const mag1 = Math.
|
|
19
|
-
const mag2 = Math.
|
|
18
|
+
const mag1 = Math.sqrt(ax * ax + ay * ay + az * az)
|
|
19
|
+
const mag2 = Math.sqrt(bx * bx + by * by + bz * bz)
|
|
20
20
|
const mag = mag1 * mag2
|
|
21
21
|
const cosine = mag && dot(a, b) / mag
|
|
22
22
|
return Math.acos(Math.min(Math.max(cosine, -1), 1))
|
|
@@ -30,17 +30,5 @@ test('vec3: angle() should return correct values', (t) => {
|
|
|
30
30
|
const angle5 = angle(vec5a, vec5b)
|
|
31
31
|
nearlyEqual(t, angle5, 0.785398, EPS)
|
|
32
32
|
|
|
33
|
-
// tiny values
|
|
34
|
-
const vec6a = fromValues(1, 0, 0)
|
|
35
|
-
const vec6b = fromValues(1e-200, 1e-200, 0)
|
|
36
|
-
const angle6 = angle(vec6a, vec6b)
|
|
37
|
-
nearlyEqual(t, angle6, 0.785398, EPS)
|
|
38
|
-
|
|
39
|
-
// huge values
|
|
40
|
-
const vec7a = fromValues(1, 0, 0)
|
|
41
|
-
const vec7b = fromValues(1e200, 1e200, 0)
|
|
42
|
-
const angle7 = angle(vec7a, vec7b)
|
|
43
|
-
nearlyEqual(t, angle7, 0.785398, EPS)
|
|
44
|
-
|
|
45
33
|
t.true(true)
|
|
46
34
|
})
|
package/src/maths/vec3/length.js
CHANGED
|
@@ -41,15 +41,5 @@ test('vec3: length() should return correct values', (t) => {
|
|
|
41
41
|
const length9 = length(vec9)
|
|
42
42
|
nearlyEqual(t, length9, 3.74165, EPS)
|
|
43
43
|
|
|
44
|
-
// huge vector
|
|
45
|
-
const vec10 = fromValues(1e200, 0, 1e200)
|
|
46
|
-
const length10 = length(vec10)
|
|
47
|
-
nearlyEqual(t, length10, Math.SQRT2 * 1e200, EPS)
|
|
48
|
-
|
|
49
|
-
// tiny vector
|
|
50
|
-
const vec11 = fromValues(1e-200, 0, 1e-200)
|
|
51
|
-
const length11 = length(vec11)
|
|
52
|
-
nearlyEqual(t, length11, Math.SQRT2 * 1e-200, EPS)
|
|
53
|
-
|
|
54
44
|
t.true(true)
|
|
55
45
|
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const test = require('ava')
|
|
2
|
+
|
|
3
|
+
const { comparePoints } = require('../../../test/helpers')
|
|
4
|
+
|
|
5
|
+
const { geom2 } = require('../../geometries')
|
|
6
|
+
|
|
7
|
+
const { circle, rectangle } = require('../../primitives')
|
|
8
|
+
|
|
9
|
+
const { intersect } = require('./index')
|
|
10
|
+
|
|
11
|
+
const { center } = require('../transforms/center')
|
|
12
|
+
|
|
13
|
+
test('intersect: intersect of one or more geom2 objects produces expected geometry', (t) => {
|
|
14
|
+
const geometry1 = circle({ radius: 2, segments: 8 })
|
|
15
|
+
|
|
16
|
+
// intersect of one object
|
|
17
|
+
const result1 = intersect(geometry1)
|
|
18
|
+
let obs = geom2.toPoints(result1)
|
|
19
|
+
let exp = [
|
|
20
|
+
[2, 0],
|
|
21
|
+
[1.4142000000000001, 1.4142000000000001],
|
|
22
|
+
[0, 2],
|
|
23
|
+
[-1.4142000000000001, 1.4142000000000001],
|
|
24
|
+
[-2, 0],
|
|
25
|
+
[-1.4142000000000001, -1.4142000000000001],
|
|
26
|
+
[0, -2],
|
|
27
|
+
[1.4142000000000001, -1.4142000000000001]
|
|
28
|
+
]
|
|
29
|
+
t.notThrows(() => geom2.validate(result1))
|
|
30
|
+
t.is(obs.length, 8)
|
|
31
|
+
t.true(comparePoints(obs, exp))
|
|
32
|
+
|
|
33
|
+
// intersect of two non-overlapping objects
|
|
34
|
+
const geometry2 = center({ relativeTo: [10, 10, 0] }, rectangle({ size: [4, 4] }))
|
|
35
|
+
|
|
36
|
+
const result2 = intersect(geometry1, geometry2)
|
|
37
|
+
obs = geom2.toPoints(result2)
|
|
38
|
+
t.notThrows(() => geom2.validate(result2))
|
|
39
|
+
t.is(obs.length, 0)
|
|
40
|
+
|
|
41
|
+
// intersect of two partially overlapping objects
|
|
42
|
+
const geometry3 = rectangle({ size: [18, 18] })
|
|
43
|
+
|
|
44
|
+
const result3 = intersect(geometry2, geometry3)
|
|
45
|
+
obs = geom2.toPoints(result3)
|
|
46
|
+
exp = [
|
|
47
|
+
[9, 9], [8, 9], [8, 8], [9, 8]
|
|
48
|
+
]
|
|
49
|
+
t.notThrows(() => geom2.validate(result3))
|
|
50
|
+
t.is(obs.length, 4)
|
|
51
|
+
t.true(comparePoints(obs, exp))
|
|
52
|
+
|
|
53
|
+
// intersect of two completely overlapping objects
|
|
54
|
+
const result4 = intersect(geometry1, geometry3)
|
|
55
|
+
obs = geom2.toPoints(result4)
|
|
56
|
+
exp = [
|
|
57
|
+
[2, 0],
|
|
58
|
+
[1.4142000000000001, 1.4142000000000001],
|
|
59
|
+
[0, 2],
|
|
60
|
+
[-1.4142000000000001, 1.4142000000000001],
|
|
61
|
+
[-2, 0],
|
|
62
|
+
[-1.4142000000000001, -1.4142000000000001],
|
|
63
|
+
[0, -2],
|
|
64
|
+
[1.4142000000000001, -1.4142000000000001]
|
|
65
|
+
]
|
|
66
|
+
t.notThrows(() => geom2.validate(result4))
|
|
67
|
+
t.is(obs.length, 8)
|
|
68
|
+
t.true(comparePoints(obs, exp))
|
|
69
|
+
})
|
|
@@ -1,83 +1,15 @@
|
|
|
1
1
|
const test = require('ava')
|
|
2
2
|
|
|
3
|
-
const { comparePolygonsAsPoints
|
|
3
|
+
const { comparePolygonsAsPoints } = require('../../../test/helpers')
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const { geom3 } = require('../../geometries')
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { sphere, cuboid } = require('../../primitives')
|
|
8
8
|
|
|
9
9
|
const { intersect } = require('./index')
|
|
10
10
|
|
|
11
11
|
const { center } = require('../transforms/center')
|
|
12
12
|
|
|
13
|
-
// test('intersect: intersect of a path produces expected changes to points', (t) => {
|
|
14
|
-
// let geometry = path.fromPoints({}, [[0, 1, 0], [1, 0, 0]])
|
|
15
|
-
//
|
|
16
|
-
// geometry = intersect({normal: [1, 0, 0]}, geometry)
|
|
17
|
-
// let obs = path.toPoints(geometry)
|
|
18
|
-
// let exp = []
|
|
19
|
-
//
|
|
20
|
-
// t.deepEqual(obs, exp)
|
|
21
|
-
// })
|
|
22
|
-
|
|
23
|
-
test('intersect: intersect of one or more geom2 objects produces expected geometry', (t) => {
|
|
24
|
-
const geometry1 = circle({ radius: 2, segments: 8 })
|
|
25
|
-
|
|
26
|
-
// intersect of one object
|
|
27
|
-
const result1 = intersect(geometry1)
|
|
28
|
-
let obs = geom2.toPoints(result1)
|
|
29
|
-
let exp = [
|
|
30
|
-
[2, 0],
|
|
31
|
-
[1.4142000000000001, 1.4142000000000001],
|
|
32
|
-
[0, 2],
|
|
33
|
-
[-1.4142000000000001, 1.4142000000000001],
|
|
34
|
-
[-2, 0],
|
|
35
|
-
[-1.4142000000000001, -1.4142000000000001],
|
|
36
|
-
[0, -2],
|
|
37
|
-
[1.4142000000000001, -1.4142000000000001]
|
|
38
|
-
]
|
|
39
|
-
t.notThrows(() => geom2.validate(result1))
|
|
40
|
-
t.is(obs.length, 8)
|
|
41
|
-
t.true(comparePoints(obs, exp))
|
|
42
|
-
|
|
43
|
-
// intersect of two non-overlapping objects
|
|
44
|
-
const geometry2 = center({ relativeTo: [10, 10, 0] }, rectangle({ size: [4, 4] }))
|
|
45
|
-
|
|
46
|
-
const result2 = intersect(geometry1, geometry2)
|
|
47
|
-
obs = geom2.toPoints(result2)
|
|
48
|
-
t.notThrows(() => geom2.validate(result2))
|
|
49
|
-
t.is(obs.length, 0)
|
|
50
|
-
|
|
51
|
-
// intersect of two partially overlapping objects
|
|
52
|
-
const geometry3 = rectangle({ size: [18, 18] })
|
|
53
|
-
|
|
54
|
-
const result3 = intersect(geometry2, geometry3)
|
|
55
|
-
obs = geom2.toPoints(result3)
|
|
56
|
-
exp = [
|
|
57
|
-
[9, 9], [8, 9], [8, 8], [9, 8]
|
|
58
|
-
]
|
|
59
|
-
t.notThrows(() => geom2.validate(result3))
|
|
60
|
-
t.is(obs.length, 4)
|
|
61
|
-
t.true(comparePoints(obs, exp))
|
|
62
|
-
|
|
63
|
-
// intersect of two completely overlapping objects
|
|
64
|
-
const result4 = intersect(geometry1, geometry3)
|
|
65
|
-
obs = geom2.toPoints(result4)
|
|
66
|
-
exp = [
|
|
67
|
-
[2, 0],
|
|
68
|
-
[1.4142000000000001, 1.4142000000000001],
|
|
69
|
-
[0, 2],
|
|
70
|
-
[-1.4142000000000001, 1.4142000000000001],
|
|
71
|
-
[-2, 0],
|
|
72
|
-
[-1.4142000000000001, -1.4142000000000001],
|
|
73
|
-
[0, -2],
|
|
74
|
-
[1.4142000000000001, -1.4142000000000001]
|
|
75
|
-
]
|
|
76
|
-
t.notThrows(() => geom2.validate(result4))
|
|
77
|
-
t.is(obs.length, 8)
|
|
78
|
-
t.true(comparePoints(obs, exp))
|
|
79
|
-
})
|
|
80
|
-
|
|
81
13
|
test('intersect: intersect of one or more geom3 objects produces expected geometry', (t) => {
|
|
82
14
|
const geometry1 = sphere({ radius: 2, segments: 8 })
|
|
83
15
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const test = require('ava')
|
|
2
|
+
|
|
3
|
+
const { comparePoints } = require('../../../test/helpers')
|
|
4
|
+
|
|
5
|
+
const { geom2 } = require('../../geometries')
|
|
6
|
+
|
|
7
|
+
const { circle, rectangle } = require('../../primitives')
|
|
8
|
+
|
|
9
|
+
const { subtract } = require('./index')
|
|
10
|
+
|
|
11
|
+
const { center } = require('../transforms/center')
|
|
12
|
+
|
|
13
|
+
test('subtract: subtract of one or more geom2 objects produces expected geometry', (t) => {
|
|
14
|
+
const geometry1 = circle({ radius: 2, segments: 8 })
|
|
15
|
+
|
|
16
|
+
// subtract of one object
|
|
17
|
+
const result1 = subtract(geometry1)
|
|
18
|
+
let obs = geom2.toPoints(result1)
|
|
19
|
+
let exp = [
|
|
20
|
+
[2, 0],
|
|
21
|
+
[1.4142000000000001, 1.4142000000000001],
|
|
22
|
+
[0, 2],
|
|
23
|
+
[-1.4142000000000001, 1.4142000000000001],
|
|
24
|
+
[-2, 0],
|
|
25
|
+
[-1.4142000000000001, -1.4142000000000001],
|
|
26
|
+
[0, -2],
|
|
27
|
+
[1.4142000000000001, -1.4142000000000001]
|
|
28
|
+
]
|
|
29
|
+
t.notThrows(() => geom2.validate(result1))
|
|
30
|
+
t.is(obs.length, 8)
|
|
31
|
+
t.true(comparePoints(obs, exp))
|
|
32
|
+
|
|
33
|
+
// subtract of two non-overlapping objects
|
|
34
|
+
const geometry2 = center({ relativeTo: [10, 10, 0] }, rectangle({ size: [4, 4] }))
|
|
35
|
+
|
|
36
|
+
const result2 = subtract(geometry1, geometry2)
|
|
37
|
+
obs = geom2.toPoints(result2)
|
|
38
|
+
exp = [
|
|
39
|
+
[2, 0],
|
|
40
|
+
[1.4142000000000001, 1.4142000000000001],
|
|
41
|
+
[0, 2],
|
|
42
|
+
[-1.4142000000000001, 1.4142000000000001],
|
|
43
|
+
[-2, 0],
|
|
44
|
+
[-1.4142000000000001, -1.4142000000000001],
|
|
45
|
+
[0, -2],
|
|
46
|
+
[1.4142000000000001, -1.4142000000000001]
|
|
47
|
+
]
|
|
48
|
+
t.notThrows(() => geom2.validate(result2))
|
|
49
|
+
t.is(obs.length, 8)
|
|
50
|
+
t.true(comparePoints(obs, exp))
|
|
51
|
+
|
|
52
|
+
// subtract of two partially overlapping objects
|
|
53
|
+
const geometry3 = rectangle({ size: [18, 18] })
|
|
54
|
+
|
|
55
|
+
const result3 = subtract(geometry2, geometry3)
|
|
56
|
+
obs = geom2.toPoints(result3)
|
|
57
|
+
exp = [
|
|
58
|
+
[12, 12], [9, 9], [8, 9], [8, 12], [9, 8], [12, 8]
|
|
59
|
+
]
|
|
60
|
+
t.notThrows(() => geom2.validate(result3))
|
|
61
|
+
t.is(obs.length, 6)
|
|
62
|
+
t.true(comparePoints(obs, exp))
|
|
63
|
+
|
|
64
|
+
// subtract of two completely overlapping objects
|
|
65
|
+
const result4 = subtract(geometry1, geometry3)
|
|
66
|
+
obs = geom2.toPoints(result4)
|
|
67
|
+
exp = [
|
|
68
|
+
]
|
|
69
|
+
t.notThrows(() => geom2.validate(result4))
|
|
70
|
+
t.is(obs.length, 0)
|
|
71
|
+
t.deepEqual(obs, exp)
|
|
72
|
+
})
|
|
@@ -1,86 +1,15 @@
|
|
|
1
1
|
const test = require('ava')
|
|
2
2
|
|
|
3
|
-
const { comparePolygonsAsPoints
|
|
3
|
+
const { comparePolygonsAsPoints } = require('../../../test/helpers')
|
|
4
4
|
|
|
5
|
-
const {
|
|
5
|
+
const { geom3 } = require('../../geometries')
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { sphere, cuboid } = require('../../primitives')
|
|
8
8
|
|
|
9
9
|
const { subtract } = require('./index')
|
|
10
10
|
|
|
11
11
|
const { center } = require('../transforms/center')
|
|
12
12
|
|
|
13
|
-
// test('subtract: subtract of a path produces expected changes to points', (t) => {
|
|
14
|
-
// let geometry = path.fromPoints({}, [[0, 1, 0], [1, 0, 0]])
|
|
15
|
-
//
|
|
16
|
-
// geometry = subtract({normal: [1, 0, 0]}, geometry)
|
|
17
|
-
// let obs = path.toPoints(geometry)
|
|
18
|
-
// let exp = []
|
|
19
|
-
//
|
|
20
|
-
// t.deepEqual(obs, exp)
|
|
21
|
-
// })
|
|
22
|
-
|
|
23
|
-
test('subtract: subtract of one or more geom2 objects produces expected geometry', (t) => {
|
|
24
|
-
const geometry1 = circle({ radius: 2, segments: 8 })
|
|
25
|
-
|
|
26
|
-
// subtract of one object
|
|
27
|
-
const result1 = subtract(geometry1)
|
|
28
|
-
let obs = geom2.toPoints(result1)
|
|
29
|
-
let exp = [
|
|
30
|
-
[2, 0],
|
|
31
|
-
[1.4142000000000001, 1.4142000000000001],
|
|
32
|
-
[0, 2],
|
|
33
|
-
[-1.4142000000000001, 1.4142000000000001],
|
|
34
|
-
[-2, 0],
|
|
35
|
-
[-1.4142000000000001, -1.4142000000000001],
|
|
36
|
-
[0, -2],
|
|
37
|
-
[1.4142000000000001, -1.4142000000000001]
|
|
38
|
-
]
|
|
39
|
-
t.notThrows(() => geom2.validate(result1))
|
|
40
|
-
t.is(obs.length, 8)
|
|
41
|
-
t.true(comparePoints(obs, exp))
|
|
42
|
-
|
|
43
|
-
// subtract of two non-overlapping objects
|
|
44
|
-
const geometry2 = center({ relativeTo: [10, 10, 0] }, rectangle({ size: [4, 4] }))
|
|
45
|
-
|
|
46
|
-
const result2 = subtract(geometry1, geometry2)
|
|
47
|
-
obs = geom2.toPoints(result2)
|
|
48
|
-
exp = [
|
|
49
|
-
[2, 0],
|
|
50
|
-
[1.4142000000000001, 1.4142000000000001],
|
|
51
|
-
[0, 2],
|
|
52
|
-
[-1.4142000000000001, 1.4142000000000001],
|
|
53
|
-
[-2, 0],
|
|
54
|
-
[-1.4142000000000001, -1.4142000000000001],
|
|
55
|
-
[0, -2],
|
|
56
|
-
[1.4142000000000001, -1.4142000000000001]
|
|
57
|
-
]
|
|
58
|
-
t.notThrows(() => geom2.validate(result2))
|
|
59
|
-
t.is(obs.length, 8)
|
|
60
|
-
t.true(comparePoints(obs, exp))
|
|
61
|
-
|
|
62
|
-
// subtract of two partially overlapping objects
|
|
63
|
-
const geometry3 = rectangle({ size: [18, 18] })
|
|
64
|
-
|
|
65
|
-
const result3 = subtract(geometry2, geometry3)
|
|
66
|
-
obs = geom2.toPoints(result3)
|
|
67
|
-
exp = [
|
|
68
|
-
[12, 12], [9, 9], [8, 9], [8, 12], [9, 8], [12, 8]
|
|
69
|
-
]
|
|
70
|
-
t.notThrows(() => geom2.validate(result3))
|
|
71
|
-
t.is(obs.length, 6)
|
|
72
|
-
t.true(comparePoints(obs, exp))
|
|
73
|
-
|
|
74
|
-
// subtract of two completely overlapping objects
|
|
75
|
-
const result4 = subtract(geometry1, geometry3)
|
|
76
|
-
obs = geom2.toPoints(result4)
|
|
77
|
-
exp = [
|
|
78
|
-
]
|
|
79
|
-
t.notThrows(() => geom2.validate(result4))
|
|
80
|
-
t.is(obs.length, 0)
|
|
81
|
-
t.deepEqual(obs, exp)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
13
|
test('subtract: subtract of one or more geom3 objects produces expected geometry', (t) => {
|
|
85
14
|
const geometry1 = sphere({ radius: 2, segments: 8 })
|
|
86
15
|
|
|
@@ -132,8 +132,8 @@ class PolygonTreeNode {
|
|
|
132
132
|
const polygon = this.polygon
|
|
133
133
|
if (polygon) {
|
|
134
134
|
const bound = poly3.measureBoundingSphere(polygon)
|
|
135
|
-
const sphereradius = bound[
|
|
136
|
-
const spherecenter = bound
|
|
135
|
+
const sphereradius = bound[3] + EPS // ensure radius is LARGER then polygon
|
|
136
|
+
const spherecenter = bound
|
|
137
137
|
const d = vec3.dot(splane, spherecenter) - splane[3]
|
|
138
138
|
if (d > sphereradius) {
|
|
139
139
|
frontnodes.push(this)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const test = require('ava')
|
|
2
|
+
|
|
3
|
+
const { comparePoints } = require('../../../test/helpers')
|
|
4
|
+
|
|
5
|
+
const { geom2 } = require('../../geometries')
|
|
6
|
+
|
|
7
|
+
const { circle, rectangle } = require('../../primitives')
|
|
8
|
+
|
|
9
|
+
const { union } = require('./index')
|
|
10
|
+
|
|
11
|
+
const { center } = require('../transforms/center')
|
|
12
|
+
const { translate } = require('../transforms/translate')
|
|
13
|
+
|
|
14
|
+
test('union of one or more geom2 objects produces expected geometry', (t) => {
|
|
15
|
+
const geometry1 = circle({ radius: 2, segments: 8 })
|
|
16
|
+
|
|
17
|
+
// union of one object
|
|
18
|
+
const result1 = union(geometry1)
|
|
19
|
+
let obs = geom2.toPoints(result1)
|
|
20
|
+
let exp = [
|
|
21
|
+
[2, 0],
|
|
22
|
+
[1.4142000000000001, 1.4142000000000001],
|
|
23
|
+
[0, 2],
|
|
24
|
+
[-1.4142000000000001, 1.4142000000000001],
|
|
25
|
+
[-2, 0],
|
|
26
|
+
[-1.4142000000000001, -1.4142000000000001],
|
|
27
|
+
[0, -2],
|
|
28
|
+
[1.4142000000000001, -1.4142000000000001]
|
|
29
|
+
]
|
|
30
|
+
t.notThrows(() => geom2.validate(result1))
|
|
31
|
+
t.true(comparePoints(obs, exp))
|
|
32
|
+
|
|
33
|
+
// union of two non-overlapping objects
|
|
34
|
+
const geometry2 = center({ relativeTo: [10, 10, 0] }, rectangle({ size: [4, 4] }))
|
|
35
|
+
|
|
36
|
+
const result2 = union(geometry1, geometry2)
|
|
37
|
+
obs = geom2.toPoints(result2)
|
|
38
|
+
exp = [
|
|
39
|
+
[2, 0],
|
|
40
|
+
[1.4142000000000001, 1.4142000000000001],
|
|
41
|
+
[0, 2],
|
|
42
|
+
[-1.4142000000000001, 1.4142000000000001],
|
|
43
|
+
[-2, 0],
|
|
44
|
+
[-1.4142000000000001, -1.4142000000000001],
|
|
45
|
+
[0, -2],
|
|
46
|
+
[8, 12],
|
|
47
|
+
[8, 8],
|
|
48
|
+
[12, 8],
|
|
49
|
+
[12, 12],
|
|
50
|
+
[1.4142000000000001, -1.4142000000000001]
|
|
51
|
+
]
|
|
52
|
+
t.notThrows(() => geom2.validate(result2))
|
|
53
|
+
t.true(comparePoints(obs, exp))
|
|
54
|
+
|
|
55
|
+
// union of two partially overlapping objects
|
|
56
|
+
const geometry3 = rectangle({ size: [18, 18] })
|
|
57
|
+
|
|
58
|
+
const result3 = union(geometry2, geometry3)
|
|
59
|
+
obs = geom2.toPoints(result3)
|
|
60
|
+
exp = [
|
|
61
|
+
[11.999973333333333, 11.999973333333333],
|
|
62
|
+
[7.999933333333333, 11.999973333333333],
|
|
63
|
+
[9.000053333333334, 7.999933333333333],
|
|
64
|
+
[-9.000053333333334, 9.000053333333334],
|
|
65
|
+
[-9.000053333333334, -9.000053333333334],
|
|
66
|
+
[9.000053333333334, -9.000053333333334],
|
|
67
|
+
[7.999933333333333, 9.000053333333334],
|
|
68
|
+
[11.999973333333333, 7.999933333333333]
|
|
69
|
+
]
|
|
70
|
+
t.notThrows(() => geom2.validate(result3))
|
|
71
|
+
t.true(comparePoints(obs, exp))
|
|
72
|
+
|
|
73
|
+
// union of two completely overlapping objects
|
|
74
|
+
const result4 = union(geometry1, geometry3)
|
|
75
|
+
obs = geom2.toPoints(result4)
|
|
76
|
+
exp = [
|
|
77
|
+
[-9.000046666666666, -9.000046666666666],
|
|
78
|
+
[9.000046666666666, -9.000046666666666],
|
|
79
|
+
[9.000046666666666, 9.000046666666666],
|
|
80
|
+
[-9.000046666666666, 9.000046666666666]
|
|
81
|
+
]
|
|
82
|
+
t.notThrows(() => geom2.validate(result4))
|
|
83
|
+
t.true(comparePoints(obs, exp))
|
|
84
|
+
|
|
85
|
+
// union of unions of non-overlapping objects (BSP gap from #907)
|
|
86
|
+
const circ = circle({ radius: 1, segments: 32 })
|
|
87
|
+
const result5 = union(
|
|
88
|
+
union(
|
|
89
|
+
translate([17, 21], circ),
|
|
90
|
+
translate([7, 0], circ)
|
|
91
|
+
),
|
|
92
|
+
union(
|
|
93
|
+
translate([3, 21], circ),
|
|
94
|
+
translate([17, 21], circ)
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
obs = geom2.toPoints(result5)
|
|
98
|
+
t.notThrows.skip(() => geom2.validate(result5))
|
|
99
|
+
t.is(obs.length, 112)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('union of geom2 with closing issues #15', (t) => {
|
|
103
|
+
const c = geom2.create([
|
|
104
|
+
[[-45.82118740347841168159, -16.85726810555620147625], [-49.30331715865012398581, -14.68093629710870118288]],
|
|
105
|
+
[[-49.10586702080816223770, -15.27604177352110781385], [-48.16645938811709015681, -15.86317173589183227023]],
|
|
106
|
+
[[-49.60419521731581937729, -14.89550781504266296906], [-49.42407001323204696064, -15.67605088949303393520]],
|
|
107
|
+
[[-49.05727291218684626983, -15.48661638542171203881], [-49.10586702080816223770, -15.27604177352110781385]],
|
|
108
|
+
[[-49.30706235399220815907, -15.81529674600091794900], [-46.00505780290426827150, -17.21108547999804727624]],
|
|
109
|
+
[[-46.00505780290426827150, -17.21108547999804727624], [-45.85939703723252591772, -17.21502856394236857795]],
|
|
110
|
+
[[-45.85939703723252591772, -17.21502856394236857795], [-45.74972032664388166268, -17.11909303495791334626]],
|
|
111
|
+
[[-45.74972032664388166268, -17.11909303495791334626], [-45.73424573227583067592, -16.97420292661295349035]],
|
|
112
|
+
[[-45.73424573227583067592, -16.97420292661295349035], [-45.82118740347841168159, -16.85726810555620147625]],
|
|
113
|
+
[[-49.30331715865012398581, -14.68093629710870118288], [-49.45428884427643367871, -14.65565769658912387285]],
|
|
114
|
+
[[-49.45428884427643367871, -14.65565769658912387285], [-49.57891661679624917269, -14.74453612941635327616]],
|
|
115
|
+
[[-49.57891661679624917269, -14.74453612941635327616], [-49.60419521731581937729, -14.89550781504266296906]],
|
|
116
|
+
[[-49.42407001323204696064, -15.67605088949303393520], [-49.30706235399220815907, -15.81529674600091794900]],
|
|
117
|
+
[[-48.16645938811709015681, -15.86317173589183227023], [-49.05727291218684626983, -15.48661638542171203881]]
|
|
118
|
+
])
|
|
119
|
+
const d = geom2.create([
|
|
120
|
+
[[-49.03431352173912216585, -15.58610714407888764299], [-49.21443872582289458251, -14.80556406962851667686]],
|
|
121
|
+
[[-68.31614651314507113966, -3.10790373951434872879], [-49.34036769611472550423, -15.79733157434056778357]],
|
|
122
|
+
[[-49.58572929483430868913, -14.97552686612213790340], [-49.53755741140093959984, -15.18427183431472826669]],
|
|
123
|
+
[[-49.53755741140093959984, -15.18427183431472826669], [-54.61235529924312714911, -11.79066769321313756791]],
|
|
124
|
+
[[-49.30227466841120076424, -14.68159232649114187552], [-68.09792828135776687759, -2.77270756611528668145]],
|
|
125
|
+
[[-49.21443872582289458251, -14.80556406962851667686], [-49.30227466841120076424, -14.68159232649114187552]],
|
|
126
|
+
[[-49.34036769611472550423, -15.79733157434056778357], [-49.18823337756091262918, -15.82684012194931710837]],
|
|
127
|
+
[[-49.18823337756091262918, -15.82684012194931710837], [-49.06069007212390431505, -15.73881563386780157998]],
|
|
128
|
+
[[-49.06069007212390431505, -15.73881563386780157998], [-49.03431352173912216585, -15.58610714407888764299]],
|
|
129
|
+
[[-68.09792828135776687759, -2.77270756611528668145], [-68.24753735887460948106, -2.74623350179570024920]],
|
|
130
|
+
[[-68.24753735887460948106, -2.74623350179570024920], [-68.37258141465594007968, -2.83253376987636329432]],
|
|
131
|
+
[[-68.37258141465594007968, -2.83253376987636329432], [-68.40089829889257089235, -2.98180502037078554167]],
|
|
132
|
+
[[-68.40089829889257089235, -2.98180502037078554167], [-68.31614651314507113966, -3.10790373951434872879]],
|
|
133
|
+
[[-54.61235529924312714911, -11.79066769321313756791], [-49.58572929483430868913, -14.97552686612213790340]]
|
|
134
|
+
])
|
|
135
|
+
// geom2.toOutlines(c)
|
|
136
|
+
// geom2.toOutlines(d)
|
|
137
|
+
|
|
138
|
+
const obs = union(c, d)
|
|
139
|
+
// const outlines = geom2.toOutlines(obs)
|
|
140
|
+
const pts = geom2.toPoints(obs)
|
|
141
|
+
const exp = [
|
|
142
|
+
[-49.10585516965137, -15.276000175919414],
|
|
143
|
+
[-49.0573272145917, -15.486679335654257],
|
|
144
|
+
[-49.307011370463215, -15.815286644243773],
|
|
145
|
+
[-46.00502320253235, -17.211117609669667],
|
|
146
|
+
[-45.85943933735334, -17.215031154432545],
|
|
147
|
+
[-45.74972963250071, -17.119149307742074],
|
|
148
|
+
[-45.734205904941305, -16.974217700023555],
|
|
149
|
+
[-48.166473975068946, -15.86316234184296],
|
|
150
|
+
[-49.318621553259746, -15.801589237573706],
|
|
151
|
+
[-49.585786209072104, -14.975570389622606],
|
|
152
|
+
[-68.31614189569036, -3.1078763476921982],
|
|
153
|
+
[-49.53751915699663, -15.184292776976012],
|
|
154
|
+
[-68.09789654941396, -2.7727464644978874],
|
|
155
|
+
[-68.24752441084793, -2.7462648116024244],
|
|
156
|
+
[-68.37262739176788, -2.8324932478777995],
|
|
157
|
+
[-68.40093536555268, -2.98186020632758],
|
|
158
|
+
[-54.61234310251047, -11.79072766159384],
|
|
159
|
+
[-49.30335872868453, -14.680880468978017],
|
|
160
|
+
[-49.34040695243976, -15.797284338334542],
|
|
161
|
+
[-45.82121705016925, -16.857333163105647]
|
|
162
|
+
]
|
|
163
|
+
t.notThrows(() => geom2.validate(obs))
|
|
164
|
+
t.is(pts.length, 20) // number of sides in union
|
|
165
|
+
t.true(comparePoints(pts, exp))
|
|
166
|
+
})
|