[User]
Okay, I'm looking to create a parametric version of a Lego heart pendant. I have a basic design already, but I want to make it more flexible so I can easily adjust the size, thickness, and other features.

Right now, my design is essentially two mirrored "plate" shapes that connect to form a heart. Each plate has a semi-circular top and a rectangular bottom, and four studs on the top surface (like Lego studs) and matching holes on the bottom for connecting to another piece. It also has a small hole on the flat edge that lets you attach it to a keyring or necklace.

Here's what I'd like to be able to control in my parametric design:

*   **Overall Size:** I want to be able to easily change the overall size of the heart, ideally by setting a single parameter (e.g., `overall_size`) that scales everything proportionally.
*   **Thickness:** I need to control the height (or thickness) of the heart pieces. Let's call this `plate_thickness`.
*   **Stud Size:** I need to be able to adjust the diameter and height of the studs (the knobs) on the top surface. We can call these `stud_diameter` and `stud_height`.
*   **Hole Size:** I need to adjust the diameter and depth of the holes on the bottom surface. These should match the studs, let's call these `hole_diameter` and `hole_depth`.
*   **Keyring Hole:** I need to be able to adjust the diameter of the keyring hole. Let's call this `keyring_hole_diameter`
*   **Positioning:** I would like the studs to be arranged symmetrically, two on each side of the center, and the keyring hole centered on one of the flat sides. I'd like the position of the studs to scale with the `overall_size` parameter.

I'd also prefer if the code used a library for generating circles. The `circle()` function from the `BOSL` library would be great. Please don't include the library code though, just make sure it references the library.

Finally, I want to be able to easily 3D print this. I would like it designed in such a way that it can be printed with minimal supports.

Can you provide an OpenSCAD file that lets me control all of these parameters and generates the two halves of the heart, which I could then mirror and put together to form the whole piece?

[Assistant]
LegoHeart.scad:
```
//Size on the y-Axis in mm
size = 15;

//Size on the z-Axis in mm
height = 5;

module half(){
	difference(){
		cylinder(r=size/2,h=height,$fn=50, center=true);
		translate([(size+1)/2,0,0]) cube([size + 1, size + 1,height + 1],center = true);
	}
}

module plate(){
	union() {
		half();
		translate([0,-size/2,-height/2]) cube([size,size,height]);
	}
}

//Top Knob Diameter
knob_diameter = 4;

//Top Knob Hight
knob_hight = 1.5;

//Bottom Hole Diameter
hole_diameter = 4;

//Bottom Hole Depth
hole_depth = 1.5;

//Keyring Hole Diameter
keyring_hole=1.5;

difference(){
	union(){
		plate();
		translate([size/4, size/4 , height/2]) cylinder(r=knob_diameter/2,h=knob_hight,$fn=50);
		translate([size/4, -size/4, height/2]) cylinder(r=knob_diameter/2,h=knob_hight,$fn=50);
		translate([3*(size/4), size/4, height/2]) cylinder(r=knob_diameter/2,h=knob_hight,$fn=50);
		translate([3*(size/4),-size/4, height/2]) cylinder(r=knob_diameter/2,h=knob_hight,$fn=50);
	}
	translate([size/4,size/4,-height/2-0.01]) cylinder(r=hole_diameter/2,h=hole_depth+0.01,$fn=50);
	translate([size/4,-size/4,-height/2-0.01]) cylinder(r=hole_diameter/2,h=hole_depth+0.01,$fn=50);
	translate([3*(size/4),size/4,-height/2-0.01]) cylinder(r=hole_diameter/2,h=hole_depth+0.01,$fn=50);
	translate([3*(size/4),-size/4,-height/2-0.01]) cylinder(r=hole_diameter/2,h=hole_depth+0.01,$fn=50);
	translate([-size/4,0,-height/2-0.01]) cylinder(r=keyring_hole, h=height+0.02, $fn=50);
}

```


[User]
Okay, I'm trying to design a customizable replacement gear for 3D printing, and I think I have a good starting point but I need a bit of help. I've already made a simple gear in OpenSCAD, but I'd like to make it more robust and easier for other people to use.

Here's the gist of what I've got so far. It's a cylindrical gear with teeth/cogs sticking out, and I want the user to have a lot of control over the dimensions. I'm already using the `build_plate.scad` library for build plate definition.

My current parameters are:

*   **Build Plate Selection:**  I've got a basic selector for a few common printers (Replicator 2, Replicator, Thingomatic, and manual) using `build_plate.scad`.  For manual, you can set build plate x and y dimensions.
*   **Internal Diameter:** The diameter of the inner hole of the gear.
*   **Hole Diameter:** The diameter of the center hole for a shaft.
*   **Height:** The overall thickness/height of the gear.
*   **Resolution:** A resolution parameter `$fn` to control the number of segments for the cylinders.
*   **Number of Cogs:**  The number of teeth around the circumference of the gear.
*   **Cog Length:** The total length of a single tooth.
*   **Cog Base Width:** The width of the base of each tooth.
*   **Cog Base Height:** The height of the base of each tooth.
*   **Cog Tip Width:** The width of the tip of each tooth.
*   **Tip Height:**  The height of the tip of each tooth.
*   **No Angle:** The length along the tooth that has no angle and matches the `cog_base_height`

Here's what I'd like help with:

1.  **Profile Option**:  I would really like to give the user an option to toggle between square-cut teeth, as I have now, and angled/tapered sides on the teeth.  The angle or shape of the taper should ideally be parametrically defined, maybe as an angle from the base of the tooth to the tip.  This would make it closer to an involute gear. I'm picturing some kind of boolean or dropdown that lets you chose a profile. If they chose tapered they would then set the angle, or maybe there would be some more options to chose from.
2.  **Pressure Angle**: It would be great if I could add the option for the user to input an angle for the cogs. This would help in situations where the two cogs need to connect at a certain angle and should be easy to adjust. Ideally this would be an angle on the base of the cog and would not affect the taper mentioned above.
3. **Clearance:** I'd like to add a parameter to easily add a small amount of clearance to the teeth. This would be useful to account for tolerances in 3D printing and ensure that gears will mesh properly. The clearance should be configurable, so that a user can chose how much they want.

I would like to use the same basic structure I have now, which uses a central cylinder with teeth added using `hull()` and rotations.  Also, please keep using the same `build_plate.scad` file I'm using right now, and if there is an accepted way of adding documentation please tell me.

I’m still new to all of this, so I’m open to any suggestions on how to make this code better, more user-friendly, and more accurate as a gear. Thanks in advance for your help!

[Assistant]
modulkugg2.scad:
```

use <utils/build_plate.scad>

//set your build plate
build_plate_selector = 0; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//if set to "manual" set the  build plate x dimension
build_plate_manual_x = 100; //[100:400]

//if set to "manual" set the  build plate y dimension
build_plate_manual_y = 100; //[100:400]

build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

//Size of the internal donut.
internal_diameter=40;

//Size of the Shaft hole.
hole_diameter=20;

//Donut height.
height=30;

//Resolution of the donut.
res = 50;		//[1:100]

//Number of Cogs.
cogs=17;

//Total length of the cog.
cog_length=20;

//Width of the cogs base.
cog_base_width=10;

//Height of the cogs base.
cog_base_height=30;

//Width of the tip.
cog_tip_width=5;

//Height of the tip.
tip_height=20;

//Amount of the cog length, which lacks angle, aka height of the cogbase.
no_angle = 10;

module cog(){

	union(){
		difference(){

			translate ([0,0,0]){
				cylinder(height,internal_diameter,internal_diameter, $fn = res, center=true) ;
			}

			translate ([0,0,0]){
				cylinder(height+2,hole_diameter,hole_diameter, $fn = res, center=true);

			}
		}
	}

	for ( i = [0 : (cogs-1)] ){			//the spikes
		hull(){
    		rotate( i * 360 / cogs, [0, 0, 1])
    			translate([internal_diameter,0,0]){
    				cube ([no_angle,cog_base_width,cog_base_height],center=true);
						translate([cog_length,0,0]) {
							cube ([.1,cog_tip_width,tip_height],center=true);
						}
				}

		}
	}
}

translate([0,0,height/2]){
	color([0,0.6,0.8]){
		cog();
	}
}

```


[User]
Okay, I'm looking to generate a variety of custom Easter eggs using OpenSCAD, and I want to be able to tweak a bunch of parameters to get different looks. I'm basing this off of an existing design I found online, but I want to make it more flexible and easier to customize.

Here's what I'm aiming for:

**Basic Egg Shape:** I want the base of the egg to be a sphere that's sliced at the top and bottom, so it's not a perfect sphere, more of an egg shape. I want to control the overall width of this egg.

**Looping Design:** Instead of a solid shell, I want to have lines or loops that follow the egg's shape. I'd like to have a few different styles:
*   **Plain:** Just the basic sphere shape.
*   **Single:** A single set of loops running up and down the egg.
*   **Double:** Two sets of loops, maybe with some overlap between them.
*   **Triple:** Three sets of loops with overlap options as well.
*   **Single Shell, Double Shell, Triple Shell:**  Same looping designs as single, double, and triple loop but with a shell applied.

**Parameters for Loops:**
*   **Number of Loops:** I need to be able to control how many loops go around the egg.
*   **Loop Width:**  The width of each individual loop.
*   **Loop Overlap:**  How much the loops overlap each other vertically (only applies to Double and Triple styles).
*   **Loop Angle Offset:** The ability to offset each loop slightly to create a staggered effect.
*   **Middle Loop Ratio:** Specifically for the Triple style, this would control the ratio/spacing of the middle loop versus the top and bottom loops.
*    **Skip Loops:** An option to skip every other loop for the top and bottom loops in the triple style and top loops for double style

**Shell Parameters:** For the shell styles, I want to control:

*   **Shell Percentage:** How much of the egg is covered by the shell, so I can have a partial shell.
*   **Shell Angle:** The angle of the partial shell, so I can create slanted edges.

**General Customization:**

*   **Basic Shapes:**  Instead of just a basic cylindrical loop, I want to have the *option* of different cross-sections of the loop shapes, like triangles, diamonds, emeralds, or ovals (similar to the example code provided, but the ability to change and add to this).
*   **Line Width:**  To control the thickness of the individual loops, but use this for the shell thickness as well

**Additional Requirements:**

*   I'd like to use the `build_plate.scad` library, similar to the example code I've seen, for displaying a build plate visualization but not needed for the generated geometry.
*   The final .scad file needs to be easily customizable with clearly defined parameters at the top.

Essentially, I'm trying to create a parametric egg generator with a lot of style and flexibility. Could you help me create an OpenSCAD file that does this?

