Skip to content

Commit 16e43a3

Browse files
committed
feat(modeling): preserve color for offset and extrude
1 parent f88669b commit 16e43a3

File tree

12 files changed

+78
-21
lines changed

12 files changed

+78
-21
lines changed

packages/modeling/src/geometries/geom2/reverse.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ import { clone } from './clone.js'
1313
export const reverse = (geometry) => {
1414
const reversed = clone(geometry)
1515
reversed.outlines = reversed.outlines.map((outline) => outline.slice().reverse())
16+
if (geometry.color) reversed.color = geometry.color
1617
return reversed
1718
}

packages/modeling/src/geometries/geom2/reverse.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,10 @@ test('reverse: does not modify input geometry', (t) => {
2929
t.true(comparePoints(toPoints(geometry), forward))
3030
t.true(comparePoints(toPoints(another), backward))
3131
})
32+
33+
test('reverse: preserves color', (t) => {
34+
const points = [[0, 0], [1, 0], [0, 1]]
35+
const geometry = colorize([1, 0, 0], create([points]))
36+
const reversed = reverse(geometry)
37+
t.deepEqual(reversed.color, [1, 0, 0, 1])
38+
})

packages/modeling/src/operations/extrusions/extrudeLinear.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { comparePolygonsAsPoints } from '../../../test/helpers/index.js'
44

55
import { TAU } from '../../maths/constants.js'
66

7+
import { colorize } from '../../colors/index.js'
8+
79
import { geom2, geom3, path2 } from '../../geometries/index.js'
810

911
import { measureVolume } from '../../measurements/index.js'
@@ -37,6 +39,17 @@ test('extrudeLinear (defaults)', (t) => {
3739
t.true(comparePolygonsAsPoints(pts, exp))
3840
})
3941

