import static uk.co.nickthecoder.foocad.extras.v1.Extras.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* class PowerSupply : Model { var size = Vector3( 150, 140, 42 ) var slack = 0.3 var ribSize = Vector2( 1.2, 6 ) var rim = Vector2( 5, 10 ) var thickness = 2.0 var topThickness = 2 var chamfer = 3.0 var meterSize = Vector2( 45.5, 26 ) var barrelD = 4 var potD = 7 var powerD = 12.5 var onD = 16.8 var usbSize = Vector3( 14.9, 18, 15.7 ) var bananaD = 4.5 var jackD = 8.5 fun hole( shape : Shape2d ) = shape.extrude( topThickness + 2 ).bottomTo(-1).color("Red") @Piece fun testFront() = frontHole( Circle(10) ) + Cube(17) fun frontHole( shape : Shape2d ) = shape.extrude( thickness + 2 ) .rotateX(90) .centerZTo( size.z *0.5 - 3 ) .backTo( -size.y / 2 + 1 ) .color("Blue") override fun build() : Shape3d { val case : Shape3d = case().rotateY(180).bottomTo(0) val power = powerLabel().rightTo( 50 ).centerYTo( 55 ).bottomTo( case.top ) val twelve = twelveLabel().rotateX(90).centerXTo( 45 ).centerZTo( size.z/4 ).backTo(case.front) val usb = usbLabel().centerYTo(60).centerXTo(-30).bottomTo( case.top ) return case + power + twelve + usb } fun label( str : String ) : Shape3d { val text = Text( str ) return text.extrude( 1.2 ).color("Black") + text.offset(1).extrude(0.8).color("White") } @Piece fun powerLabel() = label( "Power" ) @Piece fun twelveLabel() = label( "12V" ) @Piece fun usbLabel() = label( "USB" ) /** Glue this to the tiny pot on the buck/boost module, so that a regular knob can be attached. */ @Piece fun potAdaptor() : Shape3d { val r = 5.5 val scale = 1.07 val rounded = Octagon( r/scale ).extrude( 1, 0.75 ).mirrorZ().bottomTo(0) val rod = Octagon( r/scale ).extrude(13+6+topThickness, scale).bottomTo( rounded.top ) val hole = Octagon(2.6+0.5).extrude(10).bottomTo(rod.top-1.5) val whole = rounded + rod - hole // We could print it upright, but it will be stronger printing it in 2 parts laying down. val halves = (whole.rotateX(90) / Cube( 50 ).centerXY()).tileX(2,0.4).centerXY() val hinge = Square( halves.size.x, halves.size.y/2).center().frontTo(halves.front+2).extrude(0.2) return hinge + halves } @Piece fun potMount() : Shape3d { val base = Square( 25, 16 ).centerY().translateX(-4).extrude(6.0)//0.8) val main = (Square( 16, 10 ).centerY().translateX(-2) - Square( 11.5, 4.9 ).centerY().translateY(-1.2)).extrude( 9 ).bottomTo(base.top) val hole = Cylinder( 20, 3.4 ).sides(20).bottomTo(-1).centerXTo(9.3) return main + base - hole } @Piece fun usbMount() : Shape3d { val t = 1.5 val mount = Cube( usbSize + Vector3( t*2, t - thickness, 0 ) ).centerX().remove( Cube( usbSize ).centerX().bottomTo(1.5).frontTo(-thickness) ) val pair = (mount and mount.translateX(30)).centerX() val front = Cube( 60, t, mount.size.z ).centerX() .backTo(mount.back).also() val base = Cube( front.size.x, mount.size.y, t ).centerX() .topTo( mount.top ).also() return pair and front + base } @Piece fun case() : Shape3d { val internal = Square( size.x + slack*2, size.y+slack*2 ) .roundAllCorners(0.1, 5) .center() val external = internal.offset(thickness) //.roundAllCorners(thickness) val case = ExtrusionBuilder().apply { // touching bed (the top of the case) crossSection( external.offset( -chamfer ) ) forward( chamfer ) crossSection( external ) // Finished the chamfer forward( size.z - chamfer ) crossSection() // At the highest point crossSection( internal ) // Ready to head down the inside forward( -rim.y ) crossSection() // Fininshed the overhang crossSection( -rim.x ) forward( -1 ) crossSection() // A flat part of the rim forward( -rim.x + 1 ) crossSection( rim.x ) // Slanted part moveTo(Vector3(0, 0, topThickness + chamfer) ) crossSection() // The main wall inside forward( -chamfer ) crossSection( - chamfer ) }.build() val ribsH = Cube( case.size.x - thickness*2, ribSize.x, ribSize.y ) .repeatY(2, 58).centerXY().centerYTo(0).bottomTo(topThickness) val ribsV = Cube( ribSize.x, case.size.y - thickness*2, ribSize.y ) .centerXY().bottomTo(topThickness) val ribs = ( ribsH + ribsV).color("Green" ) val bananaHoles = frontHole( Octagon( bananaD ).repeatX(3,25) ) .rightTo(-4) val jackHole = frontHole( Octagon( jackD ) ) .repeatX( 2, 25 ) .leftTo(bananaHoles.left + bananaD/2 -jackD/2 ) .mirrorY() // BEGIN Variable Voltage val meterHole = hole( Square( meterSize ).center() ) .centerYTo( 12 ) .centerXTo( bananaHoles.middle.x ) val potHole = hole( Circle( potD / 2 ) ) .centerXTo( bananaHoles.middle.x ) .centerYTo( -20 ) val mockPot = Cylinder( 17, 14/2 ) .centerXTo( potHole.middle.x ) .centerYTo( potHole.middle.y ) .topTo(0) .previewOnly() // The 12V line is always connected to the buck/boost, but the output from the buck/boost // is switched with an LED-lit button. // This lets us adjust the voltage while the banana jack is not powered. val onHole = hole( Circle( onD / 2 ) ) .centerYTo( -50 ) .centerXTo( potHole.middle.x ) // END Variable Voltage val powerHole = frontHole( Octagon( powerD ) ).mirrorY() val usbHole = frontHole( Square( usbSize.x, usbSize.z ) ) .backTo( case.back + 1 ) .bottomTo( 8 ) // A pair of double sockets at the front and the back. val usbHoles = usbHole.repeatX(2, 30).centerXTo(size.x/4).mirrorY().also() // The back ones are switched. The front are always on. val mockUSB = (Cube( usbSize.x, usbSize.y, usbSize.z ).centerXY() + Cube( usbSize.x - 3, 8, usbSize.z + 5 ).centerX() ) .repeatX(2, 30) .leftTo(usbHoles.left).bottomTo(usbHoles.bottom).frontTo(case.front) .mirrorY().also() .previewOnly() val usbSwitches = hole( Circle( onD / 2 ) ) .repeatX( 2, 30 ) .centerXTo( usbHoles.middle.x ) .centerYTo( 42 ) val topHoles = meterHole + potHole + powerHole + onHole + usbSwitches val lines = Cube( 1, size.y, 0.6 ).centerXTo( meterHole.middle.x ).centerY() + Cube( 1, 0.6, size.z ).centerXTo( meterHole.middle.x ) .topTo( jackHole.middle.z ) .backTo(case.front) .mirrorY().also() + Cube( 1, size.y, 0.6 ).repeatX(2, 30).centerXTo( size.x/4 ).frontTo( usbSwitches.back ) val all = case - topHoles - usbHoles - bananaHoles - jackHole -lines + ribs + mockUSB return all + mockPot } }