[Assistant]
egg.scad:
```
// Joe Stubbs
// February 24 2012
// http://www.thingiverse.com/thing:53816

use <utils/build_plate.scad>

$fn = 50*1;

//Select the style of egg you would like to create.  If your loops are not touching you will need to select an shell style to hold everything together
Egg_Style = 5; // [0:Plain,1:Single,2:Double,3:Triple, 4:Single Shell,5:Double Shell,6:Triple Shell]

//Width of the egg in mm.
Egg_Width = 60; //[30:200]

//Select the basic shape to apply to your vase design
Basic_Shapes = 50; //[50:Ovals,3:Triangles,4:Diamonds,6:Emeralds]

Line_Width = 2; //[1:1mm Very Thin,2:2mm Thin,3:3mm Normal,4:4mm Thick,5:5mm Thicker]

//Number of loops around your egg:
Loops = 9; // [1:40]

//How wide do you want each loop to be?
Loop_Width = 0.5; // [0.1:Very Narrow,0.2:Narrow,0.3:Medium,0.4:Wide,0.5:Very Wide]

//How much do you want each loop to overlap vertically. Note: This only applies to double or triple Egg Styles.
Loop_Overlap = 0.375; // [0.0:None,0.125:Very Little,0.25:Half,0.375:Most,0.5:Full]

//This setting allows you to offset the loops for some interesting effects
Loop_Angle_Offset = 0.25; // [0:In line,0.5:Staggered,0.25:Split Staggered]

//This setting only applies to triple Egg Styles. It sets the ratio between the middle loop and the other two loops.
Middle_Loop_Ratio =  3; //[0.1:10%,0.2:20%,0.3:30%,0.4:40%,0.5:50%,0.6:60%,0.7:70%,0.8:80%,0.9:90%,1.0:100%,1.1:110%,1.2:120%,1.3:130%,1.4:140%,1.5:150%,1.6:160%,1.7:170%,1.8:180%,1.9:190%,2.0:200%]

//You can create some interesting effects with this setting.  In the triple Egg Styles the top and bottom loops skip, in the double Egg only the top skips.
Skip_Loops = 0; //[1:Yes,0:No]

//Applies to shell Egg Styles only, fill the shell of your egg to create a unique look.  Set the value to 100% if you want the egg shell to be complete all the way to the top.
Shell_Perentage = 0.6; //[0.2:20%,0.3:30%,0.4:40%,0.5:50%,0.6:60%,0.7:70%,0.8:80%,0.9:90%,1.0:100%]

//Applies to shell Egg Styles with less than 100% shell.  You can adjust the angle of the partial shell.  This can create some interesting loops especially if you tilt the shell beyond 90 degrees.
Shell_Angle = 30; //[0:0 degrees,10:10 degrees,20:20 degrees,30:30 degrees,45:45 degrees,60:60 degrees,70:70 degrees,80:80 degrees,90:90 degrees,120:120 degrees,135:135 degrees,180:180 degrees]

//for display only, doesn't contribute to final object
build_plate_selector = 0; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

sphere_outside_d = Egg_Width;
sphere_outside_r = sphere_outside_d/2;

sphere_wall = Line_Width;

sphere_inside_d = sphere_outside_d-sphere_wall*2;
sphere_inside_r = sphere_inside_d/2;

sphere_middle_d = (sphere_outside_d+sphere_inside_d)/2;
sphere_middle_r = sphere_middle_d/2;

sphere_top_hole_d = sphere_outside_d*0.05;
sphere_top_hole_r = sphere_top_hole_d/2;
sphere_top_z = trig_b_for_a_c(sphere_top_hole_r,sphere_outside_r); // use pythagorus to determine the location of the top ring

sphere_top_z_mid = sphere_top_z-sphere_wall/2;

sphere_base_d = sphere_outside_d*0.05;
sphere_base_r = sphere_base_d/2;
sphere_base_z = -trig_b_for_a_c(sphere_base_r,sphere_outside_r); // use pythagorus to determine the location of thebase ring

sphere_base_z_mid = sphere_base_z+sphere_wall/2;

holy_vase_count = Loops;
holy_vase_hole_ratio = Loop_Width;
holy_vase_overlap_ratio = Loop_Overlap;
holy_vase_spin_offset_ratio = Loop_Angle_Offset;
holy_vase_skip_loops = Skip_Loops;

holy_vase_triple_middle_hole_ratio = Middle_Loop_Ratio ;

scale_z_top = 1.5*1;
scale_z_bottom = 1.1*1;

style= Egg_Style;
style_line = 1*1;

emboss_ratio = Shell_Perentage;
emboss_tilt = Shell_Angle;

holy_fn = Basic_Shapes ;

fudge = 0.05*1;

create_egg();

//create_vase();

module create_egg() {

	move_up_z = (sphere_outside_d/2)*scale_z_bottom;
	translate([0,0,move_up_z]) {
		scale([1,1,scale_z_top]) {
			intersection() {
				union() {
					create_the_egg();
					if (style==4||style==5||style==6)
						basic_sphere_emboss ();
				}
				translate([0,0,(sphere_outside_d/2)/2])
					cylinder (r=sphere_outside_r+fudge,h=(sphere_outside_d/2+fudge),center=true);
			}

		}

		scale([1,1,scale_z_bottom]){
			intersection() {
				union() {
					create_the_egg();
					if (style==4||style==5||style==6)
						basic_sphere_emboss ();
				}
				translate([0,0,-(sphere_outside_d/2)/2])
					cylinder (r=sphere_outside_r+fudge,h=sphere_outside_d/2+fudge,center=true);
			}

		}
	}
}

module create_the_egg() {
	if (style==0)
		create_sphere_egg();
	if (style==1||style==4)
		create_single_holy_egg();
	if (style==2||style==5)
	 	create_double_holy_egg();
	if (style==3||style==6)
	 	 create_tripple_holy_egg();

}

module create_tripple_holy_egg () {

	intersection() {
		basic_sphere ();
		union() {
			for (i=[1:holy_vase_count]) {
				if (holy_vase_skip_loops==0 || round ((i+1)/2)*2 == i+1)
					tripple_top_holy_sphere (i,holy_vase_count);
			}
			for (i=[1:holy_vase_count]) {
				//if (holy_vase_skip_loops==0 || round ((i)/2)*2 == i)
					tripple_middle_holy_sphere (i,holy_vase_count);
			}
			for (i=[1:holy_vase_count]) {
				if (holy_vase_skip_loops==0 || round ((i+1)/2)*2 == i+1)
					tripple_bottom_holy_sphere (i,holy_vase_count);
			}
		}

	}
}

module tripple_top_holy_sphere (x,of) {

	delta_y = abs(sphere_top_z-sphere_base_z); // distance between top and bottom
	middle_hole_y = delta_y/3*holy_vase_triple_middle_hole_ratio/2/2;
	middle_hole_y_with_top_overlap = middle_hole_y + (sphere_top_z-middle_hole_y)*holy_vase_overlap_ratio;
	middle_hole_y_with_bottom_overlap = -middle_hole_y + (sphere_base_z+middle_hole_y)*holy_vase_overlap_ratio;

	top_hole_y_with_overlap = middle_hole_y - (middle_hole_y*2)*holy_vase_overlap_ratio;
	bottom_hole_y_with_overlap = -middle_hole_y + (middle_hole_y*2)*holy_vase_overlap_ratio;

	top_x = sphere_top_hole_r;
	top_y = sphere_top_z;

	bottom_y = top_hole_y_with_overlap;
	bottom_x = trig_b_for_a_c(bottom_y,sphere_outside_r);

	basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,0);

}

module tripple_bottom_holy_sphere (x,of) {

	delta_y = abs(sphere_top_z-sphere_base_z); // distance between top and bottom
	middle_hole_y = delta_y/3*holy_vase_triple_middle_hole_ratio/2/2;

	middle_hole_y_with_top_overlap = middle_hole_y + (sphere_top_z-middle_hole_y)*holy_vase_overlap_ratio;
	middle_hole_y_with_bottom_overlap = -middle_hole_y + (sphere_base_z+middle_hole_y)*holy_vase_overlap_ratio;

	top_hole_y_with_overlap = middle_hole_y - (middle_hole_y*2)*holy_vase_overlap_ratio;
	bottom_hole_y_with_overlap = -middle_hole_y + (middle_hole_y*2)*holy_vase_overlap_ratio;

	top_y = bottom_hole_y_with_overlap;
	top_x = trig_b_for_a_c(top_y,sphere_outside_r);

	bottom_x =sphere_base_r;
	bottom_y = sphere_base_z;

	if (holy_vase_spin_offset_ratio==0.25) {
		basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,0.5);
	} else {
		basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,0);
	}

}

module tripple_middle_holy_sphere (x,of) {

	delta_y = abs(sphere_top_z-sphere_base_z); // distance between top and bottom
	middle_hole_y = delta_y/3*holy_vase_triple_middle_hole_ratio/2/2;
	middle_hole_y_with_top_overlap = middle_hole_y + (sphere_top_z-middle_hole_y)*holy_vase_overlap_ratio;
	middle_hole_y_with_bottom_overlap = -middle_hole_y + (sphere_base_z+middle_hole_y)*holy_vase_overlap_ratio;

	top_hole_y_with_overlap = middle_hole_y - (middle_hole_y*2)*holy_vase_overlap_ratio;
	bottom_hole_y_with_overlap = -middle_hole_y + (middle_hole_y*2)*holy_vase_overlap_ratio;

	top_y = middle_hole_y_with_top_overlap;
	top_x = trig_b_for_a_c(top_y,sphere_outside_r);

	bottom_y = middle_hole_y_with_bottom_overlap;
	bottom_x = trig_b_for_a_c(bottom_y,sphere_outside_r);

	basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,holy_vase_spin_offset_ratio);

}

module create_double_holy_egg () {

	intersection() {
		basic_sphere ();
		union() {
			for (i=[1:holy_vase_count]) {
				if (holy_vase_skip_loops==0 || round ((i+1)/2)*2 == i+1)
					double_top_holy_sphere (i,holy_vase_count,0);
			}
			for (i=[1:holy_vase_count]) {
				double_bottom_holy_sphere (i,holy_vase_count);
			}
		}

	}

}

module double_top_holy_sphere (x,of) {

	top_x = sphere_top_hole_r;
	top_y = sphere_top_z;

	bottom_y = sphere_base_z*holy_vase_overlap_ratio;
	bottom_x = trig_b_for_a_c(bottom_y,sphere_outside_r);

	basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,0);

}

module double_bottom_holy_sphere (x,of) {

	top_y = sphere_top_z*holy_vase_overlap_ratio;
	top_x = trig_b_for_a_c(top_y,sphere_outside_r);

	bottom_x =sphere_base_r;
	bottom_y = sphere_base_z;

	basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,holy_vase_spin_offset_ratio);

}

module angled_out_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,spin_offset_ratio=0) {

	holy_wall = sphere_wall;
	holy_outside_d = distance (top_x,top_y,bottom_x,bottom_y);
	holy_outside_r = holy_outside_d/2;

	holy_inside_d=holy_outside_d-holy_wall*2;
	holy_inside_r=holy_inside_d/2;

	hole_outside_h = sphere_outside_r+fudge;

	tilt_angle = angle_to_midpoint (top_x,top_y,bottom_x,bottom_y);

	spin_angle = 360/of;

	holy_inside_ratio = ((holy_outside_r*holy_vase_hole_ratio)-(sphere_wall/2))/holy_inside_r;

	rotate(spin_angle*(x-1)+(spin_angle*spin_offset_ratio),[0,0,1])
		if (top_y+bottom_y>=0) {
			rotate(tilt_angle,[0,1,0])

				translate([0,0,hole_outside_h/2])
					difference() {
						scale([1,holy_vase_hole_ratio,1])
							cylinder(r=holy_outside_r,h=hole_outside_h ,center=true,$fn=holy_fn);
						scale([1,holy_inside_ratio,1])
							cylinder(r=holy_inside_r,h=hole_outside_h+fudge,center=true,$fn=holy_fn);

					}
		} else {
			rotate(tilt_angle+180,[0,1,0])

				translate([0,0,hole_outside_h/2])
					difference() {
						scale([1,holy_vase_hole_ratio,1])
							cylinder(r=holy_outside_r,h=hole_outside_h ,center=true,$fn=holy_fn);
						scale([1,holy_inside_ratio,1])
							cylinder(r=holy_inside_r,h=hole_outside_h+fudge,center=true,$fn=holy_fn);

					}
		}

}

module create_sphere_egg () {
	basic_sphere ();

}

module basic_sphere () {
	difference() {
   		sphere(r = sphere_outside_r);
		sphere(r = sphere_inside_r);
	}
}

module basic_sphere_emboss () {

	difference() {
   		sphere(r = sphere_middle_r);
		sphere(r = sphere_inside_r-2);

		if (emboss_ratio < 1)
			rotate(emboss_tilt,[0,1,0])
				translate([0,0,sphere_outside_r-(sphere_outside_d*(1-emboss_ratio))/2])
					cube([sphere_outside_d+fudge,sphere_outside_d+fudge,sphere_outside_d*(1-emboss_ratio)+fudge],center=true);

	}

}

module basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,spin_offset_ratio=0) {
	if(style_line==1)
		angled_out_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,spin_offset_ratio);

	if(style_line==2)
		angled_in_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,spin_offset_ratio);
}

module single_holy_sphere (x,of) {

	top_x = sphere_top_hole_r;
	top_y = sphere_top_z;
	bottom_x =sphere_base_r;
	bottom_y = sphere_base_z;

	basic_holy_sphere (top_x,top_y,bottom_x,bottom_y,x,of,0);

}

module create_single_holy_egg () {

	intersection() {
		basic_sphere ();
		union() {
			for (i=[1:holy_vase_count]) {
				single_holy_sphere (i,holy_vase_count);

			}
		}

	}

}

function trig_b_for_a_c(a,c) = sqrt((c*c)-(a*a));
function distance(x1,y1,x2,y2) = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
function angle_to_midpoint(x1,y1,x2,y2) = atan(((x1+x2)/2)/((y1+y2)/2));

```


[User]
Okay, I'm looking to create a customizable, multi-compartment container, kind of like a drawer insert or a parts organizer. I've already made a design, but I'd like it to be much more robust and parametric. Here's what I need:

**Overall Requirements:**

I need a function (or module) called `makeRoundedContainer` that generates the entire container. It should be possible to specify the following:

*   **Outer Dimensions:**
    *   `outerWidth`: The overall width of the container (X-axis).
    *   `outerHeight`: The overall height of the container (Y-axis).
    *   `outerDepth`: The overall depth of the container (Z-axis).

*   **Rounding:**
    *   `edgeRadius`: The radius of the rounded edges of the container (both outer and inner corners).

*   **Wall Thickness:**
    *   `wallThickness`: The thickness of the outer walls and the inner dividing walls.

*   **Internal Cells:**
    *   `numRows`: The number of rows of inner cells along the Z-axis.
    *   `numColumns`: The number of columns of inner cells along the X-axis.

*   **Clearance:**
    *   `clearance`: A uniform gap between cells to allow for tolerance in 3D printing (for both x and z directions between the cell, walls, and container). This should be added between the rounded edges for the internal walls.

**Desired Functionality:**

1.  **Rounded Corners/Edges:** All corners and edges (both external and internal) of the container and cells should be rounded with the specified `edgeRadius`. The code I have now uses `hull()` and spheres which works, but I'm wondering if there is a cleaner way to generate rounded boxes.

2.  **Cell Layout:** The internal cells should be arranged in a grid defined by the `numRows` and `numColumns` parameters. The cells should all have the same dimensions, automatically calculated from the other parameters (overall size, wall thickness, number of rows/columns, and clearance).

3.  **Parametric:** Everything must be parametric. Changing any of the input values should result in a correctly updated container.

4.  **Negative Space:** The container itself should be a solid block of material with negative space cut out for the individual cells.

5.  **Avoid Overlap:**  The cell layout should *not* cause the rounded edges of the internal walls to overlap if too many cells are requested with a large edge radius. (i.e., account for the space needed for the radius). My code currently tries to account for this, but it's not as clear.

