import uk.co.nickthecoder.foocad.threaded.v2.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import uk.co.nickthecoder.foocad.smartextrusion.v1.* import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* class Wheel : Model { @Custom( about="Diameter and width of the hub" ) var hubSize = Vector2( 60, 19 ) @Custom( about="The final wheel's diameter = hubSize.x + typeDiameter*2" ) var tyreThickness = 6 @Custom var tyreRounding = 5 @Custom( about="Only used to display a preview of the axel and nuts" ) var axelDiameter = 8 @Custom( about="Diameter of the recess for nuts" ) var nutRecessDiameter = 16 @Custom( about="Diameter and thickness of the bearing. The hole is given additional `clearance`" ) var bearingSize = Vector2( 22, 7 ) @Custom( about="Determines the size of the hub cap" ) var threadDiameter = 35 @Custom( about="Additional width and thickness for the hub cap" ) var capSize = Vector2( 6, 2 ) // 0.075 gives a perfect fit using a 0.6mm nozzel on Qidi Max3 @Custom( about="Additional space for the bearing to fit into its hole" ) var clearance = 0.075 @Custom( about="Offsets for the tyre. Negative for a tight fit" ) var tyreClearance = -0.2 @Custom( about="Chamfer on the hub and the type to locate it in place" ) var tyreChamfer = 1.0 // Positions the bearing in the middle (Z direction as printed) meth recessDepth() = (hubSize.y - bearingSize.y) / 2 // Thread for the hub cap. meth hubThread() = Thread( threadDiameter, 2 ) .rodChamfer( 0.5 ) @Piece( about="The main piece" ) meth hub() : Shape3d { val main = Circle( hubSize.x/2 ) .smartExtrude( hubSize.y ) .top( Chamfer( 1 ) ) // To help put on the tyre. .bottom( Chamfer(-tyreChamfer,tyreChamfer) ) val threadedRecess = hubThread().threadedHole( recessDepth() ) .chamferStart(false) .topTo(main.top + 0.01) val forBearing = Circle( bearingSize.x / 2 + clearance ) .smartExtrude( main.size.z ) .bottomTo( main.top - recessDepth() - bearingSize.y ) val nutRecess = Circle( nutRecessDiameter/2 ) .extrude(forBearing.bottom + 0.2) .bottomTo( -0.1 ) return main - forBearing - threadedRecess - nutRecess//- throughHole } @Piece( about="For display purposes only; showing the axel and nuts", printable = false ) meth displayHub() : Shape3d { val hub = hub() val axel = Cylinder( 100, axelDiameter/2 ) .topTo( hub.top ) .previewOnly() val bearing = ( Circle( bearingSize.x / 2 ) - Circle( axelDiameter/2 ) ).extrude( bearingSize.y ) .centerZTo( hub.middle.z ) .color("orange").opacity(0.8) val nut = Circle( axelDiameter * 0.9 ) .sides(6) .roundAllCorners(2) .extrude( axelDiameter/2 ) .previewOnly() val nuts = nut.topTo(hub.top-1).also() return hub + axel + nuts + bearing } @Piece( about="Hides the nut which fixes the wheel in place. Finger tighten only." ) meth hubCap() : Shape3d { val diameter = hubThread().diameter + capSize.x*2 println( "cap diameter = $diameter" ) val thread = hubThread() val cap = Circle( diameter/2 ) .smartExtrude( capSize.y ) .bottom( Chamfer( capSize.y/2 ) ) val rod = thread.threadedRod( recessDepth() + capSize.y/2 - 0.5 ) .chamferBottom(false) .bottomTo( capSize.y/2 ) val hole = Cylinder( recessDepth(), thread.coreRadius() -2 ) .bottomTo( cap.top + 0.01 ) return cap + rod - hole } @Piece( about="TPU" ) @Slice( fillDensity=100 ) meth tyre() : Shape3d { val inside = Circle( hubSize.x/2 + tyreClearance ) val outside = inside.offset( tyreThickness ) val shape = outside - inside return shape .smartExtrude( hubSize.y ) .outside( roundedChamfer( tyreRounding ) ) .insideTop( Chamfer(tyreChamfer) ) } @Piece( about="Print this, and ensure the bearing is a tight fit. Adjust `clearance`" ) meth testFit() : Shape3d { val inside = Circle( bearingSize.x/2 + clearance/2) val outside = inside.offset(3) val text = Text( "${clearance}", 8 ) val text3d = ( text.boundingSquare().offset(2).roundAllCorners(3).extrude(0.8) + text.extrude(1.6) ).leftTo( outside.right - 2 ).centerY() return text3d + (outside-inside).extrude( bearingSize.y + 2) + (outside - outside.offset(-6)).extrude(2) } @Piece( about="Helps remove a bearing from `testFit` piece" ) meth bearingWhacker() : Shape3d { val pin = Cylinder( 16, axelDiameter/2 - 0.2 ) + Cylinder( 16 - bearingSize.y, axelDiameter/2 + 2 ) val standCircle = Circle( bearingSize.x / 2 + 0.5 ) val stand = (standCircle.offset(1) - standCircle) .extrude( bearingSize.y + 2 ) + standCircle.extrude(1) return pin + stand.leftTo(pin.right + 1 ) } @Piece( printable=false ) override meth build() : Shape3d { val hub = displayHub() val cap = hubCap() .rotateX(180) .topTo( hub.top + 2.02 ) .previewOnly() val tyre = tyre() .rotateX(180) .bottomTo(0.1).color( "DarkGrey" ) return (hub + tyre + cap) .rotateY(90) } }