import uk.co.nickthecoder.foocad.compound.v1.* import static uk.co.nickthecoder.foocad.debug.v1.Debug.* import static uk.co.nickthecoder.foocad.extras.v1.Extras.* import uk.co.nickthecoder.foocad.cup.v1.* import static uk.co.nickthecoder.foocad.cup.v1.Cup.* import uk.co.nickthecoder.foocad.smartextrusion.v1.* import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* class BirdFeeder2 : ModelWithSetup { @Custom( about="Width of the tube" ) var diameter = 50 @Custom( about="The height of the tube." ) var height = 100 @Custom( about="The radius of the tube's corners" ) var radius = 10 @Custom( about="Size of the feeding hole" ) var holeDiameter = 20 var baseHeight = 20 var thickness = 1.0 var lipSize = Vector2( 1.5, 5 ) var clearance = 0.5 // Distance for pieces to easily slot together var interferanceFit = 0.2 // Distance for pieces to only just fit together. var perchDiameter = 4.75 var perchExtra = 30 var holeHeight = 15 var attachHeight = 6 var perchHeight = 0 var hangOffset = 20 // Distance from top to the holes for the wire hanger. var lidSize = Vector2( 8, 2) // Height and thickness of the lid override fun setup() { perchHeight = baseHeight / 2 } fun profile() = Square( diameter ).center() .roundAllCorners( radius ) fun hole() = Circle( holeDiameter/2 ) - Square( holeDiameter ).center().backTo( -holeDiameter * 0.4 ) fun lip() = fatLip( lipSize.y, lipSize.x ) fun perchShape() = Circle( perchDiameter / 2 ).sides(32) + Square( perchDiameter, perchDiameter / 2 ).centerX().backTo(0) fun holeAndReinforcement( shape : Shape2d, y : double, outside : bool ) : Shape3d { val hole = shape.offset( interferanceFit ) .extrude( y * 2 + 10 ) .rotateX(90) .centerY() val reinforcement = shape.offset( 4 ) .smartExtrude( lipSize.x ) .outsideTop( Chamfer( lipSize.x ) ) .rotateX(90) .backTo( if (outside) {-y } else y ) return reinforcement.mirrorY().also().remove( hole ) } // Print two. // Print with ears (or a brim) to prevent lifting off the bed. @Piece fun perch() = perchShape().extrude( diameter + perchExtra * 2 ) .rotateX(90) .bottomTo(0) .centerXY() .color("darkGreen") @Piece fun connector() = perchShape().extrude( diameter + 4 ) .rotateX(-90) .centerXY() .color("darkGreen") @Piece meth tubePrint() = tube().mirrorZ().rotateZ(90).bottomTo(0) @Piece( printable=false ) meth tube() : Shape3d { val tube = profile().outline( 0, thickness) .smartExtrude( height ) .insideTop( lip() ) //.outsideTop( lip() ) .outsideBottom( lip() ) // Allow the base to fit inside and be printable without supports. .insideBottom( Chamfer( thickness + lipSize.x ) ) val feedingHole = holeAndReinforcement( hole(), diameter/2, true ) .translateZ( holeHeight + holeDiameter/2 ) val attachment = holeAndReinforcement( perchShape().offset(0.2), diameter/2, true ) .centerZTo( attachHeight ) .rotateZ(90) val hanger = holeAndReinforcement( Circle(2).sides(32), diameter/2, true ) .translateZ( tube.top - hangOffset ) .rotateZ(90) return Compound(true).apply { + tube + attachment + feedingHole + hanger }.build().color("WhiteSmoke") } @Piece fun basePrint() = base().mirrorZ().bottomTo(0) @Piece( printable = false ) fun base() : Shape3d { val profile = profile().offset( lipSize.x ) val ring = profile.outline( 0, thickness) val lip = lip() val base = ring.smartExtrude( baseHeight ) .insideTop( lip ) .insideBottom( lip ) val insideChamfer = thickness + lipSize.x + clearance val inside = Cup( profile.offset(-insideChamfer), holeHeight - 2, thickness ) .outsideTop( Chamfer( -insideChamfer, insideChamfer ) ) .mirrorZ() .bottomTo( base.top ) val attachment = holeAndReinforcement( perchShape(), base.right -insideChamfer - thickness, false ) .translateZ( base.top + attachHeight ) .rotateZ(90) val perchHole = holeAndReinforcement( perchShape(), base.size.y/2, true ) .translateZ( base.top - perchHeight ) return Compound(true).apply { + base + inside + perchHole + attachment }.build().color("darkGreen") } @Piece fun insert() : Shape3d { val floorShape = profile().offset(-thickness-clearance) val floor = floorShape.extrude(thickness) val size = floor.size.x val archShape = Circle( holeDiameter/2 ) .frontTo( 2 ) hull Square( holeDiameter, 1 ).centerX() hull Square( 1 ).centerX() .backTo( holeDiameter * 1.2 ) val lipSize = 3 val archThickness = 1.2 val arch = archShape.outline(archThickness, 0) .smartExtrude( floor.size.y ) .outside( fatLip(2.4,2) ) .rotateX(90).centerY() .bottomTo(-lipSize-archThickness/2) val ledge = Cube( floorShape.right - archShape.right, size/2, 7 ) .leftTo( archShape.right ) //.centerY() .rotateX(25) .mirrorZ().translateZ( 7 ) .mirrorX().also() .mirrorY().also() val slope = PolygonBuilder().apply { moveTo( 0,0 ) lineTo( size, 0 ) lineTo( size, 10 ) lineTo( size * 0.7, thickness ) lineTo( size * 0.3, thickness ) lineTo( 0, 10 ) }.build() .extrude( size ) .rotateX(90) .centerXY() val insertHoleSize = Vector2( 10, 12 ) val hole = Cube( diameter, insertHoleSize.x, insertHoleSize.y ) .center() .frontTo( -size/2 + 3 ) .bottomTo( thickness ) val holes = hole.mirrorY().also() val dividerChamfer = 4 val divider = archShape .cup( thickness/2 + dividerChamfer, 0 ) .baseThickness(thickness/2) .insideBottom( Chamfer(dividerChamfer) ) .rotateX(90) .frontTo( hole.back ) .mirrorY().also() .bottomTo(0) val envelope = floorShape.extrude( arch.size.z ) return (floor + divider + arch + ledge - holes + slope) .intersection( envelope ) //.color( "darkGreen" ) } @Piece fun lidPrint() = lid().mirrorZ().bottomTo(0) @Piece( printable=false ) fun lid() : Shape3d { val profile = profile().offset( lidSize.y + clearance ) val lid = profile.cup( lidSize.x, lidSize.y ) .outsideBottom( Chamfer( lidSize.y - 1 ) ) .outsideTop( Chamfer( 0.6 ) ) return lid.color( "darkGreen" ) } @Piece fun notTube() : Shape3d { return basePrint().leftTo(1).frontTo(1) + insert().leftTo(1).backTo(-1) + lid().rightTo(-1) } @Piece( printable = false ) override fun build() = Compound().apply { val base = base() val insert = insert().bottomTo( base.top +0.5 ) val tube = tube().bottomTo( baseHeight + clearance ) val perch = perch() val lid = lid().mirrorZ().topTo( tube.top + lidSize.y + clearance ) + tube + base + lid + insert //+ perch.rotateZ(90).centerZTo( tube.bottom + attachHeight ) + perch.centerZTo( perchHeight ) }.build() }