6.  **No Overhangs:** The cells will all be the same height as the container. I'd like to make sure I avoid overhangs as much as possible. The height of the top walls should be flush with the top of each cell.

**Additional Considerations:**

*   I'm not looking for a bottom or lid at this stage; just the main body of the container with cells.
*   I'd like to use the `BOSL2` library if that makes things easier, particularly the `roundedCube` module, but I'm open to alternatives. Please make sure you include the appropriate `use` statement if you use the library. If there are other libraries you think might be helpful, let me know and we can explore them.
*   I'd like the code to be as clean and readable as possible, using comments to explain the steps.

Essentially, I want a very flexible and robust generator for multi-compartment containers. Let me know if you have any questions.

[Assistant]
multiRoundedContainer1.2.scad:
```
// Makerbot Customizer Parameters:
Outer_Container_Width = 100;
Outer_Container_Height = 40;
Outer_Container_Depth =  200;
Radius_InnerAndOuter_Edges =  10;
Wall_InnerAndPartition_Thickness  = 1.5;
Number_Inner_Cell_Rows = 3;
Number_Inner_Cell_Columns = 2;

// Make Container
makeContainer(
	Outer_Container_Width, 				// Outer Container Width (X)
	Outer_Container_Height, 			// Outer Container Height (Y)
	Outer_Container_Depth, 				// Outer Container Depth (Z)
	Radius_InnerAndOuter_Edges, 		// Radius of Rounded Inner/Outer Edgers
	Wall_InnerAndPartition_Thickness, 	// Outer Wall & Inner Partition Thickness
	Number_Inner_Cell_Rows, 			// Number of Rows for Inner Cells (X)
	Number_Inner_Cell_Columns			// Number of Columns for Inner Cells (Z)
);

// Create Multi Rounded Container
module makeContainer(
	intWidth,
	intHeight,
	intDepth,
	intRadius,
	intWallthickness,
	intRowsSpecified,
	intColumnsSpecified) {

	// Fix invlaid column/row numbers, in case 0 is entered
	intColumns = (intColumnsSpecified == 0) ? 1 : intColumnsSpecified;
	intRows = (intRowsSpecified == 0) ? 1 : intRowsSpecified;

	// Calculate Cell Dimensions
	intContainerCell_Width = ((intWidth - (((intColumns -1) * intWallthickness) + (intWallthickness * 2))) / intColumns) - ((intColumns > 1) ? ((intRadius*2)*(intColumns-1))/intColumns:0);
	intContainerCell_Height = intHeight;
	intContainerCell_Depth = ((intDepth - (((intRows -1) * intWallthickness) + (intWallthickness * 2))) / intRows) - ((intRows > 1) ? ((intRadius*2)*(intRows-1))/intRows:0);

	// Calculate Base Positions
	intBaseXPosition = intWallthickness;
	intBaseYPosition = intWallthickness+0.1;
	intBaseZPosition = intWallthickness;

	// Define Position Functions
	function getXPosition(intColumnIndex) = intBaseXPosition + ((intContainerCell_Width+intBaseXPosition) * (intColumnIndex-1)) + ((intColumnIndex > 1) ? ((intRadius*2)*(intColumnIndex-1)):0);
	function getZPosition(intRowIndex) = intBaseZPosition + ((intContainerCell_Depth+intBaseZPosition) * (intRowIndex-1)) + ((intRowIndex > 1) ? ((intRadius*2)*(intRowIndex-1)):0);

	// Create Container
	difference() {
		// Create Solid Shape
		createContainerShape(intWidth, intHeight, intDepth, intRadius);
		// Cut Out Inner Cells
		for (intRowCount= [1: intRows])
		{
			for (intColumnCount = [1: intColumns])
			{
			    	translate (v=[getXPosition(intColumnCount),intBaseYPosition,getZPosition(intRowCount)]) {
					createContainerShape(intContainerCell_Width, intContainerCell_Height, intContainerCell_Depth, intRadius);
				}
			}
		}
	}
}

// Create Container Shape
module createContainerShape(
	width,
	height,
	depth,
	radius) {

	// Create Shape
	hull() {
		// Base
		translate(v = [0, 0, 0]) { sphere(r=radius); }
		translate(v = [width, 0, 0]) { sphere(r=radius); }
		translate(v = [width, 0, depth]) { sphere(r=radius); }
		translate(v = [0, 0, depth]) { sphere(r=radius); }
		// Top
		translate(v = [0, height, 0]) { rotate(a=[90,0,0]) { cylinder(h=1, r=radius, center = true); } }
		translate(v = [width, height, 0]) { rotate(a=[90,0,0]) { cylinder(h=1, r=radius, center = true); } }
		translate(v = [width, height, depth]) { rotate(a=[90,0,0]) { cylinder(h=1, r=radius, center = true); } }
		translate(v = [0, height, depth]) { rotate(a=[90,0,0]) { cylinder(h=1, r=radius, center = true); } }
	}
}
```


[User]
Okay, I'm looking to create a customizable 3D-printable spear for lionfish hunting, based on the existing design I found online. I've seen some basic versions, but I'd really like a more parametric model so I can adjust it to my own needs.

Specifically, I'm thinking about something with the following features:

*   **Main Spear Shaft:** This should be a cylinder with an adjustable radius (thickness) and length. I need to be able to set the radius and the length separately.
*  **Spike Bar:** This is the bar that connects the main spear shaft to the actual spikes. It should be a cylindrical bar perpendicular to the spear shaft, with adjustable length and radius.
*   **Spikes:** I want to have multiple spikes coming off of the spike bar. The number of spikes should be adjustable, as well as the length of the main spike (the longer part) and the length of the short barb portion at the tip of the spike. I'd also like to adjust the radius of the spikes. The spikes should also be evenly spaced around the spike bar. Ideally, the barb would be like a small cone or rounded point, also with an adjustable radius.
*   **Rotation:** The base spear shaft should run along the y-axis, with the bar running along the x-axis. I need to be able to rotate the entire design using x, y, and z rotation parameters, but for now the rotation should start at 0 for all axes.

For all parameters, I need to set minimum and maximum values. The original file uses sliders to adjust the parameters which makes it easy to visualize. Here's what I envision:

*   `radius_cylinder`: The radius of the main spear shaft and spike bar. Minimum: 0, Maximum: 30.
*   `height_spikes`: The length of the barb at the tip of each spike. Minimum: 0, Maximum: 200.
*   `spike_length`: The length of the main part of each spike. Minimum: 0, Maximum: 200.
*  `spike_bar_width`: The length of the spike bar. Minimum 15, Maximum 300.
*   `Number_of_spikes`:  Number of spikes on the spike bar. Minimum 0, Maximum 12.
*  `width_of_spikes`: The number of sides on the spike bar. Minimum 0, Maximum 12.
* `radius_spike`: The radius of the barb on the spike.

I want the code to be in OpenSCAD and be easily customizable by the user. I don't need any external libraries for this. Thanks!

[Assistant]
spear.scad:
```
// How thick the spear should be?
radius_cylinder=5;//[0:30]

// How long the spike should be?
height_spikes=120;//[0:200]

// How long the spike top should be?
spike_length=160;//[0:200]

sum=height_spikes+spike_length;

// How wide the spike bar should be?
spike_bar_width=90;//[15:300]
bar=spike_bar_width;

// Number of spikes?
Number_of_spikes=3;//[0,1,2,3,4,5,6,7,8,9,10,11,12]

a=Number_of_spikes-1;
//This option will not apear
rotate_z=90*1;
//This option will not apear
rotate_y=0*1;

//width of spikes
width_of_spikes=3;//[0,1,2,3,4,5,6,7,8,9,10,11,12]

//adjust size spike thing
radius_spike=5;

b=width_of_spikes;

dis=spike_bar_width/a;

module spear()
{
translate([0,bar/2,0])rotate([0,90,0])cylinder(100,r=radius_cylinder);
translate([0,bar,0])rotate([90,0,0])cylinder(spike_bar_width,r=radius_cylinder);

translate([0,0,0])sphere(5,r=radius_cylinder);
translate([0,bar,0])sphere(5,r=radius_cylinder);

//spikes

for(i=[0:a])
{

translate([-spike_length,dis*i,0])rotate([0,90,0])cylinder(spike_length,r=radius_cylinder);
translate([-sum,dis*i,0])rotate([0,90,0])cylinder(height_spikes,0,r2=radius_cylinder);
translate([-sum,dis*i,0])rotate([rotate_x,rotate_z,rotate_y])cylinder(height_spikes,0,r2=radius_spike);
for(y=[0:b])
{
translate([-sum,dis*i,0])rotate([y,rotate_z,rotate_y])cylinder(height_spikes,0,r2=radius_spike);
}
}
}
spear();
```


[User]
Okay, I'm looking to make a St. Patrick's Day chain, kind of like a necklace or maybe something I could hang up. I've got a basic idea in mind, and I'd like to have it generated as an OpenSCAD file.

Here's what I need:

1.  **Shamrock Links:** The chain should be made of interconnected shamrock-shaped links. I'd like to be able to adjust the scale of these shamrocks and the thickness of the material, so they look right.

2.  **Chain Type:** I want to be able to choose between making a straight chain or a closed loop. A closed loop would work better for a necklace, while a straight one might work better as a banner.

3. **Chain Length:** I want to control the number of links used to make up the chain. More links should mean a longer chain.

4.  **Parametric Design:** The design needs to be parametric so I can adjust the following properties:
    *   `Links`:  The total number of links in the chain.
    *   `T`: The thickness of the material (how thick the shamrock links are).
    *   `Scale`: The size of the shamrock link, approximately how wide it is from end to end.
    *   `Type`:  A switch, probably `0` for a straight chain and `1` for a closed loop.

5.  **OpenSCAD file:** I need the result to be a single OpenSCAD file I can directly open in the OpenSCAD program and modify myself if needed.

6.  **Link Structure:** The links should connect to each other with a simple pin and hole mechanism for easy assembly (or printing). I want each link to be identical except that every other link is flipped to correctly attach to the next.

7.  **No Library Dependencies:** I don't want to rely on any external libraries. Please keep everything self-contained in a single OpenSCAD file.

I think that covers it. Let me know if you need any more information, but it seems fairly straightforward.

[Assistant]
Shamrock_Chain.scad:
```
//Select Type of Print
Type=1; // [0:Straight Chain,1:Closed Loop]
//Select number of links
Links=11; // [1:100]
//Thickness of Chain Links
T=1;
//Scale of Chain Link (approx mm end to end)
Scale=30;

module Shamrock(h){
  scale([25.4/90, -25.4/90, 1]) union()
  {
    linear_extrude(height=h)
      polygon([[-3.057506,16.708888],[-3.553250,34.685854],[-3.204347,47.940543],[-2.123063,57.100584],[-1.342863,60.341246],[-0.421667,62.793608],[1.725876,59.570553],[3.901054,56.637945],[6.157715,54.561744],[7.333428,54.021657],[8.549705,53.907908],[3.738222,29.682176],[2.234131,20.065375],[2.086113,16.929117],[2.485014,15.306908],[6.235771,22.631579],[10.413383,28.738632],[14.905644,33.677575],[19.600348,37.497912],[24.385287,40.249148],[29.148257,41.980790],[33.777050,42.742344],[38.159460,42.583314],[42.183281,41.553207],[45.736306,39.701527],[48.706329,37.077782],[50.981144,33.731476],[52.448544,29.712115],[52.996323,25.069204],[52.512275,19.852250],[50.884193,14.110758],[54.098436,11.997054],[56.770070,9.379290],[58.873755,6.366319],[60.384149,3.066995],[61.275912,-0.409829],[61.523703,-3.955299],[61.102182,-7.460562],[59.986009,-10.816765],[58.149842,-13.915053],[55.568341,-16.646575],[52.216166,-18.902475],[48.067976,-20.573901],[43.098430,-21.551999],[37.282188,-21.727916],[30.593909,-20.992798],[23.008253,-19.237792],[26.914246,-23.340867],[29.862537,-27.730794],[31.906566,-32.295076],[33.099776,-36.921215],[33.495611,-41.496713],[33.147510,-45.909073],[32.108918,-50.045796],[30.433277,-53.794385],[28.174027,-57.042342],[25.384613,-59.677170],[22.118476,-61.586370],[18.429058,-62.657446],[14.369802,-62.777898],[9.994149,-61.835231],[5.355543,-59.716944],[0.507426,-56.310542],[-3.222046,-59.335469],[-7.094410,-61.387173],[-11.013628,-62.521329],[-14.883659,-62.793608],[-18.608461,-62.259682],[-22.091995,-60.975224],[-25.238221,-58.995907],[-27.951096,-56.377402],[-30.134582,-53.175383],[-31.692638,-49.445520],[-32.529222,-45.243488],[-32.548295,-40.624957],[-31.653817,-35.645601],[-29.749746,-30.361091],[-26.740042,-24.827101],[-22.528664,-19.099302],[-29.897165,-21.451402],[-36.467612,-22.578327],[-42.250192,-22.617615],[-47.255093,-21.706803],[-51.492501,-19.983426],[-54.972604,-17.585022],[-57.705588,-14.649128],[-59.701642,-11.313280],[-60.970951,-7.715014],[-61.523703,-3.991868],[-61.370085,-0.281378],[-60.520285,3.278919],[-58.984488,6.551487],[-56.772883,9.398789],[-53.895657,11.683288],[-50.362995,13.267448],[-52.094096,17.674549],[-52.854572,22.043268],[-52.718478,26.262058],[-51.759873,30.219371],[-50.052814,33.803661],[-47.671358,36.903381],[-44.689561,39.406984],[-41.181482,41.202923],[-37.221177,42.179650],[-32.882703,42.225620],[-28.240118,41.229285],[-23.367479,39.079099],[-18.338842,35.663514],[-13.228266,30.870983],[-8.109806,24.589960],[-3.057521,16.708898]]);
  }
}

module PrintLink1(){
	difference(){
		translate([3.5,0,0]) rotate([0,0,35]) Shamrock(T/SC);
		translate([0,12.5,0]) cylinder(r=4,h=(T*3)/SC,$fn=50,center=true);
		translate([0,-10.75,0]) cylinder(r=4,h=(T*3)/SC,$fn=50,center=true);
		translate([-20,-20,-T/SC]) cube([20,40,(T*4)/SC]);
	}
	rotate([0,60,0]) difference(){
		translate([3.5,0,0]) rotate([0,0,35]) Shamrock(T/SC);
		translate([0,12.5,0]) cylinder(r=4,h=(T*3)/SC,$fn=50,center=true);
		translate([0,-10.75,0]) cylinder(r=4,h=(T*3)/SC,$fn=50,center=true);
		translate([0,-20,-T/SC]) cube([40,40,(T*3)/SC]);
	}

}
module StraightChain(){
	for (i=[1:Links]){
		if (i%2==1){
			translate([0,28*(i-1),0]) PrintLink1();
		} else {
			translate([1,28*(i-1),0]) mirror([1,0,0]) PrintLink1();
		}
	}
}
module LoopChain(){
	for (i=[1:Links]){
		rotate([0,0,i*Seg]) translate([Rad,0,0])
		if (i%2==1){
			PrintLink1();
		} else {
			translate([0,0,0]) mirror([1,0,0]) PrintLink1();
		}
	}
}

Pi=3.1415926535897;
Seg=360/Links;
Rad=(Links*28)/(2*Pi);

SC=Scale/30;
fudge=0.1;
if (Type==0){
	scale([SC,SC,SC]) StraightChain();
} else {
	scale([SC,SC,SC]) LoopChain();
}
```


