Exit Full View
Up

/Kitchen/ScrapsBin.foocad

ScrapsBin

A bin for food scraps to be composted similar in style to "CornerBin.foocad".

The cleat is glued onto the bin, and the other half is screwed to an outside wall by my back door. (So I can shove it outside when full if I don't want to head out to the compost heap). The "bumper" piece is screwed to the wall, and keeps the bin upright.

FooCAD Source Code
import uk.co.nickthecoder.foocad.screws.v3.*
import uk.co.nickthecoder.foocad.extras.v1.*
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 ScrapsBin : Model {

    var size = Vector3( 180, 100, 100 )
    var thickness = 1.8
    var radius = 12
    var slack = 0.5
    var lipSize = Vector2(4, 8)
    var lidThickness = 4.0
    var swingY = 22
    var chamfer = 2

    @Piece
    meth bin() : Shape3d {
        val shape = Square( size.x, size.y ).centerX().backTo(0)
            .roundAllCorners(radius)

        val r = chamfer
        val lipShape = PolygonBuilder().apply {
            moveTo(0,0)
            lineTo(lipSize.x, lipSize.y - chamfer)
            circularArcBy( Vector2( -r, r ), r, false, true )
        }.buildPath()

        val lip = ProfileEdge( lipShape ).reverse()

        val main = shape.cup( size.z, thickness )
            .insideBottom( Fillet( radius ) )
            .outsideBottom( Chamfer(2) )
            .insideTop( lip )
        
        val trim = trim().bottomTo( size.z - chamfer )

        val plainStop = Square(16, 5)
            .roundCorner(0,3)
            .extrude( lipSize.x * 3 )
        val shaveStop = Cube( 30 ).centerY()
            .rotateY(-45)
            .translateX(plainStop.right)

        val stop = (plainStop - shaveStop)
            .rotateY(90).backTo(0)
            .rotateX(-10)
            .leftTo( main.left )
            .translateY( -rotatePos() - lidThickness+0.75 )
            .translateZ( size.z - lidThickness )
        
        val stops = stop.mirrorX().also()

        val hinges = hingeHole().translateZ( size.z ).mirrorX().also()

        return main + trim - hinges + stops
    }

    @Piece
    meth lid() : Shape3d {
        val boxShape = Square( size.x, size.y ).centerX().backTo(0)
            .roundAllCorners(radius)

        val foo = lipSize.x+slack+thickness
        val innerR = radius - lipSize.x-slack/2 - thickness/2

        val handle = Square(size.x * 0.7, 10 ).center()
            .roundAllCorners(5)
            .centerYTo(boxShape.front)

        val shape = boxShape -
            Square( size.x * 2, swingY - lidThickness ).centerX().backTo( 1 ) +
            Square( size.x - foo*2, size.y/2 ).centerX().roundAllCorners(innerR).backTo(-foo) +
            handle

        val main = shape.smartExtrude( lidThickness )
            .bottom( Chamfer(1) )

        val angle = angle(true)

        val hinges = hingeHole().translateZ( lidThickness / 2 )
            .mirrorX().also()


        return main - angle - hinges
    }

    meth trim() : Shape3d {

        val binShape = Square( size.x, size.y/2 ).centerX().backTo(0)
            .roundAllCorners(radius)
        val inside = binShape.offset( -lipSize.x - thickness )
        val shape = binShape - inside

        val main = shape.smartExtrude( lidThickness + chamfer )
            .top( Chamfer(1) )

        return main - angle(false)
    }

    meth angle(forLid : bool) : Shape3d {

        val block = Cube( size.x + 2, size.y/2, 100 )
            .centerX().centerZ()

        val angle = if (forLid) {
            block.frontTo(0).rotateX(45) 
        } else {
            block.backTo(0).rotateX(-45) 
        }

        return if (forLid) {
            angle.leftTo( size.x/2 - lipSize.x - slack - thickness )
                .translateY( -swingY ).translateZ(lidThickness)
                .mirrorX().also()
        } else {
            angle.translateY( -swingY +slack )
        }
    }
    
    meth rotatePos() = swingY*0.70

    @Piece
    meth hingeHole() : Shape3d {

        var hingeSize = 2
        val exposedLength = 10
        val holeShape = Circle( hingeSize/2 ).hole()
        val length = lipSize.x*3 + exposedLength
        val full = holeShape.extrude( length )
        val exposed = holeShape.hull( holeShape.offset(1).translateX(lidThickness) )
            .extrude( exposedLength )
            .topTo( length )

        return (full + exposed)
            .rotateY(-90)
            .rightTo( size.x / 2 - thickness )
            .translateY( -rotatePos() )
            .color("Red")
    }

    var cleatSize = Vector2(6,6)


    @Piece
    meth cleat() : Shape3d {

        val length = size.x * 0.7
        val dist = 50
    
        val one = Parallelogram( cleatSize.y, cleatSize.x ).angle(-35)
            .roundCorner(3,0.5,1)
            .rotate(-90)

        val shape = one + Square( thickness, one.size.y + cleatSize.y*2 )
            .centerY()
            .rightTo( one.left )

        val strips = shape.extrude(length)

        return (strips).color("DarkGray")
    }

    @Piece
    meth wallCleat() : Shape3d {
        val main = cleat()
        val screwHole = Circle(5).smartExtrude(main.size.x).scaleTop(Vector2(2,1))
            .remove( Countersink().mirrorZ() )

        val screwHoles = screwHole.rotateY(-90)
            .translateY(-5)
            .leftTo(main.left)
            .centerZTo( main.size.z * 0.2 )
            .centerZTo( main.size.z * 0.8 ).also().withCavities()
            
        return main and screwHoles
    }

    @Piece
    meth bumper() : Shape3d {
        return Circle(10).smartExtrude(cleatSize.x + thickness*2)
                .top(Chamfer(1)) -
            Countersink().topTo(cleatSize.x)

    }

    override fun build() : Shape3d {
        val tilt = 100
        val bin = bin().color("Green")
        val lid = lid().color("Yellow")
            .mirrorZ().bottomTo(0)
            .translate(0,rotatePos(), -lidThickness/2).rotateX(-tilt).translate(0,-rotatePos(), lidThickness/2)
            .translateZ( size.z + 0.1 )

        val cleatBack = cleat().rotateY(-90).rotateX(-90)
            .centerX().centerZTo( size.z*0.75 + 5 ).translateY( thickness )

        val wallCleat = wallCleat().rotateY(-90).rotateX(90)
            .centerX().centerZTo( size.z*0.75  ).translateY( 8 )

        val bumper = bumper().color("Orange")
            .rotateX(90).frontTo(0)
            .translateZ(20)
    
        return bin + lid + cleatBack + wallCleat + bumper
    }
}