import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* /* NOTE. I have NOT tested this yet! 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. */ class CutleryDrainer : Model { var scale = 1.4 var baseThickness = 3 var thickness = 1.2 var lipThickness = 2.5 var lipHeight = 5 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, height : int ) : Shape3d { val main = ExtrusionBuilder().apply { crossSection( profile ) forward( height ) crossSection() crossSection( -thickness ) forward( -height ) crossSection() }.buildClosed() 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 main + ridges } fun lip( profile : Shape2d ) : Shape3d { return ExtrusionBuilder().apply { crossSection( profile.offset( -thickness -slack ) ) forward( lipHeight ) crossSection() crossSection( -lipThickness ) forward( -lipHeight * 2 ) crossSection() crossSection( 2 ) forward( lipHeight ) crossSection( lipThickness + thickness + slack - 2 ) }.buildClosed().mirrorY() } var aHeight = 70 var bHeight = 95 var cHeight = 110 var dHeight = 95 @Piece fun a() = section( profileA(), aHeight ) @Piece fun b() = section( profileB(), bHeight ) @Piece fun c() = section( profileC(), cHeight ) @Piece fun d() = section( profileD(), cHeight ) @Piece fun ab() = section( profileA(), aHeight ) + section( profileB(), bHeight ) @Piece fun cd() = section( profileC(), cHeight ) + section( profileD(), dHeight ) @Piece fun abcd() = section( profileA(), 70 ) + section( profileB(), 95) + section( profileC(), 110) + section( profileD(), 95) @Piece fun lipA() = lip( profileA() ) @Piece fun lipB() = lip( profileB() ) @Piece fun lipC() = lip( profileC() ) @Piece fun lipD() = lip( profileD() ) override fun build() : Shape3d { val a = section( profileA(), 70 ).color( "Red" ) val b = section( profileB(), 95).color( "Orange" ) val c = section( profileC(), 110).color( "Yellow" ) val d =section( profileD(), 95).color( "Green" ) val lipA = lip( profileA() ).rotateX(180).bottomTo(a.top).color( "Red" ).darker() val lipB = lip( profileB() ).rotateX(180).bottomTo(b.top).color( "Orange" ).darker() val lipC = lip( profileC() ).rotateX(180).bottomTo(c.top).color( "Yellow" ).darker() val lipD = lip( profileD() ).rotateX(180).bottomTo(d.top).color( "Green" ).darker() return a + b + c + d + lipA + lipB + lipC + lipD } }