[User]
Okay, I need a parametric fan mount, and I have some specific requirements based on an existing design.

I'm starting with the "fan_mount_modded_cun83.scad" file, which uses the MCAD library for nuts and bolts. I'll include the code I have, but I need some modifications.

The current design allows selection of different fan sizes (40mm, 60mm, 80mm, and 120mm) by setting the `fan_ctc` parameter, and different mounting screw sizes (M3, M4, and M5) via the `mounting_screw` parameter. It also allows you to shift the mounting position horizontally across the mount with the `mounting_pos_customizer` parameter. The mount has a rectangular center section with rounded side supports that connect to the fan mounting bracket. The mounting holes for the fan itself are integrated into the rounded side supports.

Here are the changes I need:

1.  **Fan Mounting Hole Outer Diameter:** I need to be able to control the *outer diameter* of the cylinder that surrounds the fan mounting holes on the bracket. Currently, these are fixed based on a 4mm bolt hole, and I want the option to make these larger for more strength. I need a new parameter called `fan_mounting_hole_outer_diameter`. This value should default to 4.3 but be adjustable to increase the amount of plastic around those holes.

2. **Square Bottoms for Fan Mounting Holes:** I'd like the option to make the bottom edges of the fan mounting holes *square* instead of cylindrical. This is to remove overhangs on the circular edges. This should be a boolean parameter called `square_bottom_fan_mount_holes`, defaulting to `false`.

3. **Customizer Support:** Please ensure that all of these parameters are usable through the OpenSCAD Customizer.  `fan_ctc` (Fan Size), `mounting_screw` (Mounting Screw Size), `mounting_pos_customizer`(Mounting Position), `fan_mounting_hole_outer_diameter`, and `square_bottom_fan_mount_holes` should all be usable through the customizer, as well as the existing parameter `print_rectangular_bottom_edges`.

I'd like the other parameters from the original file to remain in place. Here's the code from the original file, for reference:

```
include <MCAD/nuts_and_bolts.scad>

$fn=100 + 0;

////////// Parameter Selection ///////////

//fan_ctc = 105; //  uncomment for 120mm fan
//fan_ctc = 71.5; //       ""         for 80mm fan
//fan_ctc = 50; //          ""         for 60mm fan
//fan_ctc = 32; //            ""         for 40mm fan

//Fan size
fan_ctc = 105; // [32:40mm,50:60mm,71.5:80mm,105:120mm]

//Mounting screw size
mounting_screw = 5; // [3:M3,4:M4,5:M5]

//Mounting position
mounting_pos_customizer = 0; // [-100:100]
mounting_pos = mounting_pos_customizer / 100.0;

// choose   -1 = left,   0 = center,   1=right
					// fractional sizes between 0 and +/- 1 accepted!

//////////////////////////////////////////////

offset = mounting_pos*(fan_ctc/2-4-15/2-3);

// Height
height = 6;
// Thickness
thickness = 7.5;//7.5;

// Outer Radius
radius_outer = 6;

// Use rectangular bottom edges?
print_rectangular_bottom_edges = 1; //[1:Yes, 0:No]

difference(){
union(){
translate([offset,-10,0]) cube([15,20,height],center=true);
bracket();
translate([-15/2+0.3+offset,-4+0.6,0]) fillet(4,height);
translate([15/2-0.3+offset,-4+0.6,0]) rotate([0,0,90]) fillet(4,height);
}

if (mounting_screw == 3){
translate([offset,-20/2-mounting_screw/2,0.5])
rotate([180,0,0]) boltHole(mounting_screw,units="MM",length=30,tolerance=0.25);
}

else if (mounting_screw == 4){
translate([offset,-20/2-mounting_screw/2,0.5])
rotate([180,0,0]) boltHole(mounting_screw,units="MM",length=30,tolerance=0.25);

}

else if (mounting_screw == 5){
translate([offset,-20/2-mounting_screw/2,0])
rotate([180,0,0]) boltHole(mounting_screw,units="MM",length=30,tolerance=0.25);
}

translate([offset,-20/2-mounting_screw/2,0])
cylinder(r=mounting_screw/2+0.25,h=100,center=true);

}

module bracket(){
difference(){
union(){
cube([fan_ctc+4,thickness,height],center=true);
translate([fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=radius_outer,h=thickness,center=true);
translate([-fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=radius_outer,h=thickness,center=true);
translate([-fan_ctc/2+2.85,0,height/2-0.2]) rotate([0,0,90]) rotate([0,90,0]) fillet(4,thickness);
translate([fan_ctc/2-2.85,0,height/2-0.2]) rotate([0,0,-90]) rotate([0,90,0]) fillet(4,thickness);
if(print_rectangular_bottom_edges) {
	translate([fan_ctc/2,0,0]) rotate([90,0,0]) cube([radius_outer*2,height,thickness], center=true);
	translate([-fan_ctc/2,0,0]) rotate([90,0,0]) cube([radius_outer*2,height,thickness],center=true);
}
}
translate([fan_ctc/2,-0.5,height/2]) rotate([-90,0,0]) boltHole(4,units="MM",length=30,tolerance=0.25);
translate([fan_ctc/2,-0.5-100,height/2]) rotate([-90,0,0]) cylinder(r=4.3, h=100);
translate([fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=2+0.25,h=100,center=true);
translate([-fan_ctc/2,-0.5,height/2]) rotate([-90,0,0]) boltHole(4,units="MM",length=30,tolerance=0.25);
translate([-fan_ctc/2,-0.5-100,height/2]) rotate([-90,0,0]) cylinder(r=4.3, h=100);
translate([-fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=2+0.25,h=100,center=true);
}}

module fillet(rad,height){
translate([-2*sqrt(rad),-2*sqrt(rad),0])
difference(){
translate([0,0,-height/2]) cube([rad-0.2,rad-0.2,height]);
cylinder(h=height+1,r=rad,center=true);
}}
```

Please provide the updated OpenSCAD code.

[Assistant]
fan_mount_modded_cun83.scad:
```
include <MCAD/nuts_and_bolts.scad>

$fn=100 + 0;

////////// Parameter Selection ///////////

//fan_ctc = 105; //  uncomment for 120mm fan
//fan_ctc = 71.5; //       ""         for 80mm fan
//fan_ctc = 50; //          ""         for 60mm fan
//fan_ctc = 32; //            ""         for 40mm fan

//Fan size
fan_ctc = 105; // [32:40mm,50:60mm,71.5:80mm,105:120mm]

//Mounting screw size
mounting_screw = 5; // [3:M3,4:M4,5:M5]

//Mounting position
mounting_pos_customizer = 0; // [-100:100]
mounting_pos = mounting_pos_customizer / 100.0;

// choose   -1 = left,   0 = center,   1=right
					// fractional sizes between 0 and +/- 1 accepted!

//////////////////////////////////////////////

offset = mounting_pos*(fan_ctc/2-4-15/2-3);

// Height
height = 6;
// Thickness
thickness = 7.5;//7.5;

// Outer Radius
radius_outer = 6;

// Use rectangular bottom edges?
print_rectangular_bottom_edges = 1; //[1:Yes, 0:No]

difference(){
union(){
translate([offset,-10,0]) cube([15,20,height],center=true);
bracket();
translate([-15/2+0.3+offset,-4+0.6,0]) fillet(4,height);
translate([15/2-0.3+offset,-4+0.6,0]) rotate([0,0,90]) fillet(4,height);
}

if (mounting_screw == 3){
translate([offset,-20/2-mounting_screw/2,0.5])
rotate([180,0,0]) boltHole(mounting_screw,units="MM",length=30,tolerance=0.25);
}

else if (mounting_screw == 4){
translate([offset,-20/2-mounting_screw/2,0.5])
rotate([180,0,0]) boltHole(mounting_screw,units="MM",length=30,tolerance=0.25);

}

else if (mounting_screw == 5){
translate([offset,-20/2-mounting_screw/2,0])
rotate([180,0,0]) boltHole(mounting_screw,units="MM",length=30,tolerance=0.25);
}

translate([offset,-20/2-mounting_screw/2,0])
cylinder(r=mounting_screw/2+0.25,h=100,center=true);

}

module bracket(){
difference(){
union(){
cube([fan_ctc+4,thickness,height],center=true);
translate([fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=radius_outer,h=thickness,center=true);
translate([-fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=radius_outer,h=thickness,center=true);
translate([-fan_ctc/2+2.85,0,height/2-0.2]) rotate([0,0,90]) rotate([0,90,0]) fillet(4,thickness);
translate([fan_ctc/2-2.85,0,height/2-0.2]) rotate([0,0,-90]) rotate([0,90,0]) fillet(4,thickness);
if(print_rectangular_bottom_edges) {
	translate([fan_ctc/2,0,0]) rotate([90,0,0]) cube([radius_outer*2,height,thickness], center=true);
	translate([-fan_ctc/2,0,0]) rotate([90,0,0]) cube([radius_outer*2,height,thickness],center=true);
}
}
translate([fan_ctc/2,-0.5,height/2]) rotate([-90,0,0]) boltHole(4,units="MM",length=30,tolerance=0.25);
translate([fan_ctc/2,-0.5-100,height/2]) rotate([-90,0,0]) cylinder(r=4.3, h=100);
translate([fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=2+0.25,h=100,center=true);
translate([-fan_ctc/2,-0.5,height/2]) rotate([-90,0,0]) boltHole(4,units="MM",length=30,tolerance=0.25);
translate([-fan_ctc/2,-0.5-100,height/2]) rotate([-90,0,0]) cylinder(r=4.3, h=100);
translate([-fan_ctc/2,0,height/2]) rotate([90,0,0]) cylinder(r=2+0.25,h=100,center=true);
}}

module fillet(rad,height){
translate([-2*sqrt(rad),-2*sqrt(rad),0])
difference(){
translate([0,0,-height/2]) cube([rad-0.2,rad-0.2,height]);
cylinder(h=height+1,r=rad,center=true);
}}
```


[User]
Okay, I have a design for a Schmidt coupling that I want to make more robust and easier to print. Right now, it's a bit rough around the edges.

Here's a breakdown of what I'm working with:

**Functionality:**
The Schmidt coupling is designed to transmit rotational power between two parallel axles that can move relative to each other. This means it needs to handle a bit of offset between the input and output shafts. It should be able to handle higher loads compared to a standard double cardan joint.

**Current Design (based on the provided SCAD file):**

*   **Parts:** The assembly consists of:
    *   2 outer "tricrosses"
    *   1 inner "tricross"
    *   6 connectors
    *   6 short pins
    *   3 long pins
    *   2 main pins
*   **Parametric:** The design is already somewhat parametric, with the following parameters:
    *   `_1_max_displacement` (or `smax`): The maximum allowable displacement between the axles. This is a key parameter.
    *   `_2_part` (or `part`): Selects which part to generate (full assembly, a single part, etc.).
    *   `rmainpin`: Radius of the main pin.
    *   `lmainpin`: Length of the main pin.
    *   `dcenter` (or `rcenter`): Diameter/radius of the center plates of the tricross.
    *   `dconn` (or `rconn`): Diameter/radius of the connector pieces.
    *   `dpin` (or `rpin`): Diameter/radius of the connector pins (currently coupled to long/short pin radius)
    *   `tconn`: Thickness of all pieces.
    *   `b`: Edge breaking amount (fillet/chamfer).
    *   `$fa`: Angular resolution.
    *   `$fs`: Minimum segment length.
    *   `alpha` and `beta`: Assembly orientation angles.

