[User]
I'd like to design a folding spool for 3D printer filament, based on the description and functionality of a similar design I've seen. It needs to be parametric so I can adjust the dimensions and number of spokes.

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

*   **Core Components:** The spool will consist of a hub base, a hub top plate, spoke forks, and spoke finger attachments.

*   **Assembly:** The design needs to allow for easy assembly and disassembly. The spoke forks will attach to the hub with bolts, and the spoke fingers will attach to the forks, also with bolts, forming the outer ring of the spool.

*   **Parametric Variables:**
    *   `numSpokes`: The number of spokes in the spool (e.g., 3, but should be adjustable).
    *   `boltSize`: The diameter of the bolts used to mount the spokes (in mm, default to M4, but adjustable).
    *   `wallThick`: The thickness of the hub walls.
    *   `hubOD`: Outer diameter of the hub.
    *   `hubID`: Inner diameter of the hub.
    *   `hubDepth`: Depth of the hub.
    *   `spokeOD`: Outer diameter of the fully assembled spool (outer ring).
    *  `spokeID`: Inner diameter of the spoke ring
    *   `forkDepth`: Depth of the spoke fork
    *   `ridgeHeight`: Height of the ridge on the hub to help keep the filament from slipping off.
    *  `boltLength`: Length of the bolts.

*   **Hub Base:**  A cylindrical base with bolt holes to attach the spokes. It should have an outer and inner wall and a ridge feature on the outer edge.

*   **Hub Top Plate:** A cylindrical plate that mates with the hub base, with corresponding bolt holes for the spokes and space for the ridge.

*   **Spoke Fork Base:** The base portion of each spoke, attaching to the hub using bolts, and providing an attachment point for the finger.  The design should have a profile that increases in width and height toward the outer rim.

*   **Spoke Fork Finger:** The finger portion that attaches to the spoke fork base to form the outside of the spool.

*   **Bolt Holes:**  Use appropriate bolt holes for the specified `boltSize`. I'd like to use the `nuts_and_bolts.scad` module from the MCAD library to handle the bolt hole generation. The code should also account for a small amount of tolerance so that the parts can be printed and assembled correctly.

*   **Modularity:** Each part should be designed as a separate module so it's easy to generate one part at a time for printing. I'd like to have an overall `print_parts()` module that can handle printing all components or just one, based on a `part` variable that can be set to "assembled", "base", "top", "fork", or "finger".

*   **Helpers:** Include the manual support helper so that screw holes are printable. Include helpers to do some of the math so I don't have to do it myself, like calculating the distance of bolt holes from the center and the angle between spokes.

Can you generate the OpenSCAD code for this design, including the use of MCAD for the nuts and bolts?  I'd like it if all of the code was in one file, like a complete self-contained project.

[Assistant]
Folding_Spool.scad:
```

/* [Global] */

// which part to display?
part = "assembled"; // [assembled:Assembled,base:Hub Base,top:Hub Top Plate,fork:Spoke Fork Base,finger:Spoke Fork Finger]

/* [Basic] */

// number of spokes in spool (suggested: 3)
numSpokes = 3; // [2:12]

// bolt diameter for mounting spokes (diameter in mm, default=M4)
boltSize = 4; // [2:10]

/* [Advanced] */

wallThick = 4;
hubOD = 85;
hubID = 40;
hubDepth = 21;
spokeOD = 150;
spokeID = 90;
forkDepth = 60;
ridgeHeight = 1;
boltLength = 25;

/* [Hidden] */

echo(version());

/*** BEGIN: from common_hardware.scad ***/

//include <common_hardware.scad>;

/* from http://hydraraptor.blogspot.com/2011/02/polyholes.html */
module polyhole(h, d, center = false) {
    n = max(round(2 * d),3);
    rotate([0,0,180])
        cylinder(h = h, r = (d / 2) / cos (180 / n), center = center, $fn = n);
}
/* from MCAD/units.scad */
epsilon = 0.001;
/* from MCAD/nuts_and_bolts.scad */
//Based on: http://www.roymech.co.uk/Useful_Tables/Screws/Hex_Screws.htm
METRIC_NUT_AC_WIDTHS =
[
	-1,-1,4.2,//m2
	6.40,//m3
	8.10,//m4
	9.20,//m5
	11.50,//m6
	-1,15.00,//m8
	-1,19.60,//m10
	-1,22.10,//m12
	-1,-1,-1,27.70,//m16
	-1,-1,-1,34.60,//m20
	-1,-1,-1,41.60,//m24
	-1,-1,-1,-1,-1,53.1,//m30
	-1,-1,-1,-1,-1,63.5//m36
];
METRIC_NUT_THICKNESS =
[
	-1,-1,1.60,//m2
	2.40,//m3
	3.20,//m4
	4.00,//m5
	5.00,//m6
	-1,6.50,//m8
	-1,8.00,//m10
	-1,10.00,//m12
	-1,-1,-1,13.00,//m16
	-1,-1,-1,16.00,//m20
	-1,-1,-1,19.00,//m24
	-1,-1,-1,-1,-1,24.00,//m30
	-1,-1,-1,-1,-1,29.00//m36
];
COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS =
[//based on max values
	-1,-1,1.99,//m2
	2.98,//m3
	3.978,//m4
	4.976,//m5
	5.974,//m6
	-1,7.972,//m8
	-1,9.968,//m10
	-1,11.966,//m12
	-1,-1,-1,15.962,//m16
	-1,-1,-1,19.958,//m20
	-1,-1,-1,23.952,//m24
	-1,-1,-1,-1,-1,29.947,//m30
	-1,-1,-1,-1,-1,35.940//m36
];
module nutHole(size, tolerance = epsilon, proj = -1)
{
	//takes a metric screw/nut size and looksup nut dimensions
	radius = METRIC_NUT_AC_WIDTHS[size]/2+tolerance;
	height = METRIC_NUT_THICKNESS[size]+tolerance;
	if (proj == -1)
	{
		//polyhole(h=height, d=radius*2);
		cylinder(r= radius, h=height, $fn = 6, center=[0,0]);
	}
	if (proj == 1)
	{
		polycircle(d=radius*2);
		//circle(r= radius, $fn = 6);
	}
	if (proj == 2)
	{
		translate([-radius/2, 0])
			square([radius*2, height]);
	}
}
module boltHole(size, length, tolerance = epsilon, proj = -1)
{
	radius = COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS[size]/2+tolerance;
//TODO: proper screw cap values
	capHeight = METRIC_NUT_THICKNESS[size]+tolerance; //METRIC_BOLT_CAP_HEIGHTS[size]+tolerance;
	capRadius = METRIC_NUT_AC_WIDTHS[size]/2+tolerance; //METRIC_BOLT_CAP_RADIUS[size]+tolerance;

	if (proj == -1)
	{
		translate([0, 0, -capHeight])
			polyhole(h=capHeight, d=capRadius*2);
			//cylinder(r= capRadius, h=capHeight);
		polyhole(h=length, d=radius*2);
		//cylinder(r = radius, h = length);
	}
	if (proj == 1)
	{
		polycircle(d=radius*2);
		//circle(r = radius);
	}
	if (proj == 2)
	{
		translate([-capRadius/2, -capHeight])
			square([capRadius*2, capHeight]);
		square([radius*2, length]);
	}
}
function mm_to_inch(v) = v / 25.4;
function inch_to_mm(v) = v * 25.4;
function cutout_tolerance(keepout=false) = keepout ? 0.2 : epsilon;
module bolt_and_nut(size=2, length=10, keepout=false, nut_offset=0, extra_nut_keepout=10, extra_cap_keepout=2) {
	t = cutout_tolerance(keepout);
	union() {
		boltHole(size=size, length=length, tolerance=t, $fn=20);
		translate([0, 0, length-METRIC_NUT_THICKNESS[size]-t-nut_offset]) {
			if (keepout) {
				cylinder(r=(METRIC_NUT_AC_WIDTHS[size]/2+t), h=extra_nut_keepout, $fn = 6, center=[0,0]);
			} else {
				nutHole(size=size, tolerance=t);
			}
		}
		if (keepout)
			translate([0, 0, -(size+t+extra_cap_keepout)+0.01])
				cylinder(r=METRIC_NUT_AC_WIDTHS[size]/2+t, h=size+t+extra_cap_keepout, $fn=20, center=[0,0]);
	}
}
module manual_support(fillCube=[1, 1, 1], supportDir=2, supportWidth=0.4, supportSpacing=2, center=false) {
	supportNormal = (supportDir==0) ? [1, 2, 0] : (supportDir==1) ? [0, 2, 1] : [0, 1, 2];
	rot = (supportDir==0) ? [0, 90, 0] : (supportDir==1) ? [90, 0, 0] : [0, 0, 90];
	widthIx = supportNormal[0];
	depthIx = supportNormal[1];
	supptIx = supportNormal[2];
	a = fillCube[widthIx] + 0.2;
	b = fillCube[depthIx] + 0.2;
	t = a + b;
	u = a - b;
	d = (a > b) ? a : b;
	shft = (supportDir==0) ? [0, 0, d] : (supportDir==1) ? [0, fillCube[supptIx], 0] : [b, b-a, 0];
	v = sqrt(d*d*2);
	translate(center ? fillCube / 2 : [0, 0, 0])
		intersection() {
			translate(shft) rotate(rot)
					for (x = [u:supportSpacing:t])
						translate([x + 0.8, 0, 0])
							rotate([0, 0, 45])
								translate([-0.1, -0.1, -0.1])
									cube([supportWidth, v, fillCube[supptIx]+0.2]);
			cube(fillCube);
		}
}
module nut_printing_support(size=2, bolt_length=10, nut_offset=0, extra_nut_keepout=10, supportDir=2, supportWidth=0.4, supportSpacing=2) {
	t = cutout_tolerance(true);
	translate([0, 0, bolt_length-METRIC_NUT_THICKNESS[size]-nut_offset])
		intersection() {
			cylinder(r=(METRIC_NUT_AC_WIDTHS[size]/2-0.5), h=METRIC_NUT_THICKNESS[size]+extra_nut_keepout, $fn = 6, center=[0,0]);
			translate([-METRIC_NUT_AC_WIDTHS[size]/2, -METRIC_NUT_AC_WIDTHS[size]/2, 0])
				manual_support(fillCube=[METRIC_NUT_AC_WIDTHS[size], METRIC_NUT_AC_WIDTHS[size], extra_nut_keepout+nut_offset], supportDir=supportDir, supportWidth=supportWidth, supportSpacing=supportSpacing);
		}
}

/*** END: from common_hardware.scad ***/

print_parts();

module print_parts() {
	if (part == "assembled") {
		hub_base();
		hub_cap();
		#replicate_and_position_spokes()
			spoke_bolt(keepout=false);
		replicate_and_position_spokes()
			spoke_position() {
				spoke();
				spoke_finger();
			}
	}

	if (part == "base")
		hub_base();

	if (part == "top")
		translate([0, 0, -hubDepth+wallThick])
			hub_cap();

	if (part == "fork")
		translate([0, 0, (hubDepth - (wallThick * 2))/2])
			spoke_position()
				spoke();

	if (part == "finger")
		rotate([180, 0, 0])
		translate([-45, -40, -(hubDepth - (wallThick * 2))/2])
			spoke_position()
				spoke_finger();
}

module hub_base() {
	angleSize = (360/numSpokes)/2;
	difference() {
		union() {
			HubPlate();
			HubCore();
			rotate([0, 0, angleSize])
				replicate_and_position_spokes()
					hub_key(keepout=false);
		}
		translate([0, 0, -1])
			polyhole(d=hubID,h=400);
		replicate_and_position_spokes()
			spoke_bolt(keepout=true);
	}
}

module hub_cap() {
	angleSize = (360/numSpokes)/2;
	difference() {
		HubPlate([0, 0, hubDepth-wallThick]);
		rotate([0, 0, angleSize])
			replicate_and_position_spokes()
				hub_key(keepout=true);
		translate([0, 0, -1])
			polyhole(d=hubID+wallThick*2,h=400);
		replicate_and_position_spokes()
			spoke_bolt(keepout=true);
	}
}

module hub_key(keepout) {
	translate([-7.5, -1, 0])
		rotate([90, 0, 0])
			polyhole(d=(keepout?8.5:8), h=(hubDepth+wallThick+(keepout?2:-2)));
}

module HubPlate(tx=[0,0,0]) {
	translate(tx)
		polyhole(d=hubOD,h=wallThick);
}

module HubCore() {
	polyhole(d=hubID+wallThick*2,h=hubDepth+wallThick);
}

module replicate_and_position_spokes() {
	angleSize = 360/numSpokes;
	distance = (hubID + hubOD) / 4;
	for(angle = [0 : numSpokes])
		translate([distance*cos(angle*angleSize), distance*sin(angle*angleSize), 0])
			rotate([0, 0, angle*angleSize])
				rotate([-90, 0, 0])
					if (version()[0] >= 2014) {
						children();
					} else {
						child();
					}
}

module spoke_bolt(keepout) {
	rotate([90, 0, 0])
		bolt_and_nut(size=boltSize,length=boltLength,keepout=keepout);
}

module fork_template() {
	A = hubDepth - (wallThick * 2);
	B = forkDepth;
	C = B + 2 * A;
	boltMargin = A / 2;
	distance = ((hubID + hubOD) / 4) - boltMargin;
	D = spokeOD - distance;
	E = spokeID - distance;
	F = C / 3;
	G = E / 2;
	points = [
		// top surface
		[0,   A+F, A], // 0
		[E-G, A+F, A], // 1
		[E-G/2.5,   C,   A], // 2
		[D,   C,   A], // 3
		[D,   C-A, A], // 4
		[E,   C-A, A], // 5
		[E-G+A*1.75,   A+F, A], // 6
		[E-G+A*1.75,   F,   A], // 7
		[E,   A,   A], // 8
		[D,   A,   A], // 9
		[D,   0,   A], // 10
		[E-G/2.5,   0,   A], // 11
		[E-G, F,   A], // 12
		[0,   F,   A], // 13

		// bottom surface
		[0,   A+F, 0], // 14
		[E-G, A+F, 0], // 15
		[E-G/2.5,   C,   0], // 16
		[D,   C,   0], // 17
		[D,   C-A, 0], // 18
		[E,   C-A, 0], // 19
		[E-G+A*1.75,   A+F, 0], // 20
		[E-G+A*1.75,   F,   0], // 21
		[E,   A,   0], // 22
		[D,   A,   0], // 23
		[D,   0,   0], // 24
		[E-G/2.5,   0,   0], // 25
		[E-G, F,   0], // 26
		[0,   F,   0]  // 27
		];
	faces = [
		// top surface
		[0, 1, 2, 5, 6, 7, 8, 11, 12, 13],
		[2, 3, 4, 5],
		[8, 9, 10, 11],
		// bottom surface
		[27, 26, 25, 22, 21, 20, 19, 16, 15, 14],
		[25, 24, 23, 22],
		[19, 18, 17, 16],
		// sides
		[0,  13, 27, 14],
		[1,  0,  14, 15],
		[2,  1,  15, 16],
		[3,  2,  16, 17],
		[4,  3,  17, 18],
		[5,  4,  18, 19],
		[6,  5,  19, 20],
		[7,  6,  20, 21],
		[8,  7,  21, 22],
		[9,  8,  22, 23],
		[10, 9,  23, 24],
		[11, 10, 24, 25],
		[12, 11, 25, 26],
		[13, 12, 26, 27]
		];
	intersection() {
		union() {
			translate([boltMargin, C+1, boltMargin])
				rotate([90,0,0])
					cylinder(d=A, h=C + 2);
			translate([boltMargin-1, -1, 0])
				cube([D + 2 -boltMargin, C + 2, A]);
		}
		difference() {
			union() {
				polyhedron(points=points, faces=faces);
				translate([-distance, F-wallThick+(wallThick-ridgeHeight)+epsilon, boltMargin])
					rotate([-90, 0, 0]) {
						ridge();
						translate([0, 0, A+ridgeHeight*2-epsilon*2])
							rotate([180, 0, 0])
								ridge();
					}
			}
			translate([47, 29.25, -1])
				polyhole(d=4, h=A+2);
			translate([112.25, boltMargin, -1])
				polyhole(d=4, h=A+2);
			translate([boltMargin, F+A+2, boltMargin])
				spoke_bolt(keepout=true);
			translate([45+A, C-A+boltMargin, (A+2)-1])
				rotate([0, 180, 0])
					bolt_and_nut(size=3,length=A+1,keepout=true); //bolt for attaching finger
			translate([45+A, C-A+boltMargin, A-0.75])
					polyhole(d=9,h=2); // washer under bolt (reduce friction)
			translate([45+A, C-A+boltMargin, boltMargin-0.75])
					polyhole(d=9,h=1.5); // space for two washers between parts (reduce friction)
		}
	}
	// add supports where needed
	if (part != "assembled"){
		translate([45+A, C-A+boltMargin, (A+2)-1])
			rotate([0, 180, 0])
				nut_printing_support(size=3,bolt_length=A+1,supportSpacing=1.6,extra_nut_keepout=METRIC_NUT_THICKNESS[3]); //support for nut hole on fork
	}
}

module spoke(){
	difference() {
		fork_template();
		fork_prong(for_cutout=true);
	}
}

module spoke_finger(){
	A = hubDepth - (wallThick * 2);
	B = forkDepth;
	C = B + 2 * A;
	boltMargin = A / 2;
	fork_start = 45;

	intersection(){
		fork_template();
		fork_prong(for_cutout=false);
	}

	if (part != "assembled"){
		translate([45+A, C-A+boltMargin, A-0.75])
			intersection(){
				polyhole(d=8,h=2); // washer under bolt (reduce friction)
				rotate([0, 0, 45]) translate([-4, -4, 0])
					manual_support(fillCube=[8, 8, 0.75], supportSpacing=1.6);
			}
	}
}

module fork_prong(for_cutout){
	A = hubDepth - (wallThick * 2);
	B = forkDepth;
	C = B + 2 * A;
	boltMargin = A / 2;
	distance = ((hubID + hubOD) / 4) - boltMargin;
	D = spokeOD - distance;
	E = spokeID - distance;
	F = C / 3;
	G = E / 2;
	fork_start = 45;

	translate([fork_start+A, C-A+boltMargin, boltMargin])
		polyhole(d=A, h=boltMargin + 1);
	if (for_cutout) {
		translate([fork_start, C-A, boltMargin])
			cube([spokeOD-fork_start, A+2, boltMargin + 1]);
		translate([fork_start+20-1, C-A-5, -1])
			cube([spokeOD-fork_start, A+6, A + 2]);
	} else {
		translate([fork_start+A, C-A, boltMargin])
			cube([spokeOD-fork_start, A, boltMargin + 1]);
		translate([fork_start+20, C-A, -1])
			cube([spokeOD-fork_start, A, boltMargin + 2]);
	}
	if (for_cutout){
		difference() {
			translate([fork_start+A, C-A+boltMargin, -1])
				cube([boltMargin+1, boltMargin+1, A+2]);
			translate([fork_start+A, C-A+boltMargin, -1])
				polyhole(d=A, h=A + 2);
		}
	}
}

module spoke_position(){
	A = hubDepth - (wallThick * 2);
	B = forkDepth;
	C = B + 2 * A;
	boltMargin = A / 2;
	F = C / 3;
	translate([0, -boltMargin-wallThick, 0])
		translate([-boltMargin, -F-boltMargin, -boltMargin])
			if (version()[0] >= 2014) {
				children();
			} else {
				child();
			}
}

module ridge() {
	difference() {
		hull() {
			polyhole(d=hubOD+3, h=ridgeHeight);
			translate([0, 0, ridgeHeight])
				polyhole(d=hubOD+20, h=0.01);
		}
		translate([0, 0, -1])
			polyhole(d=hubOD+0.25, h=ridgeHeight+2);
	}
}

```


