[User]
Hey, I'm looking to create a gear and plate generator for my Spiro Machine project. I've seen some similar things, but I need a custom one based on the formulas used in that one and also with the capability to produce both gears and plates for a spirograph.

Specifically, I want a module that can create both gears and plates, and the user should be able to select whether to generate a 'Gear' or a 'Plate' using a variable, let's call it `gear_or_plate` that can have "Gear" or "Plate" values. This should be a top-level variable. I also need to control the number of teeth on the gear/plate, let's call that `teehts`. This will determine the number of 'points' in the spirograph pattern so it's important. The actual number of teeth will be stored in `dientes` using `dientes = teehts;`.

The gear module should follow the design described in the included 'Parametric Involute Bevel and Spur Gears' library that I've seen, so I'll need that code. The basic parameters are `number_of_teeth`, `circular_pitch`, `gear_thickness`, `rim_thickness`, `hub_thickness`, `hub_diameter`, `bore_diameter`, and the other parameters used in the `gear()` function in that libary. The code should produce two identical gears mirrored over the Z axis and moved slightly apart, in the fashion that the existing code does using `mirror([0,0,1])` and `translate([0,0,-10])`

The `circular_pitch` should be set to 250. The `twist` parameter in the `gear()` function should be derived from an angle parameter which I'll call `angulo` with value 400, and divide it by the number of teeths (`dientes`). I will use the code to change the gears to make other patterns like some "double-helix" types so it should be included. This `twist` should be applied to both mirrored gears.

For the gears, there should also be a series of circular holes around the gear (but not on the plate), the quantity of which is determined by a formula based on the radius of the gear. The radius is equal to `0.5 * (teehts * 250 / 180)`, and the number of holes is equal to the radius minus 12, divided by 3 and floored (`floor((radius-12)/3)`). The holes themselves should be cylinders centered around the origin, with a radius of 2.5 and a height of 10.1, with `$fn=20` for the smoothness. These holes should be rotated by 45 degrees multiplied by the index when they are created.

For the plates, instead of gears, a simple plate should be created. This will consist of a cylinder with a radius of 50 and height of 10, minus a cylinder with a radius of 40 and height 10. The plate's base should be translated up by 1 unit to prevent any z-fighting, with an additional cylinder placed at the origin with a radius of 10 and height of 1 to form the base, in an if/else statement depending on whether the `gear_or_plate` variable has a "Plate" value or not.

Both gears and plates should have the number of teeth printed on the side. This text should be extruded a small amount for visibility, and should be created using a `linear_extrude(height=3)` and `text(str(dientes), size=8, font="Arial:style=Bold")`. This text should be translated to `[-6, -15, 8.5]` on gears and plates.

Could you generate the necessary OpenSCAD files to do this? I'd prefer not to rely on a bunch of external libraries, but I do know that I will need the existing `gear()` module and `involute` calculation functions etc from the linked library above to create the shapes.

[Assistant]
gear_generator_customizer.scad:
```
/*

GEAR GENERATOR FOR SPIRO MACHINE (http://www.thingiverse.com/thing:2039878)

Fernando Jerez 2017

BASED ON:
Parametric Involute Bevel and Spur Gears by GregFrost
http://www.thingiverse.com/thing:3575

*/

gear_or_plate = "Gear"; // [Gear:Gear, Plate:Plate]
teehts = 36; // Number of Theeths

/* [Hidden] */
dientes =  teehts;
angulo = 400; // 400 para el espirografo

radius  =  0.5* (teehts * 250 / 180);
holes = floor((radius-12)/3);

difference(){
    union(){
        gear (
        number_of_teeth=dientes,
        circular_pitch=250,
        gear_thickness = 10,
        rim_thickness = 5,
        hub_thickness = 10,
        hub_diameter=10,
        bore_diameter=10,
        circles=0,
        backlash=0,
        twist=angulo/dientes,
        involute_facets=0);

        mirror([0,0,1])
            translate([0,0,-10])
            gear (
                number_of_teeth=dientes,
                circular_pitch=250,
                gear_thickness = 10,
                rim_thickness = 5,
                hub_thickness = 10,
                hub_diameter=10,
                bore_diameter=10,
                circles=0,
                backlash=0,
                twist=angulo/dientes,
                involute_facets=0);

    }

    if(gear_or_plate=="Gear"){
        if(holes>=1){
            for(i=[0:holes-1]){
                rotate([0,0,45*i]) translate([9+3*i,0,0]) cylinder(r=2.5,h=10.1,$fn=20);
            }
        }
    }
    if(gear_or_plate=="Plate"){
        translate([0,0,1])
        difference(){
            cylinder(r=50,h=10,$fn=100);
            cylinder(r=40,h=10,$fn=100);
        }
    }

    // texto
    translate([-6,-15,8.5]){
        linear_extrude(height=3){
            text(str(dientes),size=8,font="Arial:style=Bold");
        }
    }

}
if(gear_or_plate=="Plate"){
    cylinder(r=10,h=1);
}

// ORIGINAL CODE by GregFrost: http://www.thingiverse.com/thing:3575

// Parametric Involute Bevel and Spur Gears by GregFrost
// It is licensed under the Creative Commons - GNU GPL license.
// © 2010 by GregFrost
// http://www.thingiverse.com/thing:3575

// Simple Test:
//test_double_helix_gear();

//Complex Spur Gear Test:
//test_gears ();

// Meshing Double Helix:
//meshing_double_helix ();

// Demonstrate the backlash option for Spur gears.
//test_backlash ();

// Demonstrate how to make meshing bevel gears.
//bevel_gear_pair ();

pi=3.1415926535897932384626433832795;

//==================================================
// Bevel Gears:
// Two gears with the same cone distance, circular pitch (measured at the cone distance)
// and pressure angle will mesh.

module bevel_gear_pair (
	gear1_teeth = 41,
	gear2_teeth = 7,
	axis_angle = 90,
	outside_circular_pitch=1000)
{
	outside_pitch_radius1 = gear1_teeth * outside_circular_pitch / 360;
	outside_pitch_radius2 = gear2_teeth * outside_circular_pitch / 360;
	pitch_apex1=outside_pitch_radius2 * sin (axis_angle) +
		(outside_pitch_radius2 * cos (axis_angle) + outside_pitch_radius1) / tan (axis_angle);
	cone_distance = sqrt (pow (pitch_apex1, 2) + pow (outside_pitch_radius1, 2));
	pitch_apex2 = sqrt (pow (cone_distance, 2) - pow (outside_pitch_radius2, 2));
	echo ("cone_distance", cone_distance);
	pitch_angle1 = asin (outside_pitch_radius1 / cone_distance);
	pitch_angle2 = asin (outside_pitch_radius2 / cone_distance);
	echo ("pitch_angle1, pitch_angle2", pitch_angle1, pitch_angle2);
	echo ("pitch_angle1 + pitch_angle2", pitch_angle1 + pitch_angle2);

	rotate([0,0,90])
	translate ([0,0,pitch_apex1+20])
	{
		translate([0,0,-pitch_apex1])
		bevel_gear (
			number_of_teeth=gear1_teeth,
			cone_distance=cone_distance,
			pressure_angle=30,
			outside_circular_pitch=outside_circular_pitch);

		rotate([0,-(pitch_angle1+pitch_angle2),0])
		translate([0,0,-pitch_apex2])
		bevel_gear (
			number_of_teeth=gear2_teeth,
			cone_distance=cone_distance,
			pressure_angle=30,
			outside_circular_pitch=outside_circular_pitch);
	}
}

//Bevel Gear Finishing Options:
bevel_gear_flat = 0;
bevel_gear_back_cone = 1;

module bevel_gear (
	number_of_teeth=11,
	cone_distance=100,
	face_width=20,
	outside_circular_pitch=1000,
	pressure_angle=30,
	clearance = 0.2,
	bore_diameter=5,
	gear_thickness = 15,
	backlash = 0,
	involute_facets=0,
	finish = -1)
{
	echo ("bevel_gear",
		"teeth", number_of_teeth,
		"cone distance", cone_distance,
		face_width,
		outside_circular_pitch,
		pressure_angle,
		clearance,
		bore_diameter,
		involute_facets,
		finish);

	// Pitch diameter: Diameter of pitch circle at the fat end of the gear.
	outside_pitch_diameter  =  number_of_teeth * outside_circular_pitch / 180;
	outside_pitch_radius = outside_pitch_diameter / 2;

	// The height of the pitch apex.
	pitch_apex = sqrt (pow (cone_distance, 2) - pow (outside_pitch_radius, 2));
	pitch_angle = asin (outside_pitch_radius/cone_distance);

	echo ("Num Teeth:", number_of_teeth, " Pitch Angle:", pitch_angle);

	finish = (finish != -1) ? finish : (pitch_angle < 45) ? bevel_gear_flat : bevel_gear_back_cone;

	apex_to_apex=cone_distance / cos (pitch_angle);
	back_cone_radius = apex_to_apex * sin (pitch_angle);

	// Calculate and display the pitch angle. This is needed to determine the angle to mount two meshing cone gears.

	// Base Circle for forming the involute teeth shape.
	base_radius = back_cone_radius * cos (pressure_angle);

	// Diametrial pitch: Number of teeth per unit length.
	pitch_diametrial = number_of_teeth / outside_pitch_diameter;

	// Addendum: Radial distance from pitch circle to outside circle.
	addendum = 1 / pitch_diametrial;
	// Outer Circle
	outer_radius = back_cone_radius + addendum;

	// Dedendum: Radial distance from pitch circle to root diameter
	dedendum = addendum + clearance;
	dedendum_angle = atan (dedendum / cone_distance);
	root_angle = pitch_angle - dedendum_angle;

	root_cone_full_radius = tan (root_angle)*apex_to_apex;
	back_cone_full_radius=apex_to_apex / tan (pitch_angle);

	back_cone_end_radius =
		outside_pitch_radius -
		dedendum * cos (pitch_angle) -
		gear_thickness / tan (pitch_angle);
	back_cone_descent = dedendum * sin (pitch_angle) + gear_thickness;

	// Root diameter: Diameter of bottom of tooth spaces.
	root_radius = back_cone_radius - dedendum;

	half_tooth_thickness = outside_pitch_radius * sin (360 / (4 * number_of_teeth)) - backlash / 4;
	half_thick_angle = asin (half_tooth_thickness / back_cone_radius);

	face_cone_height = apex_to_apex-face_width / cos (pitch_angle);
	face_cone_full_radius = face_cone_height / tan (pitch_angle);
	face_cone_descent = dedendum * sin (pitch_angle);
	face_cone_end_radius =
		outside_pitch_radius -
		face_width / sin (pitch_angle) -
		face_cone_descent / tan (pitch_angle);

	// For the bevel_gear_flat finish option, calculate the height of a cube to select the portion of the gear that includes the full pitch face.
	bevel_gear_flat_height = pitch_apex - (cone_distance - face_width) * cos (pitch_angle);

//	translate([0,0,-pitch_apex])
	difference ()
	{
		intersection ()
		{
			union()
			{
				rotate (half_thick_angle)
				translate ([0,0,pitch_apex-apex_to_apex])
				cylinder ($fn=number_of_teeth*2, r1=root_cone_full_radius,r2=0,h=apex_to_apex);
				for (i = [1:number_of_teeth])
//				for (i = [1:1])
				{
					rotate ([0,0,i*360/number_of_teeth])
					{
						involute_bevel_gear_tooth (
							back_cone_radius = back_cone_radius,
							root_radius = root_radius,
							base_radius = base_radius,
							outer_radius = outer_radius,
							pitch_apex = pitch_apex,
							cone_distance = cone_distance,
							half_thick_angle = half_thick_angle,
							involute_facets = involute_facets);
					}
				}
			}

			if (finish == bevel_gear_back_cone)
			{
				translate ([0,0,-back_cone_descent])
				cylinder (
					$fn=number_of_teeth*2,
					r1=back_cone_end_radius,
					r2=back_cone_full_radius*2,
					h=apex_to_apex + back_cone_descent);
			}
			else
			{
				translate ([-1.5*outside_pitch_radius,-1.5*outside_pitch_radius,0])
				cube ([3*outside_pitch_radius,
					3*outside_pitch_radius,
					bevel_gear_flat_height]);
			}
		}

		if (finish == bevel_gear_back_cone)
		{
			translate ([0,0,-face_cone_descent])
			cylinder (
				r1=face_cone_end_radius,
				r2=face_cone_full_radius * 2,
				h=face_cone_height + face_cone_descent+pitch_apex);
		}

		translate ([0,0,pitch_apex - apex_to_apex])
		cylinder (r=bore_diameter/2,h=apex_to_apex,$fn=30);
	}
}

module involute_bevel_gear_tooth (
	back_cone_radius,
	root_radius,
	base_radius,
	outer_radius,
	pitch_apex,
	cone_distance,
	half_thick_angle,
	involute_facets)
{
//	echo ("involute_bevel_gear_tooth",
//		back_cone_radius,
//		root_radius,
//		base_radius,
//		outer_radius,
//		pitch_apex,
//		cone_distance,
//		half_thick_angle);

	min_radius = max (base_radius*2,root_radius*2);

	pitch_point =
		involute (
			base_radius*2,
			involute_intersect_angle (base_radius*2, back_cone_radius*2));
	pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
	centre_angle = pitch_angle + half_thick_angle;

	start_angle = involute_intersect_angle (base_radius*2, min_radius);
	stop_angle = involute_intersect_angle (base_radius*2, outer_radius*2);

	res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;

	translate ([0,0,pitch_apex])
	rotate ([0,-atan(back_cone_radius/cone_distance),0])
	translate ([-back_cone_radius*2,0,-cone_distance*2])
	union ()
	{
		for (i=[1:res])
		{
            point1=involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i-1)/res);
            point2= involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i)/res);
            side1_point1 = rotate_point (centre_angle, point1);
            side1_point2 = rotate_point (centre_angle, point2);
            side2_point1 = mirror_point (rotate_point (centre_angle, point1));
            side2_point2 = mirror_point (rotate_point (centre_angle, point2));
            polyhedron (
                points=[
                    [back_cone_radius*2+0.1,0,cone_distance*2],
                    [side1_point1[0],side1_point1[1],0],
                    [side1_point2[0],side1_point2[1],0],
                    [side2_point2[0],side2_point2[1],0],
                    [side2_point1[0],side2_point1[1],0],
                    [0.1,0,0]],
                triangles=[[0,1,2],[0,2,3],[0,3,4],[0,5,1],[1,5,2],[2,5,3],[3,5,4],[0,4,5]]);
		}
	}
}

module gear (
	number_of_teeth=15,
	circular_pitch=false,
    diametral_pitch=false,
	pressure_angle=28,
	clearance = 0.2,
	gear_thickness=5,
	rim_thickness=8,
	rim_width=5,
	hub_thickness=10,
	hub_diameter=15,
	bore_diameter=5,
	circles=0,
	backlash=0,
	twist=0,
	involute_facets=0)
{
	if (circular_pitch==false && diametral_pitch==false)
		echo("MCAD ERROR: gear module needs either a diametral_pitch or circular_pitch");

	//Convert diametrial pitch to our native circular pitch
	circular_pitch = (circular_pitch!=false?circular_pitch:180/diametral_pitch);

	// Pitch diameter: Diameter of pitch circle.
	pitch_diameter  =  number_of_teeth * circular_pitch / 180;
	pitch_radius = pitch_diameter/2;
	echo ("Teeth:", number_of_teeth, " Pitch radius:", pitch_radius);

	// Base Circle
	base_radius = pitch_radius*cos(pressure_angle);

	// Diametrial pitch: Number of teeth per unit length.
	pitch_diametrial = number_of_teeth / pitch_diameter;

	// Addendum: Radial distance from pitch circle to outside circle.
	addendum = 1/pitch_diametrial;

	//Outer Circle
	outer_radius = pitch_radius+addendum;

	// Dedendum: Radial distance from pitch circle to root diameter
	dedendum = addendum + clearance;

	// Root diameter: Diameter of bottom of tooth spaces.
	root_radius = pitch_radius-dedendum;
	backlash_angle = backlash / pitch_radius * 180 / pi;
	half_thick_angle = (360 / number_of_teeth - backlash_angle) / 4;

	// Variables controlling the rim.
	rim_radius = root_radius - rim_width;

	// Variables controlling the circular holes in the gear.
	circle_orbit_diameter=hub_diameter/2+rim_radius;
	circle_orbit_curcumference=pi*circle_orbit_diameter;

	// Limit the circle size to 90% of the gear face.
	circle_diameter=
		min (
			0.70*circle_orbit_curcumference/circles,
			(rim_radius-hub_diameter/2)*0.9);

	difference ()
	{
		union ()
		{
			difference ()
			{
				linear_extrude (height=rim_thickness, convexity=10, twist=twist)
				gear_shape (
					number_of_teeth,
					pitch_radius = pitch_radius,
					root_radius = root_radius,
					base_radius = base_radius,
					outer_radius = outer_radius,
					half_thick_angle = half_thick_angle,
					involute_facets=involute_facets);

				if (gear_thickness < rim_thickness)
					translate ([0,0,gear_thickness])
					cylinder (r=rim_radius,h=rim_thickness-gear_thickness+1);
			}
			if (gear_thickness > rim_thickness)
				cylinder (r=rim_radius,h=gear_thickness);
			if (hub_thickness > gear_thickness)
				translate ([0,0,gear_thickness])
				cylinder (r=hub_diameter/2,h=hub_thickness-gear_thickness);
		}
		translate ([0,0,-1])
		cylinder (
			r=bore_diameter/2,
			h=2+max(rim_thickness,hub_thickness,gear_thickness),$fn=30);
		if (circles>0)
		{
			for(i=[0:circles-1])
				rotate([0,0,i*360/circles])
				translate([circle_orbit_diameter/2,0,-1])
				cylinder(r=circle_diameter/2,h=max(gear_thickness,rim_thickness)+3);
		}
	}
}

module gear_shape (
	number_of_teeth,
	pitch_radius,
	root_radius,
	base_radius,
	outer_radius,
	half_thick_angle,
	involute_facets)
{
	union()
	{
		rotate (half_thick_angle) circle ($fn=number_of_teeth*2, r=root_radius);

		for (i = [1:number_of_teeth])
		{
			rotate ([0,0,i*360/number_of_teeth])
			{
				involute_gear_tooth (
					pitch_radius = pitch_radius,
					root_radius = root_radius,
					base_radius = base_radius,
					outer_radius = outer_radius,
					half_thick_angle = half_thick_angle,
					involute_facets=involute_facets);
			}
		}
	}
}

module involute_gear_tooth (
	pitch_radius,
	root_radius,
	base_radius,
	outer_radius,
	half_thick_angle,
	involute_facets)
{
	min_radius = max (base_radius,root_radius);

	pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
	pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
	centre_angle = pitch_angle + half_thick_angle;

	start_angle = involute_intersect_angle (base_radius, min_radius);
	stop_angle = involute_intersect_angle (base_radius, outer_radius);

	res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;

	union ()
	{
		for (i=[1:res])
		{
			point1=involute (base_radius,start_angle+(stop_angle - start_angle)*(i-1)/res);
			point2=involute (base_radius,start_angle+(stop_angle - start_angle)*i/res);
            side1_point1=rotate_point (centre_angle, point1);
            side1_point2=rotate_point (centre_angle, point2);
            side2_point1=mirror_point (rotate_point (centre_angle, point1));
            side2_point2=mirror_point (rotate_point (centre_angle, point2));
            polygon (
                points=[[0,0],side1_point1,side1_point2,side2_point2,side2_point1],
                paths=[[0,1,2,3,4,0]]);
		}
	}
}

// Mathematical Functions
//===============

// Finds the angle of the involute about the base radius at the given distance (radius) from it's center.
//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html

function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / pi;

// Calculate the involute position for a given base radius and involute angle.

function rotated_involute (rotate, base_radius, involute_angle) =
[
	cos (rotate) * involute (base_radius, involute_angle)[0] + sin (rotate) * involute (base_radius, involute_angle)[1],
	cos (rotate) * involute (base_radius, involute_angle)[1] - sin (rotate) * involute (base_radius, involute_angle)[0]
];

function mirror_point (coord) =
[
	coord[0],
	-coord[1]
];

function rotate_point (rotate, coord) =
[
	cos (rotate) * coord[0] + sin (rotate) * coord[1],
	cos (rotate) * coord[1] - sin (rotate) * coord[0]
];

function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*pi/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*pi/180*cos (involute_angle)),
];

```


