/Garden/BirdBathMoat.foocad

A bird bath with an extra container at the center where I can drop slugs/snails etc. for food. Heopfully the water acts as a moat to prevent the the pests escaping.
Print with PETG? In my experience PLA never holds water.
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
}
}
