Exit Full View
Up

/Hardware/PressStud.foocad

PressStud

Functional, but not elegant press studs (aka poppers?). Use the slots tosew each half to your material.

The male part can optionaly have a rim.

FooCAD Source Code
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)
    }

}