[User]
Hi, I'm looking for an OpenSCAD design for a bird ladder. I have some specific requirements in mind, and I'd like it to be parametric so I can easily adjust the dimensions later.

Here’s what I need:

*   **Overall Shape:** The ladder should consist of two vertical rails connected by horizontal rungs. The rails should have rounded edges to prevent sharp corners.
*   **Dimensions:**
    *   I need to be able to specify the total height of the ladder.
    *   I need to be able to specify the total width of the ladder.
    *   The rungs should be evenly spaced, and I need to be able to control this distance.
    *   The rungs should be cylindrical, and I need to be able to specify their diameter.
    *   The rails should have a consistent thickness that I can specify.
    *   The rounding on the edges of the rails should also be customizable.
*   **Hooks:**
    *   I'd like the option for hooks at the top of each rail that allow it to hang on the side of a cage.
    *   These hooks should have an adjustable angle relative to the rails.
    *   I should be able to adjust the length of the hooks, or even set them to zero to remove them entirely.
*   **Material Considerations:** I will be 3D printing this, so I would appreciate considerations for printability (like no need for supports or very minimal support material). I would prefer to print this in PLA.
*   **OpenSCAD libraries**: I'm open to the use of libraries as long as they are common. I haven't used any before though, so if you could keep it simple that would be ideal.

I'm looking for the design to be easily customizable for different bird sizes and cage configurations. Let me know if you need more details. Thank you!

[Assistant]
bird_ladder.scad:
```
// The total height of the ladder
height = 200;

// The total width of the ladder
width = 90;

// The distance between the centre of each rung
rung_spacing = 50;

// The diameter of each rung
rung_diameter = 15;

// How thick the connecting rails should be
rail_thickness = 8;

// Rounding applied to the rail's edges. This prevents sharp edges. Must be less than half the rail thickness and less than half the rung diameter
rail_corner_radius = 3;

// The angle the hooks make with the rails in degrees.
hook_angle = 70; // [90]

// The length of the hooks, set to zero for no hooks.
hook_length = 30;

/* [Hidden] */
$fa = 10;
$fn = 360 / $fa;

build();

module build()
{
    num_rungs = floor((height - rung_spacing / 2 - rung_diameter / 2) / rung_spacing) + 1;
    rail();
    translate([width - rail_thickness, 0, 0]) rail();

    module rail()
    {
        corner_diameter = rail_corner_radius * 2;
        minkowski()
        {
            translate([rail_corner_radius, rail_corner_radius, rail_corner_radius]) cube([rail_thickness - corner_diameter, rung_diameter - corner_diameter, height - corner_diameter]);
            sphere(r = rail_corner_radius);
        }
        translate([0, cos(hook_angle) * rail_thickness / 2 + rail_thickness / 2, height - sin(hook_angle) * rail_thickness]) rotate([180 - hook_angle, 0, 0]) minkowski()
        {
            translate([rail_corner_radius, rail_corner_radius, rail_corner_radius]) cube([rail_thickness - corner_diameter, rail_thickness - corner_diameter, hook_length + rail_thickness / 2]);
            sphere(r = rail_corner_radius);
        }
    }

    for(idx = [0 : num_rungs - 1])
        rotate([0, 90, 0]) translate([-(idx + 0.5) * rung_spacing, rung_diameter / 2, rail_thickness / 2]) cylinder(d = rung_diameter, h = width - rail_thickness);
}
```


[User]
I want to create a word cube generator, similar to the one MrKindergarten designed. Basically, it's a cube with a rotating middle section, and words printed on the sides. Each side of the cube will have three letters. I'd like to be able to specify the four 3-letter words, the overall size of the cube, the gap between the inner cylinder and the outer frame, the font, the font size as a percentage of the cube size, and the depth of the text extrusion as a percentage of the cube size.

Specifically, the user should be able to define:

*   Four 3-letter words, using variables like `W1_L1`, `W1_L2`, `W1_L3` etc for each word/letter combination.
*   The overall `size` of the cube.
*   The `gap` between the rotating middle and the outer cube frame.
*   The `font` to use for the text.
*   The `fontSize` of the letters, as a percentage of the overall cube size.
*   The `depth` of the text extrusion, also as a percentage of the overall cube size.

The outer cube should be built with a central cube with two rectangular cutouts on each side for clearance. Then, the inner cylinder will rotate freely within it. The text for each word should be on the appropriate face, extruded inwards, with each letter being positioned in a row with a small space. The central cylinder should be the size so it can fit within the outer frame, with an additional, slightly larger cylinder used to hollow out the center during subtraction.

Could you generate the OpenSCAD code for this? I do not need any external libraries besides the basic OpenSCAD functionality.

