Exit Full View
Up

/Boxes/PinBox.foocad

PinBox

A box, which slides open, with catches at the sides to prevent it opening by accident.

Includes a slope to help get pins out by dragging them up the slope.

FooCAD Source Code
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*

class PinBox : Model {
    
    // The -0.8 and -1.6 are bodges to let me change the thickness of the
    // outside without re-printing the inside.
    @Custom
    var width = 50 - 0.8 + 1/2

    @Custom
    var depth = 70 - 1.6 + 1

    @Custom
    var height = 20 - 1.6 + 1
    
    @Custom
    var innerThickness = 1.6

    @Custom
    var outerThickness = 0.8

    @Custom
    var text = ""

    @Custom
    var patternDepth = 0.3

    @Custom
    var frontText = "↑ PINS ↑"

    @Custom
    var slope = true

    var slack = 1.5
    var gap = 0.5
    var chamfer = 1
    var thumbR = 10


    fun thumb() : Shape2d {
        return Circle( thumbR ) / Square( thumbR*3 ).centerY()
    }

    fun clip() = clip( 10, 2, 10, width*0.5, 1, innerThickness )

    fun clip( clipWidth : double, clipThickness : double, clipHeight : double, span : double, gap : double, thickness : double ) : Shape3d {
        val clipP = PolygonBuilder().apply {
            moveTo(0,0)
            lineTo(clipWidth,0)
            lineTo(clipWidth,clipThickness)
            lineTo(clipWidth-clipThickness, clipThickness)
        }.build()
        val clip = clipP.extrude(clipHeight) - Cube( clipP.size.x ).rotateX(-45)

        val clipGapP = Square( span, gap ).rightTo(gap)
                .translateY(clipHeight+gap).also() +
            Square( gap, clipHeight+gap-0.6 ).translateY(gap+0.6)
        val clipGaps = clipGapP.extrude( thickness+0.01 )
            .rotateX(90).centerZ()//.translateX( -clipWidth-gap )

        return clip.centerZ().rightToOrigin().color("Blue")
            .remove( clipGaps.color("Red") )
    }

    @Piece
    fun inside() : Shape3d {

        val h = height- outerThickness*2-slack
        val w = width - outerThickness  -slack/2
        val d = depth - outerThickness*2-slack

        val profile = Square( w, d )
            .roundAllCorners(2)
            .center()

        val inside = ExtrusionBuilder().apply {
            crossSection( profile.offset(-chamfer) )
            forward( chamfer )
            crossSection( profile )
            forward( h-chamfer )
            crossSection()
            crossSection( -innerThickness )
            forward( -h + innerThickness )
            crossSection()
            
        }.build().center().color("Yellow")
        val thumb : Shape3d = thumb().chamferedExtrude( h + slack, 0, chamfer ).center()
            .translateZ(innerThickness)
            .mirrorX().rightTo( w/2 )

        val insideHeight = h - innerThickness
        val curve1 :Shape3d =
            (
                    Square( insideHeight ) -
                    Circle( insideHeight )
            ).extrude( d-innerThickness*6 ).center().rotateX(90).rotateY(180)
                .leftTo(-width/2+innerThickness)
        val curve : Shape3d = if (slope == true) curve1 else Cube(0)
    
        val side = (
            Cube( w-innerThickness*2, innerThickness, h-innerThickness ).centerZ().centerX() +
            Cube( w-innerThickness*2, innerThickness*3, innerThickness ).centerX().topTo(h/2)
        ).backTo(d/2-innerThickness)

        val clip : Shape3d = clip()
            .translateY(d/2)
            .translateX(w/2-6)

        val text = Text(frontText).center()
            .extrude(patternDepth)
            .rotateX(90)
            .rotateZ(90)
            .leftTo( inside.right )
            .color("Green")

        return text + inside.and(clip).and(clip.mirrorY()) + thumb + side.mirrorY().also() + curve

    }

    @Piece
    fun outside() : Shape3d {
        val outsideP = Square( height, depth ).center()
            .roundAllCorners( chamfer, 1 )
        val insideP = outsideP.offset(-outerThickness) //Square( height-outerThickness*2, depth-outerThickness*2 ).center()

        val cham = chamfer / Math.sqrt(2)

        val solid = ExtrusionBuilder().apply {
            crossSection( outsideP.offset(-chamfer) )
            forward( chamfer )
            crossSection( outsideP )
            forward( width - chamfer + cham )
            crossSection()
            crossSection( insideP )
            forward( - width + outerThickness )
            crossSection()
            forward( -cham )
            crossSection( -cham )
        }.build()

        val thumb : Shape3d = thumb().offset(gap).internalChamferedExtrude( height, 0.5 )
            .rotateY(90)
            .centerX()
            .topTo(width+gap+cham)

        val text3d = Text(text).center().extrude(0.4)
            .rotateZ(-90).rotateY(90)
            .translateZ(width/2)
            .translateX(height/2)

        val slots = Cube( 11 ,depth+2, 11 ).center()
            .translateZ(width-10)


        return (solid - thumb).color("Green") - slots + text3d
    }
    
    @Piece
    fun both() = inside().toOriginZ() +
        outside().toOriginZ().translateX(-width/2-height/2-2)

    override fun build() : Shape3d {

        val result =
            inside() +
            outside()
                .center().rotateY(90).translateX(-outerThickness/2)
                .translateX( -40 )

        return result
    }
}