/Games/Wooden Block Puzzle/Box3.foocad
A three part box. There are two "lids", and a tube joining them.
FYI, I have created another version of this in Boxes/PuzzleBox.foocad where the middle section is optional, or you can add many middle sections.
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* include WoodenBlock.foocad class Box3 : AbstractModel() { @Custom var part = "view" // top, middle, bottom, or debug or view or exploded @Custom var width = 63 // Internal size @Custom var depth = 63 // Internal size @Custom var height = 155 // Internal size @Custom var topHeight = 28 // Internal size @Custom var bottomHeight = 18 // Internal size @Custom var radius = 6 // Radius of the outside. Other radii are calculated. @Custom var radiusSides = 4 @Custom var thickness = 4 // Thickness of the top (the bottom will be thicker) @Custom var patternThickness = 0.6 @Custom var lipThickness = 2 // Should probably be half of thickness (or close to it) @Custom var lipHeight = 6 // The height of the lip on the bottom piece. // I created small prototypes to find the best value for this. // It is the additional space in the top part for the bottom's lip // to fit into. I wanted an interferance fit. @Custom var lipSlack = 0.3 @Custom var chamfer = 2 // Chamfer of the bottom and top edges. override fun build() : Shape3d { val contents = Cube( 60, 60, 60 ) .centerXY() .translateZ(thickness + 1) .color("Orange") val inside = Square( width, depth ).center().roundAllCorners(radius- thickness, radiusSides) val outside = Square( width + thickness * 2, depth + thickness * 2 ).center().roundAllCorners(radius, radiusSides) val outsideChamfer = Square( width + thickness * 2 - chamfer * 2, depth + thickness * 2 - chamfer * 2 ).center().roundAllCorners(radius - chamfer, radiusSides) val outsideLip = Square( width + lipThickness*2, depth + lipThickness*2 ).center().roundAllCorners(radius - thickness + lipThickness, radiusSides) val slackLip = Square( width + lipThickness*2 - lipSlack*2, depth + lipThickness*2 - lipSlack*2 ).center().roundAllCorners(radius - thickness + lipThickness + lipSlack, radiusSides) val top = ExtrusionBuilder().apply { crossSection( outsideChamfer ) forward( chamfer ) crossSection( outside ) forward( topHeight + thickness - chamfer ) crossSection( outside ) crossSection( slackLip ) forward( lipHeight - 1 ) crossSection( slackLip ) crossSection( inside ) forward( -topHeight - lipHeight + 1 ) crossSection( inside ) }.build().color( "Blue" ) val bottom = ExtrusionBuilder().apply { crossSection( outsideChamfer ) forward( chamfer ) crossSection( outside ) forward( bottomHeight + thickness - chamfer ) crossSection( outside ) crossSection( slackLip ) forward( lipHeight - 1 ) crossSection( slackLip ) crossSection( inside ) forward( -bottomHeight - lipHeight + 1 ) crossSection( inside ) }.build().color( "Blue" ) val middleHeight = height - topHeight * 2 val middleSolid = outside.extrude( middleHeight + lipHeight *2 ) .color( "Blue" ).brighter() val middleHole = ExtrusionBuilder().apply { forward(-1) crossSection( outsideLip ) forward(1 + lipHeight + 1 ) crossSection( outsideLip ) forward( thickness ) // Chamfer so that we don't need support material crossSection( inside ) forward( middleHeight - 2 - thickness ) crossSection( inside ) crossSection( outsideLip ) forward(1 + lipHeight + 1 ) crossSection( outsideLip ) }.build() val middle = middleSolid - middleHole val view = contents + bottom + middle.translateZ( bottomHeight + thickness + 1 ) + top.rotateX(180).toOriginZ().translateZ( bottomHeight + middleHeight + thickness + lipHeight + 3 ) val pattern = topPattern() .extrude( patternThickness ) .translateZ( -0.01) .color( "WhiteSmoke" ) val inspection = Cube( 600, 5, 600 ).center() + Cube( 5, 400, 400 ).center() + Cube(400, 1, 400).centerY().rotateZ(45) return if (part == "top" ) { top - pattern } else if (part == "middle" ) { middle } else if (part == "bottom" ) { bottom - pattern } else if (part == "view" ) { view } else if (part == "exploded" ) { contents + middle.translateZ(topHeight) + top.rotateX(180).translate( width + 10, 0, height + topHeight + 50) } else { view / inspection } } fun topPattern() : Shape2d{ return Square( width *3, 5 ).tileY( 6, 5 ).center()//.rotate(45) } }