Exit Full View
ZipUp

/Garden/CaneTop.foocad

CaneTop

Place on the top of a cane to prevent eye damage if someone trips and fall onto it. This is often done with corks, cans and other upcycled items.

I wanted something that looks nicer, and also supplies a perch for birds (instead of on my chairs!!)

For fun, I've included a mini tray, which can be placed on top of roundPerch to add a few seeds/peanuts.

FooCAD Source Code
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 CaneTop : Model {

    @Custom
    var holeDiameter = 7

    @Custom
    var length = 40

    @Custom
    var thickness = 3.5

    @Custom
    var perchSize = Vector2( 100, 8 )

    @Custom
    var ribSize = Vector2( 2, 1.2 )

    @Custom
    var flatDiameter = 40

    
    @Piece
    meth plain() : Shape3d {

        val chamfer = thickness / 4

        val inside = Circle( holeDiameter/2 )
        val main = inside.offset( thickness )
            .cup( length, thickness )
            .cavity(true)
            .bottom( Chamfer( thickness / 2 ) )
            .top( Chamfer( chamfer ) )
            .mirrorZ()
            .bottomTo(0)

        val ribs = Square( ribSize.x + chamfer, ribSize.y ).centerY()
            .rightTo( holeDiameter/2 + chamfer )
            .extrude( length - thickness )
            .repeatAroundZ(5)
            .color("Purple")

        val ribCone = Cylinder( length - thickness, holeDiameter/2 + chamfer, holeDiameter/2 - ribSize.x )
            .bottomTo( -0.01 )

        return main insert (ribs remove ribCone)
    }

    @Piece
    meth simplePerch() : Shape3d {

        val plain = plain()

        val perch = Circle( perchSize.y / 2 )
            .safeOverhang().rotate(90)
            .smartExtrude( perchSize.x )
                .edges( Fillet(perchSize.y/3) )
            .rotateY(90).centerX()
            .topTo(plain.top)

        return (perch and plain).mirrorZ().bottomTo(0)
    }

    @Piece
    meth roundPerch() : Shape3d {

        val plain = plain()

        val perch = Circle( perchSize.y / 2 )
            .safeOverhang()
            .translateX( perchSize.x/2 )
            .revolve()
            .topTo(plain.top)

        val chamfer = Chamfer( perchSize.y/8 )
        val spokes = Square( perchSize.x / 2, perchSize.y * 0.7 ).centerY()
            .smartExtrude( perchSize.y * 0.9 )
            .edges( chamfer )
            .topTo(plain.top)
            .repeatAroundZ(3)

        val flat = Circle( flatDiameter/2 )
            .cup( spokes.size.z - chamfer.height, 2 )
                .bottom( chamfer )
            .mirrorZ().topTo( spokes.top )

        return (perch and spokes and flat and plain).mirrorZ().bottomTo(0)
    }

    @Piece
    meth tray() : Shape3d {
        val radius = flatDiameter/2 + 0.2
        val cup = Circle( radius + 3 ).cup( 20, 3 )
            .baseThickness(10)
            .top( Fillet( 1.5 ) )
            .insideBottom( Fillet(4) )
        val bottomShape = Circle( radius )
        val spokesShape = Square( perchSize.x / 2, perchSize.y * 0.7 + 0.4 ).centerY()
            .repeatAround(3)
        val remove = (bottomShape + spokesShape).extrude( 10 - 2 ).bottomTo(-0.01)

        return cup - remove
    }

    @Piece( print="roundPerch" )
    override fun build() : Shape3d {
        val perch = roundPerch().mirrorZ()
        val tray = tray()

        return perch + tray.previewOnly()
    }

}