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() ) @Piece meth lock() : Shape3d { val margin = 6 val width = barSpacing - smallBarDiameter*2 - margin*2 val length = barSpacing val shape = Square( width, length ).center().roundAllCorners(4) + Circle( width/2+margin - 1 ) val hole = Circle( holeDiameter/2 ) val slot = Square( flapWidth + 1, length ).centerX() .backTo( hole.front-5 ) val main = (shape - hole - slot).smartExtrude(thickness) .edges( Chamfer(0.4) ) val lumpShape = Square( width, 5 ) .centerX() .backTo( main.front - 0.5 ) .roundAllCorners(1) val lump = lumpShape.smartExtrude( thickness + lumpHeight + 1 ) .top( Chamfer(0.4) ) .bottomTo( 0 ) val flap = Square( flapWidth, - lump.middle.y + hole.front ) .center().frontTo( lump.middle.y ) .extrude( flapThickness ) val result = main + lump + flap return result } @Piece( about="With a locking bar, kept in place by spring steel wire" ) meth lock3() : Shape3d { val margin = 6 val width = barSpacing - smallBarDiameter*2 - margin*2 val length = barSpacing val extraLength = 5 val shape = Square( width, length + extraLength ).center().roundAllCorners(4) .translateY(extraLength) val hole = Circle( holeDiameter/2 ) val main = (shape - hole).smartExtrude(thickness) .outsideTop( Chamfer(1.5) ) .insideTop( Chamfer(0.4) ) .bottom( Chamfer(0.4) ) val sides = Square( margin -1 + 4, holeDiameter ).centerY().roundAllCorners(2) .leftTo( main.right - 4 ) .smartExtrude( thickness + lumpHeight + 1 ) .top( Chamfer(1) ) .mirrorX().also() val bar = Square( width-8, 10 ) .centerX() .backTo( main.front - 0.5 ) .roundAllCorners(1) .smartExtrude( thickness + lumpHeight + 1 ) .top( Chamfer(1.5) ) .bottomTo( 0 ) val springHoles1 = Cube( 2, length*2, 2 ) .centerY() .centerZTo( bar.middle.z ) .leftTo( sides.left + 3 ) .mirrorX().also() val springHoles2 = Cube( width + 2, 2, 2 ) .centerX() .centerZTo( bar.middle.z ) .centerYTo( bar.middle.y ) val result = main + sides + bar - springHoles1 - springHoles2 return result } @Slice( perimeters=8, topSolidLayers=6, bottomSolidLayers=6 ) @Piece( about="Relies on a snug fit (and friction) to prevent accidental unlocking" ) meth lock2() : Shape3d { val margin = 6 val width = barSpacing - smallBarDiameter*2 - margin*2 val length = barSpacing + 20 val shape = Square( width, length ).center().roundAllCorners(4) + Circle( width/2+margin - 1 ) val hole = Circle( holeDiameter/2 ) val main = (shape - hole).smartExtrude(thickness) .top( Chamfer(0.4) ) .insideBottom( 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, 12 ) .frontTo( hole.back + 0 ) .translateX( width/3 ).also() .centerX() .extrude( thickness - 0.6 ) .centerZTo( main.middle.z ) .mirrorY().also() .color("Red") val reinforcements = PolygonBuilder().apply { moveTo( 0, main.size.y - 5 ) lineBy( 0, main.size.y/2 - 20 ) bezierBy( Vector2( 0, 4 ), Vector2(0, 8), Vector2( 4, 15 ) ) bezierBy( Vector2( 0, 8 ), Vector2(0, 4), Vector2( -4, 15 ) ) lineBy( 0, main.size.y/2 - 20 ) }.buildPath().thickness( 4 ).centerY() //Square( 4, main.size.y - 10 ).roundAllCorners(1).center() .smartExtrude( thickness + 1 ) .top(Chamfer(0.4)) //.bottom( Fillet(1).reverse() ) .translateX( width/2 - 2 ).mirrorX().also() .bottomTo( main.top - 0.6 ) val result = main - voids + reinforcements 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 + 3 ) val cap = capShape.smartExtrude( thickness ) .bottom( Chamfer(1) ) val axel = Circle( holeDiameter/2 - clearance ) .smartExtrude( thickness + lockSpacerHeight ) .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 } override fun build() : Shape3d { val rack = rack().topTo(0).color("DimGrey") val block = Cube( 45, 100, 12 ) .centerX() .translateY(-barSpacing/2) .topTo(0) .color("Green") val mount = mount().color("LightGreen").previewOnly() .bottomTo( shim ) val rubbers = rubber().mirrorZ().topTo( mount.bottom ) .centerXTo( rack.left + barDiameter/2 ) .translateY(90) .mirrorY().also().mirrorX().also() val endRubbers = rubberHalf().rotateZ(-90).mirrorZ().topTo( mount.bottom ) .translateY( rack.back - barDiameter/2 ) .mirrorY().also() val lock = lock2().mirrorZ().topTo( block.bottom ).color("Purple") val fixture = fixture().topTo( block.bottom ).color("Orange") val rails = Square( 16, 300 ) .smartExtrude( 10 ) .offsetBottom( 5 ) .leftTo( mount.right - 4 ) .topTo( mount.top ) .centerY() .mirrorX().also() .color("Red") return mount + rack + rubbers + endRubbers + lock.rotateZ(90) + lock.previewOnly() + fixture + block } }