/Hardware/Band.foocad

Creates "rubber" bands.
The simple version straight is limited by the width of the print bed.
spiral can make much longer bands.
doubleSpiral
import uk.co.nickthecoder.foocad.extras.v1.*
import static uk.co.nickthecoder.foocad.extras.v1.Extras.*
// BEWARE. Many changes made since I last checked that size.x is respected.
// doubleSpiral's length has never been tested.
class Band : Model {
@Custom
var size = Vector3(1000, 3, 1.2)
@Custom( about="The diameter of the semicircle at the ends of the band" )
var endDiameter = 10
@Custom( about="Distance between each loop of the spiral (Not used for piece `straight`)" )
var spiralGap = 3
@Custom( about="How close to the center of the spiral do we go? (1=Nearest to center)" )
var startLoops = 3
@Piece
meth straight() : Shape3d {
val start = CircularArc( endDiameter/2, 0, 180 ).thickness( size.z )
val length = (size.x - Math.PI * endDiameter)/2
val middle = Square(size.z , length)
.backTo(0)
.centerXTo( -endDiameter/2 )
.mirrorX().also()
val end = start.mirrorY().translateY(-length)
val shape = start + middle + end
return shape.extrude( size.y )
}
@Piece
meth spiral() = spiralShape(size.x, true).extrude( size.y )
@Piece
meth doubleSpiral() = spiralShape(size.x/2, false).rotate(180).also().extrude(size.y)
meth spiralShape( length : double, withEnd : bool ) : Shape2d {
val spiralDelta = spiralGap + endDiameter
var loops = startLoops
var remaining = length
var flip = false
var shape : Shape2d = CircularArc( endDiameter/2, 0, 180 ).thickness( size.z )
.translateX( -spiralDelta/2 * (loops-1) )
remaining -= Math.PI * endDiameter * 2
while (remaining > 0) {
val r1 = spiralDelta/2 * loops - endDiameter/2
val r2 = spiralDelta/2 * loops + endDiameter/2
val willUse = Math.PI * (r1 + r2) / 2
var toAngle = 180
if (willUse > remaining) {
toAngle = 180 * remaining / willUse
}
val small = CircularArc( r1, -1, toAngle+1 ).thickness( size.z )
val large = CircularArc( r2, -1, toAngle+1 ).thickness( size.z )
if (flip) {
shape = shape + (small + large)
} else {
shape = shape + (small + large).rotate(180).translateX( spiralDelta/2 )
}
// Is this the last iteration?
if (willUse > remaining) {
if (withEnd) {
val end = CircularArc( endDiameter/2, -1, 181 ).thickness( size.z )
.translateX( spiralDelta/2 * loops )
.rotate( toAngle )
if (flip) {
shape = shape + end
} else {
shape = shape + end.rotate(180).translateX( spiralDelta/2 )
}
} else {
// When the end is omitted, position the resulting shape such that the
// end is at the origin. This makes piece `doubleSpiral` simple.
if (!flip) {
shape = shape.translateX( -spiralDelta/2 ).rotate(-180)
}
shape = shape.rotate(-toAngle).translateX( -spiralDelta/2 * loops )
}
}
loops += 1
remaining -= willUse
flip = !flip
}
return shape
}
override fun build() : Shape3d {
return spiral()
}
}