[User]
Hey there, I'm looking for some help designing a parametric 3D printable corn sheller. It's a tool for removing kernels from corn cobs, and I'd like it to be customizable for different corn sizes. I've seen some designs, but I need something I can easily tweak for various crops and print myself.

Here's the general idea:

*   It should be a hollow, roughly cylindrical shape, tapered slightly from top to bottom. The top opening will be where the corn cob enters, and the bottom will be narrower to help the kernels separate.
*   Inside, I need "fingers" or digits that protrude inward. These are what will strip the kernels from the cob as you twist it. I'd like the number of fingers and their size to be adjustable. I'd also need to control the length, taper, and angle of those fingers.
*   The whole thing needs to be printable, so I'll need to control the thickness of the walls and the clearance between the fingers and the walls.
*   I'd like to control the overall height, the radius of the top opening, and the radius of the bottom opening.

I think we can use OpenSCAD for this, and it should be a fully parametric design, meaning that I can change parameters at the top to adjust the whole thing. I'd prefer that all parameters be set at the top of the file and described with a comment. I'd like to use only basic OpenSCAD operations; no libraries needed here.

Could you generate that for me?

[Assistant]
corn-sheller-final2.scad:
```
//Open-source parametric hand corn sheller

// height of corn sheller
h=55;

// radius of top of corn sheller
rt=35; //[50:130]

rb=0.85*rt; //radius of bottom of corn sheller

//number of digits
d=6;

// digit radius
r=1.5;

// extra length of digit
l=1;

// thickness of sheller
t=3;

module sheller(){
union (){
for (z = [0:d]) // d iterations, z = 0 to d
{
    rotate([0,0, z*360/d])translate([rb,0,h*.1])finger();
}
difference(){
cylinder(h = h, r1 =rt, r2 =rb, center = true, $fn=100);
translate([0,0,0])cylinder(h = h+1, r1 =rt-t, r2 =rb-t, center = true, $fn=100);
}
}
}
module finger(){
rotate([0,(rb/rt)*-10,0])
hull(){
cylinder(h = h*.9, r1 =2*r, r2 =2*r, center = true, $fn=100);
translate([l-(rt-rb),0,0])cylinder(h = h*.9, r1 =r, r2 =r, center = true, $fn=100);
}
}

rotate([180,0,0])
difference(){
sheller();
translate([0,0,h/2])cylinder(h=10, r=rt+10);
}
```


[User]
Hey, I'm looking to design a customizable case with dividers, a hinge, and an optional label. I've seen some examples that use a rounded rectangle base with internal fillets, and a similar lid that has a lip that inserts into the base. The lid should be connected to the base with a flexible living hinge.

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

**Overall Dimensions:**

*   **`interiorWidth`**: The internal width of the case in millimeters.
*   **`interiorLength`**: The internal length of the case in millimeters.
*   **`interiorHeight`**: The internal height of the case in millimeters.
*   **`interiorFillet`**: The radius of the fillets on the inside corners of the case.
*   **`hingeWidth`**: The width of the hinge, which should not exceed the width of the base minus the width of the fillets on either side.

**Dividers:**

*   **`widthSections`**: The number of sections to divide the case into along its width.
*   **`lengthSections`**: The number of sections to divide the case into along its length.

**Walls and Lid:**

*   **`coverThickness`**: The thickness of the top and bottom of the case (the lid and base).
*   **`sidewallWidth`**: The thickness of the vertical walls of the case.
*   **`lidInsetHeight`**: The height of the lip on the lid that fits into the base (larger values will make the case close more securely).
*   **`hingeThickness`**: The thickness of the flexible part of the hinge (it should be relatively thin).

**Optional Details:**

*   **`tabSize`**: The length of an optional tab on the lid, if this is zero it should be removed.
*   **`tabFillet`**:  The fillet radius used for the optional tab on the lid.

**Fine Tuning:**

*  **`lidInsetOffset`**: An adjustment to the lid's inset height to fine-tune how tightly the case closes.
*  **`hingeExtension`**: An adjustment to the length of the hinge,
*   **`hingeBend`**: A value that increases or decreases the length of the flexible portion of the hinge.

**Label:**

*   **`labelText`**: Text to be embossed on the lid.
*  **`labelFont`**: A specific font to use for the embossed label. Should support "write/orbitron.dxf", "write/letters.dxf", "write/knewave.dxf", "write/BlackRose.dxf", and "write/braille.dxf" options, which are all fonts that appear to be included in the "write" library I would like to use.
*   **`labelDepth`**: How deep to emboss the label.
*   **`labelHeight`**: The height of the text for the label.

I'm thinking that a library called "write" would be helpful for the text embossing functionality. I'd like you to generate the necessary .scad file(s). I'm also hoping for good defaults so that if I only change a few parameters to start, I can get a reasonable result.

