import uk.co.nickthecoder.foocad.smartextrusion.v1.* import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* import uk.co.nickthecoder.foocad.screws.v3.* import static uk.co.nickthecoder.foocad.arrange.v1.Arrange.* import uk.co.nickthecoder.foocad.threaded.v2.* import static uk.co.nickthecoder.foocad.threaded.v2.Thread.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.* class AdjustableFoot : AbstractModel() { @Custom var diameter = 25 @Custom var pitch = 2.0 @Custom var height = 20 @Custom var wallThickness = 6 @Custom var baseThickness = 1.2 @Custom var extraNutHeight = 0 @Custom var extraRodHeight = 2 @Custom var chamfer = 3 @Custom var holeCount = 3 var mock = false fun threaded() : Thread { val thread = Thread( diameter, 2 ) .rodChamfer( 1 ) .mock( mock ) return thread } /** An example profile which can be passed to [customFoot]. */ meth plainProfile() : Shape2d { return Square( diameter/2 + wallThickness, 40 ) .roundCorner(2, diameter * 0.3 ) } /** Make a foot by revolving an arbitrary profile. */ meth customFoot( profile : Shape2d ) : Shape3d { val thread = threaded() val main = profile.revolve() val hole = thread.threadedHole( height + extraRodHeight ) .chamferStart( false ) .clipped( true ) .color("Green") return main - hole } @Piece fun nut() : Shape3d { val thread = threaded() val main = Circle( diameter/2 + wallThickness ) .sides(6).roundAllCorners(5) .chamferedExtrude( height + extraNutHeight, chamfer, 1 ) val hole = thread.threadedHole( main.top - baseThickness ) .chamferStart( false ) .clipped( true ) .topTo( main.top ) .color("Green") return main - hole } @Piece fun rod() : Shape3d { val thread = threaded() val rod = thread.threadedRod( height ) val hole = Countersink() .depth( height + extraRodHeight ) .recess( height + extraRodHeight - 3 ) .mirrorZ().bottomTo(0) val holes = if (holeCount < 2) { hole } else { hole.translateX( diameter*0.25 ) .repeatAroundZ(3) } val extra = Circle(thread.coreRadius()).sides(thread.sides()) .extrude( extraRodHeight + thread.rodChamfer ) .bottomTo( height - thread.rodChamfer ) return if (mock) { rod + extra } else { rod + extra - holes } } @Custom var cornerSize = Vector2(40, 3 ) @Piece fun rodWithCorner() : Shape3d { val thread = threaded() val rod = thread.threadedRod( height ) val hole = Countersink() .depth( height + extraRodHeight + cornerSize.y ) .recess(height + extraRodHeight + cornerSize.y - 8) .mirrorZ().bottomTo(0) val extra = Circle(thread.coreRadius()).sides(thread.sides()) .extrude( extraRodHeight + thread.rodChamfer ) .bottomTo( height - thread.rodChamfer ) val corner = Square( cornerSize.x ).center() .roundAllCorners( 3 ) .extrude( cornerSize.y ) .bottomTo( extra.top ) val offset = Math.max( diameter/2, cornerSize.x/2 - 10) val holes = hole + Countersink() .translate( offset, offset, 0 ) .mirrorZ().bottomTo(corner.bottom) .mirrorX().also() .mirrorY().also() return if (mock) { rod + corner + extra } else { rod + corner + extra - holes }.rotateX(180).bottomTo(0) } // A template to help mark pilot holes for the screws. @Piece fun template() = rod() intersection Cube( 100, 100, 0.4 ).centerXY() override fun build() : Shape3d { return arrangeX( 5, nut(), rod(), rodWithCorner(), customFoot( plainProfile() ) ) } }