/** A wall mounted holder for 3 juggling balls. A companion to the ClubsHolder. Print 1 "base" and three "ring" pieces. The rings can be TPU for a rubbery feel. Glue with cyanoacrylate (AKA superglue). */ import static uk.co.nickthecoder.foocad.layout.Layout2d.* import static uk.co.nickthecoder.foocad.layout.Layout3d.* import static uk.co.nickthecoder.foocad.screws.Screws.* class BallHolder : Model { // The diameter of the balls you wish to display. @Custom var ballD = 85 // The gap between adjascent balls @Custom var gap = 2 // The thickness of the rings (i.e. the "small" diameter of the torus). @Custom var ringT = 10 // The diameter of the rings compared to the ball's diameter. @Custom var ringScale = 0.6 fun ringD() = ballD * ringScale @Piece fun ring() : Shape3d { val profile = Circle( ringT / 2 ).translateX( ringD()/2 ) / Square( ringD() + 1 ) return profile.revolve().sides(50).color( "Green" ) } @Piece fun base() : Shape3d { val rings = repeat(ring()).mirrorZ() val line = ( Cylinder( ballD * 2 + gap * 2, ringT/2 ) / Cube( ballD*3 ).centerY() ) .centerY() .rotateY(90) .centerX() .translateY(ringD()/2) val coneH = (ballD + 4 - ringD()) / 2 val coneD = coneH*1.3 val keyHole = keyholeHanger( 4, 8 ).mirrorZ() .rotateX(90) .translateY( coneH ) .translateZ(-6) val cone = ( ( Cylinder( coneH *0.8, ringT*0.6, coneD ) + Cylinder( coneH * 0.2, coneD ).translateZ( coneH * 0.8) ) / Cube( ringT*3 ).centerX() ).rotateX(-90) - keyHole val cones = repeat( cone.translateY( ringD()/2 ) ) val result = line + rings + cones return result.color("Yellow") } fun repeat( shape : Shape3d ) = shape.repeatX( 3, ballD + gap ).centerX() @Piece fun printBase() = base().mirrorZ().rotateZ(45) + Cube( 230, 230, 1 ).center().previewOnly() override fun build() : Shape3d { val balls = repeat( Sphere( ballD/2 ) ) .translateZ( ballD * 0.50 ) .previewOnly() return base() + balls + repeat( ring() ) } }