import static uk.co.nickthecoder.foocad.extras.v1.Extras.* import uk.co.nickthecoder.foocad.threaded.v1.Threaded /** Sometimes, I want to attach things to a plywood sheet, which can be undone by hand (no tools) Drill a large hole through the plywood, and glue in the `nut`. Cap the other side of the wood with the optional `trim`. */ class NutAndBoltForWood : Model { @Custom( about="Thickness of the plywood" ) var woodThickness = 8 @Custom var holeDiameter = 14.7 // Actually 15mm, but adding clearance. @Custom( about="The size of the square part on the opposite side of the wood" ) var nutSize = Vector3( 30, 30, 5 ) @Custom var threadSize = 2 @Custom var threadDiameter = 10 @Custom var threadPitch = 6 @Custom var washerThickness = 2.0 @Custom( about="Extra length to add to the bolt (the thickness of the thing being attached") var boltExtra = 10 @Custom( about="Thickness and depth of the trim" ) var trimSize = Vector2( 1, 2 ) fun boltLength() = woodThickness + nutSize.z + boltExtra + washerThickness fun threaded() = Threaded.create( threadSize, threadDiameter, threadPitch ) // If you need a different shape, create a subclass, and override this method. fun nutProfile() : Shape2d = Square( nutSize.x, nutSize.y ).center().roundAllCorners(4) // If you need a different shape, create a subclass, and override this method. fun trimProfile() : Shape2d = Circle( holeDiameter/2 + 2 ) @Piece fun nut() : Shape3d { // On the opposite side of the wood. val block = nutProfile().extrude( nutSize.z ) // Inside the hole drilled through the plywood. val neck = Cylinder( woodThickness, holeDiameter / 2 ) .bottomTo( block.top ) // Recess for the `trim` piece. val forTrim = Cylinder( trimSize.y+0.3, holeDiameter / 2 - trimSize.x ) .topTo(neck.top+0.1) .color("Red") val thread = threaded().hole( nutSize.z + woodThickness + 4 ).translateZ(-2) return block + neck - thread - forTrim } @Piece fun trim() : Shape3d { val r = holeDiameter / 2 - trimSize.x - 0.3 val neck = (Circle( r ) - Circle( r - trimSize.x)) .extrude( trimSize.x + trimSize.y ) val flat = (trimProfile() - Circle( r )) .extrude( trimSize.x ) return neck + flat } @Custom var boltHeadHeight = 4 @Piece fun bolt() : Shape3d { val bolt = threaded().bolt( boltLength() + boltHeadHeight, boltHeadHeight ) // For a slot for a screwdriver, so we can get the bolt out, if it snaps. val slot = Cube( 20, 20, 1 ).centerZ() .center() .rotateX(90) .bottomTo( bolt.top - 1 ) return bolt - slot } /** Print using TPU */ @Piece fun washer() : Shape3d { val bolt = bolt() return (Circle( bolt.size.x * 0.45 ) - Circle( threadDiameter/2 ) ) .extrude( 1.6 ) } override fun build() : Shape3d { // Set to 0 for the pieces in the final posision. // Set to 10 ish so that each piece is separated. val explode = 10 val nut = nut().color("Green") val trim = trim().mirrorZ().topTo( nut.top + trimSize.x + explode ).color("LightGreen") val attachment = (Square( 30 ).center() - Circle( threadDiameter/2 + 1)) .extrude( boltExtra ) .bottomTo( trim.top + explode ) .previewOnly() val washer = washer(). bottomTo( attachment.top + explode ).color( "DarkBlue" ) val bolt = bolt().mirrorZ().topTo( washer.top + boltHeadHeight + explode ) return nut + trim + bolt + washer + attachment } }