Exit Full View
Up

/New/LampShade2.foocad

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

class LampShade2 : Model {
    
    var tubeDiameter = 60

    var ledLength = 17//0
    var ledWidth = 15.5
    var ledThickness = 1.7

    var ledCount = 5
    var thickness = 1.5
    var floorThickness = 3
    var extraHeight = 5

    var strainThickness = 3
    var strainHeight = 10
    var strainHeight2 = 20
    var strainGripThickness = 2
    
    var cableDiameter = 8
    var slack = 0.3

    fun strainClip() : Shape3d {

        val fc = flattenedCircle(ledWidth, tubeDiameter/2-slack-thickness)
        val profile = fc - fc.offset( -strainThickness )
        val ring = profile.extrude( strainHeight )
        
        val foo = tubeDiameter + strainThickness

        val tie = Cylinder( 20, cableDiameter/2 + strainGripThickness )
        val hole = Cylinder( 60, cableDiameter/2 ).center()
        val removeHalf = Cube( cableDiameter + strainGripThickness* 3, cableDiameter + strainGripThickness* 3, strainHeight2 + 2)
            .centerX()
            .translateZ(-1)
            .translateY( -strainGripThickness )
            
        val tab = PolygonBuilder().apply {
            moveTo( -foo/2 + 4, 0 )
            lineTo( -foo/2 + 4, strainHeight )
            bezierTo(
                Vector2(-foo/2+15, strainHeight),
                Vector2(-20, strainHeight2),
                Vector2(-10, strainHeight2)
            )
            radius(4)
            lineTo( 15, strainHeight2 )
            radius(0)
            lineTo( 15, 0 )
        }.build().extrude( strainGripThickness )
            .rotateX(90)
            .translateY(-strainGripThickness)

        val arm = tie + tab - hole - removeHalf 
        return arm.rotateZ(180).also() + ring
    }

    fun flattenedCircle( flat : double, radius : double ) : Shape2d {
        val angle = Math.PI / ledCount * 2
        val point1 = Vector2(radius,flat/2)
        val point2 = Vector2(radius,-flat/2)
                
        return PolygonBuilder().apply {

            moveTo(point1)
            for (i in 0 until ledCount) {
                lineTo(point2.rotate(angle*i))
                val next = point1.rotate(angle * (i + 1))        
                circularArcTo(next.x,next.y, radius,false, false)
            }
        }.build()
    }


    fun clipProfile() : Shape2d {
        return Square( ledThickness + thickness * 2, ledWidth + thickness*2 ).centerY() -
            Square( 100, ledWidth-thickness*2 ).centerY().translateX(thickness) -
            Square( ledThickness, ledWidth ).centerY().translateX(thickness)
    }

    fun end(withGaps : bool ) : Shape3d {

        val tp = flattenedCircle( ledWidth, tubeDiameter/2 )
        val profile = (tp - tp.offset(-thickness)) +
            clipProfile().translateX(tubeDiameter/2-thickness)
                .repeatAround( ledCount )

        val tube = profile.extrude( ledLength+floorThickness + extraHeight )
       
        val floor = (
            flattenedCircle( ledWidth+thickness*2, tubeDiameter/2 + thickness + ledThickness ) -
            flattenedCircle( ledWidth, tubeDiameter/2 )
        ).extrude(floorThickness)

        
        return if ( withGaps ) {

            // Create gaps in the clips, so that wires can be attached to
            // the led.
            val gapHeight = 5
            val gaps = (
                // An angled piece, so that there is no overhang
                Cube( 10, ledWidth + thickness*2 + 1, 20 )
                    .centerY()
                    .rotateY(20)
                    .translateX( tubeDiameter/2 )
                    .translateZ( floorThickness + gapHeight ) +

                // Completely removed at the base
                Cube( 10, ledWidth + thickness*2 + 1, gapHeight )
                    .centerY()
                    .translateX( tubeDiameter/2 )
                    .translateZ( floorThickness ) +

                // A hole for the wires
                Cube( 10, 6, 3 )
                    .centerXY()
                    .translateZ( floorThickness )
                    .translateX( tubeDiameter/2 )
                    .rotateZ( 180/ ledCount )
                ).repeatAroundZ( ledCount ) 
                
            tube - gaps + floor

        } else {
            tube + floor
        }
    }

    override fun build() : Shape3d {
       
        return end(true) + strainClip().translateZ(30)
    }
}