Skip to content

Commit 6c1954f

Browse files
authored
feat(modeling): new geometry for 3D paths (path3)
1 parent f5dabe8 commit 6c1954f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+719
-31
lines changed

jsdoc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"packages/modeling/src/geometries/geom2",
1111
"packages/modeling/src/geometries/geom3",
1212
"packages/modeling/src/geometries/path2",
13+
"packages/modeling/src/geometries/path3",
1314
"packages/modeling/src/geometries/poly2",
1415
"packages/modeling/src/geometries/poly3",
1516
"packages/modeling/src/geometries/slice",

packages/modeling/src/geometries/geom3/create.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,4 @@ import * as mat4 from '../../maths/mat4/index.js'
2424
* @returns {Geom3} a new geometry
2525
* @alias module:modeling/geometries/geom3.create
2626
*/
27-
export const create = (polygons) => {
28-
if (polygons === undefined) {
29-
polygons = [] // empty contents
30-
}
31-
return {
32-
polygons,
33-
transforms: mat4.create()
34-
}
35-
}
27+
export const create = (polygons = []) => ({ polygons, transforms: mat4.create() })
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * as geom2 from './geom2/index.js'
22
export * as geom3 from './geom3/index.js'
33
export * as path2 from './path2/index.js'
4+
export * as path3 from './path3/index.js'
45
export * as poly2 from './poly2/index.js'
56
export * as poly3 from './poly3/index.js'
67
export * as slice from './slice/index.js'

packages/modeling/src/geometries/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
export * as geom2 from './geom2/index.js'
1717
export * as geom3 from './geom3/index.js'
1818
export * as path2 from './path2/index.js'
19+
export * as path3 from './path3/index.js'
1920
export * as poly2 from './poly2/index.js'
2021
export * as poly3 from './poly3/index.js'
2122
export * as slice from './slice/index.js'

packages/modeling/src/geometries/path2/create.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,4 @@ import * as mat4 from '../../maths/mat4/index.js'
2121
* @example
2222
* let newPath = create()
2323
*/
24-
export const create = (points) => {
25-
if (points === undefined) {
26-
points = []
27-
}
28-
return {
29-
points: points,
30-
isClosed: false,
31-
transforms: mat4.create()
32-
}
33-
}
24+
export const create = (points = []) => ({ points: points, isClosed: false, transforms: mat4.create() })
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import * as mat4 from '../../maths/mat4/index.js'
2+
import * as vec3 from '../../maths/vec3/index.js'
3+
4+
/*
5+
* Apply the transforms of the given geometry.
6+
*
7+
* NOTE: This function must be called BEFORE exposing any data. See toVertices.
8+
*
9+
* @param {Path3} geometry - the geometry to transform
10+
* @returns {Path3} the given geometry
11+
* @function
12+
*
13+
* @example
14+
* geometry = applyTransforms(geometry)
15+
*/
16+
export const applyTransforms = (geometry) => {
17+
if (mat4.isIdentity(geometry.transforms)) return geometry
18+
19+
geometry.vertices = geometry.vertices.map((vertex) => vec3.transform(vec3.create(), vertex, geometry.transforms))
20+
geometry.transforms = mat4.create()
21+
return geometry
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import test from 'ava'
2+
3+
import { fromVertices } from './index.js'
4+
5+
import { applyTransforms } from './applyTransforms.js'
6+
7+
import { comparePoints, compareVectors } from '../../../test/helpers/index.js'
8+
9+
test('applyTransforms: Updates a populated path with transformed points', (t) => {
10+
const vertices = [[0, 0, 0], [1, 0, 0], [0, 1, 0]]
11+
const expected = {
12+
vertices: [[0, 0, 0], [1, 0, 0], [0, 1, 0]],
13+
isClosed: false,
14+
transforms: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
15+
}
16+
const geometry = fromVertices({}, vertices)
17+
const updated = applyTransforms(geometry)
18+
t.is(geometry, updated)
19+
t.true(comparePoints(updated.vertices, expected.vertices))
20+
t.false(updated.isClosed)
21+
t.true(compareVectors(updated.transforms, expected.transforms))
22+
23+
const updated2 = applyTransforms(updated)
24+
t.is(updated, updated2)
25+
t.true(comparePoints(updated2.vertices, expected.vertices))
26+
t.false(updated2.isClosed)
27+
t.true(compareVectors(updated2.transforms, expected.transforms))
28+
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type { Path3 } from './type.d.ts'
2+
3+
export function close(geometry: Path3): Path3
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { EPS } from '../../maths/constants.js'
2+
3+
import * as vec3 from '../../maths/vec3/index.js'
4+
5+
/**
6+
* Close the given geometry.
7+
*
8+
* @param {Path3} geometry - the path to close
9+
* @returns {Path3} a new path
10+
* @function
11+
* @alias module:modeling/geometries/path3.close
12+
*/
13+
export const close = (geometry) => {
14+
if (geometry.isClosed) return geometry
15+
16+
const cloned = Object.assign({}, geometry)
17+
cloned.isClosed = true
18+
19+
if (cloned.vertices.length > 1) {
20+
// make sure the paths are formed properly
21+
const vertices = cloned.vertices
22+
const p0 = vertices[0]
23+
let pn = vertices[vertices.length - 1]
24+
while (vec3.distance(p0, pn) < (EPS * EPS)) {
25+
vertices.pop()
26+
if (vertices.length === 1) break
27+
pn = vertices[vertices.length - 1]
28+
}
29+
}
30+
return cloned
31+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import test from 'ava'
2+
3+
import { close, create, fromVertices } from './index.js'
4+
5+
test('close: closes an empty path', (t) => {
6+
const p1 = create()
7+
t.false(p1.isClosed)
8+
9+
const p2 = close(p1)
10+
t.true(p2.isClosed)
11+
t.not(p1, p2)
12+
13+
const p3 = close(p2)
14+
t.true(p3.isClosed)
15+
t.is(p2, p3)
16+
})
17+
18+
test('close: closes various paths', (t) => {
19+
let p1 = create()
20+
p1 = close(p1)
21+
t.true(p1.isClosed)
22+
t.is(0, p1.vertices.length)
23+
24+
let p2 = fromVertices({ closed: false }, [])
25+
p2 = close(p2)
26+
t.true(p2.isClosed)
27+
t.is(0, p2.vertices.length)
28+
29+
let p3 = fromVertices({ closed: true }, [[0, 0, 0]])
30+
p3 = close(p3)
31+
t.true(p3.isClosed)
32+
t.is(1, p3.vertices.length)
33+
34+
let p4 = fromVertices({ closed: true }, [[0, 0, 0], [0, 0, 0]])
35+
p4 = close(p4)
36+
t.true(p4.isClosed)
37+
t.is(1, p4.vertices.length) // the last point is removed
38+
39+
let p5 = fromVertices({ closed: true }, [[0, 0, 0], [1, 1, 0], [0, 0, 0]])
40+
p5 = close(p5)
41+
t.true(p5.isClosed)
42+
t.is(2, p5.vertices.length) // the last point is removed
43+
})

0 commit comments

Comments
 (0)