[Assistant]
WordCube.scad:
```
//Word Cube Generator
//Inspired by Word Cubes by MrKindergarten
//http://www.thingiverse.com/thing:1554507

/*[Word 1]*/
W1_L1 = "B";
W1_L2 = "o";
W1_L3 = "x";
/*[Word 2]*/
W2_L1 = "Z";
W2_L2 = "i";
W2_L3 = "p";
/*[Word 3]*/
W3_L1 = "T";
W3_L2 = "e";
W3_L3 = "n";
/*[Word 4]*/
W4_L1 = "H";
W4_L2 = "u";
W4_L3 = "T";
/*[Cube Features]*/
size = 25.4;
gap = 2;

/*[Text Features]*/
font = "arial";
//percentage
fontSize = .50;
//percentage
depth = .02;//[.01:.01:.25]
union(){
  difference(){
    cube([size*3+gap*2,size,size], center = true);
    translate([-size/2-gap/2,0,0])
      cube([gap,size+1,size+1], center = true);
    translate([size/2+gap/2,0,0])
      cube([gap,size+1,size+1], center = true);
    rotate([0,90,0])
        cylinder(r = size/4+1, h = size+gap*2, center = true);
    //Word 1
    rotate([0,0,0])
    {
      translate([-size*(fontSize/2+1)-gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W1_L1), font = font, size = size*fontSize);
      translate([-size*(fontSize/2),-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W1_L2), font = font, size = size*fontSize);
      translate([size*(fontSize/2+.5)+gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W1_L3), font = font, size = size*fontSize);
    }
    //Word 2
    rotate([90,0,0])
    {
      translate([-size*(fontSize/2+1)-gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W2_L1), font = font, size = size*fontSize);
      translate([-size*(fontSize/2),-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W2_L2), font = font, size = size*fontSize);
      translate([size*(fontSize/2+.5)+gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W2_L3), font = font, size = size*fontSize);
    }
    //Word 3
    rotate([180,0,0])
    {
      translate([-size*(fontSize/2+1)-gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W3_L1), font = font, size = size*fontSize);
      translate([-size*(fontSize/2),-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W3_L2), font = font, size = size*fontSize);
      translate([size*(fontSize/2+.5)+gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W3_L3), font = font, size = size*fontSize);
    }
    //Word 4
    rotate([270,0,0])
    {
      translate([-size*(fontSize/2+1)-gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W4_L1), font = font, size = size*fontSize);
      translate([-size*(fontSize/2),-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W4_L2), font = font, size = size*fontSize);
      translate([size*(fontSize/2+.5)+gap,-size*fontSize/2,size/2+.01-size*depth])
        linear_extrude(size*depth)
          text(text = str(W4_L3), font = font, size = size*fontSize);
    }
  }
  rotate([0,90,0])
    translate([0,0,-size/2-gap])
      cylinder(r = size/4, h = size+gap*2);
}
```


[User]
I need help designing a parametric switch plate for a shutter switch, and I'd like the design to be in OpenSCAD. The plate should have two parts: a top part and a bottom part that fit together.

Here's what I'm envisioning for the design:

**General Structure:**

*   The plate will be rectangular, with separate width and height parameters.
*   Both the top and bottom parts will have a basic rectangular shape with rounded edges.
*   The top part will have a slightly different outer shape with chamfered edges.
*   Both parts will have screw holes and a rectangular cutout for a standard shutter switch.

**Parameters:**

I'd like to control the following aspects with parameters:

*   `plateWidth`: The overall width of the switch plate (in mm).
*   `plateHeight`: The overall height of the switch plate (in mm).
*   `thicknessTop`: The thickness of the top part (in mm).
*   `thicknessBottom`: The thickness of the bottom part (in mm).
*   `screwSpacing`: The distance between the centers of the screw holes (in mm).
*   `screwDiameter`: The diameter of the screw holes (in mm).
*   `screwHoleAxe`: A string parameter that accepts values of "Vertical" or "Horizontal," determining the orientation of the screw holes.
*   `switchWidth`: The width of the switch cutout (in mm).
*   `switchHeight`: The height of the switch cutout (in mm).
*   `printedObject`: A string parameter to choose which object to output: "Demo" (both parts together), "Top" (just the top part), or "Bottom" (just the bottom part).

**Specific Features:**

*   **Bottom Part:**
    *   A simple rectangular shape with slightly rounded corners.
    *   Two screw holes, the placement of which is controlled by `screwSpacing` and `screwHoleAxe`.
    *   A rectangular cutout for the switch centered on the plate.
*   **Top Part:**
    *   A rectangular shape, with chamfered outer edges formed using the `minkowski` function.
    *   Two screw holes, same as the bottom part.
    *   A rectangular cutout for the switch, same as the bottom part.
*   **Screw Holes:**
    *   The screw holes should be created with a cylinder that extends through both parts, and include a countersink effect (created by a cylinder with a larger diameter that only goes partway through).
    *   The screw hole placement should be controlled by the `screwHoleAxe` parameter, either vertically or horizontally.
*   **Output:**
    *   If `printedObject` is "Demo," then both parts should be displayed together, with the top part positioned on top of the bottom part. This is useful for visualizing the assembly.
    *   If `printedObject` is "Top" or "Bottom," then only the selected part should be rendered for STL export.

I think that covers everything. Can you generate the necessary OpenSCAD code? I don't need any external libraries beyond what's included in a standard OpenSCAD installation.

[Assistant]
switch-plate3.scad:
```
// CC-BY-SA Olivier Boyaval
// Swith plate for shutter
//
//    TOP part :
//           width
//    +-----------------+
//    !                 !
//    !        O        ! screw hole (if vertical)
//    !                 !
//    !    +-------+    !
//    !    !       !    !
//    !    ! switch!    !
//    !    ! hole  !    !  height
//    !    !       !    !
//    !    !       !    !
//    !    +-------+    !
//    !                 !
//    !        O        ! screw hole (if vertical)
//    !                 !
//    +-----------------+
//
//    BOTTOM part :
//    +-----------------+
//    ++               ++
//     !       O       !
//     !               !
//     !   +-------+   !
//     !   !       !   !
//     !   !       !   !
//     !   !       !   !
//     !   !       !   !
//     !   !       !   !
//     !   +-------+   !
//     !               !
//     !       O       !
//    ++               ++
//    +-----------------+
//
//Parameters for switch plate in 2 parts (top and bottom parts)
//measurements in mm

/* [Plate size] */
// Width (mm)
plateWidth              = 36;
// Height (mm)
plateHeight             = 74;

/* [Plate Thickness] */
// Top part (mm)
thicknessTop            = 3;
// Bottom part
thicknessBottom         = 4;

/* [Screw holes) */
// spacing beetwen center screw holes (mm)
screwSpacing            = 58;
//hole size (mm)
screwDiameter           = 3.5;
// Axe for screw holes
screwHoleAxe            = "Vertical"; //[Vertical,Horizontal]

/* [Switch hole size] */
// switch width (mm)
switchWidth             = 21;
// switch height (mm)
switchHeight            = 37;

/* [Output] */
// What object do you want in STL format
printedObject           = "Demo"; //[Demo,Top,Bottom]

// screw hole size and chamfer
module screwHole(diameter,depth) {
    union () {
        translate([0,0,-0.25]) cylinder(h=depth+0.5, d=diameter, $fn=20);
        translate([0,0,depth/2+0.25]) cylinder(h=depth/2, d1=diameter, d2=2*diameter, $fn=20);
    }
}

// bottom part (basic shape)
module basicShapeBottomPart (width,height,thickness) {
    union () {
        translate([-width/2+2,-height/2+2,0]) cube([width-4,height-4,thickness]);
        translate([-width/2+2,-height/2+2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([-width/2+2,+height/2-2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([+width/2-2,-height/2+2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([+width/2-2,+height/2-2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([-width/2+2,-height/2,0]) cube([width-4,4,thickness]);
        translate([-width/2+2,+height/2-4,0]) cube([width-4,4,thickness]);
        *translate([-width/2,-height/2+2,0]) cube([4,height-4,thickness]);
        *translate([+width/2-4,-height/2+2,0]) cube([4,height-4,thickness]);
    }
}

// Top part (basic shape)
module old_basicShapeTopPart (width,height,thickness) {
    chamfer=thickness*4;
intersection () {
intersection () {
    union () {
        translate([-width/2+2,-height/2+2,0]) cube([width-4,height-4,thickness]);
        translate([-width/2+2,-height/2+2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([-width/2+2,+height/2-2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([+width/2-2,-height/2+2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([+width/2-2,+height/2-2,0]) cylinder(h=thickness, d=4, $fn=20);
        translate([-width/2+2,-height/2,0]) cube([width-4,4,thickness]);
        translate([-width/2+2,+height/2-4,0]) cube([width-4,4,thickness]);
        translate([-width/2,-height/2+2,0]) cube([4,height-4,thickness]);
        translate([+width/2-4,-height/2+2,0]) cube([4,height-4,thickness]);
    }
    union () {
        translate([-width/2-2,+height/2-chamfer,0]) rotate([0,+90,0]) scale([1,2,1]) cylinder(h=width+4, d=chamfer, $fn=20);
        translate([-width/2-2,-height/2+chamfer,0]) rotate([0,+90,0]) scale([1,2,1]) cylinder(h=width+4, d=chamfer, $fn=20);
        translate([-width/2,-height/2+2,0]) cube([width,height-chamfer/2,chamfer/2]);
    }
}
    union () {
        translate([+width/2-chamfer,-height/2-2,0]) rotate([-90,-90,0]) scale([1,2,1]) cylinder(h=height+4, d=chamfer, $fn=20);
        translate([-width/2+chamfer,-height/2-2,0]) rotate([-90,-90,0]) scale([1,2,1]) cylinder(h=height+4, d=chamfer, $fn=20);
        translate([-width/2+2,-height/2,0]) cube([width-chamfer/2,height,chamfer/2]);
    }
}
}

module basicShapeTopPart(width,height,thickness) {
    $fn=50;
    intersection() {
        translate([-width/2+thickness,-height/2+thickness,0])
        minkowski()
        {
            cube([width-2*thickness,height-2*thickness,thickness]);
            sphere(r=thickness);
        }
        translate([-width/2-thickness,-height/2-thickness,0])
        cube([width+thickness,height+thickness,2*thickness]);
    }
}

module bottomPlate(width,height,thicknessI,thicknessS,screwD,screwE,widthI,heightI) {
    difference () {
        basicShapeBottomPart(width,height,thicknessI);
        union () {
            if (screwHoleAxe=="Vertical") {
                translate ([0,-screwE/2,0]) screwHole(screwD, thicknessI+thicknessS);
                translate ([0,+screwE/2,0]) screwHole(screwD, thicknessI+thicknessS);
                translate([-width/2+5,-(screwE-2*screwD)/2,-thicknessI/2]) cube([width-10,screwE-2*screwD,thicknessI]);
                translate([-width/2+screwD,-height/2+5,-thicknessI/2]) cube([width/2-2*screwD,height-10,thicknessI]);
                translate([screwD,-height/2+5,-thicknessI/2]) cube([width/2-2*screwD,height-10,thicknessI]);
            } else {
                translate ([-screwE/2,0,0]) screwHole(screwD, thicknessI+thicknessS);
                translate ([+screwE/2,0,0]) screwHole(screwD, thicknessI+thicknessS);
                translate([-(screwE-2*screwD)/2,-height/2+5,-thicknessI/2]) cube([screwE-2*screwD,height-10,thicknessI]);
               translate([-width/2+5,-height/2+screwD,-thicknessI/2])
    cube([width-10,height/2-2*screwD,thicknessI]);
                translate([-width/2+5,screwD,-thicknessI/2]) cube([width-10,height/2-2*screwD,thicknessI]);
            }

            // switch hole
            translate([-widthI/2,-heightI/2,-10]) cube([widthI,heightI,20]);
        }
    }
}

module topPlate(width,height,thicknessI,thicknessS,screwD,screwE,widthI,heightI) {
    difference () {
        basicShapeTopPart(width,height,thicknessS/2);
        union () {
            if (screwHoleAxe=="Vertical") {
                translate ([0,-screwE/2,-thicknessI]) screwHole(screwD, thicknessI+thicknessS);
                translate ([0,+screwE/2,-thicknessI]) screwHole(screwD, thicknessI+thicknessS);
            } else {
                translate ([-screwE/2,0,-thicknessI]) screwHole(screwD, thicknessI+thicknessS);
                translate ([+screwE/2,0,-thicknessI]) screwHole(screwD, thicknessI+thicknessS);
            }
            // switch hole
            translate([-widthI/2,-heightI/2,-10]) cube([widthI,heightI,20]);
        }
    }
}

//Main program
if (printedObject=="Demo") {
    color("Wheat") bottomPlate(plateWidth,plateHeight,thicknessBottom,thicknessTop,screwDiameter, screwSpacing,switchWidth,switchHeight);
    translate ([0,0,thicknessBottom+3]) color("Sienna") topPlate(plateWidth,plateHeight,thicknessBottom,thicknessTop,screwDiameter, screwSpacing,switchWidth,switchHeight);
}

if (printedObject=="Bottom") {
    // To render STL object of bottom plate part
    //translate ([0,0,thicknessBottom]) rotate([0,180,0])
    bottomPlate(plateWidth,plateHeight,thicknessBottom,thicknessTop,screwDiameter, screwSpacing,switchWidth,switchHeight);
}

if (printedObject=="Top") {
    // To render STL object of top plate part
    topPlate(plateWidth,plateHeight,thicknessBottom,thicknessTop,screwDiameter, screwSpacing,switchWidth,switchHeight);
}
```


