[User]
Hey, I'm looking to get a custom honing guide designed for my sharpening steel. I have some specific needs for it and I think OpenSCAD would be the right tool for the job.

Essentially, I need a guide that will hold the honing steel at a specific angle, so I can easily maintain a consistent bevel when sharpening. The design should be a cone shape, cut down the middle, with a hole for the steel to fit through. I’ll want to be able to adjust the angle and the steel diameter, of course. I’m thinking a rubber band groove will be needed to secure the steel. Here are the specific parameters I need to be able to control:

*   **Sharpening Angle:** This is the primary adjustment; it should be in degrees.
*   **Honing Rod Diameter:** This will vary depending on the steel I'm using, so it should be adjustable in millimeters.
*   **Guide Height:** The overall height of the guide itself, in mm.
*   **Printer Nozzle Size:** The width of the guide's top wall will be dependent on the print nozzle size for adequate print quality, adjustable in mm.
*   **Rubber Band Groove Height:** How tall the groove should be, in mm.
*   **Rubber Band Groove Inset Depth:** How far from the outer surface the groove will be cut in, in mm.
*   **Halves Gap:** How much space there should be when the guide is split into two halves, in mm.
*   **Number of Cylinder Segments:** How many segments for the cylinders, mainly for visual quality.

The code should generate a file that allows for all of these adjustments. It should consist of two main modules: `honing_guide` and `band_cutout`. Within the `honing_guide` module, the main cone should be created, with the central hole for the rod, a rubber band groove, and the cut for splitting the cone into two halves. The `band_cutout` module should create the shape of the rubber band groove, which is a cutout from the outer shape of the guide. It would be amazing if the code includes comments as well!

Let me know if you need anything else from me!

[Assistant]
honing_guide.scad:
```
// Desired sharpening angle [deg]
angle = 19;
// Diameter of your honing steel [mm]
rod_diameter = 13.5;
/* [Advanced] */
// Desired height of angle guide [mm]
height = 30;
// Printer nozzle diameter [mm]
nozzle_size = 0.4;
// Height of inlay for rubber band [mm]
band_height = 3;
// Minimum depth of rubber band holder inlay [mm]
band_inset = 3.5;
// Width of cutout for splitting the halves [mm]
halves_gap = 3;
// Number of cylinder segment divisions
segments = 100;

/* [Hidden] */
eps = 0.001;

$fn = segments;
honing_guide();

module honing_guide() {
    top_wall_w = nozzle_size * 2;
    h_offset = top_wall_w / tan(angle);
    bottom_d = ((height + h_offset) * tan(angle)) * 2 + rod_diameter;
    top_d = rod_diameter + top_wall_w;
    band_d = (((height + h_offset - (0.5 * band_height)) * (2/3) ) * tan(angle)) - band_inset;

    // move to baseplate
    translate([0,0, height / 2])
        difference() {
            // main cone
            cylinder(h = height, d1 = bottom_d, d2 = top_d, center = true);
            // hollow out rod
            cylinder(h = height+eps, d = rod_diameter, center = true);
            // rubber band cutout
            translate([0,0, height * -(1/6)])
                band_cutout(band_height, rod_diameter + (band_d * 2), bottom_d);
            // split in 2
            cube([halves_gap, bottom_d+eps, height+eps], true);
        }
}

module band_cutout(height, inner_d, outer_d) {
    difference() {
        cylinder(h = height, d = outer_d, center = true);
        cylinder(h = height+eps, d = inner_d, center = true);
    }
}
```


[User]
I'd like to design a customizable die, specifically a trapezohedron. I'm looking for something that can be adjusted to have a different number of sides, as long as that number is even and at least six. I've got some parameters in mind, and I'd like the design to be fully parametric.

Here are the parameters I want to be able to control:

*   **`size`**: The overall size of the die.
*   **`die`**: The number of sides (must be even and >=6).
*   **`roundness`**: How rounded the corners are, as a factor of the die's size.
*   **`letter_ratio`**: The size of the text as a factor of the die's size.
*   **`depth_ratio`**: The depth of the text as a factor of the die's size.
*   **`sides`**: An array defining the text or numbers for each face of the die.
*   **`$fn`**: The number of facets used for rounding, affecting render times.
*    **`kite`**: A parameter to manually adjust the shape so that the polar triangles and equitorial triangles appear coplanar.
*   **`angular_fudge`**: An angle to rotate the numbers to align with the faces.
*  **`radial_fudge`**: A factor of size to translate the numbers to align with the faces.

I need the design to be a proper trapezohedron shape. The text should be placed on each face, and I want to be able to use numbers, text, or even unicode characters in the `sides` array. I'd like the numbers to be extruded and inset into the faces of the die.

Could you generate the OpenSCAD code for this? I'm not using any custom libraries, so I don't think any include files will be needed.

[Assistant]
trapezohedron.scad:
```
//Trapezohedron
//Ari M Diacou
//Jan 6, 2022

//Shared under Creative Commons License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
//see http://creativecommons.org/licenses/by-sa/3.0/

////////////////////// Parameters ////////////////////////
//The size of the die
size=25;
//The number of sides of the die
die=10;
//how round the corners should be as a factor of size
roundness=0.15;
//How big the text should be, as a factor of the size
letter_ratio=.3;
//How deep the text should be, as a factor of the size
depth_ratio=.03;
//The text that should appear on each side of the die (accepts numbers, text or unicode)
sides=[5, 10, 2, 8, 4, "6.", 7, 3, "9.", 1];
//How many facets create the rounded corners. This will significantly affect the refresh time.
$fn=20;//[4,8,12,16,20]
//How far from the equator the kite tips drift towards the poles. Adjust manually based on the number of sides so that the polar triangles and equitorial triangles appear coplanar. (for die=10, kite=.052)
kite=.052;
//The additional angle from 45 that numbers must be rotated to be plane-parallel with the faces (for die=10, angular_fudge=3
angular_fudge=3;
//The additional factor of size numbers must be translated to be coplanar with the faces (for die=10, radial_fudge=.125)
radial_fudge=.125;

/////////////////// Derived Parameters ///////////////////
equitorial_n=floor(die/2);

//////////////////////// Main ////////////////////////////
difference(){
//the trapezohedron
#hull(){
    for(i=[0:equitorial_n-1]){
        rotate([0,0,i*360/equitorial_n])
            translate(size*[.5,0,kite])
                sphere(d=roundness*size);
        rotate([0,0,(i+.5)*360/equitorial_n])
            translate(size*[.5,0,-kite])
                sphere(d=roundness*size);
        }
    translate(size*[0,0,.5])
        sphere(d=roundness*size);
    translate(size*[0,0,-.5])
        sphere(d=roundness*size);
    }
//top numbers
for(i=[0:die/2-1]){
        translate(.5*size*[cos((i+.5)*360/equitorial_n),sin((i+.5)*360/equitorial_n),+.5]) color("yellow")
            rotate([0,45+angular_fudge,(i+.5)*360/equitorial_n])
                rotate([0,0,90])
                    translate([0,0,(-radial_fudge-depth_ratio)*size+.05])
                        linear_extrude(.25*size)
                           text(str(sides[i]),size=size*letter_ratio,valign="center",halign="center");
}
//bottom numbers

for(i=[die/2:die-1]){
        translate(.5*size*[cos(i*360/equitorial_n),sin(i*360/equitorial_n),-.5]) color("yellow")
            rotate([180,-45-angular_fudge,i*360/equitorial_n])
                rotate([0,0,90])
                    translate([0,0,(-radial_fudge-depth_ratio)*size+.05])
                        linear_extrude(.25*size)
                           text(str(sides[i]),size=size*letter_ratio,valign="center",halign="center");
}
}
////////////////////// Functions /////////////////////////

```


[User]
I'm looking to design a customizable XYZ calibration tool for 3D printers, something that can be printed quickly and uses minimal material. I've seen a design that uses an axial structure, like a three-dimensional plus sign, with a central Z-axis tower and four arms extending along the X and Y axes. I need it to be parametric, so I can easily adjust the dimensions and some print settings.

Specifically, I need the following parameters:

*   **Dimensions:**
    *   `XLength`: Total length of the X-axis (the full horizontal span, not just one arm).
    *   `YLength`: Total length of the Y-axis (full vertical span).
    *   `ZLength`: Height of the central Z-axis tower.
    *   `XYTipLength`: Width of the tips at the end of each X and Y axis arm.

*   **Printer Settings:**
    *   `LayerHeight`: Height of each printed layer.
    *   `FirstLayerHeight`: Height of the first layer (usually thicker for better adhesion).
    *   `ExtrusionWidth`: Width of the line the printer lays down.

*   **Advanced:**
    *   `TowerEdges`: Number of sides for the Z tower (higher numbers make it more circle-like).
    *   `Offset`: An offset value to adjust for line width inconsistencies, especially where lines intersect/overlap.

Here's how I envision the design:

The X and Y axes should be a "double wide" line for the base, and "single wide" for the top, and a single center line for each arm.  They should intersect at the center, and then each have a solid tip at the end. I'd like the tips to have a distinctive shape, maybe with angled edges where they connect to the arms.  Each tip should be 2 lines wide, and the arm lines should be single width.  I also need small diagonal braces between the arms, and a circular cross-section for the central Z-axis. The Z-axis should taper from a larger diameter at the bottom to a smaller diameter at the top.

I'd like to have a small "X" added to the base of the X arm lines.

I'd also like to have the following calculations built in, so that the design is mostly automatic:
* `XHalfLength` and `YHalfLength` to quickly get the half-lengths of each arm.
* `LineW` as the extrusion width minus the offset.
* `LayerH` as the layer height minus the offset.
* `XYAvg` as the average of the X and Y lengths.
* `SideBraceLines` as a calculation from the `XYAvg` that is about 4.2 for the average of X and Y less than 121, and 6.1 otherwise.
* `SideBraceH` as a calculation from the `XYAvg` that is about 3 for the average of X and Y lengths equal to 100, and increases linearly with the average of X and Y.
* `SideBraceOffset` to space the diagonal braces from the tips.
* `MainBraceLines` as a calculation from the `XYAvg` that is about 6.1 for the average of X and Y less than 121, and increases linearly with the average of X and Y starting at 121.
* `MainBraceH` as a calculation from the `XYAvg` that is about 3.8 for the average of X and Y lengths equal to 0, and increases linearly with the average of X and Y.
* `BottomR` as a calculation from the Z length to determine the base radius of the Z cylinder.
* `TopR` as a calculation from the Z length to determine the top radius of the Z cylinder.
* `Deg` to get the degrees of the angle from the edge of the X arm to the edge of the Y arm.

Could you create the necessary OpenSCAD file(s) to generate this? I don't need any specific libraries used.

