/Furniture/Stool.foocad

The wood is from old bed slats (from Ikea), with each slat cut in thirds. This is why the sizes is almost square, but not quite. Care must be taken to not switch the pieces, which are different by only 4mm.
import uk.co.nickthecoder.foocad.smartextrusion.v1.*
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*
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.*
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.*
include BoxConstruction.foocad
class Stool : Model {
var size = Vector3( 360, 360, 480 )
var linkThickness = 4
var gap = 1
var rodDiameter = 3.1
val lidThickness = 12
var lumberSize = Vector2( 21, 19 )
var quick = false
meth wood() = Wood( "main", lumberSize.x, lumberSize.y ).color("DarkGrey")
meth screwHole() = if (quick) {
Cube(0)
} else {
Countersink().headDiameter(7).holeDiameter(3.5).recess(0.75).depth(2.8)
}
meth construction() : BoxConstruction = BoxConstruction().apply {
cornerExtra = 17
angleExtra = 10
thickness = 3.0
insideRadius = 2
crossSection = lumberSize
screwHole = screwHole()
}
meth fourOf( shape: Shape3d ) : Shape3d {
return shape.leftTo(1).frontTo(1).mirrorX().also().mirrorY().also()
}
@Piece( about="For base's top corners. Required: 2x2" )
meth corner() : Shape3d {
val con = construction()
// As the corner will be hidden by the seat, we can add an extra screw...
return con.cornerB() -
screwHole().mirrorZ()
.translateX( con.thickness + wood().thickness/2 )
.translateY( con.thickness + wood().width/2 )
}
@Piece
meth corners() = fourOf( corner() )
@Piece(about="For bars near the floor. Required: 2x2" )
meth forBar() : Shape3d {
val a = construction().straightConnectorA()
val b = construction().straightConnectorC()
.mirrorY()
.mirrorZ().bottomTo(0)
.rotateZ(90)
.leftTo( a.left ).frontTo( a.front )
return (a and b).rotateX(90).bottomTo(0)
}
@Piece
meth forBars() = fourOf( forBar() )
@Piece
meth forRailA() = forBar()
@Piece
meth forRailB() = construction().straightConnectorC().rotateX(90).bottomTo(0)
@Piece
meth forRails() : Shape3d {
val a = forRailA().leftTo(1).frontTo(1)
val b = forRailB().rightTo(-1).frontTo(1)
return (a + b).mirrorY().also()
}
@Piece
meth angleA() = construction().angleA(45)
@Piece
meth angleC() = construction().angleC(45)
@Piece
meth backAngles() : Shape3d {
return fourOf( angleA() )
}
@Piece
meth frontAngles() : Shape3d {
val con = construction()
val a = angleA().leftTo(1).mirrorX().also().frontTo(1)
val c = angleC().leftTo(1).mirrorX().also().backTo(-1)
return a + c
}
@Piece( about="For Lid's corners. Required: 2x2" )
meth elbow() = construction().jointC()
@Piece
meth elbows() : Shape3d {
return fourOf( elbow() )
}
@Piece
meth foot() = construction().endStop(20) -
screwHole().mirrorZ()
@Piece
meth feet() = fourOf( foot() )
@Piece( about="Rubber (TPU) glued to piece `foot` (or directly to the leg if you prefer)" )
meth footPad() = Square( wood().width + 2, wood().thickness + 2 )
.center()
.roundAllCorners(3)
.smartExtrude(2)
.top( Chamfer(1.5) )
.color("Purple")
meth ply( x : double, y : double, cornerSize: double ) : Shape3d {
val sq = Square(x,y).offset(-3).center()
val corners = Square( cornerSize -3 )
.roundCorner(2, cornerSize*0.75)
.leftTo(sq.left).frontTo(sq.front)
.mirrorX().also().mirrorY().also()
return (sq-corners).extrude(6)
}
@Piece( about="A template to draw the corners of the seat" )
meth topCornerJig() = cornerJig( wood().width*2 )
@Piece( about="A template to draw the corners of the shelf" )
meth shelfCornerJig() = cornerJig( wood().width*1.75 )
meth cornerJig( cornerSize : double) : Shape3d {
val hole = Square( cornerSize -3 )
.roundCorner(2, cornerSize*0.75 )
val shape = Square( cornerSize*1.5 ).roundCorner(2,cornerSize*2) - hole
val walls = Cube( 2, cornerSize/2, 4 )
.rightTo(0)
.frontTo( cornerSize )
.rotateZ(-90).backTo(0).also(2)
return shape.extrude(0.6) + walls
}
@Piece( printable=false )
meth seat() : Shape3d {
val con = construction()
val wood = wood()
val extra = con.thickness*4 + 6
val size = Vector2( this.size.x + wood.thickness*2 + extra, this.size.y + wood.thickness*2 + extra )
val sides = wood.cut( size.x )
.label("lidSide")
.edgeDownAlongX().centerX().frontTo( -size.y/2 )
.mirrorY().also()
val ends = wood.cut( size.y - wood.thickness*2 )
.label("lidEnd")
.edgeDownAlongY().centerY().leftTo( -size.x/2 )
.mirrorX().also()
val corners = elbow()
.rotateX(-90).bottomTo( -con.thickness )
.leftTo( -size.x/2 - con.thickness )
.frontTo( -size.y/2 - con.thickness )
.mirrorX().also().mirrorY().also()
.color("Orange")
val ply = ply( size.x, size.y, wood.width*2 )
.bottomTo( sides.top )
return sides + ends + corners + ply
}
meth rail() : Shape3d {
val con = construction()
val wood = wood()
val sideRails = wood.cut( size.y - wood.thickness*2 )
.label("sideRail")
.edgeDownAlongY()
.centerY()
.rightTo( size.x/2 )
.mirrorX().also()
val backRail = wood.cut( size.x - wood.width*2 )
.label("endRail")
.edgeDownAlongX()
.centerX()
.backTo( size.y/2 )
.color("LightGrey")
val forRailsA = forRailA().rotateX(-90)
.rotateZ(180)
.rightTo( sideRails.right + con.thickness )
.backTo( backRail.back + con.thickness )
.bottomTo( - con.thickness )
.mirrorX().also()
.color("Orange")
val forRailsB = forRailB().rotateX(-90)
.rotateZ(90)
.rightTo( sideRails.right + con.thickness )
.frontTo( -size.y/2 - con.thickness )
.bottomTo( - con.thickness )
.mirrorX().also()
.color("Orange")
return sideRails + backRail //+ forRailsA + forRailsB
}
meth shelf() : Shape3d {
val con = construction()
val wood = wood()
val sideBars = wood.cut( size.y - wood.width*2 )
.label("sideBar")
.edgeDownAlongX().centerX().frontTo( -size.y/2 )
.mirrorY().also()
.color("LightGrey")
val endBars = wood.cut( size.x - wood.thickness*2 )
.label("endBar")
.edgeDownAlongY().centerY().leftTo( -size.x/2 )
.mirrorX().also()
val shelf = ply( size.x -2, size.y-2, wood.width*1.75 )
.bottomTo( sideBars.top )
val forBars = forBar().rotateX(-90)
.translateX( -size.x/2 + wood.width )
.frontTo( -size.y/2 - con.thickness )
.translateZ( -con.thickness )
.mirrorX().also().mirrorY().also()
.color("Orange")
return sideBars + endBars + forBars + shelf
}
@Piece( printable=false )
override fun build() : Shape3d {
quick = true
val con = construction()
val wood = wood()
val barHeight = size.z * 0.2
val railHeight = size.z * 0.6
val corners = corner()
.rotateZ(90)
.rightTo( size.x/2 + con.thickness )
.frontTo( -size.y/2 - con.thickness )
.mirrorX().also().mirrorY().also()
.mirrorZ().translateZ(size.z + con.thickness)
.color("Orange")
val foot = foot()
.leftTo( -size.x/2 -con.thickness )
.frontTo( -size.y/2 - con.thickness )
.translateZ( - con.thickness )
val feet = foot
.mirrorX().also().mirrorY().also()
.color("Orange")
val pad = footPad().mirrorZ()
.centerXTo( foot.middle.x )
.centerYTo( foot.middle.y )
.topTo(feet.bottom)
val pads = pad
.mirrorX().also().mirrorY().also()
val strutSide = wood.cut( size.x )
.label("sideStrut")
.edgeDownAlongX().centerX().frontTo( -size.y/2 )
.mirrorY().also()
.color("DarkGrey").darker()
val strutEnds = wood.cut( size.y - wood.thickness*2 )
.label("endStrut")
.edgeDownAlongY().centerY().leftTo( -size.x/2 )
.mirrorX().also()
val legs = wood.cut( size.z - wood.width )
.label("leg")
.leftTo( -size.x/2 ).frontTo( -size.y/2 )
.mirrorX().also().mirrorY().also()
.color("DimGray")
val struts = legs +
(strutSide + strutEnds).translateZ( size.z - wood.width)
val seat = seat()
.translateZ( size.z - wood.width )
val shelf = shelf().translateZ( barHeight )
val backAngleJoints1 = con.angleA(45)
.rotateY(90)
.backTo( corners.back )
.topTo( corners.top )
.translateX(10).mirrorX().also()
.color("Orange")
val backAngleJoints2 = con.angleA(45)
.backTo( corners.back )
.leftTo(corners.left).mirrorX().also()
.bottomTo( size.z - size.x/2 )
.color("Orange")
val frontAngleJoints1 = con.angleC(45)
.rotateZ(90)
.frontTo( corners.front )
.bottomTo( railHeight - 150 )
.leftTo( corners.left ).mirrorX().also()
.color("Orange")
val frontAngleJoints2 = con.angleA(45)
.rotateZ(-90).rotateX(90)
.backTo( -size.y/2 + 150 )
.leftTo( corners.left ).mirrorX().also()
.topTo( railHeight + con.thickness )
.color("Orange")
val angles = backAngleJoints1 + backAngleJoints2 + frontAngleJoints1 + frontAngleJoints2
val rails = rail().topTo( railHeight )
return struts + corners + rails + angles + seat + feet + pads + shelf
}
}
