/Games/BallHolderRails.foocad

Holds juggling balls on two wooden rails. The brackets are attached to the wall by screws.
NOTE. There is a keyhole cutout to attach it to the wall, but to aid printing, it is hidden from view - you will need to cut 1 perimeter of plastic to reveal it.
import uk.co.nickthecoder.foocad.screws.v3.*
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*
class BallHolderRails : AbstractModel() {
    
    @Custom
    var railD = 9
    @Custom
    var thickness = 14
    @Custom
    var chamfer = 2
    // The distance of the two rails.
    // Due to a bug in FooCAD, some values fail - just adjust slightly and try again. Soz.
    @Custom
    var spacing = 60
   fun bracket( center : bool ) : Shape3d {
        val doc = SVGParser().parseFile( "ballHolderRails.svg" )
        val scale = spacing / (doc.shapes["rod2"].left - doc.shapes["rod1"].left)
        val profile = doc.shapes["profile"].scale(scale)
        val outside = Polygon(profile.paths[0])
        val inside = Polygon(profile.paths[1]).offset(-chamfer)
        val holeDepth = if(center) thickness else thickness - 2
        val c2 = 1 // if (piece == "center") 1 else 0
        val holes = Circle.hole( railD/2 ).translate( doc.shapes["rod1"].scale(scale).middle )
                .chamferedExtrude( holeDepth+0.1, -1, -c2 ) +
            Circle.hole( railD/2 ).translate( doc.shapes["rod2"].scale(scale).middle )
                .chamferedExtrude( holeDepth+0.1, -1, -c2 )
        val solid = (
            outside.chamferedExtrude( thickness, chamfer ) -
            inside.chamferedExtrude( thickness+0.2, -chamfer ).translateZ(-0.1) -
            holes.translateZ(-0.1)
        ).center().mirrorZ()
        val keyHole = KeyholeHanger( 4, 8 )
            .rotateY(90).mirrorX()
            .translate( -solid.size.x/2+0.6-0.9, solid.size.y/3, 0 )
        //return keyHole
        return solid - keyHole // + Sphere( 70/2 ).translate(6,45,0).previewOnly()
    }
    override fun build() : Shape3d {
        return bracket(false)    
    }
}

