Exit Full View
ZipUp

/Kitchen/CutleryDrainer.foocad

CutleryDrainer

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.

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

class CutleryDrainer : AbstractModel() {
    
    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() )

    @Piece( printable = false )
    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
    }
}