import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.* class Floodlight : Model { val size = Vector3(120,80,16) val thickness = 2 val margin = 5 val slack = 0.3 val recessT = 5 var radius = 6 var postChamfer = 1 var frontChamfer = 3 val postDist = 92 var postT = 5 var postHeight = 30 var heatSize = Vector3( 80.5, 61.5, 39 ) // I'm using old heat sinks from CPUs, which have a lip on one edge. var heatLip = 1.1 @Custom var apeture = Vector2(55, 45) @Custom var led = Vector2( 27, 27 ) @Custom var board = Vector2(79, 45 ) var caseScrews = Vector2( 104, 64 ) var cablePos = 44 fun heatSink() : Shape3d { return Cube(heatSize).centerXY().previewOnly() } @Piece fun back() : Shape3d { val backP = ( Square( size.x, size.y ).center().roundAllCorners(radius) - Square( board ).center() ) val backP2 = ( Square( size.x, size.y ).center().roundAllCorners(radius) ) val back = backP.extrude( thickness ) + (backP2 - backP2.offset( -thickness )).extrude(thickness*3) val recess = ( Square( heatSize.x + thickness *2, heatSize.y + thickness* 2 ).center() - Square( heatSize.x + slack*2, heatSize.y + slack*2 ).center() ).extrude( recessT ).translateZ(thickness) val lip = Cube( heatSize.x, 5, heatLip ).centerX().bottomTo( thickness ).frontTo(recess.front).color("Red") val postP = Circle( 7 ).translateY(postHeight).hull( Square( 30, 0.1 ).centerX() ) val postP2 = postP - Circle( 10 ).translateY(postHeight) val post = postP .chamferedExtrude( postT, postChamfer ) - Cylinder( postT*3, 2).translateY(postHeight).centerZ() + postP2.chamferedExtrude( postT*2, postChamfer ) val posts = post .rotateX(90).rotateZ(90) .translateX( postDist/2 ) .mirrorX().also().withCavities() val screwPost = Cylinder( 6, 5 ).remove(Cylinder( 12, 2 ).center()).remove(Cylinder( 4, 0, 4 ).topTo(6.01)) val screwPosts = screwPost.translate( caseScrews.x/2, caseScrews.y/2, 0 ) .mirrorX().also().withCavities().mirrorY().also().withCavities() return (back + recess + lip + posts).and( screwPosts ) } @Piece fun bracket() : Shape3d { val backP = ( Square( size.x, 50 ).center()- Square( 40, 30 ).center() ) .translateY(6) .roundAllCorners(radius) val back = backP.extrude(thickness) + (backP - backP.offset( -thickness )).extrude(thickness*3) val postP = Circle( 7 ).translateY(postHeight).hull( Square( 30, 0.1 ).centerX() ) val postP2 = postP - Circle( 10 ).translateY(postHeight) val gap = 0.5 // Space for a locking washer (has teeth which aids friction). val post = postP.chamferedExtrude(postT, postChamfer).bottomTo( postT ) + postP2.chamferedExtrude( postT*2, postChamfer ) - Cylinder( 10, 2 ).translateY( postHeight ) val posts = post .rotateX(90).rotateZ(90) .translateX( postDist/2) .mirrorX().also().withCavities() val screwPost = Cylinder( 6, 5 ).remove(Cylinder( 12, 2 ).center()).remove(Cylinder( 4, 0, 4 ).topTo(6.01)) val screwPosts = screwPost.translateX( postDist/2 ).mirrorX().also().withCavities().translateY(22) return (back + posts) .and ( screwPosts ) } var cableD = 8 var grometT = 2 @Piece fun front() : Shape3d { val profile = Square( size.x, size.y ) .roundAllCorners( radius ) .offset( thickness + slack ) .center() val overlap = 5 val front = ExtrusionBuilder().apply { crossSection( profile.offset(-frontChamfer) ) forward( frontChamfer ) crossSection( profile ) forward( size.z + thickness * 3 - frontChamfer ) crossSection() crossSection( -thickness ) forward(-thickness*3) crossSection() crossSection( -overlap ) forward( -overlap ) crossSection( overlap ) forward( -size.z + thickness + overlap +frontChamfer ) crossSection() forward( -frontChamfer ) crossSection( -frontChamfer ) }.build() val holeP = Square( apeture ).roundAllCorners( 1, 10 ) val hole = holeP.extrude( thickness*3 ).center() val screwPost = Cylinder( size.z, 5 ) - Cylinder( 12, 2 ).translateZ(size.z-10) val screwPosts = screwPost.translate( caseScrews.x/2, caseScrews.y/2, 0 ) .mirrorX().also().mirrorY().also() val gripPostDist = 13 val gripD = 8 val gripHoleD = 1.5 val gripPost = ( Cylinder( 6, gripD/2 ) - Cylinder( 12, gripHoleD ) ).translateX(-gripPostDist/2) val gripPosts = ( gripPost.mirrorX().also().translateZ(4) + gripPost.hull( gripPost.mirrorX() ) ).translate(cablePos,16,0) val gripBar = ( Circle( gripD/2 ).hull( Circle( gripD/2 ).translateX( -gripPostDist ) ) - Circle( gripHoleD+0.5 ) - Circle( gripHoleD+0.5 ).translateX(-gripPostDist) ).extrude( 2 ) + // A little nub, that can grip the cable, if the cable is thin. // Flip over the out of the way if not needed. Square( gripPostDist - gripD -0.5, 2).center().translateX(-gripPostDist/2) .chamferedExtrude( 4, 0.6 ) val cableHole = Cylinder( 8, cableD/2 + grometT/2 ) .center() .rotateX(90) .translate( cablePos, size.y/2, cableD/2+6) return front + screwPosts + gripPosts - hole - cableHole + gripBar } @Piece fun gromet() : Shape3d { val h = 8 return ( Cylinder( h, cableD/2 + grometT ) + Cylinder( grometT*2, 10 ) - Cylinder( h, cableD/2+1, cableD/2 ) ) } override fun build() : Shape3d { return back().color("Orange") + front().translateZ(-50)+ bracket().mirrorZ().translateZ(postHeight*2).color("Yellow") + heatSink().bottomTo(thickness) + gromet().translateX(-80) } }