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 FloatingSphere2 : Model { var pulleyA = 20 var pulleyB = 10 var pulleyThickness = 9.0 // The groovy will be pulleyThickness - pulleySide * 2 var pulleySide = 0.8 var radius = 27 var thickness = 1.2 var slack = 0.3 // How much bigger in mm each half is, compared to a hemisphere. // Hopefully this will mitigate the need for a piece of paper, as a spacer. // Experimental! var halfSlack = 0.4 var magnetD = 11.0 var magnetH = 2.0 var ringSize = 23 @Piece fun pulley( radius : double ) : Shape3d { val inside = pulleyThickness - pulleySide * 2 val profile = PolygonBuilder().apply { moveTo(0, -pulleyThickness/2) lineTo(radius, -pulleyThickness/2) lineTo(radius, -inside/2) lineTo(radius-inside/2, -inside/2) // Assymetric lineTo(radius-inside/2, 0) lineTo(radius, inside/2) lineTo(radius, pulleyThickness/2) lineTo(0, pulleyThickness/2) }.build() return profile.revolve().sides(60) } @Piece fun doublePulley() : Shape3d { val result = pulley(pulleyA).toOriginZ() + pulley( pulleyB ).toOriginZ().translateZ(pulleyThickness - pulleySide) // A hole in the middle can be used to tie the ends of the thread, // or to pass the thread from one pulley onto the other if you use a single // length. val hole = Cylinder( pulleyThickness * 5, 4 ).center() return result.color("Silver") - hole } @Piece fun half() : Shape3d { val sides = 80 val slotA = Cylinder( pulleyThickness + slack*2, pulleyA + slack*2 ) .rotateX(90) .translateY(pulleyThickness-pulleySide/2+slack) .color("Red") val slotB = Cylinder( pulleyThickness - pulleySide + slack, pulleyB + slack*2 ) .rotateX(90) .translateY( -pulleySide/2 ) .color("Red") val hemi = Sphere( radius ).sides(sides) / Cube( radius * 2 ).centerXY().translateZ(-halfSlack) val hole = Cube( 2, 4, radius*2.1 ).center() // Attemps to make the string for pulleyB easier. // However, both strings will cut into the plastic over time. val exit = Square( pulleyB + slack*2 ).rotate(45).center() .scale(1,pulleyA/pulleyB) .translate(0, (pulleyB+slack*2)/Math.sqrt(2)) .extrude( pulleyThickness ) .rotateX(90) val magnets = Cylinder.hole( magnetH+0.01, magnetD/2 ) .translate( radius*0.42, radius*0.57, -0.01 ) .mirrorX().also().mirrorY().also() val result = hemi - slotA - slotB - exit - hole - magnets return result.translateZ(halfSlack) } // Not needed for the device, but may help perform the trick by making it // easier to hold the ends of the string. // Hide a thread cutter somewhere, and cut the thread at the end of the trick. // (Don't use a blade!). FYI, you can buy thread cutters which are rings! @Piece fun ring() : Shape3d { return Circle(ringSize/2+3).chamferedExtrude( 3, 0.6 ) - Circle( ringSize/2 ).internalChamferedExtrude( 3, 0.6 ) } @Piece fun inspect() : Shape3d { val pieces = half() + doublePulley().center().rotateX(90) return pieces // Cube( 1, innerR*2.2, innerR*2.2 ).center().rotateZ(30) } override fun build() : Shape3d { return half().translateY(radius*2+2).also() + doublePulley().translateX(radius*2) + ring().translateY( -radius - 20 ).tileX(2,2) } }