FooCAD Source Codeimport 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)
}
}