[Assistant]
Divided_Case_v1-1.scad:
```
use <write/Write.scad>

/*[Dimensions]*/

// Width of the case in mm (interior dimension)
interiorWidth = 48;

// Length of the case in mm (interior dimension)
interiorLength = 32;

// Height of the case in mm (interior dimension)
interiorHeight = 8;

// Case interior fillet radius
interiorFillet = 4.0;

// Width of the hinge in mm
hingeWidth = 32;

/*[Dividers]*/

// Number of sections along the width of the case
widthSections = 3; //[1:20]

// Number of sections along the length of the case
lengthSections = 2; //[1:20]

/*[Walls]*/

// Horizontal wall (top and bottom) thickness
coverThickness = 1.0;

// Vertical wall (side) thickness
sidewallWidth = 1.0;

// Amount the lid protrudes into the case (larger value allows the case to close more securely)
lidInsetHeight = 2.4;

// Thickness of the hinge (it should be no more than a few layers thick keep it flexible)
hingeThickness = 0.3;

/*[Details]*/

// Length of the opening tab on the lid of the case (optional - set to 0 to remove)
tabSize = 0;

// Fillet radius used for the optional tab on the lid
tabFillet = 2;

/*[Fine Tuning]*/

// Adjust the tightness of the closed case (larger value makes the case looser, negative value makes it tighter - try adjusting in 0.1mm increments)
lidInsetOffset = 0;

// Make the hinge longer or shorter
hingeExtension = 0;

// Increase or decrease the flexible portion of the hinge (may be useful for working with different plastics)
hingeBend = 0.6;

/*[Label]*/

// text string embossed into the top of the lid
labelText = "";

// font used to render the label
labelFont = "write/orbitron.dxf"; // ["write/orbitron.dxf":Orbitron, "write/letters.dxf":Basic, "write/knewave.dxf":KneWave, "write/BlackRose.dxf":BlackRose, "write/braille.dxf":Braille]

// depth of the label embossed on the lid
labelDepth = 0.2;

// height of the text in mm
labelHeight = 10;

/*[hidden]*/
eps = 0.1;
$fn = 120; // resolution

module case()
{
	caseLength = interiorLength + sidewallWidth*2;
	caseWidth = interiorWidth + sidewallWidth*2;
	caseRadius = interiorFillet + sidewallWidth;

	lidLength = caseLength + sidewallWidth*2 - lidInsetOffset*2;
	lidWidth = caseWidth + sidewallWidth*2 - lidInsetOffset*2;
	lidRadius = caseRadius + sidewallWidth - lidInsetOffset;

	hingeLength = interiorHeight + coverThickness*2 + hingeExtension;
	centerY = (caseLength + hingeLength)/2;

	hingeWidth = min(hingeWidth, caseWidth - caseRadius*2);
	hingeChamfer = (coverThickness - hingeThickness) * 0.75;

	widthDividerSize = (interiorWidth + sidewallWidth) / widthSections;
	lengthDividerSize = (interiorLength + sidewallWidth) / lengthSections;

	module addLabel(label, zoffset, depth, height, font) {
		if (label != "") {
			translate([0,0,zoffset])
			mirror([0,1,0])
			write(label, t=depth, h=height, font=font, space=1.2, center=true);
		}
	}

	module rrect(h, w, l, r) {
		r = min(r, min(w/2, l/2));
		w = max(w, eps);
		l = max(l, eps);
		h = max(h, eps);
		if (r <= 0) {
			translate([-w/2, -l/2,0]) {
				cube([w,l,h]);
			}
		} else {
			hull() {
				for (y = [-l/2+r, l/2-r]) {
					for (x = [-w/2+r, w/2-r]) {
						translate([x,y,0]) {
							cylinder(h=h, r=r, center=false);
						}
					}
				}
			}
		}
	}

	module rrectTube(h, ow, ol, or, t) {
		difference() {
			rrect(h=h, w=ow, l=ol, r=or);
			translate([0,0,-eps]) {
				rrect(h=h+eps*2, w=ow-t*2, l=ol-t*2, r=or-t);
			}
		}
	}

	union() {
		// lid
		difference() {
			union() {
				translate([0,-centerY - sidewallWidth,0]) {
					rrect(h=coverThickness, w=lidWidth, l=lidLength, r=lidRadius);
					rrectTube(h=lidInsetHeight+coverThickness, ow=lidWidth, ol=lidLength, or=lidRadius, t=sidewallWidth);
				}
			}

			// label
			translate([0,-centerY - sidewallWidth,0]) {
				addLabel(labelText, (labelDepth+eps)/2 - eps, labelDepth+eps, labelHeight, labelFont);
			}

			// hinge cutout
			translate([-hingeWidth/2 - eps, -hingeLength/2 - sidewallWidth - eps, -eps]) {
				cube([hingeWidth + eps*2, hingeLength/2 + sidewallWidth + eps, coverThickness + lidInsetHeight + eps*2]);
			}
		}

		// base
		translate([0,centerY,0]) {
			rrect(h=coverThickness, w=caseWidth, l=caseLength, r=caseRadius);
		}
		difference() {
			translate([0,centerY,coverThickness-eps]) {
				rrectTube(h=interiorHeight+eps, ow=caseWidth, ol=caseLength, or=caseRadius, t=sidewallWidth);
			}

			// hinge cutout
//				translate([-hingeWidth/2 - eps, 0, coverThickness-eps]) {
//					#cube([hingeWidth + eps*2, centerY, interiorHeight+eps*2]);
//				}
		}

	}

	// hinge
	union() {
		translate([-hingeWidth/2,-(hingeLength + sidewallWidth*2 + eps*4)/2,0]) {
			cube([hingeWidth, hingeLength + sidewallWidth * 2 + eps*4, hingeThickness]);
		}
		hull() {
			translate([-hingeWidth/2,-hingeLength/2 + hingeBend/2,0]) {
				cube([hingeWidth, hingeLength-sidewallWidth - hingeBend, coverThickness - hingeChamfer]);
			}
			translate([-hingeWidth/2,-hingeLength/2 + hingeBend/2 + hingeChamfer,0]) {
				cube([hingeWidth, hingeLength-sidewallWidth - hingeBend - hingeChamfer*2, coverThickness]);
			}
		}
	}

	// x dividers
	if (widthSections > 1) {
		for (x = [1:widthSections-1]) {
			translate([widthDividerSize * x - interiorWidth/2 - sidewallWidth,centerY - interiorLength/2 - eps,coverThickness-eps]) {
				cube([sidewallWidth, interiorLength + eps*2, interiorHeight+eps]);
			}
		}
	}

	// y dividers
	if (lengthSections > 1) {
		for (y = [1:lengthSections-1]) {
			translate([-interiorWidth/2 - eps, hingeLength/2 + lengthDividerSize * y, coverThickness-eps]) {
				cube([interiorWidth + eps*2, sidewallWidth, interiorHeight+eps]);
			}
		}
	}

	// tab
	if (tabSize > 0) {
		hull() {
			for (x = [tabFillet - hingeWidth/2, hingeWidth/2 - tabFillet]) {
				translate([x,-caseLength - sidewallWidth*2 - hingeLength/2 - tabSize + tabFillet,0]) {
					cylinder(h=coverThickness, r=tabFillet, center=false);
				}
			}
			translate([-hingeWidth/2, -centerY - sidewallWidth * 2 - caseLength/2 + eps,0]) {
				cube([hingeWidth, eps*2, coverThickness]);
			}
		}
	}

}

case();

```


[User]
I'm looking to generate a parametric Hirth joint, and I've seen a few different implementations but none of them quite fit my needs exactly. I'm hoping you can help me design something similar, but with a few key differences.

The basic structure of the joint is a series of trapezoidal teeth arranged radially around a central axis. I need to be able to control:

*   **Number of Periods:**  The number of teeth around the circumference.
*   **Flank Angle:** The angle of the tooth's sides (relative to vertical).
*   **Base Height:** The height of the base of the joint (before the teeth start).
*   **Vertex Radius:** The overall radius at which the tooth vertices are placed.
*   **Cut Round Radius:**  The radius of a cut-out cylinder that can be used to create a rounded base. If this is zero, there should be no cut-out.
*   **Bore Radius:** The radius of a central bore. If this is zero, there should be no bore.
*   **Vertical Stretching Factor:** A scaling factor along the Z axis. I understand this will change the flank angle, and that's okay for my use-case.
*   **Color Marked Vertices:** An option to visualize the vertices of the joint using differently colored spheres.

Specifically, I want to be able to use the generated joint for mating two parts together. The code I saw generates just one side of the hirth joint, but I need the code to generate *both* sides such that one side is an exact mirror image of the other. The code should be able to create both sides centered and oriented correctly so that they are aligned and can be used for coupling.
Also, I'd like to have a function for a demo grid of hirth joints.

So, could you generate a parametric OpenSCAD file (or files) that will handle all of this for me?  I'm not really particular about which libraries you use, so whatever is easiest for you is fine (if you need any libraries).

[Assistant]
Hirth-joint-generator-2.scad:
```

// author:  Lukas Süss aka mechadense
// date:    2014-07
// title:   parametric Hirth-joint
// license: public domain

/*
This is a trapezoidal Hirt-joint generator.

usage:
* either use customizer
* or use it as a library:
hirth(
  period_number,
  flank_angle,
  base_hight,
  vertex_radius,
  [cutround_diameter|default=0...do_not_cut_round],
  [bore_radius|default=0...no_bore],
  [vertical_stretching_factor|default=1],
  [colormarked_vertices|default=false]);
*/

/*

alternate name: V-tooth coupling
maybe related: curvic couplings

TODO:
  further subdivide mantle-triangles so that the mantle-flanks
  stay parallel to the z-axis and don't slant inward
  especially important for period_number=2 and high flank angles
  (see demogrid)

TODO:
  create alternate more elegant volumetric version defined via halfspaces
  (plane normals)

TODO:
  Create a version that uses a regular polygon instead of a single point
  at the center. This is can enforces self centering on hirth couplings
  of tubes (big bores) without aligning screw.
  such couplings can be found on bicycle axle couplings.

TODO: still buggy:
  with z0=1 and gamma0=45° the teeth should become triangular...

*/

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

/* [Global] */

// flank angle (looking from the side; measured from vertical)
gamma0 = 15;
// number of periods (>=2)
nn0 = 6; //[2:42]

// radius
r0 = 8; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// scaling indentation depth (changes flank angle!)

// diameter of center bore
dbore0 = 3.25; // not yet implemented
// radius to cut from the polygonsal base shape (0 ... do not cut)
rcut0 = 7;

//increase groove depth / flank hight
z0 = 1;
// hight of base body to centerpoint
h0 = 4;

// ################################# constants

/* [Hidden] */

pi = 3.141592653*1;
//centerpoint
cc = [0,0,0]*1;
//$fa = 5*1; $fn = 0.1*1;
degreetorad = ((2*pi)/360);
radtodegree = (360/(2*pi));

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

// size estimation cube
// translate([0,0,20]) cube([10,10,10],center=true);

hirth(nn0,gamma0,h0,r0,rcut0,dbore0,z0); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//pairing();// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//demogrid();// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

module pairing(expl=0.5)
{
  //color("orange") // ?
  translate([0,0,-expl/2])
  hirth(nn0,gamma0,h0,r0,rcut0,dbore0,z0);

  translate([0,0,+expl/2])
  rotate(360/nn0/2,[0,0,1]) scale([1,1,-1])
  hirth(nn0,gamma0,h0,r0,rcut0,dbore0,z0);
}

module demogrid()
{
  for(i=[2:6]){ for(j=[1:5]){
    translate([(i-2)*r0*2.5,(j-1)*r0*2.5,0])
      hirth(i,10*j,h0,r0);
  }}
}

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

module hirth(nn,              // * number of periods
             gamma,           // * flank angle
             h,               // * base body hight
             rr,              // * rough polygonal radius
             rcutround = 0,   // if > 0 => radius of intersecting cylinder
             dbore = 0,       // 0 ... no bore
             z = 1,           // scale cutoff hight
             colvert = false) // for easier vertex identification
{
  // -------------- derived sizes
  n = max(2,nn);
  // periodicity angle
  a = 360/n;
  // double triagle to trapezoid cutoff hight
  // choosen such that at the unit circle
  cutoff = a*degreetorad /3*z; // <= (gamma <= 45°)
  b = cutoff*tan(gamma) *radtodegree;
  a_head = a/2-b;
  a_root = a/2+b;
  h3 = [0,0,h]*1; // helper vector

  function h1(i) = [cos(i*a-a_head/2),sin(i*a-a_head/2),cutoff/2];
  function h2(i) = [cos(i*a+a_head/2),sin(i*a+a_head/2),cutoff/2];
  function r1(i) = [cos(i*a-a_root/2),sin(i*a-a_root/2),-cutoff/2];
  function r2(i) = [cos(i*a+a_root/2),sin(i*a+a_root/2),-cutoff/2];

  difference()
  {
    intersection()
    {
      for(i=[0:n-1])
      {
        toothpolyeder(i);
        // translate([cos(i*a)*1,sin(i*a)*1,-1]) // explode
        basepolyeder(i);
      }
      if(rcutround>0)
      {
        echo("cutround");
        translate([0,0,-3*h])
          cylinder(r=rcutround, h= 6*(h+10),$fa=4,$fs=0.2); // Hack
      }
    }
    if(dbore>0)
    {
      translate([0,0,-3*h])
        cylinder(r=dbore/2, h= 6*h,$fa=4,$fs=0.2);
    }
  }

  module toothpolyeder(i)
  {
    ps = [cc, h1(i)*rr, h2(i)*rr, r1(i)*rr, r2(i)*rr];
    ts = [ [0,1,3],[0,2,1],[0,4,2], // left top and right flank
           [1,4,3],[1,2,4], // mantle (todo: subdivide)
           [0,3,4] ]; // bottom
    polyhedron(points = ps, triangles = ts, convexity = 3);
  }

  module basepolyeder(i)
  {
    ps = [cc, r1(i)*rr, r2(i)*rr, r1(i+1)*rr,
          [0,0,-cutoff/2*rr]-h3, r1(i)*rr-h3, r2(i)*rr-h3, r1(i+1)*rr-h3];
    ts = [ [0,2,1],[0,3,2], [4,5,6],[4,6,7],    // top & bottom
           [1,6,5],[1,2,6], [2,7,6],[2,3,7],    //  mantle (todo: subdivide)
           [0,5,4],[0,1,5], [3,4,7],[3,0,4] ];  // antikoplanar :S
    polyhedron(points = ps, triangles = ts, convexity = 3);
  }

  if(colvert)
  {
    for(i=[0:n-1])
    {
      color("red")    translate(h1(i)*s) sphere(r=1);
      color("orange") translate(h2(i)*s) sphere(r=1);
      color("yellow") translate(r1(i)*s) sphere(r=1);
      color("green")  translate(r2(i)*s) sphere(r=1);
    }
  }

}

```


