import static uk.co.nickthecoder.foocad.arrange.v1.Arrange.* import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.* class PannierBoxFixture : Model { val toHole = 16 // 27 var pannierWidth = 166 var clipDiameter = 12 var thickness = 3 var clipDepth = 12 //var tabDepth = 18 var holeDiameter = 6.5 // The size while it is printed, i.e, Z is the "thickness". // The original use Y=20mm var blockSize = Vector3( 20, 15, 18 ) var spacerThickness = 3.0 var washerSize = Vector2( 16, 6 ) @Custom(required=false) var boltHeadSize = Vector2(14, 4) @Piece @Slice( brimWidth=4 ) fun mirror() : Shape3d = one().mirrorX() @Piece @Slice( brimWidth=4 ) fun one() : Shape3d { val profile = clip(clipDiameter-thickness/2, toHole) val wedge = Cube( 100 ).centerY().rotateX(-45-90).translateZ(clipDepth) val hole = Cylinder( 100, holeDiameter/2 ) .rotateX(-90) .translate(toHole, 0, blockSize.z/2 ) val block = Cube( blockSize.x, blockSize.y, blockSize.z ).centerXTo(hole.middle.x)frontTo( profile.back - thickness ) val insert = ( Circle( blockSize.z/2 ).sides(6).roundAllCorners(2) + Square( 10, blockSize.z ).center() - Circle( holeDiameter ).sides(6) ).extrude( holeDiameter ) .rotateX(-90) .translate(toHole, 0, blockSize.z/2).backTo(profile.back - thickness ) return ( profile.extrude(clipDepth) + (profile.extrude(blockSize.z) intersection wedge) ) + block - hole // + wedge.previewOnly() } // Print using TPU, and glue to the block, to give a rubbery feel. // This make help protect the fixture and the box on rough terrain. // Use the Tile extension to print 4 at once. @Piece fun spacer() : Shape3d { return Cube( blockSize.x, blockSize.z, spacerThickness ).centerXY() - Cylinder( 100, holeDiameter / 2 ).center() } // Use the Tile extension to print 4 at once. @Piece @Slice( brimWidth=4, perimeters=6 ) fun washer() : Shape3d { return (Circle( washerSize.x/2 ) - Circle( holeDiameter/2 )).extrude( boltHeadSize.y + 1 ) - Cylinder( 100, boltHeadSize.x / 2 ).translateZ( 1 ) } // I printed this using TPU. Use the Tile extension to print 4 at once. @Piece fun washerCap() : Shape3d { val t = 2 val innerD = washerSize.x + 0.6 val outerD = innerD + t return Circle( outerD /2 ).chamferedExtrude( washerSize.y + t, 0.8, 0 ) - Cylinder( 100, innerD / 2 ).translateZ( t ) } @Slice( brimWidth=4, perimeters=6 ) override fun build() : Shape3d = arrange( 3, one(), mirror() ) fun clip(left : double, right : double) : Shape2d { val scale = clipDiameter + thickness val a = Vector2( -0.5, 0.5 ) * scale val b = Vector2( -0.38, 0.36 ) * scale val c = Vector2( -0.5, 0 ) * scale val delta1 = Vector2( 0.1, 0 ) * scale val delta2 = Vector2( 0, -0.09 ) * scale val delta3 = Vector2( 0, 0.25 ) * scale val path = PolygonBuilder().apply { moveTo( -left, a.y ) lineTo( a ) //lineTo( b ) bezierByTo( delta1, delta2, b ) //lineTo( c ) bezierByTo( delta2, -delta3, c ) circularArcTo( c.mirrorX(), 0.5*scale, true, true ) //lineTo( b.mirrorX() ) bezierByTo( delta3, -delta2, b.mirrorX() ) //lineTo( a.mirrorX() ) bezierByTo( -delta2, delta1, a.mirrorX() ) lineBy( right, 0 ) }.buildPath() val circles = Circle( thickness/2 ).centerTo(path.points[0]) + Circle( thickness/2 ).centerTo(path.points[path.points.size()-1]) return path.thickness( thickness ) + circles } }