[User]
Hey, I'm looking for an OpenSCAD design for a word cube that can display words in Braille. I saw a similar design that used regular text, but I'd like to adapt that for Braille, making the bumps on the cube represent Braille letters.

Here's what I'm thinking:

*   **Shape:** The main structure is a cube with a cylindrical cutout through the center. There should also be a small cut-out on the sides, creating the four separate panels/faces for the text.
*   **Text:** I need to display three-letter words on each face of the cube. The letters should be rendered as Braille dots.
*   **Customization:** I need the design to be parametric so I can easily change the words on each face of the cube, and the overall size of the cube, the size of the Braille dots, and the spacing between them.
*   **Braille Dot Placement:** I'm thinking the Braille characters should be placed horizontally and spaced out across the faces of the cube, with a gap between characters.
*   **Orientation bump:** There should be a small sphere located to the left of the top face. This will help a user know the starting face/orientation.
*   **Default Orientation:**  I'd like the starting or default orientation to be one where a single face is easily printable on a flat bed.

I don't have any code to start with, so I need you to generate a new design from scratch. I'm not sure how to represent the Braille dots for different letters, but I assume that's a manageable task. If you can implement the Braille letters as a look-up table, or something similar, that would be useful. And please keep in mind that the Braille should be raised from the surface.

[Assistant]
BrailleWordCube.scad:
```
//Word Cube Generator
//Inspired by Word Cubes by MrKindergarten
//http://www.thingiverse.com/thing:1554507

/*[Word 1]*/
W1_L1 = "b";
W1_L2 = "o";
W1_L3 = "x";
/*[Word 2]*/
W2_L1 = "z";
W2_L2 = "i";
W2_L3 = "p";
/*[Word 3]*/
W3_L1 = "t";
W3_L2 = "e";
W3_L3 = "n";
/*[Word 4]*/
W4_L1 = "h";
W4_L2 = "u";
W4_L3 = "t";
/*[Cube Features]*/
size = 25.4;
gap = 2;
topBump = true;//[true,false]
/*[Braille Text Size]*/
//percentage of cube
fontSize = .75;//[.05:.05:1]

rotate([0,90,0]){
  union(){
    if(topBump)
      translate([-size-gap,0,0])
        sphere(3);
    difference(){
      cube([size*2+gap*2,size,size], center = true);
      translate([-size/3-gap/2,0,0])
        cube([gap,size+1,size+1], center = true);
      translate([size/3+gap/2,0,0])
        cube([gap,size+1,size+1], center = true);
      rotate([0,90,0])
          cylinder(r = size/4+1, h = size+gap*2, center = true);
    }
    rotate([0,90,0])
      translate([0,0,-size/2-gap])
        cylinder(r = size/4, h = size+gap*2);
    //Word 1
    rotate([0,0,0])
    {
      translate([-size*2/3-gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W1_L1);
      translate([0,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W1_L2);
      translate([size*2/3+gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W1_L3);
    }
    //Word 2
    rotate([90,0,0])
    {
      translate([-size*2/3-gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W2_L1);
      translate([0,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W2_L2);
      translate([size*2/3+gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W2_L3);
    }
    //Word 3
    rotate([180,0,0])
    {
      translate([-size*2/3-gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W3_L1);
      translate([0,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W3_L2);
      translate([size*2/3+gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W3_L3);
    }
    //Word 4
    rotate([270,0,0])
    {
      translate([-size*2/3-gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W4_L1);
      translate([0,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W4_L2);
      translate([size*2/3+gap,0,size/2])
        scale(size*fontSize/8)
          brailConversion(W4_L3);
    }
  }

}
//All the braille text logic below...

braille_conversion_db =[
["CAPS",  [6]          ],
["a",   [1]            ],
["b",   [1, 2]         ],
["c",   [1, 4]         ],
["d",   [1, 4, 5]      ],
["e",   [1, 5]         ],
["f",   [1, 2, 4]      ],
["g",   [1, 2, 4, 5]   ],
["h",   [1, 2, 5]      ],
["i",   [2, 4]         ],
["j",   [2, 4, 5]      ],
["k",   [1, 3]         ],
["l",   [1, 2, 3]      ],
["m",   [1, 3, 4]      ],
["n",   [1, 3, 4, 5]   ],
["o",   [1, 3, 5,]     ],
["p",   [1, 2, 3, 4]   ],
["q",   [1, 2, 3, 4, 5]],
["r",   [1, 2, 3, 5]   ],
["s",   [2, 3, 4,]     ],
["t",   [2, 3, 4, 5]   ],
["u",   [1, 3, 6,]     ],
["v",   [1, 2, 3, 6]   ],
["w",   [2, 4, 5, 6]   ],
["x",   [1, 3, 4, 6]   ],
["y",   [1, 3, 4, 5, 6]],
["z",   [1, 3, 5, 6]   ],
["!",   [2, 3, 5,]     ],
[",",   [2]            ],
["-",   [3, 6]         ],
[".",   [2, 5, 6]      ],
["?",   [2, 3, 6]      ],
["#",   [3, 4, 5, 6]   ],
["0",   [2, 4, 5]      ],
["1",   [1]            ],
["2",   [1, 2]         ],
["3",   [1, 4]         ],
["4",   [1, 4, 5]      ],
["5",   [1, 5]         ],
["6",   [1, 2, 4]      ],
["7",   [1, 2, 4, 5]   ],
["8",   [1, 2, 5]      ],
["9",   [2, 4]         ]
];
$fn = 10;
module drawDot(pos = 0)
{
  if(pos == 1)
    translate([-1.5,3,0])
      sphere(center = true);
  else if(pos == 2)
    translate([-1.5,0,0])
      sphere(center = true);
  else if(pos == 3)
    translate([-1.5,-3,0])
      sphere(center = true);
  else if(pos == 4)
    translate([1.5,3,0])
      sphere(center = true);
  else if(pos == 5)
    translate([1.5,0,0])
      sphere(center = true);
  else if(pos == 6)
    translate([1.5,-3,0])
      sphere(center = true);
}
module brailConversion(char = " "){
  temp = search(char, braille_conversion_db)[0];
  for(dot = braille_conversion_db[temp][1]){
    drawDot(dot);
  }
}
```


[User]
Hey, I'm looking to create a more complete braille generator for OpenSCAD and I need some help. I've got a basic module that handles the letter conversions and draws the dots, but it's pretty bare-bones and I'm looking to make it more robust, and flexible for real-world use.

Specifically, I want to design a system that can:

1.  **Handle any input string:** The current system handles basic letters, numbers, and a few symbols but I'd like to handle all standard braille characters, including contractions (e.g. "and", "for", "the"). Basically I want a full, up-to-date braille conversion table.
2.  **Customizable spacing:** The spacing between braille cells should be adjustable, both horizontally and vertically. I also want to be able to control the spacing between the dots within each cell.
3.  **Different Dot Shapes:** I want to be able to easily change the dots from the current default spheres to other shapes like cylinders or even small squares or rounded rectangles. I also want to be able to control the size and height of the dots.
4.  **Embossing/Debossing Options:** I need an option to generate either raised (embossed) or recessed (debossed) braille dots into a substrate. So, the dots should either be added to or subtracted from the surface of the substrate object.
5.  **Text alignment options:** I'd like to be able to control whether the text is left-aligned, right-aligned or center-aligned.
6.  **Substrate Generation:** Ideally, I'd like a system that can either work in a simple "braille text" mode that just generates the braille characters by themselves, or generate the text as part of a substrate object (like a plaque, tag, or box).
7. **Importable/modular:** I need to be able to bring this into other designs. It needs to be something I can just include in other files.

I'm hoping that the system can be as parametric as possible so that I can tweak it for different project requirements. I don't really care about the efficiency of the code itself, but do want it to be clear, readable and easy to maintain.

Could you generate a set of OpenSCAD files that include these features? I don't need to incorporate any external libraries, and I'm happy to have it broken down into separate files for easier understanding. I'm not worried about code quality at the moment, but do want all the functionality. Let me know if you have any questions. Thanks!

[Assistant]
brailleModule.scad:
```
/*[Begin Variables]*/
word = "Example";
$fn = 6;

/*[hidden*/
braille_conversion_db =[
["CAPS",  [6]          ],
//Capital Letters
//todo still, make them put the cap before hand
["A",   [1]            ],
["B",   [1, 2]         ],
["C",   [1, 4]         ],
["D",   [1, 4, 5]      ],
["E",   [1, 5]         ],
["F",   [1, 2, 4]      ],
["G",   [1, 2, 4, 5]   ],
["H",   [1, 2, 5]      ],
["I",   [2, 4]         ],
["J",   [2, 4, 5]      ],
["K",   [1, 3]         ],
["L",   [1, 2, 3]      ],
["M",   [1, 3, 4]      ],
["N",   [1, 3, 4, 5]   ],
["O",   [1, 3, 5,]     ],
["P",   [1, 2, 3, 4]   ],
["Q",   [1, 2, 3, 4, 5]],
["R",   [1, 2, 3, 5]   ],
["S",   [2, 3, 4,]     ],
["T",   [2, 3, 4, 5]   ],
["U",   [1, 3, 6,]     ],
["V",   [1, 2, 3, 6]   ],
["W",   [2, 4, 5, 6]   ],
["X",   [1, 3, 4, 6]   ],
["Y",   [1, 3, 4, 5, 6]],
["Z",   [1, 3, 5, 6]   ],
//lowercase letters
["a",   [1]            ],
["b",   [1, 2]         ],
["c",   [1, 4]         ],
["d",   [1, 4, 5]      ],
["e",   [1, 5]         ],
["f",   [1, 2, 4]      ],
["g",   [1, 2, 4, 5]   ],
["h",   [1, 2, 5]      ],
["i",   [2, 4]         ],
["j",   [2, 4, 5]      ],
["k",   [1, 3]         ],
["l",   [1, 2, 3]      ],
["m",   [1, 3, 4]      ],
["n",   [1, 3, 4, 5]   ],
["o",   [1, 3, 5,]     ],
["p",   [1, 2, 3, 4]   ],
["q",   [1, 2, 3, 4, 5]],
["r",   [1, 2, 3, 5]   ],
["s",   [2, 3, 4,]     ],
["t",   [2, 3, 4, 5]   ],
["u",   [1, 3, 6,]     ],
["v",   [1, 2, 3, 6]   ],
["w",   [2, 4, 5, 6]   ],
["x",   [1, 3, 4, 6]   ],
["y",   [1, 3, 4, 5, 6]],
["z",   [1, 3, 5, 6]   ],
//Numbers
["0",   [2, 4, 5]      ],
["1",   [1]            ],
["2",   [1, 2]         ],
["3",   [1, 4]         ],
["4",   [1, 4, 5]      ],
["5",   [1, 5]         ],
["6",   [1, 2, 4]      ],
["7",   [1, 2, 4, 5]   ],
["8",   [1, 2, 5]      ],
["9",   [2, 4]         ],
//other symbols
["!",   [2, 3, 5,]     ],
[",",   [2]            ],
["-",   [3, 6]         ],
[".",   [2, 5, 6]      ],
["?",   [2, 3, 6]      ],
["#",   [3, 4, 5, 6]   ],
[" ",   []             ]
];

module drawDot(pos = 0)
{
  if(pos == 1)
    translate([-1.5,3,0])
      sphere(center = true);
  else if(pos == 2)
    translate([-1.5,0,0])
      sphere(center = true);
  else if(pos == 3)
    translate([-1.5,-3,0])
      sphere(center = true);
  else if(pos == 4)
    translate([1.5,3,0])
      sphere(center = true);
  else if(pos == 5)
    translate([1.5,0,0])
      sphere(center = true);
  else if(pos == 6)
    translate([1.5,-3,0])
      sphere(center = true);
}
module brailConversion(word = " "){
  temp = search(str(word), braille_conversion_db);
  echo(temp);
  for(num = [0:len(temp)]){
    translate([6*num,0,0])
    {
      for(dot = braille_conversion_db[temp[num]][1]){
        drawDot(dot);
      }
    }
  }
}

brailConversion(word);
```


[User]
I'd like to generate a customizable braided ring design using OpenSCAD. I've seen some cool ring designs that use a "sweeping" technique with hulls to create a braided look, and that's what I'm aiming for.

Here's what I'm looking for in terms of customization:

*   **Ring Sizing:** I need the ring size to be adjustable, and it needs to understand different sizing systems. Specifically, I want to be able to input ring sizes for the United States (including half sizes and quarter sizes if possible), United Kingdom (with lettered sizes), Europe (numerical), China (numerical), India (numerical), Spain (numerical), and Japan. Also, there needs to be a way to default to a diameter value when I put in any unrecognised sizes, and I may need the ability to specify the diameter manually, so that functionality should be in it too.
*   **Ring Height:** I want to be able to adjust the overall height of the ring.
*   **Ring Thickness:** I also want to be able to control the thickness of the individual strands of the braid.
*   **Braid Detail:** I'd like to be able to control the resolution of the braid, so that I can adjust it for slower processors if necessary. Something like a 'step' value that determines the density of the braid.
*   **Number of Braids:** I would like for the default to be 3 braids, but it would be good to have the option to add another braid or more for a thicker design.

