Exit Full View
Up

/Bike/PannierAdaptor.foocad

PannierAdaptor

Post Processing

The hole needs to be drilled out, using a 5mm drill bit. (I can't make the hole any smaller in the model).

Measure the distance between the two bagClip pieces when attached to the bag. Glue the blocks to the box, then drill the hole through the box.

Custom Pieces

The box's ribs aren't the same size all the way round, so I need custom version of piece boxBlock.

#larger# : For the right side of the bike. It is ribs are deeper there.

FooCAD Source Code
import static uk.co.nickthecoder.foocad.arrange.v1.Arrange.*
import uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*

class PannierAdaptor : Model {

    @Custom
    var thickness = 24

    @Custom( about="The box has a pair of ribs at the top. The gap between them." )
    var ribGap = 16

    @Custom( about="The internal depth of the channel made by these ribs." )
    var ribDepth = 12

    @Custom( about="The height and thickness. used by both pieces" )
    var locatorSize = Vector2(12,7)

    @Custom
    var insertDiameter = 7.8

    /**
     * This piece attaches to the pannier bag, instead of the stock clip
     */
    @Piece
    fun bagClip() : Shape3d {
        // Use the svg diagram used by [PaccnierClip.foocad]
        val doc = SVGDocument("pannierClip.svg" )
        val scale = 50.0 / doc["fivecm"].size.x
        val angle = 13.5
        val curvy = doc["main"].scale(scale).rotate(angle)

        // Now let's chop off part of it, and move it to the origin
        val movedCurvy = curvy.center().translateX(17)
        val clipped = movedCurvy intersection Square( 43, 12 ).toOrigin()

        // Take the tab from the svg document, and transform it the as `curvy`:
        var tab2d : Shape2d= doc["rect"].scale(scale).rotate(angle).toPolygon()
        tab2d = tab2d.translate( -curvy.corner + movedCurvy.corner )
        val tab = tab2d.roundAllCorners(1).chamferedExtrude( thickness, 1.5 )

        // Add a block that we can add a screw threw to.
        val block = Square( 17, 11.35 ).roundAllCorners(2).rightTo(15).frontTo(0.45)
        val locator = Square( locatorSize + Vector2(0,3) ).roundAllCorners(2).centerXTo( 7 ).backTo(3)
        val profile = clipped.toOrigin() + block + locator
        val solid = profile.chamferedExtrude( thickness, 1 )
    
        // Holes to attach it to the pannier bag.
        val hole = Cylinder.hole( 100, 2.5, 8 )
            .rotateX(90)
            .centerXTo( tab2d.middle.x )
            .frontTo( tab2d.front )
            .centerZTo( thickness/2 )
        val hole2 = Cylinder.hole( 10, 5, 8 )
            .rotateX(90)
            .centerXTo( tab2d.middle.x )
            .backTo( tab2d.front-1.2 +3.5 )
            .centerZTo( thickness/2 )

        // Hole for a threaded insert
        val hole3 = Cylinder( 100, insertDiameter/2 ).center()
            .rotateX(90)
            .centerZTo( thickness/2 )
            .leftTo( 3 )

        return solid + tab.color( "Green" ) - hole - hole2 - hole3
    }

    /**
     * This piece is glued to the box between the pair of ribs around the top.
     */
    @Piece
    fun boxBlock() : Shape3d {

        val block = Square( thickness + 16, ribGap )
            .roundAllCorners(1)
            .center()
            .chamferedExtrude( ribDepth, 1 )

        val slot = Square( thickness + 1, locatorSize.x + 1 )
            .center()
            .chamferedExtrude( locatorSize.y, 0, -1 )
            .centerYTo(block.middle.y)    
            .topTo( block.top+0.1 )

        // Hole for an M6 bolt (with 1mm slack)
        val hole = Cylinder( 100, 3.5 ).centerZ()

        return block - slot - hole
    }

    /**
     * See BagClip.foocad.
     * This prevents the clip from moving. The screw thread still takes no load though.
     */
    @Piece
    fun blockForBagClip() : Shape3d {

        val block = Square( thickness, ribGap )
            .roundAllCorners(1)
            .center()
            .chamferedExtrude( ribDepth, 1 )

        // Hole for the screw in bolt in BagClip.foocad
        val hole = (
            Circle( 8/2 + 0.5 ).backTo( block.back - 1.5 ) hull
            Circle( 8/2 + 0.5 ).frontTo( block.front + 1.5 )
        ).extrude( block.size.z ).bottomTo(1)

        return block - hole
    }

    // Copy pasted from FlatBedAttachments
    @Piece
    fun boltKnob() : Shape3d {

        val size = Vector2(10, 10)
        val knobSpacer = 2
        val headD = 12
        val holeD = 6.6
        
        val knobDiameter = 25
        val recessDepth = 8
        val height = knobSpacer + recessDepth
        val hex = Circle( knobDiameter/2 ).sides(6).roundAllCorners( 3 )

        val knob = hex.smartExtrude( height )
            .filletTop( 2 )
            .chamferBottom( 1 )
    
        val throughHole = Cylinder( 100, holeD / 2 ).center()
        val recess = Circle( headD/2 ).sides( 6 ).extrude( recessDepth + 0.1 )
            .topTo( knob.top + 0.1 )

        return knob - recess - throughHole
    }

    // Copy pasted from FlatBedAttachments
    @Piece
    fun cap() : Shape3d {
        val headD = 12
        val capHeight =  4
        return Circle(  headD / 2 - 0.3 ).sides(6).roundAllCorners(1, 1).extrude( capHeight )
    }

    override fun build() : Shape3d {
        return arrangeX(3, 
            bagClip(),
            boxBlock(),
            boltKnob(),
            cap(),
            blockForBagClip()
        ).centerX()
    }
}