Exit Full View
ZipUp

/GardenFurniture/BikeShed.foocad

BikeShed

Rather than moving the bike into the shed, move the whole shed! It runs on a pair of wheels. Lift the shed slightly from the end, wheel it forward, put the bike in place, and wheel the shed back again.

Note to scale - I used random values for size.

The sides will be lined with material (same stuff cheap tents are made from). The roof will be a piece of thin ply, with wooden batterns for strength, covered in roofing felt.

FooCAD Source Code
import uk.co.nickthecoder.foocad.screws.v3.*
import uk.co.nickthecoder.foocad.compound.v1.*
import uk.co.nickthecoder.foocad.threaded.v2.*
import uk.co.nickthecoder.foocad.smartextrusion.v1.*
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*
import static uk.co.nickthecoder.foocad.along.v3.Along.*
import uk.co.nickthecoder.foocad.woodworking.v1.*
import static uk.co.nickthecoder.foocad.woodworking.v1.Woodworking.*

class BikeShed : Model {
    
    var size = Vector3( 1800, 600, 1100 )
    var extraHeight = 150
    var wheelSize = Vector2( 30, 50 )
    var wheelThreadDiameter = 30
    var tyreThickness = 5
    var wheelFlangeSize = Vector2( 4, 6 )

    var main = Wood( "main", 38, 22 ).color( "Green" )
    var half = Wood( "half", 38, 22 ).color( "Orange" )

    fun angle() = Math.tan( extraHeight / size.y )

    fun back() : Shape3d {

        val extra = main.thickness * Math.sin( angle() )
        val length = size.z + extraHeight - main.width * 2 + extra
        val center = main.cut(length)        
            .label( "BackCenter" )
            .centerX()
            .backTo( size.y/2 )
            .bottomTo( main.width )

        val left = center       
            .leftTo( -size.x / 2 )

        val bottom = main.cut( size.x )
            .label( "BackBottom" )
            .edgeDownAlongX()
            .leftTo( left.right )
            .backTo(left.back)
            .centerX().darker()

        // Top will need to be angled (planing/cutting along the grain).
        val topAndBottom = bottom
            .bottomTo( center.top ).also()

        return center +
            left.mirrorX().also() +
            topAndBottom
    }

    fun front() : Shape3d {
        val center = main.cut(size.z - main.width * 2)        
            .label( "FrontCenter" )
            .centerX()
            .frontTo( -size.y / 2 )
            .bottomTo( main.width )

        val left = center
            .leftTo( -size.x / 2 )

        val bottom = main.cut( size.x )
            .label( "FrontBottom" )
            .edgeDownAlongX()        
            .leftTo( left.right )
            .backTo( left.back )
            .centerX().darker()

        return center +
            left.mirrorX().also() +
            // Top will need to be angled (planing/cutting along the grain).
            bottom.topTo( size.z ).also()
    }

    fun side( open : bool ) : Shape3d {
        val height = if (open) 100 else size.z
        val offsetZ = if (open) size.z - height else 0.0

        val angle = angle()
        val angleDegrees = angle * 180 / Math.PI

        val front = main.cut( height )
            .label( "SideFront" )
            .rotateZ(90)
            .frontTo( -size.y/2 + main.thickness )
            .rightTo( size.x / 2  )
            .translateZ( offsetZ )
            .darker()

        val back = main.cut( height + extraHeight - main.width )
            .label( "SideBack" )
            .rotateZ(90)
            .backTo( size.y/2 - main.thickness )
            .rightTo( front.right )
            .translateZ( offsetZ )
            .darker()

        val bottom = main.cut( size.y - main.width * 2 - main.thickness * 2 )
            .label( "SideBottom" )
            .edgeDownAlongY()
            .rightTo( front.right )
            .centerY()
            .translateZ( offsetZ )

        val topExtra = main.thickness * Math.sin( angle )
        // Will need trimming to size
        val top = main.cut( extraHeight/Math.asin(angle) + topExtra)
            .label( "SideTop" )
            .edgeDownAlongY()
            .centerY().translateY(topExtra/2)
            .rotateX(angleDegrees)
            .translateZ( (back.top + front.top) / 2 - main.width/2 )
            .rightTo( front.right )

        val across = bottom.translateZ( size.z / 3 )
            .topTo( back.top - size.z/3 ).also()

        return Compound().apply {
            + front
            + back
            + top
            + bottom
            if (! open ) {
                + across
            }
        }.build()
    }

