Exit Full View
Up

/Kitchen/CutleryDrainer.foocad

CutleryDrainer
FooCAD Source Code
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*

/*
NOTE. I have NOT tested this yet!

A reimplementation of the cutlery drainer that I first created using OpenSCAD.
If I were to do it from scratch, I would probably design the profiles in Inkscape.
But I've chosen to replicate the old profiles exactly.

You can print it in one piece (abcd) two pieces (ab and cd), or as four individual pieces.
I originally printed it in two pieces because my printer at the time wasn't big enough
to print it in one piece. However, I've grown to like it in two pieces.

If you want colourful... Why not print them separately in different colours, and then
glue them together if you want them joined.

*/
class CutleryDrainer : Model {
    

    var scale = 1.4
    var baseThickness = 3
    var thickness = 1.2

    var lipThickness = 2.5
    var lipHeight = 5

    var slack = 0.3

    fun back() = Square( 300 ).centerX()

    fun profileA() = Hull2d(
        Circle( 55/2 ).translate(-80,-25 ),
        Circle( 30/2 ).translate( -60, 10 )
    ).scale( scale ) - profileB() - back()

    fun profileB() = Hull2d(
        Circle( 55/2 ).translate( -40, -35 ),
        Circle( 50/2 ).translate( -35, 10 )
    ).scale( scale ) - profileC() - back()

    fun profileC() = Hull2d(
        Circle( 55/2 ).translate( 0, -40 ),
        Circle( 30/2 ).translate( 5, 10 )
    ).scale ( scale ) - back()

    fun profileD() = Hull2d(
        Circle( 55/2 ).translate( 50, -30 ),
        Circle( 20/2 ).translate( 10, -5 ),
        Circle( 30/2 ).translate( 40, -10 )
    ).scale( scale ) - profileC() - back()

    fun section( profile : Shape2d, height : int ) : Shape3d {

        val main = ExtrusionBuilder().apply {
            crossSection( profile )
            forward( height )
            crossSection()
            crossSection( -thickness )
            forward( -height )
            crossSection()
        }.buildClosed()

        val xRidges = Square( 2, main.size.y ).tileXWithin( main.size.x + 5, 3 )
            .leftTo(main.left).backTo(main.back)
        val yRidges = Square( main.size.x, 2 ).tileYWithin( main.size.y + 5, 5 )
            .leftTo(main.left).backTo(main.back)
        val ridges = (xRidges.intersection(profile))
            .extrude( baseThickness )
            .translateZ(baseThickness) +
            (yRidges.intersection(profile))
                .extrude( baseThickness )

        return main + ridges
    }


    fun lip( profile : Shape2d ) : Shape3d {
        return ExtrusionBuilder().apply {
            crossSection( profile.offset( -thickness -slack ) )
            forward( lipHeight )
            crossSection()
            crossSection( -lipThickness )
            forward( -lipHeight * 2 )
            crossSection()
            crossSection( 2 )
            forward( lipHeight )
            crossSection( lipThickness + thickness + slack - 2 )
        }.buildClosed().mirrorY()
    }

    var aHeight = 70
    var bHeight = 95
    var cHeight = 110
    var dHeight = 95

    @Piece
    fun a() = section( profileA(), aHeight )

    @Piece
    fun b() = section( profileB(), bHeight )

    @Piece
    fun c() = section( profileC(), cHeight )

    @Piece
    fun d() = section( profileD(), cHeight )

    @Piece
    fun ab() = section( profileA(), aHeight ) +
        section( profileB(), bHeight )

    @Piece
    fun cd() = section(  profileC(), cHeight ) +
        section( profileD(), dHeight )

    @Piece
    fun abcd() = section( profileA(), 70 ) +
            section( profileB(), 95) +
            section( profileC(), 110) +
            section( profileD(), 95)

    @Piece
    fun lipA() = lip( profileA() )

    @Piece
    fun lipB() = lip( profileB() )

    @Piece
    fun lipC() = lip( profileC() )

    @Piece
    fun lipD() = lip( profileD() )

    override fun build() : Shape3d {
        val a = section( profileA(), 70 ).color( "Red" )
        val b = section( profileB(), 95).color( "Orange" )
        val c = section( profileC(), 110).color( "Yellow" )
        val d =section( profileD(), 95).color( "Green" )

        val lipA = lip( profileA() ).rotateX(180).bottomTo(a.top).color( "Red" ).darker()
        val lipB = lip( profileB() ).rotateX(180).bottomTo(b.top).color( "Orange" ).darker()
        val lipC = lip( profileC() ).rotateX(180).bottomTo(c.top).color( "Yellow" ).darker()
        val lipD = lip( profileD() ).rotateX(180).bottomTo(d.top).color( "Green" ).darker()
        return a + b + c + d + lipA + lipB + lipC + lipD
    }
}