import uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* import static uk.co.nickthecoder.foocad.arrange.v1.Arrange.* class PressStud : Model { @Custom( about="Diameter and thickness of the studs. Min diameter of 10mm" ) var size = Vector2( 10.0, 0.8 ) @Custom( about="Diameter of the male bobble. Female hole is smaller by 'slack'" ) var bobbleSize = Vector2(3.0, 1.5) @Custom( about="Width of the slots for sewing the studs to your material" ) var sewingWidth = 1.2 @Custom( about="Width of the slots in the female part" ) var slotWidth = 0.8 @Custom( about="Width and height of the rim on the male part. Set to zero for no rim" ) var rimSize = Vector2( 1.0, 0.8 ) @Custom( about="The size difference of the male and female parts. May need tweaking for your printer" ) var fit = 0.02 @Custom( about="Addition height of the bobble. Changes the amount of play when closed" ) var play = 0.0 // Force an even number of sewing holes (and slots in the female part). // Increases as the diameter of the press stud increases. fun rotations() : int = (size.x ~/ 3.5) * 2 // Common base for the male and female parts. fun baseShape( radius : double ) : Shape2d { val profile = Circle( radius ) val holeCount = rotations() val offset = radius - 1.2 val holeLength = offset * 3.8 / holeCount val sewingHole = Square( sewingWidth, holeLength ) .roundAllCorners(0.5) .center() .rightTo( offset ) val sewingHoles = sewingHole.repeatAround( holeCount ) return profile - sewingHoles } fun base( radius : double ) : Shape3d { return baseShape( radius ).extrude( size.y ) } @Piece fun male() : Shape3d { val radius = bobbleSize.x/2 val base = if (rimSize.x > 0 && rimSize.y > 0) { base( size.x / 2 + rimSize.x + 0.3 ) } else { base( size.x / 2 ) } val rim = if ( rimSize.x > 0 && rimSize.y > 0) { (Circle( size.x / 2 + rimSize.x + 0.3 ) - Circle( size.x/2 + 0.3 )) .extrude( rimSize.y ).bottomTo( base.top ) } else { Cube(0) } val post = Cylinder( size.y + radius*0.3 + play, radius-0.15 ) .bottomTo( base.top ) val bobble = Circle( bobbleSize.x / 2 ) .smartExtrude( bobbleSize.y ) .fillet( bobbleSize.y/2-0.2) .centerZTo( post.top ) return base + rim + post + bobble } @Piece fun female() : Shape3d { val hole = Circle.hole( bobbleSize.x/2-fit ) .smartExtrude( size.y + 0.02 ) //.offsetTop( tweak ) .bottomTo(-0.01) val rotations = rotations() val slots = Square( size.x * 0.55, slotWidth ) .roundAllCorners(slotWidth/2,1) .center() .rotate( 180 / rotations ) .repeatAround( rotations ) val base = (baseShape( size.x / 2 ) - slots).extrude( size.y ) return base - hole } // Shows 3 different sized pairs. @Piece fun selection() : Shape3d { size = Vector2( 10, 0.8 ) bobbleSize = Vector2(3.0, 1.2) val small = build() size = Vector2( 12, 1.0 ) bobbleSize = Vector2(4.0, 1.2) val medium = build() size = Vector2( 16, 1.2 ) bobbleSize = Vector2(6.0, 1.2) val large = build() return arrangeY(3, small, medium, large ) } @Piece override fun preview() : Shape3d { val male = male().color("Green") val female = female() return male + female.bottomTo( size.y + 0.1 ) } override fun build() : Shape3d { val male = male() val female = female() return male.rightTo(-1) + female.leftTo(1) } }