[User]
I need a parametric clip designed in OpenSCAD for holding an electronics bed beneath a Kossel 3D printer. It needs to be able to rotate freely. Here are the basic requirements:

*   **Shape:** The main body will be a cylinder, with an L-shaped lip extending from it.
*   **Fastening:** It will be fastened using a metric screw. The design needs a clearance hole for the screw. There also needs to be room for a spring to keep the clip tight against the screw head and bed surface.
*   **Parametrization:** I need the following parameters to be adjustable:
    *   `gQuality`: for cylinder quality (number of facets)
    *   `gMetricScrewSize`: diameter of the screw (e.g. 3 for M3 screw)
    *  `gShaftDiameter`: diameter of the main cylindrical shaft
    *   `gShaftHeight`: height of the main cylindrical shaft
    *  `gExposedLipHeight`: the height of the L-shaped lip
    *   `gExposedLipWidth`: how far the L-shaped lip extends from the main shaft
    *   `gSpringDiameter`: the diameter of the smaller cylindrical space for the spring
*   **Functionality:** The clip should have a clearance hole for the screw running through the center of the main cylindrical shaft, and a spring seat for the spring, also centered on the main cylindrical shaft but slightly offset along the height. The L-shaped lip should extend at a 90-degree angle from the base of the main shaft. The clip should also be designed to rotate freely around the screw.

I'm not sure how to best model the spring clearance or clearance hole, and I'm open to suggestions. I would like the code to be clean and well-commented, and I'm not using any specific libraries.

[Assistant]
ElectronicsBedClip.scad:
```
/**
  * A basic clip for holding the bed underneath the kossel.
  **/
// How much 'roundness' do you want to the cylinders?
gQuality=200;

// What screw do you want to use to fasten this?
gMetricScrewSize=3;

// What is the diameter of the shaft used to bolt this down?
gShaftDiameter=12;

// How tall do we want the entire bed clip to be?
gShaftHeight=10;

// The lip that holds the electronics - how much of the shaft does it use?
gExposedLipHeight=3;

// How wide into the bed does the clip extend?
gExposedLipWidth=20;

// How thick should we make the remainder of the shaft to hold the spring?  This is useful for keeping the clamp tight against the frame.  You may need a washer against your screw.
gSpringDiameter=5;

module ScrewClearance(metricSize, height, center=false)
{
	cylinder(r=(metricSize*1.1)/2,h=height, center=center, $fn=gQuality);
}

difference()
{
	// The actual L clamp
	union()
	{
		cylinder(r=gShaftDiameter/2,h=gShaftHeight,center=true, $fn=gQuality);
		translate([-gExposedLipWidth/2,0,(-gShaftHeight+gExposedLipHeight)/2])
		cube([gExposedLipWidth,gShaftDiameter,gExposedLipHeight],center=true);
	}

	ScrewClearance(gMetricScrewSize, height=2000, center=true);
	translate([0,0,gExposedLipHeight])
	cylinder(r=gSpringDiameter/2, h=gShaftHeight,center=true, $fn=gQuality);
}

```


[User]
I'm looking to design a finger cast, similar to the one referenced in Thingiverse (387792 by BRADATECH), but I need it to be fully parametric so I can easily adjust the size and angles. I'd like to be able to specify the diameters of the three sections, the lengths of the first two sections, and the angle between the first and second sections. Also, I want to be able to control the wall thickness.

Specifically, I want the design to be based on a series of joined cylindrical segments. I also need to be able to easily specify a radius and position for two holes in each segment and one hole down the middle of the entire cast.

Could you generate an OpenSCAD design for this? I'd like to be able to control:

*   `diameter_1`: Diameter of the base segment.
*   `diameter_2`: Diameter of the middle segment.
*   `diameter_3`: Diameter of the end segment.
*   `segment_1`: Length of the first segment.
*   `segment_2`: Length of the second segment.
*   `angle`: Angle between the first and second segments (in degrees).
*   `wall`: The thickness of the cast walls.
*   `radius_hole_1_segement_1`: Radius of the first hole in the first segment.
*    `radius_hole_2_segement_1`: Radius of the second hole in the first segment.
*   `radius_hole_1_segement_2`: Radius of the first hole in the second segment.
*   `radius_hole_2_segement_2`: Radius of the second hole in the second segment.
*   `radius_hole_middle`: Radius of the hole through the entire cast.

I'm assuming standard OpenSCAD functions should be sufficient, so I don't think I'll need any specific libraries like MCAD or BOSL.

[Assistant]
FingerCast.scad:
```
diameter_1 = 15;
diameter_2 = 20;
diameter_3 = 25;

segment_1 = 20;
segment_2 = 25;

angle = 20;

wall = 1;

radius_hole_1_segement_1 = 0;
radius_hole_2_segement_1 = 6;

radius_hole_1_segement_2 = 5;
radius_hole_2_segement_2 = 8;

radius_hole_middle = 8;

$fn=30;

fingercast();

module fingercast(){
	difference(){
		hollowfinger();

			rotate([0,90,0])
					translate([0,0,-diameter_3*4])
						cylinder(r=radius_hole_middle, h=diameter_3*4);
	}
}

module hollowfinger(){
	difference(){
		finger(diameter_1/2,diameter_2/2,diameter_3/2,wall, true,radius_hole_1_segement_1,radius_hole_2_segement_1,radius_hole_1_segement_2,radius_hole_2_segement_2);
		finger(diameter_1/2,diameter_2/2,diameter_3/2);
	}
}

module finger(r_1,r_2,r_3,add=0, holes=false, hole1_seg1, hole2_seg1, hole1_seg2, hole2_seg2){
	//Segment 1
	translate([0,0,-segment_1])
		segement(r_1 + add, r_2 + add, segment_1, holes, hole1_seg1, hole2_seg1);
	//Segment 2
	rotate([0,angle,0])
		segement(r_2 + add, r_3 + add,segment_2, holes, hole1_seg2, hole2_seg2);

	//Segmentlinkage
	hull(){
		cylinder(r=r_2 + add, h=0.001);

	rotate([0,angle,0])
		cylinder(r=r_2 + add, h=0.001);
	}
}

module segement(a,b,h,holes, hole1, hole2){
	difference(){
		cylinder(r1=a, r2=b, h=h);

		if(holes){
			if(hole1 > 0)
			translate([0,0,h/2])
				rotate([0,90,0])
					translate([0,0,-h*2])
						cylinder(r=hole1, h=h*4);

			if(hole2 > 0)
			translate([0,0,h/2])
				rotate([90,0,0])
					translate([0,0,-h*2])
						cylinder(r=hole2, h=h*4);
		}
	}
}

```


[User]
Hey, I've been playing around with OpenSCAD and I'm trying to create a kind of tetrahedron-like shape by subtracting cylindrical volumes from a sphere. I've been having some trouble getting it robust and would love some help making it more parametric and less susceptible to weird bugs when I change dimensions.

I've attached the existing file I'm messing with, "artifact-tetrahedron.scad". The basic idea is that you start with a sphere, and then cut away four cylinders to form the tetrahedron shape. The cylinders are positioned and rotated in a way that creates the edges of the tetrahedron when they intersect the sphere.

Here's a summary of the parameters I'm currently using (and would like to have exposed):

*   `size`: This controls the overall size of the tetrahedron (and how far the cylinders are translated)
*   `r0`:  The radius of the starting sphere
*   `rzyl`: The radius of the cutting cylinders
*   `hzyl`: The height of the cutting cylinders

Ideally, the design should be robust to changes in these parameters, and I'm hoping to avoid issues where the cylinders are too short or too small to properly cut away from the sphere, leading to unexpected results. The attached code currently has hardcoded rotation values and I would prefer those to be derived directly from basic geometry.

I'm also hoping for a design that is more efficient (as the author of the example file points out, there are unnecessary surfaces being created). Maybe there's a way to define the cutting volumes using something more akin to infinite planes or halfspaces instead of cylinders that need to be sized large enough to be sure they intersect the initial sphere. I know that OpenSCAD doesn't directly support this, but I'm wondering if there's a clever workaround that could be implemented with modules. I'd like to avoid needing to carefully size my `r0`, `rzyl`, and `hzyl` parameters.

I'd like the whole thing to be a single `.scad` file, and it would be nice if the code was well-commented, easy to understand, and easy to adjust. Thanks for any help you can offer. I'd be really grateful if the new file was more robust to parameter changes than my current approach!

[Assistant]
artifact-tetrahedron.scad:
```

// 2014 Lukas Süss aka mechadense
// public domain
// OpenSCAD: infinite volumes desired

/*
The lack of (semi)-infinite volumes (like halfspaces) introduce a lot of unnecessary variables. If they are not kept big enough in all conceivable cases
(there are too many cases to conceive in any sufficiently complex model)
bugs can be expected to slowly and continulally drizzle in from the run time user side. Furthermore the unnecessary surfaces potentially waste computing power.

I invite you to play with this demo-"artifact-tetrahedron" in customizer to get the picture.

Semi-infinite volumes are implemented in my miniSageCAD experiment:
http://www.thingiverse.com/thing:40210

sidenote: there are some similarities to lazy evaluation
*/

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

/* [the parameter] */

size = 7;

/* [non-infinite bug-parameters] */

r0=20;
rzyl=14;
hzyl=16;

/* [Resolution] */

$fa = 5;
$fs = 0.2;

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

difference()
{
  sphere (r=r0);

  translate([0,0,0])
  {
    rotate(  0,[0,0,1]) cutter();
    rotate(180,[0,0,1]) cutter();
    scale([1,1,-1]) rotate(  90,[0,0,1]) cutter();
    scale([1,1,-1])rotate(270,[0,0,1]) cutter();
  }
}

module cutter()
{
  rotate(45,[0,0,1])
  rotate(-atan(1/sqrt(2)),[0,1,0])
  translate([size,0,0])
  rotate(90,[0,1,0])
    cylinder(r=rzyl,h=hzyl);
}
```


[User]
I'm looking to create a parametric cable tie anchor for securing wire bundles and tubes to flat surfaces. The basic idea is a block with a slot through it for a cable tie, and a hole through the center for the wires. I'd like to be able to adjust the size of the wire bundle, cable tie, and the overall anchor. I want to be able to attach the anchor using double stick foam tape on the bottom.

Specifically, I need the following parameters:

*   **`wire_diameter`**: The maximum diameter of the wire bundle, in millimeters.
*   **`tie_width`**: The width of the cable tie, in millimeters.
*   **`tie_thickness`**: The thickness of the cable tie, in millimeters.
*   **`slot_spacing`**: The distance between the wire bundle hole and the cable tie slot inner edge, in millimeters.
*  **`vertical_tolerance`**: The additional space on top and bottom of the cable tie slot, in millimeters.
*  **`horizontal_tolerance`**: The additional space at the sides of the cable tie slot, in millimeters.

The design should include:

1.  A central hole/cylinder for the wire bundle. This diameter will be equal to the `wire_diameter` variable.

2.  A slot for the cable tie, perpendicular to the wire bundle hole. The slot's width and height should be derived from the `tie_width`, `tie_thickness`, and the tolerances.
    *   Slot width = `tie_width` + 2 \* `horizontal_tolerance`
    *   Slot height = `tie_thickness` + 2 \* `vertical_tolerance`
    *   The inner diameter of the slot should be equal to the wire diameter + slot spacing \* 2

3. The slot should have an outer diameter derived from slot_id + (slot_height * 2).

4. A truncated square-based pyramid block, large enough to contain both the wire hole and the cable tie slot, and that also provides a good bonding area for double stick foam tape. The block should be just slightly larger than slot outer diameter with a base side of 2.5\* wire diameter. The height should be 0.8 * the slot OD. The pyramid should have the flat part of the truncated pyramid facing down.

5.  A small cube at the top center (z axis) to provide structural integrity, with side length equal to 1.1 times the base side.

