import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.* import static uk.co.nickthecoder.foocad.extras.v1.Extras.* class BirdHouseFeeder : Model { val glass = Vector3( 150, 120, 4 ) var gap = 20 var extra = 3 var exit = 7 var baseMargin = 30 var roofMargin = 20 var troughDepth = 4 var slack = 0.3 fun glass() = Cube( glass ) fun side() : Shape3d { val profile = Square( extra*2, gap + glass.z*2 + slack*4 + extra*2 ) .center() .roundCorner(3,2,1) .roundCorner(0,2,1) val side = profile.extrude( glass.y + exit + 25 ) val pointed = Cube( side.size.x * 2, side.size.Z, side.size.z ).center().rotateX(45).topTo(side.top) val groove = Cube( extra * 2, glass.z + slack*2, side.size.z ) .backTo( -gap/2-slack ) .bottomTo( exit + troughDepth) val grooves = groove.mirrorY().also() val grometHole = Cylinder( 100, grometD/2 ).center().rotateY(90) .centerZTo(side.top - grometOffset ) return (side/pointed - grooves - grometHole ).color("Green") } @Piece fun printTop() = top().mirrorZ().bottomTo(0) fun top() : Shape3d { val flat = Square( glass.x - extra*2, gap + glass.z*2 + slack*4 + extra*2 ).center() .extrude( extra * 2 ) .color("LightGreen") val groove = Cube( flat.size.x * 2, glass.z + slack*2, extra * 2).centerXY() .frontTo(gap/2) val grooves = groove.mirrorY().also().topTo( extra ) val hole = Square( gap * 2, gap-4 ).roundAllCorners(4) .chamferedExtrude(flat.size.z+2, 0, -6) .center().bottomTo(-1) return flat - grooves - hole } fun base() : Shape3d { val profile = Square( glass.x + baseMargin*2, gap + glass.z*2 + baseMargin*2 ) .roundAllCorners( 12, 1 ) val base = profile.chamferedExtrude( 12, 0, 2 ) .centerXY() .color("DimGrey") val margin = 0 val troughP = Square( glass.x + margin*2, gap + glass.z*2 + slack*4 + extra*2 + margin*2) .roundAllCorners( 0, 1 ) .center() val trough = troughP.extrude( troughDepth ) .topTo( base.top ) return base - trough } fun roof() : Shape3d { val half = Cube( glass.x + roofMargin*2, 80, 12 ).centerX() .topTo(0) .rotateX(-45) .bottomTo(0) val mitred = half / Cube( half.size.x, half.size.y, half.size.z ).centerX().translateY(1) return mitred.mirrorY().also() } @Piece fun baseAndSides() : Shape3d { val base : Shape3d = base() val pane = Cube( glass ).centerX() .rotateX(90) .translateY(-gap/2) .bottomTo(exit+ base.top) .previewOnly() val panes = pane.mirrorY().also() val side : Shape3d = side() .rightTo( pane.left + extra ) .bottomTo(base.top - troughDepth) // A flying butress val buttresSize = 60 val buttress = (Square(buttresSize) - Circle(buttresSize).centerTo(buttresSize,buttresSize)) .extrude(1.5) .rotateX(90) .centerY() .leftTo(side.right) .bottomTo( side.bottom ) .mirrorX().also() // Force extra perimeters where the edge joins to the base, giving extra strength. val pins = Cube(0.1,4, 30).centerXY() .centerXTo(side.middle.x).frontTo(side.front+2) .mirrorY().also() .mirrorX().also() .bottomTo(0.4) return base + side.mirrorX().also() + buttress + panes - pins } var grometD = 10 var grometOffset = 30 @Piece fun eve() : Shape3d { val tri = Triangle( 60, 60 ).rotate(-45) - Circle( grometD/2 ).translateX(grometOffset) return tri.chamferedExtrude(3.0,0,1) .color("GhostWhite") } override fun build() : Shape3d { val base : Shape3d = base() val pane = Cube( glass ).centerX() .rotateX(90) .translateY(-gap/2) .bottomTo(exit+ base.top) .previewOnly() val panes = pane.mirrorY().also() val side : Shape3d = side().bottomTo(base.top - troughDepth) val sides = side.rightTo( pane.left + extra ).mirrorX().also() val top : Shape3d = top().bottomTo( pane.top - extra ) val eves = eve().rotateY(90).topTo( side.top ).leftTo(sides.right) .mirrorX().also() val roof : Shape3d = roof().topTo( eves.top+17) return base + sides + roof + top + eves + panes } }