import uk.co.nickthecoder.foocad.extras.v1.* import static uk.co.nickthecoder.foocad.extras.v1.Extras.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import uk.co.nickthecoder.foocad.screws.v3.* import uk.co.nickthecoder.foocad.smartextrusion.v1.* import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* class RackMount : Model { val barSpacing = 63 val thickness = 4.0 val flapWidth = 10 val flapThickness = 1.2 val clearance = 0.3 val holeDiameter = 20 var barDiameter = 12.2 var smallBarDiameter = 8 val lumpHeight = smallBarDiameter/2 val hookLength = 25 // Adjust to compensate for non-planar rack bars. @Custom( about="The thicknesss of the thin part of the rack rubbers" ) var shim = 0.6 var rubberThickness = 8 @Piece meth lockTestFit() = lock().translateZ(-0.4) .intersection( Cube( 200,200,0.4 ).centerXY() ) meth lockShape() : Shape2d { val length = barSpacing + 20 val margin = 6 val width = barSpacing - smallBarDiameter*2 - margin*2 return Square( width, length ).center().roundAllCorners(4) + Circle( width/2+margin - 1 ) } meth lockHalfShape() : Shape2d { val length = barSpacing + 20 val margin = 6 val width = barSpacing - smallBarDiameter*2 - margin*2 return Square( width, length/2 ).centerX().roundAllCorners(8) + Circle( width/2+margin - 1 ) } @Slice( perimeters=8, topSolidLayers=6, bottomSolidLayers=6 ) @Piece( about="Relies on a snug fit (and friction) to prevent accidental unlocking" ) meth lock() : Shape3d = lock( lockShape() ) @Slice( perimeters=8, topSolidLayers=6, bottomSolidLayers=6 ) @Piece( about="Relies on a snug fit (and friction) to prevent accidental unlocking" ) meth lockHalf() : Shape3d = lock( lockHalfShape() ) meth lock( shape : Shape2d ) : Shape3d { val hole = Circle( holeDiameter/2 ) val main = (shape - hole).smartExtrude(thickness) .inside( Chamfer(0.4) ) .outsideBottom( Chamfer(2.0) ) // Force the slicer to include extra perimeters (instead if unfill) where strength is most needed. val voids = Square( 0.2, 18 ) .frontTo( hole.back + 0 ) .translateX( shape.size.x/3 ).also() .centerX() .extrude( thickness - 0.6 ) .centerZTo( main.middle.z ) .mirrorY().also() .color("Red") val reinforcements = (shape - shape.offset( -4 )) .smartExtrude( thickness + 1 ) .top( Chamfer(0.8) ) .insideBottom( ProfileEdge.fillet(1).reverse() ) .bottomTo( main.top ) val result = main + reinforcements - voids return result } val lockSpacerHeight = 0 @Piece meth lockSpacer() : Shape3d { val margin = 6 val width = barSpacing - smallBarDiameter*2 - margin*2 val length = barSpacing val shape = Circle( width/2+margin - 1 ) val hole = Circle( holeDiameter/2 ) return (shape - hole).extrude( lockSpacerHeight ) } @Piece meth fixture() : Shape3d { val capShape = Circle( holeDiameter/2 + 6 ) val cap = capShape.smartExtrude( thickness ) .bottom( Chamfer(1) ) // The axel is shorter than the lock. When it is screwed to the (green) block, // a friction fit is achieved by screwing down as hard as required. val axel = Circle( holeDiameter/2 - clearance ) .smartExtrude( thickness - 0.4 ) .top( Chamfer(0.3) ) .bottomTo(cap.top) val screwHoles = Countersink().mirrorZ() .translateY( holeDiameter/2 - 4 ) .repeatAroundZ(3) return cap + axel - screwHoles } @Piece( about="TPU between the box and the metal rack. x6" ) meth rubber() : Shape3d { val tabLength = 13 val depth = 16 val thickness = rubberThickness + shim val radius = barDiameter/2 + clearance val block = Square( tabLength*2 + barDiameter, depth ).center() .roundAllCorners(3) .smartExtrude( thickness ) .top( Chamfer(1) ) val valley = Circle( radius ).extrude( depth + 2 ) .rotateX(90).centerXY() .bottomTo( shim ) val screwHoles = Countersink() .elongated(2) .translateX( barDiameter/2 + tabLength/2 ) .topTo( block.top ) .mirrorX().also() return block - valley - screwHoles } @Piece( about="Similar to piece `rubber`, but oriented differently" ) meth rubberHalf() : Shape3d { val tabLength = 13 val depth = 30 val thickness = rubberThickness + shim val radius = barDiameter/2 + clearance val extra = 3 val block = Square( tabLength + barDiameter + extra, depth ).centerY() .leftTo( -barDiameter/2 - extra ) .roundAllCorners(3) .smartExtrude( thickness ) .top( Chamfer(1) ) val valley = Circle( radius ).extrude( depth + 2 ) .rotateX(90).centerXY() .bottomTo( shim ) val screwHoles = Countersink() .elongated(2) .translateX( barDiameter/2 + tabLength/2 ) .topTo( block.top ) return block - valley - screwHoles } @Piece meth shim() = rubber() - Cube( 100 ).centerXY().bottomTo( shim ) @Piece meth shimHalf() = rubberHalf() - Cube( 100 ).centerXY().bottomTo( shim ) meth rack() : Shape3d { val main = Circle(12/2).extrude( Square( 120, 400 ).center().roundAllCorners(30) ) val smaller = Circle( smallBarDiameter/2 ) .extrude( Square( barSpacing - smallBarDiameter, 300 ).center().roundAllCorners(20) ) .bottomTo( main.bottom ) return main + smaller } meth mount() : Shape3d { val rack = rack() return Trapezium( rack.size.x + 40, 440 ) //.deltaX(20) // If the mount tapered? There are pros and cons. .center() .roundAllCorners(20) .smartExtrude(9) .offsetBottom(-5) // Forms a DOVETAIL shape } @Piece meth foot() : Shape3d { val height = 20 val foot = Triangle( 34 ).roundAllCorners(7).backTo(8) //Square( 30, 15 ).center().roundAllCorners(5) //Circle( 10 ) .smartExtrude( height ) .top( Fillet( 2 ) ) .offsetTop( -1 ) val hole = Countersink() .recess( height - 6 ) .topTo( foot.top ) return foot - hole } @Piece( print="boltPrint" ) meth boltAssembly() : Shape3d { val boltDiameter = 11 val height = 25 val boltShape = ( Circle( boltDiameter/2 ) - Square( boltDiameter + 2 ).centerY().rightTo( -3 ) ).toPolygon() val shaft = boltShape .smartExtrude( height ) .edges( Chamfer(1) ) val boltHandle = Square( 14, 4 ).centerY() .leftTo(shaft.right - 5) .roundAllCorners(0.6) .smartExtrude( 8 ).edges(Chamfer(0.4)) .topTo( shaft.top - 1 ) val bolt = (shaft + boltHandle).label( "bolt" ) val blockShape = Square( boltDiameter+4, boltDiameter + 8 ) .centerY().rightTo(boltDiameter/2+2) .roundCorner(2, 4) .roundCorner(1, 4) val slot = Cube( boltDiameter, 5, height ).centerY() .translateZ(4) val block = (blockShape - boltShape.offset(0.5)).extrude( height + 2 ) - slot val cap = ( blockShape.smartExtrude(1.2).top( Chamfer(0.6) ) + boltShape.smartExtrude(0.8).topTo(0) ).label( "cap" ).bottomTo(block.top) val screwHoles = Countersink() .recess(block.right-boltShape.left+1.5) .rotateY(90) .rightTo( block.right ) .translateZ(17) val fixture = (block - screwHoles).label( "fixture" ) return bolt.color("Green") + cap.color("Orange") + fixture } @Piece meth boltPrint() : Shape3d { val fixture = boltFixture() val bolt = bolt().leftTo( fixture.right + 1 ) val cap = boltCap().rightTo( fixture.left -1 ) return fixture + bolt + cap } @Piece meth bolt() = boltAssembly().find( "bolt" ).rotateY(-90).bottomTo(0) @Piece meth boltFixture() = boltAssembly().find( "fixture" ) @Piece meth boltCap() = boltAssembly().find( "cap" ).mirrorZ().bottomTo(0) /* // I have lots of springs which match this exact size. I wanted to make holes so that // the springs screw into the holes. meth springHole( length : double ) : Shape3d { val radius = 3.5 val waveLength = 9 // The natural waveLength is 10, by making it smaller, the spring grips. val turns = length / waveLength val stepsPerTurn = 20 var pos = Vector2( radius, 0 ) val path = Path3dBuilder().apply { for ( i in 0 until turns * stepsPerTurn ) { pos = pos.rotateDegrees( -360/stepsPerTurn ) moveTo( Vector3( pos.x, pos.y, i / stepsPerTurn * waveLength ) ) } }.build() return Circle(1.1).hole().center().extrude(path) } */ override fun build() : Shape3d { val rack = rack().topTo(0).color("DimGrey") val block = Cube( 45, 100, 12 ) .centerXY() .topTo(0) .color("Green") val endBlock = Square( rack.size.x - barDiameter *2 - 4, 36 ) .roundCorner(3, 24) .roundCorner(2, 24) .extrude(12) .centerXY() .topTo(0) .backTo( rack.back - barDiameter - 2 ) .mirrorY().also() .color("Green") val board = mount().color("LightGreen").previewOnly() .bottomTo( shim ) val rubbers = rubber().mirrorZ().topTo( board.bottom ) .centerXTo( rack.left + barDiameter/2 ) .translateY(90) .mirrorY().also().mirrorX().also() val endRubbers = rubberHalf().rotateZ(-90).mirrorZ().topTo( board.bottom ) .translateY( rack.back - barDiameter/2 ) .mirrorY().also() val lock = lock().mirrorZ().topTo( block.bottom ).color("Purple") val fixture = fixture().topTo( block.bottom ).color("Orange") var lockHalf : Shape3d = lockHalf() .mirrorZ() .topTo( block.bottom ).color("Purple") .rotateZ(90) lockHalf = (lockHalf.rotateZ(-90-45) + lockHalf.previewOnly()) .translateX( 31 ) .translateY( rack.back - barDiameter - lockHalf.size.y/2 ) val rails = Square( 16, 300 ) .smartExtrude( 10 ) .offsetBottom( 5 ) .leftTo( board.right - 4 ) .topTo( board.top ) .centerY() .mirrorX().also() .color("Red") return board + rack + rubbers + endRubbers + lockHalf + lock + fixture + block + endBlock } }