@jscad/modeling 3.0.0-alpha.0 → 3.0.2-alpha.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 +49 -0
- package/LICENSE +1 -1
- package/dist/jscad-modeling.es.js +2 -2
- package/dist/jscad-modeling.min.js +2 -2
- package/package.json +2 -2
- package/rollup.config.js +1 -1
- package/src/colors/colorize.js +1 -5
- package/src/colors/colorize.test.js +8 -8
- package/src/geometries/geom2/transform.js +9 -1
- package/src/geometries/geom2/transform.test.js +57 -0
- package/src/geometries/geom3/fromPointsConvex.d.ts +4 -0
- package/src/geometries/geom3/fromPointsConvex.js +25 -0
- package/src/geometries/geom3/fromPointsConvex.test.js +32 -0
- package/src/geometries/geom3/index.d.ts +1 -0
- package/src/geometries/geom3/index.js +1 -0
- package/src/geometries/index.js +3 -4
- package/src/geometries/path2/appendBezier.js +1 -1
- package/src/geometries/poly3/index.js +1 -1
- package/src/geometries/poly3/measureBoundingBox.js +2 -0
- package/src/geometries/poly3/measureBoundingSphere.d.ts +2 -1
- package/src/geometries/poly3/measureBoundingSphere.js +25 -8
- package/src/geometries/poly3/measureBoundingSphere.test.js +12 -8
- package/src/geometries/poly3/type.d.ts +1 -1
- package/src/geometries/slice/validate.js +1 -2
- package/src/index.js +41 -0
- package/src/maths/index.js +1 -0
- package/src/maths/mat4/isOnlyTransformScale.js +1 -1
- package/src/measurements/measureAggregateArea.js +0 -1
- package/src/measurements/measureAggregateBoundingBox.js +0 -1
- package/src/measurements/measureAggregateEpsilon.js +0 -1
- package/src/measurements/measureAggregateVolume.js +0 -1
- package/src/measurements/measureArea.js +0 -1
- package/src/measurements/measureBoundingBox.js +0 -1
- package/src/measurements/measureBoundingSphere.js +2 -6
- package/src/measurements/measureEpsilon.js +0 -1
- package/src/measurements/measureVolume.js +0 -1
- package/src/operations/booleans/index.d.ts +1 -0
- package/src/operations/booleans/intersect.js +5 -5
- package/src/operations/booleans/intersect.test.js +6 -7
- package/src/operations/booleans/intersectGeom2.js +2 -6
- package/src/operations/booleans/intersectGeom2.test.js +25 -1
- package/src/operations/booleans/intersectGeom3.js +2 -6
- package/src/operations/booleans/intersectGeom3.test.js +5 -1
- package/src/operations/booleans/martinez/compareEvents.js +2 -7
- package/src/operations/booleans/martinez/connectEdges.js +30 -41
- package/src/operations/booleans/martinez/contour.js +1 -1
- package/src/operations/booleans/martinez/divideSegment.js +12 -11
- package/src/operations/booleans/martinez/fillQueue.js +24 -28
- package/src/operations/booleans/martinez/index.js +2 -1
- package/src/operations/booleans/martinez/possibleIntersection.js +41 -30
- package/src/operations/booleans/martinez/segmentIntersection.js +7 -9
- package/src/operations/booleans/martinez/splaytree.js +59 -457
- package/src/operations/booleans/martinez/subdivideSegments.js +4 -4
- package/src/operations/booleans/martinez/sweepEvent.js +3 -17
- package/src/operations/booleans/mayOverlap.js +0 -1
- package/src/operations/booleans/scission.d.ts +5 -0
- package/src/operations/booleans/scission.js +3 -5
- package/src/operations/booleans/scission.test.js +6 -0
- package/src/operations/booleans/subtract.js +5 -5
- package/src/operations/booleans/subtract.test.js +6 -7
- package/src/operations/booleans/subtractGeom2.js +2 -6
- package/src/operations/booleans/subtractGeom2.test.js +25 -1
- package/src/operations/booleans/subtractGeom3.js +2 -6
- package/src/operations/booleans/subtractGeom3.test.js +5 -1
- package/src/operations/booleans/trees/Node.js +25 -27
- package/src/operations/booleans/trees/PolygonTreeNode.js +153 -106
- package/src/operations/booleans/trees/Tree.js +9 -4
- package/src/operations/booleans/trees/splitLineSegmentByPlane.js +5 -3
- package/src/operations/booleans/trees/splitPolygonByPlane.d.ts +33 -0
- package/src/operations/booleans/trees/splitPolygonByPlane.js +39 -34
- package/src/operations/booleans/union.js +5 -5
- package/src/operations/booleans/union.test.js +6 -7
- package/src/operations/booleans/unionGeom2.js +2 -6
- package/src/operations/booleans/unionGeom2.test.js +25 -1
- package/src/operations/booleans/unionGeom3.js +2 -6
- package/src/operations/booleans/unionGeom3.test.js +6 -1
- package/src/operations/extrusions/extrudeFromSlices.test.js +8 -1
- package/src/operations/extrusions/extrudeHelical.js +2 -8
- package/src/operations/extrusions/extrudeLinear.js +1 -5
- package/src/operations/extrusions/extrudeLinear.test.js +7 -1
- package/src/operations/extrusions/extrudeRotate.js +3 -2
- package/src/operations/extrusions/extrudeRotate.test.js +13 -1
- package/src/operations/extrusions/extrudeWalls.js +3 -1
- package/src/operations/extrusions/project.js +1 -5
- package/src/operations/hulls/hull.js +6 -5
- package/src/operations/hulls/hull.test.js +56 -3
- package/src/operations/hulls/hullChain.js +11 -6
- package/src/operations/hulls/hullChain.test.js +12 -2
- package/src/operations/hulls/hullGeom2.js +5 -6
- package/src/operations/hulls/hullGeom3.js +9 -18
- package/src/operations/hulls/hullPath2.js +6 -7
- package/src/operations/hulls/hullPath2.test.js +1 -1
- package/src/operations/hulls/hullPoints2.d.ts +3 -0
- package/src/operations/hulls/hullPoints2.js +24 -30
- package/src/operations/hulls/hullPoints3.d.ts +4 -0
- package/src/operations/hulls/hullPoints3.js +21 -0
- package/src/operations/hulls/index.d.ts +2 -0
- package/src/operations/hulls/index.js +3 -1
- package/src/operations/modifiers/generalize.js +2 -6
- package/src/operations/modifiers/index.js +1 -1
- package/src/operations/modifiers/mergePolygons.js +2 -3
- package/src/operations/modifiers/reTesselateCoplanarPolygons.js +7 -7
- package/src/operations/modifiers/snap.js +2 -6
- package/src/operations/offsets/offset.js +1 -5
- package/src/operations/offsets/offsetFromPoints.test.js +0 -1
- package/src/operations/offsets/offsetGeom2.test.js +1 -0
- package/src/operations/offsets/offsetGeom3.js +0 -2
- package/src/operations/offsets/offsetGeom3.test.js +9 -1
- package/src/operations/offsets/offsetPath2.js +3 -3
- package/src/operations/transforms/align.js +8 -7
- package/src/operations/transforms/align.test.js +2 -2
- package/src/operations/transforms/center.js +6 -9
- package/src/operations/transforms/center.test.js +19 -1
- package/src/operations/transforms/mirror.js +5 -8
- package/src/operations/transforms/mirror.test.js +7 -7
- package/src/operations/transforms/rotate.js +5 -8
- package/src/operations/transforms/scale.js +5 -8
- package/src/operations/transforms/transform.js +2 -5
- package/src/operations/transforms/translate.js +5 -8
- package/src/primitives/arc.js +2 -0
- package/src/primitives/arc.test.js +11 -11
- package/src/primitives/circle.test.js +18 -8
- package/src/primitives/cube.test.js +10 -0
- package/src/primitives/cuboid.test.js +10 -0
- package/src/primitives/cylinder.test.js +12 -0
- package/src/primitives/cylinderElliptic.test.js +21 -1
- package/src/primitives/ellipse.test.js +18 -8
- package/src/primitives/ellipsoid.test.js +12 -0
- package/src/primitives/geodesicSphere.test.js +8 -0
- package/src/primitives/line.test.js +1 -1
- package/src/primitives/polygon.d.ts +1 -0
- package/src/primitives/polygon.js +13 -4
- package/src/primitives/polygon.test.js +15 -0
- package/src/primitives/polyhedron.js +1 -0
- package/src/primitives/polyhedron.test.js +8 -2
- package/src/primitives/rectangle.test.js +9 -3
- package/src/primitives/roundedCuboid.js +1 -1
- package/src/primitives/roundedCuboid.test.js +20 -4
- package/src/primitives/roundedCylinder.js +1 -1
- package/src/primitives/roundedCylinder.test.js +20 -0
- package/src/primitives/roundedRectangle.js +1 -1
- package/src/primitives/roundedRectangle.test.js +15 -6
- package/src/primitives/sphere.test.js +12 -0
- package/src/primitives/square.test.js +10 -4
- package/src/primitives/star.test.js +14 -6
- package/src/primitives/torus.js +1 -1
- package/src/primitives/torus.test.js +11 -1
- package/src/primitives/triangle.test.js +17 -9
- package/src/utils/coalesce.d.ts +3 -0
- package/src/utils/coalesce.js +20 -0
- package/src/utils/index.js +2 -2
- package/src/maths/mat4/leftMultiplyVec2.d.ts +0 -4
- package/src/maths/mat4/leftMultiplyVec2.js +0 -26
- package/src/maths/mat4/leftMultiplyVec3.d.ts +0 -4
- package/src/maths/mat4/leftMultiplyVec3.js +0 -27
- package/src/maths/mat4/mirror.d.ts +0 -4
- package/src/maths/mat4/mirror.js +0 -32
- package/src/maths/mat4/rightMultiplyVec2.d.ts +0 -4
- package/src/maths/mat4/rightMultiplyVec2.js +0 -27
- package/src/maths/mat4/rightMultiplyVec3.d.ts +0 -4
- package/src/maths/mat4/rightMultiplyVec3.js +0 -28
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom3 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea, measureVolume } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { cylinder } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePolygonsAsPoints } from '../../test/helpers/index.js'
|
|
@@ -11,6 +13,8 @@ test('cylinder (defaults)', (t) => {
|
|
|
11
13
|
const pts = geom3.toPoints(obs)
|
|
12
14
|
|
|
13
15
|
t.notThrows(() => geom3.validate(obs))
|
|
16
|
+
t.is(measureArea(obs), 18.789084266699856)
|
|
17
|
+
t.is(measureVolume(obs), 6.2428903045161)
|
|
14
18
|
t.is(pts.length, 96)
|
|
15
19
|
})
|
|
16
20
|
|
|
@@ -18,6 +22,8 @@ test('cylinder (zero height)', (t) => {
|
|
|
18
22
|
const obs = cylinder({ height: 0 })
|
|
19
23
|
const pts = geom3.toPoints(obs)
|
|
20
24
|
t.notThrows(() => geom3.validate(obs))
|
|
25
|
+
t.is(measureArea(obs), 0)
|
|
26
|
+
t.is(measureVolume(obs), 0)
|
|
21
27
|
t.is(pts.length, 0)
|
|
22
28
|
})
|
|
23
29
|
|
|
@@ -25,6 +31,8 @@ test('cylinder (zero radius)', (t) => {
|
|
|
25
31
|
const obs = cylinder({ radius: 0 })
|
|
26
32
|
const pts = geom3.toPoints(obs)
|
|
27
33
|
t.notThrows(() => geom3.validate(obs))
|
|
34
|
+
t.is(measureArea(obs), 0)
|
|
35
|
+
t.is(measureVolume(obs), 0)
|
|
28
36
|
t.is(pts.length, 0)
|
|
29
37
|
})
|
|
30
38
|
|
|
@@ -55,6 +63,8 @@ test('cylinder (options)', (t) => {
|
|
|
55
63
|
]
|
|
56
64
|
|
|
57
65
|
t.notThrows(() => geom3.validate(obs))
|
|
66
|
+
t.is(measureArea(obs), 311.1986222206015)
|
|
67
|
+
t.is(measureVolume(obs), 380.4226065180614)
|
|
58
68
|
t.is(pts.length, 15)
|
|
59
69
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
60
70
|
|
|
@@ -85,6 +95,8 @@ test('cylinder (options)', (t) => {
|
|
|
85
95
|
]
|
|
86
96
|
|
|
87
97
|
t.notThrows(() => geom3.validate(obs))
|
|
98
|
+
t.is(measureArea(obs), 16.51098762732523)
|
|
99
|
+
t.is(measureVolume(obs), 4.755282581475773)
|
|
88
100
|
t.is(pts.length, 15)
|
|
89
101
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
90
102
|
})
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
+
import { geom3 } from '../geometries/index.js'
|
|
4
|
+
|
|
3
5
|
import { TAU } from '../maths/constants.js'
|
|
4
6
|
|
|
5
|
-
import {
|
|
7
|
+
import { measureArea, measureVolume } from '../measurements/index.js'
|
|
6
8
|
|
|
7
9
|
import { cylinderElliptic } from './index.js'
|
|
8
10
|
|
|
@@ -13,6 +15,8 @@ test('cylinderElliptic (defaults)', (t) => {
|
|
|
13
15
|
const pts = geom3.toPoints(obs)
|
|
14
16
|
|
|
15
17
|
t.notThrows(() => geom3.validate(obs))
|
|
18
|
+
t.is(measureArea(obs), 18.789084266699856)
|
|
19
|
+
t.is(measureVolume(obs), 6.2428903045161)
|
|
16
20
|
t.is(pts.length, 96)
|
|
17
21
|
})
|
|
18
22
|
|
|
@@ -72,6 +76,8 @@ test('cylinderElliptic (options)', (t) => {
|
|
|
72
76
|
]
|
|
73
77
|
|
|
74
78
|
t.notThrows(() => geom3.validate(obs))
|
|
79
|
+
t.is(measureArea(obs), 68.11657082460499)
|
|
80
|
+
t.is(measureVolume(obs), 30.00000000000001)
|
|
75
81
|
t.is(pts.length, 36)
|
|
76
82
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
77
83
|
|
|
@@ -130,6 +136,8 @@ test('cylinderElliptic (options)', (t) => {
|
|
|
130
136
|
]
|
|
131
137
|
|
|
132
138
|
t.notThrows(() => geom3.validate(obs))
|
|
139
|
+
t.is(measureArea(obs), 32.34210030145122)
|
|
140
|
+
t.is(measureVolume(obs), 12.999999999999991)
|
|
133
141
|
t.is(pts.length, 48)
|
|
134
142
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
135
143
|
|
|
@@ -138,6 +146,8 @@ test('cylinderElliptic (options)', (t) => {
|
|
|
138
146
|
pts = geom3.toPoints(obs)
|
|
139
147
|
|
|
140
148
|
t.notThrows(() => geom3.validate(obs))
|
|
149
|
+
t.is(measureArea(obs), 22.17105015072561)
|
|
150
|
+
t.is(measureVolume(obs), 6.5)
|
|
141
151
|
t.is(pts.length, 28)
|
|
142
152
|
|
|
143
153
|
// test startAngle and endAngle
|
|
@@ -145,6 +155,8 @@ test('cylinderElliptic (options)', (t) => {
|
|
|
145
155
|
pts = geom3.toPoints(obs)
|
|
146
156
|
|
|
147
157
|
t.notThrows(() => geom3.validate(obs))
|
|
158
|
+
t.is(measureArea(obs), 18.78908426669986)
|
|
159
|
+
t.is(measureVolume(obs), 6.2428903045160995)
|
|
148
160
|
t.is(pts.length, 96)
|
|
149
161
|
|
|
150
162
|
// test segments
|
|
@@ -152,6 +164,8 @@ test('cylinderElliptic (options)', (t) => {
|
|
|
152
164
|
pts = geom3.toPoints(obs)
|
|
153
165
|
|
|
154
166
|
t.notThrows(() => geom3.validate(obs))
|
|
167
|
+
t.is(measureArea(obs), 17.902724085175244)
|
|
168
|
+
t.is(measureVolume(obs), 5.6568542494923815)
|
|
155
169
|
t.is(pts.length, 24)
|
|
156
170
|
|
|
157
171
|
// test center
|
|
@@ -193,6 +207,8 @@ test('cylinderElliptic (options)', (t) => {
|
|
|
193
207
|
]
|
|
194
208
|
|
|
195
209
|
t.notThrows(() => geom3.validate(obs))
|
|
210
|
+
t.is(measureArea(obs), 24.025659003016692)
|
|
211
|
+
t.is(measureVolume(obs), 8.485281374238578)
|
|
196
212
|
t.is(pts.length, 24)
|
|
197
213
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
198
214
|
})
|
|
@@ -202,6 +218,8 @@ test('cylinderElliptic (cone)', (t) => {
|
|
|
202
218
|
const pts = geom3.toPoints(obs)
|
|
203
219
|
|
|
204
220
|
t.notThrows(() => geom3.validate(obs))
|
|
221
|
+
t.is(measureArea(obs), 10.128239395900382)
|
|
222
|
+
t.is(measureVolume(obs), 2.080963434838702)
|
|
205
223
|
t.is(pts.length, 64)
|
|
206
224
|
})
|
|
207
225
|
|
|
@@ -210,5 +228,7 @@ test('cylinderElliptic (squished)', (t) => {
|
|
|
210
228
|
const pts = geom3.toPoints(obs)
|
|
211
229
|
|
|
212
230
|
t.notThrows(() => geom3.validate(obs))
|
|
231
|
+
t.is(measureArea(obs), 8.47213595499958)
|
|
232
|
+
t.is(measureVolume(obs), 0.6666666666666666)
|
|
213
233
|
t.is(pts.length, 8)
|
|
214
234
|
})
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import test from 'ava'
|
|
2
2
|
|
|
3
|
+
import { geom2 } from '../geometries/index.js'
|
|
4
|
+
|
|
3
5
|
import { TAU } from '../maths/constants.js'
|
|
4
6
|
|
|
5
|
-
import {
|
|
7
|
+
import { measureArea } from '../measurements/index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePoints } from '../../test/helpers/index.js'
|
|
8
10
|
|
|
@@ -13,7 +15,8 @@ test('ellipse (defaults)', (t) => {
|
|
|
13
15
|
const obs = geom2.toPoints(geometry)
|
|
14
16
|
|
|
15
17
|
t.notThrows(() => geom2.validate(geometry))
|
|
16
|
-
t.
|
|
18
|
+
t.is(measureArea(geometry), 3.1214451522580537)
|
|
19
|
+
t.is(obs.length, 32)
|
|
17
20
|
})
|
|
18
21
|
|
|
19
22
|
test('ellipse (options)', (t) => {
|
|
@@ -56,7 +59,8 @@ test('ellipse (options)', (t) => {
|
|
|
56
59
|
]
|
|
57
60
|
|
|
58
61
|
t.notThrows(() => geom2.validate(geometry))
|
|
59
|
-
t.
|
|
62
|
+
t.is(measureArea(geometry), 3.121445152258051)
|
|
63
|
+
t.is(obs.length, 32)
|
|
60
64
|
t.true(comparePoints(obs, exp))
|
|
61
65
|
|
|
62
66
|
// test radius
|
|
@@ -82,7 +86,8 @@ test('ellipse (options)', (t) => {
|
|
|
82
86
|
]
|
|
83
87
|
|
|
84
88
|
t.notThrows(() => geom2.validate(geometry))
|
|
85
|
-
t.
|
|
89
|
+
t.is(measureArea(geometry), 45.92201188381077)
|
|
90
|
+
t.is(obs.length, 16)
|
|
86
91
|
t.true(comparePoints(obs, exp))
|
|
87
92
|
|
|
88
93
|
// test startAngle
|
|
@@ -106,7 +111,8 @@ test('ellipse (options)', (t) => {
|
|
|
106
111
|
]
|
|
107
112
|
|
|
108
113
|
t.notThrows(() => geom2.validate(geometry))
|
|
109
|
-
t.
|
|
114
|
+
t.is(measureArea(geometry), 34.44150891285808)
|
|
115
|
+
t.is(obs.length, 14)
|
|
110
116
|
t.true(comparePoints(obs, exp))
|
|
111
117
|
|
|
112
118
|
// test endAngle
|
|
@@ -122,7 +128,8 @@ test('ellipse (options)', (t) => {
|
|
|
122
128
|
]
|
|
123
129
|
|
|
124
130
|
t.notThrows(() => geom2.validate(geometry))
|
|
125
|
-
t.
|
|
131
|
+
t.is(measureArea(geometry), 11.480502970952696)
|
|
132
|
+
t.is(obs.length, 6)
|
|
126
133
|
t.true(comparePoints(obs, exp))
|
|
127
134
|
|
|
128
135
|
// test full rotation with non-zero startAngle
|
|
@@ -130,18 +137,21 @@ test('ellipse (options)', (t) => {
|
|
|
130
137
|
obs = geom2.toPoints(geometry)
|
|
131
138
|
|
|
132
139
|
t.notThrows(() => geom2.validate(geometry))
|
|
133
|
-
t.
|
|
140
|
+
t.is(measureArea(geometry), 3.1214451522580537)
|
|
141
|
+
t.is(obs.length, 32)
|
|
134
142
|
|
|
135
143
|
// test segments
|
|
136
144
|
geometry = ellipse({ segments: 72 })
|
|
137
145
|
obs = geom2.toPoints(geometry)
|
|
138
146
|
t.notThrows(() => geom2.validate(geometry))
|
|
139
|
-
t.
|
|
147
|
+
t.is(measureArea(geometry), 3.1376067389156956)
|
|
148
|
+
t.is(obs.length, 72)
|
|
140
149
|
})
|
|
141
150
|
|
|
142
151
|
test('ellipse (zero radius)', (t) => {
|
|
143
152
|
const geometry = ellipse({ radius: [1, 0] })
|
|
144
153
|
const obs = geom2.toPoints(geometry)
|
|
145
154
|
t.notThrows(() => geom2.validate(geometry))
|
|
155
|
+
t.is(measureArea(geometry), 0)
|
|
146
156
|
t.is(obs.length, 0)
|
|
147
157
|
})
|
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom3 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea, measureVolume } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { ellipsoid } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePolygonsAsPoints } from '../../test/helpers/index.js'
|
|
@@ -11,6 +13,8 @@ test('ellipsoid (defaults)', (t) => {
|
|
|
11
13
|
const pts = geom3.toPoints(obs)
|
|
12
14
|
|
|
13
15
|
t.notThrows(() => geom3.validate(obs))
|
|
16
|
+
t.is(measureArea(obs), 12.465694088650583)
|
|
17
|
+
t.is(measureVolume(obs), 4.121941740785839)
|
|
14
18
|
t.is(pts.length, 512)
|
|
15
19
|
})
|
|
16
20
|
|
|
@@ -141,6 +145,8 @@ test('ellipsoid (options)', (t) => {
|
|
|
141
145
|
[[0, 0, 7], [1.5000000000000004, 0, 6.06217782649107], [1.2990381056766578, 1.2500000000000013, 6.06217782649107]]
|
|
142
146
|
]
|
|
143
147
|
t.notThrows(() => geom3.validate(obs))
|
|
148
|
+
t.is(measureArea(obs), 291.2703265603712)
|
|
149
|
+
t.is(measureVolume(obs), 391.86533479473223)
|
|
144
150
|
t.is(pts.length, 72)
|
|
145
151
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
146
152
|
|
|
@@ -148,6 +154,8 @@ test('ellipsoid (options)', (t) => {
|
|
|
148
154
|
obs = ellipsoid({ segments: 8 })
|
|
149
155
|
pts = geom3.toPoints(obs)
|
|
150
156
|
t.notThrows(() => geom3.validate(obs))
|
|
157
|
+
t.is(measureArea(obs), 11.013439076647456)
|
|
158
|
+
t.is(measureVolume(obs), 3.2189514164974597)
|
|
151
159
|
t.is(pts.length, 32)
|
|
152
160
|
|
|
153
161
|
obs = ellipsoid({ center: [-3, 5, 7], segments: 8 })
|
|
@@ -204,6 +212,8 @@ test('ellipsoid (options)', (t) => {
|
|
|
204
212
|
]
|
|
205
213
|
|
|
206
214
|
t.notThrows(() => geom3.validate(obs))
|
|
215
|
+
t.is(measureArea(obs), 11.013439076647467)
|
|
216
|
+
t.is(measureVolume(obs), 3.218951416497485)
|
|
207
217
|
t.is(pts.length, 32)
|
|
208
218
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
209
219
|
})
|
|
@@ -212,5 +222,7 @@ test('ellipsoid (zero radius)', (t) => {
|
|
|
212
222
|
const obs = ellipsoid({ radius: [1, 1, 0] })
|
|
213
223
|
const pts = geom3.toPoints(obs)
|
|
214
224
|
t.notThrows(() => geom3.validate(obs))
|
|
225
|
+
t.is(measureArea(obs), 0)
|
|
226
|
+
t.is(measureVolume(obs), 0)
|
|
215
227
|
t.is(pts.length, 0)
|
|
216
228
|
})
|
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom3 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea, measureVolume } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { geodesicSphere } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePolygonsAsPoints } from '../../test/helpers/index.js'
|
|
@@ -41,6 +43,8 @@ test('geodesicSphere (options)', (t) => {
|
|
|
41
43
|
]
|
|
42
44
|
|
|
43
45
|
t.notThrows(() => geom3.validate(obs))
|
|
46
|
+
t.is(measureArea(obs), 239.3635345818432)
|
|
47
|
+
t.is(measureVolume(obs), 317.0188387650327)
|
|
44
48
|
t.is(pts.length, 20)
|
|
45
49
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
46
50
|
|
|
@@ -49,6 +53,8 @@ test('geodesicSphere (options)', (t) => {
|
|
|
49
53
|
pts = geom3.toPoints(obs)
|
|
50
54
|
|
|
51
55
|
t.notThrows.skip(() => geom3.validate(obs))
|
|
56
|
+
t.is(measureArea(obs), 303.76605423529395)
|
|
57
|
+
t.is(measureVolume(obs), 492.6739732379337)
|
|
52
58
|
t.is(pts.length, 180)
|
|
53
59
|
})
|
|
54
60
|
|
|
@@ -56,5 +62,7 @@ test('geodesicSphere (zero radius)', (t) => {
|
|
|
56
62
|
const obs = geodesicSphere({ radius: 0 })
|
|
57
63
|
const pts = geom3.toPoints(obs)
|
|
58
64
|
t.notThrows(() => geom3.validate(obs))
|
|
65
|
+
t.is(measureArea(obs), 0)
|
|
66
|
+
t.is(measureVolume(obs), 0)
|
|
59
67
|
t.is(pts.length, 0)
|
|
60
68
|
})
|
|
@@ -4,6 +4,7 @@ import type { Geom2 } from '../geometries/geom2/type.d.ts'
|
|
|
4
4
|
export interface PolygonOptions {
|
|
5
5
|
points: Array<Vec2> | Array<Array<Vec2>>
|
|
6
6
|
paths?: Array<number> | Array<Array<number>>
|
|
7
|
+
orientation?: 'counterclockwise' | 'clockwise'
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export function polygon(options: PolygonOptions): Geom2
|
|
@@ -2,10 +2,13 @@ import * as geom2 from '../geometries/geom2/index.js'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Construct a polygon in two dimensional space from a list of points, or a list of points and paths.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* NOTE: The ordering of points is important, and must define a counter clockwise rotation of points.
|
|
7
|
+
*
|
|
6
8
|
* @param {object} options - options for construction
|
|
7
9
|
* @param {Array} options.points - points of the polygon : either flat or nested array of 2D points
|
|
8
10
|
* @param {Array} [options.paths] - paths of the polygon : either flat or nested array of point indexes
|
|
11
|
+
* @param {String} [options.orientation='counterclockwise'] - orientation of points
|
|
9
12
|
* @returns {Geom2} new 2D geometry
|
|
10
13
|
* @alias module:modeling/primitives.polygon
|
|
11
14
|
*
|
|
@@ -24,9 +27,10 @@ import * as geom2 from '../geometries/geom2/index.js'
|
|
|
24
27
|
export const polygon = (options) => {
|
|
25
28
|
const defaults = {
|
|
26
29
|
points: [],
|
|
27
|
-
paths: []
|
|
30
|
+
paths: [],
|
|
31
|
+
orientation: 'counterclockwise'
|
|
28
32
|
}
|
|
29
|
-
const { points, paths } = Object.assign({}, defaults, options)
|
|
33
|
+
const { points, paths, orientation } = Object.assign({}, defaults, options)
|
|
30
34
|
|
|
31
35
|
if (!(Array.isArray(points) && Array.isArray(paths))) throw new Error('points and paths must be arrays')
|
|
32
36
|
|
|
@@ -63,5 +67,10 @@ export const polygon = (options) => {
|
|
|
63
67
|
const setOfPoints = path.map((index) => allPoints[index])
|
|
64
68
|
outlines.push(setOfPoints)
|
|
65
69
|
})
|
|
66
|
-
|
|
70
|
+
|
|
71
|
+
let geometry = geom2.create(outlines)
|
|
72
|
+
if (orientation === 'clockwise') {
|
|
73
|
+
geometry = geom2.reverse(geometry)
|
|
74
|
+
}
|
|
75
|
+
return geometry
|
|
67
76
|
}
|
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom2 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { polygon } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePoints } from '../../test/helpers/index.js'
|
|
@@ -13,6 +15,7 @@ test('polygon: providing only object.points creates expected geometry', (t) => {
|
|
|
13
15
|
let exp = [[0, 0], [100, 0], [130, 50], [30, 50]]
|
|
14
16
|
|
|
15
17
|
t.notThrows(() => geom2.validate(geometry))
|
|
18
|
+
t.is(measureArea(geometry), 5000)
|
|
16
19
|
t.true(comparePoints(obs, exp))
|
|
17
20
|
|
|
18
21
|
geometry = polygon({ points: [[[0, 0], [100, 0], [0, 100]], [[10, 10], [80, 10], [10, 80]]] })
|
|
@@ -21,6 +24,7 @@ test('polygon: providing only object.points creates expected geometry', (t) => {
|
|
|
21
24
|
exp = [[0, 0], [100, 0], [0, 100], [10, 10], [80, 10], [10, 80]]
|
|
22
25
|
|
|
23
26
|
t.notThrows(() => geom2.validate(geometry))
|
|
27
|
+
t.is(measureArea(geometry), 7450)
|
|
24
28
|
t.true(comparePoints(obs, exp))
|
|
25
29
|
})
|
|
26
30
|
|
|
@@ -31,6 +35,7 @@ test('polygon: providing object.points (array) and object.path (array) creates e
|
|
|
31
35
|
let exp = [[30, 50], [130, 50], [100, 0], [0, 0]]
|
|
32
36
|
|
|
33
37
|
t.notThrows(() => geom2.validate(geometry))
|
|
38
|
+
t.is(measureArea(geometry), -5000)
|
|
34
39
|
t.true(comparePoints(obs, exp))
|
|
35
40
|
|
|
36
41
|
// multiple paths
|
|
@@ -40,6 +45,7 @@ test('polygon: providing object.points (array) and object.path (array) creates e
|
|
|
40
45
|
exp = [[0, 0], [100, 0], [0, 100], [10, 10], [80, 10], [10, 80]]
|
|
41
46
|
|
|
42
47
|
t.notThrows(() => geom2.validate(geometry))
|
|
48
|
+
t.is(measureArea(geometry), 7450)
|
|
43
49
|
t.true(comparePoints(obs, exp))
|
|
44
50
|
|
|
45
51
|
// multiple points and paths
|
|
@@ -49,5 +55,14 @@ test('polygon: providing object.points (array) and object.path (array) creates e
|
|
|
49
55
|
exp = [[0, 0], [100, 0], [0, 100], [10, 10], [80, 10], [10, 80]]
|
|
50
56
|
|
|
51
57
|
t.notThrows(() => geom2.validate(geometry))
|
|
58
|
+
t.is(measureArea(geometry), 7450)
|
|
52
59
|
t.true(comparePoints(obs, exp))
|
|
53
60
|
})
|
|
61
|
+
|
|
62
|
+
test('polygon: clockwise points', (t) => {
|
|
63
|
+
const poly = polygon({
|
|
64
|
+
points: [[-10, -0], [-10, -10], [-15, -5]],
|
|
65
|
+
orientation: 'clockwise'
|
|
66
|
+
})
|
|
67
|
+
t.is(measureArea(poly), 25)
|
|
68
|
+
})
|
|
@@ -5,6 +5,7 @@ import { isNumberArray } from './commonChecks.js'
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Construct a polyhedron in three dimensional space from the given set of 3D vertices and faces.
|
|
8
|
+
*
|
|
8
9
|
* The faces can define outward or inward facing polygons (orientation).
|
|
9
10
|
* However, each face must define a counterclockwise rotation of vertices which follows the right hand rule.
|
|
10
11
|
* @param {object} options - options for construction
|
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom3 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea, measureVolume } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { polyhedron } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePolygonsAsPoints } from '../../test/helpers/index.js'
|
|
@@ -22,7 +24,9 @@ test('polyhedron (points and faces)', (t) => {
|
|
|
22
24
|
[[-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]]
|
|
23
25
|
]
|
|
24
26
|
t.notThrows(() => geom3.validate(obs))
|
|
25
|
-
t.
|
|
27
|
+
t.is(measureArea(obs), 24)
|
|
28
|
+
t.is(measureVolume(obs), 7.999999999999999)
|
|
29
|
+
t.is(pts.length, 6)
|
|
26
30
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
27
31
|
|
|
28
32
|
// test orientation
|
|
@@ -39,6 +43,8 @@ test('polyhedron (points and faces)', (t) => {
|
|
|
39
43
|
[[-10, 10, 0], [10, -10, 0], [-10, -10, 0]]
|
|
40
44
|
]
|
|
41
45
|
t.notThrows(() => geom3.validate(obs))
|
|
42
|
-
t.
|
|
46
|
+
t.is(measureArea(obs), 965.6854249492379)
|
|
47
|
+
t.is(measureVolume(obs), 1333.3333333333333)
|
|
48
|
+
t.is(pts.length, 6)
|
|
43
49
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
44
50
|
})
|
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom2 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { rectangle } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePoints } from '../../test/helpers/index.js'
|
|
@@ -17,7 +19,8 @@ test('rectangle (defaults)', (t) => {
|
|
|
17
19
|
]
|
|
18
20
|
|
|
19
21
|
t.notThrows(() => geom2.validate(geometry))
|
|
20
|
-
t.
|
|
22
|
+
t.is(measureArea(geometry), 4)
|
|
23
|
+
t.is(obs.length, 4)
|
|
21
24
|
t.true(comparePoints(obs, exp))
|
|
22
25
|
})
|
|
23
26
|
|
|
@@ -33,7 +36,8 @@ test('rectangle (options)', (t) => {
|
|
|
33
36
|
]
|
|
34
37
|
|
|
35
38
|
t.notThrows(() => geom2.validate(geometry))
|
|
36
|
-
t.
|
|
39
|
+
t.is(measureArea(geometry), 4)
|
|
40
|
+
t.is(obs.length, 4)
|
|
37
41
|
t.true(comparePoints(obs, exp))
|
|
38
42
|
|
|
39
43
|
// test size
|
|
@@ -47,7 +51,8 @@ test('rectangle (options)', (t) => {
|
|
|
47
51
|
]
|
|
48
52
|
|
|
49
53
|
t.notThrows(() => geom2.validate(geometry))
|
|
50
|
-
t.
|
|
54
|
+
t.is(measureArea(geometry), 60)
|
|
55
|
+
t.is(obs.length, 4)
|
|
51
56
|
t.true(comparePoints(obs, exp))
|
|
52
57
|
})
|
|
53
58
|
|
|
@@ -55,5 +60,6 @@ test('rectangle (zero size)', (t) => {
|
|
|
55
60
|
const geometry = rectangle({ size: [1, 0] })
|
|
56
61
|
const obs = geom2.toPoints(geometry)
|
|
57
62
|
t.notThrows(() => geom2.validate(geometry))
|
|
63
|
+
t.is(measureArea(geometry), 0)
|
|
58
64
|
t.is(obs.length, 0)
|
|
59
65
|
})
|
|
@@ -151,7 +151,7 @@ export const roundedCuboid = (options) => {
|
|
|
151
151
|
|
|
152
152
|
if (roundRadius > (size[0] - EPS) ||
|
|
153
153
|
roundRadius > (size[1] - EPS) ||
|
|
154
|
-
roundRadius > (size[2] - EPS)) throw new Error('roundRadius must be smaller
|
|
154
|
+
roundRadius > (size[2] - EPS)) throw new Error('roundRadius must be smaller than the radius of all dimensions')
|
|
155
155
|
|
|
156
156
|
segments = Math.floor(segments / 4)
|
|
157
157
|
|
|
@@ -2,6 +2,8 @@ import test from 'ava'
|
|
|
2
2
|
|
|
3
3
|
import { geom3 } from '../geometries/index.js'
|
|
4
4
|
|
|
5
|
+
import { measureArea, measureVolume } from '../measurements/index.js'
|
|
6
|
+
|
|
5
7
|
import { roundedCuboid } from './index.js'
|
|
6
8
|
|
|
7
9
|
import { comparePolygonsAsPoints } from '../../test/helpers/index.js'
|
|
@@ -11,13 +13,17 @@ test('roundedCuboid (defaults)', (t) => {
|
|
|
11
13
|
const pts = geom3.toPoints(obs)
|
|
12
14
|
|
|
13
15
|
t.notThrows(() => geom3.validate(obs))
|
|
14
|
-
t.
|
|
16
|
+
t.is(measureArea(obs), 21.87859958298585)
|
|
17
|
+
t.is(measureVolume(obs), 7.800061070935406)
|
|
18
|
+
t.is(pts.length, 614)
|
|
15
19
|
})
|
|
16
20
|
|
|
17
21
|
test('roundedCuboid (zero size)', (t) => {
|
|
18
22
|
const obs = roundedCuboid({ size: [1, 1, 0] })
|
|
19
23
|
const pts = geom3.toPoints(obs)
|
|
20
24
|
t.notThrows(() => geom3.validate(obs))
|
|
25
|
+
t.is(measureArea(obs), 0)
|
|
26
|
+
t.is(measureVolume(obs), 0)
|
|
21
27
|
t.is(pts.length, 0)
|
|
22
28
|
})
|
|
23
29
|
|
|
@@ -25,7 +31,9 @@ test('roundedCuboid (zero radius)', (t) => {
|
|
|
25
31
|
const obs = roundedCuboid({ roundRadius: 0 })
|
|
26
32
|
const pts = geom3.toPoints(obs)
|
|
27
33
|
t.notThrows(() => geom3.validate(obs))
|
|
28
|
-
t.
|
|
34
|
+
t.is(measureArea(obs), 24)
|
|
35
|
+
t.is(measureVolume(obs), 7.999999999999999)
|
|
36
|
+
t.is(pts.length, 6)
|
|
29
37
|
})
|
|
30
38
|
|
|
31
39
|
test('roundedCuboid (options)', (t) => {
|
|
@@ -35,6 +43,8 @@ test('roundedCuboid (options)', (t) => {
|
|
|
35
43
|
let exp = []
|
|
36
44
|
|
|
37
45
|
t.notThrows(() => geom3.validate(obs))
|
|
46
|
+
t.is(measureArea(obs), 21.65472758198208)
|
|
47
|
+
t.is(measureVolume(obs), 7.734600480283937)
|
|
38
48
|
t.is(pts.length, 62)
|
|
39
49
|
|
|
40
50
|
// test center
|
|
@@ -44,6 +54,8 @@ test('roundedCuboid (options)', (t) => {
|
|
|
44
54
|
]
|
|
45
55
|
|
|
46
56
|
t.notThrows(() => geom3.validate(obs))
|
|
57
|
+
t.is(measureArea(obs), 21.65472758198207)
|
|
58
|
+
t.is(measureVolume(obs), 7.73460048028392)
|
|
47
59
|
t.is(pts.length, 62)
|
|
48
60
|
|
|
49
61
|
// test size
|
|
@@ -144,7 +156,9 @@ test('roundedCuboid (options)', (t) => {
|
|
|
144
156
|
[-3.8, 4.8, -6], [3.8, 4.8, -6]]
|
|
145
157
|
]
|
|
146
158
|
t.notThrows(() => geom3.validate(obs))
|
|
147
|
-
t.
|
|
159
|
+
t.is(measureArea(obs), 580.6448151876211)
|
|
160
|
+
t.is(measureVolume(obs), 958.6098905200406)
|
|
161
|
+
t.is(pts.length, 62)
|
|
148
162
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
149
163
|
|
|
150
164
|
// test roundRadius
|
|
@@ -243,6 +257,8 @@ test('roundedCuboid (options)', (t) => {
|
|
|
243
257
|
[[2, -3, -6], [-2, -3, -6], [-2, 3, -6], [2, 3, -6]]
|
|
244
258
|
]
|
|
245
259
|
t.notThrows(() => geom3.validate(obs))
|
|
246
|
-
t.
|
|
260
|
+
t.is(measureArea(obs), 470.09666312772333)
|
|
261
|
+
t.is(measureVolume(obs), 835.1892253143822)
|
|
262
|
+
t.is(pts.length, 62)
|
|
247
263
|
t.true(comparePolygonsAsPoints(pts, exp))
|
|
248
264
|
})
|
|
@@ -38,7 +38,7 @@ export const roundedCylinder = (options) => {
|
|
|
38
38
|
if (!isGTE(height, 0)) throw new Error('height must be positive')
|
|
39
39
|
if (!isGTE(radius, 0)) throw new Error('radius must be positive')
|
|
40
40
|
if (!isGTE(roundRadius, 0)) throw new Error('roundRadius must be positive')
|
|
41
|
-
if (roundRadius > radius) throw new Error('roundRadius must be smaller
|
|
41
|
+
if (roundRadius > radius) throw new Error('roundRadius must be smaller than the radius')
|
|
42
42
|
if (!isGTE(segments, 4)) throw new Error('segments must be four or more')
|
|
43
43
|
|
|
44
44
|
// if size is zero return empty geometry
|