[User]
I'm looking to create a parametric design for a coin, with a focus on generating intricate, flowing patterns on its surface. The inspiration is drawn from magnetic field curves, similar to what's seen in the research papers you can find on "Magnetic Curves: Curvature-Controlled Aesthetic Curves" and "Computer-generated floral ornament based on magnetic curves." I'd like to achieve this using OpenSCAD, of course.

Here's a breakdown of the desired features and parameters:

**Core Coin Structure:**

*   **Base Shape:** The coin should be a circular disk.
*   **Diameter:** The diameter (or what I've been calling "plate") should be a parameter I can easily adjust.
*   **Thickness:** The coin should have a defined thickness, also adjustable as a parameter.
*   **Multiple Layers:** I'd like the coin to have at least two distinct layers: a base layer that is mostly solid, and a top layer with the patterns. This might need to be done through separate but related processes in SCAD.
*   **Slight Variation:** I would like each layer to be scaled down by a small amount to give each layer a slightly smaller circumference.

**Pattern Generation:**

*   **Lorentz-like Curves:** The patterns should be generated by simulating a particle moving through a magnetic field. This involves a moving particle influenced by a vector field (or force), which changes its direction and speed over time (what I've been calling "dir").
*   **Spiral Trajectory:** The overall look should be spiral-like, starting from a point and expanding outwards.
*   **Variable Force:** The "force" acting on the particle should be a combination of a base vector and a changing "magnetic" force (my "magfield").
*   **Calligraphic Effect:** I would like each point in the "lines" that represent the moving particle, to be calligraphic - essentially, a thin line will be more of a curved, slightly widened shape like that from a brush or pen. I should be able to adjust the calligraphic effect and even the slant.
*   **Multiple Curves:** I want the ability to generate multiple curves on the coin's surface at different angles.
*   **Coloring:** Some of the curves should be one color and some another color, which will need to be adjustable as parameters.
*   **Randomization:** A lot of the variables should be randomized using a seed value to create a variety of possible designs from the same code.
*   **Scaling:** There should be a general parameter to control the overall size of the pattern generation.
*   **Layer Height:** All of the "lines" from the pattern generation should be at slightly different heights above the base layer of the coin.

**Key Parameters I want to control:**

*   `Seed` (integer) - For random number generation.
*   `plate` (number) - Diameter of the coin.
*   `thickness` (number) - Thickness of the coin.
*   `Calligraphic` (number) - Controls the width of the "brush stroke" effect.
*   `CalligraphicSlant` (number) - Controls the angle of the calligraphic effect.
*   `Oscale` (2D vector) - Controls the overall scaling of the patterns
*   `golds` (array of strings) - Controls the two colors used.

**Modules**

*   I want a `spiral` module that defines the generation of the curves based on the lorentz-like force.
*    I want a `line` module that builds the calligraphic effect.
*  I want a `rnd` function that returns a random value between two parameters
* I want a `len3` function to calculate the length of a 2D or 3D vector.

I am aware that I may not be able to get the exact same result I created in my example as this was from the perspective of being a developer, but I'm hoping for a parametric approach that can produce a variety of interesting designs based on the same underlying principles.

Could you please generate the necessary OpenSCAD file(s) to achieve this design? I do not need any external libraries or include files for this design.

[Assistant]
Coin2.scad:
```
Seed=83244815397;//
Calligraphic=2;//
CalligraphicSlant=45;//
Oscale=[1,1];//
plate=45;//
thickness=3;
/*[Hidden]*/
dir=[rnd(-0,-0.5,Seed-435),0.5,0]*10;
golds=["DarkGoldenrod","Goldenrod"];
difference(){
color("DarkGoldenrod")translate([0,0,-thickness]) linear_extrude(height = thickness +1,  convexity = 10, scale=0.97,$fn=40)offset(r=3, chamfer=true)offset(r=-3, chamfer=false) circle(plate,center=true);
color("Goldenrod")mirror([0,0,1])translate([0,0,-1.99]) linear_extrude(height = 2,  convexity = 10, scale=0.93,$fn=40)offset(delta=3, chamfer=true)offset(r=-6, chamfer=false) circle(plate,center=true);
}

up=[0,0,-2];
intersection(){
color("DarkGoldenrod")translate([0,0,-thickness]) linear_extrude(height = thickness +1,  convexity = 10, scale=0.97,$fn=40)offset(r=3, chamfer=true)offset(r=-3, chamfer=false) circle(plate,center=true);
scale([Oscale[0],Oscale[1],1]){
// first run
 for(t=[rnd(-40,-10,Seed+421):rnd(15,20,Seed+763):rnd(10,60,Seed+432)]){
rotate([0,0,000])translate([0,0,-rnd(0.2,0.0,Seed+123+t)])color(golds[round(rnd(1,0,Seed-t))])spiral([rnd(plate*0.3,0,Seed),0,0],dir,t);
rotate([0,0,120])translate([0,0,-rnd(0.2,0.0,Seed+123+t)])color(golds[round(rnd(1,0,Seed-t))])spiral([rnd(plate*0.3,0,Seed),0,0],dir,t);
rotate([0,0,240])translate([0,0,-rnd(0.2,0.0,Seed+123+t)])color(golds[round(rnd(1,0,Seed-t))])spiral([rnd(plate*0.3,0,Seed),0,0],dir,t);
}
//second run
dir2=[-0.5,-0.1-rnd(0.7,0,Seed+344),0]*10;
 { for(t=[rnd(-40,-10,Seed):rnd(15,20,Seed+548):rnd(10,60,Seed+556)]){
translate([0,0,-rnd(0.1,0.0,Seed+123+t)])color(golds[round(rnd(1,0,Seed+t))])rotate([0,0,60])spiral([rnd(plate*0.3,0,Seed),0,0],dir2,t);
translate([0,0,-rnd(0.1,0.0,Seed+123+t)])color(golds[round(rnd(1,0,Seed+t))])rotate([0,0,180])spiral([rnd(plate*0.3,0,Seed),0,0],dir2,t);
translate([0,0,-rnd(0.1,0.0,Seed+123+t)])color(golds[round(rnd(1,0,Seed+t))])rotate([0,0,300])spiral([rnd(plate*0.3,0,Seed),0,0],dir2,t);
}}
}
}
// modules
module spiral(op,dir,t, i=0){
magfield=[0,0,cos(i*t)*3];
ndir=dir*0.85+cross(dir,magfield)*0.1;// blend dirction with force ( nonscientific)
np=op+ndir;
line(op,np);
if(i<25&&len3(np)<plate*0.8){spiral(np,ndir,t,i+1);}

}

module line(p1, p2) {
  hull() {
    translate(p1) rotate([0,0,-CalligraphicSlant]) scale([1/Calligraphic,Calligraphic,1])sphere(1);
    translate(p2) rotate([0,0,-CalligraphicSlant])scale([1/Calligraphic,Calligraphic,1])sphere(1);
  }
}
function rnd(a = 0, b = 1,S) = (rands(min(a, b), max(a, b), 1,S)[0]);
function len3(v)=len(v)==2?sqrt(pow(v[0],2)+pow(v[1],2)):sqrt(pow(v[0],2)+pow(v[1],2)+pow(v[2],2));

```


[User]
Okay, I'm looking to create a customizable ornamental coin generator in OpenSCAD. I have some initial ideas and a basic structure in mind, but I need your help to create a parametric design that’s flexible and visually interesting.

Here's the general concept: The coin will be based on a circular base plate, with a couple of layers of decorations on top. These decorations should be generated using a combination of sine wave-based curves and radial repetitions. The design should allow for a lot of variability through parameters, including random seed based generation.

Here are the detailed requirements:

**Base Shape:**
*   The coin will start with a circular base plate.
*   The base plate should have a thickness parameter.
*  I would like to have the option for the baseplate to have a couple of simple chamfer and offset features.

**First Decoration Layer:**
*   This layer will be built using a series of points around a circle.
*   The radial position of each point should be affected by sine waves to create an undulating curve. Specifically, it should be based off of a `baser` parameter, with additional sine waves that are added to that.
*   Parameters should allow the user to control amplitude, frequency (number of repetitions), and phase of each sine wave. I would like to control multiple individual sine waves that are added together to influence the radial position.
*   These points should be connected to form a solid shape. The connecting method should be a `hull` primitive.
*   There should be a `step` parameter to control how many points are created along the circle.
*    There should be overall phase control on the curve generation for further control.

**Second Decoration Layer:**
*   This layer will be a repetition of the first layer.
*    There should be the ability to have the first layer of curves to be applied to multiple points on the baseplate, using symmetry transformations.
*   The symmetry transformations should be controlled by:
  *   A radial symmetry parameter to control how many repetitions
  *    A mirror symmetry parameter that can either add or not add a mirror transformation. This should be controlled by a parameter.
 *   Both symmetry parameters should be able to go to `0` to disable them.
*   Each repeated shape should be independently scaled and rotated for further variability. The scaling should allow for non-uniform scaling by use of two separate parameters.

**General Parameters and Features:**
*   **Seed:** The entire design should be generated based on a random seed so that each seed produces a unique design. There should be a toggle to use a specific seed or not.
*   **Random Number Generation:** I would like the random numbers to be generated by `rands()` so that the seed generation is consistent. Use a simple rnd() function for ease of use.
*   **Color:**  I would like to color the coin base and the decorative elements with contrasting colours. I will manually define these, so I don't need a parametric color generation.
*   **Units:** I'm assuming the design will use mm but please specify this explicitly in the code, where it's defined.

**Output:**

*   The final output should be a 3D printable model.

**Libraries:**

*   No external libraries are needed for this design. Everything can be built with standard OpenSCAD primitives and language constructs.

This is all I can think of for now. The goal is to have a parametric design that can create a wide variety of coin-like shapes, all unique based on the seed. Please let me know if anything is unclear and I'll try to be more descriptive.

[Assistant]
Shapecoin.scad:
```
Seed=6547648057;//
Seeded=0;//[1,0]

Oscale=[0.9,0.9];//
plate=45;//
thickness=5;
/*[Hidden]*/
baser=rnd(Seed+1,1.4,2);
phase=rnd(Seed+2,360);

mag1=rnd(Seed+3,6)*baser;
rep1=round(rnd(Seed+4,0,8));
ophase1=rnd(Seed+5,360);

mag2=rnd(Seed+6,6)*baser;
rep2=round(rnd(Seed+7,3,10));
ophase2=rnd(Seed+8,360);

phase0=rnd(Seed+9,360);
r0=rnd(Seed+10,0,1);
phase1=rnd(Seed+1,360);
r1=rnd(Seed+11,0,1)/2;
phase2=rnd(Seed+1,360);
r2=rnd(Seed+12,0,1)/3;
phase3=rnd(Seed+1,360);
r3=rnd(Seed+13,0,1)/4;
phase8=rnd(Seed+1,360);
r8=rnd(Seed+14,0,1)/8;
rsym1=round(rnd(Seed+15,1,8));
rsym2=round(rnd(Seed+16,0,rnd(Seed+16,16)));
msym1=round(rnd(Seed+17,0,rsym1));
msym2=round(rnd(Seed+18,0,rsym2));
rsum=baser+r0+r1+r2+r3+r8;
step=24*rsym1;
d=rnd(Seed+19,360);
e=rnd(Seed+20,-0.1,0.1);

dir=[rnd(Seed+21,-0,-0.5,Seed-23),0.5,0]*10;
golds=["DarkGoldenrod","Goldenrod"];
difference(){
color("DarkGoldenrod")translate([0,0,-thickness]) linear_extrude(height = thickness +1,  convexity = 10, scale=0.97,$fn=50)offset(r=3, chamfer=true)offset(r=-3, chamfer=false) circle(plate,center=true);
color("Goldenrod")mirror([0,0,1])translate([0,0,-1.99]) linear_extrude(height = 2,  convexity = 10, scale=0.93,$fn=50)offset(delta=3, chamfer=true)offset(r=-6, chamfer=false) circle(plate,center=true);
}

up=[0,0,-2];
intersection(){
color("DarkGoldenrod")translate([0,0,-thickness]) linear_extrude(height = thickness +1,  convexity = 10, scale=0.97,$fn=50)offset(r=3, chamfer=true)offset(r=-3, chamfer=false) circle(plate,center=true);

color("DarkGoldenrod")translate([0,0,0]) scale([Oscale[0]*plate,Oscale[1]*plate,30]) symmetries(rsym1,msym1){translate([-0.7+0.7/rsym1,0,0])rotate([0,0,d])scale([0.3+0.7/rsym1,e+0.3+0.7/rsym1,1])symmetries(rsym2,msym2){it ();};
}
}
//symmetries(rsym2,msym2){it ();}
module symmetries(rsym,msym){
for(j=[0:360/rsym:360])rotate([0,0,j]){
intersection(){
if(msym==0) children ();else union(){
    intersection(){
    children ();
    translate([-1,0,-0.05])scale([2,1,0.2])cube(1);
    }
    mirror([0,1,0]) intersection(){
    children ();
    translate([-1,0,-0.05])scale([2,1,0.2])cube(1);
    }}

if(rsym>1){intersection(){
rotate ([0,0,(360/rsym)*0.5])translate([-1,0,-0.05])scale([2,1,0.2])cube(1);
mirror([0,1,0])rotate ([0,0,(360/rsym)*0.5])translate([-1,0,-0.05])scale([2,1,0.2])cube(1);
}}else {scale([1,1,0.2])cube(2,center=true);
}
}}}

module it(){
cube(0.03,$fn=10);
for(i=[0:step:360]){hull(){
theta = i+ sin((i+ophase1)*rep1)*mag1+ sin((i+ophase2)*rep2)*mag2;
translate([
sin(theta+phase)*(baser+sin((i+phase0))*r0 +sin((i+phase1)*2)*r1+sin((i+phase2)*3)*r2+sin((i+phase3)*4)*r3+sin((i+phase8)*8)*r8)/rsum
,
cos(theta+phase)*(baser+sin((i+phase0))*r0+sin((i+phase1)*2)*r1+sin((i+phase2)*3)*r2+sin((i+phase3)*4)*r3+sin((i+phase8)*8)*r8)/rsum
,0

])sphere(0.09,$fn=6 );
ii=(i+step)%360;
theta2 = ii+ sin((ii+ophase1)*rep1)*mag1+ sin((ii+ophase2)*rep2)*mag2;
translate([
sin(theta2+phase)*(baser+sin((ii+phase0))*r0 +sin((ii+phase1)*2)*r1+sin((ii+phase2)*3)*r2+sin((ii+phase3)*4)*r3+sin((ii+phase8)*8)*r8)/rsum
,
cos(theta2+phase)*(baser+sin((ii+phase0))*r0+sin((ii+phase1)*2)*r1+sin((ii+phase2)*3)*r2+sin((ii+phase3)*4)*r3+sin((ii+phase8)*8)*r8)/rsum
,0

])sphere(0.09,$fn=6 );
}}}

function rndR()=[rands(0,360,1)[0],rands(0,360,1)[1],rands(0,360,1)[0]];

function un(v)=v/max(len3(v),0.000001)*1;
function p2n(pa,pb,pc)=
let(u=pa-pb,v=pa-pc)un([u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]]);
function avrg(v)=sumv(v,max(0,len(v)-1))/len(v);
function lerp(start,end,bias)=(end*bias+start*(1-bias));
function len3(v)=len(v)==2?sqrt(pow(v[0],2)+pow(v[1],2)):sqrt(pow(v[0],2)+pow(v[1],2)+pow(v[2],2));
function sumv(v,i,s=0)=(i==s?v[i]:v[i]+sumv(v,i-1,s));
function rnd(S,a=0,b=1)=Seeded==1?(rands(min(a,b),max(a,b),1,S)[0]):(rands(min(a,b),max(a,b),1)[0]);
function rndc()=[rands(0,1,1)[0],rands(0,1,1)[0],rands(0,1,1)[0]];
```


[User]
Hey there, I'm looking to design some gears, and I've seen some cool stuff done with OpenSCAD's involute gear generator, but I'd like something a bit more robust. Specifically, I need to create both spur and bevel gears with a good amount of customization, and I'd like the whole thing to be parametric.

For both types of gears, I need the following parameters:

*   **Number of teeth:** Obvious, I know.
*   **Circular pitch:** This defines the size of the teeth and gears.
*   **Pressure angle:** This will affect the shape of the involute curve, typically 20 or 30 degrees, I'm not sure which we'll need to use yet.
*   **Clearance:** The space between meshing teeth, important for smooth operation.
*   **Gear thickness:** The thickness of the gear itself.
*   **Rim thickness:** How thick the outer rim of the gear should be.
*   **Rim width:** How wide the rim is from the root of the teeth.
*   **Hub thickness:** The thickness of the hub, where you'd attach the gear to a shaft.
*   **Hub diameter:** The diameter of the hub itself.
*   **Bore diameter:** The diameter of the center hole.
*   **Number of circles:**  I'd like to be able to add lightening holes in the gear, and this will specify how many holes to put in.
*   **Backlash:** I'd like to have the option to add a bit of play between teeth for tolerance.
*    **Involute facets:**  I'd also like to control how many facets are used to approximate the involute curve.
*    **Flat:** A boolean to control if the linear extrusion should be flat or an actual extrusion.
*   **Twist:** This will be used for double helical gears.

For **bevel gears** specifically, I also need:

*   **Cone distance:** The distance from the apex of the cone to the gear face.
*   **Face width:** The width of the tooth face on the bevel gear.
*   **Finish:** This would be an option to control the shape of the gear, with flat or back_cone options.

I need a separate module for creating a pair of meshing bevel gears, which will require these additional parameters:

*   **Gear 1 teeth:** The number of teeth for the first gear.
*   **Gear 2 teeth:** The number of teeth for the second gear.
*   **Axis angle:** The angle between the axes of the two bevel gears.
*   **Outside circular pitch:**  The circular pitch as measured at the outside of the gear.

I also need a separate module for generating a double helical gear. This needs the same parameters as spur gears, but it has an additional parameter:

*   **Double gear yes or no:** This will let the user decide if there should be one or two gears that are mirror images of each other, forming the double helical.

For all of the above, can you create a parametric OpenSCAD library (or set of libraries) to handle all of these things, as well as some test cases that demonstrate their use? I'd like the library to be well documented, using comments to describe each module and parameter. I'd also like to include a demonstration of meshing a double helical, as well as a demonstration of meshing a pair of bevel gears. No need to use any external libraries.

[Assistant]
involute_gears.scad:
```
// Parametric Involute Bevel and Spur Gears by GregFrost
// It is licensed under the Creative Commons - GNU LGPL 2.1 license.
// © 2010 by GregFrost, thingiverse.com/Amp
// http://www.thingiverse.com/thing:3575 and http://www.thingiverse.com/thing:3752

// Simple Test:
//gear (circular_pitch=700,
//	gear_thickness = 12,
//	rim_thickness = 15,
//	hub_thickness = 17,
//	circles=8);

teeth = 25;
holes = 6;
height = 40;
gear_twist = 700;
pressure_angle= 30;
circular_pitch = 500;
clearance = 0.2;
rim_width = 5;
hub_diameter = 25;
bore_diameter = 10;
hub_height_multiplier = 3;
gear_thickness_multiplier = .75;
double_gear_yes_or_no = "yes";

if (double_gear_yes_or_no != "yes"){
    height = height /2;
}

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

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

module test_meshing_double_helix(){
    meshing_double_helix ();
}

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

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

module test_bevel_gear_pair(){
    bevel_gear_pair ();
}

module test_bevel_gear(){bevel_gear();}

//bevel_gear();

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);
	}
}

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])
		{
			assign (
				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))
			{
				assign (
					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,2,1],[0,3,2],[0,4,3],[0,1,5],[1,2,5],[2,3,5],[3,4,5],[0,5,4]]);
				}
			}
		}
	}
}

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,
	flat=false)
{
	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_exturde_flat_option(flat=flat, 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)
				linear_exturde_flat_option(flat=flat, height=gear_thickness)
				circle (r=rim_radius);
			if (flat == false && hub_thickness > gear_thickness)
				translate ([0,0, -hub_thickness/2 + height/4 + height/8])
				linear_exturde_flat_option(flat=flat, height=hub_thickness-gear_thickness)
				circle (r=hub_diameter/2);
		}
		translate ([0,0,-1])
		linear_exturde_flat_option(flat =flat, height=2+max(rim_thickness,hub_thickness,gear_thickness))
		circle (r=bore_diameter/2);
		if (circles>0)
		{
			for(i=[0:circles-1])
				rotate([0,0,i*360/circles])
				translate([circle_orbit_diameter/2,0,-1])
				linear_exturde_flat_option(flat =flat, height=max(gear_thickness,rim_thickness)+3)
				circle(r=circle_diameter/2);
		}
	}
}

module linear_exturde_flat_option(flat =false, height = 10, center = false, convexity = 2, twist = 0)
{
	if(flat==false)
	{
		linear_extrude(height = height, center = center, convexity = convexity, twist= twist) child(0);
	}
	else
	{
		child(0);
	}

}

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])
		assign (
			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))
		{
			assign (
				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))
];

// Test Cases
//===============

module test_gears()
{
	translate([17,-15])
	{
		gear (number_of_teeth=17,
			circular_pitch=500,
			circles=8);

		rotate ([0,0,360*4/17])
		translate ([39.088888,0,0])
		{
			gear (number_of_teeth=11,
				circular_pitch=500,
				hub_diameter=0,
				rim_width=65);
			translate ([0,0,8])
			{
				gear (number_of_teeth=6,
					circular_pitch=300,
					hub_diameter=0,
					rim_width=5,
					rim_thickness=6,
					pressure_angle=31);
				rotate ([0,0,360*5/6])
				translate ([22.5,0,1])
				gear (number_of_teeth=21,
					circular_pitch=300,
					bore_diameter=2,
					hub_diameter=4,
					rim_width=1,
					hub_thickness=4,
					rim_thickness=4,
					gear_thickness=3,
					pressure_angle=31);
			}
		}

		translate ([-61.1111111,0,0])
		{
			gear (number_of_teeth=27,
				circular_pitch=500,
				circles=5,
				hub_diameter=2*8.88888889);

			translate ([0,0,10])
			{
				gear (
					number_of_teeth=14,
					circular_pitch=200,
					pressure_angle=5,
					clearance = 0.2,
					gear_thickness = 10,
					rim_thickness = 10,
					rim_width = 15,
					bore_diameter=5,
					circles=0);
				translate ([13.8888888,0,1])
				gear (
					number_of_teeth=11,
					circular_pitch=200,
					pressure_angle=5,
					clearance = 0.2,
					gear_thickness = 10,
					rim_thickness = 10,
					rim_width = 15,
					hub_thickness = 20,
					hub_diameter=2*7.222222,
					bore_diameter=5,
					circles=0);
			}
		}

		rotate ([0,0,360*-5/17])
		translate ([44.444444444,0,0])
		gear (number_of_teeth=15,
			circular_pitch=500,
			hub_diameter=10,
			rim_width=5,
			rim_thickness=5,
			gear_thickness=4,
			hub_thickness=6,
			circles=9);

		rotate ([0,0,360*-1/17])
		translate ([30.5555555,0,-1])
		gear (number_of_teeth=5,
			circular_pitch=500,
			hub_diameter=0,
			rim_width=5,
			rim_thickness=10);
	}
}

module meshing_double_helix ()
{
	test_double_helix_gear ();

	mirror ([0,1,0])
	translate ([58.33333333,0,0])
	test_double_helix_gear (teeth=13,circles=6);
}

test_double_helix_gear(pressure_angle,holes,teeth,height,gear_twist,circular_pitch,clearance,rim_width,hub_diameter,bore_diameter,hub_height_multiplier,gear_thickness_multiplier,double_gear_yes_or_no);

module test_double_helix_gear ()
{
	//double helical gear
	{
		circles = holes;
        twist=gear_twist;
		height=height;
		pressure_angle=pressure_angle;

		gear (number_of_teeth=teeth,
			circular_pitch=circular_pitch,
			pressure_angle=pressure_angle,
			clearance = clearance,
			gear_thickness = height/2*gear_thickness_multiplier,
			rim_thickness = height/2,
			rim_width = rim_width,
			hub_thickness = height/2*hub_height_multiplier,
			hub_diameter=hub_diameter,
			bore_diameter=bore_diameter,
			circles=circles,
			twist=twist/teeth);

        if (double_gear_yes_or_no == "yes"){

        mirror([0,0,1])
		gear (number_of_teeth=teeth,
			circular_pitch=circular_pitch,
			pressure_angle=pressure_angle,
			clearance = clearance,
			gear_thickness = height/2*gear_thickness_multiplier,
			rim_thickness = height/2,
			rim_width = rim_width,
			hub_thickness = height/2*hub_height_multiplier,
			hub_diameter=hub_diameter,
			bore_diameter=bore_diameter,
			circles=circles,
			twist=twist/teeth);
        }
	}
}

module test_backlash ()
{
	backlash = 2;
	teeth = 15;

	translate ([-29.166666,0,0])
	{
		translate ([58.3333333,0,0])
		rotate ([0,0,-360/teeth/4])
		gear (
			number_of_teeth = teeth,
			circular_pitch=700,
			gear_thickness = 12,
			rim_thickness = 15,
			rim_width = 5,
			hub_thickness = 17,
			hub_diameter=15,
			bore_diameter=5,
			backlash = 2,
			circles=8);

		rotate ([0,0,360/teeth/4])
		gear (
			number_of_teeth = teeth,
			circular_pitch=700,
			gear_thickness = 12,
			rim_thickness = 15,
			rim_width = 5,
			hub_thickness = 17,
			hub_diameter=15,
			bore_diameter=5,
			backlash = 2,
			circles=8);
	}

	color([0,0,128,0.5])
	translate([0,0,-5])
	cylinder ($fn=20,r=backlash / 4,h=25);
}

```


[User]
I need a design for a customizable tool holder, specifically for dop sticks used in lapidary, but something that could be adapted for other tools as well. I've got a good idea of the basics, but I want something that's flexible enough for various use cases.

Here are the main requirements:

*   **Parametric Design:** Everything needs to be easily adjusted via parameters.
*   **Hole Grid:** The holder should have a grid of holes to hold the tools vertically. I want to specify the number of rows and columns of these holes.
*   **Hole Size:** I need to control the diameter of the holes so it can be adapted to various stick sizes.
*   **Spacing:** The distance between the holes (center-to-center) needs to be adjustable.
*   **Overall Dimensions:** The overall height of the holder needs to be set as a parameter, as does the depth of the holes.
*   **Index Ridge (Optional):** I'd also like an optional ridge at the bottom of the holes for orienting tools with a notch. The ridge size should be adjustable and turned on or off.
*   **Units:** It needs to use either inches or millimeters with a single units parameter. It should convert dimensions internally based on the units that are selected, and this should be transparent to the user. The user should not have to specify whether any individual measurement is in mm or inches - they should just provide one measurement and it should scale to the proper dimensions based on the units parameter.
*   **Libraries:** I'm not picky about what libraries are used, but I know that BOSL has some useful functions. I would prefer to use that if it's a good fit, but am otherwise open to suggestions.

Basically, I'm thinking of a rectangular block with an array of holes, and the option for an orientation ridge. I need a parametric file that lets me change all these things easily. Could you provide an OpenSCAD file for that, preferably using BOSL if it seems like a good idea? I would like to be able to use it in the customizer in OpenSCAD.

[Assistant]
simple_dop_holder.scad:
```
//Title: Dop Stick Holder
//Author: Alex English - ProtoParadigm
//Date: 8/5/16
//License: Creative Commons - Share Alike - Attribution

//Notes: This is intnded to hold dop sticks used in lapidary work, and can be configured to use different size dop sticks, have different spacing between them, and different numbers of holes. It may have other applicatoins, particularly tool-holding in other fields.

IN=25.4*1; //multiplication by 1 to prevent customizer from presenting this as a configurable value

//Units to use, inches or mm - Make sure to update all dimensional values if you change this
units = "i"; //["i":Inches, "m":Millimeters]

//Diameter of the Dop sticks or other tools to be used
dop_diameter = 0.5;
dop_d = units=="i" ? dop_diameter*IN : dop_diameter;

//Center-to-center spacing of holes
hole_spacing = 1.5;
spacing = units=="i" ? hole_spacing*IN : hole_spacing;

//Number of rows of holes
rows=2;

//Number of columns of holes
cols=5;

//Height of the entire holder
height=1.5;
h = units=="i" ? height*IN : height;

//Depth of the holes
hole_depth=1;
depth = units=="i" ? hole_depth*IN : hole_depth;

//Turn the index ridge at the bottom of the holes on or off
use_index=1; //[1:On, 0:Off]

//Size of the ridge at the bottom - only used if the index is turned on
index_size=3; //[1:5]

difference()
{
    cube([rows*spacing,cols*spacing,h]);
    for(x=[0:rows-1]) for(y=[0:cols-1]) translate([x*spacing+spacing/2, y*spacing+spacing/2, h-depth]) cylinder(d=dop_d+0.25, h=depth+1, $fa=10, $fs=0.5);
}

if(use_index)
    for(x=[0:rows-1]) translate([spacing/2+spacing*x, 0, h-depth]) rotate([0, 45, 0]) translate([-index_size/2, 0, -index_size/2]) cube([index_size, cols*spacing, index_size]);
```


[User]
I need to design some adapters for my dop stick holder. I have a holder with uniform diameter holes, but my dop sticks come in various sizes. I want to make adapters that sit in the larger holes and then hold the smaller dop sticks securely upright.

My current design, which I've attached as `dop_holder_adapter.scad`, is pretty simple. It uses a cylinder to represent the outside of the adapter (which sits in the hole), and then subtracts another cylinder to make a hole for the smaller dop stick. I have it set up to use either inches or mm, and the important dimensions are things like the diameter of the hole in the holder, the diameter of the dop stick, and the height of the adapter.

I'd like you to generate a parametric OpenSCAD file that can create these adapters. The important parameters should be:

*   `hole_diameter`: The diameter of the hole in the dop stick holder.
*   `dop_diameter`: The diameter of the dop stick.
*   `adapter_height`: The height of the adapter.
*   `units`: To choose between "i" for inches and "m" for millimeters. This should affect the dimensions before any OpenSCAD geometry is made.

I need the adapters to have a slightly tighter fit with the holder hole, so the outer diameter of the adapter should be `hole_diameter - 0.2` when expressed in mm. The hole for the dop stick should be `dop_diameter + 0.5` when expressed in mm.

The adapter should have a small chamfer, or rounded edge, on its top to make insertion into the holder a little easier. I don't really care about the specifics of the chamfer as long as it exists and looks nice.

The adapter doesn't need any complex shapes, just basic cylinders with some differences and transforms, and a small chamfer on the top edge. I'd also like the code to be well commented.

[Assistant]
dop_holder_adapter.scad:
```
//Title: Dop Stick Holder Adapter
//Author: Alex English - ProtoParadigm
//Date: 8/5/16
//License: Creative Commons - Share Alike - Attribution

//Notes: This is designed to be used with the dop stick holder for lapidary work. It will adapt smaller dop sticks to sit upright in a larger holder hole so that one holder with larger holes can be printed and accommodate a variety of dop stick sizes.

IN=25.4*1; //multiplication by 1 to prevent customizer from presenting this as a configurable value

//Units to use, inches or mm - Make sure to update all dimensional values if you change this
units = "i"; //["i":Inches, "m":Millimeters]

//Diameter of the holes in the holder
hole_diameter = 0.5;
od = units=="i" ? hole_diameter*IN : hole_diameter;

//Diameter of the dop stick
dop_diameter = 0.375;
id = units=="i" ? dop_diameter*IN : dop_diameter;

//Height of the adapter - must be less than the depth of the hole)
height = 0.5;
h = units=="i" ? height*IN : height;

difference()
{
    union()
    {
        cylinder(d=od-0.2,h=h, $fa=6, $fs=0.5);
        cylinder(d=od+4, h=3);
    }
    translate([0, 0, -1]) cylinder(d=id+0.5, h=h+2, $fa=6, $fs=0.5);
}
```


[User]
Hey, I'm looking to create a customizable 6-sided die with text on each face, and I'd like to be able to control the font, the text on each face, the size of the text, the overall die size, the depth of the text cut, and the roundness of the edges. I have an existing design I'm basing this off of that uses the `linear_extrude()` and `text()` modules, and the `minkowski()` operation to create the rounded edges. I'd like the new design to be parametric so I can easily tweak all of those values.

Specifically:
1.  I want to specify the text for each face separately.
2.  I want to be able to scale each text independently from the others.
3. I want to use any font that is available on the system.
4. The die should be a cube with rounded (spherical) edges using `minkowski()` with a sphere, not filleted edges.
5. The text should be cut into the surface of the die, not protruding out, and the cut depth should be adjustable.
6. The overall size of the die (side length) should be adjustable.
7. The amount of rounding on the corners should also be adjustable.

Could you generate the necessary OpenSCAD code for me? I don't have any specific libraries in mind, but if something makes the process easier, I'm open to suggestions.

[Assistant]
Unicode_D6.scad:
```
//Created by Ari M. Diacou, June 2015
//Shared under Creative Commons License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
//see http://creativecommons.org/licenses/by-sa/3.0/

/* [Characters] */
// use any letters, numbers or unicodes, see http://en.wikipedia.org/wiki/List_of_Unicode_characters or my favorite http://www.decodeunicode.org/
text_1= "1";
scale_1=.8;
text_2= "2";
scale_2=.8;
text_3= "3";
scale_3=.8;
text_4= "5";
scale_4=.8;
text_5= "8";
scale_5=.8;
text_6= "13";
scale_6=.6;
/* [Dimensions] */
//Depth of indendations in mm
depth=0.75;
//One side of the cube in mm
cube_size=15;
//How much of the corners should be cut off? Higher is more spherical, 0 is a cube. Recommend 0.0-2.0.
curvature=1.2;
//DejaVu Sans was the font I found on this list with the most Unicode 7 implementations
font = "DejaVu Sans"; //[ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alegreya,Alegreya Sans,Alegreya Sans SC,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andada SC,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Antonio,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arial,Arial Black,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bhavuka,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bruno Ace,Bruno Ace SC,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butcherman Caps,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clara,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Comic Sans MS,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Creepster Caps,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,DejaVu Sans,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Dhyana,Didact Gothic,Dinah,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Droid Arabic Kufi,Droid Arabic Naskh,Droid Sans,Droid Sans Ethiopic,Droid Sans Mono,Droid Sans Thai,Droid Serif,Droid Serif Thai,Dr Sugiyama,Duru Sans,Dynalight,Eagle Lake,Eater,Eater Caps,EB Garamond,Economica,Eczar,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Encode Sans,Encode Sans Compressed,Encode Sans Condensed,Encode Sans Narrow,Encode Sans Wide,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Geneva,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Helvetica,Henny Penny,Hermeneus One,Herr Von Muellerhoff,Hind,Holtwood One SC,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Inknut Antiqua,Irish Grover,Irish Growler,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jaldi,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Sans Std Light,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kadwa,Kalam,Kameron,Kantumruy,Karla,Karla Tamil Inclined,Karla Tamil Upright,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Lemon One,Liberation Sans ,Libre Baskerville,Libre Caslon Text,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Lohit Bengali,Lohit Tamil,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Loved by the King,Lovers Quarrel,Love Ya Like A Sister,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merge One,Merienda,Merienda One,Merriweather,Merriweather Sans,Mervale Script,Metal,Metal Mania,Metamorphous,Metrophobic,Miama,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Miss Saint Delafield,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedford,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Sheppards,Mrs Saint Delafield,Muli,Mystery Quest,Nanum Brush Script,Nanum Gothic,Nanum Gothic Coding,Nanum Myeongjo,Nanum Pen Script,NATS,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nosifer Caps,Nothing You Could Do,Noticia Text,Noto Sans,Noto Sans Hebrew,Noto Sans Symbols,Noto Sans UI,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,OFL Sorts Mill Goudy TT,Oldenburg,Old Standard TT,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Overlock,Overlock SC,Over the Rainbow,Ovo,Oxygen,Oxygen Mono,Pacifico,Palanquin,Palanquin Dark,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Pecita,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Phetsarath,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poetsen One,Poiret One,Poller One,Poly,Pompiere,Ponnala,Pontano Sans,Poppins,Porter Sans Block,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puralecka Narrow,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redacted,Redacted Script,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansation,Sansita One,Sarabun,Sarala,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sedan,Sedan SC,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siamreap,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stalin One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Strong,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tahoma,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Terminal Dosis,Terminal Dosis Light,Text Me One,Thabit,The Girl Next Door,Tienne,Tillana,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tuffy,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Verdana,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

/* [Hidden] */
text=[text_1,text_2,text_3,text_4,text_5,text_6];
text_scaling=[scale_1,scale_2,scale_3,scale_4,scale_5,scale_6];
//How each die surface is rotated
rot=[[0,0,0],[90,0,0],[180,0,0],[270,0,0],[0,90,0],[0,-90,0]];
ep=0+0.05; //epsilon, a small number used for alignment and overlap
image_size=cube_size-2*depth-ep; //The size of the images is based on the depth of the cuts so that they wont intersect
///////////////////////// Main() /////////////////////////////////
intersection_for(i=[1:6]){ //Each side is a cube minus the image, the die is the intersection of all the cubes
	side(i);
}
////////////////////////// Functions //////////////////////////////
module letter(l){
    // Use linear_extrude() to make the letters 3D objects
    linear_extrude(height = depth, convexity=20)
        text(str(l), size = image_size, font = font, halign = "center", valign = "center", $fn = 40);
}
module side(side_num){
//this function takes the surface, scales it to the right size then subtracts the surface from the cube. The resulting cube is then rotated into the correct position.
	rotate(rot[side_num-1])
		difference(){
			minkowski(){
				cube(cube_size-2*curvature,true);
				sphere(curvature, $fn=20);
			}
			translate([0,0,+cube_size/2-depth+ep])
				scale([text_scaling[side_num-1],text_scaling[side_num-1],1])
                    letter(text[side_num-1]);
		}
}
```


[User]
I'm looking to create a customizable 10-sided die (a d10) in OpenSCAD. I want the design to be similar to the provided code, but I need it to be fully parametric.

Here are the key features I'm looking for:

*   **Shape:** The base shape should be a standard 10-sided die, with flat faces, and the ability to add curvature to those edges.
*   **Text:** Each face should have a different text label. I want to be able to customize the text on each face, the scale of each text label, and the font used for all labels.
*   **Customization:** I need to be able to control:
    *   The overall size of the die (diameter from 'pole to pole').
    *   The amount of curvature or rounding of the edges/corners (from sharp corners to rounded edges).
    *  The font used for the text on the faces.
    * The specific text on each face.
    * The scale of the text on each face.
*   **Orientation:** The die should be designed so that when printed, one flat side can rest on the print bed, meaning a specific face must have a consistent orientation.
*   **Font**: I prefer that a user can choose from the fonts available via the text() command, and it's okay if the generator recommends "DejaVu Sans" as a reliable unicode font.

I don't have a specific target print size in mind - just that it is easily customizable. I'm thinking that the dimensions of the die will be a major point of customization, so I want to be able to freely scale it. I do not have any requirements in regards to libraries, but would greatly appreciate it if your solution worked out of the box with OpenSCAD.

Could you generate the OpenSCAD files for this?

[Assistant]
Unicode_D10.scad:
```
//Created by Ari M. Diacou, June 2015
//Shared under Creative Commons License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
//see http://creativecommons.org/licenses/by-sa/3.0/

/* [Characters] */
// use any letters, numbers or unicodes, see http://en.wikipedia.org/wiki/List_of_Unicode_characters or my favorite http://www.decodeunicode.org/
text_1= "⅟₈";
scale_1=.5;
text_2= "½π";
scale_2=.35;
text_3= "2";
scale_3=.7;
text_4= "⅟₄";
scale_4=.5;
text_5= "π";
scale_5=.7;
text_6= "4";
scale_6=.7;
text_7= "5";
scale_7=.7;
text_8= "2π";
scale_8=.4;
text_9= "8";
scale_9=.7;
text_10= "1";
scale_10=.7;
/* [Dimensions] */
//Distance from "pole to pole", in mm
size=22;
//How much of the corners should be cut off? Higher is more rounded, 0 gives the sharpest edge possible. Recommend 0.0-3.0.
curvature=2;
//DejaVu Sans was the font I found on this list with the most Unicode 7 implementations
font = "DejaVu Sans"; //[ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alegreya,Alegreya Sans,Alegreya Sans SC,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andada SC,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Antonio,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arial,Arial Black,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bhavuka,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bruno Ace,Bruno Ace SC,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butcherman Caps,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clara,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Comic Sans MS,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Creepster Caps,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,DejaVu Sans,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Dhyana,Didact Gothic,Dinah,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Droid Arabic Kufi,Droid Arabic Naskh,Droid Sans,Droid Sans Ethiopic,Droid Sans Mono,Droid Sans Thai,Droid Serif,Droid Serif Thai,Dr Sugiyama,Duru Sans,Dynalight,Eagle Lake,Eater,Eater Caps,EB Garamond,Economica,Eczar,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Encode Sans,Encode Sans Compressed,Encode Sans Condensed,Encode Sans Narrow,Encode Sans Wide,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Geneva,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Helvetica,Henny Penny,Hermeneus One,Herr Von Muellerhoff,Hind,Holtwood One SC,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Inknut Antiqua,Irish Grover,Irish Growler,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jaldi,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Sans Std Light,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kadwa,Kalam,Kameron,Kantumruy,Karla,Karla Tamil Inclined,Karla Tamil Upright,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Lemon One,Liberation Sans ,Libre Baskerville,Libre Caslon Text,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Lohit Bengali,Lohit Tamil,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Loved by the King,Lovers Quarrel,Love Ya Like A Sister,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merge One,Merienda,Merienda One,Merriweather,Merriweather Sans,Mervale Script,Metal,Metal Mania,Metamorphous,Metrophobic,Miama,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Miss Saint Delafield,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedford,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Sheppards,Mrs Saint Delafield,Muli,Mystery Quest,Nanum Brush Script,Nanum Gothic,Nanum Gothic Coding,Nanum Myeongjo,Nanum Pen Script,NATS,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nosifer Caps,Nothing You Could Do,Noticia Text,Noto Sans,Noto Sans Hebrew,Noto Sans Symbols,Noto Sans UI,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,OFL Sorts Mill Goudy TT,Oldenburg,Old Standard TT,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Overlock,Overlock SC,Over the Rainbow,Ovo,Oxygen,Oxygen Mono,Pacifico,Palanquin,Palanquin Dark,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Pecita,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Phetsarath,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poetsen One,Poiret One,Poller One,Poly,Pompiere,Ponnala,Pontano Sans,Poppins,Porter Sans Block,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puralecka Narrow,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redacted,Redacted Script,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansation,Sansita One,Sarabun,Sarala,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sedan,Sedan SC,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siamreap,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stalin One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Strong,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tahoma,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Terminal Dosis,Terminal Dosis Light,Text Me One,Thabit,The Girl Next Door,Tienne,Tillana,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tuffy,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Verdana,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

/* [Hidden] */

angles = [
    [0,  0,0*360/5],
    [0,  0,1*360/5],
    [0,  0,2*360/5],
    [0,  0,3*360/5],
    [0,  0,4*360/5],

    [0,180,0*360/5],
    [0,180,1*360/5],
    [0,180,2*360/5],
    [0,180,3*360/5],
    [0,180,4*360/5],
];

text=[text_1,text_2,text_3,text_4,text_5,text_6,text_7,text_8,text_9,text_10,];
text_scaling=[scale_1,scale_2,scale_3,scale_4,scale_5,scale_6,scale_7,scale_8,scale_9,scale_10,];

module die()
resize([0,0,size], auto=true)
intersection_for (i=[0:9]) {
    rotate(angles[i])
    side(text[i], 1, text_scaling[i]);
}

module side(letter, depth, scaling){
    rotate([0,45,0])
    translate([0,0,3.6])
    difference(){
        translate([0,0,-3.6])
        rotate([0,-45,0])
        resize([0,0,10], auto=true)
        minkowski(){
            sphere(curvature, $fn=15);
            d10_base();
        }

        scale(scaling)
        scale(.5)
        translate([0,0,-0.9])
        translate([4,0,0])
        rotate([0,0,90])
        letter(letter, 1.5);
    }
}

module letter(l, depth){
    // Use linear_extrude() to make the letters 3D objects
    linear_extrude(height = depth, convexity=20)
        text(str(l),
            size = image_size,
            font = font,
            halign = "center",
            valign = "center",
            $fn = 20);
}

module d10_base ()
hull()
polyhedron
       (points = [
                 [  -0.00000,  -0.00000,  29.69850],
                 [ -10.14620,  31.22680,   3.13535],
                 [ -32.83380,  -0.00001,   3.13535],
                 [ -26.56310,  19.29920,  -3.13535],
                 [ -26.56310, -19.29930,  -3.13535],
                 [ -10.14620, -31.22680,   3.13535],
                 [   0.00000,   0.00000, -29.69850],
                 [  26.56310, -19.29920,   3.13535],
                 [  32.83380,   0.00001,  -3.13535],
                 [  26.56310,  19.29920,   3.13535],
                 [  10.14620,  31.22680,  -3.13535],
                 [  10.14620, -31.22680,  -3.13535],
                ],
           faces = [
                 [    0,    1,    2],[    3,    4,    5],
                 [    6,    7,    8],[    9,    10,   11]
           ]
      );

rotate([0,-45,0])
rotate([0,0,360/5])
die();

indeterminate = 1e6;
infinitesimal = 1e-6;

module space(){
    cube(indeterminate, center=true);
}

module opening(curvature){
    dilate(curvature)
    erode(curvature)
    children();
}

module erode(curvature){
    difference(){
        space();
        dilate(curvature)
        difference(){
            space();
            children();
        }
    }
}
module dilate(curvature){
    minkowski(){
        sphere(curvature, $fn=15);
        children();
    }
}
```


[User]
I'd like to design a spray can straw holder. I need it to be parametric so I can adjust it to different cans and straws. The design should have two main types: one that clamps onto the can and another that uses tape to attach.

For the clamp type, I'll need to be able to specify:
*   The diameter of the can it should fit
*   The height of the holder
*   The diameter of the hole for the straw
*   The thickness of the walls of the holder
*   Whether to include a chamfer on the straw hole
*   The angle of the opening in the clamp - this would be the gap in the circle shape
*   The number of segments to define the circle

For the taped type of holder, I need:
*   The diameter of the can
*   The height of the holder (which should match the width of the tape)
*   The straw hole diameter
*   The thickness of the walls
*   Chamfer on the straw hole (yes/no)

I'd also like the following:
*   For the clamp type, to be able to add small supporting cylinders around the gap to reinforce it.
*   For the taped version, the main body should be rounded on the corners and edges, but should still leave the front relatively open so tape can be applied easily.
*   Also for the taped version, there should be a small rectangular cutout on the back of the holder to allow the straw to sit lower in the holder and to be inserted more easily.

I think that's everything. Can you generate the OpenSCAD code for this? I'm not using any special libraries, just standard OpenSCAD primitives.

[Assistant]
SprayCanStrawHolder_v3.scad:
```
/* Customizable Spray Can Straw Holder
 * By DrLex, v3.0 2019/12
 * Thingiverse thing:1707976
 * Released under Creative Commons - Attribution license */

/* [Dimensions (all in mm)] */
// Type of holder: 'clamp' yields a circle segment that grabs the can by itself; 'taped' yields a small holder that must be attached to the can with one or two strips of adhesive tape.
type = "clamp"; //[clamp,taped]

// Diameter of the can. For the 'clamp' type holder, you may want to use a value that is slightly too small, to give the holder extra clamping force.
can_dia = 57.0; //[40:0.1:80]

// Height of the holder. For the 'taped' type, you should use the width of your strip of tape.
height = 8.0; //[3:0.1:32]

// Diameter of the straw hole. The ideal value will depend on your printer, print settings, and filament. Try out a few values and print the final model with what works best.
straw_dia = 2.30; //[1:0.01:4]

// Thickness of the holder walls. Preferably set this to a value that will yield exactly an integer number of perimeters.
thickness = 1.8; //[0.8:0.01:3]

// Add a chamfer to the hole. This makes it easier to insert the straw, especially for the 'taped' model if you're going to attach it with a single strip of tape that blocks the gap in the front.
chamfer = "no"; //[no,yes]

/* [Advanced] */

// The angle for the opening in the clamp (only for 'clamp' shape). Zero produces a half circle which will obviously not clamp at all, 90 produces a full circle which you could only slide onto the can if there is nothing in the way. The default has been tested to work well, so you probably should not change this.
opening_angle = 36; //[0:1:90]

// Number of segments (detail) for the model.
segments = 80; //[32:128]

/* [Hidden] */
rounding = 0.8;
inner_radius = can_dia / 2;
straw_r = straw_dia / 2;

outer_radius = inner_radius + thickness;
mid_radius = (inner_radius + outer_radius)/2;

cut_x = (outer_radius + 2) * cos(opening_angle);
cut_y = (outer_radius + 2) * sin(opening_angle);
r_x = mid_radius * cos(opening_angle);
r_y = mid_radius * sin(opening_angle);

block_w = straw_dia + 3.5;
block_x = block_w/2 - rounding;
xtra_y = straw_dia < 2.6 ? 0 : (straw_dia-2.6)/2;
block_y = outer_radius + 2.5 + straw_dia + xtra_y - rounding;
straw_y = outer_radius + 1.0 + straw_dia;

if(type == "clamp") {
    difference() {
        cylinder(h=height, r=outer_radius, $fn=segments);
        translate([0,0,-1]) {
            cylinder(h=height+2, r=inner_radius, $fn=segments);
            if(opening_angle < 90) {
                linear_extrude(height+2) polygon([[0, 0], [cut_x, cut_y], [cut_x, cut_y + outer_radius], [-cut_x, cut_y + outer_radius], [-cut_x, cut_y]]);
            }
        }
    }
    if(opening_angle < 90) {
        translate([r_x, r_y, 0]) cylinder(r=thickness/2, h=height, $fn=16);
        translate([-r_x, r_y, 0]) cylinder(r=thickness/2, h=height, $fn=16);
    }
}
else {
    touch_x = cos(60) * (inner_radius+rounding);
    touch_y = sin(60) * (inner_radius+rounding);
    block_x2 = block_x + rounding*2 + .4;
    block_w2 = block_w + .8;
    difference() {
        hull() {
            translate([-touch_x, -touch_y, 0]) cylinder(h=height, r=rounding, $fn=24);
            translate([touch_x, -touch_y, 0]) cylinder(h=height, r=rounding, $fn=24);
            translate([block_x2, -block_y, 0]) cylinder(h=height, r=rounding, $fn=24);
            translate([-block_x2, -block_y, 0]) cylinder(h=height, r=rounding, $fn=24);
        }
        translate([0, -(outer_radius + block_w2/2), height/2]) cube([block_w2, block_w2, height+1], center=true);
        translate([0,0,-1]) {
            cylinder(h=height+2, r=inner_radius, $fn=segments);
        }
    }
}

difference() {
    hull() {
        translate([block_x, -block_y, 0]) cylinder(h=height, r=rounding, $fn=24);
        translate([-block_x, -block_y, 0]) cylinder(h=height, r=rounding, $fn=24);
        translate([0, -mid_radius, height/2]) cube([block_w, 0.1, height], center=true);
    }

    translate([0, -straw_y, -1]) {
        cylinder(h=height + 2, r=straw_r, $fn=32);
        linear_extrude(height + 2, convexity=4)
            polygon([[0.2*straw_dia, straw_dia + 0.35], [0.26*straw_dia, 0.2*straw_dia], [straw_dia, -1.85*straw_dia],
                    [-straw_dia, -1.85*straw_dia], [-0.26*straw_dia, 0.2*straw_dia], [-0.2*straw_dia, straw_dia + 0.35]]);
    }

    if(chamfer == "yes") {
        translate([0, -straw_y, height-straw_r-rounding]) cylinder(h=straw_dia+rounding, r1=0, r2=straw_dia+rounding, $fn=32);
        translate([0, -straw_y, -straw_r]) cylinder(h=straw_dia+rounding, r2=0, r1=straw_dia+rounding, $fn=32);
    }
}

// Finishing touches
if(type == "clamp") {
    // Round the connection between the circle and the block
    round_y = sqrt(pow(outer_radius + rounding, 2) - pow(block_w/2 + rounding, 2));
    ft_x = block_w/2 - .1;
    ft_y = round_y + .1;
    difference() {
        linear_extrude(height, convexity=4) {
            polygon([[ft_x, -ft_y], [ft_x, -mid_radius], [block_w/2 + round_y - mid_radius, -mid_radius]]);
            polygon([[-ft_x, -ft_y], [-ft_x, -mid_radius], [-(block_w/2 + round_y - mid_radius), -mid_radius]]);
        }
        translate([block_w/2 + rounding, -round_y, height/2]) cylinder(h=height+2, r=rounding, center=true, $fn=24);
        translate([-block_w/2 - rounding, -round_y, height/2]) cylinder(h=height+2, r=rounding, center=true, $fn=24);
    }
}

```


[User]
Hi! I'm trying to design a mold and stencil for a soft pneumatic actuator. I've been using a customizer script that does this, but I'd like to have more control over the design process and make it fully parametric. I'm hoping you can help me generate the necessary OpenSCAD files.

Basically, I need to create two parts: a mold and a stencil. The actuator will be formed by layers of silicone, and the pattern on the actuator will come from an image.

Here's a breakdown of what I need:

**Mold:**

*   The mold should consist of a base with two cavities.
*   The bottom cavity will determine the outline of the actuator. This outline should be a simple rectangle with slightly rounded corners, the size of which is configurable.
*   The top cavity is where the second silicone layer (that will eventually form the active part of the actuator) will sit. The depth of this top cavity will also be configurable. This should also be a rectangular shape but slightly smaller than the base.
*   The heights of each cavity should be configurable as parameters.
*   The base should be slightly larger than both cavities.
*   I'd like some kind of tolerance added to the mold design - if the two cavities are the same size, they should be offset by a slight amount to ensure silicone fits properly in the mold.

**Stencil:**

*   The stencil will be used to create the pattern of the actuator.
*   It should be based on an input image file (like a PNG). The image should be stretched to fit the dimensions of the actuator outline.
*   The stencil will consist of the inverse of the image, scaled to a slightly larger size than the actuator. This scaled and inverse image will form the basis of the stencil.
*   The stencil thickness should also be configurable and should be such that it sits within the mold.
*  The stencil should also be offset along the Z axis so that it is positioned over the mold.
*  Finally, there should be a cutout in the stencil which aligns with the second cavity in the mold.

**Parameters:**

*   **`image_file`**: The path to the input image file (e.g., "my_image.png").
*   **`side_length`**: The length of the sides of the square actuator in millimeters.
*  **`radius`**: The radius of the rounded corners on the actuator outline.
*   **`layer_1_height`**: The thickness of the first layer of silicone in the mold in millimeters.
*   **`layer_2_height`**: The thickness of the second layer of silicone in the mold in millimeters.
*  **`stencil_height`**: The height (or thickness) of the stencil in millimeters.
*   **`tolerance`**: A small value in millimeters for tolerances.
*  **`stencil_offset_z`**: The Z-axis offset of the stencil relative to the mold.

I'd like the design to be fully parametric using OpenSCAD and not be dependent on any specific libraries.

Could you help me generate the OpenSCAD code for the mold and stencil based on these requirements? I'd really appreciate it!

[Assistant]
Flat_Actuators.scad:
```
part = "both"; // [first:Mold Only,second:Stencil Only,both:Mold and Stencil]

/* [Parameters] */
// Load a 100x100 pixel image. (images will be automatically stretched to fit) Simple, high contrast images like logos work best.
Image = "image-surface.dat"; // [image_surface:100x100]
//Length of the sides of the square actuator
Side_Length = 50; //[1:100]
//Thickness of the first layer of silicone (Having different thicknesses on the layer will create varying effects)
Layer_1_Height = 4; //[1:4]
//Thickness of the second layer of silicone (Having different thicknesses on the layer will create varying effects)
Layer_2_Height = 4; //[1:4]

/* [Hidden] */
height = Layer_2_Height;
tolerance = .3;
thickness = height*2;
scaleFactor = Side_Length/100;
Layer_1_Height_2 = Layer_1_Height;
Layer_2_Height_2 = Layer_2_Height;

print_part();

module print_part() {
	if (part == "first") {
		mold();
	} else if (part == "second") {
		stencil();
	} else if (part == "both") {
		both();
	} else {
		both();
	}
}

module both() {
    mold();
    stencil();
}

module stencil() {
    translate([0,0,Layer_1_Height+Layer_2_Height+23]) {

        scale([scaleFactor,scaleFactor,1]) {
            difference() {
                scale([1.01,1.01,thickness]) {
                    surface(file=Image, center=true, convexity=5);
                }

                translate([0,0,-(height)]) {
                    cube([135,135,2*thickness],center=true);
                }
            }
        }
    }
}

module mold() {
    difference() {
        difference() {
            translate([0,0,(Layer_1_Height+Layer_2_Height+3)/2]) {
                cube([Side_Length+10,Side_Length+10,Layer_1_Height+Layer_2_Height+3], center = true);
            }
            translate([0,0,Layer_1_Height+3]) {
                translate([0,0,(Layer_2_Height_2)/2]) {
                    cube([Side_Length+tolerance,Side_Length+tolerance,Layer_2_Height_2], center = true);
                }
            }
        }

        translate([0,0,3]) {
            translate([0,0,(Layer_1_Height_2)/2]) {
                cube([Side_Length-2,Side_Length-2,Layer_1_Height_2], center = true);
            }
        }
    }
}
```


[User]
Hey, I'm looking for a design for a parametric monitor stand that I can 3D print. I've been using some pretty janky 2x4s and I'd like something a bit more refined.

The stand needs to be in three pieces, because my printer bed isn't big enough to do it all in one go. There should be two identical side pieces and a single center support. The sides will have a rectangular base with rounded corners and a hollowed-out center, kind of like a frame, so the monitor feet will sit on the outer edges. The center support will slot into these sides and create a stable platform.

Here are the parameters I'd like to be able to control:
*   **Stand_Width:** This is the overall width of the stand, measuring from the outer edges of the monitor's rubber feet.
*   **Stand_Depth:** The front-to-back depth of the monitor base.
*   **Stand_Height:** The overall height of the stand.
*   **Wall_Width:** The width of the side walls, this should be wide enough to support the monitor's rubber feet.
*   **Overall_Thickness:** The thickness of all parts of the stand.
*   **Fitment_Adjust:** An adjustment factor to compensate for any fitment issues with my printer, to help ensure pegs fit well. I have a test piece that can be printed, which is used to adjust the fitment.
*   **Rounded_Corners:** A toggle to enable rounded corners on the side pieces.

I'd like the parts to interlock using a system of tabs and slots and I'll need a test print module to check the fitment.

It would also be great if the design included the ability to generate all three parts laid out on the build plate, for ease of printing.

I'd like it to utilize the MCAD library, specifically the `roundedBox` module. Let me know what you think!

[Assistant]
lcdstand.scad:
```
// Measure left to right of monitor base from outer edge of monitor's rubber feet (mm).
Stand_Width = 200;          // [100:300]

// Measure front to rear of monitor base (mm).
Stand_Depth = 170;          // [100:300]

// Overall height of the stand (mm).
Stand_Height = 125;         // [80:300]

// Width of side walls, should at least match the diameter of the monitor's rubber feet.
Wall_Width = 20;            // [10:50]

// Applies to the thickness of everything.
Overall_Thickness = 4.1;    // [0.1:0.1:9.9]

// Adds error compensation to interlock joint gaps, use the fitment test print to trial for your printer.
Fitment_Adjust = 0.8;       // [0:0.1:3]

// Leave off to speed up viewing, enable before creating.
Rounded_Corners = "No";     // [Yes,No]

// Select part to view.
Build = "Assembled";        // [Wall:Wall,Support:Support,Assembled:Assembled Stand,Fit_Test:Joint fitment test, Print_Bed:All 3 parts laid out for printing]

/* [Hidden] */

WW = Wall_Width;                                    // Wall Width
TH = Overall_Thickness;                             // Thickness
L = Stand_Width - WW - TH;                          // Length
W = Stand_Depth;                                    // Width
H = Stand_Height;                                   // Height
FW = 10;                                            // Section Frame Width
CW = 22;                                            // Center Width
R = (Rounded_Corners == "Yes" ? 3.5 : 0);           // Rounded Edge Radius
TA = Fitment_Adjust;                                // Joint gap fitment compensation adjustment
SW = 15;                                            // Support Width
SH = 20;                                            // Support Height
TL = 80;                                            // Triangle Length
LH = 25;                                            // Latch Height
LP = 1;                                             // Latch Position
HP = 10;                                            // Hole Position
HH = 20;                                            // Hole Height
HW = 16;                                            // Hole Width
GH = 23.6;                                          // Gap Height
GW = 5.3;                                           // Gap Width
WR = ((W / 2) - ((TH + FW) * 2) - (CW / 2)) / 2;    // Frame void radius if height is within limit
HR = (H - TH - (FW * 2)) / 2;                       // Frame void radius if height is outside limit
$fn = 40;                                           // Number of sides in a circle

// Build wall
if(Build == "Wall")
{
    wall();
}

// Build support
else if(Build == "Support")
{
    support();
}

// Build assembled stand
else if(Build == "Assembled")
{
    rotate(a = [180, 0,0])
    {
        support();

        for(X = [1, -1])
            translate(v = [(L + TH) / 2 * X, 0, (H - TL) / 2])
                rotate(a = [0, 0, 90 * X])
                    wall();
    }
}

else if(Build == "Fit_Test")
{
    // Create latch hole only.
    translate(v = [0, 0, H / 2])
        difference()
        {
            wall();

            translate(v = [(W / 4) + (CW / 2) + TH, 0, 0])
                cube(size = [W / 2, WW * 2, H * 1.1], center = true);
            translate(v = [-(W / 4) - (CW / 2) - TH, 0, 0])
                cube(size = [W / 2, WW * 2, H * 1.1], center = true);
            translate(v = [0, 0, H / 2])
                cube(size = [CW + (TH * 3), WW * 2, (H * 2) - (TL * 2)], center = true);
        }

    // Create latch tab only.
    translate(v = [(L / 2) - (TL / 2), 0, TL / 2])
        difference()
        {
            support();

            translate(v = [15, 0, 0])
                cube(size = [L, SW * 1.1, H], center = true);
        }
}

else if(Build == "Print_Bed")
{
    rotate(a = [0, 0, 45])
    {
        translate(v = [0, 0, TL / 2])
        support();
        for(X = [1, -1])
        translate(v = [0, X * WW * 1.5, H / 2])
        wall();
    }
}

module support()
{
    rotate(a = [180, 0, 0])
        difference()
        {
            union()
            {
                translate(v = [0, 0, (TL / 2) - (SH / 2)])
                    difference()
                    {
                        cube(size = [L, SW, SH], center = true);

                        for(X = [1, -1])
                            translate(v = [0, X * ((SW / 2) - (((SW / 2) - TH) / 2)), -TH / 2 - 0.01])
                                cube(size = [L - (TH * 2), SW / 2, SH - TH], center = true);
                    }

                for(X = [1, -1])
                {
                    translate(v = [((L / 2) - (TL / 2)) * X, 0, 0])
                        triangle(size = [TL, SW, TL], dir = X);

                    translate(v = [((L / 2) + (((TH * 2) + TA) / 2) - 0.01) * X, 0, -LP])
                        difference()
                        {
                            cube(size = [(TH * 2) + TA, SW, LH], center = true);

                            for(Y = [1, -1])
                                translate(v = [-X * (TH / 2), Y * SW / 1.5, 0])
                                    cube(size = [TH + TA, SW, LH + 0.01], center = true);

                            translate(v = [(TA + (TH * 2)) / 2 * -X, -SW, LH / 2])
                                rotate (a = [0, 180 + (-90 * X) - 45, 0])
                                    cube(size = [(TA + TH) * 6, SW * 2, (TA + TH) * 6]);

                            for(Y = [1, -1])
                                translate(v = [(-0.01 * X) + TH - (TA / 2 * -X) + (TH * X), SW * 0.1666 * Y, (LH / 2) - TA - TH])
                                    rotate (a =[0, 45 - 90 + (90 * Y), 90])
                                        cube(size = [TH * 2, TH * 2, TH * 2]);

                            for(Y = [1, -1])
                                translate(v = [(-0.01 * X) +  - (TA / 2 * -X) + (TH * X), SW * 0.1666 * Y, -(LH / 2)])
                                    rotate (a =[45 - (45 * Y), 45 + 90 + (90 * X), 0])
                                        cube(size = [TH * 2, TH * 2, TH * 2]);
                        }
                }
            }

            for(X = [1, -1])
                for(Y = [1, -1])
                    translate(v = [((L / 2) - (TL / 2) + (TH / 1.5)) * X, Y * ((SW / 2) - (((SW / 2) - TH) / 2)), TH / 1.5])
                        triangle(size = [TL - (TH * 3.5), SW / 2, TL - (TH * 3.5)], dir = X);
        }
}

module wall()
{
    rotate(a = [180, 0, 0])
        difference()
        {
            // Main wall structure
            cube(size = [W, WW, H], center = true);

            // Remove outside section material
            for(X = [1, -1])
                for(Y = [1, -1])
                {
                    // Remove to create inset area
                    translate(v = [(W + CW) / 4 * X, Y * ((WW / 2) - (((WW / 2) - TH) / 2)), -TH])
                        roundedBox(size = [(W / 2) - (TH * 2) - (CW / 2), WW / 2, H], center = true, radius = R);

                    // Remove to create hole/frame
                    if(H - TH - FW - FW < (WR * 2))                   // Check if frame radius is valid for given height
                    {
                        // Frame radius is too big for height, limit for given height instead
                        translate(v = [(W + CW) / 4 * X, 0, (((H - TH) / 2) - HR - FW) - (TH / 2)])
                            rotate(a = [90, 0, 0])
                                cylinder(r = HR, h = WW / 2, center = true);
                    }

                    else
                    {
                        for(Z = [1, -1])
                            translate(v = [(W + CW) / 4 * X, 0, (Z * (((H - TH) / 2) - WR - FW)) - (TH / 2)])
                                rotate(a = [90, 0, 0])
                                    cylinder(r = WR, h = WW / 2, center = true);
                        translate(v = [(W + CW) / 4 * X, 0, -TH / 2])
                            cube(size = [(W / 2) - ((TH + FW) * 2) - (CW / 2), WW / 2, (2 * (((H - TH) / 2) - WR - FW)) - (TH / 2)], center = true);
                    }
                }

            // Remove to create inset in middle
            translate(v = [0, ((WW / 2) - (((WW / 2) - TH) / 2)), -TH])
                roundedBox(size = [CW, WW / 2, H], center = true, radius = R);
            translate(v = [0, -((WW / 2) - (((WW / 2) - TH) / 2)), 0])
                cube(size = [CW, WW / 2, H + 0.01], center = true);

            // Remove hole and channel for center support interlock
            translate(v = [0, 0, (H / 2) - HP - (HH / 2)])
            {
                cube(size = [HW, TH + 0.01, HH], center = true);
                translate(v = [0, 0, -(GH + HH - 0.01) / 2])
                    cube(size = [GW + TA, TH + 0.01, GH], center = true);
            }

            // Angle hole for printing
            for(X = [1, -1])
                translate(v = [X * HW / 2, -TH, (H / 2) - HP - HH])
                    rotate(a = [0, 45 + 90 + (X * 90), 0])
                        cube(size = [HW / 2, HW / 2, HW / 2]);
        }
}

module triangle(size, dir)
{
    difference()
    {
        cube(size, center = true);

        translate(v = [-(dir * size[0] / 2), -size[1], size[2] / 2])
            rotate(a = [0, 135, 0])
                cube(size = [size[0] * 1.5, size[1] * 2, size[2] * 1.5]);
    }
}

// --- from MCAD/boxes.scad
module roundedBox(size, radius, sidesonly)
{
	rot = [ [0,0,0], [90,0,90], [90,90,0] ];
	if (sidesonly)
	{
		cube(size - [2*radius,0,0], true);
		cube(size - [0,2*radius,0], true);
		for (x = [radius-size[0]/2, -radius+size[0]/2],
			y = [radius-size[1]/2, -radius+size[1]/2])
		{
			translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
		}
	}
	else
	{
		cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
		cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
		cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);

		for (axis = [0:2])
		{
			for (x = [radius-size[axis]/2, -radius+size[axis]/2],
				y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2])
			{
				rotate(rot[axis])
				translate([x,y,0])
					cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
			}
		}
		for (x = [radius-size[0]/2, -radius+size[0]/2],
			y = [radius-size[1]/2, -radius+size[1]/2],
			z = [radius-size[2]/2, -radius+size[2]/2])
		{
			translate([x,y,z]) sphere(radius);
		}
	}
}
```