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) } }