I'm not sure what libraries would be useful for this, so if you can recommend a good library for this sort of thing, that would be great. I suppose the most obvious one to use might be the "BOSL" library, but I'm not familiar with its capabilities. I'm not sure if I need multiple .scad files for this or not.

[Assistant]
anchor.scad:
```
// Parameterizable cable tie anchor
// Ned Konz, ned@bike-nomad.com

// max. diameter of wire bundle, mm
wire_diameter = 10;
// width of cable tie, mm
tie_width = 3.4;
// thickness of cable tie, mm
tie_thickness = 1.5;
// wire to slot ID, mm
slot_spacing = 4;
// additional space on top and bottom of tie, mm
vertical_tolerance = 1.5;
// additional space at sides of tie, mm
horizontal_tolerance = 0.5;

/* [Hidden] */
// width of slot for cable tie
slot_width = tie_width + 2 * horizontal_tolerance;
// height of slot for cable tie
slot_height = tie_thickness + 2 * vertical_tolerance;
slot_id = wire_diameter + slot_spacing * 2;
slot_od = slot_id + 2 * slot_height;
block_side = wire_diameter * 2.5;
block_height = slot_od * 0.8;

$fn = 32;

module slot(diameter,height,width) {
	difference() {
		cylinder(h=width, d=diameter + height, center=true);
		cylinder(h=width, d=diameter, center=true);
	}
}

module block(side,height) {
	s2 = side / 2;
	polyhedron(
  points=[ [s2,s2,0],[s2,-s2,0],[-s2,-s2,0],[-s2,s2,0], // the four points at base
           [0,0,height]  ],                                 // the apex point
  faces=[ [0,1,4],[1,2,4],[2,3,4],[3,0,4],              // each triangle side
              [1,0,3],[2,1,3] ]                         // two triangles for square base
 );
}

difference() {
	translate([0,0,-block_height/2])
		block(block_side, block_height);
	rotate([90,0,0])
		slot(slot_id, slot_height, slot_width);
	rotate([90,0,0])
		cylinder(h=block_side, d=wire_diameter, center=true);
	translate([0,0,block_side/2])
		cube(block_side * 1.1, center=true);

}
```


[User]
I need an OpenSCAD design for a parametric outlet shim. My house wiring is a mess, and the outlet boxes aren't flush with the drywall. I'm thinking a shim that extends the box outwards would help create a sturdy mounting point.

Here's what I need:

*   **Two Main Types:** I need a design that can handle two types of situations:
    *   **Regular Box Shim:** This will be a simple rectangular prism that extends the box outwards. The thickness on either side of the outlet is the same in this situation.
    *   **Uneven Box Shim:** This will be similar but will have different thicknesses on either the left or right side of the box.
*   **Parameters:** The design needs to be fully parametric, allowing for adjustments in the following:
    *   `type`: A variable indicating the type of shim - "no" for regular, "yes" for uneven.
    *   `L_thickness`: The thickness of the shim on the left (and right, if `type = no`).
    *   `R_thickness`: The thickness of the shim on the right (only used if `type = yes`).
    *   `Box_width`: The width of the outlet box.
    *   `Box_height`: The desired height of the shim extending from the edge of the junction box.
    *   `Lip_thick`: The thickness of the lip that inserts under the junction box. Should be set to "0" if a lip is not needed.
    *   `Lip_length`: The length of the lip.
    *   `Radius`: The radius of the screw hole.
    *   `Hole_distance`: The distance from the edge of the outlet box to the center of the screw hole.

*   **Lip:** I'd like the ability to add a lip that extends under the junction box for extra stability, but it should be optional (a setting to disable the lip should be provided.)

*   **Screw Hole:** The design needs a countersunk screw hole in the middle of the width on the front face. The hole should accommodate a standard outlet screw. The depth of this hole needs to go through the entire thickness of the shim.

*   **Units:** All measurements will be in millimeters (mm).

Could you generate an OpenSCAD file that includes all of this? I am looking for an .scad file that is fully parametric and can easily be adjusted using the Customizer. Please do not provide a separate file for libraries, and I am not requiring that the code use any external libraries.

Thanks!

[Assistant]
Outlet_support.scad:
```
//All measurements are in millimeters(mm)

//Wider on one side than another? Leave as no for a regular box shaped shim
type = "no";

//How much gap between wall and outlet box? Left side - When type=no is both left and right thickness
L_thickness = 12;

//Right side - Unused when type=no
R_thickness = 9;

//Width of outlet box
Box_width = 55;

//Height you want the shim as measured from the edge of the junction box
Box_height = 10.5;

//Thickness of lip that inserts under the junction box, a "0" removes the lip
Lip_thick = 1.5;

//Length of Lip
Lip_length = 7;

//Size of hole radius
Radius = 2;

//Distance from edge of outlet box to the center of the screw hole
Hole_distance = 7.5;

if(type == "no")
{
translate([0,L_thickness,0])cube([Box_width,Lip_length,Lip_thick]);
difference(){
	cube([Box_width,L_thickness,Box_height]);
	translate([Box_width/2,-.00001,Hole_distance])
	rotate([270,0,0])
	cylinder(L_thickness+.00002,Radius,Radius);

}}
if(type == "yes")
{
cube([Box_width,Lip_length,Lip_thick]);
difference(){
polyhedron(
  points=[ [0,0,0],[0,-L_thickness,0],[0,-L_thickness,Box_height],[0,0,Box_height],																					//left side box
	[Box_width,0,0],[Box_width,0,Box_height],[Box_width,-R_thickness,Box_height],[Box_width,-R_thickness,0]],                          // right side box
  faces=[ [0,1,2],[0,2,3],												//left face
				[0,3,4],[3,5,4],              						//front face
          [3,2,5],[2,6,5],												//top face
				[2,1,6],[1,7,6],												//back face
				[0,4,1],[1,4,7],												//bottom face
				[4,5,6],[4,6,7] ]                         		//right face
 );
	translate([Box_width/2,(-(L_thickness+R_thickness)/2)-3,Hole_distance])
	rotate([270,0,0])
	cylinder(L_thickness+3,Radius,Radius);

}}
```


[User]
I'm looking to create a tool that I can attach to my calipers to easily measure the center-to-center distance between holes. Basically, it will be a cylinder with a pointy tip on one end and a slot cut out of the side for the caliper arm to slide into.

Here are the specifics:

*   The main body should be a cylinder, with a given outside diameter and height.
*   At one end of the cylinder, there should be a conical point. The angle of this tip from vertical should be adjustable.
*   There needs to be a rectangular gap cut out of the side of the cylinder, for the caliper arm to fit into. I need to be able to control the width of this gap, and its height (along the axis of the cylinder).

I'd like to be able to define the following parameters:

*   `od`: The outer diameter of the main cylinder.
*   `body_height`: The height of the main cylindrical body.
*   `tip_half_angle`: The angle of the conical tip, measured from vertical.
*   `gap_width`: The width of the gap for the caliper arm.
*  `gap_height`: The height of the gap for the caliper arm.

I'd also like the code to use `$fa` and `$fs` to make the surfaces nice and smooth. Also, include a small `slop` parameter to add a tiny bit of clearance between the gap and the caliper arm to ensure it slides easily.

Could you generate the OpenSCAD code for this, please? I'm not using any special libraries, so this should be straightforward.

[Assistant]
caliper-center-distance-attachment.scad:
```
// Outer diameter of cylinder.
od = 10;
// Length of main cylinder.
body_height = 25;
// Angle of the tip measured from vertical.
tip_half_angle = 30; // [30:60]
// Width of the gap to place caliper arm into.
gap_width = 3.6;
// Length of the caliper arm gap.
gap_height = 20;

/* [Hidden] */
// Make everything nice and round.
$fa = 5;
$fs = 0.5;

slop = 0.1;

difference() {
  union() {
    cylinder(h=body_height, r=od/2);
    translate([0, 0, body_height]) cylinder(h=od/2 / tan(tip_half_angle), r1=od/2, r2=0);
  }
  translate([0, -gap_width/2, -slop]) cube([od/2+slop, gap_width, gap_height+slop]);
}
```


[User]
Hey there, I'm looking to generate an OpenSCAD design for a customizable holder, similar to the one I have already that's included in the attached file. Basically, it's a block with holes to hold cylindrical objects, but with some added flexibility.

Here’s what I'm looking for in terms of features and parameters:

*   **Multiple Object Types:** The holder should accommodate different types of cylindrical objects. Each type needs its own set of parameters. For now, I'll call each type a 'nozzle' in my descriptions, but they could be anything.
*   **Array-Based Input:** I need to be able to specify the characteristics of each nozzle type using arrays:
    *   `r`: Array of nozzle shaft diameters.
    *   `h`: Array of nozzle hole depths.
    *   `n`: Array of the number of each nozzle type to include.
    *   `o`: Array of text labels for each nozzle type.
    *   `s`: Array specifying block sizes for each nozzle type.
*   **Text Labels:** Each nozzle type should have a text label associated with it, engraved or embossed as a design choice. This text should use the `write()` module from the Write.scad library. I can specify the font, size, height/depth, and whether it's embossed or engraved.
*   **Border:** I need a border around each hole for the nozzles. The border can be either round or square, and its size needs to be parametric as well.
*   **Holder Thickness:** The overall thickness of the holder should be configurable.
*   **Layout:** The different nozzle groups should be placed side-by-side along the X axis. Each nozzle of a type should be laid out along the Y axis, one after another.

Basically, each group of holes in the X axis should be defined by a different set of parameters from the arrays above.

So, to summarize: a base block, holes of different sizes and depths arranged in groups, with associated text labels, and the ability to choose round or square borders around those holes. I need to use the `Write.scad` library for text, and ideally be able to define how each of those groups are arranged and sized, via arrays. Can you help me create the scad files for this?

[Assistant]
Nozzle_Holder_V1.scad:
```
include <write/Write.scad>
//include <VectorMath.scad>
//Font
font="write/Letters.dxf"; //["write/BlackRose.dxf":BlackRose,"write/braille.dxf":Braille,"write/knewave.dxf":knewave,"write/Letters.dxf":Default,"write/orbitron.dxf":Orbitron]
//Text size
t_size=6;
//Text Vertical Offset from hole
t_vert=0;
//Text depth/height
depth=1;
//Text emboss or engrave
emboss=0; //[0:engrave,1:emboss]
//Border around holes
bor=2.5;
//Square or round border
square=0; //[0:round,1:square]
//Thickness of holder
thick=8;
//number of nozzle types
num=4;
//Nozzle shaft diameters in array
r=[6.3,6.3,6.3,6.3];
//Nozzle hole depths in array
h=[7,7,7,7];
//Number of each nozzle type in array
n=[1,2,1,4];
//Nozzle orifice diameter/labels in array
o=["0.25mm SS","0.4mm SS","0.7mm SS","0.4mm Br"];
//Label block sizes in array
s=[50,45,45,45];

//offset=0;

if(emboss==1) textemb();
else texteng();

module base(){
for(i=[0:num-1]){assign(offset=bor+i*bor+2*sumv(r,i)-r[1]){
translate([offset,0,0]){difference(){
	union(){
	translate([0,s[i]/2,0])cube([2*(bor+r[i]),s[i],thick],center=true);
for(j=[0:n[i]-1]){
	translate([0,-j*(bor+2*r[i]),0])
	if(square==0)cylinder(r=bor+r[i],h=thick, $fn=50,center=true);
	else cube([2*(bor+r[i]),2*(bor+r[i]),thick],center=true);
}	//end for
}	//end union
	for(j=[0:n[i]-1])translate([0,-j*(bor+2*r[i]),thick-h[i]])cylinder(r=r[i],h=h[i]+0.1,$fn=50,center=true);
}}	//end trans dif
}}	//end for assign
}	//end module

module textemb(){
union(){
base();
for(i=[0:num-1]){assign(offset=bor+i*bor+2*sumv(r,i)-r[1]){
translate([offset,s[i]/2+r[i]/2,thick/2])rotate([0,0,90])write(o[i],h=t_size,t=depth,center=true,font=font);
}}	//end for assign
}	//end union
}	//end module

module texteng(){
difference(){
base();
for(i=[0:num-1]){assign(offset=bor+i*bor+2*sumv(r,i)-r[1]){
translate([offset,s[i]/2+r[i]/2,thick/2])rotate([0,0,90])write(o[i],h=t_size,t=depth,center=true);
}}	//end for assign
}	//end union
}	//end module

// VectorMath.scad
// Version 2
// Released to the Public Domain
function sumv(v,i,s=0) = (i==s ? v[i] : v[i] + sumv(v,i-1,s));
```


[User]
I'm looking to create a parametric OpenSCAD design for a set of rolling ellipses, similar to what's described in "How Round is Your Circle". The key is that as these ellipses roll, their center of mass stays at the same height, resulting in a smooth roll without any preferred resting orientation. I've seen some implementations, but I need a version I can customize heavily.

Specifically, I want the design to have these parameters that I can adjust in OpenSCAD's Customizer:

