Exit Full View
Up

/Mum/HangingDrawer.foocad

HangingDrawer
FooCAD Source Code
import static uk.co.nickthecoder.foocad.ears.v1.Ears.*
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.*

/**
    A shallow drawer for the underside of an over-bed table.
    It is very shallow, so that no "leg room" is lost.
    (The height is very nearly the same as the table's metalwork).

    The table is 770x400, so the maximum length (y) is about (400-30)/2  = 185

    The position of the runners is vital, so I've made the holes slots to allow for some adjustment.
    Attach them to the table using round head screws and washers.
    Pre-drill the holes with a depth stop on the drill bit.

    There are no handles/knobs. Just slide the drawer by drawwing its base.

Print Notes
    2 Perimeters
    3 top and bottom layers
    Low infill (10%)

    I used 3DQF's beige for the runners, and will use a variety of colours for the drawers
    Transluscent filament gives a nice effect if the wall thickness > 2 * perimeters (due to the infill)
    (Monochrome is so dull ;-)

*/
class HangingDrawer : Model {
    

    @Custom
    var size = Vector3( 125, 170, 30 )

    @Custom
    var runnerSize = 6

    @Custom
    var radius = 8
    @Custom
    var chamfer = 3

    @Custom
    var glueWidth=5

    @Custom
    var text = Text("Lilian", BOLD, 40)

    @Custom
    var slack = 1

    @Custom
    var thickness = 3

    @Custom
    var clearance = 1

    @Custom
    var earSize = Vector2(45,4)


    fun drawer() : Shape3d {

        val lip = 1
        val lip2 = lip * Math.sqrt(2)

        val base = Square( size.x, size.y ).center().offset(-chamfer).roundAllCorners(radius)
        val mid = base.offset(chamfer)
        val inside = mid.offset(-thickness)
        val top = Square( size.x + runnerSize*2 - lip*2, size.y ).center().roundAllCorners(radius)
        val drawer = ExtrusionBuilder().apply {
            crossSection( base )
            forward(chamfer)
            crossSection( mid )
            forward( size.z -chamfer - runnerSize )
            crossSection()

            forward( runnerSize - lip )
            crossSection(top)
            forward(lip)
            crossSection()

            crossSection( -thickness )

            forward( -runnerSize + lip/Math.sqrt(2) )
            crossSection( inside )
            forward( -size.z + chamfer*2 + runnerSize - lip/Math.sqrt(2) )           
            crossSection()
            forward(-chamfer)
            crossSection(-chamfer)
        }.build()

        val text = this.text
            .mirrorX()
            .rotate(90)
            .extrude(0.6)
            .centerXTo( drawer.middle.x ).centerYTo(drawer.middle.y)

       return (drawer - text).margin(-runnerSize,0,0)
    }

    var lidThickness = 2.0

    fun lid() : Shape3d {
        val lip = 1
        val top    = Square( size.x + runnerSize*2 - lip*2 - thickness*2 - 2-0.4, size.y - thickness * 2 - 0.2 )
            .center().roundAllCorners(radius - thickness - 0.1)
        val bottom = Square( size.x + runnerSize*2 - lip*2 - thickness*2 - 0.4 - lidThickness*2, size.y - thickness * 2 - 0.2 )
            .center().roundAllCorners(radius)
        return ExtrusionBuilder().apply {
            crossSection( top )
            forward(1)
            crossSection()
            forward( lidThickness -1 )
            crossSection( bottom )
        }.build().color( "Purple" )
    }

    fun holes() : Shape3d {
        val profile = Circle( 2 ).translateX(1) hull Circle( 2 ).translateX(-1)
        val slot = profile.extrude(100)
        return slot.spreadY( 2, size.y-20 )
            .centerY()
            .color("Red")
    }

    fun runner() : Shape3d {
        val profile = PolygonBuilder().apply {
            moveTo(0,0)
            lineBy( glueWidth/2 + runnerSize, 0 )
            lineBy( -runnerSize, runnerSize )
            lineBy( 0, clearance )
            lineBy( -glueWidth - runnerSize/2, 0 )
            lineBy( 0, -runnerSize - clearance )
        }.build().roundCorner(1,0.5,1)

        val main = profile.chamferedExtrude(size.y,0,1).rotateX(90).centerY()

        return main - holes()
    }

    fun doubleRunner() : Shape3d {
        val profile = PolygonBuilder().apply {
            moveTo(0,0)
            lineBy( glueWidth/2 + runnerSize, 0 )
            lineBy( -runnerSize, runnerSize )
            lineBy( 0, clearance )
            lineBy( -glueWidth, 0 )
            lineBy( 0, -clearance )
            lineBy( -runnerSize, -runnerSize )
        }.build().roundCorners(listOf<int>(6,1),0.5,1)

        val main = profile.chamferedExtrude(size.y,1).rotateX(90).centerY()

        return main - holes()
    }


    fun withEars( shape : Shape3d ) = shape +
        shape.ears( earSize.x/2 ).ribs(1.2,earSize.y).ribsMargin(2)

    @Piece
    fun runnerWithEars() = withEars(runner())

    @Piece
    fun doubleRunnerWithEars() = withEars(doubleRunner())

    @Piece
    fun drawerWithEars() = withEars(drawer())

    @Piece
    fun lidWithEars() = withEars(lid())

    @Piece
    fun testLidCorner() = lid().toOrigin().intersection( Cube( 30 ) )

    override fun build() : Shape3d {
        val drawer = drawer()
        val runner = runner()
            .translateX( -size.x/2 - runnerSize - 1 - glueWidth/2)
            .topTo( drawer.top )
        val doubleRunner = doubleRunner()
            .translateX( size.x/2 + runnerSize + 1 + glueWidth/2 )
            .topTo( drawer.top)

        val lid = lid()
            .mirrorZ().topTo( drawer.top )
            //.previewOnly()

        return drawer + (runner + doubleRunner).color("Green") + lid
    }
}