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 static uk.co.nickthecoder.foocad.cup.v1.Cup.* class ShearY( val factor : float ) : Transform3d { override meth transform(from: Vector3): Vector3 { return Vector3( from.x, from.y + from.x * factor, from.z ) } } class DrillBitTidy : Model { @Custom( about="Extarior size of each tray" ) var size = Vector2( 70, 130 ) @Custom( about="Wall thickness" ) var thickness = 1.8 @Custom( about="Thickness of the base" ) var baseThickness = 1.2 @Custom( about="Radius of the corners" ) var radius = 5 @Custom( about="How much smaller is the lower part" ) var clearance = 0.3 @Custom( about="Each side has ribs, which form an interference fit with the next tray" ) var ribClearance = -0.3 @Custom( about="How much the tray fits (Z) into the tray below (not including the chamfer)" ) var recess = 5 @Custom( about="A small chamfer at the base (prevents elephant foot, and nicer feel" ) val baseChamfer = 0.8 meth tray( dividerHeight : float ) : Shape3d { val depth = dividerHeight + recess + thickness + 1 val shape = Square( size.x, size.y ) .center() .roundAllCorners( radius ) val base = shape.offset( -thickness - clearance ) val rib = Square( thickness ) .center() .smartExtrude( recess ).bottom( Chamfer(thickness/5) ) .bottomTo( baseChamfer ) .color("red") val main = ExtrusionBuilder().apply { crossSection( base.offset(-baseChamfer) ) forward(baseChamfer) crossSection( base ) forward( recess-baseChamfer ) crossSection() forward( thickness ) crossSection( shape ) forward( depth - recess-thickness ) crossSection() // Top forward( -thickness ) crossSection( -thickness ) val down = depth - thickness*2.5 - recess forward( -down ) crossSection() val delta1 = depth - down - thickness - baseThickness forward( -delta1 ) crossSection( -delta1 ) crossSection() }.build() val ribs = rib.rightTo(size.x/2-thickness-ribClearance).repeatY( 2, size.y/2 ).centerY() .mirrorX().also() + rib.backTo(size.y/2-thickness-ribClearance).repeatX( 2, size.x/2 ).centerX() .mirrorY().also() return main + ribs } meth divider( height : float ) : Shape3d { val below = Cube( size.x - thickness*2 - clearance*2, thickness, recess + thickness ) .bottomTo( baseThickness ) .centerX() // x used to use thickness*2, which made it disconnected from the walls :-( val middle = Cube( size.x - thickness - clearance*2, thickness, height - below.size.z ) .centerX() .bottomTo( below.top ) return below + middle } meth slottedDivider( height : float, diameters : List ) : Shape3d { val divider = divider( height ) var shape : Shape2d = Square(0) var x = 0.0 val deltaX = (divider.size.x - thickness * 3) / ( diameters.size() +0.25 ) for ( diameter in diameters ) { val hole = Circle( diameter/2 ).translate( x, height/2 + divider.bottom - 1 ) val slot = hole.hull( hole.translateY( height ) ) shape += slot x += deltaX } val toRemove = shape.centerX() .extrude( thickness *3 ) .centerZ() .rotateX(90) return divider - toRemove } meth embossedLabels( labels : List ) : Shape3d { var labelShape : Shape2d = Square(0) var x = 0 var y = 12 val deltaX = (size.x - thickness * 3 - recess*2) / ( labels.size() +0.25 ) for (label in labels) { labelShape += Text( label ).centerX().translate( x, y ) x += deltaX y = 12 - y } return labelShape.centerX() .extrude( 1 ) .bottomTo( baseThickness - 0.6 ) } @Piece meth simple() : Shape3d { val dividerHeight = 9 val tray = tray( dividerHeight ) val divider = divider( dividerHeight ) .translateY( 37 ) val slottedDivider = slottedDivider( dividerHeight, listOf( 2.8, 4, 6.0, 6.5, 8 ) ).frontTo( tray.front + 20 ) val angledDivider = slottedDivider.transform( ShearY( 0.5 ) ) .frontTo( slottedDivider.front + 30 ) val labels = embossedLabels( listOf( "3", "4", "6", "6.5", "8" ) ) .translateY(-34) val example = Cylinder( 92, 8/2 ) .rotateX(90) .centerZTo( baseThickness + dividerHeight/2 ) .frontTo( tray.front + thickness + 6 ) .centerXTo(22) .previewOnly() return ( tray - labels + divider + angledDivider + slottedDivider ) .color("Violet" ) + example } @Piece meth selfCentering() : Shape3d { val dividerHeight = 13 val height = dividerHeight + recess + thickness + 1 val tray = tray( dividerHeight ) val example = Cylinder( 100, 12/2 ).rotateX(90) .bottomTo( baseThickness ) .translateY( 50 ) .previewOnly() val farDivider = slottedDivider( dividerHeight, listOf( 5.9, 6.0, 6.9, 6.9 ) ) .translateY( 23 ) val nearDivider = slottedDivider( dividerHeight, listOf( 5, 5, 5, 5 ) ) .centerYTo( tray.front + thickness + 20 ) val labels = embossedLabels( listOf( "1.8", "2.6", "3.3", "4.0" ) ) .backTo( farDivider.front ) return ( tray - labels + farDivider + nearDivider ).color( "Blue" ) + example } @Piece meth countersinkDrill() : Shape3d { val dividerHeight = 21 val tray = tray( dividerHeight ) val divider = slottedDivider( dividerHeight, listOf( 2.8, 3.9, 6, 4.9, 5.8 ) ) .backTo( tray.back - thickness - 20 ) val slottedDividers = slottedDivider( dividerHeight, listOf( 2.8, 3.9, 10, 4.9, 5.8 ) ) + slottedDivider( dividerHeight, listOf( 2.8, 3.9, 0, 4.9, 5.8 ) ).frontTo( tray.front + thickness + 20 ) val labels = embossedLabels( listOf( "3", "4", "", "5", "6" ) ) .translateY(10) .translateY(-40).also() val example = Cylinder( 93, 15/2 ) .rotateX(90) .bottomTo( baseThickness ) .frontTo( tray.front + thickness + 10 ) .translateX(22) .previewOnly() val example2 = ( Cylinder( 73, 5/2 ) + Cylinder( 49, 20/2, 5/2 ).translateZ(24) ) .rotateX(90) .backTo( tray.back - thickness ) .centerZTo( baseThickness + dividerHeight/2 ) .previewOnly() return ( tray + divider + slottedDividers - labels ).color( "Green" ) + example + example2 } @Piece meth tray15() : Shape3d = tray(15).color("Orange") @Piece meth lid() : Shape3d { val tray = tray( 10 ) val envelope = Cube( size.x + 2, size.y + 2, thickness + recess ) .centerXY() val hole = Cylinder( baseThickness*3, 20/2 ) .centerZ() .backTo( tray.back - thickness - 10 ) return (tray.intersection(envelope) - hole).color("Yellow") } @Piece meth long() : Shape3d { size = Vector2( 160, 70 ) val tray = tray( 15 ) val divider = divider( 15 ) return tray + divider } @Piece meth longLid() : Shape3d { size = Vector2( 160, 70 ) return lid() } override fun build() : Shape3d { val tray15 = tray15() val lid = lid().bottomTo( tray15.top - thickness - recess ) val selfCentering = selfCentering() .leftTo( tray15.right + 2 ) val countersinkDrills = countersinkDrill() .frontTo(tray15.back+2) val simple = simple() .frontTo(tray15.back+2) .leftTo( tray15.right + 2 ) //return selfCentering + lid.bottomTo( selfCentering.top - thickness - recess ) //return simple + lid return tray15 + lid + selfCentering + countersinkDrills + simple } }