@@ -145,19 +145,22 @@ public final class Geometry: Hashable {
145145 var type = type
146146 switch type {
147147 case var . extrude( paths, options) :
148- ( paths, material) = paths. vertexColorsToMaterial ( material: material)
149- ( options. along, material) = options. along. vertexColorsToMaterial ( material: material)
150148 switch ( paths. count, options. along. count) {
151149 case ( 0 , 0 ) :
152150 break
153- case ( 1 , 1 ) , ( 1 , 0 ) :
154- assert ( children . isEmpty )
151+ case ( 1 , 0 ) :
152+ ( paths , material ) = paths . vertexColorsToMaterial ( material : material )
155153 type = . extrude( paths, options)
154+ case ( 1 , 1 ) :
155+ var pair = ( paths + options. along)
156+ ( pair, material) = pair. vertexColorsToMaterial ( material: material)
157+ options. along = [ pair [ 1 ] ]
158+ type = . extrude( [ pair [ 0 ] ] , options)
156159 case ( _, 0 ) :
157- assert ( children. isEmpty)
158160 type = . extrude( [ ] , . default)
159161 children = paths. map { path in
160- Geometry (
162+ let ( path, material) = path. vertexColorsToMaterial ( material: material)
163+ return Geometry (
161164 type: . extrude( [ path] , options) ,
162165 name: nil ,
163166 transform: . identity,
@@ -167,17 +170,18 @@ public final class Geometry: Hashable {
167170 sourceLocation: sourceLocation
168171 )
169172 }
173+ material = children. first? . material ?? . default
170174 default :
171175 // For extrusions with multiple paths, convert each path to a
172176 // separate child geometry so they can be renderered individually
173- assert ( children. isEmpty)
174177 type = . extrude( [ ] , . default)
175178 children = paths. flatMap { path in
176179 options. along. map { along in
180+ let ( pair, material) = [ path, along] . vertexColorsToMaterial ( material: material)
177181 var options = options
178- options. along = [ along ]
182+ options. along = [ pair [ 1 ] ]
179183 return Geometry (
180- type: . extrude( [ path ] , options) ,
184+ type: . extrude( [ pair [ 0 ] ] , options) ,
181185 name: nil ,
182186 transform: . identity,
183187 material: material,
@@ -187,23 +191,23 @@ public final class Geometry: Hashable {
187191 )
188192 }
189193 }
194+ material = children. first? . material ?? . default
190195 }
191196 case . lathe( var paths, let segments) :
192- ( paths, material) = paths. vertexColorsToMaterial ( material: material)
193197 switch paths. count {
194198 case 0 :
195199 break
196200 case 1 :
197- assert ( children . isEmpty )
201+ ( paths , material ) = paths . vertexColorsToMaterial ( material : material )
198202 type = . lathe( paths, segments: segments)
199203 default :
200204 // For lathes with multiple paths, convert each path to a
201205 // separate child geometry so they can be renderered individually
202- assert ( children. isEmpty)
203206 type = . lathe( [ ] , segments: 0 )
204- children = paths. map {
205- Geometry (
206- type: . lathe( [ $0] , segments: segments) ,
207+ children = paths. map { path in
208+ let ( path, material) = path. vertexColorsToMaterial ( material: material)
209+ return Geometry (
210+ type: . lathe( [ path] , segments: segments) ,
207211 name: nil ,
208212 transform: . identity,
209213 material: material,
@@ -212,23 +216,23 @@ public final class Geometry: Hashable {
212216 sourceLocation: sourceLocation
213217 )
214218 }
219+ material = children. first? . material ?? . default
215220 }
216221 case var . fill( paths) :
217- ( paths, material) = paths. vertexColorsToMaterial ( material: material)
218222 switch paths. count {
219223 case 0 :
220224 break
221225 case 1 :
222- assert ( children . isEmpty )
226+ ( paths , material ) = paths . vertexColorsToMaterial ( material : material )
223227 type = . fill( paths)
224228 default :
225229 // For fills with multiple paths, convert each path to a
226230 // separate child geometry so they can be renderered individually
227- assert ( children. isEmpty)
228231 type = . fill( [ ] )
229- children = paths. map {
230- Geometry (
231- type: . fill( [ $0] ) ,
232+ children = paths. map { path in
233+ let ( path, material) = path. vertexColorsToMaterial ( material: material)
234+ return Geometry (
235+ type: . fill( [ path] ) ,
232236 name: nil ,
233237 transform: . identity,
234238 material: material,
@@ -237,7 +241,14 @@ public final class Geometry: Hashable {
237241 sourceLocation: sourceLocation
238242 )
239243 }
244+ material = children. first? . material ?? . default
240245 }
246+ case var . loft( paths) :
247+ ( paths, material) = paths. vertexColorsToMaterial ( material: material)
248+ type = . loft( paths)
249+ case var . path( path) :
250+ ( path, material) = path. vertexColorsToMaterial ( material: material)
251+ type = . path( path)
241252 case let . mesh( mesh) :
242253 material = mesh. polygons. first? . material as? Material ?? material
243254 case . hull, . minkowski:
@@ -248,7 +259,7 @@ public final class Geometry: Hashable {
248259 if debug {
249260 children. forEach { $0. debug = true }
250261 }
251- case . cone, . cylinder, . sphere, . cube, . loft , . path , . camera, . light:
262+ case . cone, . cylinder, . sphere, . cube, . camera, . light:
252263 break
253264 }
254265
@@ -626,26 +637,30 @@ private extension Geometry {
626637 case . cube:
627638 mesh = . cube( )
628639 case let . extrude( paths, . default) where paths. count == 1 :
629- mesh = Mesh . extrude ( paths [ 0 ] ) . makeWatertight ( )
640+ mesh = . extrude( paths [ 0 ] ) . makeWatertight ( )
630641 case let . extrude( paths, options) where paths. count == 1 && options. along. count == 1 :
631- mesh = Mesh . extrude (
632- paths [ 0 ] ,
633- along: options. along [ 0 ] ,
642+ mesh = . extrude(
643+ paths [ 0 ] . materialToVertexColors ( material : material ) ,
644+ along: options. along [ 0 ] . materialToVertexColors ( material : material ) . predividedBy ( material ) ,
634645 twist: options. twist,
635646 align: options. align,
636647 isCancelled: isCancelled
637- ) . makeWatertight ( )
648+ )
649+ . vertexColorsToMaterial ( material: material)
650+ . replacing ( material, with: nil )
651+ . makeWatertight ( )
638652 case let . lathe( paths, segments: segments) where paths. count == 1 :
639- mesh = Mesh . lathe ( paths [ 0 ] , slices: segments) . makeWatertight ( )
653+ mesh = . lathe( paths [ 0 ] , slices: segments, isCancelled : isCancelled ) . makeWatertight ( )
640654 case let . fill( paths) where paths. count == 1 :
641- mesh = Mesh . fill ( [ paths [ 0 ] . closed ( ) ] , isCancelled : isCancelled ) . makeWatertight ( )
655+ mesh = . fill( paths [ 0 ] . closed ( ) ) . makeWatertight ( )
642656 case let . loft( paths) :
643- mesh = Mesh . loft ( paths) . makeWatertight ( )
657+ mesh = . loft( paths, isCancelled : isCancelled ) . makeWatertight ( )
644658 case let . hull( vertices) :
645- let m = Mesh . convexHull ( of: vertices, material: material, isCancelled: isCancelled)
646- let meshes = ( [ m ] + childMeshes( callback) ) . map { $0. materialToVertexColors ( material: material) }
659+ let base = Mesh . convexHull ( of: vertices, material: material, isCancelled: isCancelled)
660+ let meshes = ( [ base ] + childMeshes( callback) ) . map { $0. materialToVertexColors ( material: material) }
647661 mesh = . convexHull( of: meshes, isCancelled: isCancelled)
648- . vertexColorsToMaterial ( material: material) . replacing ( material, with: nil )
662+ . vertexColorsToMaterial ( material: material)
663+ . replacing ( material, with: nil )
649664 case . minkowski:
650665 var children = ArraySlice ( children. enumerated ( ) . sorted {
651666 switch ( $0. 1 . type, $1. 1 . type) {
@@ -676,45 +691,55 @@ private extension Geometry {
676691 var sum : Mesh
677692 if let shape = first. path? . transformed ( by: first. transform) {
678693 guard let next = children. popFirst ( ) else {
679- sum = . empty
694+ mesh = . empty
680695 break
681696 }
697+ let shape = shape. materialToVertexColors ( material: first. material)
682698 if let path = next. path? . transformed ( by: next. transform) {
683- let mesh = Mesh . fill ( shape) . materialToVertexColors ( material: first. material)
684- sum = mesh. minkowskiSum ( with: path, isCancelled: isCancelled)
699+ sum = . fill( shape) . minkowskiSum (
700+ with: path. materialToVertexColors ( material: next. material) ,
701+ isCancelled: isCancelled
702+ )
685703 } else {
686- let mesh = next. flattened ( callback) . materialToVertexColors ( material: next. material)
687- sum = mesh. minkowskiSum ( with: shape, isCancelled: isCancelled)
704+ sum = next. flattened ( callback) . materialToVertexColors ( material: next. material) . minkowskiSum (
705+ with: shape,
706+ isCancelled: isCancelled
707+ )
688708 }
689709 } else {
690710 sum = first. flattened ( callback) . materialToVertexColors ( material: first. material)
691711 }
692712 while let next = children. popFirst ( ) {
693- if var path = next. path? . transformed ( by: next. transform) {
694- path = path. materialToVertexColors ( material: next. material)
695- sum = sum. minkowskiSum ( with: path, isCancelled: isCancelled)
713+ if let path = next. path? . transformed ( by: next. transform) {
714+ sum = sum. minkowskiSum (
715+ with: path. materialToVertexColors ( material: next. material) . predividedBy ( first. material) ,
716+ isCancelled: isCancelled
717+ )
696718 } else {
697- let mesh = next. flattened ( callback) . materialToVertexColors ( material: next. material)
698- sum = sum. minkowskiSum ( with: mesh, isCancelled: isCancelled)
719+ sum = sum. minkowskiSum (
720+ with: next. flattened ( callback) . materialToVertexColors ( material: next. material) ,
721+ isCancelled: isCancelled
722+ )
699723 }
700724 }
701725 mesh = sum. vertexColorsToMaterial ( material: material)
702- . replacing ( material, with: nil ) . makeWatertight ( )
726+ . replacing ( material, with: nil )
727+ . makeWatertight ( )
703728 case . union, . lathe, . extrude, . fill:
704- mesh = Mesh . union ( childMeshes ( callback) , isCancelled: isCancelled) . makeWatertight ( )
729+ mesh = . union( childMeshes ( callback) , isCancelled: isCancelled) . makeWatertight ( )
705730 case . xor:
706- mesh = Mesh . symmetricDifference ( flattenedChildren ( callback) , isCancelled: isCancelled) . makeWatertight ( )
731+ mesh = . symmetricDifference( flattenedChildren ( callback) , isCancelled: isCancelled) . makeWatertight ( )
707732 case . difference:
708733 let first = flattenedFirstChild ( callback)
709734 let meshes = [ first] + children. dropFirst ( ) . meshes ( with: material, callback)
710- mesh = Mesh . difference ( meshes, isCancelled: isCancelled) . makeWatertight ( )
735+ mesh = . difference( meshes, isCancelled: isCancelled) . makeWatertight ( )
711736 case . intersection:
712737 let meshes = flattenedChildren ( callback)
713- mesh = Mesh . intersection ( meshes, isCancelled: isCancelled) . makeWatertight ( )
738+ mesh = . intersection( meshes, isCancelled: isCancelled) . makeWatertight ( )
714739 case . stencil:
715740 let first = flattenedFirstChild ( callback)
716741 let meshes = [ first] + children. dropFirst ( ) . meshes ( with: material, callback)
717- mesh = Mesh . stencil ( meshes, isCancelled: isCancelled) . makeWatertight ( )
742+ mesh = . stencil( meshes, isCancelled: isCancelled) . makeWatertight ( )
718743 case let . mesh( mesh) :
719744 self . mesh = mesh
720745 }
@@ -798,11 +823,34 @@ private extension Geometry {
798823 }
799824}
800825
826+ private extension Color {
827+ func predividedBy( _ other: Color ) -> Color {
828+ . init(
829+ other. r > 0 ? r / other. r : r,
830+ other. g > 0 ? g / other. g : g,
831+ other. b > 0 ? b / other. b : b,
832+ other. a > 0 ? a / other. a : a
833+ )
834+ }
835+ }
836+
837+ private extension Material {
838+ func predividedBy( _ other: Material ) -> Material {
839+ var result = self
840+ result. albedo = . color( {
841+ let lhs = color ?? . white
842+ let rhs = other. color ?? . white
843+ return lhs. predividedBy ( rhs)
844+ } ( ) )
845+ return result
846+ }
847+ }
848+
801849private extension [ Path ] {
802850 /// Returns the uniform color of all vertices, or nil if they have different colors
803851 var uniformVertexColor : Color ? {
804852 let uniformColor = first? . uniformVertexColor ?? . white
805- return allSatisfy { $0. uniformVertexColor == uniformColor } ? uniformColor : nil
853+ return allSatisfy { [ uniformColor , . white ] . contains ( $0. uniformVertexColor) } ? uniformColor : nil
806854 }
807855
808856 /// Convert uniform point colors to a material instead
@@ -827,8 +875,8 @@ private extension [Path] {
827875extension Path {
828876 /// Returns the uniform color of all vertices, or nil if they have different colors
829877 var uniformVertexColor : Color ? {
830- let uniformColor = points. first? . color
831- return points. allSatisfy { $0. color == uniformColor } ? ( uniformColor ?? . white ) : nil
878+ let uniformColor = points. first? . color ?? . white
879+ return points. allSatisfy { $0. color ?? . white == uniformColor } ? uniformColor : nil
832880 }
833881
834882 /// Convert uniform point colors to a material instead
@@ -849,13 +897,17 @@ extension Path {
849897 return ( self , material)
850898 }
851899
852- /// Convert material color to vertex colors
900+ /// Convert material color to vertex colors, preserving the existing vertex colors if set
853901 func materialToVertexColors( material: ShapeScript . Material ? ) -> Path {
854902 guard let color = material? . color, color != . white, !hasColors else {
855903 return self
856904 }
857905 return withColor ( color)
858906 }
907+
908+ func predividedBy( _ other: Material ) -> Path {
909+ mapColors { $0? . predividedBy ( other. color ?? . white) }
910+ }
859911}
860912
861913extension Polygon {
@@ -883,7 +935,7 @@ extension Polygon {
883935 return withMaterial ( material)
884936 }
885937
886- /// Convert material color to vertex colors
938+ /// Convert material colors to vertex colors, preserving the existing vertex colors if set
887939 func materialToVertexColors( material: ShapeScript . Material ? ) -> Polygon {
888940 guard var material = self . material as? ShapeScript . Material ?? material,
889941 let color = material. color, color != . white,
@@ -921,7 +973,7 @@ extension Mesh {
921973 return withMaterial ( material)
922974 }
923975
924- /// Convert material colors to vertex colors
976+ /// Convert material colors to vertex colors, preserving the existing vertex colors if set
925977 func materialToVertexColors( material: ShapeScript . Material ? ) -> Mesh {
926978 . init( polygons. map { $0. materialToVertexColors ( material: material) } )
927979 }
0 commit comments