*   **`major_diameter`**: This sets the major diameter of the ellipses. I'd like to have it configurable, say from 10mm to 100mm.
*   **`minor_diameter_ratio`**: Instead of setting the minor diameter directly, I want to set it as a ratio to the major diameter.  For example, a value of 1000 would make the minor diameter equal to the major diameter, and a value of around 707.1 would produce the sqrt(2) relationship that results in the rolling ellipses whose centers do not displace as they roll. I want to adjust this ratio, probably in a range of around 500 to 1414.2 (sqrt(2)*1000).
*   **`thickness`**: This is the thickness of the material, probably with settings of 1mm, 2mm, or 5mm as options.
*   **`Display`**: This will be a dropdown selection with two options: "3D" and "Flat". When selected as "3D", the ellipses are displayed in their rolling orientation. When selected as "Flat", the ellipses are laid flat.
*   **`time`**: I would like to have an animation that rotates the 3D model around the axis of rolling, just like in the given example; the variable `time` should range from 0 to 100 and represent a fraction of a full rotation. The parameter should be within an "Animation" collapsible group in the customizer.
*   **`$fn`**: I'd like the level of detail for the curves to be adjustable; it should be within a "Hidden" collapsible group, set to 100 by default, but able to be adjusted if needed.

The design should include the math to calculate the separation between the centers of the ellipses based on the major and minor diameters. Also, it should handle the rotation to orient the ellipses for a smooth roll in 3D mode. I'm particularly interested in seeing the "slots" used to create the rolling action when the `Display` option is set to "Flat".

I will need all of the code for the design, including any helper modules you create. I would prefer that the code be modular to increase understandability. I would like you to use the MCAD units library to define lengths.

Could you generate the OpenSCAD file or files for this design?

[Assistant]
PerpendicularRollingEllipses.scad:
```

//Variables for customizer
// preview[view:south, tilt:top diagonal]

//The (typically larger) diameter of an ellipse (mm)
major_diameter = 25; //[10:100]

//When 1000, minor dia=major dia. (ratio*1000)
minor_diameter_ratio = 1000; //[500:1414.2]

//Thickness of the material (mm)
thickness = 1; //[1,2,5]

//How to orient the ellipses
Display = "3D"; //[3D, Flat]

/* [Animation] */
//Time step
time = 0; //[0:100]

/* [Hidden] */
//Detail ($fn)
$fn=100;

$t = time / 100;
if(Display == "3D")
	PerpendicularRollingEllipses(majorDia = major_diameter, minorDia = major_diameter*minor_diameter_ratio / 1000, thickness = thickness, cut=false);
else
	PerpendicularRollingEllipses(majorDia = major_diameter, minorDia = major_diameter*minor_diameter_ratio / 1000, thickness = thickness, cut=true);

//Limit: sqrt(2)*a <= b, or separation between centers becomes complex (not a real solution)

//Interesting objects:
//1. Rolls in two directions; b=sqrt(2)*a; no displacement between centers
//PerpendicularRollingEllipses(majorDia = 2 * inch, minorDia = 2*sqrt(2)*inch, thickness = 1);
//2. b == a; circle (not ellipse); Displacement=sqrt(2)*radius
//PerpendicularRollingEllipses(majorDia = 2 * inch, minorDia = 2*inch, thickness = 1);
//3. b < a
//PerpendicularRollingEllipses(majorDia = 2 * inch, minorDia = 1.2*inch, thickness = 1);

module PerpendicularRollingEllipses(
majorDia = 2 * inch,
minorDia = 2*inch,
thickness = 3,
cut = false
)
{

	//From "How Round is Your Circle"
	//Chapter 13 "Finding Some Equilibrium"
	//Page 35 of 44

	//separation (mm) = sqrt(4a^2 - 2b^2)

	assign(a=majorDia / 2, b = minorDia / 2)
	{
		assign(separation = sqrt(4*pow(a,2) - 2*pow(b, 2)))
		{
			//assign(minorDia = 2*b)
			{
				echo("Separation: ", separation);
				echo("Major radius: ",a);
				echo("Minor radius: ",b);
				echo("Slot depth: ", a - separation/2);
				echo("Slot fraction of radius: ", (a - separation/2)/a);

				if(cut)
				{
					translate([0, b+1, 0])
					SlottedEllipse(a, b, separation, thickness);

					translate([0, -b-1, 0])
					SlottedEllipse(a, b, separation, thickness);
				}
				else
				{
					rotate([360*$t,-cos(720*$t)*atan2(a, separation+a),0])
					{
						translate([-separation/2, 0, -thickness/2])
						linear_extrude(height=thickness)
						SlottedEllipse(a, b, separation, thickness);

						translate([separation/2, 0 , 0])
						rotate([90,0,180])
						translate([0, 0, -thickness/2])
						linear_extrude(height=thickness)
						SlottedEllipse(a, b, separation, thickness);
					}
				}
				*cube([7.439, 5, 5], center=true);
			}
		}
	}

}

module SlottedEllipse(major = 1*inch, minor = 0.5*inch, separation=0.25 * inch, thickness = 3)
{
	difference()
	{
		Ellipse(major, minor);
		//circle(r=separation-major);
		//circle(r=1);

		rotate([0,0,-90])
		translate([0, major/2 + separation / 2, 0])
		square([thickness, major], center=true);
	}
}

module Ellipse(major = 1*inch, minor = 0.5*inch)
{
	scale([1, minor/major, 1])
	circle(major);
}

include <MCAD/units.scad>
```


[User]
Hey there, I'm looking for some OpenSCAD code to generate a customizable clip, specifically for cylindrical objects. I've got some basic ideas, but I need help implementing them in a parametric way.

Essentially, I need a C-shaped clip that can wrap around a cylinder. I'd like to be able to control the following parameters:

*   **Inner Radius:** This is the radius of the cylinder I want to clip onto. It's super important to get this right.
*   **Thickness:** How thick the clip is. The thicker it is, the more rigid it will be.
*   **Height:** The height of the clip. This influences the amount of grip it has on the cylinder.
*   **Support Width:** I also need a small support base at the bottom of the clip to help with 3D printing. This parameter will control the width of that support.
*   **Support Height:**  This will control the height of the support base.