[Assistant]
xyzSCAD.scad:
```
/* [Dimensions (mm)] */

XLength=100; //[20:1:500]
YLength=100; //[20:1:500]
ZLength=100; //[20:1:500]
//How wide the 4 tips at the end of axes are.
XYTipLength = 5; //[2:0.5:20]

/* [Printer Settings (mm)] */

//Set smaller than nozzle width(usually 0.4mm). Bigger number means faster print.
LayerHeight = 0.35; //[0.1:0.01:0.8]
//By default the first layer is slightly thicker for bed adheision.
FirstLayerHeight = 0.2; //[0.1:0.01:0.8]
//Thickness of a printed line. Usually about 15% bigger than nozzle width.
ExtrusionWidth = 0.45;

/* [Advanced] */
//Higher number makes Z tower more circle-lish but sometimes causes slicing error.
TowerEdges = 4; //[4:1:30]
//Increase this when walls use more lines than they should. For reference, the XY tips should be 2 walls thick, and the rest just 1 wall thick.
Offset = 0.03;

//=========================
//==== Auto Calculate =====
//=========================
$fn = TowerEdges;
XHalfLength = XLength/2;
YHalfLength = YLength/2;
//FirstLineWMult = LineWidth/FirstLineWidth - Offset;
LineW = ExtrusionWidth - Offset;

LayerH = LayerHeight - Offset; // It cannot be higher than nozzle width in PrusaSlicer but you could theorically go higher
XYAvg = (XLength+YLength)/2;
SideBraceLines = XYAvg<121? 4.2: 6.1;
SideBraceH = 0.2*(XYAvg/100)+3;
SideBraceOffset = LineW*2;  //How far diagnal braces are from the tips
MainBraceLines = XYAvg<121? 6.1: 0.1*(XYAvg-121)+6.1;
MainBraceH = (XYAvg/100)+3.8;
BottomR = 0.005*ZLength+3.24-0.66/(0.01*ZLength+0.32)/(0.01*ZLength+0.32);
TopR = 0.007*ZLength+0.7;

Deg = atan(YHalfLength/XHalfLength);

//=========================
//===== Plane Cubes =======
//=========================
//Clockwise: 1=+x+y, 2=+x-y, 3=-x-y, 4=-x+y
//translate([0,0,-20])
//    cube(XHalfLength+50,YHalfLength+50,ZLength+50);
//translate([0,0,-20])
//    rotate([0,0,-90])
//    cube(XHalfLength+50,YHalfLength+50,ZLength+50);
//translate([0,0,-20])
//    rotate([0,0,180])
//    cube(XHalfLength+50,YHalfLength+50,ZLength+50);
//translate([0,0,-20])
//    rotate([0,0,90])
//    cube(XHalfLength+50,YHalfLength+50,ZLength+50);

//=========================
//======= Main Axis =======
//=========================

//=======X Axis=======
difference(){
translate([0,0,(FirstLayerHeight+LayerH)/2])
    cube([2*(XHalfLength-LineW),LineW*MainBraceLines,FirstLayerHeight+LayerH],center=true);
translate([0,0,-5])
    linear_extrude(10)
    circle(BottomR-LineW/2);
}
difference(){
translate([0,0,MainBraceH/2])
    cube([2*XHalfLength,LineW,MainBraceH],center=true);
translate([0,0,-5])
    linear_extrude(10)
    circle(BottomR-LineW/2);
}
//translate([0,0,MainBraceH/4])
//   cube([BottomR*2,LineW,MainBraceH/2],center=true);

// +X Tip
translate([XHalfLength-LineW,0,MainBraceH/2])
    cube([LineW*2,XYTipLength,MainBraceH],center=true);
translate([XHalfLength,-XYTipLength/2,0])
    rotate([0,0,160])
    cube([LineW*2,2,MainBraceH]);
translate([XHalfLength,XYTipLength/2,0])
    rotate([0,0,110])
    cube([2,LineW*2,MainBraceH]);
intersection(){
cube([XLength,YLength,50],center=true);
translate([XHalfLength,0,(FirstLayerHeight+LayerH)/2])
    rotate([0,0,45])
    cube([XYTipLength*0.7,XYTipLength*0.7,FirstLayerHeight+LayerH],center=true);
}
// -X Tip
translate([-(XHalfLength-LineW),0,MainBraceH/2])
    cube([LineW*2,XYTipLength,MainBraceH],center=true);
translate([-XHalfLength,-XYTipLength/2,0])
    rotate([0,0,-70])
    cube([2,LineW*2,MainBraceH]);
translate([-XHalfLength,XYTipLength/2,0])
    rotate([0,0,-20])
    cube([LineW*2,2,MainBraceH]);
intersection(){
cube([XLength,YLength,50],center=true);
translate([-XHalfLength,0,(FirstLayerHeight+LayerH)/2])
    rotate([0,0,45])
    cube([XYTipLength*0.7,XYTipLength*0.7,FirstLayerHeight+LayerH],center=true);
}
// Letter X
XSize = 2;
XDeg = 40;
XPos = (YHalfLength-MainBraceLines*LineW/2-SideBraceLines*LineW/cos(Deg))/tan(Deg)-XSize/tan(Deg)-SideBraceOffset;
intersection(){
translate([XPos,LineW*MainBraceLines/2,0])
    rotate([0,0,90+XDeg])
    cube([LineW*tan(XDeg)+XSize/cos(XDeg),LineW,FirstLayerHeight+LayerH]);
translate([XPos,MainBraceLines*LineW/2,-1])
    rotate([0,0,90])
    cube([XSize,LineW/cos(XDeg)+XSize*tan(XDeg),3]);
}
intersection(){
translate([XPos,LineW*MainBraceLines/2+XSize,0])
    rotate([0,0,90-XDeg])
    mirror([1,0,0])
    cube([LineW*tan(XDeg)+XSize/cos(XDeg),LineW,FirstLayerHeight+LayerH]);
translate([XPos,MainBraceLines*LineW/2,-1])
    rotate([0,0,90])
    cube([XSize,LineW/cos(XDeg)+XSize*tan(XDeg),3]);
}

//=======Y Axis=======
difference(){
translate([0,0,(FirstLayerHeight+LayerH)/2])
    cube([LineW*MainBraceLines,2*(YHalfLength-LineW),FirstLayerHeight+LayerH],center=true);
translate([0,0,-5])
    linear_extrude(10)
    circle(BottomR-LineW/2);
}
difference(){
translate([0,0,MainBraceH/2])
    cube([LineW,2*YHalfLength,MainBraceH],center=true);
translate([0,0,-5])
    linear_extrude(10)
    circle(BottomR-LineW/2);
}
//translate([0,0,MainBraceH/4])
//   cube([LineW,BottomR*2,MainBraceH/2],center=true);

// +Y Tip
rotate([0,0,90])
translate([YHalfLength-LineW,0,MainBraceH/2])
    cube([LineW*2,XYTipLength,MainBraceH],center=true);
rotate([0,0,90])
translate([YHalfLength,-XYTipLength/2,0])
    rotate([0,0,160])
    cube([LineW*2,2,MainBraceH]);
rotate([0,0,90])
translate([YHalfLength,XYTipLength/2,0])
    rotate([0,0,110])
    cube([2,LineW*2,MainBraceH]);
intersection(){
cube([XLength,YLength,50],center=true);
translate([0,YHalfLength,(FirstLayerHeight+LayerH)/2])
    rotate([0,0,45])
    cube([XYTipLength*0.7,XYTipLength*0.7,FirstLayerHeight+LayerH],center=true);
}
// -Y Tip
rotate([0,0,90])
translate([-(YHalfLength-LineW),0,MainBraceH/2])
    cube([LineW*2,XYTipLength,MainBraceH],center=true);
rotate([0,0,90])
translate([-YHalfLength,-XYTipLength/2,0])
    rotate([0,0,-70])
    cube([2,LineW*2,MainBraceH]);
rotate([0,0,90])
translate([-YHalfLength,XYTipLength/2,0])
    rotate([0,0,-20])
    cube([LineW*2,2,MainBraceH]);
intersection(){
cube([XLength,YLength,50],center=true);
translate([0,-YHalfLength,(FirstLayerHeight+LayerH)/2])
    rotate([0,0,45])
    cube([XYTipLength*0.7,XYTipLength*0.7,FirstLayerHeight+LayerH],center=true);
}

//=========================
//====== Side Braces ======
//=========================
//Clockwise: 1=+x+y, 2=+x-y, 3=-x-y, 4=-x+y

//=======Plane[+x+y]Origin[1,0]=======
translate([XHalfLength-SideBraceOffset,0,0])
    rotate([0,0,270-Deg])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset)/cos(Deg))
    square([SideBraceLines*LineW,FirstLayerHeight+LayerH]);
translate([-SideBraceOffset*SideBraceLines/2/sin(Deg),0,0])
    translate([XHalfLength,0,0])
    rotate([0,0,270-Deg])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset*SideBraceLines/2/sin(Deg))/cos(Deg))
    square([LineW,SideBraceH]);

//=======Plane[+x-y]Origin[0,-1]=======
translate([0,-YHalfLength+SideBraceOffset,0])
    rotate([0,0,90+Deg])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset)/cos(Deg))
    square([SideBraceLines*LineW,FirstLayerHeight+LayerH]);
translate([0,LineW*SideBraceLines/2/cos(Deg)+SideBraceOffset,0])
    translate([0,-YHalfLength,0])
    rotate([0,0,90+Deg])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset-LineW*SideBraceLines/2/sin(Deg))/cos(Deg))
    square([LineW,SideBraceH]);

//=======Plane[-x-y]Origin[-1,0]=======
translate([-XHalfLength+SideBraceOffset,0,0])
    rotate([0,0,90-Deg])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset)/cos(Deg))
    square([SideBraceLines*LineW,FirstLayerHeight+LayerH]);
translate([LineW*SideBraceLines/2/sin(Deg)+SideBraceOffset,0,0])
    translate([-XHalfLength,0,0])
    rotate([0,0,90-Deg])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset-LineW*SideBraceLines/2/sin(Deg))/cos(Deg))
    square([LineW,SideBraceH]);

//=======Plane[-x+y]Origin[0,1]=======
translate([0,YHalfLength-SideBraceOffset,0])
    rotate([0,0,Deg-90])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset)/cos(Deg))
    square([SideBraceLines*LineW,FirstLayerHeight+LayerH]);
translate([0,-LineW*SideBraceLines/2/cos(Deg)-SideBraceOffset,0])
    translate([0,YHalfLength,0])
    rotate([0,0,Deg-90])
    rotate([90,0,0])
    linear_extrude((XHalfLength-SideBraceOffset-LineW*SideBraceLines/2/sin(Deg))/cos(Deg))
    square([LineW,SideBraceH]);

//=========================
//======== Z Axis =========
//=========================

difference(){
linear_extrude(ZLength, scale=TopR/BottomR)
    circle(BottomR);

translate([0,0,-0.001])
    linear_extrude(ZLength+0.002, scale=(TopR-LineW)/BottomR)
    circle(BottomR-LineW-Offset*2);
}
cylinder(FirstLayerHeight+LayerH, BottomR, BottomR);
```


[User]
I'm looking to create a parametric design in OpenSCAD for a laser mirror alignment tool, specifically for a K40 laser. I've seen a few designs online, but I'd like to make one that is fully customizable and well-suited for my needs.

Essentially, I need a mount that fits snugly onto the laser head and holds a paper target. The key features I'm looking for are:

