@@ -58,7 +58,7 @@ public final class Geometry: Hashable {
5858 case . cone, . cylinder, . sphere, . cube, . lathe, . loft, . path, . mesh, . camera, . light,
5959 . intersection, . difference, . stencil:
6060 return false
61- case . union, . xor, . extrude, . fill, . hull:
61+ case . union, . xor, . extrude, . fill, . hull, . minkowski :
6262 return mesh == nil
6363 }
6464 }
@@ -185,13 +185,11 @@ public final class Geometry: Hashable {
185185 default :
186186 assert ( children. isEmpty)
187187 }
188- case . hull:
189- break // TODO: what needs to be done here?
190188 case . cone, . cylinder, . sphere, . cube, . loft, . path, . camera, . light:
191189 assert ( children. isEmpty)
192190 case let . mesh( mesh) :
193191 material = mesh. polygons. first? . material as? Material ?? material
194- case . union, . xor, . difference, . intersection, . stencil:
192+ case . union, . xor, . difference, . intersection, . stencil, . hull , . minkowski :
195193 material = children. first? . material ?? . default
196194 case . group:
197195 if debug {
@@ -233,7 +231,7 @@ public final class Geometry: Hashable {
233231 // Must be set after cache key is generated
234232 self . isOpaque = isOpaque
235233
236- // Compute bounds
234+ // Compute the overestimated, non-transformed bounds
237235 switch type {
238236 case . difference, . stencil:
239237 self . bounds = children. first. map {
@@ -253,7 +251,13 @@ public final class Geometry: Hashable {
253251 self . bounds = type. bounds. union ( Bounds ( children. map {
254252 $0. bounds. transformed ( by: $0. transform)
255253 } ) )
256- case . cone, . cube, . cylinder, . sphere, . path, . mesh:
254+ case . minkowski:
255+ var bounds = Bounds ( min: . zero, max: . zero)
256+ for child in children {
257+ bounds. formMinkowskiSum ( with: child. bounds. transformed ( by: child. transform) )
258+ }
259+ self . bounds = bounds
260+ case . cone, . cylinder, . sphere, . cube, . mesh, . path:
257261 self . bounds = type. bounds
258262 case . camera, . light:
259263 self . bounds = . empty
@@ -466,15 +470,13 @@ private extension Geometry {
466470 switch type {
467471 case . extrude( [ ] , _) , . lathe( [ ] , _) , . fill( [ ] ) :
468472 mesh = nil
469- case . hull:
470- mesh = nil
471473 case . group, . path, . mesh,
472474 . cone, . cylinder, . sphere, . cube,
473475 . extrude, . lathe, . loft, . fill:
474476 assert ( type. isLeafGeometry) // Leaves
475477 case . stencil, . difference:
476478 mesh = children. first? . merged ( callback)
477- case . union, . xor, . intersection, . camera, . light:
479+ case . union, . xor, . intersection, . hull , . minkowski , . camera, . light:
478480 mesh = nil
479481 }
480482 return callback ( )
@@ -529,6 +531,11 @@ private extension Geometry {
529531 let m = Mesh . convexHull ( of: vertices, material: Material . default, isCancelled: isCancelled)
530532 let meshes = ( [ m] + childMeshes( callback) ) . map { $0. materialToVertexColors ( material: material) }
531533 mesh = . convexHull( of: meshes, isCancelled: isCancelled) . fixupColors ( material: material)
534+ case . minkowski:
535+ let meshes = childMeshes ( callback) . map { $0. materialToVertexColors ( material: material) }
536+ mesh = Mesh . minkowskiSum ( of: meshes, isCancelled: isCancelled)
537+ . fixupColors ( material: material)
538+ . makeWatertight ( )
532539 case let . fill( paths) :
533540 mesh = Mesh . fill ( paths. map { $0. closed ( ) } , isCancelled: isCancelled) . makeWatertight ( )
534541 case . union, . lathe, . extrude:
@@ -704,7 +711,7 @@ public extension Geometry {
704711 case . camera, . light, . path:
705712 return false
706713 case . cone, . cylinder, . sphere, . cube,
707- . extrude, . lathe, . loft, . fill, . hull,
714+ . extrude, . lathe, . loft, . fill, . hull, . minkowski ,
708715 . union, . difference, . intersection, . xor, . stencil,
709716 . group, . mesh:
710717 return true
@@ -718,7 +725,7 @@ public extension Geometry {
718725 case . camera, . light:
719726 return 0
720727 case . cone, . cylinder, . sphere, . cube,
721- . extrude, . lathe, . loft, . fill, . hull,
728+ . extrude, . lathe, . loft, . fill, . hull, . minkowski ,
722729 . union, . difference, . intersection, . xor, . stencil,
723730 . path, . mesh:
724731 return 1
@@ -731,7 +738,7 @@ public extension Geometry {
731738 . extrude, . lathe, . fill, . loft,
732739 . mesh, . path, . camera, . light:
733740 return 0 // TODO: should paths/points be treated as children?
734- case . union, . xor, . difference, . intersection, . stencil, . group, . hull:
741+ case . union, . xor, . difference, . intersection, . stencil, . group, . hull, . minkowski :
735742 return children. count
736743 }
737744 }
@@ -790,6 +797,10 @@ public extension Geometry {
790797 bounds. formUnion ( child. exactBounds ( with: child. transform * transform, callback) )
791798 }
792799 return bounds
800+ case . minkowski:
801+ return children. reduce ( . empty) {
802+ $0. minkowskiSum ( with: $1. exactBounds ( with: $1. transform * transform, callback) )
803+ }
793804 case let . path( path) :
794805 return path. transformed ( by: transform) . bounds
795806 case let . fill( paths) , let . loft( paths) :
0 commit comments