The core of the design is based on a swept path using the `hull()` command, with multiple paths offset from each other. I'd prefer that all the calculations for placement happen in a module.

For output, I would prefer that there are three different colors of braid if possible, but it might be good to also have the option to output a single braid version for each color if someone only wanted to print one color.

I'm not familiar with any libraries so I don't know which ones would be best.

[Assistant]
BraidedRing.scad:
```
/* [Ring Maker] */
// this uses a lot of hull commands, and thus takes a while to load.

//bare in mind that printers often print weird, so it might scaled in your slicer or cleaned up

//BEGIN CUSTOMIZER VARIABLES
/*[Sizing]*/
Country="United States"; //[United States,Canada,Mexico,United Kingdom,Ireland,Australia,New Zealand,South Africa,Italy,Spain,Netherlands,Switzerland,India,China,South America,Japan,France,Germany,Austria,Belgium,Scandinavia]
//Format half sizes like that, regular sizes no spaces, always use capital letters if needed.
sizeValue= "7 1/4";

/* [Ring Options] */
//work in progress
ringheight=3;
//ditto
thickness=2;//[1:0.5:10]
//higher step takes more time but looks less blocky.
step = 10;//[.5:.5:20]
$fn=6;
//END CUSTOMIZER VARIABLES

/* [Hidden] */
US_Countries=["US","United States","Canada","Mexico"];
UK_Countries=["UK","United Kingdom","Ireland","Australia","New Zealand","South Africa"];
Spain_Countries=["ES","Italy","Spain","Netherlands","Switzerland"];
India_Countries=["IN","India"];
China_Countries=["CI","China","South America"];
Japan_Countries=["JP","Japan"];
ISO_Countries=["EU","France","Germany","Austria","Belgium","Scandinavia"];
//https://en.wikipedia.org/wiki/Ring_size

//USSizes_All =[12.04,12.24  ,12.45,12.65  ,12.85  ,13.06  ,13.26 ,13.46  ,13.67  ,13.87  ,14.07 ,14.27  ,14.48  ,14.68  ,14.88 ,15.09  ,15.29  ,15.49  ,15.7   ,15.9   ,16.1   ,16.31  ,16.51  ,16.71  ,16.92  ,17.12  ,17.32  ,17.53  ,17.73  ,17.93  ,18.14  ,18.34  ,18.54  ,18.75  ,18.95  ,19.15  ,19.35  ,19.56  ,19.76  ,19.96   ,20.17   ,20.37   ,20.57  ,20.78   ,20.98   ,21.18   ,21.39  ,21.59   ,21.79   ,22      ,22.2   ,22.4    ,22.61   ,22.81   ,23.01  ,23.22   ,23.42   ,23.62   ,23.83  ];
//USValues_All=["1/2","3/4"  ,"1"  ,"1 1/4","1 1/2","1 3/4","2"   ,"2 1/4","2 1/2","2 3/4","3"   ,"3 1/4","3 1/2","3 3/4","4"   ,"4 1/4","4 1/2","4 3/4","5"    ,"5 1/4","5 1/2","5 3/4","6"    ,"6 1/4","6 1/2","6 3/4","7"    ,"7 1/4","7 1/2","7 3/4","8"    ,"8 1/4","8 1/2","8 3/4","9"    ,"9 1/4","9 1/2","9 3/4","10"   ,"10 1/4","10 1/2","10 3/4","11"   ,"11 1/4","11 1/2","11 3/4","12"   ,"12 1/4","12 1/2","12 3/4","13"   ,"13 1/4","13 1/2","13 3/4","14"   ,"14 1/4","14 1/2","14 3/4","15"   ];
//UKValues_All=["A"  ,"A 1/2","B"  ,"B 1/2","C"    ,"C 1/2","D"   ,"D 1/2","E"    ,"E 1/2","F"   ,"F 1/2","G"    ,"G 1/2","H"   ,"H 1/2","I"    ,"J"    ,"J 1/2","K"    ,"K 1/2","L"    ,"L 1/2","M"    ,"M 1/2","N"    ,"N 1/2","O"    ,"O 1/2","P"    ,"P 1/2","Q"    ,"Q 1/2","R"    ,"R 1/2","S"    ,"S 1/2","T"    ,"T 1/2","U"     ,"U 1/2" ,"V"     ,"V 1/2","W"     ,"W 1/2" ,"X"     ,"X 1/2","Y"     ,"Z"  ];
//China_All   =[""   ,""     ,"1"  ,""     ,""     ,""     ,"2"   ,""     ,"3"    ,""     ,"4"   ,"5"    ,""     ,"6"    ,"7"   ,""     ,"8"    ,""     ,"9"    ,""     ,"10"   ,""     ,"11"   ,"12"   ,"13"   ,""     ,"14"   ,""     ,"15"   ,""     ,"16"   ,""     ,"17"   ,""     ,"18"   ,""     ,"19"   ,""     ,"20"   ,"21"    ,"22"    ,""      ,"23"   ,""      ,"24"    ,""      ,"25"   ,""      ,"26"    ,""      ,"27"   ,""      ,""      ,""      ,""     ,""      ,""      ,""      ,""     ];
//India_All   =[""   ,""     ,""   ,""     ,""     ,"1"    ,"2"   ,""     ,"3"    ,"4"    ,""    ,"5"    ,""     ,"6"    ,""    ,"7"    ,"8 1/2","9"    ,""     ,"10"   ,""     ,"11"   ,"12"   ,""     ,"13"   ,""     ,"14"   ,"15"   ,""     ,"16"   ,"17"   ,""     ,"18"   ,"19"   ,""     ,"20"   ,"21"   ,""     ,"22"   ,"23"    ,""      ,"24"    ,"25"   ,""      ,"26"    ,""      ,"27    ,"28"    ," "     ,"29"    ,"30"   ,""      ,"31"    ,"32"    ,""     ,"33"    ,""      ,"34"    ,"35"   ];
//Spain_All   =[""   ,""     ,""   ,""     ,"0.5"  ,"1"    ,"1.75","2.25" ,"3"    ,"3.5"  ,"4.25","4.75" ,"5.5"  ,"6"    ,"6.75","7.5"  ,"8"    ,"8.75" ,"9.25" ,"10"   ,"10.5" ,"11.25","11.75","12.5" ,"13.25","13.75","14.5" ,"15"   ,"15.75","16.25","17"   ,"17.5" ,"18.25","19"   ,"19.5" ,"20.25","20.75","21.5" ,"22"   ,"22.75" ,"23.25" ,"24"    ,"24.75","25.25" ,"26"    ,"26.5"  ,"27.25","27.75" ,"28.5"  ,"29"    ,"29.75","30.5"  ,"31"    ,"31.75" ,"32.25","33"    ,"33.5"  ,"34.25" ,"34.75"];
//source : https://www.kuberbox.com/blog/international-ring-size-conversion-chart/

if (search([Country],US_Countries)[0]>0)
{
  USValues_All=["1/2","3/4"   ,"1"  ,"1 1/4"  ,"1 1/2"  ,"1 3/4"  ,"2"     ,"2 1/4"  ,"2 1/2"  ,"2 3/4"  ,"3"     ,"3 1/4"  ,"3 1/2"  ,"3 3/4"  ,"4"     ,"4 1/4"  ,"4 1/2"  ,"4 3/4" ,"5"     ,"5 1/4"  ,"5 1/2" ,"5 3/4"  ,"6"      ,"6 1/4" ,"6 1/2"  ,"6 3/4"  ,"7"      ,"7 1/4"  ,"7 1/2"  ,"7 3/4" ,"8"      ,"8 1/4" ,"8 1/2"  ,"8 3/4" ,"9"     ,"9 1/4"  ,"9 1/2"  ,"9 3/4" ,"10"     ,"10 1/4"  ,"10 1/2"  ,"10 3/4" ,"11"     ,"11 1/4" ,"11 1/2"  ,"11 3/4" ,"12"     ,"12 1/4" ,"12 1/2"  ,"12 3/4"  ,"13"     ,"13 1/4"   ,"13 1/2"  ,"13 3/4" ,"14"     ,"14 1/4"  ,"14 1/2"  ,"14 3/4"  ,"15"      ];
  USSizes_All =[12.04,12.24   ,12.45,12.65    ,12.85    ,13.06    ,13.26   ,13.46    ,13.67    ,13.87    ,14.07   ,14.27    ,14.48    ,14.68    ,14.88   ,15.09    ,15.29    ,15.49   ,15.7    ,15.9     ,16.1    ,16.31    ,16.51    ,16.71   ,16.92    ,17.12    ,17.32    ,17.53    ,17.73    ,17.93   ,18.14    ,18.34   ,18.54    ,18.75   ,18.95   ,19.15    ,19.35    ,19.56   ,19.76    ,19.96     ,20.17     ,20.37    ,20.57    ,20.78    ,20.98     ,21.18    ,21.39    ,21.59    ,21.79     ,22        ,22.2     ,22.4       ,22.61     ,22.81    ,23.01    ,23.22     ,23.42     ,23.62     ,23.83     ];
  ring(USSizes_All[search([str(sizeValue)],USValues_All)[0]]);
}

else if (search([Country],ISO_Countries)[0]>0)
{
  EUValues_All =["44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71"];
  EUSizes_All  =[14.01,14.33,14.65,14.97,15.29,15.61,15.92,16.24,16.56,16.88,17.2,17.52,17.83,18.15,18.47,18.79,19.11,19.43,19.75,20.06,20.38,20.7,21.02,21.34,21.66,21.97,22.29,22.61];
  //source : http://www.cartier.fr/fr/services/le-guide-cartier/guide-des-tailles/guide-des-tailles-bagues/-10402.html
  ring(EUSizes_All[search([str(sizeValue)],EUValues_All)[0]]);
}

else if (search([Country],Spain_Countries)[0]>0)
{
  SpainValues_All =["0.5", "1"  , "1.75", "2.25", "3"  , "3.5", "4.25", "4.75", "5.5", "6"  , "6.75", "7.5", "8"  , "8.75", "9.25", "10", "10.5", "11.25", "11.75", "12.5", "13.25", "13.75", "14.5", "15" , "15.75", "16.25", "17" , "17.5", "18.25", "19" , "19.5", "20.25", "20.75", "21.5", "22" , "22.75", "23.25", "24" , "24.75", "25.25", "26" , "26.5", "27.25", "27.75", "28.5", "29", "29.75", "30.5", "31" , "31.75", "32.25", "33" , "33.5", "34.25", "34.75"];
  SpainSizes_All  =[12.85, 13.06, 13.26 , 13.46 , 13.67, 13.87, 14.07 , 14.27 , 14.48, 14.68, 14.88 , 15.09, 15.29, 15.49 , 15.7  , 15.9, 16.1  , 16.31  , 16.51  , 16.71 , 16.92  , 17.12  , 17.32 , 17.53, 17.73  , 17.93  , 18.14, 18.34 , 18.54  , 18.75, 18.95 , 19.15  , 19.35  , 19.56 , 19.76, 19.96  , 20.17  , 20.37, 20.57  , 20.78  , 20.98, 21.18 , 21.39  , 21.59  , 21.79 , 22  , 22.2   , 22.4  , 22.61, 22.81  , 23.01  , 23.22, 23.42 , 23.62  , 23.83  ];
  ring(SpainSizes_All[search([str(sizeValue)],SpainValues_All)[0]]);
}

else if (search([Country],UK_Countries)[0]>0)
{
  UKValues_All=["A"  , "A 1/2", "B"  , "B 1/2", "C"  , "C 1/2", "D"  , "D 1/2", "E"  , "E 1/2", "F"  , "F 1/2", "G"  , "G 1/2", "H"  , "H 1/2", "I"  , "J"  , "J 1/2", "K" , "K 1/2", "L"  , "L 1/2", "M"  , "M 1/2", "N"  , "N 1/2", "O"  , "O 1/2", "P"  , "P 1/2", "Q"  , "Q 1/2", "R"  , "R 1/2", "S"  , "S 1/2", "T"  , "T 1/2", "U"  , "U 1/2", "V"  , "V 1/2", "W"  , "W 1/2", "X"  , "X 1/2", "Y"  , "Z"  , "Z 1/2", "Z1", "Z2" , "Z3" , "Z4" ];
  UKSizes_All =[12.04, 12.24  , 12.45, 12.65  , 12.85, 13.06  , 13.26, 13.46  , 13.67, 13.87  , 14.07, 14.27  , 14.48, 14.68  , 14.88, 15.09  , 15.29, 15.49, 15.7   , 15.9, 16.1   , 16.31, 16.51  , 16.71, 16.92  , 17.12, 17.32  , 17.53, 17.73  , 17.93, 18.14  , 18.34, 18.54  , 18.75, 18.95  , 19.15, 19.35  , 19.56, 19.76  , 19.96, 20.17  , 20.37, 20.57  , 20.78, 20.98  , 21.18, 21.39  , 21.59, 21.79, 22     , 22.4, 22.81, 23.01, 23.42];
  ring(UKSizes_All[search([str(sizeValue)],UKValues_All)[0]]);
}

else if (search([Country],India_Countries)[0]>0)
{
  IndiaValues_Main   =["1"      ,"2"     ,"3"      ,"4"      ,"5"      ,"6"      ,"7"      ,"8 1/2"  ,"9"     ,"10"     ,"11"     ,"12"     ,"13"     ,"14"     ,"15"     ,"16"    ,"17"     ,"18"     ,"19"    ,"20"     ,"21"     ,"22"     ,"23"      ,"24"     ,"25"     ,"26"      ,"27"      ,"28"     ,"29"      ,"30"     ,"31"      ,"32"     ,"33"      ,"34"      ,"35"      ];
  IndiaSizes_Main    =[13.06    ,13.26   ,13.67    ,13.87    ,14.27    ,14.68    ,15.09    ,15.29    ,15.49   ,15.9     ,16.31    ,16.51    ,16.92    ,17.32    ,17.53    ,17.93   ,18.14    ,18.54    ,18.75   ,19.15    ,19.35    ,19.76    ,19.96     ,20.37    ,20.57    ,20.98     ,21.39    ,21.59    ,22        ,22.2     ,22.61     ,22.81    ,23.22     ,23.62     ,23.83     ];
  ring(IndiaSizes_Main[search([str(sizeValue)],IndiaValues_Main)[0]]);
}

else if (search([Country],China_Countries)[0]>0)
{
  ChinaValues_Main   =["1"  ,"2"     ,"3"      ,"4"     ,"5"      ,"6"      ,"7"     ,"8"      ,"9"     ,"10"    ,"11"     ,"12"    ,"13"     ,"14"     ,"15"     ,"16"     ,"17"     ,"18"    ,"19"     ,"20"     ,"21"      ,"22"      ,"23"     ,"24"      ,"25"    ,"26"      ,"27"     ];
  ChinaSizes_Main    =[12.45,13.26   ,13.67    ,14.07   ,14.27    ,14.68    ,14.88   ,15.29    ,15.7    ,16.1    ,16.51    ,16.71   ,16.92    ,17.32    ,17.73    ,18.14    ,18.54    ,18.95   ,19.35    ,19.76    ,19.96     ,20.17     ,20.57    ,20.98     ,21.39   ,21.79     ,22.2     ];
  ring(ChinaSizes_Main[search([str(sizeValue)],ChinaValues_Main)[0]]);
}

else if (search([Country],Japan_Countries)[0]>0)
{
  JapanSizes_All    =[12.37,13.21   ,13.61    ,14.05   ,14.36    ,14.56    ,14.86    ,15.27    ,15.7     ,16       ,16.51   ,16.92    ,17.35    ,17.75    ,18.19    ,18.53   ,18.89   ,19.41    ,19.84   ,20.02    ,19.96     ,20.68    ,21.08    ,21.49    ,21.89    ,22.33     ];
  JapanValues_All   =["1"  ,"2"     ,"3"      ,"4"     ,"5"      ,"6"      ,"7"      ,"8"      ,"9"      ,"10"     ,"12"    ,"13"     ,"14"     ,"15"     ,"16"    ,"17"     ,"18"    ,"19"     ,"20"     ,"21"      ,"22"    ,"23"     ,"24"     ,"25"     ,"26"     ,"27"  ];
  //JapanSource="http://www.ringsizes.co/"
  ring(JapanSizes_All[search([str(sizeValue)],JapanValues_All)[0]]);
}

else
  ring(sizeValue);

//The fun logic is below, Just due to thingiverse standards can't leave all that alone in a seperate file.

module sweepAlongPath(step  = 3, end = 360, current = 0, radi)
{
  //the function:
  hull(){
    rotate([0,90,current])
      linear_extrude(.0001)
        translate([ringheight*cos(3*current)*cos(3*current),
            radi+thickness/2+thickness/2*sin(12*current)])
          scale([ringheight/2,thickness])
            circle();
    rotate([0,90,current+step])
      linear_extrude(.0001)
        translate([ringheight*cos(3*(current+step))*cos(3*(current+step)),
            radi+thickness/2+thickness/2*sin(12*(current+step))])
            scale([ringheight/2,thickness])
              circle();
  }
  if(current+step < end)
    sweepAlongPath(step = step, end = end, current = current + step, radi = radi);
}

module ring(diameter){
  color([.9,0,0])
    sweepAlongPath(radi = diameter/2);
  color([0,.9,0])
    rotate([0,0,20])
      sweepAlongPath(radi = diameter/2);
  color([0,0,.9])
    rotate([0,0,20*2])
      sweepAlongPath(radi = diameter/2);
}
```