*   **Customizable Mount:** The mount needs to have parameters for:
    *   Mounting Diameter (the diameter of the cylindrical part that fits into the laser head)
    *   Mounting Tolerance (a small allowance to ensure a good fit)
    *   Mounting Height (the total height of the mount)
    *   Mounting Cutout Height (the height of a cutout area on the side of the mount)
    *   Mounting Cutout Width (the width of that side cutout)
    *   Wall Thickness (the thickness of the material forming the mount)

*   **Target Support:**  A target area with:
    *   Target Radius (the radius of the circular paper target)
    *   Target Slot Depth (the depth of the slot that the target sits in)
    *   Target Slot Width (either a fixed width or automatically sized based on the target radius)

*   **Mirror Opening:** There should be an opening through the tool to allow for a visual alignment to the mirror.  This needs:
    *   Mirror Opening Diameter (the diameter of the through-hole)

*   **Construction Notes:**  The tool should be constructed using a cylinder for the main mount, a cutout on the side, a slot on the bottom to hold the target and then a central mirror opening through everything.

I'd like the design to be based on a difference of solids, making use of `cylinder()` and `cube()` primitives. If possible, could you create a fully parametric OpenSCAD file that allows for easy adjustment of all these parameters? I'm not attached to the names I've given above, if there's a better way of describing them feel free to make those changes.

[Assistant]
K40_Mirror_Alignment_v1.0.scad:
```
/*
K40 Laser Mirror Alignment Tool - Customizable (c) by Surlum

K40 Laser Mirror Alignment Tool - Customizable is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License.

This license is available for viewing at:
    https://creativecommons.org/licenses/by-nc-sa/4.0/
*/
/* [ Mount ] */
// --- Default: 26.035
Mounting_Diameter = 26.035;

// --- Default: 0.1
Mounting_Tolerance = 0.1;

// --- Default: 28.4988
Mounting_Height = 28.4988;

// --- Default: 20
Mounting_Cutout_Height = 20;

// --- Default: 16
Mounting_Cutout_Width = 16;

// --- Default: 1
Wall_Thickness = 1;

/* [ Target ] */

// --- Default: 12    Half: 5.05
Target_Radius = 12;

// --- Default: 2
Target_Slot_Depth = 2;

// --- 0 - Automatic    # - Width
Target_Slot_Width = 0;

/* [ Mirror Opening] */
// --- Default: 10.1
Mirror_Opening_Diameter = 10.1;

// ===============================================
// ==========  STOP DO EDIT NOT BELOW  ===========
// ===============================================

// Alias Definitions
Paper_Target_Radius = Target_Radius;
Paper_Target_Depth = Target_Slot_Depth;
Paper_Target_Width = Target_Slot_Width;

// Radius of internal cylinder for cutout operation
mountRadius = (Mounting_Diameter / 2) + Mounting_Tolerance;
// Paper target width for cutout operation
slotWidth = (Paper_Target_Width > 0) ? (Paper_Target_Width) : ((Paper_Target_Radius * 2) + 0.5);

// MAIN
main();

module main() {
    base();
    target();
}

module base() {
    difference() {
        cylinder(h = Mounting_Height, r1 = mountRadius + Wall_Thickness, r2 = mountRadius + Wall_Thickness, center = true, $fn=180);
        cylinder(h = Mounting_Height + 1, r1 = mountRadius, r2 = mountRadius, center = true, $fn=180);
        translate([0,-5,0]) {
            mirror_hole();
        }
        cutout_cube();
    }
}

module target() {
    difference() {
        translate([0,(mountRadius + (Paper_Target_Depth / 2) + Wall_Thickness) * -1,0]) {
            difference() {
                cube([slotWidth + 2, Paper_Target_Depth + 2, Mounting_Height], center = true);
                cube([slotWidth, Paper_Target_Depth, Mounting_Height + 1], center = true);
                mirror_hole();
                target_hole();
            }
        }
        mirror_hole();
    }
}

module cutout_cube() {
    translate([0, (Mounting_Diameter / 2) + (Wall_Thickness / 2), (Mounting_Height - Mounting_Cutout_Height)]) {
        cube([Mounting_Cutout_Width, Mounting_Diameter + Wall_Thickness, Mounting_Height], center = true);
    }
}

module mirror_hole() {
    translate([0,-(Wall_Thickness + Mounting_Diameter) / 2,0]) {
        rotate([90, 0, 0]) {
            cylinder(h = (Mounting_Diameter / 2) + Wall_Thickness, r1 = (Mirror_Opening_Diameter / 2), r2 = (Mirror_Opening_Diameter / 2), center = true, $fn = 180);
        }
    }
}

module target_hole() {
    translate([0,-3,0]) {
        rotate([90, 0, 0]) {
            cylinder(h = 5, r1 = Paper_Target_Radius, r2 = Paper_Target_Radius, center=true, $fn=180);
        }
    }
}
/* Physical Measurements (mm):

    Mounting Diameter       = 26.035  // Base Opening
    Mounting Height         = 28.4988 // Base Height
    Mirror Opening Diameter = 9.8298  // Mirror Opening

    b = 9.525        // Base bottom to bottom of mirror opening
    x = 9.398        // Base top to top of mirror opening
    y1 = 8.509       // Base left to left of mirror opening
    y2 = 8.509       // Base right to right of mirror opening

*/
```


[User]
I need help creating an OpenSCAD design for a Brio-compatible train track connector. I'm attaching a basic SCAD file I've been using as a starting point, but I'd like to make it fully parametric, with some features that are easier to adjust.

Essentially, I'm trying to model the basic connector piece, which is a rectangular base with a smaller cylinder on one end and a larger cylinder on the other. These cylinders are the "heads" that fit into the track pieces. The overall shape is kind of like a bone.

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

*   **Overall Height (H):** The vertical height of the connector.
*   **Center-to-Center Distance:** The distance between the center points of the two cylindrical heads.
*   **Large Head Diameter:** The diameter of the larger cylindrical head.
*   **Small Head Diameter:** The diameter of the smaller cylindrical head.
*   **Neck Width:** The width of the rectangular base between the two heads.

My initial file also includes a way to put a few small cylindrical "alignment" posts on the top, positioned diagonally from each of the heads' center points, but that's not critical if it's too complicated.

I'd like to be able to easily change all these values using customizer variables, and I'd love to see this implemented in a clean, parametric way. I'd really appreciate it if you could produce a fully functional OpenSCAD file (or files if necessary). I'm not really attached to any particular libraries, but if they help make it easier that's fine.

[Assistant]
brio-connector.scad:
```
/* [Rendering Details] */
// Arc resolution ($fn)
$fn = 100;

/* [Dimensions] */
// Z Height (mm) of piece
H = 11.0; //[8:0.1:15]

// mm between centerpoints of each head
ctr_to_ctr = 22.5; // [21 : 0.1 : 25]

//...
head_diameter_large = 12; // [10 : 0.1 : 14]

//...
head_diameter_small = 11; // [9 : 0.1 : 13]

//...
neck_width = 6.5; // [5 : 0.1 : 8]

module __CustomizerLimit__() {}

ptx = ctr_to_ctr / 2;

translate([-ptx, -2.5, 0])
cube([ptx, 5, H]);

translate([-ptx, 0, 0])
cylinder(h=H, d=head_diameter_small);

translate([0, -neck_width/2, 0])
cube([ptx, neck_width, H]);

translate([ptx, 0, 0])
cylinder(h=H, d=head_diameter_large);

tx = head_diameter_large/2 * sin(45);

for (x = [ptx + tx, ptx - tx]) {
  for ( y  = [ -tx, tx]) {
    translate([x, y, 0])
    cylinder(d=1, h=H);
  }
}

```


[User]
I'm looking to create a customizable drawer for a small parts storage rack, similar to the one I found on Thingiverse (link provided). I'd like the design to be parametric so I can adjust various aspects using variables.

Specifically, the drawer should have the following features:

*   **Overall Dimensions:** I need to be able to set the outer width, depth, and height of the drawer in millimeters.
*   **Shell Thickness:** I need a variable to control the thickness of the drawer's walls.
*   **Internal Divisions:** I'd like to be able to specify the number of divisions both along the width and depth of the drawer.
*   **Back Tab:** The drawer should have a back tab with a customizable height.
*   **Text Labels:** I need to add three text labels at different locations:
    *   One centered on the front face of the drawer.
    *   One in the top right corner of the front face.
    *   One in the top left corner of the front face.
    * I also need to control the font and size for each text label.
*   **Grip Opening:** The drawer should have a grip opening on the front, and I need to be able to choose between a cylinder or a sphere shape for the opening, and adjust the size of the opening as a fraction of the inner width.
*   **Font:** The font for the text labels should be customizable.

Could you generate the necessary OpenSCAD code to achieve this? I would prefer not to rely on any external libraries.

[Assistant]
drawer.scad:
```
//OUTER width in mm
drawer_width = 30;

//OUTER depth in mm, excluding text
drawer_depth = 70;

//OUTER height in mm, including tab
drawer_height = 25;

//Shell thickness in mm
thickness = 1.5;

//Number of divisions on width
divisions_width = 1;

//Number of divisions on depth
divisions_depth = 1;

//Back tab height
tab_height = 3.3;

//Text 1
text1 = "100";

//Font height 1
font_height1 = 10; //[0.1:0.1:20]

//Text 2 (top right)
text2 = "kΩ";

//Font height 2
font_height2 = 3; //[1:0.1:5]

//Text 3 (top left)
text3 = "";

//Font height 3
font_height3 = 3; //[1:0.1:5]

//Font
font="DIN Alternate";

//Grip opening fraction of width
open_fraction=0.70; //[0.00:0.01:1.00]

//Grip opening type
open_type = "Cylinder"; //["Cylinder","Sphere"]

drawer_width_inner = drawer_width - 2*thickness;
drawer_depth_inner = drawer_depth - 2*thickness;
drawer_height_inner = drawer_height - tab_height - thickness;
rayon = open_fraction * drawer_width_inner/2;

//Main box
difference() {
    union() {
        difference() {
            cube([drawer_width, drawer_depth, drawer_height_inner+thickness]);
            translate([thickness, thickness, thickness]) {
                cube([drawer_width_inner, drawer_depth_inner, drawer_height]);
            }
        }

        //Divisions
        if (divisions_width > 1)
            for(division = [1 : 1 : divisions_width - 1]) {
                translate([division * drawer_width/divisions_width,
                           drawer_depth / 2,
                           (drawer_height - tab_height)/2])
                cube([thickness, drawer_depth, (drawer_height - tab_height)], center = true);
            }
        if (divisions_depth > 1)
            for(division = [1 : 1 : divisions_depth - 1]) {
                translate([drawer_width / 2,
                           division * drawer_depth/divisions_depth,
                           (drawer_height - tab_height)/2])
                cube([drawer_width, thickness, (drawer_height - tab_height)], center = true);
            }
    }

    //Grip opening
    translate([drawer_width/2, -0.01, drawer_height_inner+thickness]) {
        rotate([-90,0,0]) {
            if (open_type == "Sphere")
                sphere(rayon, $fn=100);
            if (open_type == "Cylinder")
                cylinder(r=rayon, h=5*thickness, $fn=100);
        }
    }
}

//Back tab
translate([drawer_width/2, drawer_depth - thickness/2, drawer_height - tab_height/2])
    cube([drawer_width - 2*4, thickness, tab_height], center=true);

//Text 1
color("SlateGray", 1.0)
translate([drawer_width/2, 0, 2])
    rotate([90,0,0])
    linear_extrude(height=1.5,convexity = 10)
        text(text1, size=font_height1, font=font, halign="center", valign="baseline");

//Text 2
color("SlateGray", 1.0)
translate([drawer_width - 0.5, 0, drawer_height_inner])
    rotate([90,0,0])
    linear_extrude(height=1.0,convexity = 10)
        text(text2, size=font_height2, font=font, halign="right", valign="top");

//Text 3
color("SlateGray", 1.0)
translate([0.5, 0, drawer_height_inner])
    rotate([90,0,0])
    linear_extrude(height=1.0,convexity = 10)
        text(text3, size=font_height3, font=font, halign="left", valign="top");
```