I want the support base to be on the bottom of the clip (so I don't need to rotate it to print) and I want the clip to have rounded edges. The cut-out on the clip to make it a "C" should be a full cut-out to make an actual C shape.

I'm imagining something similar to the file I've been tinkering with (clip.scad), but I want a proper parametric version. Let me know if this is doable.

[Assistant]
clip.scad:
```

clipInnerRad = 9;
clipThikness = 3;
clipHeight = 15;

supportWidth = 1;
supportHeight = 0.3;

rotate([0,0,-90]){
	clip(ir=clipInnerRad-supportWidth/2,t=clipThikness+supportWidth,h=supportHeight);
	translate([0,0,supportHeigth])clip();
}

module clip(ir=clipInnerRad,t=clipThikness,h=clipHeight){

	difference(){
		cylinder(r=ir+t,h=h,$fn=PI*(ir+t)*5);
		translate([0,0,-.5])
		cylinder(r=ir,h=h+1,$fn=PI*ir*5);

		rotate([0,0,-45])
		translate([0,0,-.5])
		cube([10e10,10e10,h+1]);
	}

	for (r=[-45,45]) rotate([0,0,r])
	translate([ir+t,0,0])
	cylinder(r=t,h=h,$fn=PI*t*5);

}
```


[User]
I need a round, hinged case that I can 3D print. I've got some specific dimensions in mind, and I'd like to be able to adjust them easily. It should have a lid that fits snugly into the base, and a flexible hinge. I'm not looking for a simple box - it needs to be a bit more sophisticated, with options for a tab and fillets, plus a chamfer to help with closing.

Here are the details:

*   **Case Dimensions:**
    *   Interior Diameter (the usable space inside): I'd like this to be a variable.
    *   Interior Height:  This should also be adjustable.
    *   Lid Inset Height: How far the lid goes into the base - this affects how secure it closes.
    *   Hinge Width:  The width of the hinge connecting the lid to the base.

*   **Wall Thickness:**
    *   Wall Height: Thickness of the walls in the horizontal direction.
    *   Wall Width: Thickness of the walls in the vertical direction.
    *   Rim Inset:  How much the rim extends beyond the main edge of the case.

*   **Hinge:**
    *   Hinge Thickness:  The thickness of the flexible hinge part.
    *   Hinge Length Scale:  A scaling factor for the hinge length, based on the interior height.

*   **Fit and Closure:**
    *   Lid Inset Offset: Allows for adjusting how tight or loose the lid fits; negative values make it tighter.

*   **Details:**
    *   Tab Size: An optional tab on the lid to help opening (0 removes it).
    *   Fillet Radius: The radius of fillets used for the hinge and tab.
    *   Chamfer: A small chamfer to help the lid close smoothly.

Could you generate a parametric OpenSCAD file (or files if you think it makes sense) for this? I'd like all of these parameters to be easily changeable at the beginning of the code. I don't have any particular libraries in mind other than what's built-in to OpenSCAD, so just base it on that, please.

[Assistant]
round_folding_case_v1-0.scad:
```

/*[Dimensions]*/

// Diameter of the case (interior dimension)
interiorDiameter = 50;

// Height of the case (interior dimension)
interiorHeight = 8;

// Amount the lid protrudes into the case (larger value allows the case to close more securely)
lidInsetHeight = 2.4;

// Width of the hinge
hingeWidth = 16;

/*[Walls]*/

// Horizontal wall thickness
wallHeight = 1.0;

// Vertical wall thickness
wallWidth = 1.2;

// Distance the rim extends beyond the edge of the case
rimInset = 0.6;

// Adjust the tightness of the closed case (larger value makes the case looser, negative value makes it tighter)
lidInsetOffset = 0.0;

// Thickness of the hinge
hingeThickness = 0.4;

// Length of the hinge
hingeLengthScale = 1.5;

/*[Details]*/

// Length of the tab on the lid of the case (optional - set to 0 to remove)
tabSize = 1.5;

// Fillet radius used for hinge and tab
filletRadius = 6;

// Chamfer used to make the case easier to close
chamfer = 0.4;

/*[hidden]*/
eps = 0.1;
$fn = 120;

module case()
{
	module tube(h, od, id) {
		difference() {
			cylinder(h=h, r=od/2);
			translate([0,0,-eps]) {
				cylinder(h=h+eps*2, r=id/2);
			}
		}
	}

	caseDiameter = interiorDiameter + wallWidth*2 + rimInset*2;
	baseDiameter = caseDiameter - rimInset*2;
	lidDiameter = baseDiameter - wallWidth*2 - lidInsetOffset;
	hingeLength = hingeLengthScale * interiorHeight + wallHeight*2;
	centerY = (caseDiameter + hingeLength)/2;

	filletXOffset = hingeWidth/2 + filletRadius;
	filletAngle = asin((filletXOffset) / (caseDiameter/2+filletRadius));
	filletYOffset = centerY - sqrt(pow(caseDiameter/2+filletRadius, 2) - pow(filletXOffset,2));
	filletHingeExpansion = filletRadius * (1-sin(filletAngle));

	union() {
		// bottom surfaces
		for (y = [-centerY, centerY]) {
			translate([0,y,0]) {
				cylinder(h=wallHeight, r=caseDiameter/2);
			}
		}

		translate([0,0,wallHeight-eps]) {
			// base
			translate([0,centerY,0]) {
				difference() {
					tube(h=interiorHeight+eps, od=baseDiameter, id=interiorDiameter);
					if (chamfer > 0) { // chamfer
						translate([0,0,interiorHeight-chamfer]) {
							cylinder(h=chamfer+eps*2,d1=interiorDiameter-eps, d2=interiorDiameter+chamfer*2,center=false);
						}
					}
				}
			}

			// lid
			translate([0,-centerY,0]) {
				difference() {
					tube(h=lidInsetHeight+eps, od=lidDiameter, id=lidDiameter-wallWidth*2);
					if (chamfer > 0) {
						difference() {
							translate([0,0,lidInsetHeight-chamfer]) {
								cylinder(h=chamfer+eps*2, r=(lidDiameter+eps)/2, center=false);
							}
							translate([0,0,lidInsetHeight-chamfer-eps]) {
								cylinder(h=chamfer+eps*4, d1=lidDiameter, d2=lidDiameter-chamfer*2, center=false);
							}
						}
					}
					//translate([-1, -lidDiameter/2 - eps, -eps]) {
					//	  cube([2, lidDiameter + 2*eps, lidInsetHeight + 2*eps]);
					//}
				}
			}
		}

		// hinge
		difference() {
			translate([-hingeWidth/2 - filletHingeExpansion,-centerY,0]) {
				cube([hingeWidth + filletHingeExpansion*2, centerY*2, hingeThickness]);
			}

			// fillet hinge
			for (x = [-filletXOffset, filletXOffset]) {
				hull() {
					for (y = [-filletYOffset, filletYOffset]) {
						translate([x,y,-eps]) {
							cylinder(h=hingeThickness + eps*2, r=filletRadius, center=false);
						}
					}
				}
			}
		}

		// tab
		if (tabSize > 0) {
			hull() {
				for (x = [filletRadius - hingeWidth/2, hingeWidth/2 - filletRadius]) {
					translate([x,-caseDiameter - hingeLength/2 - tabSize + filletRadius,0]) {
						cylinder(h=wallHeight, r=filletRadius, center=false);
					}
				}
				translate([-hingeWidth/2,-centerY,0]) {
					cube([hingeWidth, eps, wallHeight]);
				}
			}
		}

	}
}

case();

```


[User]
Hey! I'm really into these gyroid structures and I've seen some cool puzzles made with them. I'm trying to design my own modular gyroid puzzle system in OpenSCAD.

Essentially, I want to have a main gyroid module that is based on a rhombic dodecahedron. The user has provided the following functions and modules to work with:

*   `L`: This is the base length parameter, defining the size of the gyroid module.
*   `d`: This is the diameter of the base clasps/connectors.
*   `tol`: This is the tolerance for the connectors.
*   `gyroid()`: This module creates the basic gyroid shape by intersecting the result of a scaled difference of imported STL files with a rhombic dodecahedron (also defined by its own module).
*   `connector(h, w, n)`: This module creates a curved connector piece. It's the most complex and I'll explain it further. The `h` and `w` parameters control the inner and outer heights of the clasp, and `n` is the number of connection elements. It does a rotational extrusion, intersects with a couple of cubes rotated with the angle. This module is used to connect the different gyroid modules to form a larger puzzle structure.
*   `rhombDodeca()`: Makes a rhombic dodecahedron shape.
*   `block()`: This is a placeholder for the imported gyroid puzzle piece, which I assume will come from an STL file, and it also does some rotations and translations to make it fit in the right place.
*   `assembly(n, type)`: Assembles `n` number of gyroid modules along each edge of a triangle, and either displays just rhombic dodecahedrons (`type=0`) or actual blocks (`type=1`).
*   `base()`: This module creates a base piece, which is derived from a rhombic dodecahedron and has connectors on the faces.
*   `baseAssembly(n)`:  Assembles `n` base modules for each edge of a triangle.
*   `totalAssembly(n, type)`: A combination of `assembly` and `baseAssembly`, displaying both gyroid modules and base modules.

I want to create something very similar but I would like to be able to modify it much more directly, so STL imports are out.  I need all of these shapes to be designed parametrically in OpenSCAD without external dependencies (meaning I don't want to use STL imports for anything).

Here's what I need:

1.  **Parametric Gyroid:** Instead of importing an STL, I need a way to generate the gyroid surface parametrically. I know it's complex, so I'm fine with using an approximation or simplified version of the gyroid, so long as it retains the general shape and its connectivity. I'm thinking I should define the gyroid surface using a mathematical equation and then create a mesh using `surface()` or similar, and then extrude it into a 3D shape. Also, all the parameters that used to apply to the imported STL should still apply (e.g. `L`). I'm happy to have some additional parameters to simplify it, but keep the L.
2.  **Parametric Connector:** I need the `connector` module to be fully parametric, using `linear_extrude`, `rotate_extrude` and boolean operations like `intersection` and `difference` in OpenSCAD primitives only. I need to be able to specify the parameters `h`, `w` and `n`, but I also want it to calculate the radius `R` and the rotation angle `theta` based on L, h, and w using the following equations: `R=L*L/(w-h)/16` and `theta=4*(w-h)/L*180/PI`.
3.  **Rhombic Dodecahedron Module:** This shape needs to be built using `cube` and `rotate` primitives, and be fully parametric with the length `L` so that it fits the gyroid module correctly.
4.  **Assembly Modules:** The `assembly`, `base`, `baseAssembly`, and `totalAssembly` modules should work in the same way as the original program, except they use the new parametric modules for the gyroid, connector, and rhombic dodecahedron shapes. I would like a way to specify the `fit` parameter, as it was also specified by the original user (I need this to adjust the connector dimensions if necessary).
5.  **Unit Testing:** I need the code to include examples of how to use the modules, especially the assembly modules.  I'd like to see some examples of assembled structures with different `n` values, just to make sure it's working correctly.

The important thing is that everything should be parametric and modifiable with OpenSCAD code only. I am looking for a set of .scad files which implement these modules.

Could you help me out with this design?

[Assistant]
gyroidpuzzle.scad:
```
// gyroid puzzle

L=20*1;// height of gyroid module will be L*sqrt(2)
d=L/3;// diameter of base clasps
tol=0.25*1;// tolerance on base clasps

//gyroid();
//base();

//Number of wiggles
n=3;
//Adjust the fit (positive makes it looser)
fit=0;

translate([-L*n/2,0,(3-fit)*sqrt(3)/4])connector(3-fit,4-fit,n);

// Assembly inputs: (n,type), where:
// n is the number of modules along each edge
// type = 0 to show rhombic dodecahedrons only
// type = 1 to show actual pieces
//assembly(4,1);// modules only
//totalAssembly(5,1);// modules and base modules
//attach();// animation of connectors twisting through gyroid

module attach(){
//block();
color([1,0,0])translate([-L-L/8,L/8,3*L/8])connector(3,4,3);
color([0,1,0])translate([L/8,3*L/8,L+L/8])rotate([0,90,0])connector(3,4,3);
color([0,0,1])translate([3*L/8,-L+L/8,L/8])rotate([0,0,90])connector(3,4,3);
}

module connector(h,w,n)
assign(R=L*L/(w-h)/16,theta=4*(w-h)/L*180/PI)
translate([-$t*L,0,0])rotate([$t*360,0,0])render()
for(i=[0:2*n-1])translate([L/2*i+L/4,0,0])rotate([0,0,i*180])
translate([0,-R*cos(theta),0])intersection(){
	rotate_extrude($fn=360/theta*4)translate([R,0])union(){
		translate([(w-h)/2,0])circle(r=h/2,$fn=6);
		translate([(h-w)/2,0])circle(r=h/2,$fn=6);
	}
	rotate([0,0,theta+0.1])translate([0,0,-R])cube(2*R);
	rotate([0,0,90-theta-0.1])translate([0,0,-R])cube(2*R);
}

module rhombDodeca(){
intersection(){
	rotate([0,0,45])cube(L*sqrt(2)*[1,1,2],center=true);
	rotate([0,45,0])cube(L*sqrt(2)*[1,2,1],center=true);
	rotate([45,0,0])cube(L*sqrt(2)*[2,1,1],center=true);
}}

module gyroid(){
translate([0,0,L/sqrt(2)])rotate([-45,0,90])
intersection(){
	scale(L/50)difference(){
		import("gyroidThick1.stl",convexity=10);
		import("gyroidThin1.stl",convexity=10);
	}
	rhombDodeca();
}}

module gyroid1(){
translate([0,0,L/sqrt(2)])rotate([-45,0,90])
intersection(){
	scale(L/50)difference(){
		import("gyroidThick1.stl",convexity=10);
		import("gyroidHalf1.stl",convexity=10);
	}
	rhombDodeca();
}}

module gyroid2(){
translate([0,0,L/sqrt(2)])rotate([-45,0,90])
intersection(){
	scale(L/50)difference(){
		import("gyroidHalf1.stl",convexity=10);
		import("gyroidThin1.stl",convexity=10);
	}
	rhombDodeca();
}}

module block(){
rotate([45,0,0])rotate([0,0,-90])translate(-[0,0,L/sqrt(2)])import("gyroidpuzzle.stl",convexity=10);
}

module assembly(n,type){
rotate([-acos(1/sqrt(3)),0,0])rotate([0,0,-45])translate(-L*(n-1)/2*[1,1,1])
	for(k=[0:n-1]){
	for(j=[0:n-1-k]){
	for(i=[0:n-1-k-j]){
		color([(i+1)/n,(j+1)/n,(k+1)/n])translate(i*[L,L,0]+j*[L,0,L]+k*[0,L,L])
			if(type==0) rhombDodeca(); else block();
	}}}
}

module base(){
render()
intersection(){
	translate([0,0,-L*3/4])rotate([180,0,0])union(){assembly(3,0);}
	translate([0,0,L])cube(2*L,center=true);
	difference(){
		union(){
			translate([0,0,L/4])rotate([-acos(1/sqrt(3)),0,0])rotate([0,0,-45])rhombDodeca();
			for(i=[0:5])rotate([0,0,i*60])translate([L/sqrt(2),0,-1])
				rotate([0,0,-45])translate([0,d/2,0])cylinder(r=d/2-tol/2,h=L,$fn=20);
		}
		for(i=[0:5])rotate([0,0,i*60])translate([L/sqrt(2),0,-1])
			rotate([0,0,-45])translate([0,-d/2,0])cylinder(r=d/2+tol/2,h=L,$fn=20);
	}
}}

module baseAssembly(n){
rotate([-acos(1/sqrt(3)),0,0])rotate([0,0,-45])translate(-L*(n-1)/2*[1,1,1])
	for(k=[0:n-1]){
	for(i=[0:n-1-k]){
		color([(i+1)/n,0,(k+1)/n])translate(i*[L,L,0]+k*[0,L,L])
			rotate([0,0,45])rotate([acos(1/sqrt(3)),0,0])base();
	}}
}

module totalAssembly(n,type){
assembly(n,type);
translate([0,0,-L])baseAssembly(n);
echo(str("Requires ",(n*n+n)/2," base modules"));
echo(str("Requires ",(n*n*n+3*n*n+2*n)/6," gyroid modules"));
}
```


[User]
I'd like to create a customizable text keychain. It should have a rectangular base with a circular ring attachment point. The main body of the keychain should be a rectangular prism, and the ring attachment should be a cylinder attached to one of the short sides. There needs to be a hole going through the center of the cylinder and the keychain body. The text should be centered on the main body of the keychain and should be raised (or extruded). I'd also like all the dimensions to be customizable.

Specifically, I want to control the following:

*   The text itself
*   The font size of the text
*   The height/thickness of the text
*   The width of the rectangular keychain body
*   The length of the rectangular keychain body
*   The overall thickness of the keychain body
*   The radius of the cylindrical ring attachment
*   The radius of the hole going through the ring and body.

I think I'd like to use the `Write.scad` library for the text part, so please make sure to include that. Thanks!

[Assistant]
text_keychain-thingiverse.scad:
```
use <write/Write.scad>

/* [Hidden] */

$fn=30;

/* [Text] */

text="Test";
font_size=2;
font_height=.5;

/* [Size] */

width=5;
length=8;
thickness=1;

/* [Ring] */

ring_radius=1;
hole_radius=.6;

difference()
{
	union()
	{
		cylinder(h=thickness,r=ring_radius);
		cube([width,length,thickness]);
	}
	cylinder(h=thickness + 1, r=hole_radius, center = true);
}

translate([width/2,length/2,thickness+font_height/2])
{
	rotate(a=90,v=[0,0,1])
	{
		write(text,t=font_height,h=font_size,center=true);
	}
}
```


[User]
I'm looking to create some clips for my IKEA SAMLA boxes, specifically the smaller 5L, 11L, and 22L sizes. I've seen similar clips for the larger SAMLA boxes, but they don't fit these smaller ones. I want to be able to secure the lids to the boxes so they don't fall off, especially when stacking them.

My idea is to have clips that slide onto the edge of the box and lid. The clips should have a little wedge that sticks out so they help lock the boxes in place when stacked. This wedge would prevent the boxes from shifting, particularly if you have two 5L boxes stacked side by side on an 11L or 22L box. The clips need to be designed so that they don't interfere with each other in this configuration. I'd also like the clips to allow me to just lift one side of the lid off, without removing the clips from the lid entirely on one side.

I’d like to specify the width of the clips as a parameter. I'm thinking about 10mm wide clips initially, but it would be great to be able to adjust that later. Ideally, I could then print 4 of these clips per box. Can you generate an OpenSCAD file for me that includes this functionality? I don’t have any code already so I’d need you to create a design from scratch. I am not using any external libraries currently, so please don't assume I have any installed and generate the code as if it were going to be run standalone.

[Assistant]
samla_clips.scad:
```
/*
 * Variables for Thingiverse Customizer
 * ==================================================================
 *
 */

// The width of the clips in mm (I use 10 mm and have 4 clips per box)
Clips_Width = 10;

/*
 * Library function: edge
 * ==================================================================
 *
 * Used to make roundes edges on objects
 *
 */
module edge(radius, height)
{
	difference()
	{
		translate([radius/2-0.5, radius/2-0.5, 0])
			cube([radius+1, radius+1, height], center = true);

		translate([radius, radius, 0])
			cylinder(h = height+1, r1 = radius, r2 = radius, center = true, $fn = 100);
	}
}

module ikea_samla_clips(width)
{
	length = 25;
	difference()
	{
		union()
		{

			translate([0, 0, -3/2])
				cube(size=[length, width, 3], center=true);

			translate([length/2-3/2, 0, -(8+3)/2])
				cube(size=[3, width, 8+3], center=true);

			difference()
			{
				translate([length/2, 0, -(8+3+1.5)/2])
					cube(size=[6, width, 8+3-1.5], center=true);

				translate([length/2+3+1, 0, -(8+3+1.5)/2-1])
				rotate(20, [0, 1, 0])
					cube(size=[6, width+1, 8+3], center=true);
			}

			translate([-length/2+3, 0, -3])
			rotate(-90, [1, 0, 0])
				edge(8, width);

			translate([-(length/2-3/2), 0, -(12+3+3)/2])
				cube(size=[3, width, 12+3+3], center=true);

			translate([-(length/2-(3+4+3)/2), 0, -12-3-3/2])
				cube(size=[3+4+3, width, 3], center=true);

			translate([-(length/2-(3+4+3)+(3/2)), 0, -12-3])
				cube(size=[3, width, 3+3], center=true);

			translate([length/2-3, 0, -3])
			rotate(-90, [1, 0, 0])
			rotate(90, [0, 0, 1])
				edge(2, width);
		}

		union()
		{
			translate([-length/2, 0, 0])
			rotate(-90, [1, 0, 0])
				edge(8+3, width+1);

			translate([-length/2, 0, -12-3-3])
			rotate(-90, [1, 0, 0])
			rotate(-90, [0, 0, 1])
				edge(1, width+1);

			translate([-length/2+3+4+3, 0, -12-3-3])
			rotate(-90, [1, 0, 0])
			rotate(-180, [0, 0, 1])
				edge(1, width+1);

			translate([length/2-3, 0, -8-3])
			rotate(-90, [1, 0, 0])
			rotate(-90, [0, 0, 1])
				edge(1, width+1);

			translate([length/2, 0, -8-3])
			rotate(-90, [1, 0, 0])
			rotate(-180, [0, 0, 1])
				edge(1, width+1);

			translate([length/2, 0, 0])
			rotate(-90, [1, 0, 0])
			rotate(90, [0, 0, 1])
				edge(1, width+1);
				}
	}
}

ikea_samla_clips(Clips_Width);
```


[User]
I'm looking to create a customizable slider switch cover. I've seen some designs online, but I'd like to be able to tweak it to fit different sized switches and desired cover dimensions.

Specifically, I need an OpenSCAD design that can handle the following parameters:

*   **Switch Dimensions:**
    *   `switch_width`: The width of the slider part of the switch.
    *   `switch_length`: The length of the switch in the sliding direction.
*   **Cover Dimensions:**
    *   `padding`: The amount of internal padding between the switch and the cover's inner wall. This needs to be adjustable for a snug or looser fit.
    *   `cover_width`: The width of the material extending outwards from the padded internal space to the outer edge of the cover.
    *   `cover_length`: The length of the material extending outwards from the padded internal space to the outer edge of the cover.
    *   `cover_height`: The overall height of the cover.

The design should create a rectangular cover with a rectangular hole in the middle to fit around the switch. The hole should be sized using the `switch_width`, `switch_length` and the `padding` variables.  The outer dimensions should be calculated using the `switch_width`, `switch_length`, `padding`, `cover_width`, and `cover_length` values.

I'd like the OpenSCAD code to include a module called `draw_cover()` which actually generates the 3D model. It would be good if the design takes advantage of the included 'build_plate' module from `utils/build_plate.scad` for layout and that it also includes a `write` library for annotations. I am using the `write` library from `write/Write.scad`. Thanks.

[Assistant]
customizable-slider_switch_cover.scad:
```
use <utils/build_plate.scad>
use <write/Write.scad>

//----------------------------------------------------------------------------
// Customize and print your own Slider Switch cover
// http://www.thingiverse.com/thing:394501
//
// by Erwin Ried (2014-07-15)
// http://www.thingiverse.com/eried/things

//---[ USER Customizable Parameters ]-----------------------------------------

/* [Switch] */
// Width of the switch slider (mm):
switch_width = 5.3;

// Length of the switch in the sliding direction (mm):
switch_length = 6.7;

/* [Cover] */
// Internal padding of the cover (mm) per side:
padding = 0.7;

// Width of the cover from the padded space (mm) to border:
cover_width = 2.5;

// Length of the cover from the padded space (mm) to border:
cover_length = 7.3;

// Height of the cover (mm):
cover_height = 0.6;

//---[ Build Plate ]----------------------------------------------------------

/* [Build plate] */
//: for display only, doesn't contribute to final object
build_plate_selector = 2; //[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);

// preview[view:south, tilt:top]

//----------------------------------------------------------------------------

draw_cover();

module draw_cover()
{
	translate([0,0,cover_height])
	{
		difference()
		{
			cube([switch_width+(2*(padding+cover_width)),switch_length+(2*(padding+cover_length)),cover_height],true);
			cube([switch_width+(2*padding),switch_length+(2*padding),cover_height*2],true);
		}
	}
}

```


[User]
I need a way to create an adjustable link for my projects. I've got two pieces that I want to join together, but I need to be able to change the distance between them after they're connected. I'm thinking something along the lines of a slotted piece where one part can slide.

I'd like to be able to customize a few key parameters: the diameter of the holes for screws/bolts, the overall width of the link, the minimum and maximum center-to-center distance between the holes, and the thickness of the material. I'd also like the walls around the holes to be easily adjusted as well, perhaps as a percentage of the hole diameter.

I'm imagining a design where there's a central part with two fixed screw holes, with a slot running along the length, and another piece with a single hole which can slide along the slot, and be secured at different positions using another screw.

Could you please generate the necessary OpenSCAD code for this? I don't have a preference for specific libraries, but I'd like to use whichever you think is best.

[Assistant]
adjustable_link.scad:
```
//Adjustable link
//By Johan Bengtsson qwerty_42@hotmail.com

//(in mm)
HoleSize=3;

//(in mm)
Distance1=30;

//(in mm)
Distance2=50;

//(in mm)
Thickness=2;

//(in percent of hole size)
WallWidth=100;

/* [Hidden] */

Width=HoleSize*(1+WallWidth/50);
MinDistance=min(Distance1,Distance2);
MaxDistance=max(Distance1,Distance2);

$fn=100;

difference()
{
	union()
	{
		cylinder(h=Thickness,r=Width/2);
		translate([MaxDistance,0,0]) cylinder(h=Thickness,r=Width/2);
		translate([0,-Width/2,0]) cube([MaxDistance,Width,Thickness]);
	}
	union()
	{
		translate([MinDistance,0,-1]) cylinder(h=Thickness+2,r=HoleSize/2);
		translate([MaxDistance,0,-1]) cylinder(h=Thickness+2,r=HoleSize/2);
		translate([0,0,-1]) cylinder(h=Thickness+2,r=HoleSize/2);
		translate([MinDistance,-HoleSize/2,-1]) cube([MaxDistance-MinDistance,HoleSize,Thickness+2]);
	}
}

```


[User]
I'm looking to create a button battery holder, and I'd like it to be parametric so I can easily adjust it for different battery sizes. I'm thinking of a design similar to the one described in this Thingiverse project (http://www.thingiverse.com/thing:21041), but I want to be able to specify the parameters directly as numbers instead of using sliders, like in bmcage's remix of that project.

Here are the main features I need:

*   **Number of slots:** The ability to specify how many batteries the holder should store. I'll need a variable for this.
*   **Battery type:** I need to be able to select from common button battery sizes like CR2032 and AG13, or specify custom dimensions.
*   **Custom battery dimensions:** If a custom battery type is selected, I need to be able to define the battery radius and the battery width.
*   **Divider width:** The width of the dividers between the battery slots should also be adjustable. This should probably be twice the nozzle diameter of my 3D printer.
*   **Basic shape:** The holder should have dividers creating individual slots for the batteries, and walls at the ends to contain them. I want a rectangular base, with the dividers perpendicular to the long side.

The basic design is to have cylindrical dividers that have a flat section, then a rectangular base that fits the outside of the dividers, and finally some vertical walls at the ends.

I'm thinking the output will need to be a single `.scad` file. Could you generate the code for this?

[Assistant]
buttonbatteryholder-remix.scad:
```
// Licence: Creative Commons, Attribution
// Parametrized button battery holder

// Thingiverse user by bmcage
// Same idea as http://www.thingiverse.com/thing:21041

//number of slots to hold battery
nr = 10;  // [2:30]
//what button battery should this hold
battery = "CR2032";  //[CR2032, AG13, custom]
//if custom battery, what is radius ?
custom_radius = 10;
//if custom battery, what is width ?
custom_width = 3;
//width of the divider, hint: take 2*nozzle diameter of your printer
sizedivider = 0.8;

module divider(radius) {
  translate([radius, 0,radius])
  rotate([-90,0,0]) {
    difference() {
      cylinder(r=radius, h=sizedivider,$fn=50);
      translate([0,0,-0.01]) cylinder(r=radius-3, h=sizedivider +0.02);
    }
  translate([-radius,0,0]) cube([2*radius,radius,sizedivider]);
  }
}

module holder(radius, width) {
  length = nr*(sizedivider+width) + sizedivider;
  rotate([0S,0,45])
  union() {
  for (i=[0:nr]) {
    translate([0,i*(sizedivider+width),0]) divider(radius);
  }
  cube([2*radius, length, sizedivider]);
  translate([-sizedivider+0.01,0,0]) cube([sizedivider, length, radius]);
  translate([2*radius-0.01,0,0]) cube([sizedivider, length, radius]);
  }
}

if (battery == "CR2032") {
    holder(10,3);
}
if (battery == "AG13") {
    holder(6,6.3);
}
if (battery == "custom") {
    holder(custom_radius,custom_width);
}
```


[User]
I need an OpenSCAD file (or files, if that makes sense) for an omni wheel for a small robot, like a RoboCup Junior robot. It should be parametric so I can easily adjust the dimensions.

The wheel has a main body, several cylindrical washers that act as rollers, and some holes for mounting.

Here's a breakdown:

*   **Main Body:** The main body has a stepped cylindrical shape. It has three sections. The first section is a cylinder, 2mm high and 26mm in radius. The second section is a cylinder, 1mm high and 27.75mm in radius, and sits on top of the first section. Finally, the third section is a truncated cone, 1mm high, with a bottom radius of 27.75mm, a top radius of 26.75mm, and sitting on top of the second section.

*   **Rollers (Washers):**  There are a number of roller "washers" spaced evenly around the main body. These are essentially rectangular prisms. Each washer is 2mm wide, 7.5mm deep, and 6mm tall. The washers are placed with their center at a radius of 21.25mm from the center of the wheel and should be positioned so the edge that's parallel to the radial direction of the main body is aligned with the circumference of the circle they are located on. They start 1 mm below the top surface of the main body. The number of washers is a parameter. I'll be using #6 washers, so that should be approximately 32, but it would be nice to be able to change that later.

*   **Mounting Holes:** There are 4 mounting holes, equally spaced, for mounting the wheel to a hub. These are simple cylinders with a diameter suitable for a #2-56 screw, which I think is a 1.2mm radius. They extend all the way through the wheel, with their centers 6.25mm from the center. They also start 1 mm below the top surface of the main body.

*   **Axle Hole:** Finally, there's a central axle hole, which should be 2mm in radius, passing all the way through the wheel, starting 1 mm below the top surface of the main body.

I'd like parameters for all the key dimensions, like the radii of the various cylinders in the main body, the number of rollers, their width, depth, and height, and the radii and positions of the mounting holes and axle hole.  It would be good to be able to adjust the height of the different layers of the main body too. I’d also like to control the height below the top surface of the wheel the rollers, mounting holes, and axle hole start.

I'd prefer if the file used MCAD for the screw hole related items as I know it provides great screw creation modules.

Thanks in advance for your help!

[Assistant]
RobocupOmniWheel.scad:
```
/* [Parameters] */
Axle_Radius = 2;
Mounting_Screw_Radius=1.2;

Number_of_Washers = 32;
Washer_Width = 2;

/* [Hidden] */
$fn=64;

difference()
{
    union(){
        cylinder(h=2,r=26);
		  translate([0,0,2])
	         cylinder(h=1,r=27.75);
        translate([0,0,3])
            cylinder(h=1,r1=27.75,r2=26.75);

    }
	for(i = [0: Number_of_Washers - 1])
	{
		rotate(i*360/Number_of_Washers)
		{
   		translate([-Washer_Width/2,21.25,-1])
			{
				cube([Washer_Width,7.5,6]);
			}
		}
	}
	for(i = [0:3])
	{
		rotate(i*90)
		{
			translate([0,6.25,-1])
			{
				cylinder(h=6,r=Mounting_Screw_Radius);
			}
		}
	}
	translate([0,0,-1])
	{
		cylinder(h=6,r=Axle_Radius);
	}
}
```