import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import uk.co.nickthecoder.foocad.cup.v1.* import static uk.co.nickthecoder.foocad.cup.v1.Cup.* import uk.co.nickthecoder.foocad.smartextrusion.v1.* import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* class SunUmbrellaConnector : Model { // I have an old pole, which is 25.4mm diameter, and 1mm thick. A classic mix of imperial an metric! @Custom( about="Diameter of the plain pole. Add extra for clearance" ) var poleDiameter = 26 @Custom( about="Diameter of the umbrella's pole. Add extra for clearance" ) var umbrellaDiameter = 50.0 @Custom( about="Plastic thickness" ) var thickness = 3.0 @Custom( about="Height of the plastic" ) var height = 50.0 @Custom( about="Diameter of the ground-spike. (The spike's internal diameter will include clearance)" ) var groundSpikeDiameter = 32.0 @Custom var adaptorHeight = 180.0 @Piece meth testFit() : Shape3d { return bottomPiece().translateZ(-thickness*2) intersection Cube( 200, 200, 1 ).centerXY() } @Piece @Slice( perimeters=2 ) meth bottomPiece() = figure8( umbrellaDiameter, poleDiameter, 3 ) @Piece @Slice( perimeters=5 ) meth topPiece() = figure8( poleDiameter, umbrellaDiameter, thickness ) meth figure8( d1 : double, d2 : double, thickness : double ) : Shape3d { val c1 = Circle( d1 / 2 ).leftTo(1) val c2 = Circle( d2 / 2 ).rightTo(-1) val inside = (c1 hull c2).toPolygon() val outside = inside.offset( thickness ) val base = (outside - c2).toPolygon() .smartExtrude( 2 ) .bottom( Chamfer(1) ) val walls = (outside - inside) .smartExtrude( height ) .top( Chamfer(thickness/4) ) .bottomTo( base.top ) // NOTE. This part is deliberately NOT attached to the walls. // This forces the slicer to use ALL the perimeters around the 2 circles, // where the strength is more needed. // The locator needs no strength. F11 to preview the GCode. val locator = (inside - c1 - c2) .intersection( inside.offset(-0.2) ) .toPolygon() .smartExtrude(height - thickness/4) //.top( Chamfer( thickness/4 ) ) // Doesn't work :-( .bottomTo( base.top ) return base + walls + locator } @Piece meth adaptorTestFit() = adaptor().translateZ(-10).intersection( Cube( 100, 100, 2 ).centerXY() ) @Piece @Slice( fillDensity=5, solidInfillEveryLayers=20, brimWidth=10 ) meth adaptor() : Shape3d { val outside = Circle( groundSpikeDiameter/2 ) val thick = groundSpikeDiameter/2 - poleDiameter/2 val chamfer = Math.min( 1.0, (groundSpikeDiameter - poleDiameter)/6 ) return Cup( outside, adaptorHeight, thick ) .baseThickness( thickness ) .insideTop( Chamfer(chamfer) ) .outsideTop( Chamfer(0.5) ) .outsideBottom( roundedChamfer( 3 ) ) } // Screw this to a sacrificial piece of wood, // and place it on top of the ground-spike. // Whack the wood to drive the spike into the ground. @Piece meth whack() : Shape3d { val spikeThicknessAndClearance = 2 val insideRadius = groundSpikeDiameter/2 + spikeThicknessAndClearance val inside = Circle( insideRadius ) val outside = inside.offset( 2 ) val ring = outside - inside val prong = Square( 7, 8 ).centerY().rightTo(0) + Circle( 8/2 ) - Circle( 3/2 ) val prongs = prong .leftTo( insideRadius ) .repeatAround( 3 ) val base = ( ring + prongs ) .extrude(3) val walls = (outside - inside) .extrude(10) // The custom values don't have the external diameter of the ground spike. // My 32mm ground spike is 35 mm wide. val groundSpike = Circle( 35/2 ).extrude(100).previewOnly() return base + walls // + groundSpike } @Piece @Slice( solidInfillEveryLayers=1 ) meth whack2() : Shape3d { val thickness = 2 val diameter = 37 val height = 16 return Circle( diameter/2 + thickness ) .cup( height, thickness ).baseThickness( 3 ) - Cylinder( 10, diameter/2 - 3 ).bottomTo(0.6) } @Piece( printable = false ) override fun build() : Shape3d { val b = bottomPiece() val umbrella = Cylinder( 300, umbrellaDiameter/2 ) .rightTo( b.right - thickness ) .bottomTo( thickness ) .previewOnly() val pole = Cylinder( 300, poleDiameter/2 ) .leftTo( b.left + thickness ) .translateZ( -adaptorHeight ) .previewOnly() val t = topPiece() .rotateY(180) .topTo(pole.top+thickness) val adaptor = adaptor() .leftTo( b.left ) .topTo( -20 ) return b + t + pole + umbrella + adaptor } }