[User]
I'd like to design a modular storage rack for small parts drawers, similar to the one described in the provided text and SCAD file. I need a parametric design in OpenSCAD that allows for easy customization of various dimensions and features. Here's what I'm looking for:

**Core Functionality:**

*   **Modular Rack:** The rack should consist of individual cells that can be arranged in a grid pattern. The number of cells in the x and y directions should be configurable (e.g., `x_modules`, `y_modules`).
*   **Drawer Dimensions:** The inner dimensions of each cell should be determined by parameters for the drawer's outer width, depth, and height (e.g., `drawer_width`, `drawer_depth`, `drawer_height`).
*   **Clearance:** A clearance parameter (e.g., `clearence`) should specify the space between the drawer and the rack walls.
*   **Wall Thickness:** The wall thickness of the rack should be customizable (e.g., `thickness`).
*   **Overhang:** There should be a configurable overhang at the top of each cell that acts as a stop for the drawer (e.g., `overhang`).
*   **Slider Width:**  A parameter should specify the width of the rails/sliders within each cell (e.g., `slider_width`).
*   **Individual Cell Design:**  The individual cells should have a solid back, and the openings at the front, top and bottom.  The top and bottom rails should be inset from the front, allowing the drawer to slide in.

**Optional Features:**

*   **Fastening Holes:**  There should be an option to include fastening holes for mounting the rack to a surface. The size and position of these holes should be determined by parameters (`fastening` boolean, `fastening_area_side_length`, and `fastening_hole`). These fastening holes need to be located at the corners of the rack, on the faces that adjoin the other racks in the grid pattern.
*   **Hexagonal Side Pattern:** I want a configurable hexagonal pattern on the sides of the rack, with three options: `None` (no pattern), `Inner` (pattern only on inner rack walls), and `Through` (pattern through all walls). The size of the hexagons should be determined by the radius parameter `radius`, and I expect that the generated pattern will use spacing to make it as even as possible.

**Parametric Design:**

I'd like all of the above properties to be easily modifiable via variables at the top of the SCAD file, and I don't expect to have any nested modules inside the top level module that isn't either for one of the features listed above or a mathematical helper. I do not expect you to use any external libraries like BOSL or MCAD. The program should generate a complete rack based on these parameters.

[Assistant]
rack.scad:
```
//Drawer OUTER width in mm
drawer_width = 30;

//Drawer OUTER depth in mm
drawer_depth = 70;

//Drawer OUTER height in mm
drawer_height = 25;

//Wall thickness in mm
thickness = 1.75;

//Single side clearense between drawer and rack in mm
clearence = 1.25;

//Opening top overhang in mm
overhang = 2.9;

//Slider width in mm
slider_width = 8;

//Number of drawers in x-axis
x_modules = 3;

//Number of drawers in y-axis
y_modules = 5;

//Generate fastening holes
fastening = false;

//Side length (in mm) for fastening area
fastening_area_side_length = 15.5;

//Fastening hole diameter in mm
fastening_hole = 3.6;

//Hexagonal side pattern
side_pattern = "None"; //["None", "Inner", "Through"]

//Hexagon radius
radius = 3.5;

width_inner = drawer_width + 2*clearence;
width_outer = width_inner + 2*thickness;
height_inner = drawer_height + clearence;
height_outer = height_inner + 2*thickness;

module case(top=false,bottom=false,left=false,right=false) {
    difference() {
        union() {
            //Fastening hole area
            if(fastening) {
                if ((bottom || top) && (left || right))
                    rotate([0, 180, 0])
                        translate ([left ? -fastening_area_side_length - thickness : -width_outer,
                                    bottom ? 0 : height_outer-thickness - fastening_area_side_length,
                                    -thickness])
                                cube([thickness + fastening_area_side_length, thickness + fastening_area_side_length, thickness]);
           }
            difference() {
                //A solid block
                cube([width_outer, height_outer, drawer_depth + thickness]);

                //Make block a shell
                translate([thickness, thickness, thickness]) {
                    cube([width_inner, height_inner, drawer_depth + 0.02]);
                }

                //Back opening
                translate([width_outer/2, height_outer/2, thickness/2]) {
                    cube([width_inner, height_outer - 8*thickness, thickness + 1], center=true);
                }

                //Top interspacing
                if(!bottom) {
                    translate([thickness + slider_width, -1, thickness + slider_width]) {
                        cube([width_inner - 2*slider_width, 5*thickness, drawer_depth]);
                    }
                }

                //Bottom interspacing
                if(!top) {
                    translate([thickness + slider_width, height_inner, thickness + slider_width]) {
                        cube([width_inner - 2*slider_width, 5*thickness, drawer_depth]);
                    }
                }
            }
        }

        //Fastening holes
        if(fastening) {
            if ((bottom || top) && (left || right))
                rotate([0, 180, 0])
                    translate([fastening_area_side_length/2 +
                                    (left ? - thickness - fastening_area_side_length :
                                    -width_outer + thickness),
                               (bottom ? fastening_area_side_length/2 + thickness :
                                         height_outer - thickness - fastening_area_side_length/2),
                               -thickness - 0.01]) {
                                           cylinder($fn=100, h=thickness+2, d=fastening_hole);
                                           cylinder($fn=100, h=(fastening_hole*1.75)/2, d1=fastening_hole*1.75, d2=0);
                                       }
        }
    }

    //Top overhang
    translate([0, height_outer - overhang - thickness, drawer_depth])
        cube([width_outer, overhang + thickness, thickness]);
}

difference() {
    for (x_pos = [0 : x_modules - 1]) {
        for (y_pos = [0 : y_modules - 1]) {
            translate([x_pos*(width_inner + thickness),
                       y_pos*(height_inner + thickness),
                       0])
                case(top    = y_pos==y_modules - 1,
                     bottom = y_pos==0,
                     left   = x_pos==0,
                     right  = x_pos==x_modules - 1);
        }
    }

    //Hexagonal side pattern
    if(side_pattern != "None") {
        z_hole_spacing = 3;
        hole_buffer = 4;
        z_holes = floor((drawer_depth - hole_buffer)/(2*radius + z_hole_spacing));
        y_holes = floor((height_inner - hole_buffer)/(2*radius));
        for (storey = [0:y_modules-1]) {     // For every storey
            for (row = [0:y_holes-1]) {      // For every row of hexagons on that storey
                for (hexagon = [0:(row%2==0 ? z_holes-2 : z_holes-1)]) {    // For every hexagon on that row
                    even_row_offset = row%2==0 ? drawer_depth/z_holes/2 : 0;
                    translate([side_pattern == "Inner" ? thickness : -1,
                               storey*(height_inner + thickness) + hole_buffer + row*((height_inner - hole_buffer)/y_holes) + radius,
                               hexagon*(drawer_depth/z_holes) + radius + thickness + z_hole_spacing/2 + even_row_offset])
                        rotate([0, 90, 0])
                            cylinder($fn=6,
                                     h=x_modules*width_outer + 0.02 + (side_pattern == "Inner" ? -(x_modules+2)*thickness : 0),
                                     r=radius);
                }
            }
        }
    }
}

```


[User]
Hey, I'm looking to get a parametric battery holder designed in OpenSCAD. I need it to be pretty flexible, able to handle different types of batteries and arrangements. I saw a design online that had some similar functionality, but I'd like a fresh design that I can easily customize.

Here are the general parameters I'd need:

*   **Base Dimensions:** I need to be able to set the overall width, length, and height of the base. Also, I need to specify a corner radius for rounding the base. There also needs to be a general spacing parameter for the distance from the edge of the base and the inner spacing between batteries.
*   **Battery Blocks:** The design needs to support AA, AAA, CR2032, and 9-volt (PP3) batteries. I'd like to be able to enable or disable each type of block independently.

For each battery block, I need these settings:

*   **Position:** The battery block should be able to be placed either below, or to the right of any existing blocks.
*   **Alignment:** The batteries within each block can be laid out horizontally or vertically.
*   **Level Alignment:** It needs to be able to define a Z-level, either relative to a main specified height, or relative to a local level.
*   **Local Level Height:** If the level align is local, I need a way to specify the height of that level.
*   **Arrangement:** For AA and AAA, the block should allow for "plain", "shifted" or "honeycomb" arrangements. I'd also need the rows and columns of batteries for each of the blocks.
*   **Element spacing:** For CR2032, a "spacing" parameter to determine the distance between the individual batteries is needed. This should be present for 9-volts as well.
*   **Rounded corners:** I need to be able to specify if CR2032 and 9-volt blocks are rounded, or square.
*   **Deltas:** Each block needs an X and Y delta offset to tweak its position.

Finally, I'd like to be able to specify the circle detail level using the `$fn` variable. I'm hoping to get this all into one scad file, but if it needs to be split up, I'm okay with that, too. I'm not using any specific libraries, so a design that doesn't depend on them would be great. Could you help me out with this?