42+
test('extrudeLinear: preserves color', (t) => {
43+
const red = colorize([1, 0, 0], square())
44+
const extruded = extrudeLinear({ }, red)
45+
t.deepEqual(extruded.color, [1, 0, 0, 1])
46+
47+
// one red, one blue
48+
const out = extrudeLinear({ }, [red, square()])
49+
t.deepEqual(out[0].color, [1, 0, 0, 1])
50+
t.is(out[1].color, undefined)
51+
})
52+
4053
test('extrudeLinear (no twist)', (t) => {
4154
const geometry2 = square({ size: 10 })
4255

packages/modeling/src/operations/extrusions/extrudeLinearGeom2.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,7 @@ export const extrudeLinearGeom2 = (options, geometry) => {
5353
repair,
5454
callback: createTwist
5555
}
56-
return extrudeFromSlices(options, baseSlice)
56+
const output = extrudeFromSlices(options, baseSlice)
57+
if (geometry.color) output.color = geometry.color
58+
return output
5759
}

packages/modeling/src/operations/extrusions/extrudeLinearPath2.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ export const extrudeLinearPath2 = (options, geometry) => {
1818
// Convert path2 to geom2
1919
const points = path2.toPoints(geometry)
2020
const geometry2 = geom2.create([points])
21+
if (geometry.color) geometry2.color = geometry.color
2122
return extrudeLinearGeom2(options, geometry2)
2223
}

packages/modeling/src/operations/extrusions/extrudeRectangular.test.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ import test from 'ava'
22

33
import { TAU } from '../../maths/constants.js'
44

5-
import { geom2, geom3 } from '../../geometries/index.js'
5+
import { colorize } from '../../colors/index.js'
6+
7+
import { geom2, geom3, path2 } from '../../geometries/index.js'
68

79
import { measureVolume } from '../../measurements/index.js'
810

9-
import { arc, rectangle } from '../../primitives/index.js'
11+
import { arc, square } from '../../primitives/index.js'
1012

1113
import { extrudeRectangular } from './index.js'
1214

1315
test('extrudeRectangular (defaults)', (t) => {
1416
const geometry1 = arc({ radius: 5, endAngle: TAU / 4, segments: 16 })
15-
const geometry2 = rectangle({ size: [5, 5] })
17+
const geometry2 = square({ size: 5 })
1618

1719
let obs = extrudeRectangular({ }, geometry1)
1820
let pts = geom3.toPoints(obs)
@@ -27,9 +29,22 @@ test('extrudeRectangular (defaults)', (t) => {
2729
t.is(pts.length, 32)
2830
})
2931

32+
test('extrudeRectangular: preserves color', (t) => {
33+
const red = colorize([1, 0, 0], square())
34+
const extruded = extrudeRectangular({ }, red)
35+
t.deepEqual(extruded.color, [1, 0, 0, 1])
36+
37+
// one red geom2, one blue path2
38+
const path = path2.create([[10, 10], [0, 0], [10, 0]])
39+
const blue = colorize([0, 0, 1], path)
40+
const out = extrudeRectangular({ }, [red, blue])
41+
t.deepEqual(out[0].color, [1, 0, 0, 1])
42+
t.deepEqual(out[1].color, [0, 0, 1, 1])
43+
})
44+
3045
test('extrudeRectangular (chamfer)', (t) => {
3146
const geometry1 = arc({ radius: 5, endAngle: TAU / 4, segments: 16 })
32-
const geometry2 = rectangle({ size: [5, 5] })
47+
const geometry2 = square({ size: 5 })
3348

3449
let obs = extrudeRectangular({ corners: 'chamfer' }, geometry1)
3550
let pts = geom3.toPoints(obs)
@@ -46,7 +61,7 @@ test('extrudeRectangular (chamfer)', (t) => {
4661

4762
test('extrudeRectangular (segments = 8, round)', (t) => {
4863
const geometry1 = arc({ radius: 5, endAngle: TAU / 4, segments: 16 })
49-
const geometry2 = rectangle({ size: [5, 5] })
64+
const geometry2 = square({ size: 5 })
5065

5166
let obs = extrudeRectangular({ segments: 8, corners: 'round' }, geometry1)
5267
let pts = geom3.toPoints(obs)

packages/modeling/src/operations/extrusions/extrudeRectangularGeom2.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const extrudeRectangularGeom2 = (options, geometry) => {
4141
expanded = expanded.concat(geom2.toOutlines(part))
4242
})
4343
const newGeometry = geom2.create(expanded)
44-
45-
return extrudeLinearGeom2(options, newGeometry)
44+
const output = extrudeLinearGeom2(options, newGeometry)
45+
if (geometry.color) output.color = geometry.color
46+
return output
4647
}

packages/modeling/src/operations/extrusions/extrudeRotate.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const extrudeRotate = (options, geometry) => {
5959
// convert geometry to an array of sides, easier to deal with
6060
let shapeSides = geom2.toSides(geometry)
6161
if (shapeSides.length === 0) throw new Error('the given geometry cannot be empty')
62+
let sliceGeometry = geometry
6263

6364
// determine if the extrusion can be computed in the first place
6465
// ie all the points have to be either x > 0 or x < 0
@@ -87,8 +88,8 @@ export const extrudeRotate = (options, geometry) => {
8788
return [point0, point1]
8889
})
8990
// recreate the geometry from the (-) capped points
90-
geometry = geom2.reverse(geom2.fromSides(shapeSides))
91-
geometry = mirrorX(geometry)
91+
sliceGeometry = geom2.reverse(geom2.fromSides(shapeSides))
92+
sliceGeometry = mirrorX(sliceGeometry)
9293
} else if (pointsWithPositiveX.length >= pointsWithNegativeX.length) {
9394
shapeSides = shapeSides.map((side) => {
9495
let point0 = side[0]
@@ -98,13 +99,13 @@ export const extrudeRotate = (options, geometry) => {
9899
return [point0, point1]
99100
})
100101
// recreate the geometry from the (+) capped points
101-
geometry = geom2.fromSides(shapeSides)
102+
sliceGeometry = geom2.fromSides(shapeSides)
102103
}
103104
}
104105

105106
const rotationPerSlice = totalRotation / segments
106107
const isCapped = Math.abs(totalRotation) < TAU
107-
let baseSlice = slice.fromGeom2(geometry)
108+
let baseSlice = slice.fromGeom2(sliceGeometry)
108109
baseSlice = slice.reverse(baseSlice)
109110

110111
const matrix = mat4.create()
@@ -126,5 +127,7 @@ export const extrudeRotate = (options, geometry) => {
126127
close: !isCapped,
127128
callback: createSlice
128129
}
129-
return extrudeFromSlices(options, baseSlice)
130+
const output = extrudeFromSlices(options, baseSlice)
131+
if (geometry.color) output.color = geometry.color
132+
return output
130133
}

packages/modeling/src/operations/extrusions/extrudeRotate.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import { comparePoints, comparePolygonsAsPoints } from '../../../test/helpers/in
44

55
import { TAU } from '../../maths/constants.js'
66

7+
import { colorize } from '../../colors/index.js'
8+
79
import { geom2, geom3 } from '../../geometries/index.js'
810

911
import { measureVolume } from '../../measurements/index.js'
1012

13+
import { square } from '../../primitives/index.js'
14+
1115
import { extrudeRotate } from './index.js'
1216

1317
test('extrudeRotate: (defaults) extruding of a geom2 produces an expected geom3', (t) => {
@@ -20,6 +24,12 @@ test('extrudeRotate: (defaults) extruding of a geom2 produces an expected geom3'
2024
t.is(pts.length, 96)
2125
})
2226

27+
test('extrudeRotate: preserves color', (t) => {
28+
const red = colorize([1, 0, 0], square())
29+
const extruded = extrudeRotate({ }, red)
30+
t.deepEqual(extruded.color, [1, 0, 0, 1])
31+
})
32+
2333
test('extrudeRotate: (angle) extruding of a geom2 produces an expected geom3', (t) => {
2434
const geometry2 = geom2.create([[[10, 8], [10, -8], [26, -8], [26, 8]]])
2535

packages/modeling/src/operations/offsets/offsetGeom2.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ export const offsetGeom2 = (options, geometry) => {
4646
}
4747
return offsetFromPoints(options, outline)
4848
})
49+
// TODO: union outlines that expanded into each other
4950

5051
// create a composite geometry from the new outlines
51-
return geom2.create(newOutlines)
52+
const output = geom2.create(newOutlines)
53+
if (geometry.color) output.color = geometry.color
54+
return output
5255
}

0 commit comments

Comments
 (0)