/Kitchen/CutleryDrainer.foocad

A reimplementation of the cutlery drainer that I first created using OpenSCAD. If I were to do it from scratch, I would probably design the profiles in Inkscape. But I've chosen to replicate the old profiles exactly.
You can print it in one piece (abcd) two pieces (ab and cd), or as four individual pieces. I originally printed it in two pieces because my printer at the time wasn't big enough to print it in one piece. However, I've grown to like it in two pieces.
If you want colourful... Why not print them separately in different colours, and then glue them together if you want them joined.
In the original the lips were separate pieces (I'm not sure why) This version keeps that as an option (by setting includeLips = false).
import uk.co.nickthecoder.foocad.smartextrusion.v1.*
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
class CutleryDrainer : AbstractModel() {
var scale = 1.4
var baseThickness = 3
var thickness = 1.2
var lipThickness = 2.5
var lipHeight = 5
var includeLip = true
var slack = 0.3
fun back() = Square( 300 ).centerX()
fun profileA() = Hull2d(
Circle( 55/2 ).translate(-80,-25 ),
Circle( 30/2 ).translate( -60, 10 )
).scale( scale ) - profileB() - back()
fun profileB() = Hull2d(
Circle( 55/2 ).translate( -40, -35 ),
Circle( 50/2 ).translate( -35, 10 )
).scale( scale ) - profileC() - back()
fun profileC() = Hull2d(
Circle( 55/2 ).translate( 0, -40 ),
Circle( 30/2 ).translate( 5, 10 )
).scale ( scale ) - back()
fun profileD() = Hull2d(
Circle( 55/2 ).translate( 50, -30 ),
Circle( 20/2 ).translate( 10, -5 ),
Circle( 30/2 ).translate( 40, -10 )
).scale( scale ) - profileC() - back()
fun section( profile : Shape2d, cutout : Shape2d, height : int ) : Shape3d {
val main = (profile - profile.offset(-thickness))
.smartExtrude( height )
val xRidges = Square( 2, main.size.y ).tileXWithin( main.size.x + 5, 3 )
.leftTo(main.left).backTo(main.back)
val yRidges = Square( main.size.x, 2 ).tileYWithin( main.size.y + 5, 5 )
.leftTo(main.left).backTo(main.back)
val ridges = (xRidges.intersection(profile))
.extrude( baseThickness )
.translateZ(baseThickness) +
(yRidges.intersection(profile))
.extrude( baseThickness )
return if (includeLip) {
slack = 0.0
val lip = lipWithCutout( profile, cutout )
.rotateX(180)
.centerZTo( height )
main + ridges + lip
} else {
main + ridges
}
}
fun lipWithCutout( profile : Shape2d, cutout : Shape2d ) : Shape3d {
val both = if (cutout == null) profile else profile + cutout.offset(0.001)
val outside = ExtrusionBuilder().apply {
crossSection( both.offset( -thickness - slack ) )
forward( lipHeight )
crossSection()
crossSection( thickness + slack )
forward( lipHeight )
crossSection( -lipThickness )
}.build()
val hole = profile.offset( -lipThickness - thickness )
.smartExtrude(lipHeight*2+1)
.bottom( Chamfer( lipThickness + slack, lipHeight ).reverse() )
.bottomTo(-0.5)
val result = if (cutout == null) {
outside - hole
} else {
val cut = cutout.offset( slack ).extrude( lipHeight*2+1 )
.bottomTo(-0.5)
val cut2 = cutout.offset( slack + thickness ).extrude( lipHeight )
outside - hole - cut - cut2
}
return result.rotateX(180).bottomTo(0)
}
var aHeight = 70
var bHeight = 95
var cHeight = 110
var dHeight = 95
@Piece
fun a() = section( profileA(), profileB(), aHeight )//.centerXY().translateX(30)
@Piece
fun b() = section( profileB(), profileC(), bHeight )
@Piece
fun c() = section( profileC(), null, cHeight )
@Piece
fun d() = section( profileD(), profileC(), dHeight )
@Piece
fun ab() = a() + b()
@Piece
fun cd() = c() + d()
@Piece
fun abcd() = ab() + cd()
@Piece
fun lipA() = lipWithCutout( profileA(), profileB() )
@Piece
fun lipB() = lipWithCutout( profileB(), profileC() )
@Piece
fun lipC() = lipWithCutout( profileC(), null )
@Piece
fun lipD() = lipWithCutout( profileD(), profileC() )
@Piece( printable = false )
override fun build() : Shape3d {
val a = a().color( "Red" )
val b = b().color( "Orange" )
val c = c().color( "Yellow" )
val d = d().color( "Green" )
return (a + b + c + d).centerXY()
}
}

