Exit Full View
Up

/Torch/Torch18650.foocad

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

/**
    A torch using "bog standard" 1W LEDs, an 18650 cell,
    a battery charger module, and a boost module.
    I chose to boost the voltage to 18V and use 6 LEDs in series.
    
*/
class Torch18650 : Model {
    
    var chamfer = 1.0
    var width = 35
    var height = 24
    var thickness = 1.8

    var frontLength = 12
    var middleLength = 60
    var backLength = 40

    var slack = 0.2

    var lip = 5
    var lipT = 2

    var buttonD = 12.8

    fun profile() = Square(
            width + thickness*2,
            height + thickness *2
        ).center().roundAllCorners( chamfer )

    fun outerLipProfile() = Square(
            width - slack,
            height -slack
        ).center().roundAllCorners( chamfer )

    @Piece
    fun front() : Shape3d {

        val internalChamfer = chamfer / Math.sqrt(2)

        val profile = profile()

        val solid = ExtrusionBuilder().apply {
            crossSection( profile.offset( -chamfer ) )
            forward( chamfer )
            crossSection( profile )
            forward( frontLength - chamfer )
            crossSection()
            crossSection( -thickness )

            forward( -frontLength + thickness + internalChamfer )

            crossSection()
            forward( -internalChamfer )
            crossSection( - internalChamfer )
        }.build()


        val holes = Cylinder( thickness + 0.02, 4, 3 )
            .repeatX( 3, 10 )
            .repeatY( 2, 10 )
            .centerXY()
            .translateZ(-0.01)
            .color("Red")

        return solid - holes
    }

    @Piece
    fun middle() : Shape3d {
        val profile = profile()

        val solid = ExtrusionBuilder().apply {
            crossSection( profile )
            forward( middleLength )
            crossSection()
            crossSection( outerLipProfile() )

            // Lip
            forward( lip )
            crossSection()
            crossSection( -lipT )
            forward( -lip-lipT )
            crossSection()
            forward( -lipT )
            crossSection( profile.offset(-thickness)  )
            forward( -middleLength+lipT*2 )
            crossSection()

        }.buildClosed()

        val buttonHole = Cylinder( height, buttonD/2 ).centerX()
            .rotateY(-90).translateZ( middleLength - buttonD/2 - lipT*2 - 6)

        return solid - buttonHole
    }

    @Piece
    fun middleWithBrim() : Shape3d {
        val p = profile()
        val brim = (p.offset( 10 ) - p ).extrude( 0.2 )

        return middle() + brim
    }

    @Piece
    fun back() : Shape3d {

        val internalChamfer = chamfer / Math.sqrt(2)

        val profile = profile()

        val solid = ExtrusionBuilder().apply {
            crossSection( profile.offset( -chamfer ) )
            forward( chamfer )
            crossSection( profile )
            forward( backLength - chamfer )
            crossSection()
            crossSection( -thickness )


            // Lip
            crossSection( outerLipProfile() )
            forward( lip )
            crossSection()
            crossSection( -lipT )
            forward( -lip-lipT )
            crossSection()
            forward( -lipT )
            crossSection( profile.offset(-thickness) )

            forward( -backLength +lipT*2 + thickness + internalChamfer )

            crossSection()
            forward( -internalChamfer )
            crossSection( - internalChamfer )
        }.build()

        val chargerHole = 
            Cube( 3.5, 8.5, thickness*3 ).center() + // main hole
            Cube( 5, 11, 0.5 ).centerXY() + // For the "lips" of the socket
            Cube( 6, 18, thickness ).centerXY().translateZ(0.9) // Circuit board
                        
        return solid - chargerHole.translateX(9).color("Red")
    }


    /**
        The charger module is glued to one side, and the battery stuck with
        double sided tape on the other.
    */
    @Piece
    fun chargeAndBatterySled() : Shape3d {
        val d = 18+2
        val w = height-lipT*2-slack*2-1
        val h = 30
        val shaped = Cube( d/2+1, w, h ).centerY().centerZ() - Cylinder( h+1, d/2 ).center()

        val floor = Cube( d, w, thickness ).centerY().translateX(-d/2)

        return shaped.toOriginZ() + floor
    }

    @Piece
    fun batteryCap() : Shape3d {
        return Cube( 23, 23, 12 ).centerXY() - Cylinder( 12, 18.5/2 ).bottomTo(1)
    }

    fun battery18650() = Cylinder( 63, 18/2 ) + Cylinder( 65, 6 )

    // Used for debugging only. Shows the size of the boost module, as well
    // as the mounting holes.
    fun buckModule() : Shape3d {
        val board = Cube( 43.5, 21.5, 1.5 ).color("Green")
        val components = Cube(43.5, 21.5, 10).translateZ(1.5).color("WhiteSmoke")

        val holes = Cylinder.hole( 20, 1.5 ).translate(15,-7.5,-1)
            .translate(-30,15,-1).also()
        return (board + components).centerXY() - holes
    }

    @Piece
    fun all() = layoutY( 2,
        layoutX( 2,  front(), back() ),
        layoutX( 2, chargeAndBatterySled(), middleWithBrim())
    )

    override fun build() : Shape3d {

        val all = back() +

            middle().color("Green").bottomTo( backLength ) + 

            front().rotateX(180).bottomTo( backLength + middleLength ) +

            chargeAndBatterySled().color("Blue")
                .translateX(-5)
                .bottomTo( thickness ) +

            battery18650().translateX((height-width)/2).previewOnly()
                .translateZ( thickness*2 ) +

            buckModule().previewOnly().rotateY(90)
                .bottomTo( 30 )
                .rightTo( width /2 - lipT ) +

            batteryCap().color("Orange")
                .rotateX(180)
                .bottomTo( 60 )
                .leftTo( -width/2 )

        return all
        
    }
}