[User]
I need to generate a parametric OpenSCAD file to create a Schlage SC1 key. I have a reference model, `sc1.scad`, and some notes to go with it that can help guide the design. Here are some of the things I need the code to do:

1.  **Units:** The primary unit should be millimeters. Although the original design uses inches internally, I want the output to be metric and specified in millimeters. There should be a `mm()` function that handles any necessary conversions of imperial measurements used in the design's logic to metric.

2.  **Key Dimensions:** The code needs to define the following parameters: key thickness, overall key length, width, shoulder position, pin spacing, and depth increment. Also I need to be able to parametrically specify the depths of the 5 key cuts, which go from deepest cut (smallest distance from the bottom) at depth 9, to the shallowest cut at depth 0.

3.  **Key Shape:** The main body of the key should have rounded edges, with a handle/bow at the grip end of the key. The tip of the key blade should be chamfered or angled. There also needs to be a small hole in the handle for a keyring. Additionally, there needs to be channels cut into the key blade for printability, which will have some angles to them.

4.  **Key Cuts (Bitting):** I need a module called `bit()` that creates the cutting profile. Then, based on the depth parameters set for each cut (1 through 5), the `bit` module should be placed at the correct depths in the key body, with the first cut closest to the tip. The distances from the bottom of each cut should be as follows: 0=.335", 1=.320", 2=.305", 3=.290", 4=.275", 5=.260", 6=.245", 7=.230", 8=.215", 9=.200".

5.  **Print Orientation:** I need a variable to specify whether to rotate the key flat for printing or not.

I would like the code to be well-commented and use meaningful variable names, and I would prefer for it to be organized into modules.

[Assistant]
sc1.scad:
```
// Physical Keygen - by Nirav Patel <http://eclecti.cc>
//
// Generate a duplicate of a Schlage SC1 key by editing the last line of the file
// and entering in the key code of the lock.  If you don't know the key code,
// you can measure the key and compare the numbers at:
// http://web.archive.org/web/20050217020917fw_/http://dlaco.com/spacing/tips.htm
//
// This work is licensed under a Creative Commons Attribution 3.0 Unported License.

// Since the keys and locks I have were all designed in imperial units, the
// constants in this file will be defined in inches.  The mm function
// allows us to retain the proper size for exporting a metric STL.

// Thanks to Roidzo - Easy Key Copier for help with the Customizer comments http://www.thingiverse.com/thing:52363

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

//(this is just a reference table to help pick cuts below)
distance_from_cut_to_bottom_of_key = 0; // [0:0 = .335",1:1 = .320",2:2 = .305",3:3 = .290",4:4 = .275",5:5 = .260",6:6 = .245",7:7 = .230",8:8 = .215",9:9 = .200"]

//(cut closest to tip of key)
cut_1 = 5; //[0:9]

//
cut_2 = 7; //[0:9]

//
cut_3 = 4; //[0:9]

//
cut_4 = 2; //[0:9]

//(cut closest to grip/bow of key)
cut_5 = 1; //[0:9]

//(Rotate key flat for printing)
rotate_flat=0; //[0:No,1:Yes]

function mm(i) = i*25.4;

module rounded(size, r) {
    union() {
        translate([r, 0, 0]) cube([size[0]-2*r, size[1], size[2]]);
        translate([0, r, 0]) cube([size[0], size[1]-2*r, size[2]]);
        translate([r, r, 0]) cylinder(h=size[2], r=r);
        translate([size[0]-r, r, 0]) cylinder(h=size[2], r=r);
        translate([r, size[1]-r, 0]) cylinder(h=size[2], r=r);
        translate([size[0]-r, size[1]-r, 0]) cylinder(h=size[2], r=r);
    }
}

module bit() {
    w = mm(1/4);
    difference() {
        translate([-w/2, 0, 0]) cube([w, mm(1), w]);
        translate([-mm(7/256), 0, 0]) rotate([0, 0, 135]) cube([w, w, w]);
         translate([mm(7/256), 0, 0]) rotate([0, 0, -45]) cube([w, w, w]);
    }
}

// Schlage SC1 5 pin key.  The measurements are mostly guesses based on reverse
// engineering some keys I have and some publicly available information.
module sc1(bits) {
    // You may need to adjust these to fit your specific printer settings
    thickness = mm(0.080);
    length = mm(17/16);
    width = mm(.335);

    shoulder = mm(.231);
    pin_spacing = mm(.156);
    depth_inc = mm(.015);

    // A fudge factor.  Printing with your average RepRap, the bottom layer is
    // going to be squeezed larger than you want. You can make the pins
    // go slighly deeper by a fudge amount to make up for it if you aren't
    // adjusting for it elsewhere like Skeinforge or in your firmware.
    // 0.5mm works well for me.
    fudge = 0.5;

    // Handle size
    h_l = mm(1);
    h_w = mm(1);
    h_d = mm(1/16);
    difference() {
        // blade and key handle
        union() {
            translate([-h_l, -h_w/2 + width/2, 0]) rounded([h_l, h_w, thickness], mm(1/4));
            intersection() {
                // cut a little off the tip to avoid going too long
                cube([length - mm(1/64), width, thickness]);
                translate([0, mm(1/4), thickness*3/4]) rotate([0, 90, 0]) cylinder(h=length, r=mm(1/4), $fn=64);
            }
        }

        // chamfer the tip
        translate([length, mm(1/8), 0]) {
            rotate([0, 0, 45]) cube([10, 10, thickness]);
            rotate([0, 0, 225]) cube([10, 10, thickness]);
        }

        // put in a hole for keychain use
        translate([-h_l + mm(3/16), width/2, 0]) cylinder(h=thickness, r=mm(1/8));

        // cut the channels in the key.  designed more for printability than accuracy
        union() {
            translate([-h_d, mm(9/64), thickness/2]) rotate([62, 0, 0]) cube([length + h_d, width, width]);
            translate([-h_d, mm(7/64), thickness/2]) rotate([55, 0, 0]) cube([length + h_d, width, width]);
            translate([-h_d, mm(7/64), thickness/2]) cube([length + h_d, mm(1/32), width]);
        }

        translate([-h_d, width - mm(9/64), 0]) cube([length + h_d, width - (width - mm(10/64)), thickness/2]);
        translate([-h_d, width - mm(9/64), thickness/2]) rotate([-110, 0, 0]) cube([length + h_d, width, thickness/2]);

        intersection() {
            translate([-h_d, mm(1/32), thickness/2]) rotate([-118, 0, 0]) cube([length + h_d, width, width]);
            translate([-h_d, mm(1/32), thickness/2]) rotate([-110, 0, 0]) cube([length + h_d, width, width]);
        }

        // Do the actual bitting
        for (b = [0:4]) {
            translate([shoulder + b*pin_spacing, width - bits[b]*depth_inc - fudge, 0]) bit();
        }
    }
}

// This sample key goes to a lock that is sitting disassembled on my desk
// Flip the key over for easy printing
if (rotate_flat==1){
	rotate([180,0,0]) sc1([cut_5,cut_4,cut_3,cut_2,cut_1]);
} else {
	rotate([90,0,0]) sc1([cut_5,cut_4,cut_3,cut_2,cut_1]);
}

```


[User]
Hey, I'm looking to design a customizable ruler with some stencils. I've seen some examples, and I'd like it to be parametric so I can easily change the dimensions and stencil types.

Here's what I'm thinking:

*   **Overall Dimensions:** I need to be able to specify the ruler's width and length, both in inches. The recommended width is about 2.5 inches and the recommended length is 7 inches.
*   **Basic Shapes:** I'd like to include up to four basic shape stencils (circles, equilateral triangles, squares, pentagons, hexagons, heptagons, and octagons). For each shape, I need to be able to specify its type, x and y coordinates, and its size (which corresponds to the side length for polygons or the diameter for circles).
*   **Rectangles:** I want to be able to add up to two rectangular stencils. For each rectangle, I need to define its x and y coordinates, width, and length.
*   **Right Triangles:** It should support up to two right triangle stencils. I'll need to set their x and y coordinates, base, and height.
*   **Lines:** I also need up to two line stencils. I need to set the x and y coordinates, length, and angle for each.
*   **Cube Stencil:** I want an option to include a cube stencil. I need to specify its x and y coordinates. It should have internal shapes for drawing the isometric 3D representation of a cube as in the included example.
*   **Angle Stencils:** It should also allow for angle stencils, with the ability to position them on the ruler via x and y coordinates.
*   **Text Emboss:** Finally, I'd like to be able to emboss some custom text onto the ruler, with x and y position and the text to be specified.

