Exit Full View
Up

/Electronics/PowerSupply.foocad

PowerSupply
FooCAD Source Code
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

    }
}