[Assistant]
battaries_box_insert.scad:
```
// preview[view:south, tilt:top diagonal]

/* [General] */
Base_width = 63.5;
Base_length = 78.37;
Base_heigth = 37.3;
Base_radius = 6.0;
Base_spacing = 2;
Inner_spacing = 2.2;
Main_leveling_height = 13.2;
Circle_detalisation = 60; //[3:100]

/* [AA Block] */
AA_block_is_on = true;
AA_block_align = "vertical";//[horizontal:Horizontal, vertical:Vertical]
AA_block_level_align = "main";//[main:Main, local:Local]
AA_block_local_level_height = 13.5;
AA_block_mode = "plain";//[plain:Plain, shifted:Shifted, honey:Honey]
AA_block_rows = 3;
AA_block_columns = 4;
AA_delta_x = 0;
AA_delta_y = -0.7;

/* [AAA Block] */
AAA_block_is_on = true;
AAA_block_position = "right";//[down:Down, right:Right]
AAA_block_align = "vertical";//[horizontal:Horizontal, vertical:Vertical]
AAA_block_level_align = "main";//[main:Main, local:Local]
AAA_block_local_level_height = 13.5;
AAA_block_mode = "plain";//[plain:Plain, shifted:Shifted, honey:Honey]
AAA_block_rows = 2;
AAA_block_columns = 5;
AAA_delta_x = -0.7;
AAA_delta_y = 1.9;

/* [CR2032 Block] */
CR2032_block_is_on = true;
CR2032_block_rounded = true;
CR2032_block_spacing = 8;
CR2032_block_position = "right";//[down:Down, right:Right]
CR2032_element_align = "vertical";//[horizontal:Horizontal, vertical:Vertical]
CR2032_block_level_align = "local";//[main:Main, local:Local]
CR2032_block_local_level_height = 9;
CR2032_block_rows = 2;
CR2032_block_columns = 1;
CR2032_delta_x = -1.1;
CR2032_delta_y = 4.95;

/* [9-volt Block] */
9_volt_block_is_on = false;
9_volt_block_rounded = false;
9_volt_block_spacing = 1.5;
9_volt_block_position = "down";//[down:Down, right:Right]
9_volt_element_align = "horizontal";//[horizontal:Horizontal, vertical:Vertical]
9_volt_block_level_align = "main";//[main:Main, local:Local]
9_volt_block_local_level_height = 13.5;
9_volt_block_rows = 2;
9_volt_block_columns = 3;
9_volt_delta_x = 0;
9_volt_delta_y = 0;

/* [Hidden] */
// Constants
c_aa_width = 15.3;
c_aa_height = 50.5;
c_aaa_width = 11.3;
c_aaa_height = 45;
c_cr2032_width = 21;
c_cr2032_height = 3.7;
c_pp3_width = 27.5;
c_pp3_depth = 18.5;
c_pp3_height = 49.5;
c_pp3_radius = 1;

// General
c_base_spacing = Base_spacing;
c_inner_spacing = Inner_spacing;
$fn = Circle_detalisation;

v_x0 = 0;
v_y0 = 0;
v_block_0_width = 0;
v_block_0_height = 0;
v_all_0_width = 0;
v_all_0_height = 0;

// AA block calculation
v_x1_aa = AA_block_is_on == true
    ? v_all_0_height
    : 0;
v_y1_aa = AA_block_is_on == true
    ? v_all_0_width
    : 0;
v_block_1_width_aa = AA_block_is_on == true
    ? AA_block_align == "horizontal"
        ? AA_block_mode != "shifted" || AA_block_rows == 1
            ? AA_block_columns * c_aa_width + c_inner_spacing
            : (AA_block_columns+0.5) * c_aa_width + c_inner_spacing
        : AA_block_mode == "plain"
            ? c_aa_width * AA_block_rows + c_inner_spacing
            : c_aa_width * (0.866*(AA_block_rows-AA_block_rows%2)/2
                + (AA_block_rows%2+(AA_block_rows-AA_block_rows%2)/2)) + c_inner_spacing
    : 0;
v_block_1_height_aa = AA_block_is_on == true
    ? AA_block_align == "horizontal"
        ? AA_block_mode == "plain"
            ? c_aa_width * AA_block_rows + c_inner_spacing
            : c_aa_width * (0.866*(AA_block_rows-AA_block_rows%2)/2
                + (AA_block_rows%2+(AA_block_rows-AA_block_rows%2)/2)) + c_inner_spacing
        : AA_block_mode != "shifted" || AA_block_rows == 1
            ? AA_block_columns * c_aa_width + c_inner_spacing
            : (AA_block_columns+0.5) * c_aa_width + c_inner_spacing
    : 0;
v_all_1_width = AA_block_is_on == true
    ? max(v_block_0_width,v_block_1_width_aa)
    : v_all_0_width;
v_all_1_height = AA_block_is_on == true
    ? max(v_block_0_height,v_block_1_height_aa)
    : v_all_0_height;

// AAA block calculation
v_x2_aaa = AAA_block_is_on == true
    ? AAA_block_position == "down"
        ? v_all_1_height
        : 0
    : 0;
v_y2_aaa = AAA_block_is_on == true
    ? AAA_block_position == "down"
        ? 0
        : v_all_1_width
    : 0;
v_block_2_width_aaa = AAA_block_is_on == true
    ? AAA_block_align == "horizontal"
        ? AAA_block_mode != "shifted" || AAA_block_rows == 1
            ? AAA_block_columns * c_aaa_width + c_inner_spacing
            : (AAA_block_columns+0.5) * c_aaa_width + c_inner_spacing
        : AAA_block_mode == "plain"
            ? c_aaa_width * AAA_block_rows + c_inner_spacing
            : c_aaa_width * (0.866*(AAA_block_rows-AAA_block_rows%2)/2
                + (AAA_block_rows%2+(AAA_block_rows-AAA_block_rows%2)/2)) + c_inner_spacing
    : 0;
v_block_2_height_aaa = AAA_block_is_on == true
    ? AAA_block_align == "horizontal"
        ? AAA_block_mode == "plain"
            ? c_aaa_width * AAA_block_rows + c_inner_spacing
            : c_aaa_width * (0.866*(AAA_block_rows-AAA_block_rows%2)/2
                + (AAA_block_rows%2+(AAA_block_rows-AAA_block_rows%2)/2)) + c_inner_spacing
        : AAA_block_mode != "shifted" || AAA_block_rows == 1
            ? AAA_block_columns * c_aaa_width + c_inner_spacing
            : (AAA_block_columns+0.5) * c_aaa_width + c_inner_spacing
    : 0;
v_all_2_width = AAA_block_is_on == true
    ? AAA_block_position == "down"
        ? max(v_all_1_width,v_block_2_width_aaa)
        : v_y2_aaa+v_block_2_width_aaa
    : v_all_1_width;
v_all_2_height = AAA_block_is_on == true
    ? AAA_block_position == "right"
        ? max(v_all_1_height,v_block_2_height_aaa)
        : v_x2_aaa+v_block_2_height_aaa
    : v_all_1_height;

// CR2032 Calculation
v_x3_cr2032 = CR2032_block_is_on == true
    ? CR2032_block_position == "down"
        ? v_all_2_height
        : 0
    : 0;
v_y3_cr2032 = CR2032_block_is_on == true
    ? CR2032_block_position == "down"
        ? 0
        : v_all_2_width
    : 0;
v_block_3_width_cr2032 = CR2032_block_is_on == true
    ? CR2032_element_align == "horizontal"
        ? CR2032_block_columns * c_cr2032_width + (CR2032_block_columns-1)*CR2032_block_spacing + c_inner_spacing
        : CR2032_block_columns * c_cr2032_height + (CR2032_block_columns-1)*CR2032_block_spacing + c_inner_spacing
    : 0;
v_block_3_height_cr2032 = CR2032_block_is_on == true
    ? CR2032_element_align == "horizontal"
        ? CR2032_block_rows * c_cr2032_height + (CR2032_block_rows-1)*CR2032_block_spacing + c_inner_spacing
        : CR2032_block_rows * c_cr2032_width + (CR2032_block_rows-1)*CR2032_block_spacing + c_inner_spacing
    : 0;
v_all_3_width = CR2032_block_is_on == true
    ? CR2032_block_position == "down"
        ? max(v_all_2_width,v_block_3_width_cr2032)
        : v_y3_cr2032+v_block_3_width_cr2032
    : v_all_2_width;
v_all_3_height = CR2032_block_is_on == true
    ? CR2032_block_position == "right"
        ? max(v_all_2_height,v_block_3_height_cr2032)
        : v_x3_cr2032+v_block_3_height_cr2032
    : v_all_2_height;

// 9-volt Calculation
v_x4_9_volt = 9_volt_block_is_on == true
    ? 9_volt_block_position == "down"
        ? v_all_3_height
        : 0
    : 0;
v_y4_9_volt = 9_volt_block_is_on == true
    ? 9_volt_block_position == "down"
        ? 0
        : v_all_3_width
    : 0;
v_block_4_width_9_volt = 9_volt_block_is_on == true
    ? 9_volt_element_align == "horizontal"
        ? 9_volt_block_columns * c_pp3_width + (9_volt_block_columns-1)*9_volt_block_spacing + c_inner_spacing
        : 9_volt_block_columns * c_pp3_height + (9_volt_block_columns-1)*9_volt_block_spacing + c_inner_spacing
    : 0;
v_block_4_height_9_volt = 9_volt_block_is_on == true
    ? 9_volt_element_align == "horizontal"
        ? 9_volt_block_columns * c_pp3_height + (9_volt_block_columns-1)*9_volt_block_spacing + c_inner_spacing
        : 9_volt_block_columns * c_pp3_width + (9_volt_block_columns-1)*9_volt_block_spacing + c_inner_spacing
    : 0;
v_all_4_width = 9_volt_block_is_on == true
    ? 9_volt_block_position == "down"
        ? max(v_all_3_width,v_block_4_width_9_volt)
        : v_x4_9_volt+v_block_4_width_9_volt
    : v_all_3_width;
v_all_4_height = 9_volt_block_is_on == true
    ? 9_volt_block_position == "right"
        ? max(v_all_3_height,v_block_4_height_9_volt)
        : v_y4_9_volt+v_block_4_height_9_volt
    : v_all_3_height;

// Main Draw
difference(){
    base(width = Base_width, length = Base_length, heigth = Base_heigth, radius = Base_radius);
    if(AA_block_is_on){
        translate([v_x1_aa + c_base_spacing + AA_delta_y,
                   v_y1_aa + c_base_spacing + AA_delta_x,
                   Base_heigth+(AA_block_level_align == "main"
                                  ? Main_leveling_height
                                  : AA_block_local_level_height)
                     -c_aa_height+1])
            finger_block(AA_block_columns,AA_block_rows,AA_block_mode,AA_block_align,"aa");
    }
    if(AAA_block_is_on){
        translate([v_x2_aaa + c_base_spacing + AAA_delta_y,
                   v_y2_aaa + c_base_spacing + AAA_delta_x,
                   Base_heigth+(AAA_block_level_align == "main"
                                  ? Main_leveling_height
                                  : AAA_block_local_level_height)
                     -c_aaa_height])
            finger_block(AAA_block_columns,AAA_block_rows,AAA_block_mode,AAA_block_align,"aaa");
    }
    if(CR2032_block_is_on){
        translate([v_x3_cr2032 + c_base_spacing + CR2032_delta_y,
                   v_y3_cr2032 + c_base_spacing + CR2032_delta_x,
                   Base_heigth+(CR2032_block_level_align == "main"
                                  ? Main_leveling_height
                                  : CR2032_block_local_level_height)
                     -c_cr2032_width])
            button_block(CR2032_block_columns,CR2032_block_rows,CR2032_block_spacing,"cr2032",CR2032_element_align,CR2032_block_rounded,0,0);
    }
    if(9_volt_block_is_on){
        translate([v_x4_9_volt + c_base_spacing + 9_volt_delta_y,
                   v_y4_9_volt + c_base_spacing + 9_volt_delta_x,
                   Base_heigth+(9_volt_block_level_align == "main"
                                  ? Main_leveling_height
                                  : 9_volt_block_local_level_height)
                     -c_pp3_height])
            pp3_block(9_volt_block_columns,9_volt_block_rows,9_volt_block_spacing,"9-volt",9_volt_element_align,9_volt_block_rounded);
    }
}

// Modules
module base(width, length, heigth, radius){
    module corner (radius, height) {
        difference(){
            cube([2*radius,2*radius,height],center = true);
            translate([radius,radius,0]){
                cylinder(r = radius, h = height+2, center = true);
            }
        }
    }
    difference(){
        cube([width,length,heigth]);
        translate([0,0,heigth/2]){
            rotate([0,0,0]){
                corner(radius, heigth+2);
            }
        }
        translate([width,0,heigth/2]){
            rotate([0,0,90]){
                corner(radius, heigth+2);
            }
        }
        translate([width,length,heigth/2]){
            rotate([0,0,180]){
                corner(radius, heigth+2);
            }
        }
        translate([0,length,heigth/2]){
            rotate([0,0,270]){
                corner(radius, heigth+2);
            }
        }
    }
}
module finger_block(x,y,mode,align,type){
    module finger(mode,type,es){
        module edges(m,z,es){
            module edge(z){
                translate([0,0,c_height*z]){
                    translate([0,cw3/4,(c_height*(1-z))/2])
                        cube([d_cross,cw3/2,c_height*(1-z)],center = true);
                    rotate([-90,0,0])
                        cylinder(d = d_cross, h = cw3/2,center = false);
                }
            }
            for(i = [0 : m - 1])
                if(es[i]>0){
                    rotate([0,0,i * (360 / m)]) edge(z);
                }
        }
        cw1 = type == "aaa" || type == "AAA"
            ? 11.5
            : 15.5 ;
        cw2 = type == "aaa" || type == "AAA"
            ? 12.5
            : 16.5 ;
        cw3 = type == "aaa" || type == "AAA"
            ? 14.5
            : 18.5 ;
        c_height = type == "aaa" || type == "AAA"
            ? c_aaa_height
            : c_aa_height ;
        cylinder(d=cw1, h = c_height);
        translate([0,0,-1.1]) cylinder(d=cw1/2, h = 2);
        zs = [  0, 0.1, 0.15, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7,   1];
        rs = [cw2, cw2,  cw1,  cw1, cw2, cw2,  cw1, cw1,  cw2,  cw2, cw1, cw1,  cw2, cw2];
        for(i = [0 : len(rs) - 2])
            translate([0,0,c_height*zs[i]])
                cylinder(d1=rs[i],d2=rs[i+1], h = c_height*(zs[i+1]-zs[i]));
        z_cross = 0.1;
        d_cross = cw1*0.2;
        if (mode == "plain")
            edges(4,z_cross,es);
        else
            edges(6,z_cross,es);
    }
    c_fin_width = type == "aaa" || type == "AAA"
        ? c_aaa_width
        : c_aa_width;
    c_fin_block_width = type == "aaa" || type == "AAA"
        ? v_block_2_width_aaa - c_inner_spacing
        : v_block_1_width_aa - c_inner_spacing;
    c_fin_block_height = type == "aaa" || type == "AAA"
        ? v_block_2_height_aaa
        : v_block_1_height_aa;
    translate([align == "horizontal" ? 0 : 0,align == "horizontal" ? 0 : c_fin_block_width,0]){
        rotate([0,0,align == "horizontal" ? 0 : 270]){
            for(i = [0 : x - 1])
                for (j = [0 : y - 1]) {
                    if (mode == "plain")
                        translate([(1/2+j)*c_fin_width,(1/2+i)*c_fin_width,0])
                            finger(mode,type,[i < x - 1 ? 1 : 0,
                                              j > 0 ? 1 : 0,
                                              i > 0 ? 1 : 0,
                                              j < y - 1 ? 1 : 0,
                                              ]);
                    else if (mode == "shifted")
                        translate([((1-0.134*j%2)/2+j)*c_fin_width,((1+j%2)/2+i)*c_fin_width,0])
                            finger(mode,type,[i < x - 1 ? 1 : 0,
                                              j == 0 || (j % 2 == 1 && i == x - 1) ? 0 : 1,
                                              j == 0 || (j % 2 == 0 && i == 0) ? 0 : 1,
                                              i > 0 ? 1 : 0,
                                              j == y - 1 || (j % 2 == 0 && i == 0) ? 0 : 1,
                                              j == y - 1 || (j % 2 == 1 && i == x - 1) ? 0 : 1
                                              ]);
                    else if (j % 2 == 0 || (j % 2 == 1 && i != x - 1))
                        translate([((1-0.134*j%2)/2+j)*c_fin_width,((1+j%2)/2+i)*c_fin_width,0])
                            finger(mode,type,[(j % 2 == 0 && i == x - 1) || (j % 2 == 1 && i == x - 2) ? 0 : 1,
                                              j == 0 || (j > 0 && j % 2 == 0 && i == x - 1) ? 0 : 1,
                                              j == 0 || (j % 2 == 0 && i == 0) ? 0 : 1,
                                              i > 0 ? 1 : 0,
                                              j == y - 1 || (j % 2 == 0 && i == 0) ? 0 : 1,
                                              j == y - 1 || (j < y - 1 && j % 2 == 0 && i == x - 1) ? 0 : 1
                                              ]);
                }
        }
    }
}

module button_block(x,y,spacing,type,align,rounded,width,height){
    module button(align,rounded,width,height){
        v_width = align == "horizontal" ? width : height;
        v_height = align == "horizontal" ? height : width;
        if(rounded == true){
            union(){
                translate([align == "horizontal" ? 0 : v_height/2,align == "horizontal" ? v_width/2 : 0,width/2])
                    rotate([align == "horizontal" ? 0 : -90, align == "horizontal" ? 90 : 0,0])
                        cylinder(d=width, h = height);
                translate([0,0,width/2])
                    cube([v_height,v_width,width*2.5]);
            }
        } else {
            cube([v_height,v_width,width*3]);
        }
    }
    width_main = type == "cr2032"
        ? c_cr2032_width
        : width;
    height_main = type == "cr2032"
        ? c_cr2032_height
        : height;
    v_width = align == "horizontal"
        ? width_main
        : height_main;
    v_height = align == "horizontal"
        ? height_main
        : width_main;
    for(i = [0 : x - 1])
        for (j = [0 : y - 1]) {
            translate([j*(v_height+spacing),i*(v_width+spacing),0])
                button(align,rounded,width_main,height_main);
        }
}

module pp3_block(x,y,spacing,type,align,rounded,radius,width,depth,height){
    width_main = type == "9-volt"
        ? c_pp3_width
        : width;
    height_main = type == "9-volt"
        ? c_pp3_height
        : height;
    depth_main = type == "9-volt"
        ? c_pp3_depth
        : depth;
    radius_main = type == "9-volt"
        ? rounded
            ? c_pp3_radius
            : 0
        : radius;
    v_width = align == "horizontal"
        ? width_main
        : depth_main;
    v_height = align == "horizontal"
        ? depth_main
        : width_main;
    for(i = [0 : x - 1])
        for (j = [0 : y - 1]) {
            translate([j*(v_height+spacing),i*(v_width+spacing),0])
                base(v_height, v_width, height_main, radius_main);
        }
}
```


