/GardenFurniture/NoobWoodworker.foocad

Can we build garden furniture using just straight cuts?
I'm also testing the use of fabric for side panels (i.e. either canvas, or the thinner plastic tent fabrics).
import uk.co.nickthecoder.foocad.woodworking.v1.* import static uk.co.nickthecoder.foocad.woodworking.v1.Woodworking.* import uk.co.nickthecoder.foocad.screws.v3.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import static uk.co.nickthecoder.foocad.along.v3.Along.* import uk.co.nickthecoder.foocad.woodworking.v1.* import static uk.co.nickthecoder.foocad.woodworking.v1.Woodworking.* class DemoNoobWoodworker : Model { @Custom var noob = NoobWoodworker() @Custom var wood = Wood( "wood", 45, 16 ) @Custom var angleRadius = 20 @Piece meth guideShim() = noob.guideShim( wood.size ) meth preview() = wood.cut( 100 ).previewOnly() @Piece meth angle() = noob.angle( wood.size.x, angleRadius ) + preview().edgeDownAlongX().mirrorY() + preview().edgeDownAlongY().rightTo(0).frontTo(-wood.thickness) @Piece meth angle2() = noob.angle2( wood.width, wood.thickness, angleRadius ) + preview().edgeDownAlongX().backTo(0).bottomTo( noob.flatThickness ) + preview().edgeDownAlongY().leftTo(-wood.thickness).frontTo(-wood.thickness).bottomTo( noob.flatThickness ) @Piece meth corner() = noob.corner( wood ) + preview().sideDownAlongX().bottomTo( noob.flatThickness ).leftTo( noob.betweenThickness ) + preview().sideDownAlongY().bottomTo( noob.flatThickness ).rightTo( 0 ) @Piece meth doubleCorner() = noob.doubleCorner( wood ) @Piece meth tConnector() = noob.tConnector( wood ) + preview().sideDownAlongX().bottomTo( noob.flatThickness ) + preview().sideDownAlongY().bottomTo( noob.flatThickness ).rightTo( -noob.betweenThickness ).centerYTo( wood.width/2 ) @Piece meth simpleConnector() = noob.simpleConnector( wood.size ) override fun build() : Shape3d { return guideShim() } } class NoobWoodworker { @Custom var betweenThickness = 2 @Custom var edgeThickness = 3 @Custom var flatThickness = 1 @Custom var betweenCountersink = Countersink() @Custom var outsideCountersink = Countersink() @Custom var guideCountersink = Countersink() @Custom var rounding = 4 var color = "Orange" // Set to true when rendering the large-scale, so that the plastic hardware // is greatly simplified. i.e. no holes, no threads etc. var mock = false meth guideShim( size : Vector2 ) : Shape3d { val shim = Square( size ).center() .roundAllCorners(rounding) .extrude( edgeThickness ) val hole = outsideCountersink.topTo( shim.top ) return if ( mock ) { shim } else { shim - hole }.color( color ) } meth angle( width : double ) = angle( width, width*0.7 ) meth angle( width : double, radius : double ) : Shape3d { val shape = Square( width, edgeThickness ) .rotate(90).leftTo(0).also(2) .roundCorner(3, radius) val holes = outsideCountersink .depth( width ) .recess( width - outsideCountersink.recessDiameter/4 - 1 ) .rotateX(-90) .backTo( width ) .centerXTo( width *0.75 ) .centerZTo( width/2 ) .rotateZ(90).mirrorX().also(2) return if (mock) { shape.extrude( width ) } else { val roundMask = Square( width ) .roundCorner(2, rounding) .roundCorner(1, rounding) .extrude( width*3 ) .rotateX(90) .centerY() .bottomTo(0) (shape.extrude( width ) - holes) .intersection(roundMask) .intersection(roundMask.rotateZ(90)) } } meth angle2( width : double, thickness : double ) = angle2( width, thickness, width*0.7 ) meth angle2( width : double, thickness : double, radius : double ) : Shape3d { val shape = Square( width, edgeThickness ) .rotate(90).leftTo(0).also(2) .roundCorner(3, radius) val holes = outsideCountersink .depth( width ) .recess( width - outsideCountersink.recessDiameter/4 - 1 ) .rotateX(-90) .backTo( width ) .centerXTo( width *0.75 ) .centerZTo( width/2 ) .rotateZ(90).mirrorX().also(2) val baseShape = ( Square( width + thickness ).leftTo(-thickness).frontTo(-thickness) - Square( width * 2 ).translate(edgeThickness, edgeThickness ) ).toPolygon() val base = baseShape .roundCorner(5, rounding ) .roundCorner(4, rounding ) .roundCorner(3, rounding ) .extrude( flatThickness ) return if (mock) { base + shape.extrude( width + flatThickness ) } else { val roundMask = Square( width, width + flatThickness ) .roundCorner(2, rounding) .extrude( width*3 ) .rotateX(90) .centerY() .bottomTo(0) base + (shape.extrude( width + flatThickness ) - holes) .intersection(roundMask) .intersection(roundMask.rotateZ(90)) } } meth corner( wood : Wood ) = corner( wood.width, wood.thickness ) meth corner( width : double, thickness : double ) : Shape3d { val back = Square( width * 2 + betweenThickness, width ) .roundCorners( listOf<int>(2, 3), rounding ) .extrude( flatThickness ) .leftTo(-width) val between = Cube( betweenThickness, width, thickness ) .bottomTo( back.top ) val betweenHole = betweenCountersink.rotateY(-90) .leftTo( between.left ) .centerYTo( between.middle.y ) .centerZTo( between.middle.z ) val end = Square( back.size.x, between.size.z + edgeThickness ) .roundCorners( listOf<int>(2, 3), rounding ) .leftTo( back.left ) .extrude( edgeThickness ) .rotateX(90) val endHoles = guideCountersink .rotateX(90) .frontTo( end.front ) .centerZTo( end.middle.z ) .translateX( -width / 4 ) .translateX( -width / 2 ).also() .translateX( width + betweenThickness ).also() return if ( mock ) { back + between + end } else { (back + between - betweenHole + end - endHoles ) }.color( color ) } meth doubleCorner( wood : Wood ) = doubleCorner( wood.width, wood.thickness ) meth doubleCorner( width : double, thickness : double ) : Shape3d { val between1 = Square( width + edgeThickness, thickness) .extrude(betweenThickness) .rotateY(-90) .leftTo(0) .frontTo(-thickness) val between2 = Square( width + betweenThickness, width + edgeThickness) .extrude( edgeThickness ) .rotateX(90) .frontTo(0) .leftTo(-width) val guide1 = Square( width*2 + betweenThickness, thickness ) .roundCorners( listOf<int>(2, 3), rounding ) .leftTo( between2.left ) .extrude( edgeThickness ) .mirrorY() val guide2 = Square( thickness, width ) .roundCorner( 3, rounding ) .leftTo( between2.left ) .frontTo( betweenThickness ) .extrude( edgeThickness ) val guide3 = Square( width + edgeThickness, width ) .roundCorner(2, rounding) .extrude( edgeThickness ) .rotateY(-90) .leftTo(guide2.right) .translateY(betweenThickness) val guide4 = guide3.rotateZ(-90) .leftTo(between2.right) .frontTo(0) val twoHoles = outsideCountersink .mirrorZ() .translateX(width/2).also() .centerXTo( - width/2 ) .centerYTo( - thickness/2 ) val bottomHoles = twoHoles.translateX(width + betweenThickness ).also() + twoHoles.rotateZ(90) .centerXTo( guide2.middle.x ) .centerYTo( guide2.middle.y ) val guide4Hole = outsideCountersink .rotateX(-90) .centerXTo( guide4.middle.x ) .centerZTo( guide4.middle.z ) .backTo( guide4.back ) val guide3Hole = outsideCountersink .rotateY(90) .centerYTo( guide3.middle.y ) .centerZTo( guide3.middle.z ) .rightTo( guide3.right ) val between1Hole = betweenCountersink .rotateY(-90) .centerYTo( between1.middle.y ) .centerZTo( width*0.8 ) .leftTo( between1.left ) var between2Hole : Shape3d = betweenCountersink .rotateX(-90) .centerXTo( between2.middle.x ) .centerZTo( width*0.8 ) .backTo( between2.back ) between2Hole = if ( false ) { between2Hole.centerXTo( -width + thickness/2 ) } else { between2Hole.centerXTo( -(width-thickness)/2 ) } return if ( mock ) { between1 + between2 + guide1 + guide2 + guide3 + guide4 } else { between1 + between2 + guide1 + guide2 + guide3 + guide4 - guide3Hole - guide4Hole - bottomHoles - between1Hole - between2Hole }.color( color ) } meth tConnector( wood : Wood ) = tConnector( wood.width, wood.thickness ) meth tConnector( wood : Wood, overlap : double ) = tConnector( wood.width, wood.thickness, overlap ) meth tConnector( width : double, thickness : double ) = tConnector( width, thickness, width * 2/3 ) meth tConnector( width : double, thickness : double, overlap : double ) : Shape3d { val back = Square( width + overlap + betweenThickness, width + edgeThickness ) .roundAllCorners(rounding) .extrude( flatThickness ) .leftTo(-overlap) val between = Cube( betweenThickness, width, thickness ) .bottomTo( back.top ) .frontTo( edgeThickness ) val guide = Cube( width + betweenThickness - rounding, edgeThickness, thickness + flatThickness ) val betweenHole = betweenCountersink .rotateY(90) .centerYTo( between.middle.y ) .centerZTo( between.middle.z ) .rightTo( between.right ) val guideHole = outsideCountersink .rotateX(90) .centerXTo( guide.middle.x ) .centerZTo( guide.middle.z ) .frontTo( guide.front ) return if (mock) { back + between + guide } else { back + between + guide - betweenHole - guideHole }.color( color ).translate( -betweenThickness, -edgeThickness, 0 ) } meth simpleConnector( size : Vector2 ) = simpleConnector( size.x, size.y ) meth simpleConnector( width : double, thickness : double ) : Shape3d { val back = Square( width * 1.5 + betweenThickness, width ) .extrude( edgeThickness ) .leftTo(-width) val between = Cube( betweenThickness, width, thickness ) .bottomTo( back.top ) return (back + between).color( color ) } }