/Boxes/JigsawOrganiser.foocad

For organising drawers or as free-standing organisers (e.g. for pens etc.) Print "bins" in various sizes which lock together using jigsaw style bumps.
The unit size is deliberatley not square (unlike gridfinity), but you could customise it to use squares.
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.*
import uk.co.nickthecoder.foocad.extras.v1.*
import static uk.co.nickthecoder.foocad.extras.v1.Extras.*
import uk.co.nickthecoder.foocad.cup.v1.*
import static uk.co.nickthecoder.foocad.cup.v1.Cup.*
class JigsawOrganiser : Model {
@Custom
var unitSize = Vector2( 55/2, 40 )
@Custom
var lugDepth = 4
@Custom
var round = 1
@Custom
var thickness = 1.2
@Custom
var baseThickness = thickness
// 0.20 for a VERY tight fit - slight elephant's foot makes it too tight.
@Custom
var clearance = 0.30
@Custom
var height = 50.0
@Custom
var flatSides = ""
@Custom
var lipSize = Vector2(1,2)
meth maleShape() = maleShape( 12 )
meth maleShape( width : double ) = lugShape( width, true )
meth femaleShape( width : double ) = lugShape( width, false )
meth lugShape( width : double, isMale : bool ) : Shape2d {
val femaleOffset = if (isMale) 0 else clearance
val inside = Square( width + lugDepth*2, 4 ).backTo(0).centerX()
val outside = Trapezium( width + femaleOffset*2, lugDepth ).angle(20).centerX()
val both = (inside + outside).toPolygon()
val round1 = lugDepth*0.15 - femaleOffset/2
val round2 = lugDepth*0.2 + femaleOffset/4
return both
.roundCorner( 3, round1,4 )
.roundCorner( 2, round2 )
.roundCorner( 1, round2 )
.roundCorner( 0, round1,4 )
}
meth bin( across : int, down : int, height : double ) = bin( across, down, height, "" )
meth bin( across : int, down : int, height : double, flatSides : String ) : Shape3d {
val basic = Square( unitSize.x * across, unitSize.y * down )
.center()
.roundAllCorners(round)
val back = if (flatSides.contains("b")) null else maleShape( unitSize.x/3 ).repeatX(across, unitSize.x).centerX().translateY(basic.back)
val front = if (flatSides.contains("f")) null else femaleShape( unitSize.x/3 ).repeatX(across, unitSize.x).centerX().translateY(basic.front)
val right = if (flatSides.contains("r")) null else maleShape( unitSize.y/3 ).rotate(-90).repeatY(down, unitSize.y).centerY().translateX(basic.right)
val left = if (flatSides.contains("l")) null else femaleShape(unitSize.y/3).rotate(-90).repeatY(down, unitSize.y).centerY().translateX( basic.left )
val shape = (basic + back + right - front - left).toPolygon()
val topEdge = ProfileEdge.chamfer(lipSize.x/2).reverse()
.and( ProfileEdge.flat(lipSize.y) )
.and( ProfileEdge.chamfer(lipSize.x/2) )
val cup = shape.cup( height, thickness )
.baseThickness(baseThickness)
.insideBottom( Fillet(0.5) )
.outsideBottom( Chamfer(0.5) )
.insideTop( topEdge )
.outsideTop( Chamfer(lipSize.x/2) )
return cup
}
@Piece
meth bin1x1() = bin( 1,1, height, flatSides)
@Piece
meth bin1x2() = bin( 1,2, height, flatSides )
@Piece
meth bin1x3() = bin( 1,3, height, flatSides )
@Piece
meth bin1x4() = bin( 1,4, height, flatSides )
@Piece
meth bin1x5() = bin( 1,5, height, flatSides )
@Piece
meth bin1x6() = bin( 1,6, height, flatSides )
@Piece
meth bin2x1() = bin( 2,1, height, flatSides )
@Piece
meth bin2x2() = bin( 2,2, height, flatSides )
@Piece
meth bin2x3() = bin( 2,3, height, flatSides )
@Piece
meth bin2x4() = bin( 2,4, height, flatSides )
@Piece
meth bin2x5() = bin( 2,5, height, flatSides )
@Piece
meth bin2x6() = bin( 2,6, height, flatSides )
@Piece
meth bin3x1() = bin( 3,1, height, flatSides )
@Piece
meth bin3x2() = bin( 3,2, height, flatSides )
@Piece
meth bin3x3() = bin( 3,3, height, flatSides )
@Piece
meth bin3x4() = bin( 3,4, height, flatSides )
@Piece
meth bin3x5() = bin( 3,5, height, flatSides )
@Piece
meth bin3x6() = bin( 3,6, height, flatSides )
@Piece
meth bin4x1() = bin( 4,1, height, flatSides )
@Piece
meth bin4x2() = bin( 4,2, height, flatSides )
@Piece
meth bin4x3() = bin( 4,3, height, flatSides )
@Piece
meth bin4x4() = bin( 4,4, height, flatSides )
@Piece
meth bin4x5() = bin( 4,5, height, flatSides )
@Piece
meth bin4x6() = bin( 4,6, height, flatSides )
@Piece
meth bin5x1() = bin( 5,1, height, flatSides )
@Piece
meth bin5x2() = bin( 5,2, height, flatSides )
@Piece
meth bin5x3() = bin( 5,3, height, flatSides )
@Piece
meth bin5x4() = bin( 5,4, height, flatSides )
@Piece
meth bin5x5() = bin( 5,5, height, flatSides )
@Piece
meth bin5x6() = bin( 5,6, height, flatSides )
@Piece
meth bin6x1() = bin( 6,1, height, flatSides )
@Piece
meth bin6x2() = bin( 6,2, height, flatSides )
@Piece
meth bin6x3() = bin( 6,3, height, flatSides )
@Piece
meth bin6x4() = bin( 6,4, height, flatSides )
@Piece
meth bin6x5() = bin( 6,5, height, flatSides )
@Piece
meth bin6x6() = bin( 6,6, height, flatSides )
@Piece
meth bin7x1() = bin( 7,1, height, flatSides )
@Piece
meth bin7x2() = bin( 7,2, height, flatSides )
override fun build() : Shape3d {
val big = bin(2,2, 60)
val thin = bin(1,2, 50, "l")
val shallow = bin(2,1, 50, "f")
val bigFour = big
.translateX( unitSize.x*2 + clearance/2 ).also()
.translateY( unitSize.y*2 + clearance/2 ).also()
val thinTwo = thin.translateX( - unitSize.x*1.5 - clearance/2 )
.translateY(unitSize.y*2 + clearance/2 ).also()
val shallowTwo = shallow
.translateY( -unitSize.y * 1.5 - clearance/2 )
.translateX( unitSize.x*2 + clearance/2 ).also()
val unit = bin(1,1, 40, "lf").leftTo( thinTwo.left ).frontTo( shallowTwo.front )
return bigFour + thinTwo + shallowTwo + unit
}
}
