Exit Full View
ZipUp

/Hardware/Band.foocad

Band

Creates "rubber" bands. The simple version straight is limited by the width of the print bed. spiral can make much longer bands. doubleSpiral

FooCAD Source Code
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()
    }

}