class BottleTop : Model { @Custom var capHeight = 15 @Custom var capRadius = 36/2 @Custom var extraHeight = 4 @Custom var thickness = 2 @Custom var chamfer = 1.5 @Custom var text = "SLOE GIN" @Custom var fontSize = 12 fun internal() : Shape2d { return Circle(capRadius) } fun exterior() : Shape2d { return Circle(capRadius + thickness) } fun around( str : String ) :Shape3d { val text = Text( str, BOLD, fontSize).center() val drum = ExtrusionBuilder.drum( text.offset(0.5), text.offset(-0.2), 1 ) val result = drum.aroundCylinder( capRadius + thickness, true ).color("Red") return result.rotateX(90) } override fun build() : Shape3d { val cap = ExtrusionBuilder().apply { forward(capHeight) crossSection(internal()) // Inside forward(-capHeight) crossSection() // Bottom inside crossSection(exterior().offset(-chamfer)) // Bottom outside pre chamfer forward(chamfer) crossSection(exterior()) // Bottom outside post chamfer forward(capHeight+extraHeight-chamfer) crossSection() // Top pre-chamfer forward(chamfer) crossSection(exterior().offset(-chamfer)) // Top post chamfer }.build() val text = around(text).translateZ((capHeight+extraHeight)/2+1) // Flip it upside down, so that the top of the cap is on the print bed. return (cap + text).rotateX(180).toOriginZ() } }