Exit Full View
Up

/Tools/DrawerSlide.foocad

DrawerSlide
FooCAD Source Code
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*
import static uk.co.nickthecoder.foocad.screws.v2.Screws.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*

class DrawerSlide : Model {
    
    @Custom( about="Length when closed" )
    var length = 310

    // Large values will make the slide wobbly and weak, but will allow the drawer to open even more
    // than 100%. 
    // negative values will prevent the drawer opening all the way, but will be stronger.
    @Custom( about="Additional length when open")
    var extra = 10

    // Determines the angle of the dovetail.
    var dovetailRatio = 0.4

    @Custom( about="Additional space between the parts. Fine tune this for your printer" )
    var slack = 0.2 // Was 0.18

    @Custom( about="Extra thickness of the inner bar, so that the draw doesn't rub on the sliders" )
    var raised = 1.2

    // A small chamfer to ensure that the internal corner of the dovetails do not bind
    // Should be AT LEAST the slicer's layer height
    var chamfer = 0.6 // Was 0.4

    @Custom( about="Size of the inner rod" )
    var inner = Vector2(14,4)

    @Custom( about="Size of the middle rod. Both dimensions must be bigger than [inner]" )
    var middle = Vector2(24,7)

    @Custom( about="Size of the outer rod. Both dimension must be bigger than [middle]" )
    var outer = Vector2(32,10)

    @Custom( about="Number of mounting holes for the inner rod" )
    var holeCount = 4

    @Custom( about="Number of mounting tabs of each side of the outer rod" )
    var tabCount = 3

    @Custom( about="Head diameter and shaft diameter of the screws for the inner rod" )
    var screwSize = Vector2(8,4)

    var tabSize = Vector2( 10, 10 )

    fun stopSize() = length/4


    fun dovetail(width : double, thickness : double, addChamfer : bool ) : Shape2d {
        val dovetail = PolygonBuilder().apply {
            moveTo( 0,0 )
            lineBy( width, 0 )
            lineBy( -thickness * dovetailRatio, thickness )
            lineBy( -width + 2 * thickness * dovetailRatio, 0 )
        }.build().centerX()
        return if ( addChamfer) {
            dovetail.roundCorner(1,chamfer,1).roundCorner(0,chamfer,1)
        } else {
            dovetail
        }
    }
    fun fatDovetail(width : double, thickness : double, addChamfer : bool ) : Shape2d {
        return dovetail(width, thickness, addChamfer) +
            Square(width-thickness*dovetailRatio, thickness/2).centerX().backTo(thickness)
    }

    fun extrude( shape : Shape2d, length : double, chamfer : double ) = shape.chamferedExtrude( length, chamfer ).rotateX(90)
    //fun extrude( shape : Shape2d, length : double ) : Shape3d = extrude( shape, length, 0 )

    fun holes( isInner : bool ) : Shape3d {
        val hole = if (isInner) {
            Countersink().holeD(screwSize.y).headD(screwSize.x).mirrorZ()
        } else {
            Cylinder.hole(middle.y*2, screwSize.x/2+1 ).bottomTo(-1)
        }
        return hole.repeatY(holeCount, (length - 20)/(holeCount-1)).centerY()
    }

    @Piece
    fun inner() : Shape3d {
        val dovetail : Shape2d =
            dovetail( inner.x, inner.y, true ) +
            Square( inner.x - inner.y * 2 * dovetailRatio, raised ).frontTo(inner.y).centerX()

        val stop = fatDovetail( inner.x, inner.y, true ) +
            Square( inner.x - inner.y * dovetailRatio, raised ).frontTo(inner.y).centerX()

        return ( extrude(dovetail, length, 1) + extrude( stop, stopSize(), 1 ) ).centerXY() - holes(true)
    }

    @Piece
    fun middle() :Shape3d {
        val dovetail : Shape2d = dovetail( middle.x, middle.y, true )
        val innerDovetail = dovetail( inner.x, inner.y, false ).backTo(middle.y).offset(slack)
        val fatInner = fatDovetail( inner.x, inner.y, false ).backTo(middle.y).offset(slack)
        val stop = fatDovetail( middle.x, middle.y, true ) //- fatInner
        

        return (
                extrude( dovetail,length, 1 ) +
                extrude( stop, stopSize(), 1 ) -
                extrude( innerDovetail, length, -1 ) -
                extrude( fatInner, length/2+stopSize()+extra/2, 0 )
            ).centerXY() - holes(false)
    }

    @Piece
    fun outer() : Shape3d {
        val dovetail : Shape2d = dovetail( outer.x, outer.y, false )

        val middleDovetail = dovetail( middle.x, middle.y, false ).backTo(outer.y).offset(slack)
        val fatMiddle = fatDovetail( middle.x, middle.y, false ).backTo(outer.y).offset(slack)

        val tabs = ( Square( tabSize ).roundAllCorners(2).center() - Circle.hole(screwSize.y/2) )
            .leftTo( outer.x/2 -2)
            .repeatY(tabCount, length/tabCount*1.3).centerY()
            .mirrorX().also().extrude( 4 )

        return (
                extrude(dovetail, length, 1 ) -
                extrude( middleDovetail, length, -1 ) -
                extrude( fatMiddle, length/2+stopSize()+extra/2, 0 )
            ).centerXY() +
            tabs - holes(false)
    }

    @Piece
    fun outerB() : Shape3d {
        val dovetail : Shape2d = dovetail( outer.x, outer.y, false )
        val hole = Countersink().depth(5)
        val holes = hole.rotateY(90).leftTo(dovetail.left).translateZ( 15 )
            .repeatY( tabCount, (length-20)/(tabCount-1) ).mirrorY().translateY(-10)
        val attachment = extrude( Square( 5, 20 ).leftTo( dovetail.left ), length, 1 ) -
            holes

        val middleDovetail = dovetail( middle.x, middle.y, false ).backTo(outer.y).offset(slack)
        val fatMiddle = fatDovetail( middle.x, middle.y, false ).backTo(outer.y).offset(slack)

        return ( extrude(dovetail, length, 1) + attachment -
            extrude( middleDovetail, length, -1 ) -
            extrude( fatMiddle, length/2+stopSize()+extra/2, 0 ) -
            holes(false)
      ).centerXY()
    }

    @Piece
    fun all() : Shape3d {
        val inner : Shape3d = inner()
        val middle : Shape3d = middle()
        val outer : Shape3d = outer()

        return inner.rightTo(middle.left -1) + middle + outer.leftTo(middle.right+1)
    }

    override fun build() : Shape3d {
        return inner().topTo(outer.y+raised).color("Yellow") +
            middle().translateY(length/2).topTo(outer.y).color("Orange") +
            outerB().translateY(length).bottomTo(0).color("Green")
    }
}