package uk.co.nickthecoder.foocad.woodworking.v1 /** * The base class for CutPieceOfWood and JointedPieceOfWood. * Here, we can add various joints, such as [mitre]. * * All the cutting methods us a `side` parameter, which is one of the constants * FACE_SIDE, OPPOSITE_SIDE, FACE_EDGE, OPPOSITE_EDIT, END_GRAIN, STARTGRAIN. * * Note that cutting from the END_GRAIN / START_GRAIN is somewhat different, because * the resulting JointedPieceOfWood has methods for moving the cut along the piece, * which isn't really useful. */ abstract class PieceOfWood() : Lazy3d() { abstract meth getWood() : Wood meth maxAlong(side : int) = if (side % 3 == Woodworking.END_GRAIN) { wood.width } else { size.z } meth maxAcross(side : int) = if (side % 3 == Woodworking.FACE_SIDE) { wood.width } else { wood.thickness } meth maxDepth(side : int) : double { val direction = side % 3 return if (direction == Woodworking.FACE_SIDE) { wood.thickness } else if (direction == Woodworking.FACE_EDGE) { wood.width } else { size.z } } meth maxDistance(side: int) = maxDepth(side) /** * Cut a rectangular lap joint half way through. * [side] is FACE_EDGE, FACE_SIDE or their opposites. * The depth and offset can be changed afterwards via methods of [JointedPieceOfWood]. */ meth lap( side : int ) : JointedPieceOfWood { val size = wood.size(side) return JointedPieceOfWood( this, side, Square(size.x), size.y / 2, 0, 0, 0 ) } /** * Cut a triangular mitre joint all the way through the wood. * [side] is FACE_EDGE, FACE_SIDE or their opposites. * The depth and offset can be afterwards via methods of [JointedPieceOfWood]. */ meth mitre( side : int ) : JointedPieceOfWood { val size = wood.size(side) return JointedPieceOfWood( this, side, Woodworking.mitreShape( size.x ), size.y, 0, 0, 0 ) } meth mitre( side : int, angle : double ) : JointedPieceOfWood { val size = wood.size(side) val shape = if ( side % 3 == 0 ) { Woodworking.mitreShape( size.x, angle ) } else { Woodworking.mitreShape( size.x, angle ).flipXY() } return JointedPieceOfWood( this, side, shape, size.y, 0, 0, 0 ) } meth round( side : int, radius : double ) = JointedPieceOfWood( this, side, Woodworking.roundedShape( radius ), wood.size(side).y, 0, 0, 0 ) /** * Create a joint of any shape and depth. */ meth joint( side : int, shape : Shape2d, depth : double ) : JointedPieceOfWood { return JointedPieceOfWood( this, side, shape, depth, 0, 0, 0 ) } /** * Create a rectangular joint of any size and depth. */ meth joint( side : int, size : Vector2, depth : double ) : JointedPieceOfWood { return JointedPieceOfWood( this, side, Square( size ), depth, 0, 0, 0 ) } /** * Create a rectangular joint of any size and depth. * The shape of the joint is a rectangle from size.x, size.y and the depth is size.z */ meth joint( side : int, size : Vector3 ) : JointedPieceOfWood { return JointedPieceOfWood( this, side, Square( size.x, size.y ), size.z, 0, 0, 0 ) } /** * Create a groove of width [size.x] and depth [size.y] starting the router bit from * side [side]. * */ meth groove( side : int, size : Vector2, position : double ) = rabbet( side, size ).along( position ) /** * Cuts a groove at the edge of the wood, along the full length of the wood. * i.e. a rectangular shape from START_GRAIN for the full length (Z) of this PieceOfWood. */ meth rabbet( size : Vector2 ) = rabbet( Woodworking.FACE_SIDE, size ) /** * Routes a rebate, along the full length/width/thickness of the wood. * [side] is the side of the wood we start the router at. START_GRAIN or END_GRAIN to route the length of the wood. */ meth rabbet( side : int, size : Vector2 ) : JointedPieceOfWood { return JointedPieceOfWood( this, side, Square( size ), maxDistance(side), 0, 0, 0 ) } /** * Note. Because this returns a plain Shape3d, it must be the last Woodworking operation in the chain. */ meth labelSides() : Shape3d { return this + Text("Face Side").extrude(1).rotateX(90).backTo(this.front) + (Text("Face Edge").extrude(1).rotateY(90).mirrorZ()) } }