All dimensions are in inches. It seems like it's going to be easiest to do this if the primary ruler object and the stencils use a difference() operation. And since the existing ruler uses a lot of translates, I think it might be easiest to just translate all of the stencils instead of rotating them.

[Assistant]
Ruler_Program_7.19.19.scad:
```
/* [Global] */
//Custom Ruler
//Written by Trevor Price <tprice2050@comcast.net>, February 2017
//Creative Commons - Attribution - Non-Commercial

/*You are free to:

Share — copy and redistribute the material in any medium or format
Adapt — remix, transform, and build upon the material
The licensor cannot revoke these freedoms as long as you follow the license terms.

Under the following terms:

Attribution — You must give appropriate credit, provide a link to the license,and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
NonCommercial — You may not use the material for commercial purposes.

*/

/* [Ruler Dimensions] */

//What total ruler dimension do you want? Notes: All of these dimensions are in Inches. Any dimensions of shapes that are not selected do not matter. The recommended width is 2.5 inches. The recommended length is 7 inches.

ruler_width = 2.5;//2.5 //[2:0.5:5.0]
ruler_length = 7;//7 //[4:0.5:12]

/* [Number of Basic Shapes] */
//How many basic shapes do you want? (Does not include rectangles,cube stencils,angle stencils, etc.)
number_of_basicShapes = 0;//[0:Zero,1:One,2:Two,3:Three,4:Four]

/* [Basic Shape 1] */
//What type of shape do you want for your first stencil?
type_of_basicShape_1 = 3 ;//[3:Equilateral Triangle,4:Square,5:Pentagon,6:Hexagon,7:Heptagon,8:Octagon,90:Circle]

//Pick the x and y coordinates of your first shape, and also its size. The size corresponds to each side length of the respective shape, or the diameter if it's a circle.

basicShape_1_x_position = .5;  //[.5:0.5:4.0]
basicShape_1_y_position = .5;  //[.5:0.5:11.5]
basicShape_1_size = .5;   //[.5:0.5:3]

/* [Basic Shape 2] */
//What type of shape do you want for your second stencil?
type_of_basicShape_2 = 3 ;//[3:Equilateral Triangle,4:Square,5:Pentagon,6:Hexagon,7:Heptagon,8:Octagon,90:Circle]

//Pick the x and y coordinates of your second shape, and also its size.

basicShape_2_x_position = .5;  //[.5:0.5:4.0]
basicShape_2_y_position = .5;  //[.5:0.5:11.5]
basicShape_2_size = .5;   //[.5:0.5:3]

/* [Basic Shape 3] */
//What type of shape do you want for your third stencil?
type_of_basicShape_3 = 3 ;//[3:Equilateral Triangle,4:Square,5:Pentagon,6:Hexagon,7:Heptagon,8:Octagon,90:Circle]

//Pick the x and y coordinates of your third shape, and also its size.

basicShape_3_x_position = .5;  //[.5:0.5:4.0]
basicShape_3_y_position = .5;  //[.5:0.5:11.5]
basicShape_3_size = .5;   //[.5:0.5:3]

/* [Basic Shape 4] */
//What type of shape do you want for your fourth stencil?
type_of_basicShape_4 = 3 ;//[3:Equilateral Triangle,4:Square,5:Pentagon,6:Hexagon,7:Heptagon,8:Octagon,90:Circle]

//Pick the x and y coordinates of your fourth shape, and also its size.

basicShape_4_x_position = .5;  //[.5:0.5:4.0]
basicShape_4_y_position = .5;  //[.5:0.5:11.5]
basicShape_4_size = .5;   //[.5:0.5:3]

/* [Number of Rectangles] */
//How many rectangular stencils do you want?
number_of_rectangles = 0;//[0:Zero,1:One,2:Two]

/* [Rectangle 1] */
//Pick the x and y coordinates of your first rectangle, and also its length/width.

rectangle_1_x_position = .5; //[.5:0.5:4.0]
rectangle_1_y_position = .5; //[.5:0.5:11.5]
rectangle_1_width = .5; //[.5:0.5:4.0]
rectangle_1_length = .5; //[.5:0.5:11.0]

/* [Rectangle 2] */
//Pick the x and y coordinates of your second rectangle, and also its length/width.

rectangle_2_x_position = .5; //[.5:0.5:4.0]
rectangle_2_y_position = .5; //[.5:0.5:11.5]
rectangle_2_width = .5; //[.5:0.5:4.0]
rectangle_2_length = .5; //[.5:0.5:11.0]

/* [Number of Right Triangles] */
//How many right triangle stencils do you want?
number_of_rightTriangles = 0;//[0:Zero,1:One,2:Two]

/* [Right Triangle 1] */
//Pick the x and y coordinates of your first right triangle, and also its base/height.

rightTriangle_1_x_position = .5; //[.5:0.5:4.0]
rightTriangle_1_y_position = .5; //[.5:0.5:11.5]
rightTriangle_1_height = .5; //[.5:0.5:3.0]
rightTriangle_1_base = .5; //[.5:0.5:5.0]

/* [Right Triangle 2] */
//Pick the x and y coordinates of your second right triangle, and also its base/height.

rightTriangle_2_x_position = .5; //[.5:0.5:4.0]
rightTriangle_2_y_position = .5; //[.5:0.5:11.5]
rightTriangle_2_height = .5; //[.5:0.5:4.0]
rightTriangle_2_base = .5; //[.5:0.5:11.0]

/* [Number of Line Stencils] */
//How many line stencils do you want?
number_of_lines = 0;//[0:Zero,1:One,2:Two]

/* [Line 1] */
//Pick the x and y coordinates of your first line stencil, and also its length/angle.

line_1_x_position = .5; //[.5:0.5:4.0]
line_1_y_position = .5; //[.5:0.5:11.5]
line_1_length = .5; //[.5:0.5:4.0]
line_1_angle = 0; //[90:-90,60:-60,45:-45,30:-30,0,-30:30,-45:45,-60:60,-90:90]

/* [Line 2] */
//Pick the x and y coordinates of your second line stencil, and also its length/angle.

line_2_x_position = .5; //[.5:0.5:4.0]
line_2_y_position = .5; //[.5:0.5:11.5]
line_2_length = .5; //[.5:0.5:4.0]
line_2_angle = 0; //[90:-90,60:-60,45:-45,30:-30,0,-30:30,-45:45,-60:60,-90:90]

/* [Cube Stencil] */
//Do you want a cube stencil?
cubeStencil_y_or_n = 0; //[0:No,1:Yes]
//Where do you want your cube stencil?

cubeStencil_x_position = .5; //[.5:0.25:4.0]
cubeStencil_y_position = .5; //[.5:0.25:11.5]

/* [Angle Stencil] */
//Do you want angle stencils?
angles_y_or_n = 0; //[0:No,1:Yes]
//Where do you want your cube stencil?

angles_x_position = .5; //[.5:0.25:4.0]
angles_y_position = .5; //[.5:0.25:11.5]

/* [Text Emboss] */
//Do you want to emboss some text?
text_y_or_n = 0; //[0:No,1:Yes]
//What words would you like to emboss?
custom_text = "Custom Ruler";
//Where do you want your embossed text?

text_x_position = .5; //[.5:0.25:4.0]
text_y_position = .5; //[.5:0.25:11.5]

drawRuler();

module drawRuler()
{
    difference()
    {
        union()
        {
         scale([25.4,25.4,25.4])  ruler();
         scale([25.4,25.4,25.4])  drawUnit();
          scale([25.4,25.4,25.4]) cubeStencil_support();
          scale([25.4,25.4,25.4]) angles2();
         scale([25.4,25.4,25.4])  text1();
        }
        union()
        {
          scale([25.4,25.4,25.4]) basicShapes();
          scale([25.4,25.4,25.4]) rectangles();
          scale([25.4,25.4,25.4]) rightTriangles();
         scale([25.4,25.4,25.4])  lines();
         scale([25.4,25.4,25.4])  angles();
          scale([25.4,25.4,25.4]) cubeStencil_cut();
        }
    }
}

module basicShapes()
{
    if(number_of_basicShapes == 1)
    {
        draw_basicShapes(type_of_basicShape_1,basicShape_1_x_position,basicShape_1_y_position,basicShape_1_size);
    }
    else if (number_of_basicShapes == 2)
    {
        draw_basicShapes(type_of_basicShape_1,basicShape_1_x_position,basicShape_1_y_position,basicShape_1_size);
        draw_basicShapes(type_of_basicShape_2,basicShape_2_x_position,basicShape_2_y_position,basicShape_2_size);
    }
    else if (number_of_basicShapes == 3)
    {
        draw_basicShapes(type_of_basicShape_1,basicShape_1_x_position,basicShape_1_y_position,basicShape_1_size);
        draw_basicShapes(type_of_basicShape_2,basicShape_2_x_position,basicShape_2_y_position,basicShape_2_size);
        draw_basicShapes(type_of_basicShape_3,basicShape_3_x_position,basicShape_3_y_position,basicShape_3_size);
    }

    else if (number_of_basicShapes == 4)
    {
        draw_basicShapes(type_of_basicShape_1,basicShape_1_x_position,basicShape_1_y_position,basicShape_1_size);
        draw_basicShapes(type_of_basicShape_2,basicShape_2_x_position,basicShape_2_y_position,basicShape_2_size);
        draw_basicShapes(type_of_basicShape_3,basicShape_3_x_position,basicShape_3_y_position,basicShape_3_size);
        draw_basicShapes(type_of_basicShape_4,basicShape_4_x_position,basicShape_4_y_position,basicShape_4_size);
    }
}

module rectangles()
{
    if(number_of_rectangles == 1)
    {
        draw_rectangles(rectangle_1_x_position,rectangle_1_y_position,rectangle_1_width,rectangle_1_length);
    }

    else if(number_of_rectangles == 2)
    {
        draw_rectangles(rectangle_1_x_position,rectangle_1_y_position,rectangle_1_width,rectangle_1_length);
        draw_rectangles(rectangle_2_x_position,rectangle_2_y_position,rectangle_2_width,rectangle_2_length);
    }
}

module lines()
{
    if(number_of_lines == 1)
    {

        rotated_line_1_x_position=line_1_x_position*cos(line_1_angle)-line_1_y_position*sin(line_1_angle);

        rotated_line_1_y_position=line_1_x_position*sin(line_1_angle) + line_1_y_position*cos(line_1_angle);

        rotate([0,0,-line_1_angle])
        draw_lines(rotated_line_1_x_position,rotated_line_1_y_position,line_1_length,line_1_angle);
    }

    else if(number_of_lines == 2)
    {
        rotated_line_1_x_position=line_1_x_position*cos(line_1_angle)-line_1_y_position*sin(line_1_angle);

        rotated_line_1_y_position=line_1_x_position*sin(line_1_angle) + line_1_y_position*cos(line_1_angle);

        rotate([0,0,-line_1_angle])
        draw_lines(rotated_line_1_x_position,rotated_line_1_y_position,line_1_length,line_1_angle);

        //Line 2

        rotated_line_2_x_position=line_2_x_position*cos(line_2_angle)-line_2_y_position*sin(line_2_angle);

        rotated_line_2_y_position=line_2_x_position*sin(line_2_angle) + line_2_y_position*cos(line_2_angle);

        rotate([0,0,-line_2_angle])
        draw_lines(rotated_line_2_x_position,rotated_line_2_y_position,line_2_length,line_2_angle);
    }
}

module rightTriangles()
{
    if(number_of_rightTriangles == 1)
    {
        draw_rightTriangles(rightTriangle_1_x_position,rightTriangle_1_y_position,rightTriangle_1_height,rightTriangle_1_base);
    }

    else if(number_of_rightTriangles == 2)
    {
        draw_rightTriangles(rightTriangle_1_x_position,rightTriangle_1_y_position,rightTriangle_1_height,rightTriangle_1_base);
        draw_rightTriangles(rightTriangle_2_x_position,rightTriangle_2_y_position,rightTriangle_2_height,rightTriangle_2_base);
    }
}

module cubeStencil_support()
{
    if(cubeStencil_y_or_n == 1)
    {
     draw_cubeStencil_support(cubeStencil_x_position,cubeStencil_y_position);
    }
}

module cubeStencil_cut()
{
    if(cubeStencil_y_or_n == 1)
    {
     draw_cubeStencil_cut(cubeStencil_x_position,cubeStencil_y_position);
    }
}

module angles()
{
    if(angles_y_or_n == 1)
    {
     draw_angles(angles_x_position,angles_y_position);
    }
}

module angles2()
{
    if(angles_y_or_n == 1)
    {
     draw_angles2(angles_x_position,angles_y_position);
    }
}

module text1()
{
    if(text_y_or_n == 1)
    {
     draw_text(text_x_position,text_y_position,custom_text);
    }
}

/* [Hidden] */
ruler_thickness=0.064015748;
tick_thickness=ruler_thickness+.02;
tick_width=.1;
tick_length=.03;
cube_thickness=ruler_thickness+.04;

module ruler()
{
    union()
    {
        cube([ruler_width,ruler_length,ruler_thickness]);
        color([1,0,0,1])
        translate([ruler_width-.03,-.0001,.0001]) cube([.0301,ruler_length+.0002,tick_thickness]);

        for(i=[1:ruler_length])
        {
            color([1,0,0,1])
            for(j=[1:10])
            {
               if (j==10 && i!=ruler_length) {
                   translate([ruler_width-tick_width*2.0,i-1+(j/10)-(tick_length/2),.0001])
                    cube([tick_width*2.0,tick_length,tick_thickness]);
                    drawInches(i,i);
               }
               if (j==5){
                  translate([ruler_width-tick_width*1.5,i-1+(j/10)-(tick_length/2),.0001])
               cube([tick_width*1.5,tick_length,tick_thickness]);
               }
               else if(j!=10){
                  translate([ruler_width-tick_width*1.0,i-1+(j/10)-(tick_length/2),.0001])
               cube([tick_width*1.0,tick_length,tick_thickness]);
               }
            }
        }
    }
}
module drawInches(sent_text,number)
{
    font = "Roboto";

    rotate([0,0,90])

    if(number<10)
    {
        translate([number-.095, -ruler_width + .23, .0001])
        linear_extrude(height = tick_thickness)
        text(text = str(sent_text), font = font, size = .22);
    }
    else
    {
        translate([number-.17, -ruler_width + .23, .0001])
        linear_extrude(height = tick_thickness)
        text(text = str(sent_text), font = font, size = .22);
    }
}
module drawUnit()
{
    rotate([0,0,90])
    color([1,0,0,1])
    translate([.17, -ruler_width + .23, .0001])
    linear_extrude(height = tick_thickness)
    text(text = "IN", font = "Roboto", size = .22);
}
module draw_basicShapes(fn_value,x,y,size)
{
        $fn=fn_value;
        translate([x,y,0])
        cylinder(ruler_thickness+2,d=size,center=true);
}
module draw_rectangles(rectangles_x,rectangles_y,rectangles_width,rectangles_length)
{
    translate([rectangles_x,rectangles_y,0])
    cube([rectangles_width,rectangles_length,ruler_thickness+2], center = true);
}

module draw_rightTriangles(rightTriangles_x,rightTriangles_y,rightTriangles_height,rightTriangles_base)
{
    polyhedron
        (
        points=[
        [rightTriangles_x + rightTriangles_height,rightTriangles_y,-10], //b
        [rightTriangles_x,rightTriangles_y,-10], //a
        [rightTriangles_x + rightTriangles_height,rightTriangles_y + rightTriangles_base,-10], //c
        [rightTriangles_x + rightTriangles_height,rightTriangles_y, ruler_thickness+2], //b
        [rightTriangles_x,rightTriangles_y,ruler_thickness+2], //a
        [rightTriangles_x + rightTriangles_height,rightTriangles_y + rightTriangles_base,ruler_thickness+2]] ,//c

        faces=[
        [0,2,1],
        [3,5,2,0],
        [5,4,1,2],
        [4,3,0,1],
        [3,4,5],]
        );
}

module draw_lines(lines_x,lines_y,lines_length,lines_angle)
{
    translate([lines_x,lines_y,-.0001])

    cube([.08,lines_length,ruler_thickness+2], center = false);

    $fn=90;
    translate([lines_x+.040,lines_y,0])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([lines_x+.040,lines_y+lines_length,0])
    cylinder(ruler_thickness+2,d=.08,center=true);
}

module draw_cubeStencil_cut(cube_x,cube_y)
{
    translate([cube_x+.04,cube_y+.04,-.0001])
    cube([1.00,1.00,ruler_thickness+2], center = false);

    translate([cube_x-0.25586614,cube_y+1.44318898,-.0001])
    cube([0.954055118,.08,ruler_thickness+2], center = false);

    translate([cube_x-.29586614,cube_y+0.563188976,-.0001])
    cube([.08,0.92011811,ruler_thickness+2], center = false);

    $fn=90;
    translate([cube_x-.2585,cube_y+1.486,0])
    cylinder(ruler_thickness+2,d=.075,center=true);

    translate([cube_x-.08,cube_y+1.095,-.0001])
    rotate([0,0,32])
    cube([.08,0.4,ruler_thickness+2], center = false);

    translate([cube_x-.047,cube_y+1.118,0])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([cube_x+.92,cube_y+1.086,-.0001])
    rotate([0,0,36.5])
    cube([.08,.48,ruler_thickness+2], center = false);

    translate([cube_x-.084,cube_y+.23,-.0001])
    rotate([0,0,32.4])
    cube([.08,.396,ruler_thickness+2], center = false);

        //Top Left Triangle
        polyhedron
        (
        points=[
        [cube_x-.084,cube_y+.230,-.1], //b
        [cube_x-.0165,cube_y+.273,-.1], //a
        [cube_x-.0165,cube_y+.128,-.1], //c
        [cube_x-.084,cube_y+.230,ruler_thickness+2], //b
        [cube_x-.0165,cube_y+.273,ruler_thickness+2], //a
        [cube_x-.0165,cube_y+.128,ruler_thickness+2]] ,//c

        faces=[
        [0,2,1],
        [3,5,2,0],
        [5,4,1,2],
        [4,3,0,1],
        [3,4,5],]
        );

        //Bottom Right Triangle

  polyhedron
        (
        points=[
        [cube_x+.920,cube_y+1.086,-.1], //b
        [cube_x+.9844,cube_y+1.134,-.1], //a
        [cube_x+1.017,cube_y+1.086,-.1], //c
        [cube_x+.920,cube_y+1.086,ruler_thickness+2], //b
        [cube_x+.9844,cube_y+1.134,ruler_thickness+2], //a
        [cube_x+1.017,cube_y+1.086,ruler_thickness+2]] ,//c

        faces=[
        [0,2,1],
        [3,5,2,0],
        [5,4,1,2],
        [4,3,0,1],
        [3,4,5],]
        );

}

module draw_cubeStencil_support(cube_x,cube_y)
{
    color([1,0,0,1])
    translate([cube_x,cube_y,.0001])
    cube([1.08,1.08,cube_thickness], center = false);
}

module draw_angles(angles_x,angles_y)
{
    translate([angles_x,angles_y,-.0001])
    cube([.5,.08,cube_thickness], center = false);

    $fn=90;
    translate([angles_x+.5,angles_y+.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x+.5,angles_y+.54,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x,angles_y+.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x+.029,angles_y+.012,-.0001])
    rotate([0,0,45])
    cube([.5/sin(45),.08,cube_thickness], center = false);

    translate([angles_x+.53,angles_y +.567,-.0001])
    rotate([0,0,135])
    cube([.5/sin(45),.08,cube_thickness], center = false);

    translate([angles_x,angles_y+1.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x-.83,angles_y,-.0001])
    cube([.5,.08,cube_thickness], center = false);

    translate([angles_x-.33,angles_y+.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x-.83,angles_y+.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x-.80,angles_y+.011,-.0001])
    rotate([0,0,60])
    cube([.6,.08,cube_thickness], center = false);

    translate([angles_x-.535,angles_y+.51+.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x-.95,angles_y+.15,-.0001])
    rotate([0,0,60])
    cube([.54,.08,cube_thickness], center = false);

    translate([angles_x-.7134,angles_y+.6+.04,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x-.9846,angles_y+.17,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);

    translate([angles_x-.9445,angles_y+.165,-.0001])
    rotate([0,0,90])
    cube([.49,.08,cube_thickness], center = false);

    translate([angles_x-.9845,angles_y+.65,-.0001])
    cylinder(ruler_thickness+2,d=.08,center=true);
}

module draw_angles2(angles_x,angles_y)
{

    color([1,0,0,1])
    translate([angles_x+.65,angles_y+.12, .0001])
    rotate([0,0,90])
    linear_extrude(height = tick_thickness)
    text(text = "45", font = "Roboto", size = .18);

    color([1,0,0,1])
    translate([angles_x+.25,angles_y+.4, .0001])
    rotate([0,0,90])
    linear_extrude(height = tick_thickness)
    text(text = "90", font = "Roboto", size = .18);

    color([1,0,0,1])
    translate([angles_x-.35,angles_y+.12, .0001])
    rotate([0,0,90])
    linear_extrude(height = tick_thickness)
    text(text = "60", font = "Roboto", size = .18);

    color([1,0,0,1])
    translate([angles_x-.75,angles_y+.7, .0001])
    rotate([0,0,90])
    linear_extrude(height = tick_thickness)
    text(text = "30", font = "Roboto", size = .18);

}

module draw_text(text_x,text_y,custom_text)
{
    color([1,0,0,1])
    translate([text_x,text_y, .0001])
    rotate([0,0,90])
    linear_extrude(height = tick_thickness)
    text(text = custom_text, font = "Roboto", size = .28);
}

```


