import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import uk.co.nickthecoder.foocad.extras.v1.* import static uk.co.nickthecoder.foocad.extras.v1.Extras.* import uk.co.nickthecoder.foocad.smartextrusion.v1.* import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* import uk.co.nickthecoder.foocad.cup.v1.* import static uk.co.nickthecoder.foocad.cup.v1.Cup.* class BirdBathMoat : Model { var size = Vector2( 235, 40 ) var insideSize = Vector2( 70, 30 ) var thickness = 2.0 var baseThickness = 1.2 var round = 20 var measureDiameter = 217 @Piece( printable=false, about="Work in progress" ) meth shade() : Shape3d { val height = 100 val radius = 100 val path = PolygonBuilder().apply { moveTo( 0, height ) bezierTo( Vector2( radius/2, height/2 ), Vector2(radius/10, height/2), Vector2( radius, 0 ) ) lineBy(8,0) bezierBy( Vector2( 4, 4 ), Vector2( -13, 8 ), Vector2( 10, 18 ) ) }.buildPath() val shape = path.thickness( thickness ) .leftTo(0.1) val end = Circle( thickness ).translate( path[-1] ) val main = (shape + end) .revolve() val ball = Sphere(6).bottomTo( main.top - thickness*1.5 ) return main + ball /* val r = 100 val ball = Sphere( r ) - Sphere( r - thickness ) val dome = ball.remove( Cube( r*3 ).center().topTo( r*0.5 ) ) return dome.rotateY(30) */ } @Piece( about="Stick 3 to the base, to locate the bath above model 'SmallBirdTable'" ) meth locatingFoot() : Shape3d { val d = 9 val post = Circle( d/2 ).smartExtrude( 10 ).top( Fillet(d/3) ) val base = Circle(20).extrude(1.0) return base + post } @Piece( about="For a free-standing bath. Slugs/snails may hide underneither ;-))" ) meth foot() : Shape3d { val radius = 14 val tipOffset = Vector2( 4, 30 ) // X offfset and height of the prong val base = Circle( radius ).rightTo(0) .smartExtrude(4 + 1) .scaleBottom( Vector2(1.2, 1.5) ) val mid = Circle( radius ) .rightTo(0) .extrude(1).translateZ(base.top-1) val tip = Sphere( 4 ) .translate( tipOffset.x, 0, tipOffset.y ) val all = base + (tip hull mid) return all } @Piece meth footRing() : Shape3d { val foot = foot() val width = 34 val radius = size.x/2-round/2-1 val ringShape = Ring( radius, radius - width*0.6) val ring = ringShape.extrude(1) val feet = foot.leftTo(ring.right - width).repeatAroundZ(5) return (ring + feet).color("Green") } @Piece @Slice( perimeters=6 ) meth main() : Shape3d { val lipPath = PolygonBuilder().apply { val r = 4 moveTo( 0,0 ) bezierBy( Vector2(-r/2,r/2), Vector2(0,r/2), Vector2(-r, r*1.1) ) circularArcBy( r, r, r, false, false ) }.buildPath() val main = Circle( size.x/2 ).cup( size.y, thickness ) .baseThickness( baseThickness ) .insideBottom( Fillet( round ) ) .outsideBottom( ProfileEdge.roundedChamfer( round ) ) .outsideTop( ProfileEdge( lipPath ) ) .insideTop( Fillet(thickness-0.1) ) val inside = Circle( insideSize.x/2 ).cup( insideSize.y, thickness ) .baseThickness( baseThickness ) .insideBottom( Fillet( round ) ) .outsideBottom( Fillet( round ).reverse() ) .insideTop( ProfileEdge( lipPath ) ) .outsideTop( Fillet(thickness-0.1) ) return main + inside } @Piece( print="main" ) override fun build() : Shape3d { // I wanted the very bottom to be the same diameter as my SmallBirdTable's top. val measure = Cube( measureDiameter, 1, 1 ).center().topTo(0).previewOnly() //val feet = foot().rightTo( main.right-6 ).mirrorZ().topTo(0).repeatAroundZ(5) val feet = footRing().mirrorZ() return main() + measure + feet } }