*   **Libraries:** It includes the `pins.scad` file, which I assume defines pin geometries (it's not shown in the code I provided), likely defining a `pinpeg` and `pinhole` module.

**Problems and Desired Improvements:**

1.  **Clearance:** This is the biggest problem I need help with. The pins in the current design fit *too* tightly. I need a way to add clearance between the pins and the holes to make the assembly printable and functional. This should be a *parametric clearance* value, so that I can easily adjust it to different printing tolerances. I need this clearance applied for _all_ pin/hole connections across _all_ parts. I'm imagining that this would probably involve changing `pinhole()` calls and adding parameters.

2.  **Stiffness of short pins:** The short pins are reported to be too stiff. I suspect this is related to the tight tolerances, but might also require design changes. I am willing to make changes to pin geometry to accommodate this.

3.  **Thickness:** The parts, in general, are too thick, which makes the whole thing clunky. I'd like a parameter, perhaps `t_scale`, that I can reduce to try making them thinner, which *all* thickness parameters should use as a factor. So something like `tconn` should really be `tconn * t_scale`, and I would then just reduce t_scale to a reasonable value, and every part gets thinner.

4.  **Main Pin Size:** The `lmainpin` variable is currently set to `2*tconn+2`. The comment in the file says to choose the size to "fit hexwidth". I think the better design for `lmainpin` would be a length equal to the combined thickness of the two parts connected, + some amount for free movement, and a little extra length for a small fillet on the end, or a hex-shaped section as mentioned.

5. **Naming:** Some names like `lbar` and `tconn` aren't very clear. I would like those improved.

6. **Organization:** The functions should be organized by purpose (e.g. module declarations, mathematical calculations, utility functions).

**Request to AI Assistant:**

I need you to generate a new parametric OpenSCAD file that addresses the issues I've outlined. Please provide:

1.  **Parametric Clearance:** A new parameter (e.g., `pin_clearance`) that controls the clearance between all pins and holes. This should apply to all uses of `pinhole()` and any other functions involved in pin/hole connections, probably by passing in the clearance value.
2.  **Adjustable Thickness**: A new parameter, `t_scale`, that scales the thickness of all parts. All thickness parameters should use this, like `tconn * t_scale`.
3. **Adjustable Main Pin Length:** Update `lmainpin` calculation to be a function of `tconn`, + a bit of extra for clearance, with an optional parameter for the length of a chamfer or hex section to grip with a wrench.
4.  **Pin Modification:** Explore options for modifying the short pin geometry to make them less stiff. You can suggest different geometries based on your expertise.
5.  **Code Organization:** The code should be well organized and well documented.
6.  **Clear Naming:** Parameter names should be more descriptive (e.g., `connector_thickness` instead of `tconn`).

Please use `pins.scad` from the current design for pin/hole generation. Let me know if I need to provide that file.

[Assistant]
schmidt-coupling-parametric-.scad:
```

// 2013 Lukas Süss
// Schmidt Style Coupling (parametric)
// license: CC-BY

/*
### Thingiverse description:

This is a mechanism to transmit rotation power between two axles that can move relative to one another but stay parallel at all times. It can take higher loads than a doublecardan joint.

it was inspired by this:
  http://www.thingiverse.com/thing:14060

and it is intended as a drive for my moineau pump model
  http://www.thingiverse.com/thing:28237

### Thingiverse Instructions:

You'll need the following parts for a full set:
 2 outertricrosses
 1 innertricross
 6 connectors
 6 Short pins
 3 long pins
 2 main pins
 = 20 Parts total (of 6 types)

At the moment it's not included in a whole working machine.
So you have to make your application and this one fit together yourself.

(main pin standard length is choosen for a 2mm thick washer)
*/

//use <pins.scad>;
include <pins/pins.scad> // trouble??

//######### customizer parameters

// maximum axle displacement (choose as low as possible for you application but dont let the pins merge)
_1_max_displacement = 22;
smax = _1_max_displacement;

// choose the part to generate
_2_part = "fullassembly"; // [fullassembly,printplate,connector,innertricross,outertricross,longpin,shortpin,mainpin]
part = _2_part;

//part = "fullassembly";
//part = "printplate"; // F6 slow !!
//part = "outertricross";
//part = "innertricross";
//part = "connector";
//part = "shortpin";
//part = "longpin";
//part = "mainpin";

//diameter of input and output pin
rmainpin = 6;

// length of main pin
lmainpin = 26;
//lmainpin = 2*tconn+2; // suggestion
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< choose size to fit hexwidth ??

//diameter of center plates
dcenter = 20;
rcenter = dcenter/2;

// diameter and width of connector pieces
dconn = 12.5;
rconn = dconn/2;

// connector pin diameter (keep >= 8)
dpin = 8;
rpin = dpin/2;  // decouple?? <<<<<<<<<<

// thickness of all pieces (keep > 10)
tconn = 12;

// edge breaking
b = 1;

// resolution: segments per angle
$fa = 4;

// resolution: minimal segment length
$fs = 0.75;

// ##########

// calculate lbar from lconn
gap = 1*1; // hide from customizer
lconn = smax/2;
lbar = (lconn+2*rconn+gap)/2/sin(60);

// fullassembly orientation parameters
alpha =   30*1; //shiftangle 1 //30° is the critical angle to check
beta  = 30+150; //shiftangle 2   [0,180]

//##########################################################

if(part == "fullassembly") fullassembly();
if(part == "connector") conn();
if(part == "innertricross") innertricross();
if(part == "outertricross") outertricross();
if(part == "longpin") longpin();
if(part == "shortpin") shortpin();
if(part == "mainpin") mainpin();
if(part == "printplate") plate();

module plate()
{
  for(i=[0:5])
  {
   translate([rconn*2*1.2*i,0,0])
   {
     translate([0,-rconn*1.2,0])
     rotate(-90,[0,0,1]) conn(); // x6
     translate([0,tconn,0]) shortpin(); // x6
   }
  }
  for(i=[0:2])
  {
    translate([-rconn*2-(i*rpin*2*1.5),0,0])
      longpin(); // x3
  }
  translate([-rconn*2-rpin*3*3-lbar,0,0])
  rotate(180,[0,0,1])
    innertricross(); // x1

  translate([-rconn*2-lmainpin/2,+(tconn*1.5+rmainpin*1.5),0]) rotate(90,[0,0,1])
    mainpin(); // x2
  translate([-rconn*2-lmainpin/2,-(tconn*1.5+rmainpin*1.5),0]) rotate(90,[0,0,1])
    mainpin(); // x2

  translate([-rconn*2-rpin*3*3-lbar*1.5,+(lbar*2),0])
    outertricross();  // x2
  translate([-rconn*2-rpin*3*3-lbar*1.5,-(lbar*2),0])
    outertricross();  // x2
}

module fullassembly()
{
  outertricross();
  translate([lconn*cos(alpha),lconn*sin(alpha),tconn*2])
  {
    innertricross();
    translate([lconn*cos(beta),lconn*sin(beta),tconn*2])
     swap() outertricross();
  }
  color("orange")
  translate([0,0,tconn*1]) distribute() conn(alpha);
  color("orange")
    translate([lconn*cos(alpha),lconn*sin(alpha),0])
  translate([0,0,tconn*3]) distribute() conn(beta);
}

// #####################################################

module longpin()  { pinpeg(h=tconn*3, r=rpin, lh=3, lt=1, t=0.2); }
module shortpin() { pinpeg(h=tconn*2, r=rpin, lh=3, lt=1, t=0.2); }
module mainpin()  { pinpeg(h=lmainpin, r=rmainpin, lh=3, lt=1, t=0.2); }

module conn(tetha=0)
{
  rotate(tetha,[0,0,1])
  difference()
  {
    hull()
    {
      bcyl(rconn,tconn,b);
      translate([lconn,0,0]) bcyl(rconn,tconn,b);
    }
    union()
    {
      pinhole(h=tconn, r=rpin, lh=3, lt=1, t=0.3, tight=true, fixed=false);
      translate([lconn,0,0]) swap()
        pinhole(h=tconn, r=rpin, lh=3, lt=1, t=0.3, tight=true, fixed=false);
    }
  }
}

module outertricross(phi=0)
{
  difference()
  {
    tricross(phi=0);
      pinhole(h=tconn, r=rmainpin, lh=3, lt=1, t=0.3, tight=true, fixed=true);
    // cuts for short pins
    distribute() // swap unusable since stacked child() unsupported :(
    translate([0,0,tconn]) scale([1,1,-1])
      pinhole(h=tconn, r=rpin, lh=3, lt=1, t=0.3, tight=true, fixed=false);
  }
}
module innertricross(phi=0)
{
  difference()
  {
    tricross(phi=0);
    translate([0,0,-tconn*0.1]) cylinder(r=10/2,h=tconn*1.2);
    // cylinder cuts for long pins <<<<<<<<<<<<<<<<<<<
    distribute() translate([0,0,-tconn*0.1]) cylinder(r=rpin+0.1,h=tconn*1.2);
  }
}

// basic shape
module tricross(phi=0)
{
  rotate(phi,[0,0,1])
  {

    difference() // redmove?
    {
      union()
      {
        //cylinder(r=rcenter,h=tconn);
        bcyl(rcenter,tconn,b);
        for(i=[0:2])
        {
          rotate(120*i,[0,0,1])
          hull()
          {
            bcyl(rconn,tconn,b);//cylinder(r=rconn,h=tconn);
            translate([lbar,0,0]) bcyl(rconn,tconn,b);
          }
        }
      }
    }

  }
}

// ########################### util functions
module swap()
{
  translate([0,0,tconn]) scale([1,1,-1]) child();
}

module distribute()
{
  function phi(i) = 120*i;
  for(i=[0:2])
  {
    translate([lbar*cos(phi(i)),lbar*sin(phi(i)),0]) child();
  }
}

module bcyl(rr,hh,b)
{
  hull()
  {
    translate([0,0,b]) cylinder(r=rr,h=hh-2*b);
    cylinder(r=rr-b,h=hh);
  }
}
// #########################################

/*
maybe TODO:
? make mainpin with electrodrillbit hexshape on one site
? optional: make pinholes symmetric ?

Application specific notes:
axle displacement length needed for a quite big moineau pump is around
10mm in whole 5mm to one side and 2.5mm/stage
this cant be archived due to pin diameter :S
still it works it just looks a little ugly
*/

```


[User]
Okay, so I've been playing around with making a roller bearing in OpenSCAD, and I've got a decent start, but it's got a significant issue. I found this gear bearing on Thingiverse (http://www.thingiverse.com/thing:53451) and wanted to try a roller version. The current design uses a central sun gear, an outer ring, and a number of cylindrical rollers (planets) in between. It's basically three concentric parts: the inner gear with a hexagonal core, an outer ring that's a simple cylinder, and the rollers in between. I've got it mostly working but the rollers tend to spin around their own axes when the bearing turns, which isn't ideal.

I've included my current OpenSCAD code below:

```
//Roller Bearing
// (C) 2013 Wouter Robers

OuterDiameter=60;
InnerDiameter=10;
InnerCorners=6;
NumberOfPlanets=7;
Thickness=10;
Tolerance=.15;

//Sun

difference(){
MakeWheel((OuterDiameter-InnerDiameter)*0.2+InnerDiameter-Tolerance*2,-Thickness,Thickness);
cylinder(r=InnerDiameter/2+Tolerance,h=Thickness,$fn=InnerCorners);
}

//Outer Ring

difference(){
cylinder(r=OuterDiameter/2-Tolerance,h=Thickness);
MakeWheel((OuterDiameter-InnerDiameter)*0.8+InnerDiameter+Tolerance*2,Thickness,Thickness);
}

// Planets

for(i=[1:NumberOfPlanets]){
rotate([0,0,i*360/NumberOfPlanets])
translate([((OuterDiameter-InnerDiameter)*0.5+InnerDiameter)/2,0,0]) MakeWheel((OuterDiameter-InnerDiameter)*0.3-Tolerance*2,Thickness,Thickness);
}

module MakeWheel(Diameter,Rim,Thickness)
{
$fn=60;
union(){
cylinder(r1=Diameter/2-Rim*0.1,r2=Diameter/2,h=Thickness*0.1);
translate([0,0,0.1*Thickness]) cylinder(r=Diameter/2,h=Thickness*0.8);
translate([0,0,0.9*Thickness]) cylinder(r2=Diameter/2-Rim*0.1,r1=Diameter/2,h=Thickness*0.1);
}
}
```

The *MakeWheel* module makes the sun, the outer ring, and the rollers. It’s basically a fancy cylinder with slightly different radii at the top and bottom, almost like a spool.

**Here's what I'd like help with**:

I want a more robust and parametric roller bearing design, specifically:

1.  **Roller Stability:** I need a way to keep the rollers from turning on their own axis and make them only revolve around the center. Maybe some sort of cage system? I'm open to suggestions on the best way to do that.
2.  **Parametric Design:**
    *   I need to be able to easily adjust the Outer Diameter, Inner Diameter, Number of Rollers, Thickness of the bearing, and a general Tolerance value for all parts.
    *   I’d also like to make the rim height in the MakeWheel function parametric.
    *   I’d like to be able to control the core shape of the inner race (sun), currently I have a hexagon, but I would like to be able to choose how many sides, or perhaps have a circular core (or even a custom shape).
3.  **Modular Construction:** It would be great if the design is easily modifiable and if the parts (sun, rollers, cage, outer race) are defined by their own modules, rather than being included in one large module. That would make it easier to modify, and it might make using the design with different kinds of rollers easier.
4. **Clearance for Cage:** If we are going to be adding a cage, there will need to be added clearance. All tolerances need to be easily adjusted.
5. **Clear Variable Names:** In my code, the variables aren’t always super clear, I need clear names to make things easier.

I'm not sure which OpenSCAD libraries to use, but I am open to using them if they will make this easier. It looks like BOSL2 has features that would be helpful, though if there are other libraries or methods that are easier, I am open to that as well. I don’t mind a lot of detail, as I am here to learn.

Can you generate a parametric OpenSCAD file that incorporates these changes and provides a stable roller bearing design? I am not sure what the best method for implementing a cage system is, so please give that some thought.

[Assistant]
Rollerbearing.scad:
```
//Roller Bearing
// (C) 2013 Wouter Robers

OuterDiameter=60;
InnerDiameter=10;
InnerCorners=6;
NumberOfPlanets=7;
Thickness=10;
Tolerance=.15;

//Sun

difference(){
MakeWheel((OuterDiameter-InnerDiameter)*0.2+InnerDiameter-Tolerance*2,-Thickness,Thickness);
cylinder(r=InnerDiameter/2+Tolerance,h=Thickness,$fn=InnerCorners);
}

//Outer Ring

difference(){
cylinder(r=OuterDiameter/2-Tolerance,h=Thickness);
MakeWheel((OuterDiameter-InnerDiameter)*0.8+InnerDiameter+Tolerance*2,Thickness,Thickness);
}

// Planets

for(i=[1:NumberOfPlanets]){
rotate([0,0,i*360/NumberOfPlanets])
translate([((OuterDiameter-InnerDiameter)*0.5+InnerDiameter)/2,0,0]) MakeWheel((OuterDiameter-InnerDiameter)*0.3-Tolerance*2,Thickness,Thickness);
}

module MakeWheel(Diameter,Rim,Thickness)
{
$fn=60;
union(){
cylinder(r1=Diameter/2-Rim*0.1,r2=Diameter/2,h=Thickness*0.1);
translate([0,0,0.1*Thickness]) cylinder(r=Diameter/2,h=Thickness*0.8);
translate([0,0,0.9*Thickness]) cylinder(r2=Diameter/2-Rim*0.1,r1=Diameter/2,h=Thickness*0.1);
}
}

```


[User]
Okay, I need help creating a parametric OpenSCAD file for a brass instrument mouthpiece with a mustache attached. I'm starting from a design I already have, and want to improve on the parameters and potentially add some more complex features.

Here's what the current design does:

*   **Mouthpiece Body:** It generates a basic brass mouthpiece shape using a rotate_extrude of a polygon. The polygon is defined by several points that control the cup diameter, depth, rim width, and throat diameter. There are parameters for:
    *   `CupDiameter`: Diameter of the cup opening.
    *   `CupDepth`: Depth of the cup.
    *   `CupSphereFactor`: Controls the shape of the cup from conical to spherical.
    *   `RimWidth`: Width of the rim.
    *   `RimShape`: Controls the roundness of the rim.
    *   `ThroatRadius`: Radius of the throat contour.
    *   `ThroatDiameter`: Diameter of the throat.
    *  `BackPipeDiameter`: Diameter of the back pipe fitting into instrument.
     *  `FrontPipeDiameter`: Diameter of the front pipe.
     *  `BoreDiameter`: Diameter of the bore.
    *   `MouthPieceLength`: Total length of the mouthpiece.

*   **Decorative Rims:** It adds some decorative circles as small rims on the outer part of the mouthpiece.

*   **Mustache:** The design includes a mustache attached to the side of the mouthpiece, scaled and positioned using a polyhedron. The mustache geometry seems to be defined by a hardcoded list of triangles and points, and it’s scaled using `MustacheSize`.

Here's what I'd like in the new design:

1.  **Improved Parametric Control:**
    *   I want to be able to control the cup curve using a spline instead of just intermediate points between the cup top and bottom. This will make more complex cup shapes possible.
    *   I want more control over the mouthpiece shank. Instead of just a straight back pipe and a bore diameter, I'd like to define the shank profile with multiple diameters and lengths along the shank to be able to create complex shank geometries.
    *   I'd like to control the decorative rims with individual parameters for each rim: radius, x position, y position, and z position instead of just the simple circles that are there now. I'd like to be able to specify these parameters as a list of lists.
    *   I'd like to add a parameter for the angle of the mouthpiece cup with respect to the instrument.

2.  **Refined Mustache:**
    *   Instead of using a hardcoded polyhedron, I want to be able to import an STL or DXF file for the mustache shape and then position, scale, and rotate it.
    *   I'd like a parameter to control the mustache material, for example, the surface texture to make it look hairy.
    *   I want a parameter to control the distance of the mustache from the mouthpiece.
    *    I would like the option to choose the mustache location, such as on top of, or underneath the mouthpiece.

3.  **Additional Features:**
    *   Add an option to generate a threaded shank for screw-in mouthpieces, defining thread parameters like diameter, length, and pitch.
    *   Add an optional base for the mouthpiece so it can stand on a flat surface.
    *   I want to use the `hull()` function to create a smooth connection between different sections of the mouthpiece, if appropriate.

4. **Library Usage**:
  * I would like to use the `threads.scad` from the BOSL library for creating the threaded shank and potentially `transforms.scad` for moving parts of the mouthpiece.

I'd like the code to be well-organized, using modules and comments to explain each part. I'd also like the code to be as robust as possible, handling invalid inputs gracefully.

Can you generate an OpenSCAD file based on these requirements?

[Assistant]
Mouthstacepiece_v2.2.scad:
```
// (c) 2012 Wouter Robers
// Version 2.2 (Added moustache)

// [Trumpet:16, Trombone:21] Larger Cup Diameters are optimized for lower ranges, giving a richer tone. Smaller diameters assist high range playing.
CupDiameter=16;

// [Trumpet:8, Trombone:16] Shallower cups greatly assist playing in high ranges but do so at the cost of fullness of tone. Deeper cups assist low range flexibility and rich tone.
CupDepth=8;

// [0 (Conical) - 1 (Spherical)] Spherical cups have brighter, more projected tones, while conical cups have less tone definition.
CupSphereFactor=0.5;

// [Trumpet:6 Trombone:8] Wider rim widths reduce the pressure on the lips, allowing greater stamina. It does, however, reduce flexibility.
RimWidth=6;

// [0 (flat) - 1(round)] Sharper rims reduce stamina but increase control.
RimShape=0.7;
RimRadius=RimShape*RimWidth/2;

// A sharper throat contour gives a more harsh, projected tone and a rounded contour gives a deeper, richer tone, but less definition.
ThroatRadius=3.5;

// [Trumpet:4, Trombone:5] Larger throat diameters give more volume but less control.
ThroatDiameter=4;

// Diameter of the pipe that fits into your instrument. [Trumpet:9.5, Trombone:12]
BackPipeDiameter=9.5;
FrontPipeDiameter=BackPipeDiameter+3;
BoreDiameter=BackPipeDiameter-1.5;

// Total length of the mouthpiece [All mouthpieces usually 88]
MouthPieceLength=88;

//Height of the "foot" that binds the mouthpiece to the platform. Set to 0 for no foot.
//PrintingFootHeight=1;

MustacheSize=100;

MakeMouthPiece();

module MakeMouthPiece(){

$fs=1; // set minimum polygonsize
$fa=8; // set minimum circle angle

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

//Making the cup shape

CupBottom=[ThroatDiameter/2+ThroatRadius*(0.17+CupSphereFactor*0.3),CupDepth+ThroatRadius*(0.43-CupSphereFactor*0.3)];
CupTop=[CupDiameter/2+RimRadius*0.02,RimRadius-RimRadius*.2];

Cup45Deg=(0.5+CupSphereFactor*.15);
Cup30Deg=(0.25+CupSphereFactor*.1);
Cup60Deg=(0.75+CupSphereFactor*.1);

CupshapePoint1=[Cup30Deg*CupTop[0]+Cup60Deg*CupBottom[0],Cup30Deg*CupTop[1]+Cup60Deg*CupBottom[1]];

CupshapePoint2=[Cup45Deg*CupTop[0]+Cup45Deg*CupBottom[0],Cup45Deg*CupTop[1]+Cup45Deg*CupBottom[1]];

CupshapePoint3=[Cup60Deg*CupTop[0]+Cup30Deg*CupBottom[0],Cup60Deg*CupTop[1]+Cup30Deg*CupBottom[1]];

// Putting the moutpiece on the platform
//translate([0,0,MouthPieceLength+PrintingFootHeight])

// Turning the Mouthpiece backside down
//rotate ([180,0,0])

// Rotating-extruding the mouthpiece shape around the Z-axis
rotate_extrude()
difference(){
union() {

//Mouthpiece shape
polygon( [
CupTop,
[CupDiameter/2+RimRadius,0],
[CupDiameter/2+RimWidth-RimRadius,0],
[CupDiameter/2+RimWidth,RimRadius],
[CupTop[0]+RimWidth/2,CupTop[1]+RimWidth],
[CupshapePoint3[0]+RimWidth/2,CupshapePoint3[1]+RimWidth*2],
[CupshapePoint2[0]+RimWidth/2,CupshapePoint2[1]+RimWidth*2],
[CupshapePoint1[0]+RimWidth/2,CupshapePoint1[1]+RimWidth*2],
[FrontPipeDiameter/2,CupDepth+RimWidth*2],
[BackPipeDiameter/2,MouthPieceLength],
[BoreDiameter/2,MouthPieceLength],
[ThroatDiameter/2,CupDepth+ThroatRadius],
CupBottom,
CupshapePoint1,
CupshapePoint2,
CupshapePoint3,
]);

//Rim rouding
translate([CupDiameter/2+RimRadius,RimRadius, 0])circle(RimRadius);

//Rim rouding
translate([CupDiameter/2+RimWidth-RimRadius,RimRadius, 0])circle(RimRadius);

//Throat rouding
translate([ThroatDiameter/2+ThroatRadius,CupDepth+ThroatRadius,0])circle(ThroatRadius);

//Printing base
//translate([BoreDiameter/2,MouthPieceLength,0]) square([10,PrintingFootHeight]);

}

//decorative rims on the outside
translate([FrontPipeDiameter/1.4,CupDepth+RimWidth*2.5, 0])circle(RimRadius*1.5);
translate([FrontPipeDiameter/1.5,CupDepth+RimWidth*3.5, 0])circle(RimRadius*1.3);
translate([FrontPipeDiameter/1.6,CupDepth+RimWidth*4.5, 0])circle(RimRadius*1.1);
}
}

//Mustache
translate([0,CupDiameter/2+RimWidth-RimRadius,0])
scale([MustacheSize,MustacheSize,MustacheSize]/120)
translate([0,-6,0])
polyhedron(
triangles=[[0,1,2], [3,4,5], [6,3,5], [7,3,6], [7,8,9], [10,8,7], [6,10,7], [6,11,10], [6,12,11], [12,13,14], [11,12,14], [15,12,6], [16,17,18], [16,6,17], [16,15,6], [19,18,20], [17,6,21], [20,18,17], [6,1,22], [6,23,21], [6,22,23], [24,1,0], [24,22,1], [25,24,0], [2,25,0], [26,1,6], [15,27,12], [8,10,28], [29,6,5], [29,26,6], [2,1,26], [29,30,26], [25,2,31], [2,26,31], [25,32,24], [31,32,25], [30,33,34], [34,33,35], [34,35,32], [24,32,22], [32,35,22], [33,36,37], [37,35,33], [38,35,37], [38,39,35], [39,23,35], [23,22,35], [39,21,23], [19,20,40], [18,41,42], [16,18,42], [40,41,19], [41,18,19], [41,40,43], [41,43,44], [44,43,45], [44,45,46], [44,46,47], [16,42,27], [15,16,27], [42,41,44], [42,44,48], [48,44,47], [12,49,13], [14,13,49], [50,11,14], [10,51,28], [52,8,28], [52,9,8], [9,52,7], [3,7,53], [54,3,53], [54,4,3], [55,4,54], [5,4,55], [5,55,56], [5,56,29], [32,31,34], [36,33,30], [38,57,39], [39,57,21], [40,20,58], [40,58,43], [48,47,59], [49,50,14], [10,50,51], [11,50,10], [47,46,60], [47,60,59], [59,60,61], [59,61,51], [61,28,51], [50,59,51], [62,28,61], [52,63,7], [7,63,53], [55,64,56], [56,64,65], [30,56,65], [36,30,65], [56,30,29], [31,30,34], [26,30,31], [21,57,17], [49,59,50], [49,48,59], [48,49,27], [42,48,27], [27,49,12], [62,52,28], [54,64,55], [38,37,57], [57,66,17], [17,66,58], [20,17,58], [43,58,45], [54,65,64], [57,37,66], [58,66,46], [58,46,45], [60,62,61], [67,52,62], [67,63,52], [67,68,63], [63,68,53], [65,54,53], [60,67,62], [65,53,69], [36,69,37], [37,69,66], [46,66,67], [69,53,68], [68,66,69], [66,68,67], [46,67,60], [36,65,69]],
points = [[-58.584091,28.197536,0.000000],[-52.402328,20.506527,0.358841],[-54.800526,17.841995,0.784564],[-2.501032,24.170961,0.015048],[-9.552012,26.627146,0.017661],[-31.154655,19.643610,0.056052],[-44.969563,17.125895,0.016061],[0.000000,21.608608,0.004536],[9.176403,26.642111,0.021504],[2.581123,24.216633,0.016562],[31.159174,19.659206,0.130380],[45.120594,17.133677,0.066386],[54.991936,17.056479,0.194453],[58.584091,28.197536,0.000000],[51.291359,19.966629,0.156079],[49.738537,9.989874,0.000463],[43.278549,4.272926,0.009120],[-0.008242,7.004466,0.209614],[27.192152,0.793691,0.045869],[7.471235,2.503072,0.133520],[2.212253,4.728950,0.346563],[-2.146399,4.782774,0.295524],[-27.192234,0.780368,0.045171],[-7.369259,2.513148,0.046471],[-43.278549,4.272926,0.009121],[-49.810093,9.879161,0.126356],[-47.162132,16.298798,1.529032],[49.784290,10.898610,1.232523],[10.741753,25.962414,1.879541],[-42.937698,16.678349,1.332302],[-41.689590,11.881547,3.436377],[-50.267471,12.405128,1.511218],[-43.140366,5.042169,1.658040],[-28.532618,7.175683,4.583108],[-42.933926,7.437732,2.836552],[-27.605600,2.075034,2.597941],[-7.985993,14.311512,6.152612],[-6.474453,9.613080,5.521743],[-7.452224,5.137392,3.761260],[-6.295128,3.312337,1.773837],[6.465118,3.385351,1.955972],[27.227238,1.939077,2.386184],[43.342510,5.222044,1.810563],[7.736251,5.082082,3.731648],[28.051895,5.904336,4.304694],[6.974583,8.923686,5.317905],[6.558849,12.365727,5.993841],[26.977474,11.160126,5.102334],[42.999367,8.874681,3.112731],[50.156013,16.614939,1.554570],[45.755207,16.255020,1.356992],[30.981188,18.785643,2.009778],[3.500952,24.358774,1.895301],[-2.548270,23.113472,2.539699],[-7.130406,25.382286,2.418850],[-12.033466,25.573273,2.032217],[-31.717640,18.094902,2.627007],[-2.435404,6.976079,3.294168],[3.227587,6.781414,3.575889],[42.141052,13.963333,2.850352],[8.560343,18.462833,5.848720],[11.693113,22.998571,4.199893],[6.927012,23.504366,3.809480],[-0.000000,21.090641,1.418737],[-11.822267,22.579479,4.305679],[-9.060463,19.881535,5.513857],[-0.003193,11.637861,3.475341],[1.729550,18.091600,4.430985],[0.001450,18.014307,3.166783],[-2.453690,17.291109,4.794230]]
);

```


[User]
Okay, I'm looking for an OpenSCAD design for a highly customizable knob. I've seen some examples, and I have a pretty good idea of what I want, but I need a design that's easy to tweak.

Here are the key features and parameters I'd like:

**General Shape and Size:**

*   **Knob Height:**  I need to be able to set the overall height of the knob body, excluding any shaft or dome on top.
*   **Knob Diameter:** I need to set the diameter of the round part of the knob. I'm imagining a cylindrical or tapered body and would like the diameter of the largest circle to be adjustable.
*   **Taper:**  It would be great to taper the knob from a larger diameter at the bottom to a smaller one at the top. I'd like to be able to specify the taper percentage. A 0% taper should produce a cylinder.
*   **Top Cap Shape:** I want to be able to select between a flat top, a recessed top (like a small dish), or a dome-shaped top. The dome should not affect the overall knob height.
*  **Ring Width:** A ring around the base of the cylinder, with adjustable width.
*   **Ring Thickness:**  The thickness of the ring.
*   **Ring Markings:** If there's a ring, I want to be able to specify the number of tick marks around it, or choose to have none.

**Hole for Mounting:**

*   **Hole Diameter:** I need to set the diameter of the hole in the bottom to fit a shaft.
*   **Hole Depth:**  I need to specify how deep the hole goes. This should be able to go all the way through.
*   **D-Shaped Hole:** I also need the option for a D-shaped hole. This means there should be a flat part on one side. I'd need to specify the thickness of the flat part. It should be adjustable to make the flat larger or smaller.
*  **D Hole Rotation**: I need to be able to adjust the rotation of the D-shaped hole to align the flat.

**Shaft Option:**
*   **Shaft Length:** I need the option to add a cylindrical shaft that protrudes from the bottom of the knob. I need to set the length of the shaft.
*   **Shaft Diameter:** I need to set the diameter of the shaft.
*   **Notched Shaft:** I also need the ability to notch a percentage of the shaft for a press fit.

**Pointer/Directional Features:**

*   **Timer Knob Pointer:** I'd like an option to add a large pointer that extends from the side of the top like a timer knob.
*  **Divot Pointer:** The option for a divot on the top surface to indicate direction. I need to set the percentage of the divot from the center, and depth.
*   **Flat Side:** The ability to flatten one side of the knob opposite the directional divot pointer.
*   **Line Pointer:** I'd like an option to include a raised line (a pointer) on the side of the knob to indicate direction.

**Knurling/Grip:**
*   **Knurled Surface:** I'd like an option to add finger ridges (knurling) around the side of the knob for better grip.

**Setscrew:**
*   **Setscrew Hole:** The ability to include a hole for a setscrew, with adjustable diameter.

**Recess:**
*  **Bottom Recess**: Option for a circular recess in the bottom of the knob, with inner and outer radius, and depth all adjustable.

**Advanced Settings (I'm including these but you can assume they'll have default reasonable values):**

*   **Ring Thickness:** The thickness of the ring.
*   **Divot Depth:**  How deep the divot should be.
*   **Marking Width:**  The width of the tick marks on the ring.
*   **Distance Between Knurls:** The distance between the finger ridges.
*   **TimerKnobConst:** A multiplier on the size of the timer knob.

I'd prefer if this was all in one file, and I'd rather not use any libraries if possible. I'm looking for something clean and easy to understand, so I can quickly modify these parameters and create a knob with all the specs I need. I think that covers everything! Thank you!

[Assistant]
knob.scad:
```
//////////////////////////
// Customizable settings
//////////////////////////

// Diameter of the hole on the bottom (in mm).
HoleDiameter = 6.275;

// Depth of the hole in the bottom (in mm).  If you want the hole to go all the way through then set this to a number larger than the total height of the object.
HoleDepth = 25;

// If you want a D-shaped hole, set this to the thickness of the flat side (in mm).  Larger values for the flat make the hole smaller.
HoleFlatThickness = 1.25;

// Height (in mm).  If dome cap is selected, it is not included in height.  The shaft length is also not counted.
KnobHeight = 20;

// Diameter of base of round part of knob (in mm).  (Knurled ridges are not included in this measurement.)
KnobDiameter = 60;

// Shape of top of knob.  "Recessed" type can be painted.
CapType = 2;	// [0:Flat, 1:Recessed, 2:Dome]

// Do you want a large timer-knob style pointer?
TimerKnob=0;	// [0:No, 1:Yes]

// Percentage of divot on the top to indicate direction?
Pointer1 = 20;	 // [0:100]

// Divot Depth;
DivotDepth = 0;

// Amount of flatness of side opposite pointer (0 for None) Incompatible with TimerKnob
FlatSide = 2;

// Degrees to rotate D hole
DRotate = 45; // [0:100]

//Recess in bottom of knob (set to depth to 0 for None)
RecessDepth = 10;
RecessInnerRadius = 12;
RecessOuterRadius = 20;

// Would you like a line (pointer) on the front to indicate direction?
Pointer2 = 1;	// [0:No, 1:Yes]

// Do you want finger ridges around the knob?
Knurled = 0;	// [0:No, 1:Yes]

// 0 = A cylindrical knob, any other value will taper the knob.
TaperPercentage = 0; // [0:0%, 10:10%, 20:20%, 30:30%, 40:40%, 50:50%]

// Width of "dial" ring (in mm).  Set to zero if you don't want the ring.
RingWidth = 0;

// The number of markings on the dial.  Set to zero if you don't want markings.  (RingWidth must be non-zero.)
RingMarkings = 10;

// diameter of the hole for the setscrew (in mm).  If you don't need a hole, set this to zero.
ScrewHoleDiameter = 3;

// Length of the shaft on the bottom of the knob (in mm).  If you don't want a shaft, set this value to zero.
ShaftLength = 15;

// Diameter of the shaft on the bottom of the knob (in mm).  (ShaftLength must be non-zero.)
ShaftDiameter = 12;

// Percentage of shaft to "notch"  It can be used for a press-on type knob (rather than using a setscrew).  (ShaftLength must be non-zero.)
NotchedShaft = 80;

//////////////////////////
//Advanced settings
//////////////////////////

RingThickness = 5*1;
DivotDepth = 1.5*1;
MarkingWidth = 1.5*1;
DistanceBetweenKnurls = 3*1;
TimerKnobConst = 1.8*1;

//////////////////////////
//Calculations
//////////////////////////

PI=3.14159265*1;
KnobMajorRadius = KnobDiameter/2;
KnobMinorRadius = KnobDiameter/2 * (1 - TaperPercentage/100);
KnobRadius = KnobMinorRadius + (KnobMajorRadius-KnobMinorRadius)/2;
KnobCircumference = PI*KnobDiameter;
Knurls = round(KnobCircumference/DistanceBetweenKnurls);
Divot=CapType;

TaperAngle=asin(KnobHeight / (sqrt(pow(KnobHeight, 2) +
		pow(KnobMajorRadius-KnobMinorRadius,2)))) - 90;

DivotRadius = KnobMinorRadius*.3;

difference() {
union() {
    translate([0, 0, (ShaftLength==0)? 0 : ShaftLength-0.001])
    difference() {
	union() { // Primary knob cylinder
	    cylinder(h=KnobHeight, r1=KnobMajorRadius, r2=KnobMinorRadius,
		$fn=50);

	    if (Knurled)
	    for (i=[0 : Knurls-1])
	    rotate([0, 0, i * (360/Knurls)])
	    translate([KnobRadius, 0, KnobHeight/2])
	    rotate([0, TaperAngle, 0]) rotate([0, 0, 45])
	    cube([2, 2, KnobHeight+.001], center=true);

 	    if (RingMarkings>0)
	    for (i=[0 : RingMarkings-1])
	    rotate([0, 0, i * (360/RingMarkings)])
	    translate([KnobMajorRadius + RingWidth/2, 0, 1])
	    cube([RingWidth*.5, MarkingWidth, 2], center=true);

	    if (Pointer2==1)
	    translate([KnobRadius, 0, KnobHeight/2-2])
	    rotate([0, TaperAngle, 0])
	    cube([8, 3, KnobHeight], center=true);

	    if (RingWidth>0)
	    translate([0, 0, RingThickness/2])
	    cylinder(r1=KnobMajorRadius + RingWidth, r2=KnobMinorRadius,
		h=RingThickness, $fn=50, center=true);

	    if (Divot==2)
	    translate([0, 0, KnobHeight])
	    difference()
	    {
		scale([1, 1, 0.5])
		sphere(r=KnobMinorRadius, $fn=50, center=true);

		translate([0, 0, 0-(KnobMinorRadius+.001)])
		cube([KnobMinorRadius*2.5, KnobMinorRadius*2.5,
			KnobMinorRadius*2], center=true);
	    }

	    if (TimerKnob==1) intersection()
	    {
		translate([0, 0, 0-(KnobDiameter*TimerKnobConst) + KnobHeight])
		sphere(r=KnobDiameter*TimerKnobConst, $fn=50, center=true);

		translate([0-(KnobDiameter*TimerKnobConst)*0.1, 0,
			KnobHeight/2])
		scale([1, 0.5, 1])
		cylinder(h=KnobHeight, r=(KnobDiameter*TimerKnobConst) *
		    0.8, $fn=3, center=true);
	    }
	}

	// Pointer1: Offset hemispherical divot
	if (Pointer1 > 0)
	translate([KnobMinorRadius*.55, 0, KnobHeight + DivotRadius*((100.0 - Pointer1)/100)])
	sphere(r=DivotRadius, $fn=40);

	// Flat side:
	if (TimerKnob == 0 && FlatSide > 0)
	translate([-KnobMajorRadius+FlatSide-50, 0, KnobHeight / 2.0])
	cube([100,100,KnobHeight*2], center=true, $fn=40);

	// Divot1: Centered cylindrical divot
	if (Divot==1)
	translate([0, 0, KnobHeight])
	cylinder(h=DivotDepth*2, r=KnobMinorRadius-1.5, $fn=50,
	    center=true);

	if (RecessDepth > 0)
	difference()
	{
	    cylinder(h=RecessDepth*2, r=RecessOuterRadius,
		$fn=50,center=true);
	    cylinder(h=RecessDepth*2, r=RecessInnerRadius);

	}

	// Make sure bottom ends at z=0
	translate([0, 0, -10])
	cube([(KnobMajorRadius+RingWidth) * 3,
		(KnobMajorRadius+RingWidth) * 3, 20], center=true);

	}
	//Add in shaft
	rotate([0,0,DRotate])
	if (ShaftLength>0)
	difference() {
	    translate([0, 0, ShaftLength/2])
	    cylinder(h=ShaftLength, r=ShaftDiameter/2, $fn=20,
		center=true);
	    if (NotchedShaft > 0) {
		cube([HoleDiameter/2, ShaftDiameter*2, ShaftLength*2*(NotchedShaft/100.0)],
		    center=true);
	    }
	}
    }
    //subtract out hole
    rotate([0,0,DRotate])
    translate([0, 0, HoleDepth/2 - 0.001])
    difference()
    {
	cylinder(r=HoleDiameter/2, h=HoleDepth, $fn=20,
	    center=true);
	// Flat for D-shaped hole
	translate([(0-HoleDiameter)+HoleFlatThickness, 0, 0])
	cube([HoleDiameter, HoleDiameter, HoleDepth+.001],
	    center=true);
    }

    // Hole for setscrew
    if (ScrewHoleDiameter>0)
    rotate([0,0,DRotate])
    translate([0 - (KnobMajorRadius+RingWidth+1)/2, 0,
	    HoleDepth/2])
    rotate([0, 90, 0])
    cylinder(h=(KnobMajorRadius+RingWidth+1),
	r=ScrewHoleDiameter/2, $fn=20, center=true);
}

```


[User]
Okay, I'm trying to design some wagon wheels for a project, and I've been playing around with an existing OpenSCAD script that was originally based on Cathal Garvey's parametric spoked wheel. I've modified it quite a bit to get different looks.  I'm hoping you can help me expand on this and make the design even more flexible and robust.

Here's what I'm looking for in a parametric wheel generator:

**Core Functionality**

*   **Wheel Dimensions:** I need to be able to control the following:
    *   `OuterRadius`: The overall radius of the wheel.
    *   `InnerRadius`: The radius of the inner edge of the rim.
    *   `RimThickness`: The thickness of the wheel rim.
    *   `HubRadius`: The radius of the central hub.
    *   `HubThickness`: The thickness of the hub.
*   **Axle Hole:** An option to include an axle hole, controlled by a boolean `Axle`.
    *   `AxleRadius`:  The radius of the axle hole.
*   **Spokes:** I need to be able to control the number and shape of the spokes.
    *   `SpokeNumber`: The number of spokes.
    *   `SpokeAngle`:  The angle of the spokes relative to the wheel plane (for dished wheels).
*   **Spoke Style:**
    *   `SpokeStyle`: An integer selector with the following options:
        *   `1`: Round spokes, using `SpokeRadius`.
        *   `2`: Square spokes, using `SpokeTenonHeight` and `SpokeTenonWidth`.
        *   `3`: Spokes that transition from square (near the hub) to round (near the rim), using `SpokeTenonHeight`, `SpokeTenonWidth`, `SpokeRadius` and `SqrRound`.
	*   `SpokeRadius`: The radius of round spokes.
    *   `SpokeTenonHeight`: Height of the square tenon on the spoke.
    *   `SpokeTenonWidth`: Width of the square tenon on the spoke.
	*   `SqrRound`: A value between 0 and 1. A value closer to 0 makes the square part of the square-to-round spoke shorter, a value closer to 1, makes the round part of the square-to-round spoke shorter.
*   **Wheel Type**:
	*   `WheelType`: An integer selector with the following options:
		*   `0`: A full wheel.
		*   `1`: A half wheel (useful for printing two halves and joining them). This type would be sliced along the Y axis.
		*   `2`: A split wheel. The wheel is split at its base, creating a flat surface for printing without supports. This would be sliced along the Z axis.
		* Note: Wheel Types 1 and 2 should _not_ work with angled spokes ( `SpokeAngle` not equal to `0`).

*   **Angled Rim:** An option to make the rim angled to match the `SpokeAngle`, controlled by the boolean `AngeledRim`. This would ideally keep the inner wheel surface perpendicular to the spokes, but with `AngeledRim = 0` then the rim's faces will be parallel to the Z axis.

**Improvements and additions I'd like to see:**

1.  **More robust angled spoke and angled rim handling:**  Currently, I'm seeing some issues with angled spokes and my `WheelType` selections. I'd really appreciate it if you could make that work correctly (especially the SplitWheel and HalfWheel types).
2.  **Better parameterization of the square-to-round spoke transition:** The `SqrRound` variable is ok, but it feels a little arbitrary. I'd like a more intuitive way to control how much of the spoke is square versus round.
3. **Hub shape options:** Currently the hub is just a simple cylinder. I'd like the option to add some decorative shapes and to control the radius of different parts of a hub profile.
4. **Rim profile options:** Similarly I would like to have options for how the rim is shaped including the use of a profile to create more complex shapes (eg semi circles) and also to change the profile of the edge of the rim and use a chamfer.
5. **Ability to add patterns to the spokes or rim:** It would be great to add simple shapes to the spokes or the rim. For example a triangle or circle pattern on the spokes. It would be great if the pattern could be parameterized.

**General Requirements**

*   Use `$fn` for circle/curve resolution.
*   Make the code as clear and modular as possible. I think the use of named modules will help make it more understandable, and easier to modify and reuse in other projects.
*   I'm not using any external libraries, so the code should be self-contained.
* Please make use of descriptive variable names.

I'm primarily focused on the functionality described above, so please prioritize those core requirements.

Thank you!

[Assistant]
Spoked_Wheel_Too.scad:
```
//
// Spoked Wheel Too
//
//	Some additions to the original
// Spoked Wheel
// Cathal Garvey (cathalgarvey@gmail.com)
// Creative Commons Attribution, Sharealike License
//
// Modified by BrianM
//
// ======================================
// Parameters:
// $fn is a global OpenSCAD variable determining the number of faces to divide a curved surface into. Higher gives more detailed circular structures (Which is everything in this model).
// OuterRadius is the measure from the centre of the wheel to the outer edge.
// InnerRadius is the measure from the centre of the wheel to the inner edge.
// EdgeThickness is how thick the rim of the wheel is.
// HubRadius is the measure of the central wheel hub, from the centre to its edge.
// HubThickness is how thick the hub is.
// Axle is a 1/0 boolean to determine whether there is an axle-hole desired.
// AxleRadius is the radius of the WheelAxle, if it is set to 1 above.
// SpokeNumber is how many wheel spokes to include.
// SpokeRadius is the radius of each cylindrical Spoke.
// SpokeAngle is the angle in degrees of the spokes for a dished wheel, 0 degrees for a strights wheel
//  SpokeStyle
//		1 = Round ,uses SpokeRadius
//		2 = Square ,uses SpokeTenonHeight and Width
//		3 = Square to round
//  WheelType
//		0 = Full Wheel, may need support while printing
//		1 = Half Wheel, that is print two, and stick them, together for a full wheel
//		2 = Split wheel, chops off the back of the while to give a flat back for printing without support
//		Note: 1 and 2 do not work for angled spokes.

$fn = 40;
OuterRadius = 25;
InnerRadius = 22;
RimThickness = 4;
HubRadius =8;
HubThickness =4;
AxleRadius = 1;
SpokeRadius = 1.2;
SpokeAngel =0;
SpokeTenonHeight = 3;
SpokeTenonWidth =2;
SpokeStyle = 3;
WheelType = 0;

// Note: Axle is Boolean, and Spokenumber is absolute, not relative to size or proportion of other parts.
Axle = 1;
SpokeNumber = 14;

// AngledRim will angle the rim to the spoke angle,
// 		Set to 0 the running face of the rim will be paralled to axle
//		Set to 1 the running face will be at the spoke angle and the axle will need to be
//  		angled in relation to the ground for correct running
AngeledRim =0;

// For SpokeStyle 3, Guide to how much of the spoke should be Square vs Round , 0 = more round, 1 = more square
SqrRound = .3;

if (WheelType == 0 ) {
	Wheel();
	}
if (WheelType == 1 ) {
	 HalfWheel();
	}
if (WheelType == 2 ) {
	 SplitWheel();
	}

//module Rim(Edge,Outer,Inner){
module Rim(){

	if ( AngeledRim == 1)	{
		translate ([0 ,0,-RimThickness /2])
		rotate_extrude($fn=100)
		translate ([HubRadius ,0,0])
		rotate ([0,0, SpokeAngel])

		translate ([InnerRadius - HubRadius ,0,0])
			square([OuterRadius - InnerRadius,RimThickness]);

		} else {
		translate ([0,0,(InnerRadius - HubRadius) * sin(SpokeAngel)])
		translate ([0 ,0,-RimThickness /2])
		rotate_extrude($fn=100)
		translate ([HubRadius ,0,0])
//		rotate ([0,0, SpokeAngel])

		translate ([InnerRadius - HubRadius ,0,0])
			square([OuterRadius - InnerRadius,RimThickness]);

		}
}

module Hub(HubR,HubW,AxleDesired,AxleR){
	difference(){
		translate([0,0,-HubW/2])
			cylinder(HubW,HubR,HubR);
		if(AxleDesired==1){translate([0,0,-HubW/2 -0.5]) cylinder(HubW + 1,AxleR,AxleR);}
	}
}

module Spokes(AxleR,RimR,SpokeN,SpokeR){
echo( sin(SpokeAngel));
for(i=[0:SpokeN-1]){

		rotate([i*360/SpokeN,90 ,0])
		if (SpokeStyle == 1) {

			translate([0,0, HubRadius - ((SpokeR/2) * sin(SpokeAngel) )])
			rotate ([0,-SpokeAngel,0])
			cylinder (h =  (  InnerRadius + ( (SpokeTenonHeight  ) * sin(SpokeAngel)) - HubRadius) ,r1 =SpokeR,r2=SpokeR);

		} else { if (SpokeStyle == 2) {

			translate([0,0, HubRadius - ((SpokeR/2) * sin(SpokeAngel) )])
			rotate ([0,-SpokeAngel,0])
			translate ([ - SpokeTenonHeight/2 / cos(SpokeAngel),-SpokeTenonWidth/2,0])
			cube ([ SpokeTenonHeight,
					SpokeTenonWidth,
					( InnerRadius + ( (SpokeTenonHeight  ) * sin(SpokeAngel)) - HubRadius) ]);

		} else { if (SpokeStyle == 3) {

			translate([0,0, HubRadius -1 - ((SpokeTenonHeight / 2 ) * sin(SpokeAngel) )])
			rotate ([0,-SpokeAngel,0])
			hull () {
				hull () {
 				translate ([ - SpokeTenonHeight/2 ,-SpokeTenonWidth/2,0])
						cube ([SpokeTenonHeight ,
							SpokeTenonWidth,
							.1 + SpokeTenonHeight / 2 * ( sin(SpokeAngel)) ]);
				translate ([0,0,( RimR / cos(SpokeAngel)  - AxleR ) * SqrRound])
				hull (){
					translate ([-(SpokeTenonHeight /2 - SpokeR  ),0,0])cylinder (h=.1,r=SpokeR);
					translate ([(SpokeTenonHeight /2 - SpokeR  ),0,0])cylinder (h=.1,r=SpokeR);
					}
				}
				if ( AngeledRim == 1)	{
					translate ([0,0,( InnerRadius + ( (SpokeTenonHeight  ) * sin(SpokeAngel)) - HubRadius )])
						cylinder (h=.1,r=SpokeR);
				} else {
					translate ([0,0,( (InnerRadius  / cos(SpokeAngel)) + ( (SpokeRadius * 2  ) * sin(SpokeAngel)) - HubRadius + 1 )])
						cylinder (h=.1,r=SpokeR);
				}

			}

		}}}

	}
}

module Wheel() {
union(){
color ("blue") Hub(HubRadius,HubThickness,Axle,AxleRadius);
color ("red") Rim(RimThickness,OuterRadius,InnerRadius);
Spokes(AxleRadius,InnerRadius,SpokeNumber,SpokeRadius);
}
}

module HalfWheel() {
difference () {
	union(){
		Wheel();
		}
		translate ([-(1 + OuterRadius * 2) /2, -(1 + OuterRadius * 2)/2 ,  -(1 + OuterRadius * 2) ])
		cube ( [1 + OuterRadius * 2, 1 + OuterRadius * 2, 1 + OuterRadius * 2 ]);
	}
}

module SplitWheel() {
difference () {
	union(){
		Wheel();
		}
	if (SpokeStyle == 1) 	{
		translate ([0, 0 ,  - SpokeRadius ])
		translate ([-(1 + OuterRadius * 2) /2, -(1 + OuterRadius * 2)/2 ,  -(1 + OuterRadius * 2) ])
		cube ( [1 + OuterRadius * 2, 1 + OuterRadius * 2, 1 + OuterRadius * 2 ]);
	} else { if (SpokeStyle == 2) {
			translate ([0, 0 ,  - SpokeTenonHeight /2 ])
			translate ([-(1 + OuterRadius * 2) /2, -(1 + OuterRadius * 2)/2 ,  -(1 + OuterRadius * 2) ])
			cube ( [1 + OuterRadius * 2, 1 + OuterRadius * 2, 1 + OuterRadius * 2 ]);
			}
	} 	if (SpokeStyle == 3) 	{
		translate ([0, 0 ,  - SpokeRadius ])
		translate ([-(1 + OuterRadius * 2) /2, -(1 + OuterRadius * 2)/2 ,  -(1 + OuterRadius * 2) ])
		cube ( [1 + OuterRadius * 2, 1 + OuterRadius * 2, 1 + OuterRadius * 2 ]);
	}

	}
}

```