[User]
Okay, I'd like to design a customizable bag clip, something like a clothespin but more robust. It should have two arms that pivot around a central point. One arm will have a latch at its end, and the other arm will have a corresponding slot or hook for the latch to engage with.

Here's what I'm envisioning:

**General Structure:**

*   **Two Arms:** The clip consists of two arms, roughly rectangular in shape, that meet at a pivot point.
*   **Pivot:** The arms are connected by a cylindrical pivot. I need to be able to specify the diameter of the pivot hole, the outer diameter of the pivot's casing, and the thickness of the casing wall.
*   **Latch Mechanism:** One arm ends with a "hook" or latch that engages with a slot/recess at the end of the second arm, securely holding the clip closed. I'd like to control the hook's depth, the slot length, and the thickness of the latching parts.
*  **First layer offset:** I will need to add an offset that applies to the first layer of the model for an 'elephant foot' effect. This would be configurable.
*   **Custom Text:** I want to include a custom text message on one of the arms. I'd like to control the text content, size, depth, and its position along the length of the arm and its position in relation to the thickness of the arm and the width of the arm. I'd also like to control the letter spacing and font.

**Specific Parametric Dimensions (and their defaults):**

*   `arm_length` (88) - Length of each arm measured from the center of the pivot.
*   `arm_width` (14) - Overall width of the clip arms.
*   `arm_thickness` (6) - Thickness of a single arm.
*   `arm_space` (1) - Space between the two arms when closed.
*   `pivot_id` (6) - Inner diameter of the pivot hole.
*   `pivot_od` (12) - Outer diameter of the pivot case.
*   `pivot_wall` (3) - Thickness of the pivot case wall.
*   `pivot_hspace` (0.3) - Horizontal margin around the pivot (within a layer).
*   `pivot_vspace` (0.4) - Vertical margin around the pivot (between layers).
*   `arm2_end_slop` (0.5) - Offset of the slot at the latch end of arm 2.
*   `arm2_end_radius` (2) - Corner radius at the latch end of arm 2.
*   `latch_thickness` (2) - Thickness of the latch's hook.
*   `latch_slot_thickness` (0.8) - Thickness of the latch slot's walls.
*   `latch_slot_length` (10) - Length of the latch clearance slot.
*   `latch_hook_depth` (1.7) - Depth of the latch hook.
*  `latch_height_factor` (1.5) - Controls the height of the latch, relative to the latch thickness.
*  `ridge_height` (1.5) - Height of the ridge/slot on the arms.
* `anti_ridge_depth` (1.5) - Depth of the anti-ridge on the arm.
*  `text_message` ("Charlie") - The text message to display on the arm.
*   `text_size` (7) - Size of the text.
*   `text_depth` (0.5) - Depth of the text.
*  `text_position` (0.6) - Position of text along the arm, 0 is close to pivot and 1 is close to latch.
*  `text_spacing` (1.1) - Space between letters.
*  `text_font` ("Helvetica:black") - Font used for the text.
*  `first_layers_inset_width` (0.3) - Amount of inset for the first layer to avoid elephant foot.
*  `first_layers_inset_height` (0.2) -  Height of first layers to inset.

I would like this to be done in OpenSCAD and I'd prefer to not use any libraries outside of the standard library that comes with OpenSCAD unless it makes something significantly easier.

[Assistant]
my_bag_clip.scad:
```

eps = 0 + 0.05;

// The text message
text_message = "Charlie";

// Text size
text_size = 7;

// Text depth
text_depth = 0.5;

// A proportion to control the text position along arm 1
text_position = 0.6;

// Inter character spacing. Normal is 1.0.
text_spacing = 1.1;

// Text font
text_font = "Helvetica:black";

// Amount of inset of first(layers) to avoid 'elephant foot'.
first_layers_inset_width = 0.3;

// Height of first layer(s) to inset. Typically set to layer height to inset a single layer.
first_layers_inset_height = 0.2;

// Length, measured from pivot center
arm_length = 88;

// Overall width
arm_width = 14;

// Thickness of a single arm
arm_thickness = 6;

// Space between the two arms
arm_space = 1;

// Pivot diameter.
pivot_id = arm_thickness;

// Outer diameter of pivote case.
pivot_od = 2*arm_thickness;

// Thickness of pivote case.
pivot_wall = 3;

// Pivot margin in horizontal direction (intra layer)
pivot_hspace = 0.3;

// Pivot margin in vertical direction (inter layer)
pivot_vspace = 0.4;

// Offset of the slot at the latch end of arm 2.
arm2_end_slop = 0.5;

// Corner radius at the latch and of arm 2.
arm2_end_radius = 2;

// Thickness of the latch L shape part.
latch_thickness = 2;

// Thickness of the latch L shape part.
latch_slot_thickness = 0.8;

// Length of the latch clearance slot.
latch_slot_length = 10;

// The latching distance.
latch_hook_depth = 1.7;

// Controls the height latch height, for easier opening.
latch_height_factor = 1.5;

// The ridge (slot) height.
ridge_height = 1.5;

anti_ridge_depth = ridge_height + 0;

// Circle smoothness
$fn = 128;

module arm1() {
  difference() {
    union() {
      // Add arm.
      translate([0, -arm_thickness, 0])
      cube([arm_length, arm_thickness, arm_width]);

      // Add pivot holder
      cylinder(d=pivot_od, h=arm_width);

      // Add latch
      translate([arm_length, 0, 0])
        latch();
    }

    // Substruct latch slot
    translate([arm_length, -arm_thickness+latch_thickness, 0])
      latch_slot();

    // Substract pivote hole
    translate([0, 0, -eps])
      cylinder(d=pivot_id, h=arm_width + 2*eps);

    // Substract Pivot clearance slope
    {
      r1 = pivot_id/2;
      r2= pivot_od/2;
      r = (r2*r2 - r1*r1)/(2*r1) + r1;
      translate([0, r-r1, pivot_wall])
        cylinder(d=2*r, h=arm_width-2*pivot_wall);
    }

    // Substract anti ridge
    translate([0, 0, arm_width/2])
      rotate([90, 0, 0])
        ridge(anti_ridge_depth, arm_length-eps);

    // Substract text
    translate([arm_length*text_position, -arm_thickness+text_depth, arm_width/2])
rotate([90, 180, 0]) linear_extrude(height = text_depth+eps)
     text(text_message, halign="center",valign="center", size=text_size, spacing=text_spacing, font=text_font);
  }
}

// Latch. Added to arm1
module latch() {
  // The latch 'hook'
  translate([0, arm_thickness + arm_space, 0])
  hull() {
    cube([latch_thickness, latch_thickness*latch_height_factor + latch_hook_depth, arm_width]);
    translate([-latch_hook_depth, 0, 0])
      cube([latch_hook_depth, latch_thickness, arm_width]);
  }

  translate([0, -arm_thickness, 0])
    cube([latch_thickness,
       2*arm_thickness+arm_space+eps,
      arm_width]);

  l = latch_slot_length + latch_thickness + eps;
  translate([-l + latch_thickness, -arm_thickness, 0])
    cube([l, latch_thickness, arm_width]);
}

// Latch slot. Substracted from arm1
module latch_slot() {
  translate([-latch_slot_thickness, 0, -eps])
    cube([latch_slot_thickness, arm_thickness, arm_width+2*eps]);

  translate([-latch_slot_length, 0, -eps])
    cube([latch_slot_length,
      latch_slot_thickness,
      arm_width+2*eps]);
}

module arm2() {
  // Arm
  translate([pivot_od/2+pivot_hspace, arm_space, 0])
    hull() {
      l = arm_length - pivot_od/2 - pivot_hspace;

      translate([l-1, arm_thickness-1, 0])
      cube([1, 1, arm_width]);

      translate([l-arm2_end_radius-arm2_end_slop, arm2_end_radius, 0])
        cylinder(r=arm2_end_radius, h=arm_width);

      cube([eps, arm_thickness, arm_width]);
    }

    // Add ridge
    translate([pivot_od/2+pivot_hspace + arm2_end_radius,
      arm_space+eps, arm_width/2])
        rotate([90, 0, 0])
           ridge(ridge_height, arm_length-pivot_od/2-pivot_hspace-2*arm2_end_radius-arm2_end_slop);

   // Add pivote cylnder
   cylinder(d=pivot_id-2*pivot_hspace, h=arm_width);

   difference() {
     // Add ,,,
     hull() {
       cylinder(d=pivot_id-2*pivot_hspace, h=arm_width);

       translate([pivot_od/2+pivot_hspace, arm_space, 0])
       cube([eps, arm_thickness, arm_width]) ;
     }

   // Substract ...
   translate([0, 0, -eps])
     cylinder(
        d=pivot_od+2*pivot_hspace,
        h=pivot_wall+pivot_vspace+eps);

   // Substract ...
   translate([0, 0, arm_width-pivot_wall-pivot_vspace])
     cylinder(
       d=pivot_od+2*pivot_hspace,
       h=pivot_wall+pivot_vspace+eps);
  }
}

module ridge(h, l) {
  hull() {
    translate([0, -h, 0])
      cube([l, 2*h, eps]);

    translate([0, -eps, -eps])
      cube([l, 2*eps, h]);
  }
}

module main() {
  arm1();
  rotate([0, 0, 45]) arm2();
}

// A library module to inset the first layer to avoid
// 'elephant foot'.
module inset_bottom(w=0.4, h=0.2, bounding_size = 200, eps=0.01) {
  if (w <= 0 || h < 0) {
    children();
  } else {
    // The top part of the children without the inset layer.
    difference() {
      children();
      // TODO: use actual extended children projection instead
      // of a clube with arbitrary large x,y values.
      translate([0, 0, -9*h])
          cube([bounding_size, bounding_size, 20*h], center=true);
    }
    // The inset layer.
    linear_extrude(height=h+eps) offset(r = -w) projection(cut=true)
      children();
  }
}

// Adjust main to printing position and inset first
// layer.
inset_bottom(w=first_layers_inset_width, h=first_layers_inset_height)
  translate([arm_length/2, 0, arm_width-eps])
  rotate([0, 180, 0])
  main();

```


[User]
I'm looking to create a parametric, customizable sample spool holder for 3D printer filament. I'd like it to be based on the design of a three-armed spool, with a central hub and arms extending outwards to support the filament. I've seen a few different designs, but I want to be able to adjust the dimensions for various sample sizes.

Here are the key parameters I need to be able to control:

