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 } }