/GardenFurniture/Hardware/Knob.foocad
A simple knob.
Use a threaded insert in the screw hole.
Beware that a wide and short knob would require support material to print in one piece.
import static uk.co.nickthecoder.foocad.diagram.v1.Diagram.* @Data class Knob( val knobSize : Vector2, val baseSize : Vector2, val waist : double, val holeDiameter : double ) : Lazy3d() { constructor() : this( Vector2( 40, 25 ) ) constructor( size : double ) : this( Vector2( size, size * 0.6 ) ) constructor( size : Vector2 ) : this ( size, Vector2(size.x * 0.7, size.y * 0.25), size.x * 0.5, 3.8 ) // 4.5 for M4 inserts // 3.8 for M3 inserts override meth build() : Shape3d { val waistPoint = Vector2( waist/2, baseSize.y ) val midPoint = Vector2( knobSize.x * 0.5, baseSize.y + knobSize.y * 0.5 ) val deltaY = Vector2( 0, knobSize.y * 0.15 ) val tip = Vector2( 0, baseSize.y + knobSize.y ) val baseTop = Vector2(baseSize.x / 2, baseSize.y/3) val profile = PolygonBuilder().apply { // The base of the knob (ending at the waist) moveTo( 0,0 ) lineTo( baseSize.x / 2, 0 ) lineTo( baseTop ) bezierTo( baseTop + Vector2(0, baseSize.y/3), waistPoint + Vector2(0,-baseSize.y/3), waistPoint) // The main part of the knob bezierTo( midPoint - deltaY*1.4, midPoint) bezierTo( midPoint + deltaY, Vector2(knobSize.x * 0.5, tip.y), tip ) }.build() val screwHole = Cylinder( knobSize.y/2, holeDiameter/2 ).hole().bottomTo( -0.01 ) return profile.revolve().color( "lightGrey") - screwHole } } class CustomisableKnob : AbstractModel() { @Custom( about="The size of the knob (not including the base's height)" ) var knobSize = Vector2( 40, 25 ) @Custom( about="The size of the base. Y = the height at the waist") var baseSize = Vector2( 24, 6 ) // This should always be smaller than baseSize.x @Custom( about="The diameter at the waist (the thinnest part of the knob") var waist = 20.0 @Custom( about="The diameter for the threaded insert" ) var holeDiameter = 4 @Piece fun diagram() : Shape3d { val knob = build() val knobSizeLabel = apiSize( "knobSize", knobSize ) .rotateX(90) .backTo( knob.front ) .bottomTo( baseSize.y ) .leftTo(knob.left) val baseSizeLabel = apiSize( "baseSize", baseSize ) .rotateX(90) .backTo( -baseSize.x/2 ) .leftTo(-baseSize.x/2) val waistLabel = apiLength( "waist", waist ) .translateY( -waist / 2 ) .bottomTo( baseSize.y ) .leftTo( waist ) return knob + knobSizeLabel + baseSizeLabel + waistLabel } override fun build() = Knob( knobSize, baseSize, waist, holeDiameter ) }