/Games/BallHolder2.foocad
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).
The design is flawed! Over time, it has sagged. In hindsight there should have been some kind of triangulation for strength. Surprisingly it has never broken, despite being knocked many times.
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import static uk.co.nickthecoder.foocad.screws.v1.Screws.* class BallHolder2 : Model { // The diameter of the balls you wish to display. @Custom var ballD = 85 // The gap between adjascent balls @Custom var gap = 5 // 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 + gap, ringT/2 ) / Cube( ballD*3 ).centerY() ) .centerY() .rotateY(90) .centerX() .translateY(ringD()/2) val lines = line + line.toOriginX() .mirrorY() .rotateZ(60) .translateY( -(ballD + gap) * Degrees.sin(60) ) .mirrorX().also() val coneH = (ballD + 4 - ringD() + gap) / 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 = cone.translateX( (ballD + gap)/2 ) .mirrorX().also().translateY( ringD()/2 ) val result = lines + rings + cones return result.color("Yellow") } fun repeat( shape : Shape3d ) = shape.repeatX( 2, ballD + gap ).centerX() + shape.translateY(-(ballD+gap)*0.87) @Piece fun printBase() = base().centerXY().mirrorZ() + Cube( 200, 200, 1 ).center().previewOnly() override fun build() : Shape3d { val balls = repeat( Sphere( ballD/2 ) ) .translateZ( ballD * 0.50 ) .previewOnly() return base() + balls + repeat( ring() ) //+ Cube( 85,10,10 ).centerX().translateX(-44) } }