Exit Full View
Up

/Garden/FatBallShelter.foocad

FatBallShelter

Put a roof over a fat ball (bird food).

Print Notes

Use a brim, to prevent lifting - there is very little contact with the bed!

FooCAD Source Code
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
import static uk.co.nickthecoder.foocad.pathextrude.v1.PathExtrude.*

class FatBallShelter : Model {
    
    var diameter = 100

    var thickness = 3.0

    @Custom( about="Length the handle sticks out the bottom os the brolly. Can be negative." )
    var handleL = 2

    fun path( diameter : double, height : double ) = PolygonBuilder().apply {
        moveTo( diameter/2, 0 )            
            bezierBy(
                Vector2( -diameter*0.1, height*0.5 ),
                Vector2( -diameter*0.25, 0 ),
                Vector2( -diameter/2, height )
            )
    }.buildPath()

    fun umbrella() : Shape3d {

        val profile = Circle( diameter/2 ).sides( 6 ).roundAllCorners(3)
        val outsidePath = path( diameter, diameter* 0.3 )
        val insidePath = path( diameter-thickness, diameter*0.3-thickness )

        val umbrella = profile.extrudePathScaled( outsidePath ) -
            profile.offset(-thickness).extrudePathScaled( insidePath )


        val handleProfile = Circle( 2.5 )
        val handleD = 12

        val handlePath = PolygonBuilder().apply {
            moveTo( 0, 0 )
            // length of the umbrella's rod
            lineBy( 0, -umbrella.size.z - handleL )
            // Make a hook shape at the end or the rod
            bezierBy(
                Vector2( 0, -handleD*0.4 ),
                Vector2( 0, -handleD*0.5 ),
                Vector2( handleD*0.5, -handleD)
            )
            bezierBy(
                Vector2( 0, -handleD*0.7 ),
                Vector2( handleD*0.2, handleD*0.9 ),
                Vector2( -handleD, handleD*0.2 ) 
            )

        }.buildPath().toPath3d()

        val handle = ExtrusionBuilder.followPath( handlePath, handleProfile )
            .rotateX(90)
            .rotateZ(90)
            .topTo(umbrella.top-thickness/2)

        val hoop = (Circle(7)-Circle(4)).chamferedExtrude(4,0.8)
            .rotateY(90)
            .center()
            .bottomTo(umbrella.top-2)

        return umbrella + handle + hoop
    }

    @Piece
    fun half() : Shape3d {
        val umbrella : Shape3d = umbrella()
        val half = umbrella / Cube( umbrella.size*2 ).centerY().centerZ()
        return half.rotateY(-90)
    }

    @Piece
    fun otherHalf() = half().mirrorX()

    @Piece
    fun ring80() = basketRing( 70 )
    @Piece
    fun ring60() = basketRing( 60 )
    @Piece
    fun ring50() = basketRing( 50 )

    fun basketRing(d : double) : Shape3d {
        val width = 4
        val profile = Circle( d/2 + width/2 ) - Circle( d/2 - width/2 )
        val extra = Circle(5).translateX(d/2).repeatAround( 10 )
        val holes = Circle(2).translateX(d/2).repeatAround( 10 )
        val main = (profile + extra - holes).extrude(2)

        return main
    }

    override fun build() : Shape3d {

        val umbrella : Shape3d = umbrella()
        val largeRing = ring80().topTo( umbrella.bottom - 10 )


        val fatBall = Sphere( 55/2 ).previewOnly().topTo(largeRing.bottom)
        val midRing = ring60().topTo( fatBall.bottom+5 )
        val smallRing = ring50().topTo( fatBall.bottom-5 )

        return umbrella + fatBall + largeRing + midRing +smallRing
    }
}