[User]
Hi, I'm looking to create a customizable grid-based storage system using OpenSCAD. I've been experimenting and have a basic version, but I'd love a more robust and user-friendly solution.

Essentially, I need to be able to define the following parameters:

*   **Module Depth:** The depth of each storage module (in mm). I'd like to be able to set a specific depth for each module.
*   **Raster Size:** The side length of each square grid cell within a module (in mm). This determines the size of the individual compartments.
*   **Width Modules:** The number of grid cells along the X-axis.
*   **Height Modules:** The number of grid cells along the Y-axis.
*   **Wall Thickness:** The thickness of the walls of each module (in mm).
*   **Base Thickness:** The thickness of the baseplate (in tenths of a mm).

The design should have the following:

*   A grid structure defined by the raster size. The grid should be like an egg crate, with walls rising up vertically from a base. The base itself should be flat, and below the bottom of the grid walls.
*   An outer box that surrounds the grid. This outer box should have the same overall dimensions as the grid, but with a defined wall thickness. The internal space should allow the grid to fit snugly inside. The outer box base should be flush with the grid base.
*   I want the option to create just the grid or the outer box, or both. It would be ideal to be able to turn these on/off with a boolean.

I'd like the design to be parametric, so I can change any of these parameters and regenerate the model. The base plate needs to be in tenths of a mm due to some limitations with the way Thingiverse customizer works.

I don't have a lot of experience with OpenSCAD, so the cleaner and easier to understand the code, the better. I think I'd like this to be split into separate modules for the base grid and the outer box so it's easier to turn them off/on. I would prefer this to be one or two files, rather than many.

I think for the math I need to use the `sqrt()` function and that's about it. No special libraries I think.

[Assistant]
gerust_v2.scad:
```
// Module Depth (mm)
Depth=40;
// Module side length (mm)
Raster=25;
// X amount of  modules
Width=2;
// Y mount of modules
Height=3;
// Wall thikness (mm)
Wall=2;
// Base Thickness (10ths of mm)
Bottom=5;

BottomActual=Bottom/10;

X=Raster*Width;
Y=Raster*Height;

translate([0,0,+Depth/2+10]) base();

h=sqrt(2*4*4);
module base(X=X, Y=Y, Z=Depth){
    w=4;
    union(){
        intersection(){
            union(){
                for (c=[-Y:Raster:Y+Raster])
                    translate([c-(Width/2==round(Width/2) ? 0 : Raster/2),0,0])
                        rotate([0,45,0])
                            cube([w,Y+w,w], center=true);
                for (c=[-X:Raster:X+Raster])
                    translate([0,c-(Height/2==round(Height/2) ? 0 : Raster/2),0 ])
                        rotate([45,0,0])
                            cube([X+w,w,w], center=true);
                }
            translate([0,0,h/2-1]) cube([X,Y,h/2-1], center=true);
            }
        translate([0,0,h/2-(1.4+BottomActual)])cube([X,Y,BottomActual], center=true);
        }
    } // module base()

//
difference(){
    cube([X,Y,Depth],center=true);

    translate([0,0,Wall]) cube([X-2*Wall,Y-2*Wall,Depth],center=true);
    translate([0,0,-Depth/2-BottomActual-1]) base();
}

```


[User]
Okay, I'm looking to create a parametric storage box for coin cell batteries, specifically CR20xx and CRxx32 types. I'd like the design to be easily customizable and printable without supports.

Here's the breakdown:

**Core Functionality:**

*   **Parametric Design:** The design needs to be driven by parameters for things like battery diameter, battery width (for CRxx32), number of cells to store, and overall box dimensions.
*   **Two Battery Sizes:** I need it to handle both CR20xx batteries (default diameter of 20mm) and CRxx32 batteries (width of 32mm) and that can be chosen via parameters.
*   **Box and Lid:** The design should include both a box base and a lid that fits securely.
*   **Text on Lid:** I'd like to be able to add text on the lid, for example to specify the type of battery it contains.
*   **Multiple Cell Storage:**  The user should be able to set how many individual cells the box will hold.

**Specific Parameters/Customization:**