    fun rail() : Shape3d {
        return half.cut( size.x - 20 - main.thickness )
            .label( "Rail" )
            .edgeDownAlongX()
            .leftTo( -size.x / 2 )
            .backTo( size.y / 2 - main.thickness - wheelFlangeSize.x - 3 )

    }
    fun stop() : Shape3d {
        return half.cut( size.y - 2*(main.thickness*2 + wheelFlangeSize.x + 3) )
            .label( "Stop" )
            .edgeDownAlongY()
            .centerY()
            .rightTo( size.x / 2 - main.thickness - 20 )
    }

    fun wheelThread() = Thread( wheelThreadDiameter )
        .rodChamfer(1)

    @Piece
    fun wheel() : Shape3d {
        val flange = Circle( wheelSize.y / 2 + wheelFlangeSize.y )
            .smartExtrude( wheelFlangeSize.x )
            .chamfer( 1 )
        val hub = Circle(  wheelSize.y / 2 - tyreThickness )
            .smartExtrude( wheelSize.x )
            .top( Chamfer(1) )
            .bottomTo( flange.top )

        val bearingHole = Cylinder( 8, 22/2 )
            .translateZ(-0.01)

        val threadedHole = wheelThread().threadedHole( wheelSize.x/2 + 4 )
            .clipped(true)        
            .topTo( hub.top + 1 )

        val shaftHole = Cylinder( 50, 8/2 + 1 )
            .bottomTo( bearingHole.top + 1 )

        return flange + hub - shaftHole - bearingHole - threadedHole
    }

    @Piece
    fun wheelCover() : Shape3d {
        val flange = Circle( wheelSize.y / 2 + wheelFlangeSize.y )
            .smartExtrude( wheelFlangeSize.x )
            .chamfer( 1 )

        val thread = wheelThread()
            .threadedRod( wheelSize.x / 2 )
            .chamferBottom(false)
            .bottomTo( flange.top-0.5 )

        val hole = Cylinder( wheelSize.x, wheelThread().coreRadius() - 2 )
            .bottomTo( flange.top )

        return flange + thread - hole
    }

    @Piece
    fun tyre() : Shape3d {
        return (Circle( wheelSize.y / 2 ) - Circle( wheelSize.y / 2 - tyreThickness ))
            .smartExtrude( wheelSize.x - 1 )
            //.outsideTop( Fillet(3) )
            .color( "DimGrey" )
    }

    @Piece( printable = false )
    fun wheelAndTyre() = wheel() +
        tyre().translateZ(wheelFlangeSize.x) +
        wheelCover().rotateX(180).topTo( wheelSize.x + wheelFlangeSize.y )
            .rotateZ(190)

    @Piece
    fun foot() : Shape3d {
         val main = Square( main.thickness, 60 )
            .center()
            .roundAllCorners(2)
            .smartExtrude( 7 ) // How much do we want the shed to be lifter up by?
            .top( Chamfer( 2 ) )

        val screwHoles = Countersink()
            .topTo(main.top)
            .centerYTo( main.front * 2/3 )
            .mirrorY().also()
            
        return main - screwHoles
    }

    @Piece( about="TPU at the end of the rails" )
    fun endStop2() : Shape3d {
        return Square( main.width, main.thickness )
            .roundAllCorners(3)
            .smartExtrude( 2 )
            .top( Chamfer( 1 ) )
    }

    @Piece( printable = false )
    override fun build() : Shape3d {

        val foot = foot()
            .mirrorZ()
            .rightTo( size.x / 2 )
            .frontTo( -size.y / 2 )
            .topTo(0)
            //.translateY(150).also()
            .mirrorY().also()

        val rail = rail()
            .translateZ(-foot.size.z)

        val stop = stop()

        val wheel = wheelAndTyre().rotateX(90)
            .backTo( rail.back + wheelFlangeSize.x + 2 )
            .bottomTo( rail.top - wheelFlangeSize.y )
            .leftTo( -size.x / 2 + 30 )

        return Compound().apply {
            + back()
            + front()
            + side(false)
            + side(true).leftTo(-size.x/2)
            + rail.mirrorY().also()
            + stop
            + wheel.mirrorY().also()
            + foot
        }.build()

    }
}