FooCAD Source Codeimport static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
class LightShadeCylindrical : Model {
func curved(x : double, y : double) = PolygonBuilder().apply {
moveTo( -1, 0)
lineTo( x, 0 )
bezierBy( Vector2( 0, y/2 ), Vector2( 0, y/2 ), Vector2(-x, y) )
lineTo( -1, y )
}.build().mirrorY().also()
static val ribbed = Circle( 10 )
static val jagged = Square( 10 ).rotate(45).center()
static val curved = curved( 3, 5 )
static val flat = Square(5).center()
@Custom( about="The diameter of the hole for the fixture" )
var fixtureDiameter = 29
var ripple : Shape2d = flat
@Custom
var piece1Size = Vector2( 100, 160 )
@Custom
var piece2Size = Vector2( 170, 110 )
@Custom
var piece3Size : Vector2 = Vector2( 200, 100 )
@Custom
var piece2Offset = 35
@Custom
var piece3Offset = -20
val stepSize = 5
@Piece
meth piece1() = solid( piece1Size, 1 )
@Piece
meth piece2() = solid( piece2Size, 2 )
@Piece
meth piece3() = solid( piece3Size, 3 )
override fun build() : Shape3d {
val a = piece1().mirrorZ().color("Red")
val b = piece2().mirrorZ().translateZ(-piece2Offset).color("Orange")
val c = if (piece3Size == null) {
Cube(0)
} else {
piece3().mirrorZ().translateZ(-piece2Offset - piece3Offset)
}
return a + b + c
}
meth solid( size : Vector2, pieceNumber : int ) : Shape3d {
val main = if ( ripple == null ) {
Circle( size.x/2 ).extrude( size.y )
} else {
rippleExtrude( size.x/2, size.y, ripple, pieceNumber )
}
val holeRadius = if (pieceNumber == 1 ) {
fixtureDiameter/2
} else if (pieceNumber == 3) {
if (piece3Offset > 0) {
piece2Size.x/2 + 1 - stepSize
} else {
piece1Size.x/2 + 1 - (pieceNumber-1) * stepSize
}
} else {
piece1Size.x/2 +1 - (pieceNumber-1) * stepSize
}
val hole = Circle( holeRadius ).extrude( 300 ).translateZ(-1)
println( "Piece $pieceNumber Hole radius = $holeRadius" )
return main - hole
}
fun rippleExtrude( radius : double, height : double, ripple : Shape2d, pieceNumber : int ) : Shape3d {
val count = height ~/ ripple.size.y
val actualRippleHeight = height / count
val actualRipple = ripple.scaleY( height / (ripple.size.y * count) ).frontTo(0)
val profile = Square( radius - ripple.right, actualRipple.size.y ) +
actualRipple.rightTo( radius )
val completeProfile = profile.tileY( count ).toPolygon()
val steppedProfile = if (pieceNumber == 1) {
val first = completeProfile.transform( StepTransform2d( piece2Offset, stepSize ) )
if (piece3Offset < 0 && piece3Size != null) {
first.transform( StepTransform2d( piece2Offset + piece3Offset, stepSize ) )
} else {
first
}
} else if (pieceNumber == 2 && (piece3Size != null && piece3Offset > 0) ) {
completeProfile.transform( StepTransform2d( piece3Offset, stepSize ) )
} else {
completeProfile
}
val stack = steppedProfile.revolve()
return stack
}
}
class StepTransform2d( val y : double, val delta : double ) : Transform2d {
override meth transform(from: Vector2): Vector2 {
val fromStep = y + delta - from.y
if ( fromStep < 0 || from.x < delta ) return from
val d = Math.min( delta, fromStep )
return Vector2( from.x - d, from.y )
}
}