*   `Cell_diameter`:  Diameter of the battery. Should default to 20mm, but can be changed by user (integer).
*   `Cell_width`: The width of the battery (32 for CRxx32 type, user can change (integer).
*   `Box_items`:  Number of cells the box should store. (integer).
*   `Box_text`: Text to be printed on the lid. (string)
*   `Font_size`: Size of the text on the lid. (integer)
*   `Render_box` : Boolean, used to render box.
*   `Render_lid` : Boolean, used to render lid.
*    `Wall_width`: Wall thickness for both box and lid. (float)
*    `Spacer_width`: Width of the space between cells (float).
*   `Lid_tolerance`: Additional space between box and lid (float)
*   `Lid_height`: Lid height as a percentage of the box height (integer)

**Design Considerations:**

*   **Tolerances:**  Please include small tolerances (e.g., 0.8mm) for proper fit.
*   **Printability:** The design should be optimized for easy printing with standard FDM printers, avoiding the need for supports.
*   **Clearance:** Account for spacing between cells and adequate clearance between the lid and the box.

**Output:**

I need the final output to be a single or multiple OpenSCAD (.scad) file that generates this design. Please use descriptive variable names, and organize the code well so that it's easy for me to understand and adjust the parameters. I am expecting a response that includes all the SCAD code necessary to implement this design and no additional code or references to external library dependencies other than the core OpenSCAD standard library.

[Assistant]
CRXXXX-Organizer.scad:
```
/*
    Parametric CRxxxx coin battery storage box
    https://www.thingiverse.com/thing:5201315

    remixed from design by Oliver Retzlaff @Oretz (https://www.thingiverse.com/thing:5193535)
    updated and fixed by Marcin Laber @mlask
*/

// "20" for CR20xx
Cell_diameter = 20; // [1:1:99]

// "32" for CRxx32
Cell_width = 32; // [1:1:99]

// default 20
Box_items = 20; // [1:1:99]

Box_text = "CR2032";
Font_size = 8;

Render_box = true;
Render_lid = true;

/* [Additional configuration] */

// box/lid wall width (a multiple of the nozzle size)
Wall_width = 1.2; // [0:0.1:10]

// battery spacer width
Spacer_width = 0.8; // [0:0.1:10]

// additional mm between box and lid
Lid_tolerance = 0.2; // [0:0.1:10]

// % of box height
Lid_height = 50; // [1:1:100]

// Process
{
    H = Cell_width / 10; // in mm
    D = Cell_diameter + 0.8; // tolerance 0.8mm
    LH = Lid_height / 100; // lid height ratio

    CW = H + Spacer_width + 0.8; // cell compartment width;

    Box_X = (Box_items * CW) + (Wall_width * 2) - Spacer_width;
    Box_Y = D + (Wall_width * 2);
    Box_Z = D + (Wall_width / 2);

    Lid_X = Box_X + (Wall_width * 2) + (Lid_tolerance * 2);
    Lid_Y = Box_Y + (Wall_width * 2) + (Lid_tolerance * 2);
    Lid_Z = Box_Z * LH;

    Lid_Xin = Box_X + (Lid_tolerance * 2);
    Lid_Yin = Box_Y + (Lid_tolerance * 2);
    Lid_Zin = Box_Z;

    if (Render_box) {
        translate([Wall_width, 2, 0]) {
            difference () {
                cube([Box_X, Box_Y, Box_Z]);
                translate([Wall_width, Wall_width, Wall_width]) cube([(Box_items * CW) - Spacer_width, D, D + 3 + Wall_width]);
            }
            for (i = [0 : Box_items]) {
                translate([(i * CW) + (Wall_width - Spacer_width), Wall_width, 0]) difference () {
                    cube([Spacer_width, D, D]);
                    translate([0, ((D + (Wall_width * 2)) / 2) - Wall_width, D + 4]) rotate([0, 90, 0]) cylinder(Box_items * CW, 8);
                }
            }
        }
    }

    if (Render_lid) {
        translate([0, -Lid_Y - 2, 0]) difference () {
            cube([Lid_X, Lid_Y, Lid_Z]);
            translate([(Lid_X - Lid_Xin) / 2, (Lid_Y - Lid_Yin) / 2, Wall_width]) cube([Lid_Xin, Lid_Yin, Lid_Zin]);
            translate([4, Lid_Y - 4, 0]) linear_extrude(min(1, Wall_width / 2), true) rotate([180, 0, 0]) text(Box_text, Font_size);
        }
    }
}
```


[User]
Hey, I need some help designing a tool for cutting PTFE tubing to a specific length, for use with 3D printers. I've got some requirements I'm hoping you can help me with.

Basically, it needs to be a block with a channel for the tube to sit in, and a slot for a cutting blade, so that I can reliably cut the tube to the right length every time. I need it to be parametric, so I can easily change the target length, tube diameter, and blade width.

Here's what I'm thinking:

*   **Cutoff Length:** I need to be able to specify the desired length of the tube after cutting, assuming that the blade cuts in the middle of the slot. This is what I will primarily adjust.
*   **Blade Width:** I need to be able to specify the width of the cutting blade used. This will be a constant for my blades.
*   **Tube Diameter:** The tool should accommodate different tubing diameters and I'd like a little bit of slack around it for easier insertion and removal. This might get confusing later, but the tube diameter value should be the *outer* diameter of the tube.
*   **Support Width:** I think there needs to be a support on either side of the cut so it can clamp the tube. Ideally, this would also be parametric.
*   **Margins:** The margin between the tube channel and the sides of the block should be adjustable.
*   **Label:** I want to have an optional text label on top of the block that specifies the cutoff length and tube diameter to be useful once printed.

To break that down further, the basic structure should be a rectangular block with the following:

*   A channel running through the middle to guide the tubing.
*   A slot perpendicular to the channel that goes through the block for the cutting blade. The position of this slot relative to the block is determined by the cutoff length and blade width. The position of the slot needs to account for the blade cutting in the middle of the slot.
*   The option to include a label on top.

I’d also like to ensure that it's easy to adjust the overall size, and I think it should be easy to modify the support width and margins later, so please make sure the block dimensions are defined based on the tube diameter, margins, and the support width parameters, even though the support width is not essential. The overall length will depend on the cutoff length, blade width, and support widths.

I'd like to define the following parameters at the beginning of the script:
*   `cutoff_length` (float)
*   `blade_width` (float)
*   `tube_diameter` (float)
*   `support_width` (float)
*   `margin` (float)
*   `add_label` (boolean)

Could you generate a parametric OpenSCAD file that can achieve this? I'm hoping it'll be a single .scad file without any special libraries; I'm not familiar with MCAD, BOSL, or any of those, and I'd prefer to keep it simple.

[Assistant]
ender3-cutter.scad:
```
// desired length of tube (assumes blade cuts at half its width)
cutoff_length = 31.3;
// width of the cutting blade
blade_width = 0.6;
// outer diameter of tube (plus slack if desired)
tube_diameter = 4.0;
// add label with sizes
add_label = true;

module __Customizer_Limit__ () {}

w = 3;   // width of supports
m = 2;   // margin around tube

o = m + tube_diameter + m; //    outer width of block
l = cutoff_length - blade_width/2;

union() {
    difference() {
        // full block
        cube([w + l + blade_width + w + 10, o, o], false);
        // carve out left part
        translate([w, -1, w])
            cube([l - w, o + 2, o], false);
        // carve out cut
        translate([w + l, -1, m])
            cube([blade_width, o + 2, o], false);
        // carve out right part
        translate([w + l + blade_width + w, -1, w])
            cube([99, o + 2, o], false);
        // carve out tube
        translate([w, tube_diameter/2 + m, tube_diameter/2 + m])
            rotate([0, 90, 0])
                cylinder(h = 99, d = tube_diameter, $fn = 360);
    }
    if (add_label) {
        translate([w, 0.1, w])
            linear_extrude(height = 1, center = true)
                text(str("l ", cutoff_length, "mm \u2300 ", tube_diameter, "mm"), size = 1.9, font="DejaVu Sans Mono:style=Bold");
    }
}

```


[User]
Hi, I'm looking to create a parametric chess set in OpenSCAD, and I need some help generating the files. I've seen a few designs online, but I'd really like something that's fully customizable in terms of size and has options for adding magnets and even initials.

Ideally, I want to be able to control:

*   **Number of pieces:** How many of each type of piece (King, Queen, Bishop, Knight, Rook, Pawn) to generate.
*   **Overall scaling:** A general scaling factor for both height and width, that I can adjust to change the size of the entire set.
*   **Magnet holes:** A way to specify the diameter and depth of a hole on the underside of each piece. This will be for holding magnets. I would like there to be a small circular base piece that snaps onto the bottom of each piece. This base piece will be what holds the magnet. It will need to have a slightly smaller circular recess than the magnet hole in the piece so the magnet sits flush. There should be two base sizes, a smaller one for pawns and a larger one for the other pieces.
*   **Rook initials:** The ability to add up to two letters on the top of the Rook pieces.
*   **Knight supports:** Temporary supports for the Knight piece that can be snapped off after printing.

For the piece profiles themselves, I've found some good starting points in some .dxf files, and I also have .stl files for the Queen's crown and the Knight's horse head. These files are: `king_profile.dxf`, `cross_profile.dxf`, `queen_profile.dxf`, `bishop_profile.dxf`, `rook_profile.dxf`, `pawn_profile.dxf`, `knight_profile.dxf`, `horse.stl`, and `queen_crown.stl`.

The basic shape of the chess pieces will be generated from the 2D profiles of the `.dxf` files by using a `rotate_extrude`. The king needs an additional cross added on top, and the queen needs the crown on top. The knight will be made of a base and the horse head. All of the pieces need a cut-out from the bottom that the bases snap into and also an additional hole to hold the magnet. The rook needs the battlements cut out of the top, and the bishop needs a small mitre cut-out. I'm thinking a difference operation for all of these.

I'm not too picky about the specifics of the supports, but I'd like the knight's supports to be easily removable.

I don't have any specific library requirements except that I'm hoping that all of the code is self-contained, using no external libraries. I'd like the output to be clear and well commented so that I can make small adjustments as needed. I'd like the pieces to be arranged in a grid to save space in the preview, four pieces across.

Could you please generate the OpenSCAD code needed for this? Let me know if you have any questions. Thanks!

[Assistant]
_Chess_Pieces15.scad:
```
/*
   CHESS PIECES
   ------------

   Remix of:
	OpenSCAD Chess Simple Printing
	by Zarlor January 26, 2019
	https://www.thingiverse.com/thing:3381939
	(Which itself is a remix of https://www.thingiverse.com/thing:585218)

   Default size has a base diameter of about 25mm, and King
   height of about 50mm.
   -Scalable, from 50% to 200% in height and/or width.
   -Choose how many of each piece to create.
   -Optional separate circular base pieces:
       These glue onto the bottom of the pieces to hold a magnet.
   -May add a weight (coin, washer, nut, etc.) by specifying the
    diameter and width of the hole underneath.
	Or attach felt to the piece or to the base part.
   -Can add initials (up to 2 characters) to Rook pieces.

   For the flat Base pieces, the small size is for Pawns,
   and the large size is for the other pieces.

   Each set should be printed twice in two different colors
   (traditionally in Black and in White).
   -Use 100% infill for more weight to the pieces.
   -No raft or supports should be needed.
   -I used layer height=0.2mm, speed=50mm/s. Smaller values may
    provide better quality.

   Removable supports are added to the Knight piece to make it
   printable. The supports snap off after printing.

   You probably do NOT want to print all pieces in one run;
   it will take a long time (and may will not fit on your
   printer platform).

   --------------------------------------------------------------
   REQUIREMENTS:
   This "OpenSCAD" file requires the installation of OpenSCAD,
   free software available here:  https://openscad.org/

   Several ".dxf" files and ".sql" files need to be downloaded
   and saved in the same folder that this runs from:

	 king_profile.dxf
	 cross_profile.dxf (cross on top of the King piece)
	 queen_profile.dxf
	 bishop_profile.dxf
	 rook_profile.dxf
	 pawn_profile.dxf
	 knight_profile.dxf (pedestal only for holding the horse head)
     horse.stl (for the horse head shape of the Knight)
	 queen_crown.stl (crown on top of the Queen piece)

   After using OpenSCAD to create an STL file, use any slicer
   program to create a file for your 3D printer. I use the CURA
   slicer program available here:
       https://ultimaker.com/software/ultimaker-cura
	   (free even if you do not own their brand of printer)

   --------------------------------------------------------------
   ADVANCED:

    The .dxf files may be edited using LibreCAD, free software
	available here:   https://librecad.org/

	The .stl files may be edited with any of several programs. I use
	Tinkercad, free software available here: https://www.tinkercad.com/

*/

/* [Piece(s) to print] */
// Print King Piece:
nKing = 1; //[0:1:1]
// Print Queen Piece:
nQueen = 0; //[0:1:1]
// Print Bishop Piece(s):
nBishop = 0; //[0:1:2]
// Print Knight Piece(s):
nKnight = 0; //[0:1:2]
// Print Rook Piece(s):
nRook = 0; //[0:1:2]
// Print Pawn Piece(s):
nPawn = 0; //[0:1:8]

/* [Piece Sizing] */
// Scaling for Height of chess piece
Height_Scaling = 1.0; //[0.50:.05:2.00]
// Scaling for Width of chess piece
Width_Scaling = 1.0; //[0.50:.05:2.00]
// Add supports to Knight piece:
Add_Supports = 1; //[0:1:1]
// Initials to add to ROOK (up to 2):
Initials="";
// Diameter of hole under piece (magnet diam+3):
HoleDiam=13.0; //[2.0:0.5:35.0]
// Depth of hole under piece (magnet ht-1:
HoleHt=2.0; //[0.0:.5:5.0]

/* [Bases - snap unto bottom and hold magnet:] */
// Large Bases (for most pieces):
LgBase_Count = 0; //[0:1:8]
// Small Bases (for Pawns):
SmBase_Count = 0; //[0:1:8]

/* [Hidden] */

segs = 64;

// Lists are in this order: King,Q,B,N,R,Pawn
// The values in the lists are later scaled by height & width scaling.

// These values may need adjusting if the .dxf files are edited:
PieceWidths = [174,174,141,140,139,108];
PieceHeights = [304,244,251,258,189,169];
BottomTrims = [10.5,10.5,9,8,8,5.5];

// Desired relative heights of each kind of piece:
HtRatios = [1.0,.9,.85,.85,.7,.5];
// Desired diameter of the bases:
Base_Sizes = [25,25,25,25,25,20];

Piece_count = nKing+nQueen+nBishop+nKnight+nRook+nPawn;
Base_count = SmBase_Count+LgBase_Count;
spacing = 35*Width_Scaling;

//
// Iterate through all requested pieces:
//
if (Piece_count>0) {
	for (n=[1:Piece_count]) {
		// Determine the type of piece for this iteration:
		TK = (n>nKing) ? 1 : 0; // 0=King type
		TQ = (n>nKing+nQueen) ? 2 : TK; // 1=Queen type
		TB = (n>nKing+nQueen+nBishop) ? 3 : TQ; // 2=Bishop type
		TN = (n>nKing+nQueen+nBishop+nKnight) ? 4 : TB; // etc
		Type = (n>nKing+nQueen+nBishop+nKnight+nRook) ? 5 : TN;

		// Calculate Scaling Adjustments:
		ScaleHt = 50 / PieceHeights[Type] * HtRatios[Type];
		HtScaleAdj = ScaleHt * Height_Scaling;
		ScaleWd = Base_Sizes[Type] / PieceWidths[Type];
		Width_Piece = ScaleWd * Width_Scaling;

		// Calculate piece size for this iteration:
		Base_Size = Base_Sizes[Type]; //* Width_Piece;
		trimBottom =  BottomTrims[Type] * HtScaleAdj;

		// Determine print location for this iteration:
		dy=floor((n-1)/4);
		dx=(n-1) - dy*4;
		translate([dx*spacing,dy*spacing,0])
		scale([Width_Piece,Width_Piece,1]) {
			difference() {
				translate([0,0,-trimBottom])
				// Chess piece body: must scale by 0.2
				// and any other scaling factor:
				//scale([0.2,0.2,0.2 * HtScaleAdj]) {
				scale([1,1,HtScaleAdj]) {
					if (Type==0) { // KING Piece
						translate([0, 0, 0])
							rotate_extrude(convexity = 10,$fn=segs)
								import(file = "king_profile.dxf");
						// Add cross portion to the top:
						translate([-25, 13, 317])
							rotate([90, 0, 0]) linear_extrude(height = 26)
								import(file = "cross_profile.dxf");
					}
					if (Type==1) { // QUEEN Piece
						translate([0, 0, 0])
							rotate_extrude(convexity = 10,$fn=segs)
								import(file = "queen_profile.dxf");
						// Add the crown
						translate([0, 0, 225]) scale(5.5)
							import(file = "queen_crown.stl");
					}
					if (Type==2) { // BISHOP Piece
						translate([0, 0, 0])
							rotate_extrude(convexity = 10,$fn=segs)
								import(file = "bishop_profile.dxf");
					}
					if (Type==3) { // KNIGHT Piece
						// Create the round base:
						translate([0, 0, 0])
							rotate_extrude(convexity = 10,$fn=segs)
								import(file = "knight_profile.dxf");
						// Import STL for the knight
						translate([-7, -13, 57])
							scale(3.2) import(file = "horse.stl");
					}
					if (Type==4) { // ROOK Piece
						translate([0, 0, 0])
							rotate_extrude(convexity = 10,$fn=segs)
								import(file = "rook_profile.dxf");
					}

					if (Type==5) { // PAWN Piece
						translate([0, 0, 0])
							rotate_extrude(convexity = 10,$fn=segs)
								import(file = "pawn_profile.dxf");
					}
				}

				//
				// Begin subtracting portions:
				//

				// Remove bottom bit of the piece,
				// to be covered by separate bottom cover part:
				color([.5,.8,.2]) // Green
				translate([0,0,-trimBottom-.1])
					cylinder(d=Base_Size/Width_Piece+1,h=trimBottom+.101,$fn=segs);

				// Subtract out center portion:
				//   Hole diameter larger than magnet by 3mm
				//   Hole depth smaller than magnet by 1mm
				//     (regardless of the piece scaling)
				HoleDiamAdj = (HoleDiam > Base_Size-4) ?
					Base_Size-4 : HoleDiam;
				// Negate effect of overall scaling first:
				scale([1/Width_Piece,1/Width_Piece,1]) // Negate prior scaling
					color([.8,.5,.8]) // Purple
					cylinder(d=HoleDiamAdj,h=HoleHt+0.5,$fn=segs);

				if (Type==2) { // BISHOP Piece - Remove slash from mitre:
					scale([1,1,HtScaleAdj]) translate([-33, 0, 227])
						rotate([0, -45, 0]) cube([10, 80, 80],center=true);
				}

				if (Type==4) { // ROOK Piece
					// Remove four cutouts for crennelations:
					scale([1,1,HtScaleAdj]) translate([0, 0, 175])  {
					  rotate([0, 0, 0])
						linear_extrude(height = 20)
							polygon( points=[[0,0],[60,30],[30,60]] );
					  rotate([0, 0, 90])
						linear_extrude(height = 20)
							polygon( points=[[0,0],[60,30],[30,60]] );
					  rotate([0, 0, 180])
						linear_extrude(height = 20)
							polygon( points=[[0,0],[60,30],[30,60]] );
					  rotate([0, 0, 270])
						linear_extrude(height = 20)
							polygon( points=[[0,0],[60,30],[30,60]] );
					}
				}
			}

			//
			// Special code to add supports to Knight pieces:
			//
			if (Type==3 && Add_Supports) {
				scale([1,1,HtScaleAdj]) {
					//---Add a temporary support below the mane:
					// Square-shaped base for mane support:
					translate([-101, -75, 5.3]) cube([30,150,5]);
					// Square-shaped base for mane support:
					translate([-102, -15, 5.38]) cube([30,30,45]);
					// Thin angled mane support:
					translate([-126, -5, 44]) rotate([0,39,0]) cube([45,12,66]);
					// Small square on top of main support:
					translate([-89, -5, 95]) rotate([0,61,0]) cube([15,12,15]);

					//---Add support below the chin:
					// Square-shaped base for head support:
					translate([72, -60, 5.3]) cube([37,120,5]);
					// Square-shaped upright head support:
					translate([81, -15, 5.3]) cube([30,30,78]);
					// Thick angled head support:
					translate([101, -15, 52]) rotate([0,-48,0])	cube([15,30,83]);
					// Thin angled head support:
					translate([101, -15, 52]) rotate([0,-48,0])	cube([6,30,117]);
					// Horizontal bar below chin:
					translate([30, -15, 115]) rotate([0,14,0]) cube([30,30,8]);
					//--Add circular support around base of entire piece:
					difference() {
						cylinder(d=240,h=5);
						translate([0,0,-.01]) cylinder(d=180,h=6);
					}
				}
			}

			// Add initials to top of ROOK:
			if (Type==4 && len(Initials) > 0) {
				scale([1,1,HtScaleAdj])
					translate([0, 0, 165]) {
						linear_extrude(10)
						text(Initials,size=40 ,halign = "center",
							valign="center",font="Segoe UI");
				}
			}
		}
	}
}

//
// Iterate through all requested Base sizes (large or small:
//
if (Base_count>0) {
	for (n=[1:Base_count]) {
		BType = (n>LgBase_Count) ? 1 : 0;
		Base_Size2 = Base_Sizes[5*BType] * Width_Scaling;

		HoleDiamAdj2 = (HoleDiam > Base_Size2-4) ? Base_Size2-4 : HoleDiam;

		x1=(Piece_count+n-1);
		dy=floor(x1/4);
		dx=x1 - dy*4;
		translate([dx*spacing,dy*spacing,0]) {
			difference() {
				union() {
					// Create cover for bottom of chess piece:
					// Use a polygon profile to shape this piece.
					rotate_extrude($fn=segs) {
						translate([(Base_Size2-7)/2.,0,0])
						polygon(points=[[0,0],[3,0],[3.5,.5],[3.5,2],[0,2]]);
					};
					// Fill in bottom of rotated base:
					cylinder(d=Base_Size2-2.9,h=2,$fn=segs);

					// Add raised portion that fits into underside
					// of chess piece:
					cylinder(d=HoleDiamAdj2-0.4,h=HoleHt+2.,$fn=segs);
				}

				// Subtract out center for the magnet:
				translate([0,0,1.1]) cylinder(d=HoleDiamAdj2-2.8,h=HoleHt+0.91,
					$fn=segs);
			}
		}
	}
}
```