*   **Hub Hole Diameter:** The diameter of the central hole in the hub (where it might mount on something).
*   **Hub Width:**  The width or thickness of the main disc part of the hub.
*   **Hub Wall Height:** The height of the raised wall part of the hub.
*   **Arm Diameter:** The diameter of the curved section of the arm.
*   **Spool Outer Diameter:** This will determine the overall size of the spool and the length of the arms; it's the diameter where the arms begin from the hub.
*   **Wall Thickness:** The thickness of most of the parts, like the hub walls and arm sections.
*   **Number of Arms:** The number of arms extending out from the hub (I'm starting with three, but I may want to experiment with more).
*   **Filament Diameter:**  The diameter of the filament for which the holes in the arms need to be sized.

I need the design to be printable without supports. The arms should attach to the hub with M3 bolts. I would like to have holes in the arms to secure the ends of the filament, angled to hold them in place and sized to the filament diameter parameter.  I'd also like the design to be modular so that I can easily generate just the hub, just an arm, or the whole assembled spool if desired.

Could you generate the OpenSCAD files to accomplish this? I don't need it to use any special libraries or anything, just the basic OpenSCAD language is fine.

[Assistant]
SimpleSampleSpool.scad:
```
/*----------------------------------------------------------------------------
 * Customisable three-armed spool holder for samples.
 * Created by FeNi64
 * Version 1.0, 2018-03-23
 * Inspired by https://www.thingiverse.com/thing:2033513
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License,
 * LGPL version 2.1, or (at your option) any later version of the GPL.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *		2018. License, GPL v2 or later
 *----------------------------------------------------------------------------*/

// Display which part(s)?
show=3; //  [1:Hub,2:Arm,3:All]

// Hub hole diameter
hole_d=52; // [5:90]

// Width of hub disc
hub_w=20;  // [10:99]

//  Height of hub wall
hubwall=15; // [10:99]

// Length and diameter of arms.
arc_d=20; // [10:99]

// Diameter of the spool of filament (arms start here)
outer=140; // [50:200]

// Thickness of most things
wall=1.2; // [1:0.1:5]

// Number of arms
armcount=3; // [3:9]

/* [Hidden] */
M3=3.2;
$fn=60;
armangle=360/armcount;
arm_l=(outer-hole_d-2*hubwall)/2;

if (show==1) {
    Hub();
} else if(show==2) {
    translate([0,5,0])arm();
} else if (show==3) {
    //color("blue")
       Hub();
    for(a=[0:armangle:360]) {
	rotate([0,0,a])
	    translate([hole_d/2+wall+(hubwall-wall)/2,wall/2,(hubwall-wall)/2+wall+0.5]) rotate([90,0,0])
	    arm() ;
    }
}

module Hub() {
    difference() {
	union() {
	    cylinder(h=wall,d=hole_d+hub_w);
	    cylinder(h=hubwall,d=hole_d + 2 * wall);

	    for(a=[0:armangle:360]) {
		rotate([0,0,a])
		    translate([hole_d/2,-hubwall/2,0])
		    difference() {
			cube([hubwall,hubwall,hubwall]);
			translate([-1,(hubwall-wall)/2-1,-1])cube([hubwall+wall,wall+2,hubwall+2]);
			// Minus the hole for the M3 bolt.
			translate([hubwall/2+wall,5*hubwall,hubwall/2+wall])rotate([90,0,0]) cylinder(h=10*hubwall,d=M3);

		    }
	    }

	}
	translate([0,0,-25]) cylinder(h=wall+50,d=hole_d);
    }
}

module arm() {
    difference() {
	hull() {
	    cylinder(h=2*wall,d=hubwall-wall-1);
	    translate([arm_l,-(hubwall-wall)/2,0])cube([2*wall,hubwall-wall,2*wall]);
	}
	// Minus the hole for the M3 bolt.
	translate([0,0,-hubwall]) cylinder(h=2*hubwall,d=M3);
    }
    x=arm_l+arc_d*2;
    translate([x,0,-(hubwall-wall)/3])rotate([0,0,0])scale([2.0,1.0,1.0]) arc(2*wall,hubwall-wall,arc_d,180);
}

/* module arc()
 * Excerpt from...
 *
 * Parametric Encoder Wheel
 *
 * by Alex Franke (codecreations), March 2012
 * http://www.theFrankes.com
 *
 * Licenced under Creative Commons Attribution - Non-Commercial - Share Alike 3.0
 */

module arc( height, depth, radius, degrees ) {
    // This dies a horible death if it's not rendered here
    // -- sucks up all memory and spins out of control
    render() {
	difference() {
	    // Outer ring
	    rotate_extrude($fn = 100)
		translate([radius - height, 0, 0])
		square([height,depth]);

	    // Cut half off
	    translate([0,-(radius+1),-.5])
		cube ([radius+1,(radius+1)*2,depth+1]);

	    // Cover the other half as necessary
	    rotate([0,0,180-degrees])
		translate([0,-(radius+1),-.5])
		cube ([radius+1,(radius+1)*2,depth+1]);

	}
    }
}

```
SimpleSampleSpoolV2.scad:
```
/*----------------------------------------------------------------------------
 * Customisable three-armed spool holder for samples.
 * Created by FeNi64
 * Version 2.0, 2018-03-28
 * Inspired by https://www.thingiverse.com/thing:2033513
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License,
 * LGPL version 2.1, or (at your option) any later version of the GPL.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *		2018. License, GPL v2 or later
 *----------------------------------------------------------------------------*/

// Display which part(s)?
show=1; //  [1:Hub,2:Arm,3:All]

// Hub hole diameter
hole_d=33; // [5:90]

// Width of hub disc
hub_w=20;  // [10:99]

//  Height of hub wall
hubwall=15; // [10:99]

// Length and diameter of arms.
arc_d=30; // [10:99]

// Diameter of the spool of filament (arms start here)
outer=140; // [50:200]

// Thickness of most things
wall=1.2; // [1:0.1:5]

// Number of arms
armcount=3; // [3:9]

// Filament diameter
filament_d=1.75; // [1.75:2,3.00:3.25]

/* [Hidden] */
M3=3.2;
$fn=60;
armangle=360/armcount;
arm_l=(outer-hole_d-2*hubwall)/2;

if (show==1) {
	Hub();
} else if(show==2) {
	translate([0,5,0])arm();
} else if (show==3) {
	//color("blue")
	Hub();
	for(a=[0:armangle:360]) {
		rotate([0,0,a])
			translate([hole_d/2+wall+(hubwall-wall)/2,wall/2,(hubwall-wall)/2+wall+0.5]) rotate([90,0,0])
			arm() ;
	}
}

module Hub() {
	difference() {
		union() {
			cylinder(h=wall,d=hole_d+hub_w);
			cylinder(h=hubwall,d=hole_d + 2 * wall);

			for(a=[0:armangle:360]) {
				rotate([0,0,a])
					translate([hole_d/2,-5*wall/2,0])
					difference() {
						cube([hubwall,7*wall,hubwall]);
						translate([-1,3*wall-1,-1])cube([hubwall+wall,wall+2,hubwall+2]);
						// Minus the hole for the M3 bolt.
						translate([hubwall/2+wall,5*hubwall,hubwall/2+wall])rotate([90,0,0]) cylinder(h=10*hubwall,d=M3);

					}
			}

		}
		translate([0,0,-25]) cylinder(h=wall+50,d=hole_d);
	}
}

module arm() {
	// The straight bit
	difference() {
		hull() {
			cylinder(h=2*wall,d=hubwall-wall-1);
			translate([arm_l,-(hubwall-wall)/2,0])cube([2*wall,hubwall-wall,2*wall]);
		}
		// Minus the hole for the M3 bolt.
		translate([0,0,-hubwall]) cylinder(h=2*hubwall,d=M3);

		// Some filament-end holes, at an angle so it bites.
		rotate([45,0,0])translate([arm_l*8/10,0,-10])cylinder(h=wall+30,d=filament_d);
	}
	// The curved bit
	x=arm_l+arc_d-2*wall; // Place it such that the inside arc touches the arm's end.
	translate([x,0,-(hubwall-wall)/3])rotate([0,0,0])scale([2.0,1.0,1.0]) arc(2*wall,hubwall-wall,arc_d/2,180);
}

/* module arc()
 * Excerpt from...
 *
 * Parametric Encoder Wheel
 *
 * by Alex Franke (codecreations), March 2012
 * http://www.theFrankes.com
 *
 * Licenced under Creative Commons Attribution - Non-Commercial - Share Alike 3.0
 */

module arc( height, depth, radius, degrees ) {
	// This dies a horible death if it's not rendered here
	// -- sucks up all memory and spins out of control
	render() {
		difference() {
			// Outer ring
			rotate_extrude($fn = 100)
				translate([radius - height, 0, 0])
				square([height,depth]);

			// Cut half off
			translate([0,-(radius+1),-.5])
				cube ([radius+1,(radius+1)*2,depth+1]);

			// Cover the other half as necessary
			rotate([0,0,180-degrees])
				translate([0,-(radius+1),-.5])
				cube ([radius+1,(radius+1)*2,depth+1]);

		}
	}
}

```


[User]
I need a parametric OpenSCAD design for a customizable inline pulley, something like the one I saw on Thingiverse, "No_Jam_Pulley_Customizable_inline". The core idea is a pulley that can function either as an idler or a loft block. I'd like the design to be flexible enough to adjust for different bearing sizes and mounting options. The key features should include a flanged outer section, a central groove to house the bearing, and a way to secure it all together. Let's break it down:

**Key Features and Parameters:**

*   **Bearing:**
    *   `bearing_diameter`: External diameter of the bearing (e.g., 22mm).
    *   `bearing_height`: Height of the bearing (e.g., 7mm).
    *   `bearing_hole`: Inner diameter of the bearing (e.g., 8mm).
*  **Flanges:** I want two outer flanges, mirroring each other, which extend past the bearing area. These flanges will also be where the tie holes are located and will be countersunk.
*   **Pulley Groove (Gola):** The groove itself should be sized to accommodate the bearing with a little extra space so it doesn't bind.
*   **Plate:** Base plate or optional frame for additional mounting. I imagine this will need a size parameter.
    *   `plate_side`: The side length of the base plate (e.g., 100mm)
* **Tie Hole:** One or more holes for securing the pulley to a frame.
    *   `tie_hole_diameter`: Diameter of the tie hole (e.g., 8mm)
    *   `tie_hole_offset`: Distance of the tie hole from the center of the pulley (e.g., `bearing_diameter*1.33`)
* **Sling Groove:** A cut-out section on the edge of the flange for a rope/sling.
    *   `sling_groove_radius`: Radius of the circular part of the sling groove (e.g., `bearing_hole/2.5`)
    *   `sling_groove_offset`: Distance of the center of the groove circle from the center of the pulley (e.g., `bearing_diameter*1.666`)
*   **Central Bolt Hole:** A through-hole in the center for a bolt if needed to secure through the bearing.
*   **Countersinking:** Be able to add countersinks on the tie holes for flat-head bolts.

**Modularity:**

*   I’d like the design to be modular, meaning I can generate just the "flange" component, just the "gola" component, or the entire assembled pulley.
*   Could you generate the OpenSCAD code so that I have a variable, say `part`, that allows me to choose between `"flange"`, `"gola"`, or `"all"`?

**Additional Notes:**

*   The original design has a support pad for the flange, can we make that a parameter?
*  I'd like to include the debugging functionality with the plate showing in grey, so I can see the size and location of my model.

I'm imagining a few .scad files. I anticipate needing files for just the main pulley design and potentially one for any mounting hardware. I don't need any files with predefined shapes; I'd like the entire design to be parametrically driven. I am familiar with OpenSCAD but don't have much experience using external libraries, so I would prefer to keep things vanilla if possible.

[Assistant]
No_Jam_Pulley_Customizable_inline.scad:
```
$fn = 100;

// Which one would you like to see?
part = "flangia"; // [flangia:Half Shell,gola:Bearing Dress,all:Complete Pulley]

// External bearing diameter in mm
bearing_diameter = 22; //[10:40]
// Bearing height in mm
bearing_height = 7; //[4:12]
// Bearing hole diameter in mm
bearing_hole = 8; //[4:12]

// Plate side in mm
plate_side = 100;

draw();

module draw() {
	if (part == "flangia") {
		translate([0,0,bearing_height]) flangia();
	} else if (part == "gola") {
		translate([0,0,bearing_height / 2]) gola();
	} else if (part == "all") {
		translate([0,0,bearing_height]) {
			flangia();
			gola();
			rotate([180,0,0]) flangia();
		}
	} else {
		translate([0,0,bearing_height]) {
			flangia();
			gola();
			rotate([180,0,0]) flangia();
		}
	}
	%translate([0,0,-1]) cube([plate_side,plate_side,2], center=true);
}
module flangia() {
	union() {
		difference() {
            union() {
                difference() {
                    translate([0,0,-bearing_height/2]) hull() {
                        translate([bearing_diameter*1.33,0,0]) cylinder(d=bearing_diameter, h=bearing_height, center=true);
                        cylinder(d=bearing_diameter*1.5, h=bearing_height, center=true);
                    }
                    translate([-bearing_diameter/3,0,0]) cylinder(d=bearing_diameter*5.5, h=bearing_height*0.75, center=true);
                }
                //New support pad.
                translate([bearing_diameter*1.33,0,-bearing_height/2]) cylinder(d=bearing_diameter, h=bearing_height, center=true);
            }
			//Drill tie hole
            translate([bearing_diameter*1.33,0,-5]) cylinder(d=bearing_hole, h=bearing_height*5, center=true);
            //Countersink tie hole
			translate([bearing_diameter*1.33,0,-bearing_height]) cylinder(d1=bearing_hole*1.5, d2=bearing_hole, h=bearing_height/2, center=true);
			//Drill shiv hole
            translate([0,0,0]) cylinder(d=bearing_diameter*1.375, h=bearing_height*1.25, center=true);
			//Drill bolt hole
            translate([0,0,0]) cylinder(d=bearing_hole, h=bearing_height*5, center=true);

            //cut sling groove
			translate([bearing_diameter*1.666, 0, -bearing_height/4]) rotate([90,0,0]) rotate_extrude(convexity = 10) translate([bearing_height*0.9, 0, 0]) scale([0.8,1,1]) circle(r = bearing_hole/2.5);
		}

        //Build bearing land.
		difference() {
			translate([0,0,-bearing_height/1.6]) cylinder(d=bearing_hole*1.75, h=bearing_height/4, center=true);
			translate([0,0,0]) cylinder(d=bearing_hole, h=bearing_height*5, center=true);
		}
	}
}

module gola() {
	difference() {
		cylinder(h=bearing_height, d=bearing_diameter*1.3, center=true);
		cylinder(h=bearing_height*2, d=bearing_diameter*1.01, center=true);
		rotate_extrude($fn=100, convexity = 10) translate([bearing_diameter/1.5, 0, 0]) scale([0.5, 1]) circle(d = bearing_height*0.875);
	}
}
```


[User]
Hey, I'm trying to make a sort of 3D printing jig for printing on tulle, you know, that kind of mesh fabric. I have a single STL file of a small, complex shape that I want to duplicate in a grid pattern to print directly on the tulle. I was hoping you could help me make an OpenSCAD script to do this.

Specifically, I need the script to be parametric, allowing me to set:

*   The number of rows of the object.
*   The number of columns of the object.
*   The spacing between the objects.

I'm starting with a single STL file that has been specifically designed to be printed onto tulle. The user will be expected to provide this file, and then specify the dimensions listed above.

I want the object to be laid out in a rectangular array on the XY plane, and not rotated.

Ideally, the code should be well-commented, just so it's easier for me to understand what's going on. I don't have a preference for a library, so it doesn't matter which one you choose to use. It's fine if you don't need a library at all.

Thanks so much for your help!

[Assistant]
PrintonTulle_1.scad:
```
// preview[view:south, tilt:top]
/* [Part1] */
/* [Globa] */
Rows = 5;
Columns = 4;
Distance_inbetween = 25;

/* [hidden] */

rectangular_array(Rows,Columns,Distance_inbetween) import("PrintonTulle_#1.stl");

module rectangular_array (rows,cols,distance){
    for( i = [0:1:rows-1]){
        for (j = [0:1:cols-1]){
            translate([distance*i,distance*j,0])
            children();
        }
    }
}
```


[User]
Hi, I'm looking to create a set of parametric drawer inserts for empty filament spools, similar to what's described in the `SpoolDrawers.scad` file I've included, but I need a more advanced and flexible system. I really like the idea of using the empty spools for storage, but the current implementation seems a little limited in the drawer layouts. I want to be able to create more complex drawer configurations than just a simple circle around the spool.

Here's what I'm envisioning:

**Core Functionality:**

*   **Spool Dimensions:** I need to be able to define the inner and outer diameters of the spool, the height between the spool walls (where the drawers go), the spool wall width, and the diameter of the center hole of the spool. This should all be parametric, just like the current design.
*   **Drawer Shape Flexibility:** I want to be able to create drawer shapes beyond just the arc-shaped drawers. I'd like options for rectangular drawers, and ideally, I'd like to be able to define the start and end angles of the drawers to allow for gaps or drawers that only cover part of the circumference. It'd also be great if I could combine rectangular drawers with arc drawers within the same layer, and define both types per drawer.
*   **Multi-Layer Support:** I want support for multiple layers of drawers (more than just two), each with potentially different heights and layouts. I also need to be able to specify a gap between the layers.
*   **Customizable Drawer Details:** I want to control the drawer wall thickness, bottom thickness, the size and placement of the hinge pins and their housing, and the presence of a handle or finger notch. I would like to be able to define the type of hinge (pin, clip, or none) per drawer
*   **Advanced Layout Options:** I would like to be able to specify the number of drawers per layer or, alternatively, define the angle of each individual drawer and create drawers of arbitrary size around the circumference.
*   **Assembly Preview:** It should have an assembly preview that includes the spool and the drawers, and the ability to simulate opening drawers at a specified angle. Also, the ability to visualize individual drawers for a "print" mode and generate a simple outline for the outer perimeters.
*   **Hinge and Template Generation:**  I need a template generation for hinge holes and the ability to generate printable tester outlines for the drawers, like the `SpoolDrawers.scad`.
*  **Color and Transparency** Support for applying color to both the spool and drawers, and ideally also specify transparency.
*  **Custom Modules** The ability to define custom modules that can be included in the drawer construction, to allow for features like dividers, or angled surfaces on the drawers.

**Specific Requests**
*   Use a single .scad file to avoid having to switch between files.
*   Use comments that explain the different parameters and sections.

**Libraries:**
I'm not using any libraries, but perhaps you could include `BOSL` for some additional functionality, if you think it would be helpful.

Essentially, I need a fully parametric system that allows me to create a wide range of drawer layouts in my empty spools and provides a way to test the designs before printing. I'd like the code to be well-structured and easy to modify later.  I am looking for something significantly more flexible and powerful than the initial `SpoolDrawers.scad` example I gave. Thank you.

[Assistant]
SpoolDrawers.scad:
```
/*
 * Customizable drawers for use in empty filament spools.
 *
 * Features:
 *  * Supply spool dimensions to make drawer sizing and preview easy
 *  * Allows 2 to 5 equal sized drawers per layer
 *  * Can have 1 or 2 layers, with different drawer heights per layer.
 *  * Allows adjusting the drawer wall and bottom thickness
 *  * Has an assembly preview option to get an idea of the final assembly.
 *  * Can simulate opening one drawer for visual help, or to test clearances -
 *    with equal sized drawers, 5 per layer is about as much as is possible
 *    before drawers starts interfering.
 *  * With multi layer option selected and drawers of different height, both
 *    drawers will be drawn in print mode.
 *  * Can generate a thin tester outline of the drawer to test fit the spool
 *    before final print.
 *  * Can generate a template for exact drilling of the hinge holes in the
 *    spool. See notes below.
 *
 * -----------
 * Note on the template option:
 * The SVG and DFX exports in the current nightly build of OpenSCAD I'm using
 * does not seem to be working, so the only way to use the template from here
 * is to export as STL and then import into some 3D CAD program, like FreeCAD,
 * generate a solid from the STL, and then a top view drawing. This drawing can
 * then be exported to PDF and printed on paper. Hope this would be easier in a
 * future version of OpenSCAD :-)
 * -----------
 *
 *
 * Thanks to keynes87 (https://www.thingiverse.com/keynes87) for his excellent
 * modules to draw the drawers in his thing here: https://www.thingiverse.com/thing:2142608
 * This thing grew out of his design!
 *
 * Author : Tom Coetser (Fitzterra) <fitzterra@icave.net>
 *
 * License:
 * This work is licensed under the Creative Commons Attribution 3.0 Unported
 * License. To view a copy of this license, visit
 * http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
 * Commons, PO Box 1866, Mountain View, CA 94042, USA.
 *
 *
 * ToDo:
 *  - Allow different size drawers around the circumference. The current
 *    customizer componets for variable definition is a bit limiting, so maybe
 *    another day.
 *
 * Releases:
 *  v1.0 - Initial release, but did not contain version numberthen
 *  v1.1 - Fixed bug in generating the hinge holes and add option for finger
 *         notch instead of handle. With the changes in the hinge hole
 *         generation, drawers created with the same parameters in v1.0 will
 *         **not** align with v1.1 and later drawers!
 */

/* [Hidden] */
version = "v1.1";

/* [ General parameters ] */
// Granularity for mainly hinge chamber cylinder and handle rounded edge.
$fn = 120;
// What to generate? The template can be used to drill holes for the hinge shafts.
mode = "assembly"; // [assembly, print, tester, template1, template2, template3]
// Show the spool in assembly mode?
showSpool = true;
// Project templates in 2D to enable export as SVG or DXF?
template2D = false;

/* [ Spool dimensions ] */
// Spool inner diameter.
spoolID = 60;
spoolIR = spoolID/2;
// Spool outer diameter.
spoolOD = 200;
spoolOR = spoolOD/2;
// Spool inner height between walls - max drawer height. Always measure height at spool inner hub!
spoolIH = 60;
// Spool wall width.
spoolWW = 4;
// Spool hub inner diameter - diameter of hole in spool center.
spoolHubID = 54;
// Spool color - See OpenSCAD color transformation for color names.
spoolColor = "DimGray";
// Spool color alpha - For transparent spool holders (does not render 100% as expected :-( )
spoolColorAlpha = 1.0; // [0.0:0.05:1.0]

/* [ Drawer Base ] */
// Drawer height - leave 0 to use spoolIH and 1mm clearance.
drawHeight = 0;
// Drawer wall width.
drawWW = 3;
// Drawer bottom thickness.
drawBT = 3;
// Drawer hinge pin outer diameter.
hingePinOD = 5;
// Hinge pin housing outer diameter.
hingeHousingOD = hingePinOD+3;
// Drawers Color - See OpenSCAD color transformation for color names.
drawColor = "RoyalBlue";

/* [ Drawer Configuration ] */
// Number of drawers around circumference. Min 2, max 5.
numDrawers = 4; // [2:1:5]
// Add another layer of drawers if drawHeight < spoolIH?
dualLayer = true;
// Gap between dual layers
layersGap = 1;
// Handle or finger notch to open drawer with
handle = false;
// Angle to open one drawer for testing in assembly mode
openAngle = 10; // [0:5:90]

// Full height or drawer height
dHeight = drawHeight==0 ? spoolIH-1 : drawHeight;
// Height for 2nd layer of drawers if dualLayer is true and there is enough
// space in the spool inner height after subtracting the base drawer height and
// the fill gap.
d2Height = dualLayer ? ( (dHeight+layersGap)<spoolIH ? spoolIH-(dHeight+layersGap) : 0) : 0;
if(d2Height) {
    echo("Bottom layer drawers height: ", dHeight);
    echo("Second layer drawers height: ", d2Height);
} else {
    echo("Drawer height: ", dHeight);
}

// Angle per drawer
drawerAngel = 360/numDrawers;

module arc(spoolOR, spoolIR, angle) {
    points_outer= [
        for(a = [0:1:angle]) [spoolOR * cos(a), spoolOR * sin(a)]
    ];
    points_inner= [
        for(b = [0:1:angle]) [spoolIR * cos(b), spoolIR * sin(b)]
    ];
    difference() {
        polygon(concat([[0, 0]], points_outer));
        polygon(concat([[0, 0]], points_inner));
        translate([spoolOR-hingeHousingOD/2,hingeHousingOD/2,0])
            circle(hingePinOD/2);
        translate([spoolOR-hingeHousingOD/2,0,0])
            square(hingeHousingOD/2);
    }
}

module shell(angle) {
    difference() {
        arc(spoolOR, spoolIR, angle);
        offset(-drawWW)
            arc(spoolOR, spoolIR, angle);
    }
}

module handle(angle) {
    translate([spoolOR*cos(angle)+drawWW*2*cos(angle-90),
               spoolOR*sin(angle)+drawWW*2*sin(angle-90),
               1])
        rotate(angle)
            offset(drawWW)
                square([10,drawWW]);
}

module screw(){
    difference() {
        circle(d=hingeHousingOD);
        circle(d=hingePinOD);
    }
}

module drawer(angle, height) {

    fnd = 25;
    difference() {
        union() {
            // The floor
            linear_extrude(drawBT)
                arc(spoolOR, spoolIR, angle);
            // Walls
            linear_extrude(height)
                shell(angle);
            // Rounded screw chamber
            translate([spoolOR-hingeHousingOD/2,hingeHousingOD/2,0])
                linear_extrude(height)
                    screw();
            // Drawer handle
            if(handle)
                linear_extrude(height)
                    handle(angle);
        }
        // Finger notch if no handle
        if(!handle && height>(fnd/2))
            rotate([0, 0, drawerAngel-12])
            translate([spoolOR+spoolWW/2, 0, height+fnd/10])
                rotate([0, -90, 0])
                    cylinder(d=fnd, h=spoolWW*2);
    }
}

module spool() {
    color(spoolColor, spoolColorAlpha)
    difference() {
        union() {
            // Center cylinder
            cylinder(d=spoolID, h=spoolIH);
            // Walls
            for(z=[-spoolWW, spoolIH])
                translate([0, 0, z])
                    cylinder(d=spoolOD, h=spoolWW);
        }
        translate([0, 0, -spoolWW-0.1])
            cylinder(d=spoolHubID, h=spoolIH+spoolWW*2+0.2);
    }
    // Hinge holes
    color("silver")
    for (n=[0:drawerAngel:359])
        rotate([0, 0, n])
            translate([spoolOR-hingeHousingOD/2, hingeHousingOD/2, -spoolWW-0.1])
                cylinder(d=hingePinOD, h=spoolIH+spoolWW*2+0.2);
}

module holesTemplate() {
    difference() {
        // Wall
        cylinder(d=spoolOD, h=1);
        // Center hole
        translate([0, 0, -0.1])
            cylinder(d=spoolHubID, h=1.2);
        // Hinge holes
        for (n=[0:drawerAngel:359])
            rotate([0, 0, n])
                translate([spoolOR-hingeHousingOD/2, hingeHousingOD/2, -0.1])
                    cylinder(d=hingePinOD, h=1.2);
    }
}

module holesTemplate2() {
    th = 1.2;
    for (n=[0:drawerAngel:359])
        rotate([0, 0, n])
            difference() {
                hull() {
                    cylinder(d=3, h=th);
                    translate([spoolOR-hingeHousingOD/2, hingeHousingOD/2, 0])
                        cylinder(d=hingePinOD+3, h=th);
                }
                translate([spoolOR-hingeHousingOD/2, hingeHousingOD/2, -0.1])
                    cylinder(d=2, h=th+0.2);
            }
    difference() {
        cylinder(d=spoolHubID+4, h=th);
        translate([0, 0, -0.1])
            cylinder(d=spoolHubID, h=th+0.2);
    }
    difference() {
        cylinder(d=spoolOD/1.5+4, h=th);
        translate([0, 0, -0.1])
            cylinder(d=spoolOD/1.5, h=th+0.2);
    }
}

module holesTemplate3() {
    difference() {
        holesTemplate();
        translate([0, 0, -0.1])
            cylinder(r=spoolOR-hingeHousingOD, h=2);
    }
}

module drawersLayer(height) {
    for (n=[drawerAngel:drawerAngel:359])
        rotate([0, 0, n])
            drawer(drawerAngel-1, height);

    translate([spoolOR-hingeHousingOD/2, hingeHousingOD/2, 0])
        rotate([0, 0, -openAngle])
            translate([-spoolOR+hingeHousingOD/2, -hingeHousingOD/2, 0])
                drawer(drawerAngel-1, height);
}

// Only show the spool in assembly mode if required
if(showSpool && mode=="assembly")
    spool();

if(mode=="assembly") {
    // Base layer of drawers
    color(drawColor)
    drawersLayer(dHeight);
    if (d2Height)
        translate([0, 0, dHeight+layersGap])
            color(drawColor)
            drawersLayer(d2Height);
} else if(mode=="print") {
    translate([0, -spoolIR*cos(drawerAngel/2), 0])
        rotate([0, 0, 90-drawerAngel/2])
            drawer(drawerAngel-1, dHeight);
    if (d2Height)
        translate([0, -spoolOR, 0])
            rotate([0, 0, 90-drawerAngel/2])
                drawer(drawerAngel-1, d2Height);
} else if(mode=="template1") {
    if (template2D==true) {
        projection()
            holesTemplate();
    } else {
       holesTemplate();
    }
} else if(mode=="template2") {
    if (template2D==true) {
        projection()
            holesTemplate2();
    } else {
       holesTemplate2();
    }
} else if(mode=="template3") {
    if (template2D==true) {
        projection()
            holesTemplate3();
    } else {
       holesTemplate3();
    }
} else if(mode=="tester") {
    difference() {
        translate([0, -spoolIR*cos(drawerAngel/2), -drawBT-0.1])
            rotate([0, 0, 90-drawerAngel/2])
                drawer(drawerAngel-1, drawBT+1.1);
        translate([0, 0, -drawBT-1])
            cylinder(d=spoolOD*1.5, h=drawBT+1.1);
    }
}

```


[User]
Hi, I'm looking for an OpenSCAD design for a nut driver, but with a twist – it needs to have a feature to help remove the nuts after they're screwed in. I'd like it to be parametric so I can adjust it for different nut sizes and screw lengths.

Specifically, here's what I'm thinking:

*   **Nut Driver Body:** A cylindrical handle with a hexagonal socket at the end to grip the nut. I need to be able to specify the handle diameter and the nut diameter. The height of the handle should also be adjustable.
*   **Screw Length:** The hexagonal socket should extend a specified length into the driver, which would be the length of the screw.
*   **Remover Feature:** This is the tricky bit. If enabled, I'd like a simple "pusher" feature – a rod that can slide into the socket and push the nut out. This would be separate from the main driver body and could be a rod extending from a small handle. This handle should be offset from the main handle.

**Parameters I need to control:**

*   `printer_accuracy`: To account for my 3D printer's tolerances.
*   `remover`: A boolean option to enable/disable the remover feature.
*   `height`: The height of the main handle.
*   `nut_diameter`: The outer diameter of the nuts I'll be using.
*   `Main_diameter`: The diameter of the main handle.
*   `screw_lengh`: The length of the screws.

It would be really helpful if the design used $fn for circular segments. I'm also not particular about which OpenSCAD libraries are used, if any, as long as the code works and is clearly written. It would be amazing to have this as an entirely new design from scratch. Thanks!

[Assistant]
Nut_screwer_with_remover.scad:
```
// The accuracy of your printer
printer_accuracy = 0.2;
// If you need aremover for the nuts
remover = "yes";//[yes,no]
// height of the holder in mm
height = 20;
// Outer diameter of your nuts in mm
nut_diameter = 3;
// Diameter of the handle in mm
Main_diameter = 8;
// Lengh of the screws you want to secrew your nuts on in mm
screw_lengh = 15;
if (remover == "yes") {
  union(){
    difference() {
      union(){
        linear_extrude( height=height, twist=0, scale=[1, 1], center=false){
          {
            $fn=6;    //set sides to 6
            circle(r=Main_diameter);
          }
        }
        translate([0, 0, height]){
          difference() {
            linear_extrude( height=screw_lengh, twist=0, scale=[1, 1], center=false){
              {
                $fn=6;    //set sides to 6
                circle(r=(nut_diameter + 2));
              }
            }

            linear_extrude( height=screw_lengh, twist=0, scale=[1, 1], center=false){
              {
                $fn=6;    //set sides to 6
                circle(r=nut_diameter);
              }
            }
          }
        }
      }

      {
        $fn=50;    //set sides to 50
        cylinder(r1=(2 + printer_accuracy), r2=2, h=100, center=false);
      }
    }
    translate([(Main_diameter + 10), 0, 0]){
      union(){
        linear_extrude( height=3, twist=0, scale=[1, 1], center=false){
          {
            $fn=6;    //set sides to 6
            circle(r=Main_diameter);
          }
        }
        {
          $fn=50;    //set sides to 50
          cylinder(r1=2, r2=2, h=(height + (screw_lengh - 1)), center=false);
        }
      }
    }
  }
} else {
  union(){
    linear_extrude( height=height, twist=0, scale=[1, 1], center=false){
      {
        $fn=6;    //set sides to 6
        circle(r=Main_diameter);
      }
    }
    translate([0, 0, height]){
      difference() {
        linear_extrude( height=screw_lengh, twist=0, scale=[1, 1], center=false){
          {
            $fn=6;    //set sides to 6
            circle(r=(nut_diameter + 2));
          }
        }

        linear_extrude( height=screw_lengh, twist=0, scale=[1, 1], center=false){
          {
            $fn=6;    //set sides to 6
            circle(r=nut_diameter);
          }
        }
      }
    }
  }
}

```


[User]
I need a customizable OpenSCAD design for a flower-shaped knob. It should be parametric, allowing me to easily adjust the height, diameter, number of petals, the rounding radius on the corners, and how bulgy or flat the petals are.

Specifically, I need these parameters:

*   `height`: The overall height of the knob (e.g., 8mm)
*   `diameter`: The approximate diameter of the knob (e.g., 30mm)
*   `numberOfPetals`: The number of petals the knob has (e.g., 6)
*   `roundingRadius`: The radius of the corner rounding (e.g., 2mm)
*   `curvatureFactor`: A value that determines how bulgy or flat the petals are. This can be negative or positive. Zero would be flat, positive values make the petals bulge outward, and negative values make them curve inward.

The final design should create a knob with a cylindrical base, and the petals should be created by adding bumps and dents around that base. The bumps and dents should be rounded on the edges according to the `roundingRadius` and the bulginess should be adjustable with the curvature factor. The `curvatureFactor` should affect the angles and positions of the petals.

Also, the design should be suitable for 3D printing, so try to keep the generated shapes clean and relatively simple. I'm not looking for super complex geometry here.

I will need a single .scad file with the function/module `flowerKnob(height, diameter, numberOfPetals, roundingRadius, curvatureFactor)` that generates the shape. I'd also like the example code to show how the module is used with the parameters.

[Assistant]
FlowerKnob.scad:
```

// Height of the knob
height = 8; // [4:30]

// Approximate diameter of the knob
diameter = 30; // [15:60]

// Number of petals of the knob
numberOfPetals = 6; // [3:10]

// Radius of the corner rounding
roundingRadius = 2; // [0:10]

// Bulginess/smoothness of the petals
curvatureFactor = 0; // [-2:0.1:2]

$fn = 40*1;

flowerKnob(height, diameter, numberOfPetals, roundingRadius, curvatureFactor);

module flowerKnob(height, diameter, numberOfPetals = 6, roundingRadius = 2, curvatureFactor = 0) {

    ff = 0.01; //fudge factor

    chordAngle = 180 / numberOfPetals;
    halfChord = sin(chordAngle / 2) * diameter / 2;
    chordDistance = pow(diameter * diameter / 4 - halfChord * halfChord, 1/2);

    curvatureAngle = chordAngle * curvatureFactor;

    dentpetalAngle = 180 - chordAngle + curvatureAngle;
    dentPetalRadius = halfChord / sin(dentpetalAngle / 2);
    rawDentPetalDistance = pow(dentPetalRadius * dentPetalRadius - halfChord * halfChord, 1/2);
    dentPetalDistance = rawDentPetalDistance * (dentpetalAngle <= 180 ? 1 : -1);

    bumpPetalAngle = 180 - chordAngle - curvatureAngle;
    bumpPetalRadius = halfChord / sin(bumpPetalAngle / 2);
    rawBumpPetalDistance = pow(bumpPetalRadius * bumpPetalRadius - halfChord * halfChord, 1/2);
    bumpPetalDistance = rawBumpPetalDistance * (bumpPetalAngle <= 180 ? 1 : -1);

    module roundedRect() {
        difference() {

            square([bumpPetalRadius,height]);

            translate([bumpPetalRadius - roundingRadius, 0])
                difference() {
                    square(roundingRadius);
                    translate([0, roundingRadius])
                        circle(roundingRadius);
                }

            translate([bumpPetalRadius - roundingRadius, height - roundingRadius])
                difference() {
                    square(roundingRadius);
                    circle(roundingRadius);

                }
        }
    }

    module hornedRect() {
        union() {

            square([dentPetalRadius,height]);

            translate([dentPetalRadius, 0])
                difference() {
                    square(roundingRadius);
                    translate([roundingRadius,roundingRadius])
                        circle(roundingRadius);
                }

            translate([dentPetalRadius, height - roundingRadius])
                difference() {
                    square(roundingRadius);
                    translate([roundingRadius,0])
                        circle(roundingRadius);

                }

            // ff
            translate([0, -ff])
                square([dentPetalRadius + roundingRadius,ff]);
            translate([0, height])
                square([dentPetalRadius + roundingRadius,ff]);

        }
    }

    module bump() {

            rotate_extrude( convexity=10)
                roundedRect();
    }

    module dent() {
            rotate_extrude(convexity=10)
                    hornedRect();
    }

    difference() {
        union() {
            cylinder(height,r=chordDistance+(dentPetalDistance+bumpPetalDistance)/2, $fn = numberOfPetals*2);

            for (i=[1:numberOfPetals])
                rotate([0, 0, chordAngle * 2 * i])
                    translate([chordDistance+bumpPetalDistance, 0, 0])
                        bump();
        }

        for (i=[1:numberOfPetals])
            rotate([0, 0, chordAngle * 2 * (i + 0.5)])
                translate([chordDistance+dentPetalDistance, 0, 0])
                    dent();
    }
}

```


[User]
Hey there, I'm looking for a parametric design for a coffee pod holder, and I'd like to use OpenSCAD. I really like the spiral design I saw on Thingiverse, but I want something more configurable. I'd like to be able to specify:

*   The number of pods the holder should store.
*   The overall rendering quality (low for previews, higher for final STL).
*   The number of legs for the base.
*   The angle of the legs relative to the horizontal plane, and the length of the legs.
*   The diameter of each leg.
*   The style of the feet - I want options for round, flat, or a 'frog' style which is flat with larger round ends, or even a hole for mounting.  If I choose the hole, I'd need to specify the diameter of that hole.
*   The diameter and height of the coffee pods it needs to hold (different pods, you know!).
*   A radius for the start of the spiral.
*  A fill quality setting - essentially how many support discs are printed between each pod holder.
*   The diameter of the center vertical support mast.
*   The shell thickness for the entire model, so I can adjust how robust it is.
*   The depth of a groove cut in each pod holder.

I'm looking for a design similar to the one I saw, which uses a spiral shape for the pod holders and a central mast supported by legs. The pod holders should be oriented at an angle. The base of the design should include legs which can be configured to use any of the specified feet types. The vertical mast connects to the base and supports the spiral. The spiral should start at a specific radius, then increase in radius and height as it goes upward, wrapping around the center mast. I need all the parameters I listed above to be user-configurable in the OpenSCAD file(s). I don't want any hardcoded values. Also, It would be great if the design was well-commented to make it easy to follow.  I'd also like a function for calculating the mast length and height as well as the angle of the pod holders.

I don't need any special libraries - just the core OpenSCAD functions.

I think that's everything, let me know if you have any questions.

[Assistant]
Spiral_Pod_Holder_v3.scad:
```
//User Inputs
/* [Global] */
//Number of pods to hold.
PODS = 12;		//[1:30]
//This sets the resolution of your 3D model - keep it at "Low" until you are ready to make your STL.
RENDER = 10;	//[10:Low, 40:STL]

/* [Base] */
//Number of legs
LEG_COUNT = 5;		//[3:11]
//Angle in degrees between XY plane and Leg
LEG_ANGLE = 5; 		//[45]
//Radius of circle that circumscribes legs
LEG_LENGTH = 55;	//[10:200]
//Radius of leg
LEG_DIAM = 12;		//[1:30]

/* [Feet] */
//Changes the style of feet. Frog and Flat settings print best. Use hole to make a mounting hole at the end of the feet.
FEET_TYPE = "frog";	//["round", "flat", "hole", "frog"]
//Sets diameter of hole, if feet type is "hole"
FEET_HOLE_DIAM = 4;	//[25]
//Diameter of the vertical shaft connecting the spiral and base.

/* [Spiral] */
//Diameter of your coffee pod
POD_DIAM = 32;		//[1:60]
//Height of your coffee pod
POD_HEIGHT = 30;	//[1:60]
//The starting radius of the spiral.
RADIUS_CONST = 64;	//[50:200]
//Represents the amount of fill between each pod holder
FILL_QUALITY = 1;	//[1:10]

/* [Advanced] */
MAST_DIAM = 12;	//[4:30]
//Wall thickness of entire model
SHELL = 1.6;	//[0.2:0.1:6]
//Depth of cut for the vertical groove across pod holders.
GROOVE	= 3;	//[0:30]

/* [Hidden] */
$fn = RENDER;		//Unit: fragments; controls render settings

//***See make_pod_tree for Spiral Input Variables***//

//Module Debugging
make_base();
make_pod_tree(RENDER,FILL_QUALITY + 1);

module make_base(){
	//MODULE VARIABLES
	mast_len = get_mast_len() +  sin(RING_ANGLE);		//Gets the distance from spiral to feet top
	angle = 360/LEG_COUNT;			//Angle between each leg
	mast_rise = get_mast_rise();
	leg_hypotenuse = LEG_LENGTH/cos(LEG_ANGLE);
	//Generate mast (center column)
	color("FireBrick") {
		union(){
			translate([0,0,mast_rise]) cylinder(d=MAST_DIAM, h=mast_len);
			make_legs(mast_rise,leg_hypotenuse,angle);
		}
	}
}

module make_legs(mast_rise=1, leg_hypotenuse=1, angle=90) {
	choice = FEET_TYPE =="round" ? 1:
	 FEET_TYPE == "flat" ? 2:
	 FEET_TYPE == "hole" ? 3:
	 FEET_TYPE == "frog" ? 4:
		//Default feet type is rounded
		1;
	//Round feet
	if(choice==1){
		for(i=[1:LEG_COUNT]){
			translate([0,0,mast_rise]) rotate([90+LEG_ANGLE,0,angle*i]) cylinder(d=LEG_DIAM,h=leg_hypotenuse);
			rotate([0,0,angle*i]) translate([0,-LEG_LENGTH,LEG_DIAM/2]) sphere(LEG_DIAM/2);
		}
	}
	//Flat bottom feet with round ends
	if(choice==2){
		for(i=[1:LEG_COUNT]){
			difference(){
				union(){
					translate([0,0,mast_rise]) rotate([90+LEG_ANGLE,0,angle*i]) cylinder(d=LEG_DIAM,h=leg_hypotenuse);
					rotate([0,0,angle*i]) translate([0,-LEG_LENGTH,0]) sphere(LEG_DIAM/2);
				}
				translate([0,0,-LEG_DIAM/2]) cylinder(r=leg_hypotenuse+LEG_DIAM,h=LEG_DIAM,center=true);
			}
		}
	}
	//Flat bottom feet with round ends and thru hole
	if(choice==3){
		for(i=[1:LEG_COUNT]){
			difference(){
				union(){
					translate([0,0,mast_rise]) rotate([90+LEG_ANGLE,0,angle*i]) cylinder(d=LEG_DIAM,h=leg_hypotenuse);
					rotate([0,0,angle*i]) translate([0,-LEG_LENGTH,0]) sphere(LEG_DIAM/2);
				}
				translate([0,0,-LEG_DIAM/2]) cylinder(r=leg_hypotenuse+LEG_DIAM,h=LEG_DIAM,center=true);
				rotate([0,0,angle*i]) translate([0,-LEG_LENGTH,-1]) cylinder(d=FEET_HOLE_DIAM, h=LEG_DIAM*2);
			}
		}
	}
	//Flat bottom feet with large round ends
	if(choice==4){
		for(i=[1:LEG_COUNT]){
			difference(){
				hull(){
					translate([0,0,mast_rise]) rotate([90+LEG_ANGLE,0,angle*i]) cylinder(d=LEG_DIAM,h=leg_hypotenuse);
					rotate([0,0,angle*i]) translate([0,-LEG_LENGTH,0]) scale([1,1,0.5]) sphere(LEG_DIAM);
				}
				translate([0,0,-LEG_DIAM/2]) cylinder(r=leg_hypotenuse+LEG_DIAM,h=LEG_DIAM,center=true);
			}
		}
	}
}

//SPIRAL ALGORITHM INPUTS
//Angle between axis of pod holder and vertical
RING_ANGLE = 45;		//Angle the ring faces upward
POD_CS = 8;				//Unit: mm; Outer diamer to inner diameter of hole
MAX_ROTATION = PODS*32 > 360? PODS*(POD_DIAM + SHELL) : 360;	//Number of rotations to perform
HOLE_TYPE = "ring";		//Unit: ring, sheet, octagon
START_HEIGHT = get_mast_len() + get_mast_rise();
//echo(START_HEIGHT);

module make_pod_tree(fn = 5, steps = 5){
	//MODULE VARIABLES
	STEP = steps;
	STEPS = STEP*PODS;
	difference(){
		for(i = [0:STEPS - STEP]){
			R = RADIUS_CONST + i * PODS/STEPS;
			TRANSLATION = [R*cos(i/(STEPS) * MAX_ROTATION), R*sin(i/(STEPS) * MAX_ROTATION), START_HEIGHT  + R/tan(RING_ANGLE) - i * START_HEIGHT/STEPS ];
			ORIENTATION = [RING_ANGLE, 0, face_normal(TRANSLATION)];	//Starting orientation in degrees
			translate(TRANSLATION) rotate(ORIENTATION)
			if(i%STEP == 0){
				make_pod_disc($fn = fn);
			}
			else{
				make_pod_disc_gap($fn = fn);
			}
		}

		for(i = [0:PODS-1]){
			R = RADIUS_CONST + i;
			TRANSLATION = [R*cos(i/(PODS) * MAX_ROTATION), R*sin(i/(PODS) * MAX_ROTATION), START_HEIGHT +R/tan(RING_ANGLE) - i * START_HEIGHT/PODS ];
			ORIENTATION = [RING_ANGLE, 0, face_normal(TRANSLATION)];	//Starting orientation in degrees
			translate(TRANSLATION) rotate(ORIENTATION) make_pod_cut(POD_HEIGHT);
		}
	}
}

module make_pod_disc(){
	//cylinder(d=POD_DIAM+POD_CS*2,h=SHELL,center=true);
	translate([0,0,-RADIUS_CONST*cos(RING_ANGLE)]) cylinder(r1=POD_DIAM/4 + SHELL, r2=POD_DIAM/2 + SHELL,h=RADIUS_CONST/cos(RING_ANGLE),center=true);
	translate([0,0,-RADIUS_CONST*1.4]) sphere(POD_DIAM/4 + SHELL);
}
module make_pod_disc_gap(){
	//cylinder(d=POD_DIAM+POD_CS*2,h=SHELL,center=true);
	R1 = POD_DIAM/5 + SHELL;
	R2 = POD_DIAM/3 + SHELL;
	H = 0.8*(RADIUS_CONST/cos(RING_ANGLE));
	translate([0,0,-RADIUS_CONST*cos(RING_ANGLE)]) cylinder(r1=R1, r2=R2,h=H,center=true);
	translate([0,0,-RADIUS_CONST*1.4]) sphere(POD_DIAM/4 + SHELL);
}

module make_pod_cut(H = POD_HEIGHT){
	//cylinder(d=POD_DIAM+POD_CS*2,h=SHELL,center=true);
	R2 = POD_DIAM/2;
	R1 = POD_DIAM/2 - 2;
	translate([0,0,-H/2 + 4]) cylinder(r2=R2, r1=R1, h=H+4,center=true);
	translate([-8,-(POD_DIAM + SHELL + 4)/2,-GROOVE + 1]) cube([16,POD_DIAM+SHELL*4,GROOVE + 1]);
}

module make_pod_hole(type = "ring", O = [0,0,0]){
	//MODULE VARIABLES
	if(type=="ring"){
		rotate(O)
		difference(){
			cylinder(d=POD_DIAM+POD_CS*2,h=SHELL,center=true);
			cylinder(d=POD_DIAM,h=SHELL+2,center=true);
		}
	}

	if(type=="sheet"){
		rotate(O)
		difference(){
			cube([POD_DIAM+POD_CS*2, POD_DIAM+POD_CS*2,SHELL],center=true);
			cylinder(d=POD_DIAM,h=SHELL+2,center=true);
		}
	}

}

function get_mast_len() = (POD_HEIGHT/5)*sin(RING_ANGLE)*PODS;

function get_mast_rise() = FEET_TYPE=="round" ? LEG_LENGTH*tan(LEG_ANGLE) + LEG_DIAM/2 : LEG_LENGTH*tan(LEG_ANGLE);

function face_normal(pos = []) = pos[0] > 0 ? 90 + atan(pos[1]/pos[0]) : pos[0] != 0 ? atan(pos[1]/pos[0]) - 90 : pos[1] > 1 ? 180 : 0;
```


[User]
Hey, I'm looking to generate some rings and have a pretty good idea of how I want to do it, but I'd love for you to help me set up the OpenSCAD file. I want it to be parametric so I can easily tweak things.

Essentially, I want to be able to choose between a torus-shaped ring (round mode) and a cylindrical ring. For the torus, I need parameters for the wall thickness, the inner diameter, and the roundness, which controls both the number of sides used to create the shape of the cross section and the number of sides used for the round part of the torus. For the cylinder version, I want to specify the height, the thickness, inner diameter and the number of sides of the circle that will be used for the cylinder.

Specifically, I need the following parameters:
- `faces_of_round_shape`: Integer, number of faces for the circular part of the torus cross-section. Only used in the torus mode.
- `height`: Real number, height of the cylinder in mm. Only used in the cylinder mode.
- `sides_of_roundness`: Integer, number of sides used to create the cross-section shape (both for torus and cylinder)
- `cylinder_or_round`: String, either `"round"` for the torus shape or `"cylinder"` for the cylinder shape.
- `thickness`: Real number, thickness of the ring wall in mm.
- `diameter`: Real number, the inner diameter of the hole in the ring in mm.

I think that's everything. I'm aiming for a file that lets me tweak those parameters and generate either a torus ring or a cylinder ring as described. I won't be using any external libraries, so I guess just a single file should be fine.

[Assistant]
ring_generator.scad:
```
// Sets the pahses of the torus (only for round mode)
faces_of_round_shape = 16;
// Height of the cylinder version in mm
height = 5;
// Defines the roundness of the shape
sides_of_roundness = 8;
cylinder_or_round = "round";//[round,cylinder]
// Thickness of the wall in mm
thickness = 1;
// Diameter ofthe hole in mm
diameter = 4;
if (cylinder_or_round == "round") {
  // torus
  rotate_extrude($fn=sides_of_roundness) {
    translate([(diameter + thickness), 0, 0]) {
      circle(r=thickness, $fn=faces_of_round_shape);
    }
  }
} else {
  difference() {
    linear_extrude( height=height, twist=0, scale=[1, 1], center=false){
      {
        $fn=sides_of_roundness;    //set sides to sides_of_roundness
        circle(r=(diameter + thickness));
      }
    }

    linear_extrude( height=height, twist=0, scale=[1, 1], center=false){
      {
        $fn=sides_of_roundness;    //set sides to sides_of_roundness
        circle(r=diameter);
      }
    }
  }
}

```


[User]
I'd like to design a parametric pendant lamp shade using OpenSCAD. I have a basic idea, and I'd like the design to be flexible so I can easily adjust it later.

Here's what I'm thinking:

The shade should have a twisted, almost spiral, form created by extruding a square shape along a vertical axis with a twist. I want to be able to control:

*   **Overall Height:** The total height of the lampshade.
*   **Square Size:** The size of the square being extruded.
*   **Twist Angle:** The total angle of rotation as the square is extruded.
*   **Layer Height:** The vertical resolution of the extrusion (important for 3D printing).
*   **Thickness:** A parameter that allows me to control how thick the overall lampshade is - I want the interior to be hollow.
*   **Center Hole Diameter:** The size of the hole at the top (or bottom) for the light cord.
*   **Convexity:** The convexity of the linear extrude (I'm assuming this affects how smooth the twist is?).
*   **Side Grills:** I'd also like to have a side grill pattern using a series of small cylinders. I want to be able to adjust:
    *   **Grill Radius:** The radius of the cylinder used for the grill
    *   **Grill Spacing:** How far apart these cylinders are from the origin.
    * **Grill Bar Radius** How thick the cylinders are that connect the individual grills

I want the design to be fully parametric, so I can easily tweak these values. Also, it would be nice if the base where the light fitting goes was a bit thicker than the rest of the lampshade. I am aiming to mount this to an IKEA Hemma light cord set, which I think has a 20mm mounting point, but I'd like to make sure that's a parametric value so it can be changed.

Could you please generate a fully parametric OpenSCAD file to achieve this? I do not need any additional library support.

[Assistant]
pendant_lamp_shade.scad:
```
// lamp shade by keiko
layerheight=0.2;
basethick=3*layerheight/10;
squaresize=100;
lampheight=200;
sliceheight=lampheight/layerheight;
twistangle=90;
hole=20;
convex=10;

module shade () {
difference() {
linear_extrude(height = lampheight, convexity = convex, slices = sliceheight, twist = twistangle)
translate([0, 0, 0])
square(squaresize, center=true);

    linear_extrude(height = lampheight, convexity = convex, slices = sliceheight, twist = twistangle)
translate([0, 0, 0])
square(squaresize-4, center=true);
}
difference() {
linear_extrude(height = lampheight*basethick, convexity = convex, slices = sliceheight*basethick, twist = twistangle*basethick)
//translate([0, 0, 0])
square(squaresize, center=true);

cylinder(r=hole,h=lampheight*basethick);

//side grill
    //squared intersection
//intersection() {
//    cube([squaresize-5,squaresize-5,2*lampheight/divider],center=true);
for(a=[0:15:360]) {
	rotate(a)
	translate([33,0,0])
	hull() {
		cylinder(r=2,h=lampheight*basethick,$fn=12);
        translate([11,0,0])
        cylinder(r=2.6,h=lampheight*basethick,$fn=12);
        }

//          else
//             translate([abs(7*sin(a*2)),0,0]) ;
//            cube ([10,10,10]);

//	}
}
//}
}
// socket rim
//color(2);
//translate([0,0,-1])
//cylinder(r=29,h=4);
}

shade();
//translate([-200,0,0])
//shade();
//translate([200,0,0])
//shade(twistangle=-twistangle);
```


[User]
Hey there, I'm looking to create a parametric iris mechanism using OpenSCAD, and I'd really appreciate your help with the design.  I've been looking at some examples, but I need to create something that is fully customizable using variables.

Essentially, I need a design with these main components:
1.  A **main shell** with an internal gear ring. This shell needs to be a cylinder, but with an opening at the bottom and an opening at the top for the lid to screw into. It also needs to have a tapered section at the bottom of the gear ring. I'd also want the ability to add edge fillets.
2. **Iris blades** that are planet gears. These blades should have gears on one side to engage with the shell's gear ring, and a curved blade section to form the iris opening itself. They also need a hole for a peg, to connect to the lever.
3.  A **lever disk** or lever that sits on top of the blades. This disk has pegs that fit into the blade's holes. It also needs to have a handle to turn the entire system.
4.  A **lid** which screws on top of everything and locks it all in place. It should screw onto the shell using threads, and it should have an opening to match the iris when it is in the fully open position. I'd also like edge fillets on the lid.

I have a few specific design parameters that need to be user-definable:

*   **`radius_outer_shell`**: The overall radius of the entire mechanism.
*   **`ratio_aperture`**:  The size of the central aperture when fully opened, as a ratio of the inner shell radius.
*   **`thickness_blade`**: The thickness of the iris blades. Should be an even multiple of print layer height.
*   **`count_blades`**: The number of iris blades.
*   **`radius_fillet`**: The radius of the edge curves/fillets on the shell and lid.
*   **`slop_shell_to_lid`**: Space between the shell and the lid, to allow rotation.
*   **`slop_shell_planet`**: Space between the shell and the planet gears.
*   **`slop_planet_to_peg`**: Space between the planet gears and the pegs on the lever disk.

And a few less important (but helpful) parameters:

*   **`epsilon`**:  A small fudge factor to help with preview holes.
*   **`resolution_shell_outer`**, **`resolution_shell_inner`**, **`resolution_fillet`**, **`resolution_gear`**, **`resolution_planet`**, **`resolution_blade`**:  resolution/smoothness for different parts of the model.

I'd also like to use the threads.scad module from the website that was mentioned in the YouTube description, if that is not too much trouble. If you have to write the thread module, I'm ok with that, too. I would need the `metric_thread` module from the "threads.scad" file linked in that YouTube description. This needs to include parameters for diameter, pitch, length, internal/external, thread\_size, etc., as listed in the attached OpenSCAD code. I'm aware this library is licensed under the GNU General Public License.

Finally, it'd be awesome if I could choose which part to render from an enum/string parameter. It'd be great to view just the shell, the blades, the lid, the lever, all of them together, or even a single blade for debugging purposes.

Let me know what you think, and thanks in advance!

[Assistant]
Aperture_Parametric_2018-04-11.scad:
```
/*
Code by Patrick Gaston, 3/2018, who admits he is utter crap at coding. Do not expect elegance, stability, or efficiency in the code that follows. But it generally works.
All thread modules are excerpted from "threads.scad" by Dan Kirshner, used by permission under GNU General Public License. The original file is available at http://dkprojects.net/openscad-threads/
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation.
Last updated: 2018.04.08 - Added ability to render a single blade. Fixed rounding error preventing 7-blade models.
*/

/* [Global] */
//Radius of entire mechanism, in mm.
radius_outer_shell = 100; //[15:0.5:100]
//Size of aperture relative to shell. Extreme values may result in impossible mechanisms.
ratio_aperture = 0.60; //[0.3:0.05:0.8]
//Keep blades thin to fit together and move easily. Should be even multiple of print layer height.
thickness_blade = 0.4; //[0.1:0.05:0.4]
//Number of iris blades. A good estimate is 10 times the aperture ratio.
count_blades = 8; //[2:1:8]
//Size of edge curves. Set to zero for no curve.
radius_fillet = 2; //[0:0.2:2]
//Select the part to view or generate.
part = "all_parts"; // [assembled:Assembled (unprintable, view only), shell:Shell Only,blades:Blades Only,lid:Lid Only,lever:Lever Only, single_blade: Single Blade, all_parts:All Parts]
//Space between shell and lid to allow rotation
slop_shell_to_lid = 0.5;
//Space between shell and planet gears to free movement.
slop_shell_planet = 0.25;
//Space between planets (blades) and pegs on lever disk to allow rotation.
slop_planet_to_peg = 0.6;

/* [Hidden] */
epsilon = 0.1; //Fudge, to make preview holes work.
resolution_shell_outer = 32;//Smoothness of the outer surface of the shell
resolution_shell_inner = 64; //Smoothness of the inner surface of the shell
resolution_fillet = 16; //Smoothness of edge curves
resolution_gear = 12; //Smoothness of each gear tooth
resolution_planet = 24; //Smoothness of gear wheel outer surface
resolution_blade = 48; //Smoothness of curve of blade
radius_gear = 1.0;
radius_negative_gear = radius_gear + 0.3;
pitch_screw = 2.5;
thread_size_screw = 2;
thickness_shell_side = 3;
radius_inner_shell = radius_outer_shell - thickness_shell_side;
radius_aperture = ratio_aperture * radius_inner_shell;
thickness_shell_bottom = 2;
height_shell_gear_bottom = thickness_shell_bottom + 4*thickness_blade; //Space for blades to overlap
height_shell_gear_top = height_shell_gear_bottom + 5;
height_shell = height_shell_gear_top + 6;
arclength_shell = 2* (radius_gear + radius_negative_gear);
degrees_to_next_gear_shell = 360 * (arclength_shell/(2 * PI * radius_inner_shell));
degrees_to_negative_gear_shell = 360 * ((radius_gear + radius_negative_gear)/(2 * PI * radius_inner_shell));
angle_blade = 0;
radius_outer_planet = (radius_inner_shell - radius_gear - radius_aperture)/2;
radius_inner_planet = radius_outer_planet - radius_gear - 1.4;
arclength_planet = 2* (radius_gear + radius_negative_gear);
degrees_to_next_gear = 360 * (arclength_planet/(2 * PI * radius_outer_planet));
degrees_to_negative_gear = 360 * ((radius_gear + radius_negative_gear)/(2 * PI * radius_outer_planet));
count_blades_gear = round(180/(degrees_to_next_gear + degrees_to_negative_gear));
height_planet = height_shell_gear_top - height_shell_gear_bottom;
angle_isoceles = atan((radius_aperture + radius_outer_planet)/(radius_aperture + 2*radius_outer_planet));
distance_head_to_tail = pow(pow(radius_aperture + 2*radius_outer_planet,2) + pow(radius_aperture + radius_outer_planet,2),0.5);
blade_R2 = (distance_head_to_tail/2)/cos(angle_isoceles);
blade_R3 = radius_aperture + 2*radius_outer_planet - blade_R2;
radius_planet_disk = radius_inner_shell - 1;
thickness_planet_disk = 2;
radius_planet_disk_peg = radius_inner_planet - slop_planet_to_peg;
radius_orbit_planet = radius_inner_shell - slop_shell_planet - radius_outer_planet - radius_gear;
height_lid = height_shell - height_shell_gear_top - thickness_planet_disk + radius_fillet;
width_handle = radius_outer_shell - radius_planet_disk + 2;

//==============================================================================================

module fillet_outer_quarter_circle(radius_circle, radius_extrusion, resolution_circle, resolution_fillet)
    {
     rotate([0,180,0])
     rotate_extrude($fn = resolution_fillet, convexity = 10)
     translate([radius_extrusion - radius_circle,-radius_circle,0])
     difference()
        {
         square(radius_circle);
         circle($fn = resolution_circle, r = radius_circle);
        }
    }

module fillet_inner_quarter_circle(radius_circle, radius_extrusion, resolution_circle, resolution_fillet)
    {
     translate([0,0,radius_circle])
     rotate_extrude($fn = resolution_fillet, convexity = 10)
     translate([radius_extrusion,-radius_circle,0])
     difference()
        {
         square(radius_circle);
         translate([radius_circle,radius_circle,0]) circle($fn = resolution_circle, r = radius_circle);
        }
    }

module main_shell ()
    {
     color("SkyBlue")
     union()
        {
         difference()
            {
             //Main shell outer
             cylinder($fn = resolution_shell_outer, h = height_shell, r = radius_inner_shell + thickness_shell_side);
             //Main shell inner
             translate([0,0,thickness_shell_bottom]) cylinder($fn = resolution_shell_inner, h = height_shell, r = radius_inner_shell);
             //Outer bottom fillet
             fillet_outer_quarter_circle(radius_fillet, radius_inner_shell + thickness_shell_side, resolution_fillet, resolution_shell_outer);
             //Inner bottom fillet
             fillet_inner_quarter_circle(radius_fillet, radius_aperture - epsilon, resolution_fillet,resolution_shell_outer);
             //Aperture opening
             translate([0,0,-epsilon])
             cylinder($fn = resolution_shell_outer, h = thickness_shell_bottom + 2*epsilon, r = radius_aperture);
             //Inner top fillet
             translate([0,0,height_shell + epsilon]) rotate([180,0,0]) fillet_inner_quarter_circle(thickness_shell_side, radius_inner_shell - epsilon, resolution_fillet, resolution_shell_inner);
             //Handle opening
             scale(v = [1, 2, 1])
             translate([0,0,height_shell_gear_bottom + height_planet])
             rotate([0,0,-135])
             cube(size = [radius_outer_shell,radius_outer_shell,height_shell]);
             //Threads
             translate([0,0,height_shell_gear_top + thickness_planet_disk])
             metric_thread (diameter = 2*(radius_inner_shell) + 2, pitch = pitch_screw, length=height_lid, thread_size = thread_size_screw, internal = true);
            };

        //Gear ring
        difference()
            {
             union()
                {
                 difference()
                    {
                     //Gear ring outer
                     translate([0,0,height_shell_gear_bottom])
                     cylinder($fn = resolution_shell_outer, h = height_shell_gear_top - height_shell_gear_bottom, r = radius_inner_shell + thickness_shell_side);

                     //Gear ring inner
                     translate([0,0,height_shell_gear_bottom - epsilon])
                     cylinder($fn = resolution_shell_inner, h = height_shell_gear_top - height_shell_gear_bottom + 2*epsilon, r = radius_inner_shell - radius_negative_gear);

                     //Shell negative gears
                    for(k = [1 : 1 : count_blades])
                        {
                         rotate([0,0,(-count_blades_gear * degrees_to_next_gear_shell/2) + (k-1) * 360/count_blades])
                         for(i = [1 : 1 : count_blades_gear])
                            {
                             rotate([0,0,i*degrees_to_next_gear_shell -90 -degrees_to_negative_gear_shell])
                             translate([radius_inner_shell - radius_negative_gear,0,height_shell_gear_bottom])
                             cylinder($fn = resolution_gear, h = height_shell_gear_top - height_shell_gear_bottom, r = radius_negative_gear);
                            }
                        }
                    }
                    //Shell positive gears
                    for(k = [1 : 1 : count_blades])
                        {
                         rotate([0,0,(-count_blades_gear * degrees_to_next_gear_shell/2) + (k-1) * 360/count_blades])
                         for(i = [1 : 1 : count_blades_gear])
                            {
                             rotate([0,0,i*degrees_to_next_gear_shell -90])
                             translate([radius_inner_shell - radius_negative_gear,0,height_shell_gear_bottom])
                             cylinder($fn = resolution_gear, h = height_shell_gear_top - height_shell_gear_bottom, r = radius_gear);
                            }
                        }
                   };

               //Cone, to taper off bottom of shell gears
                translate([0,0,height_shell_gear_bottom - epsilon])
                cylinder($fn = resolution_planet, h = radius_inner_shell, r1 = radius_inner_shell, r2 = 0);
               }
          }
    }

module make_planet()
    {
     color("Gray")
     difference()
        {
         union()
            {
             difference()
                {
                 union()
                    {
                     make_blade();
                     cylinder($fn = resolution_planet, h = height_planet, r = radius_outer_planet);
                    };
                 translate([0,0,thickness_blade])
                 cylinder($fn = resolution_planet, h = height_planet + epsilon, r = radius_inner_planet);
                };
             for(i = [1 : 1 : count_blades_gear])
                {
                 rotate([0,0,i*degrees_to_next_gear-45]) translate([radius_outer_planet,0,0]) cylinder($fn = resolution_gear, h = height_planet, r = radius_gear);
                };
            };
            {
             for(i = [1 : 1 : count_blades_gear])
                {
                 rotate([0,0,i*degrees_to_next_gear -45 -degrees_to_negative_gear]) translate([radius_outer_planet,0,0]) cylinder($fn = resolution_gear, h = height_planet + epsilon, r = radius_negative_gear);
                }
            }
        };
    }
module make_blade()
    {
     translate([-radius_orbit_planet,0,0])
     rotate([0,0,-90])
     linear_extrude(height = thickness_blade, center = false, convexity = 10)
        {
        //Planet, also head of iris blade
        rotate([0,0,90])
        translate([radius_aperture + radius_outer_planet,0,0])
        circle($fn = resolution_blade, r = radius_outer_planet);

        //Tail of iris blade
        translate([radius_aperture + radius_outer_planet/2,0,0])
        circle($fn = resolution_blade, r = radius_outer_planet/2);

        difference()
            {
            //Arc circle
            translate([0,blade_R3,0])
            circle($fn = resolution_blade, r = blade_R2);

            //Aperture
            circle($fn = resolution_blade, r = radius_aperture);

            //Blocks of negative space
            translate([0,-2*blade_R2,0]) square(2*blade_R2);
            translate([-2*blade_R2,-2*blade_R2,0]) square(size = [2*blade_R2,4*blade_R2]);
            }
        }
    }

module place_planets(angle_blade)
    {
     for (i = [0 : (360/count_blades) : 360])
        {
         rotate([0,0,i]) translate([radius_orbit_planet,0,height_shell_gear_bottom])
            {
             rotate([0,0,-angle_blade])
                {
                 make_planet();
                }
            }
        }
    }

module make_planet_disk()
    {
     color("SpringGreen")
     union()
        {
         //Disk
         difference()
            {
             //disk outer
             translate([0,0,height_shell_gear_bottom + height_planet])
             cylinder($fn = resolution_shell_outer, h = thickness_planet_disk, r = radius_orbit_planet + radius_planet_disk_peg);
             //disk inner
             translate([0,0,height_shell_gear_bottom + height_planet - epsilon])
             cylinder($fn = resolution_shell_outer, h = thickness_planet_disk + 2*epsilon, r = radius_orbit_planet - radius_planet_disk_peg);
            }
         //Planet mounts
         for (i = [0 : floor(360/count_blades) : 360])
            {
             rotate([0,0,i])
             translate([radius_orbit_planet,0,height_shell_gear_bottom])
             difference()
                {
                 cylinder($fn = resolution_planet, h = height_planet, r = radius_planet_disk_peg);
                 translate([0,0,-epsilon])
                 fillet_outer_quarter_circle(height_planet/2, radius_planet_disk_peg + epsilon, resolution_fillet, resolution_shell_outer);
                }
            }
         //Handle
            {
             translate([radius_orbit_planet - radius_planet_disk_peg,-width_handle/2,height_shell_gear_bottom + height_planet])
             cube(size = [radius_planet_disk - radius_orbit_planet + radius_planet_disk_peg + 1.25*width_handle,width_handle,thickness_planet_disk], center = false);
             difference()
                {
                 //Handle peg
                 translate([radius_planet_disk + 1.25*width_handle,0,height_shell_gear_bottom])
                 cylinder($fn = resolution_fillet, h = height_planet + thickness_planet_disk, r = width_handle/2);
                 //Handle peg fillet
                 translate([radius_planet_disk + 1.25*width_handle,0,height_shell_gear_bottom-epsilon])
                 fillet_outer_quarter_circle(width_handle/2/2, width_handle/2 + epsilon, resolution_fillet, resolution_shell_outer);
                }
            }
        }
    }

module make_lid()
    {
     color("Salmon")
     difference()
        {
         union()
            {
             //main cylinder
             translate([0,0,height_shell_gear_top + thickness_planet_disk])
             cylinder($fn = resolution_shell_outer, h = height_lid, r = radius_inner_shell - slop_shell_to_lid);
             //lid top cylinder
             translate([0,0,height_shell + radius_fillet])
             rotate([180,0,0])
             difference()
                {
                 cylinder($fn = resolution_shell_outer, h = radius_fillet, r = radius_outer_shell);
                 //minus outer fillet
                 fillet_outer_quarter_circle(radius_fillet, radius_outer_shell + epsilon, resolution_fillet, resolution_shell_outer);
                };
             //plus inner fillet
             translate([0,0,height_shell])
             rotate([180,0,0])
             fillet_inner_quarter_circle(thickness_shell_side, radius_inner_shell - slop_shell_to_lid, resolution_fillet, resolution_shell_inner);
             //plus threads
             translate([0,0,height_shell_gear_top + thickness_planet_disk])
             metric_thread (diameter = 2*(radius_inner_shell - slop_shell_to_lid) + 2, pitch = pitch_screw, length=height_lid, thread_size = thread_size_screw);
            };
         //minus aperture
         translate([0,0,height_shell_gear_top + thickness_planet_disk - epsilon])
         cylinder($fn = resolution_shell_outer, h = height_shell - height_shell_gear_top - thickness_planet_disk + radius_fillet + (2*epsilon), r = radius_aperture);
         //minus aperture fillet
         translate([0,0,height_shell + radius_fillet + epsilon])
         rotate([180,0,0])
         fillet_inner_quarter_circle(radius_fillet + (2*epsilon), radius_aperture - epsilon, resolution_fillet, resolution_shell_outer);
        };
    }

module metric_thread (diameter=8, pitch=1, length=1, internal=false, n_starts=1,
                      thread_size=-1, groove=false, square=false, rectangle=0,
                      angle=30, taper=0, leadin=0, leadfac=1.0)
{
   // thread_size: size of thread "V" different than travel per turn (pitch).
   // Default: same as pitch.
   local_thread_size = thread_size == -1 ? pitch : thread_size;
   local_rectangle = rectangle ? rectangle : 1;

   n_segments = segments (diameter);
   h = (square || rectangle) ? local_thread_size*local_rectangle/2 : local_thread_size / (2 * tan(angle));

   h_fac1 = (square || rectangle) ? 0.90 : 0.625;

   // External thread includes additional relief.
   h_fac2 = (square || rectangle) ? 0.95 : 5.3/8;

   tapered_diameter = diameter - length*taper;

   difference () {
      union () {
         if (! groove) {
            metric_thread_turns (diameter, pitch, length, internal, n_starts,
                                 local_thread_size, groove, square, rectangle, angle,
                                 taper);
         }

         difference () {

            // Solid center, including Dmin truncation.
            if (groove) {
               cylinder (r1=diameter/2, r2=tapered_diameter/2,
                         h=length, $fn=n_segments);
            } else if (internal) {
               cylinder (r1=diameter/2 - h*h_fac1, r2=tapered_diameter/2 - h*h_fac1,
                         h=length, $fn=n_segments);
            } else {

               // External thread.
               cylinder (r1=diameter/2 - h*h_fac2, r2=tapered_diameter/2 - h*h_fac2,
                         h=length, $fn=n_segments);
            }

            if (groove) {
               metric_thread_turns (diameter, pitch, length, internal, n_starts,
                                    local_thread_size, groove, square, rectangle,
                                    angle, taper);
            }
         }
      }

      // fillet z=0 end if leadin is 2 or 3
      if (leadin == 2 || leadin == 3) {
         difference () {
            cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);

            cylinder (r2=diameter/2, r1=diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
                      $fn=n_segments);
         }
      }

      // fillet z-max end if leadin is 1 or 2.
      if (leadin == 1 || leadin == 2) {
         translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) {
            difference () {
               cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
               cylinder (r1=tapered_diameter/2, r2=tapered_diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
                         $fn=n_segments);
            }
         }
      }
   }
}

module metric_thread_turns (diameter, pitch, length, internal, n_starts,
                            thread_size, groove, square, rectangle, angle,
                            taper)
{
   // Number of turns needed.
   n_turns = floor (length/pitch);

   intersection () {

      // Start one below z = 0.  Gives an extra turn at each end.
      for (i=[-1*n_starts : n_turns+1]) {
         translate ([0, 0, i*pitch]) {
            metric_thread_turn (diameter, pitch, internal, n_starts,
                                thread_size, groove, square, rectangle, angle,
                                taper, i*pitch);
         }
      }

      // Cut to length.
      translate ([0, 0, length/2]) {
         cube ([diameter*3, diameter*3, length], center=true);
      }
   }
}

module metric_thread_turn (diameter, pitch, internal, n_starts, thread_size,
                           groove, square, rectangle, angle, taper, z)
{
   n_segments = segments (diameter);
   fraction_circle = 1.0/n_segments;
   for (i=[0 : n_segments-1]) {
      rotate ([0, 0, i*360*fraction_circle]) {
         translate ([0, 0, i*n_starts*pitch*fraction_circle]) {
            //current_diameter = diameter - taper*(z + i*n_starts*pitch*fraction_circle);
            thread_polyhedron ((diameter - taper*(z + i*n_starts*pitch*fraction_circle))/2,
                               pitch, internal, n_starts, thread_size, groove,
                               square, rectangle, angle);
         }
      }
   }
}

module thread_polyhedron (radius, pitch, internal, n_starts, thread_size,
                          groove, square, rectangle, angle)
{
   n_segments = segments (radius*2);
   fraction_circle = 1.0/n_segments;

   local_rectangle = rectangle ? rectangle : 1;

   h = (square || rectangle) ? thread_size*local_rectangle/2 : thread_size / (2 * tan(angle));
   outer_r = radius + (internal ? h/20 : 0); // Adds internal relief.
   //echo (str ("outer_r: ", outer_r));

   // A little extra on square thread -- make sure overlaps cylinder.
   h_fac1 = (square || rectangle) ? 1.1 : 0.875;
   inner_r = radius - h*h_fac1; // Does NOT do Dmin_truncation - do later with
                                // cylinder.

   translate_y = groove ? outer_r + inner_r : 0;
   reflect_x   = groove ? 1 : 0;

   // Make these just slightly bigger (keep in proportion) so polyhedra will
   // overlap.
   x_incr_outer = (! groove ? outer_r : inner_r) * fraction_circle * 2 * PI * 1.02;
   x_incr_inner = (! groove ? inner_r : outer_r) * fraction_circle * 2 * PI * 1.02;
   z_incr = n_starts * pitch * fraction_circle * 1.005;
   x1_outer = outer_r * fraction_circle * 2 * PI;
   z0_outer = (outer_r - inner_r) * tan(angle);
   z1_outer = z0_outer + z_incr;

   // Give internal square threads some clearance in the z direction, too.
   bottom = internal ? 0.235 : 0.25;
   top    = internal ? 0.765 : 0.75;

   translate ([0, translate_y, 0]) {
      mirror ([reflect_x, 0, 0]) {
         if (square || rectangle) {
            // Rule for face ordering: look at polyhedron from outside: points must
            // be in clockwise order.
            polyhedron (
               points = [
                         [-x_incr_inner/2, -inner_r, bottom*thread_size],         // [0]
                         [x_incr_inner/2, -inner_r, bottom*thread_size + z_incr], // [1]
                         [x_incr_inner/2, -inner_r, top*thread_size + z_incr],    // [2]
                         [-x_incr_inner/2, -inner_r, top*thread_size],            // [3]
                         [-x_incr_outer/2, -outer_r, bottom*thread_size],         // [4]
                         [x_incr_outer/2, -outer_r, bottom*thread_size + z_incr], // [5]
                         [x_incr_outer/2, -outer_r, top*thread_size + z_incr],    // [6]
                         [-x_incr_outer/2, -outer_r, top*thread_size]             // [7]
                        ],

               faces = [
                         [0, 3, 7, 4],  // This-side trapezoid
                         [1, 5, 6, 2],  // Back-side trapezoid
                         [0, 1, 2, 3],  // Inner rectangle
                         [4, 7, 6, 5],  // Outer rectangle
                         // These are not planar, so do with separate triangles.
                         [7, 2, 6],     // Upper rectangle, bottom
                         [7, 3, 2],     // Upper rectangle, top
                         [0, 5, 1],     // Lower rectangle, bottom
                         [0, 4, 5]      // Lower rectangle, top
                        ]
            );
         } else {

            // Rule for face ordering: look at polyhedron from outside: points must
            // be in clockwise order.
            polyhedron (
               points = [
                         [-x_incr_inner/2, -inner_r, 0],                        // [0]
                         [x_incr_inner/2, -inner_r, z_incr],                    // [1]
                         [x_incr_inner/2, -inner_r, thread_size + z_incr],      // [2]
                         [-x_incr_inner/2, -inner_r, thread_size],              // [3]
                         [-x_incr_outer/2, -outer_r, z0_outer],                 // [4]
                         [x_incr_outer/2, -outer_r, z0_outer + z_incr],         // [5]
                         [x_incr_outer/2, -outer_r, thread_size - z0_outer + z_incr], // [6]
                         [-x_incr_outer/2, -outer_r, thread_size - z0_outer]    // [7]
                        ],

               faces = [
                         [0, 3, 7, 4],  // This-side trapezoid
                         [1, 5, 6, 2],  // Back-side trapezoid
                         [0, 1, 2, 3],  // Inner rectangle
                         [4, 7, 6, 5],  // Outer rectangle
                         // These are not planar, so do with separate triangles.
                         [7, 2, 6],     // Upper rectangle, bottom
                         [7, 3, 2],     // Upper rectangle, top
                         [0, 5, 1],     // Lower rectangle, bottom
                         [0, 4, 5]      // Lower rectangle, top
                        ]
            );
         }
      }
   }
}

function segments (diameter) = min (50, ceil (diameter*6));

module print_part()
    {
	 if (part == "assembled")
        {
		 show_assembled();
        }
	 if (part == "shell")
        {
		 show_shell();
        }
     else if (part == "blades")
        {
		 show_blades();
        }
     else if (part == "lid")
        {
		 show_lid();
        }
     else if (part == "single_blade")
        {
		 make_planet();
        }
     else if (part == "lever")
        {
		 show_lever();
        }
     else if (part == "all_parts")
        {
		 show_all();
        }
    }

module show_assembled()
    {
     main_shell();
     place_planets(angle_blade = 25);
     make_planet_disk();
     make_lid();
    }

module show_shell()
    {
	 main_shell();
    }

module show_blades()
    {
     translate([0,0,-height_shell_gear_bottom])
     place_planets(angle_blade = 310);
    }

module show_single_blade()
    {
     make_single_planet();
    }

module show_lid()
    {
     translate([0,0,height_shell_gear_top + thickness_planet_disk + height_lid])
     rotate([0,180,0])
     make_lid();
    }

module show_lever()
    {
     translate([0,0,height_shell_gear_bottom + height_planet + thickness_planet_disk])
     rotate([0,180,0])
     make_planet_disk();
    }

module show_all()
    {
     main_shell();

     translate([radius_outer_shell * 2.75,0,-height_shell_gear_bottom])
     place_planets(angle_blade = 310);

     translate([0,radius_outer_shell * 2.25,height_shell_gear_bottom + height_planet + thickness_planet_disk])
     rotate([0,180,0])
     make_planet_disk();

     translate([-radius_outer_shell * 2.25,0,height_shell_gear_top + thickness_planet_disk + height_lid])
     rotate([0,180,0])
     make_lid();
    }

print_part();

```