[User]
Hey, I'm trying to make a cool 3D model in OpenSCAD, and I'm struggling a bit with the math. I'm aiming for a shape that looks like a torus that has been inverted and then knotted. I've seen some examples online using sphere inversion and I'd like to try that myself.

Here’s what I'm picturing and the parameters I'd like to be able to control:

*   **Basic Shape:** The starting point is a torus. I need to be able to adjust the large radius (R) and the small radius (r) of the torus.
*   **Knotting:** The knotting effect is achieved by winding the torus around itself a certain number of times. I want a `windings` parameter for the number of windings (or revolutions) the tube makes, and `revs` for how many times it goes around the z-axis, and finally a `direction` parameter to control the direction of the spiral.
*   **Tube Thickness:** The thickness of the resulting "tube" should be adjustable using a `fattness` parameter.
*   **Sphere Inversion:** The core of the design should be sphere inversion.  I need to control the center of the inversion sphere with parameters `x0`, `y0`, and `z0`.  I also need a `k` parameter for the radius of the inversion sphere.
*   **Resolution:** I'd like to control the smoothness of the tube with a `resolution` parameter, controlling the number of points used to draw it.
*   **Libraries:** I'm not using any special libraries at the moment.

I'm not sure how to combine all these things, but I think it might work by generating a set of points along a parametric torus curve, applying the sphere inversion to them, and then using `hull` to create a solid shape. Can you generate an OpenSCAD file or files that does this, and takes all these parameters as user adjustable variables?

[Assistant]
customizable_torus_inverter.scad:
```

//number of windings around the donut
windings = 0; //[0:1]

//number of revolutions around the z axis
revs = 6; //[2:12]

//size of the spheres(fattness of the tubes)
fattness = 2; //[1:4]

//x coordinate of the inversion
x0 = .5; //[.5, 0]

//y coordinate of the inversion
y0 = .5; //[.5, 0]

//z coordinate of the inversion
z0 = .5; //[.5, 0]

//radius of the inversion
k = 4; //[3, 4]

//large radius
R = 9; //[9, 7]

//small radius
r = 6; //[6, 7]

//tube resolution
resolution = 10; //[10, 15]

//spiral direction
direction = 1; //[1, -1]

for(t=[0:360*revs])
{
	hull()
	{
		translate([x0 + k*k*(cos(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - x0)/(pow((cos(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - x0), 2)+pow((sin(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - y0), 2)+pow((r*sin(360+direction*(windings+1/revs)*t)-z0), 2)),
				   y0 + k*k*(sin(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - y0)/(pow((cos(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - x0), 2)+pow((sin(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - y0), 2)+pow((r*sin(360+direction*(windings+1/revs)*t)-z0), 2)),
				   z0 + k*k*(r*sin(360+direction*(windings+1/revs)*t) - z0)/(pow((cos(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - x0), 2)+pow((sin(t)*(R-r*cos(360+direction*(windings+1/revs)*t)) - y0), 2)+pow((r*sin(360+direction*(windings+1/revs)*t)-z0), 2))])
		{
			sphere($fn=resolution, .1*fattness, true);
		}
		translate([x0 + k*k*(cos(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - x0)/(pow((cos(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - x0), 2)+pow((sin(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - y0), 2)+pow((r*sin(360+direction*(windings+1/revs)*(t+1))-z0), 2)),
				   y0 + k*k*(sin(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - y0)/(pow((cos(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - x0), 2)+pow((sin(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - y0), 2)+pow((r*sin(360+direction*(windings+1/revs)*(t+1))-z0), 2)),
				   z0 + k*k*(r*sin(360+direction*(windings+1/revs)*(t+1)) - z0)/(pow((cos(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - x0), 2)+pow((sin(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))) - y0), 2)+pow((r*sin(360+direction*(windings+1/revs)*(t+1))-z0), 2))])
		{
			sphere($fn=resolution, .1*fattness, true);
		}
	}
}
```