[User]
I'm looking to create a customizable wrench holder for my workbench. I'd like it to have a base with two sides, and two support braces that attach to the base. I've seen some designs that use rounded rectangles for the base and braces and that seems like a good approach.

Specifically, the base should have two main parts, one on each side, that are basically long, rounded rectangles. These parts need to have slots cut into them to hold the wrenches vertically. The slots should be evenly spaced. I also want to be able to define the number of wrenches held, as well as the length of the base, and the overall height.

The support braces should also be rounded rectangles, and they should have cylindrical male protrusions that slot into corresponding cylindrical holes cut into the base sides to connect them. I need to control the size of both support braces independently, the width of the braces, the thickness of the braces and the base, and the radius of the rounded rectangle edges. The diameter of the socket protrusions on the braces and the female sockets in the base should also be customizable.

I’d like this to be fully parametric so I can easily adjust the size and number of wrenches it holds. I'd like the code to be in OpenSCAD and I’m comfortable using the hull function for the rounded rectangles and other solid shapes. Let's try to make this from scratch, without any existing base code. No libraries are required, I just need a single .scad file.

[Assistant]
wrench_table_holder.scad:
```
/*
Wrench Table Holder (c) by Jorge Monteiro

Wrench Table Holder is licensed under a
Creative Commons Attribution-ShareAlike 4.0 International.

You should have received a copy of the license along with this
work.  If not, see <http://creativecommons.org/licenses/by-sa/4.0/>.
*/
$fn = 40;

topBrace = 90;
bottomBrace = 60;
//base
thickness = 2.5;
baseWidth = 20;
baseHeight = 25;
baseThickness = 1.5;

// braces
braceWidth = 10;
braceThickness = 1.5;

drawBraces();
drawSides(100, 5);

module drawBraces() {

    translate([0, braceWidth + baseWidth + 20, 0]) drawBrace(topBrace);
    translate([0, braceWidth + baseWidth + 40, 0]) drawBrace(bottomBrace);
};

module drawBrace(size) {
    union() {
        roundedRect(size, braceWidth, braceThickness, 5);
        translate([0, 0, braceThickness]) socket(size/2-5, baseThickness);
        translate([0, 0, braceThickness]) socket(-size/2+5, baseThickness);
    };
};

module drawSides(length, slots) {

    translate([0, baseWidth + 5, 0]) drawLeftBase(length, slots);
    drawRightBase(length, slots);
};

module wrenchSlots(length, slots) {
    difference() {
        // frame
        rotate([90, 0, 0]) cube([length, baseHeight, thickness]);
        // slots per wrench
        for (i = [0 : slots]) {
            translate([i * length/(slots+1),0,baseHeight]) {
                rotate([90, 90, 0]) {
                    hull(){
                        translate([baseHeight/2,0,0]) cylinder(r=2, h=thickness);
                        translate([0,0,0]) cylinder(r=.1, h=thickness);
                        translate([0,10,0]) cylinder(r=.1, h=thickness);
                    };
                };
            };
        };
    };
};

module drawLeftBase(length, slots) {
    difference() {
        translate([0, baseWidth/6, 0]) roundedRect(length, baseWidth, baseThickness, 3);
        socket(length/2-8, baseThickness);
        socket(-length/2+8, baseThickness);
    }
    translate([-length/2, baseWidth/2, 0]) {
        wrenchSlots(length, slots);
    };
};

module drawRightBase(length, slots) {
    difference() {
        translate([0, -baseWidth/6, 0]) roundedRect(length, baseWidth, baseThickness, 3);
        socket(length/2-8, baseThickness);
        socket(-length/2+8, baseThickness);
    }
    translate([-length/2,-baseWidth/2+thickness,0]) {
        wrenchSlots(length, slots);
    };
};

module socket(location, thick) {
    translate([location, 0, 0]) cylinder(h = thick, r = 2);
};

module roundedRect(xdim, ydim, zdim, rdim) {
    translate([-xdim/2,-ydim/2,0]){
        hull(){
            translate([xdim-rdim,rdim,0]) cylinder(r=rdim, h=zdim);
            translate([xdim-rdim,ydim-rdim,0]) cylinder(r=rdim, h=zdim);

            translate([rdim,ydim-rdim,0]) cylinder(r=rdim, h=zdim);
            translate([rdim,rdim,0]) cylinder(r=rdim, h=zdim);
        };
    };
};

```
wrench_table_holder_v2.scad:
```
/*
Wrench Table Holder (c) by Jorge Monteiro

Wrench Table Holder is licensed under a
Creative Commons Attribution-ShareAlike 4.0 International.

You should have received a copy of the license along with this
work.  If not, see <http://creativecommons.org/licenses/by-sa/4.0/>.
*/
$fn = 40;

topBrace = 90;
bottomBrace = 60;
//base
thickness = 2.5;
baseWidth = 20;
baseHeight = 25;
baseThickness = 1.5;

// braces
braceWidth = 10;
braceThickness = 1.5;
// socket
maleSocket = 2.2;
femaleSocket = 2;

drawBraces();
drawSides(100, 5);

module drawBraces() {

    translate([0, braceWidth + baseWidth + 20, 0]) drawBrace(topBrace);
    translate([0, braceWidth + baseWidth + 40, 0]) drawBrace(bottomBrace);
};

module drawBrace(size) {
    union() {
        roundedRect(size, braceWidth, braceThickness, 5);
        translate([0, 0, braceThickness]) maleSocket(size/2-5, baseThickness);
        translate([0, 0, braceThickness]) maleSocket(-size/2+5, baseThickness);
    };
};

module drawSides(length, slots) {

    translate([0, baseWidth + 5, 0]) drawLeftBase(length, slots);
    drawRightBase(length, slots);
};

module wrenchSlots(length, slots) {
    difference() {
        // frame
        rotate([90, 0, 0]) cube([length, baseHeight, thickness]);
        // slots per wrench
        for (i = [0 : slots]) {
            translate([i * length/(slots+1),0,baseHeight]) {
                rotate([90, 90, 0]) {
                    hull(){
                        translate([baseHeight/2,0,0]) cylinder(r=2, h=thickness);
                        translate([0,0,0]) cylinder(r=.1, h=thickness);
                        translate([0,10,0]) cylinder(r=.1, h=thickness);
                    };
                };
            };
        };
    };
};

module drawLeftBase(length, slots) {
    difference() {
        translate([0, baseWidth/6, 0]) roundedRect(length, baseWidth, baseThickness, 3);
        socket(length/2-8, baseThickness);
        socket(-length/2+8, baseThickness);
    }
    translate([-length/2, baseWidth/2, 0]) {
        wrenchSlots(length, slots);
    };
};

module drawRightBase(length, slots) {
    difference() {
        translate([0, -baseWidth/6, 0]) roundedRect(length, baseWidth, baseThickness, 3);
        socket(length/2-8, baseThickness);
        socket(-length/2+8, baseThickness);
    }
    translate([-length/2,-baseWidth/2+thickness,0]) {
        wrenchSlots(length, slots);
    };
};

module socket(location, thick) {
    translate([location, 0, 0]) cylinder(h = thick, r = femaleSocket);
};

module maleSocket(location, thick) {
    translate([location, 0, 0]) cylinder(h = thick, r = maleSocket);
};

module roundedRect(xdim, ydim, zdim, rdim) {
    translate([-xdim/2,-ydim/2,0]){
        hull(){
            translate([xdim-rdim,rdim,0]) cylinder(r=rdim, h=zdim);
            translate([xdim-rdim,ydim-rdim,0]) cylinder(r=rdim, h=zdim);

            translate([rdim,ydim-rdim,0]) cylinder(r=rdim, h=zdim);
            translate([rdim,rdim,0]) cylinder(r=rdim, h=zdim);
        };
    };
};

```


[User]
I'd like to design a customizable toolbox, something simple but useful for organizing small tools. I was thinking of a rectangular box with some internal dividers. Here are the details I have in mind:

*   **Basic Shape:** The toolbox should be a rectangular prism.
*   **Customizable Dimensions:** I'd like to be able to easily set the box's width, length, and height. Let's call these parameters `boxWidth`, `boxLength`, and `boxHeight`.
*   **Wall Thickness:** The walls should have a consistent thickness, which I want to be able to adjust using a `wallThickness` parameter.
*   **Base:** The box needs a solid base (floor) also of thickness `wallThickness`.
*   **Internal Dividers:** I'd like some internal dividers to separate the box into sections.
    *   One divider should run across the width of the box, dividing it in half along the length.
    *   Two other dividers should run along the length, dividing the box into three sections along the width. Let's call the spacing from the left two dividers `separatorVertGrid`.
    *   These dividers should not go all the way to the top. There should be a gap between the top of the divider and the top of the box. Let's call this parameter `separatorTopGap`.
    *   The dividers should also have a consistent thickness defined by the `separatorThickness` parameter.
*  **Parameters**: I'd like to easily configure all of the parameters:
   * `wallThickness`
   * `boxWidth`
   * `boxLength`
   * `boxHeight`
   * `separatorTopGap`
   * `separatorThickness`
   * `separatorVertGrid`

So, could you please generate an OpenSCAD file (or files, if that makes more sense) that implements this design? I'd like it to be fully parametric, making it easy to adjust the dimensions and divider configurations. I don't require any external libraries for this design, just simple OpenSCAD primitives.

[Assistant]
SimpleToolBox.scad:
```
/*
Simple Tool Box (c) by Jorge Monteiro

Simple Tool Box is licensed under a
Creative Commons Attribution-ShareAlike 4.0 International.

You should have received a copy of the license along with this
work.  If not, see <http://creativecommons.org/licenses/by-sa/4.0/>.
*/
wallThickness = 1.5;
boxWidth = 90;
boxLength = 60;
boxHeight = 60;
separatorTopGap = 5;
separatorThickness = 1;

drawBox();
drawSeparators();

module drawSeparators() {
    separatorVertGrid = boxWidth/4;
    // Draw the walls
    translate([-boxWidth/2, 0, 0]) cube([boxWidth, separatorThickness, boxHeight-separatorTopGap]);
    translate([0, -boxLength/2, 0]) cube([separatorThickness, boxLength, boxHeight-separatorTopGap]);
    translate([-separatorVertGrid, -boxLength/2, 0]) cube([separatorThickness, boxLength, boxHeight-separatorTopGap]);
};

module drawBox() {
    // Draw the base
    translate([-boxWidth/2, -boxLength/2, 0]) cube([boxWidth,boxLength,wallThickness]);
    // Draw the walls
    translate([-boxWidth/2, -boxLength/2, 0]) cube([boxWidth, wallThickness, boxHeight]);
    translate([-boxWidth/2, boxLength/2-wallThickness, 0]) cube([boxWidth, wallThickness, boxHeight]);
    translate([-boxWidth/2, -boxLength/2, 0]) cube([wallThickness, boxLength, boxHeight]);
    translate([boxWidth/2-wallThickness, -boxLength/2, 0]) cube([wallThickness, boxLength, boxHeight]);
};

```


[User]
Hey, I'm looking to design a phone holder with a built-in Qi charger. I have a round Qi charger, and want to cradle the phone at an angle, like a little desk stand. I also need a base to support everything.

Here's what I'm thinking:

**Phone and Charger Dimensions:**

*   My phone is about 140mm tall, 74mm wide, and 14mm deep.
*   The Qi charger is a cylinder, about 70mm in diameter and 12mm deep.
*   I want the charger to sit about 40mm above the table, and the bottom of the phone to sit about 5mm above the table.

**Holder Structure:**

*   The phone should lean back at an angle of about 30 degrees from vertical.
*   There should be a base plate under the phone, and behind the charger, but the parts don't need to be one solid piece.
*   The base plate under the phone should include a couple of clips to hold the phone in place.
*   The area behind the charger should have a cutout for the cord to run through, about 15mm wide. The cord is about 5mm in diameter.
*   I want the legs of the holder behind the charger to flare out a little, so maybe an angle of 22 degrees, just for looks.
*   I also want a small radius of 20mm on the side of the holder, where a clip for the cord could go.
*   The walls around the charger should be about 5mm thick, and there should be a back plate behind the charger about 5mm deep and 10mm wide.
*  The support legs should have a width of 15mm, and a 4mm wide support structure inside the legs.
*   And the top of the charger should have some extra structure above it, about 15mm tall, for support.

**Other Details**

*   I'd like to be able to control the polygon resolution, so a variable for that would be good. I'd start with a resolution of about 10.
*   Also, add a tiny bit of slop in there so that things don't have coplanar surfaces, so maybe a variable around 0.01.

Could you generate the necessary OpenSCAD files for this? I'm not using any particular libraries for this. It would be great if you could make this parametric, so I can adjust the dimensions later.

[Assistant]
qi_holder_dimensions.scad:
```
// Parameters describing the phone, charger dimensions and charger position.
phone_height = 140;
phone_width = 74;
phone_depth = 14;

charger_diameter = 70;
charger_depth = 12;

phone_height_from_table = 5;
charger_height_from_table = 40;

charger_cord_cutout_width = 15;
cord_diameter = 5;

// Parameters for other dimensions of the holder assembly.
holder_assembly_angle = 30; // Degrees that the holder will lean the phone back from upright.

phone_base_holder_spacing = 40;
phone_base_holder_width = 6;

// Depth and width of the plate that sits behind the Qi charger
charger_back_plate_depth = 5;
charger_back_plate_width = 10;
// Thickness of the outer wall around the Qi charger
charger_holder_thickness = 5;

back_plate_leg_width = 15;
back_plate_leg_structure_width = 4;
back_plate_leg_angle = 22; // Legs are angled out a little to look fancy.

cord_clip_plate_radius = 20;
extra_charger_holder_height = 15;

resolution = 10; // Determines polygon count in several places.
manifold_slop = 0.01; // Used to prevent coplanar surfaces that might create non-manifold geometry.

```
base_plate.scad:
```
// base_plate.scad
// Gregg Christopher, 2015. This file is public domain.
//
// Base plate for a Qi charger holder.
// Sized for the Google Nexus 5 phone and LG round Qi charger.
// This project is intended to eventually be a general-purpose parameterizable phone charger holder,
// but not all of the shape responds appropriately to some values for desired dimensions.
// It is a work in progress.
//

include <qi_holder_dimensions.scad>;
use <back_plate.scad>;

// Preview the back plate in place to see that the base plate will fit.
rotate([90 - holder_assembly_angle, 0, 0]) translate([0, phone_base_holder_width, 0]) {
  color([0, 0, 1, .5]) %back_plate();
  %translate([-phone_width/2, phone_height_from_table, charger_back_plate_depth + charger_depth]) phone_shape();
}

// Bottom straight section
translate([-back_plate_leg_width/2, -(charger_back_plate_depth + charger_depth)/cos(holder_assembly_angle), 0]) {

  difference() {
    cube([back_plate_leg_width, 90, charger_holder_thickness]);
    rotate([-holder_assembly_angle, 0, 0])
    translate([-manifold_slop, -5, 0])
    cube([back_plate_leg_width + 2*manifold_slop, 5, 2*charger_holder_thickness]);
  }
  translate([back_plate_leg_width/2, 90, 0])
  cylinder(r = back_plate_leg_width/2, h = charger_holder_thickness, $fn = 30);
}

difference() {
  union() {
    // Rounded section of the base
    difference() {
      cylinder(r = 25, h = charger_holder_thickness, $fn = 60);
      translate([-25-manifold_slop, -25-manifold_slop, -manifold_slop])
      cube([50+2*manifold_slop, 25+2*manifold_slop, charger_holder_thickness +2*manifold_slop]);
    }

    // Triangular support sections
    difference() {
      rotate([holder_assembly_angle, 0, 0]) {
        translate([back_plate_leg_width/2 + manifold_slop, 0, -10])
        cube([charger_holder_thickness - 2*manifold_slop, 16, 30]);
        translate([-back_plate_leg_width/2 - charger_holder_thickness + manifold_slop, 0, -10])
        cube([charger_holder_thickness - 2*manifold_slop, 16, 30]);
      }
      translate([-30, 0, -10])
      cube([60, 20, 10]);
    }

  }
  // Use the actual back plate to cut away any intersecting material.
  rotate([90 - holder_assembly_angle, 0, 0]) translate([0, phone_base_holder_width, -10*manifold_slop])
  back_plate();
}

```
back_plate.scad:
```
// base_plate.scad
// Gregg Christopher, 2015. This file is public domain.
//
// Main section of a cradle to hold a phone and round Qi charger.
//
// Sized for the Google Nexus 5 phone and LG round Qi charger.
// This project is intended to eventually be a general-purpose parameterizable phone charger holder,
// but not all of the shape responds appropriately to some values for desired dimensions.
// It is a work in progress.
//

include <qi_holder_dimensions.scad>;

// The platonic ideal cellular phone.
module phone_shape() {
  cube([phone_width, phone_height, phone_depth]);
}

// A rounded bracket with an indentation to hold the bottom of a phone.
module phone_clip() {
  translate([-charger_holder_thickness/2 - manifold_slop, 0, 0]) {
    intersection() {
      scale([1, .5, 1]) rotate([0, 90, 0]) cylinder(h = charger_holder_thickness, r = 1.5*phone_depth, $fn = resolution*6);
      translate([0, -.5*1.5*phone_depth, 0]) cube([charger_holder_thickness, .5*1.5*phone_depth, 1.5*1.2*phone_depth]);
    }
    translate([0, 0, phone_depth]) difference() {
      cube([charger_holder_thickness, .3*phone_depth, .5*phone_depth]);
      rotate([38, 0, 0]) translate([-manifold_slop, 0, -.5*phone_depth]) cube([charger_holder_thickness + 2*manifold_slop, phone_depth, .5*phone_depth]);
    }
  }
}

// The main structure of the phone and charger cradle.
module back_plate() {

  // Round section that holds the Qi charger.
  translate([0, charger_diameter/2 + charger_height_from_table, 0])
  difference() {
    cylinder(r = charger_diameter/2 + charger_holder_thickness, h = charger_back_plate_depth + charger_depth, $fn = resolution*16);
    translate([0, 0, -manifold_slop]) cylinder(r = charger_diameter/2 - charger_back_plate_width, h = charger_back_plate_depth + 2*manifold_slop, $fn = resolution*16);
    translate([0, 0, charger_back_plate_depth]) cylinder(r = charger_diameter/2, h = charger_depth + manifold_slop, $fn = resolution*16);
    translate([-charger_diameter/2 - charger_holder_thickness, extra_charger_holder_height, - manifold_slop]) cube([charger_diameter + 2*charger_holder_thickness + 2*manifold_slop,charger_diameter/2 + charger_holder_thickness + manifold_slop, charger_back_plate_depth + charger_depth + 2*manifold_slop]);
    translate([-charger_cord_cutout_width/2, -charger_diameter/2 - charger_holder_thickness - manifold_slop, -manifold_slop]) cube([charger_cord_cutout_width, charger_diameter/2, charger_back_plate_depth + charger_depth + 2*manifold_slop]);
  }

  // Outer section of the cradle legs. Angled to look nifty or optimize material usage or maybe some other reason.
  module base_leg_outline() {
    difference() {
      intersection() {
        translate([charger_cord_cutout_width/2, -charger_diameter/2, 0]) square([charger_diameter, charger_height_from_table + charger_diameter]);
        translate([charger_cord_cutout_width/2, charger_height_from_table + charger_diameter/2, 0]) rotate([0, 0, back_plate_leg_angle])
        translate([-charger_diameter, -charger_height_from_table - charger_diameter, 0]) square([charger_diameter, charger_height_from_table + charger_diameter]);

      }
      translate([0, charger_diameter/2 + charger_height_from_table]) circle(r = charger_diameter/2 + manifold_slop, $fn = resolution*4);
    }
  }

  // The flat plate that defines the lean angle for the cradle.
  module base_plane() {
    rotate([holder_assembly_angle, 0, 0]) translate([-charger_diameter, -charger_holder_thickness, 0]) cube([2*charger_diameter, charger_holder_thickness, 2*(charger_back_plate_depth + charger_depth)]);
  }

  // Use offsets from the leg outline to create the legs of the cradle.
  module leg() {
    difference() {
      union() {
        linear_extrude(height = charger_back_plate_depth + charger_depth) {
          difference() {
            base_leg_outline();
            offset(-charger_holder_thickness) base_leg_outline();
          }
        }
        translate([0, -10, charger_back_plate_depth + charger_depth - charger_holder_thickness]) cube([charger_cord_cutout_width/2, charger_holder_thickness*4, charger_holder_thickness]);
      }
      rotate([holder_assembly_angle, 0, 0]) translate([-charger_diameter, -charger_holder_thickness - 30, 0]) cube([2*charger_diameter, charger_holder_thickness + 30, 2*(charger_back_plate_depth + charger_depth)]);
    }
    intersection() {
      base_plane();
      linear_extrude(height = charger_back_plate_depth + charger_depth) base_leg_outline();
    }

    translate([charger_cord_cutout_width/2 + charger_holder_thickness/2, phone_height_from_table, charger_back_plate_depth + charger_depth]) phone_clip();
    translate([charger_cord_cutout_width/2, charger_height_from_table + charger_diameter/2, 0]) rotate([0, 0, back_plate_leg_angle]) translate([ - charger_holder_thickness/2, -charger_height_from_table + phone_height_from_table - charger_diameter/2 - 3, charger_back_plate_depth + charger_depth]) phone_clip();
  }

  leg();
  mirror([1, 0, 0]) leg();

  // Braces on either side of the Qi charger section to keep the phone from falling out sideways.
  difference() {
    translate([phone_width/2, charger_height_from_table + charger_diameter/2, 0]) cylinder(h = charger_back_plate_depth + charger_depth + phone_depth, r = charger_holder_thickness);
    translate([-phone_width/2, 0, charger_back_plate_depth + charger_depth + manifold_slop]) phone_shape();
    translate([0, charger_diameter/2 + charger_height_from_table, 0])
    translate([0, 0, charger_back_plate_depth]) cylinder(r = charger_diameter/2, h = charger_depth + 2*manifold_slop, $fn = resolution*16);
  }
  mirror([1, 0, 0]) difference() {
    translate([phone_width/2, charger_height_from_table + charger_diameter/2, 0]) cylinder(h = charger_back_plate_depth + charger_depth + phone_depth, r = charger_holder_thickness);
    translate([-phone_width/2, 0, charger_back_plate_depth + charger_depth + manifold_slop]) phone_shape();
    translate([0, charger_diameter/2 + charger_height_from_table, 0])
    translate([0, 0, charger_back_plate_depth]) cylinder(r = charger_diameter/2, h = charger_depth + 2*manifold_slop, $fn = resolution*16);
  }
}

back_plate();
%translate([-phone_width/2, phone_height_from_table, charger_back_plate_depth + charger_depth]) phone_shape();

```


[User]
I'm looking to create a cufflink holder, and I've got some ideas about how it should work, but I need your help to generate the OpenSCAD code.

Essentially, it's going to have a base plate with a number of slots or 'holders' to secure cufflinks. The holders will be angled slightly, and there will be two rows of these holders, one angled to the left and one to the right. It's intended to be something that can be easily mounted on a wardrobe door, like with Blu-Tack.

Here are the specifics:

*   **Holders:**
    *   Each holder should be a rectangular block with a rounded end for the cufflink to sit against.
    *   The holders should be angled at 3 degrees, with the first set of holders angled counter-clockwise, and the second set clockwise.
    *   There should be a number of these holders in a row, and that number should be variable. Let's start with 4 holders.
    *   The overall space allocated for each holder including the gap should be 20mm wide.
    *   The holder itself should be 3mm wide and 3mm high, with a length of 21.5mm.
    *   There should be a small gap between each row of holders (4mm).
    *   The rounded end of the holder should be a half-sphere, with a small 'indent' made to fit the cufflink better. It is essentially a sphere, cut by a cube that is centered.
*   **Base Plate:**
    *   The base plate should be a rectangular plate.
    *   It should be slightly wider than the total width of all the holders and the gaps between the holders, with a small margin (2mm) on each side.
    *   The length of the plate is 4mm, with a 0.5mm offset.
    *   The height of the base plate is 10mm.
    *   The base plate should have a slight angle as well (4 degrees), but this angle will be around the Y axis.
*   **General:**
    *   I want to be able to vary the number of holders.
    *   I'd also like to adjust the other measurements easily through variables at the top of the file.
    *   Let's start with a high resolution (e.g. `$fn=80`) so the rounded part is smooth.

Could you provide me with the OpenSCAD code to achieve this? I do not expect the code to use any external libraries.

[Assistant]
Cufflink_Holder.scad:
```
// Resolution of radius
$fn=80;
// Variables
iNoOfHolders=4;
// Ratio: 2mm from side, 20mm in total (split in: 5 (free), 3 (material), 4 (free), 3 (material), 5 (free) = Total: 20mm)
lHolderLengthX=21.5;
lHolderWidthY=3;
lHolderHeightZ=lHolderWidthY;
lGapY=4;
lHolderMaxWidth=20;
lHolderSpacingY=(lHolderMaxWidth - lGapY - 2*lHolderWidthY) / 2;
lHolderRotationz=3;

lPlateMarginY=2;
lPlateHeightZ=10;
lPlateWidthY=iNoOfHolders*lHolderMaxWidth + 2*lPlateMarginY;
lPlateLengthX=4;
lPlateRotationY=4;

// Base Plate
rotate([0,lPlateRotationY,0]) translate([-lPlateLengthX+0.5,0,0]) cube([lPlateLengthX,lPlateWidthY,lPlateHeightZ]);

// Set # 1
	for (i = [0:iNoOfHolders-1]) {
    translate([0,lPlateMarginY + lHolderSpacingY +i*lHolderMaxWidth,0])
        rotate([0,0,lHolderRotationz]) cube([lHolderLengthX,lHolderWidthY,lHolderHeightZ]);
    translate([lHolderLengthX,lPlateMarginY + lHolderSpacingY +i*(lHolderMaxWidth)+ tan(lHolderRotationz)*lHolderLengthX + lHolderWidthY/2,0])
        cylinder(r=lHolderWidthY/2,h=lHolderWidthY);
    difference() {
        translate([lHolderLengthX,lPlateMarginY + lHolderSpacingY +i*lHolderMaxWidth + tan(lHolderRotationz)*lHolderLengthX + lHolderWidthY/2,lHolderHeightZ])
            sphere(lHolderWidthY/2);
        translate([lHolderLengthX-lHolderWidthY/2,lPlateMarginY + lHolderSpacingY +i*lHolderMaxWidth + tan(lHolderRotationz)*lHolderLengthX + lHolderWidthY/2,lHolderHeightZ])
            cube([lHolderWidthY,lHolderWidthY,lHolderWidthY], center = true);
    }
      }

// Set # 2
	for (i = [0:iNoOfHolders-1]) {
    translate([0,lPlateMarginY + lHolderSpacingY + lHolderWidthY + lGapY + i*lHolderMaxWidth,0])
        rotate([0,0,-lHolderRotationz]) cube([lHolderLengthX,lHolderWidthY,lHolderHeightZ]);
    translate([lHolderLengthX,lPlateMarginY + lHolderSpacingY + lHolderWidthY + lGapY + i*lHolderMaxWidth + -tan(lHolderRotationz)*lHolderLengthX + lHolderWidthY/2,0])
        cylinder(r=lHolderWidthY/2,h=lHolderWidthY);
    difference() {
        translate([lHolderLengthX, lPlateMarginY + lHolderSpacingY + lHolderWidthY + lGapY + i*lHolderMaxWidth -tan(lHolderRotationz)*lHolderLengthX + lHolderWidthY/2,lHolderHeightZ])
            sphere(lHolderWidthY/2);
        translate([lHolderLengthX-lHolderWidthY/2, lPlateMarginY + lHolderSpacingY + lHolderWidthY + lGapY + i*lHolderMaxWidth -tan(lHolderRotationz)*lHolderLengthX + lHolderWidthY/2,lHolderHeightZ])
            cube([lHolderWidthY,lHolderWidthY,lHolderWidthY], center = true);
    }
      }

```


[User]
Hi, I'm looking to have a customizable nut trap designed in OpenSCAD. I'm building a CNC router, and I need to be able to attach my tool holder securely. I need a parametric design so I can adjust it as needed.

I've seen a couple of designs online, but they're not quite what I need, so I want to make my own. This needs to be a more flexible design that allows for 2 or 3 nuts and adjustable spacing for those nuts. The basic shape should be a cylinder, with holes and nut traps cut out of it.

Here's a breakdown of the parameters I want to control:

*   **Number of Nuts:** This needs to be a parameter so I can switch between 2 or 3 nuts. Default should be 3.
*   **Overall Length:**  I want to specify the total length of the nut trap. This is based on my tool holder.
*   **Spacing between 1st & Last Nut:**  I need to be able to set the distance between the centers of the first and last nut traps. Default is 76.2mm.
*   **Spacing between 1st & 2nd Nut:**  If I'm using 3 nuts, I need to control the distance between the centers of the first and second nuts. This should be 0 if I am only using 2 nuts. The default should be 28mm.
*   **Nut Trap Diameter:** This is the diameter of the hole cut for the nut. This should be 21mm.
*   **Nut Trap Resolution:** This is the number of segments used when creating the cylinder for the nut trap body. 96 should be fine for the default.
*   **Bolt Hole Diameter:** This will be the diameter of the bolt holes. It needs to be 3.6mm for M3 bolts.
*   **Bolt Hole Resolution:** This is the number of segments used for creating the bolt hole cylinder. I think 24 should be sufficient.
*   **Nut Diameter:**  This is the diameter of the hexagonal part of the nut that fits into the nut trap. This should be 9.18mm.
*   **Nut Height:**  The height of the nut. This should be 4.7mm.
*   **Offset from Left for 1st Nut Trap:** This controls the distance from the left edge of the part to the center of the first nut trap. The default should be 19.05mm.
*  **Offset from Right of Last Nut Trap:** This will control the distance from the right edge of the part to the center of the last nut trap. The default is 8.35mm.
*   **Rotation of Nut Trap:** This should allow me to rotate the nut trap by a specified number of degrees.  This will allow the flats of the nut to align with the end of the part. It should default to 0 (no rotation) but also allow 30 degrees.
*   **Quantity to Print:** This will determine how many nut traps should be created. Default to 2
*   **Z-Origin:** This controls how far the design is extruded up. I need to be able to adjust this to adjust the thickness of the piece. Default is -2.

I need the design to make the nut trap holes have a small taper to help retain the nut. So I would expect to have one larger diameter cylinder used to cut the trap hole, and then an additional smaller diameter cylinder used to taper.

I'd also like to include a drill guide from a design I saw. The link is included above but I want it to be part of this design.

I think that covers everything. Please let me know if you need any more information or clarification. Thanks!

[Assistant]
Tool_Holder_Nut_Trap_rev1.scad:
```
//Parametric Nut trap for Mostly Printed CNC Router
//July 7,2015 By: David Bunch
//
//Revised 9/21/2015 to allow for 3 nuts
//I needed to make a length that would fit with my customized tool holder for
//a Mastergrip rotary tool I bought at Costco years ago, so I decided to make it parametric.
//Spacing for my tool holder is 53mm distance between holes

//Even though this is for the U.S. Standard Version, I use mm for dimensions
//
//Designed for Bosch Toolholder with Dust cover using 2 parts
//76.25mm 1st & 3rd hole
//28.01mm 1st & 2nd hole
//48.24mm 2nd & 3rd hole

//CUSTOMIZER VARIABLES

//1. Number of Nuts
NumNuts = 3;    //usually 2, but need 3 for Bosch with Vac attachment

//2. Spacing between 1st & Last Nut
NutSpacing=76.2;     //mm spacing between Nuts (original design seems to be 76.2mm)

//3. Spacing between 1st & 2nd Nut
NutSpacing2 = 28;    //Use 0 if only using 2 nuts

//4. Diameter of Nut Holder (21mm is U.S. Version Size)
THNT_Dia=21;      //Dia Tool Holder Nut Trap

//5. Resolution of Nut Holder (96 gives you about .7mm length segments in curve)
ires=96;    //Number of  segments for Tool Holder
                    //Circumference of 21mm Dia circle is 65.97
                    //Making each segment about .7mm will give you 96 for the number of sides

//6. Diameter of Bolt Threading
M3Dia=3.6;             //Dia. of Hole

//7. Resolution of Bolt Threads (24 gives .47mm length segments in curve)
M3_ires=24;         //Number of segments for M3 holes (.47mm segments)
                    //original design was 180 sides (.06mm segments)
//8. Diameter of Nut
M3NutDia=9.18;

//9. Height of Nut trap
M3Nut_Ht=4.7;

//10. Offset from Left for 1st Nut Trap
LtNutOffset=19.05;      //Original Design is 19.05mm

//11. Offset from Right of 2nd Nut Trap (Original is 6.35mm)
RtNutOffset=8.35;       //(I decided to add 2mm to this gap)

//12. Rotation of Nut Trap (0 = Original or 30 = Nut face parallel with End)
RotNut=0;	//	[0:Original, 30:parallel with End]

//13. Print 1 or 2 Nut Traps
Qty=2;

//14. Change this number to make it thicker or thinner
Z_Origin=-2;      //Z origin of Nut trap profile cylinder to extrude
//CUSTOMIZER VARIABLES END

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

Len=LtNutOffset+RtNutOffset+NutSpacing;     //Total Length of Nut Trap
echo("Len = ",Len);
RtNut_X=Len-RtNutOffset;
//Len=101.6;   //Original Tool Holder Nut Trap length was 101.6
Cube_z=(Z_Origin + 30)* (-1);
module Base()
{
    difference()
    {
        translate([0,0,Z_Origin])
        rotate([0,90,0])
        cylinder(d=THNT_Dia,h=Len,$fn=ires);
        translate([-1,-15,-30])
        cube([Len+2,30,30]);
    }
}
module DrawFinal()
{
    difference()
    {
        Base();
//Drill the Left Bolt Hole
        translate([LtNutOffset,0,-1])
        cylinder(d=M3Dia,h=12,$fn=M3_ires);
        if (NumNuts == 3)
        {
            if (NutSpacing2 > 0)
            {
                translate([LtNutOffset+NutSpacing2,0,-1])
                cylinder(d=M3Dia,h=12,$fn=M3_ires);
                translate([LtNutOffset+NutSpacing2,0,-1])
        rotate([0,0,RotNut])
                cylinder(d=M3NutDia,h=M3Nut_Ht+1,$fn=6);
                translate([LtNutOffset+NutSpacing2,0,M3Nut_Ht-.01])
        rotate([0,0,RotNut])            //Rotate Nut either 0 or 30
        cylinder(d1=M3NutDia,d2=M3NutDia-2,h=1,$fn=6);
            }
        }
//Cut Left Nut Trap
        translate([LtNutOffset,0,-1])
        rotate([0,0,RotNut])            //Rotate Nut either 0 or 30
                                        //rotating 30 gives more plastic between Nut and end
        cylinder(d=M3NutDia,h=M3Nut_Ht+1,$fn=6);        //6 sided Nut trap hole
        translate([LtNutOffset,0,M3Nut_Ht-.01])
        rotate([0,0,RotNut])            //Rotate Nut either 0 or 30
        cylinder(d1=M3NutDia,d2=M3NutDia-2,h=1,$fn=6);  //Add slight taper for nut hole
//Drill the Right Bolt Hole
        translate([RtNut_X,0,-1])
        cylinder(d=M3Dia,h=12,$fn=M3_ires);
//Cut Right Nut Trap
        translate([RtNut_X,0,-1])
        rotate([0,0,RotNut])            //Rotate Nut either 0 or 30
        cylinder(d=M3NutDia,h=M3Nut_Ht+1,$fn=6);        //6 sided Nut trap hole
        translate([RtNut_X,0,M3Nut_Ht-.01])
        rotate([0,0,RotNut])            //Rotate Nut either 0 or 30
        cylinder(d1=M3NutDia,d2=M3NutDia-2,h=1,$fn=6);  //Add slight taper for nut hole
    }
}
DrawFinal();
if (Qty == 2)
{
    translate([0,25,0])
    DrawFinal();
}
```


[User]
Hi! I'm looking to create a customizable drill guide for a CNC Z-pipe, similar to the one on Thingiverse (thing:910707).  I've remixed it to work with a tool holder with a vacuum attachment that uses three mounting points, but the original design only supported two, and I'd like to have more flexibility. I need to be able to customize the number of nuts/mounting holes (either two or three), the spacing between them, and the sizes. Basically, I want to rebuild this design from scratch but with a few enhancements.

Here's what I need:

*   **Number of Nuts/Holes:** This should be a variable, allowing the user to choose between 2 or 3 mounting points/holes.
*   **Nut Spacing:** I need two spacing variables – one for the standard spacing between the first and third nut (if using 3 nuts) or between the two nuts, and another for the spacing between the first and second nuts, where that middle nut will not be present if two nuts are selected.
*   **Drill Hole Size:** The diameter of the drill holes, with an additional tolerance for slip fit.
*   **Pipe Diameter:**  The outer diameter of the pipe, with a bit of tolerance for a slightly tight fit.
*   **Pipe Wall Thickness:** The thickness at the bottom of the pipe support structure.
*   **Resolution:** Resolution controls for the pipe and hole curves.
*   **Nut Trap Offsets:** Offsets from the left side of the first nut trap and from the right side of the last nut trap.
*   **Center Clamp Width:** Width of any optional clamping area between the mounting holes.
*   **Number of Guides:** Control whether one or two drill guides are created.

I think it would be best if this was done using a single scad file, using conditionals based on the number of nuts selected to ensure the proper middle hole is added. I will be printing this on my 3d printer so would need to use the `linear_extrude` function. Also, could you create the nut trap design using the nut trap offsets, so I don't need to use another file to print them? I would prefer to be able to modify them in place. It also appears that the current design does not allow for the user to configure the z-thickness of the nut traps. Could you add that variable?  I don't have any experience with external libraries, so no extra libraries are required for this project.

Essentially, I need a fully parametric and customizable drill guide that includes nut traps integrated into the design.

[Assistant]
Zpipe_DrillGuide_rev5.scad:
```
//Drill guide for Mostly Printed CNC Z Pipe
//7/3/2015  By: David Bunch
//Revised center cuts for larger Diameter holes to work better
//
//Designed for Bosch Toolholder with Dust cover using 2 parts
//76.25mm 1st & 3rd hole
//28.01mm 1st & 2nd hole
//48.24mm 2nd & 3rd hole

//CUSTOMIZER VARIABLES

//1. Number of Nuts
NumNuts = 3;    //usually 2, but need 3 for Bosch with Vac attachment

//2. Spacing between Nuts (Standard is 76.2mm)
NutSpacing = 76.2;      //(I used 53mm for the rotary tool I am using)

//3. Spacing between 1st & 2nd Nut
NutSpacing2 = 28;    //Use 0 if only using 2 nuts

//4. Dia of Drill Hole (9/64" Drill bit, Added .2mm for slip fit)
//M3 = 3.8;
DrSize = 3.8;

//5. Pipe Dia. to Use (Added 0.8 for slight tight fit)
OD = 23.8;              //23.7mm was a little tight & 24.0 was a little loose for me

//6. Thickness at bottom of Pipe
Thickness = 5;

//7. Resolution of Pipe (108 gives .688mm length segments)
Pipe_res = 108;

//8. Resolution of holes (24 gives .497mm length segments)
Hole_res = 24;

//9. Offset from Left for 1st Nut Trap
LtNutOffset = 19.05;      //Original Design is 19.05mm

//10. Offset from Right of 2nd Nut Trap (Original is 6.35mm)
RtNutOffset = 8.35;       //(I decided to add 2mm to this gap)

//11. Center Clamp Width
Cl_Wid = 6;

//12. Number of Holes (1 or 2)
Num_Holes=2;

//13. Print 1 or 2 Nut Traps
Qty = 2;

//CUSTOMIZER VARIABLES END
//----------------------------------------
//Begin calculations based on input variables
MidNutOffset = LtNutOffset + NutSpacing2;
echo("MidNutOffset = ", MidNutOffset);
TotCenGap=NutSpacing - DrSize - 12;         //I use 6mm plastic around holes
echo("TotCenGap = ",TotCenGap);

DrRad = DrSize / 2;
echo("DrRad = ", DrRad);
THK = OD /2 + Thickness;

DrLen = OD + Thickness + Thickness+2;

echo("THK = ",THK);

Width = OD + Thickness + Thickness;
echo("Width = ",Width);

WidSlice = Width + 2;
Rad = OD / 2;
echo("Rad = ", Rad);

Ht = LtNutOffset + NutSpacing + RtNutOffset;
echo("Ht = ", Ht);

CenCub_Z2 = LtNutOffset + DrRad + 3;         //6mm of plastic each side of hole

CenCub_Z1 = MidNutOffset + DrRad + 3;

CenCubLen1 = NutSpacing - NutSpacing2 - (6 + DrSize);                     //Use this if Cl_Wid = 0;
//CenCubLen2 = (TotCenGap - Cl_Wid) / 2;
CenCubLen2 = NutSpacing2 - (6 + DrSize);

echo("CenCubLen1 = ", CenCubLen1);
echo("CenCubLen2 = ", CenCubLen2);
//translate([LtNutOffset,0,0])
//%cube([DrRad + 3,4,10]);
module Base()
{
    translate([0,0,THK])
    rotate([0,90,0])
    difference()
    {
        translate([0,-THK])
        cube([THK,Width,Ht]);                   //Basic starting cube
        translate([0,0,-1])
        cylinder(d=OD,h=Ht+2,$fn=Pipe_res);     //Cut for where pipe is laid
        if (Cl_Wid > 0)
        {
            translate([-1,-Rad,CenCub_Z2])
            cube([OD,OD,CenCubLen2]);           //cube cut out of 1st part of center
            translate([-1,-Rad,CenCub_Z1])
            cube([OD,OD,CenCubLen1]);           //cube cut out of 2nd part of center
        } else {
            translate([-1,-Rad,CenCub_Z])
            cube([OD,OD,CenCubLen1]);          //cube cut out of center
        }
        translate([-1,-Rad,-1])
        cube([OD,OD,(LtNutOffset - DrRad - 6) + 1]);         //Slice a cube cut at left side
        translate([-(Thickness+2),-(WidSlice/2),LtNutOffset])
        cube([THK,WidSlice,NutSpacing]);        //Slice across Top for less plastic

        translate([0,0,LtNutOffset])
        rotate([0,90,0])
        cylinder(d=DrSize,h=DrLen,center=true,$fn=Hole_res);       //Drill Bottom Hole
        translate([0,0,LtNutOffset+NutSpacing2])
        rotate([0,90,0])
        cylinder(d=DrSize,h=DrLen,center=true,$fn=Hole_res);       //Drill Middle Hole
        if (Num_Holes == 2)
        {
                translate([0,0,LtNutOffset+NutSpacing])
                rotate([0,90,0])
                cylinder(d=DrSize,h=DrLen,center=true,$fn=Hole_res);    //Drill Top Hole
        }
    }
}
            //translate([-1,-Rad,CenCub_Z])
            //cube([OD,OD,CenCubLen2]);           //cube cut out of 1st part of center
Base();
if (Qty == 2)
{
    translate([0,Width+6,0])
    Base();
}
```


[User]
I'd like a parametric OpenSCAD design for a bathroom sponge holder, please. I've been experimenting, and I'm looking for something that's customizable, sturdy, and doesn't need support when printed.

Here are the basic requirements:

*   **Overall Structure:** The holder will consist of a base with support bars, a support structure for the sponge itself, and a front piece to help keep the sponge in place.
*   **Base:** The base should be a rectangular platform with a recessed area in the center to prevent water buildup. It needs support bars running along the length to add strength. I would like two of these support bars. There also needs to be two support bars, running perpendicular along the short side of the base, centered on the structure. The base should also have rounded edges, like quarter-circles on each corner.
*   **Sponge Support:** There should be a raised support structure on the base where the sponge will sit. I was thinking maybe two raised, parallel, flat bars of some thickness, attached to the base. There also needs to be some quarter-cylinders, attached to each raised bar, to support the sponge.
*  **Front Piece:** A semi-circular or half-cylinder piece attached to the front edge of the base to help keep the sponge from falling out. I want the semi-circle to be oriented with its flat side attached to the base.
*  **Customizability:** I need the following parameters to be adjustable:
    *   `length`: The overall length of the sponge holder.
    *   `width`: The overall width of the sponge holder.
    *   `height`: The height of the base.
    *   `thickness`: The thickness of the base, support bars, and the front piece.
    *   `supportHeight`: The height of the sponge support above the base.
    * `supportWidth`: The thickness of the sponge support

*   **No Supports:** The design needs to be such that it prints without needing support structures.

I'm aiming for something similar to what I've designed, but I think you can do better. I'd like you to use the `rcube.scad` library for the rounded edges of the base.

[Assistant]
sponge-holder2.1.scad:
```
// Attempted bath sponge holder
include <rcube.scad>

thickness = 10;
supportHeight = 20;

length = 90;
height = 5;
width = 80;

module base()
{
  union()
  {
    // Support bars
    translate([0, (width - thickness) / 3, 0])
    {
      cube(size = [length, thickness, height]);
    }
    translate([0, (width - thickness) * (2/3), 0])
    {
      cube(size = [length, thickness, height]);
    }
    translate([width / 2, 0, 0])
    {
      cube(size = [thickness, length - thickness, height]);
    }

    difference()
    {
      cube(size = [length, width, height]);
      translate([thickness, thickness, - thickness])
        cube(size = [length - thickness * 2, width - thickness * 2, thickness * 2 + height]);
    }
    difference()
    {
      translate([thickness / 2, width - thickness / 2, thickness / 2])
        sphere(r = thickness, $fn = 50);
      translate([-thickness / 2, width - thickness * 1.5, -thickness * 2])
        cube([thickness * 2 , thickness * 2, thickness * 2]);
    }

    difference()
    {
      translate([length - thickness / 2, width - thickness / 2, thickness / 2])
        sphere(r = thickness, $fn = 50);
      translate([length - thickness * 1.4, width - thickness * 1.5, -thickness * 2])
        cube([thickness * 2 , thickness * 2, thickness * 2]);
    }
  }
}

module halfCylinder(r, h)
{
  difference()
  {
    e = 0.2;
    cylinder(r = r, h = h, center = false);
    translate([0, -(r + e), -e])
      cube([2 * (r + e), 2 * (r + e), h + 2 * e]);
  }
}

module support()
{
  translate([ thickness, 0, 0])
    cube(size = [length - thickness * 2, thickness, supportHeight]);
  translate([ length / 4, 0 , thickness / 2 ])
    rotate([0, 90, 90])
      halfCylinder(r = length / 4, h = thickness);
  translate([ length * (3/4), 0, thickness / 2 ])
    rotate([0, 90, 90])
      halfCylinder(r = length / 4, h = thickness);
}

module front()
{
  translate([length / 2, width, 0])
    rotate([90, 90, 0])
      halfCylinder(r = length / 2, h = thickness);
}

module assemble()
{
  width = width + 2 * thickness;

  union()
  {
    support();
    base();
    front();
  }
}

assemble();

```
sponge-holder2.scad:
```
// Attempted bath sponge holder
include <rcube.scad>

thickness = 7;
supportWidth = 15 + thickness;

length = 90;
height = 5;
width = 60 + 2 * thickness;

module base()
{
  union()
  {
    translate([0, (width - thickness) / 2, 0])
      cube(size = [length, thickness, height]);
    difference()
    {
      cube(size = [length, width, height]);
      translate([thickness, thickness, - thickness])
        cube(size = [length - thickness * 2, width - thickness * 2, thickness * 2 + height]);
    }
    difference()
    {
      translate([thickness / 2, width - thickness / 2, thickness / 2])
        sphere(r = thickness, $fn = 50);
      translate([-thickness / 2, width - thickness * 1.5, -thickness * 2])
        cube([thickness * 2 , thickness * 2, thickness * 2]);
    }

    difference()
    {
      translate([length - thickness / 2, width - thickness / 2, thickness / 2])
        sphere(r = thickness, $fn = 50);
      translate([length - thickness * 1.4, width - thickness * 1.5, -thickness * 2])
        cube([thickness * 2 , thickness * 2, thickness * 2]);
    }
  }
}

module support()
{
  cube(size = [length, thickness, supportWidth]);
}

module halfCylinder(r, h)
{
  difference()
  {
    e = 0.2;
    cylinder(r = r, h = h, center = false);
    translate([0, -(r + e), -e])
      cube([2 * (r + e), 2 * (r + e), h + 2 * e]);
  }
}

module front()
{
  translate([length / 2, width, 0])
    rotate([90, 90, 0])
      halfCylinder(r = length / 2, h = thickness);
}

module assemble()
{
  union()
  {
    support();
    base();
    front();
  }
}

assemble();

```


[User]
Hey there, I'm looking to design a custom rock climbing hold and could really use some help generating the OpenSCAD files. I've got some basic ideas but need them parameterized so I can tweak things later.

Here's what I'm thinking:

The core shape should be built using a `hull` operation, connecting a base and several shaping spheres for the grip. The base will be a sphere, and the grip will consist of a few spheres at different locations - one at the top, and a couple defining the sides of the grip, as well as some out at the widest part. The main grip spheres will need some variables to adjust their position on the grip, kind of like shaping points.

I'd like to be able to control these specific parameters:

*   **GripDepth:** How far the grip extends out from the base (the Z-axis value of the top grip sphere).
*   **BaseSize:** The radius of the base sphere.
*   **GripHeight:** How far down the grip top sphere is from the base (the negative Z-axis offset).
*   **GripWidth:** The total width of the grip (distance between the two outer-most grip spheres on the Y-axis).
*   **GripComfort:** The radius of all the grip spheres.
*   **ShapingConstant1:** A unitless value that adjusts the Z-axis positions of the shaping grip spheres.
*   **ShapingConstant2:** Another unitless value for adjusting the Y-axis positions of the shaping grip spheres.
*    **BoltLocation:** The X-axis offset of the bolt hole (relative to the origin).
*    **BoltEngagement:** The Z-axis offset of the bolt hole (relative to the origin).

I also need a module to define the bolt clearance. This will be a union of two cylinders: a short, wider one at the surface of the hold and a longer, narrower one that extends further into the hold. I'm using metric threads so the bolt clearance should be sized appropriately. This will also be parametric, but with its own set of parameters for thread engagement.

Finally, I'd like a module that includes a large cube to simulate a wall so that I can see how the rock hold will look against something. It should be easy to adjust the wall size.

The design should use the `hull()` operation, and then a `difference()` operation to remove the bolt clearance and wall for ease of viewing. The entire thing needs to be parameterized, and should be easy to customize. I'm thinking that most of the math should be in the variables at the top of the file, with the modules fairly straightforward. I'd really appreciate it if the output of each operation was clearly named (i.e. `module Basic_Hold()` with its components inside, then `module Complete_Hold()`, for the final output).

Could you generate the necessary OpenSCAD file(s) for this? I'm happy to work in a single file, so long as the modules are clearly named and organized.

[Assistant]
RockWallHold.scad:
```
//Created by Kyle Barie
//MY4777 10/06/2015
//Rock Wall Hold

$fa = 0.5;
$fs = 0.5;

//Units = mm;

GripDepth = 40;
BaseSize = 35;
GripHeight = 10;
GripWidth = 80;
GripComfort = 4;
ShapingConstant1 = 0.75;  //Unitless: Controls Z position of shaping points
ShapingConstant2 = 3.5;    //Unitless: Controls Y position of shaping points
BoltLocation = 25;
BoltEngagement = 25;

//Wall Size. Only change if scaleing very large
w = 600;
h = 300;
l = 100;

module WALL()
{
    translate([w/4,0,-(l/2)]){
cube([w,h,l] , center=true);
    }
}

module Base()
{
  translate([(BaseSize*1.3),0,0]) {
    sphere(BaseSize);
}

}

module Grip()
{
  //Top point
 translate([-(GripHeight),0,GripDepth]) {
    sphere(GripComfort*1.25);
}

 //Shaping Points
translate([-(GripHeight/2),(GripWidth/ShapingConstant2),(GripDepth*ShapingConstant1)]) {
    sphere(GripComfort);
}
translate([-(GripHeight/2),-(GripWidth/ShapingConstant2),(GripDepth*ShapingConstant1)]) {
    sphere(GripComfort);
}
 //Extent Points
translate([0,(GripWidth/2),0]) {
    sphere(GripComfort);
}
translate([0,-(GripWidth/2),0]) {
    sphere(GripComfort);
}

}

module BoltClearance()
{
 *import("Bolt.stl");

     union(){
    cylinder(40,d=25);
   translate([0,0,-60]){
    cylinder(61,d=10);
   }
  }
}

module Basic_Hold()
{
difference(){

hull(){

Base();

Grip();
}

WALL();
}
}

module Complete_Hold()
{
difference(){
Basic_Hold();

translate([BoltLocation,0,BoltEngagement]){
BoltClearance();
}
}
}

Complete_Hold();
```


[User]
I'd like to design a customizable softbox for a NeoPixel LED ring. I've seen some examples, but I need something really flexible.

Here's the basic concept: I have a circular NeoPixel ring, and I want a softbox that fits around it, creating a diffused light. The softbox should have a front opening that's smaller than the overall diameter of the box, sort of like a shallow truncated cone. I’ll be 3D printing this, so some design considerations for printing should be in mind.

Here are the key parameters I need to control:

*   **`Segments`**: The number of LEDs on the NeoPixel ring.
*   **`RingLedDiameter`**: The diameter of the LED ring at the center of the LEDs, in millimeters.
*   **`RingInnerDiameter`**: The inner mounting diameter of the LED ring (for mounting domes), in millimeters. This could be zero if no mounting domes are needed.
*   **`RingOuterDiameter`**: The outer mounting diameter of the LED ring, also for mounting domes, in millimeters. Again, this could be zero.
*  **`DisplayInnerDiameter`**: The diameter of the *inner* edge of the visible opening of the softbox, in millimeters.
*   **`DisplayOuterDiameter`**: The diameter of the *outer* edge of the visible opening of the softbox, in millimeters.
*   **`MountingDepth`**: The total depth of the softbox, in millimeters.
*   **`WallWidth`**: The thickness of the softbox wall, in millimeters.
*   **`LedDiameter`**: The diameter of a single LED, in millimeters.
*   **`Mountings`**: The number of mounting domes that will be included
*   **`UsePrintSupport`**: A boolean (0 or 1) to enable a support ring to make printing easier. Set to 0 for no support ring, 1 for a support ring.

I'd like the design to be parametric so that I can easily modify these values. The mounting domes should be optional, and when present, they should include holes for 3mm screws.

The design should account for the fact that the LEDs themselves are located a certain distance from the mounting surfaces. The inside of the softbox (behind the front opening) should also be considered, and should accommodate the shape of the LED ring. The wall of the softbox should transition smoothly from the mounting surface to the front opening.

I’m printing this on a standard FDM printer, so no crazy thin walls or overhangs please. I’d also like to be able to export the final result as an STL, so please make sure that the OpenSCAD file uses the `$fs` and `$fn` variables appropriately.

I’m thinking this could be done in a single scad file, but if it makes sense to split things up, that's okay too. Thanks in advance for your help!

[Assistant]
SoftBoxNeoPixelRing01.scad:
```
// Template for SoftBox for NeoPixel-LED-Ring
// by Jochen Krapf
// Version 1.02

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

/* [Global] */

// To render the parts choose the correcponding Part Name

Part = "Ring";   // [Ring:Complete Ring,Test:Test Single Segment]

// Parameters

// Count of LEDs of the ring
Segments = 24;

// PCB Ring Diameter at middle of LEDs in mm
RingLedDiameter = 59;

// PCB Ring Inner Mounting Diameter in mm
RingInnerDiameter = 52.0;

// PCB Ring Outer Mounting Diameter in mm
RingOuterDiameter = 65.7;

// Visible Inner Ring Diameter of SoftBox in mm
DisplayInnerDiameter = 45;

// Visible Outer Ring Diameter of SoftBox in mm
DisplayOuterDiameter = 90;

// Mounting Depth in mm
MountingDepth = 15;

// Wall Width in mm
WallWidth = 1;

// Diameter of a single LED in mm
LedDiameter = 5;

// Count of Mounting Domes
Mountings = 4;

// Use Printer Support
UsePrintSupport = 1;   // [0:No Print Support,1:Print Support Ring 1mm]

/* [Hidden] */

// Level of Details - Set to 0.1 for export to stl
//$fn = 24*4;
$fs = 0.5;

Wall = WallWidth;
SegmentAngle = 360/Segments;
SegmentAngle2 = SegmentAngle/2;
ScrewDiameter = 3;
mountingSteps = floor ( Segments / Mountings + 0.5 );

// Modules

module PrintSupport()
{
	difference()
	{
		// outer circle
		cylinder(d=RingLedDiameter+1, h=MountingDepth, $fn=90);

		// inner circle
		translate([0,0,-1])
			cylinder(d=RingLedDiameter-1, h=MountingDepth+2, $fn=90);
	}
}

module SegPlateTemplate(di, do, w)
{
	difference()
	{
		// outer circle
		cylinder(d=do, h=Wall, $fn=90);

		// inner circle
		translate([0,0,-1])
			cylinder(d=di, h=Wall+2, $fn=90);

		// cut to segment
		for ( r = [180+SegmentAngle2,-SegmentAngle2] )
			rotate([0,0,r])
				translate([w,-do,-1])
					cube([do*2,do*2,Wall+2]);
	}
}

module SegTemplate(di, do, w, l)
{
render()
	difference()
	{
		// make solid softbox
		hull()
		{
			// upper segment plate
			translate([0,0,MountingDepth-Wall])
				SegPlateTemplate(di, do, w);

			// lower led circle
			translate([0,RingLedDiameter/2,0])
				cylinder(d=l, h=Wall, $fn=24);
		}

		// reconstruct koncave inner circle (got lost by hull)
		translate([0,0,-0.01])
			cylinder(d1=RingLedDiameter-l, d2=di, h=MountingDepth-Wall+0.02, $fn=90);
		translate([0,0,MountingDepth-Wall-0.01])
			cylinder(d=di, h=Wall+0.02, $fn=90);
	}
}

module MountingTemplate()
{
	screw = ScrewDiameter*0.7;

	difference()
	{
		cylinder(d=5, h=MountingDepth);

		translate([-screw/2,-screw/2,-1])
			cube([screw,screw,MountingDepth+2]);
	}
}

module Ring()
{
	difference()
	{
		union()
		{
			// segments outside
			for ( r = [0:SegmentAngle:359] )
				rotate([0,0,r])
					SegTemplate(DisplayInnerDiameter-2*Wall,DisplayOuterDiameter+2*Wall,Wall/2, LedDiameter+2*Wall);

			// mounting domes
			if (Mountings>0)
				for ( r = [0:SegmentAngle*mountingSteps:359] )
					rotate([0,0,r])
					{
						if (RingInnerDiameter>0)
							translate([0,(RingInnerDiameter-ScrewDiameter)/2,0])
								MountingTemplate();
						if (RingOuterDiameter>0)
							translate([0,(RingOuterDiameter+ScrewDiameter)/2,0])
								MountingTemplate();
					}

			if (UsePrintSupport>0)
				PrintSupport();
		}

		// segments inside
		for ( r = [0:SegmentAngle:359] )
			rotate([0,0,r])
				translate([0,0,0.01])
					color( [1, 1, 1, 1] ) SegTemplate(DisplayInnerDiameter,DisplayOuterDiameter,-Wall/2, LedDiameter);

		// LEDs
		for ( r = [0:SegmentAngle:359] )
			rotate([0,0,r])
				translate([0,(RingLedDiameter)/2,-1])
					#cylinder(d=LedDiameter, h=1.02);
	}
}

module Test()
{
	difference()
	{
		union()
		{
			SegTemplate(DisplayInnerDiameter-Wall,DisplayOuterDiameter+Wall,Wall/2, LedDiameter+2*Wall);

			if (RingInnerDiameter>0)
				translate([0,(RingInnerDiameter-ScrewDiameter)/2,0])
					MountingTemplate();
			if (RingOuterDiameter>0)
				translate([0,(RingOuterDiameter+ScrewDiameter)/2,0])
					MountingTemplate();
		}

		translate([0,0,0.01])
			SegTemplate(DisplayInnerDiameter,DisplayOuterDiameter,-Wall/2, LedDiameter);

		translate([0,(RingLedDiameter)/2,-1])
			#cylinder(d=LedDiameter, h=1.02);
	}
}

//	color( [0.25, 0.5, 1, 0.25] )

// Use Modules

if (Part == "Ring")
{
	Ring();
}

if (Part == "Test")
{
	Test();
}

echo("Outer Wall Angle [deg] =", atan ( ((DisplayOuterDiameter - RingLedDiameter - LedDiameter - 2*Wall) / 2) / (MountingDepth - Wall) ) );
echo("Inner Wall Angle [deg] =", atan ( -((DisplayInnerDiameter - RingLedDiameter + LedDiameter + 2*Wall) / 2) / (MountingDepth - Wall) ) );

```


[User]
I'm looking to create a parametric magnet holder for my desk. I've got some strong block magnets that I want to use to hold various small metal objects. I've already drafted something, but I'd rather have something a bit more robust and flexible.

Here's the basic idea:

*   **Magnet Blocks:** The holder should accommodate rectangular block magnets. I want to be able to easily adjust the dimensions (width, depth, height) of these magnets using parameters. It also needs to allow me to vary how many blocks there are.
*   **Rows and Spacing:** I'd like to be able to have multiple rows of magnets, and also control the spacing between those rows.
*   **Mounting:** The holder needs to have mounting points that allow me to screw it into the underside of my desk. I should be able to set the number of mounting points and the distance between them. This means each screw hole should have an outer cylinder that provides material to screw into and an inner cylinder defining the actual screw hole.
*   **Robustness:** The design should have a parameter to control the 'skin depth', or the thickness of the material surrounding the magnets, and the overall sturdiness.
*   **Friction Ribs:** On the inside of the holder, I want to have small ribs or bumps that press against the magnets to keep them snugly in place. I'd like to control the angle and radius of these ribs, their 'inward' offset, the number of them, and their spacing.
*   **Teeth:** To help prevent objects from rotating when stuck to the magnet, I want to have small 'teeth' sticking out from the main block. Parameters should control the X, Y, and Z dimensions of the teeth, the amount of overhang they have, the number of teeth, and the distance between teeth. Also each 'tooth' needs to have an overhang and a 45 degree angle on both the top and bottom of each. It should create a 'bridge' on each tooth, ensuring it can be printed correctly.

The goal is to make this very configurable, so I can easily adapt it to different magnet sizes and mounting needs. I'd like the design to use modules, and I assume you will be using the `difference()`, `union()`, and `intersection()` functions in OpenSCAD. I don't expect you to include a library, but I want to know if any libraries are needed.

[Assistant]
magnet_holder.scad:
```
/* Magnet Holder.scad */

$fn = 30;

// The Magnet:
blockWidth = 49.1;
blockDepth = 9.2;
blockHeight = 4.9;

// Amount of magnets
nrOfBlocks = 4;

// Nr of rows of magnets:
nrOfRows = 1;

// space between them
rowDist = 20;

nrOfMounts = 3; // * 2 == nr of screws.

// The amount of PLA around the magnet and overall sturdyness
skinDepth = 2;

// screw holes:
holeInnerR = 5 / 2;
holeOuterR = 10 / 2;

totalWidth = (blockWidth * nrOfBlocks);
mountWidth = holeOuterR * 2;

distScrews = mountWidth + (totalWidth - (mountWidth * nrOfMounts)) / (nrOfMounts - 1);

// These are little 'bumps' on the inside that exercise some pressure on the magnets
// keeping them in place.
ribAngle = 3;
ribRadius = 2;
ribOffset = .1; // move 'inward' by this distance
nrOfRibs = nrOfBlocks * 3 + 1;
ribDistance = (ribRadius * 2) + (totalWidth - (ribRadius * 2 * nrOfRibs)) / (nrOfRibs - 1);

// The teeth prevent objects from turning around, snapping to the magnet
teethX = 1.5;
teethZ = 1.7; // was 1.3
teethOverhang = .3;
teethY = skinDepth + teethOverhang;

nrOfTeeth = nrOfBlocks * 5 + 1;
teethDistance = (teethX * 2) + (totalWidth - (teethX * 2 * nrOfTeeth)) / (nrOfTeeth - 1);

teethDistance = (totalWidth - teethX) / (nrOfTeeth - 1);

for (y = [0 : nrOfRows -1]) {
    translate (v = [0, y * (rowDist + blockDepth + (skinDepth * 2)), 0]) {
        // body
        difference () {
            cube ([totalWidth, blockDepth + 2 * skinDepth, blockHeight + skinDepth]);
            translate (v = [-1, skinDepth, skinDepth])
                cube (size = [totalWidth + 2, blockDepth, blockHeight + 1]);
        }

        // Teeth:
        for (x = [0 : nrOfTeeth -1]) {
            translate (v = [x * teethDistance, 0, skinDepth + blockHeight]) {
                difference () {
                    burtBridgeHouse(teethX, teethY, teethZ);

                    // The 45 degree edge on the teeth:
                    translate (v = [-1, skinDepth, 0])
                        rotate (a = [-45, 0, 0])
                            cube ([teethX + 2, teethX, teethX]);
                }

                translate (v = [0, blockDepth + skinDepth - teethOverhang, 0]) {
                    difference () {
                        burtBridgeHouse(teethX, teethY, teethZ);

                        translate (v = [0, teethOverhang, 0]) {
                            rotate (a = [45 + 90, 0, 0]) {
                                cube ([teethX + 2, teethX, teethX]);
                            }
                        }
                    }
                }
            }
        }

        // friction ribs:
        intersection () {
            cube ([totalWidth, blockDepth + 2 * skinDepth, blockHeight + skinDepth]);

            for (x = [0 : nrOfRibs - 1]) {
                rotate (a = [- ribAngle, 0, 0])
                translate (v = [x * ribDistance + ribRadius, skinDepth - ribRadius - ribOffset, skinDepth])
                    cylinder (r = ribRadius, h = blockHeight * 2);

                rotate (a = [ribAngle, 0, 0])
                translate (v = [(ribDistance / 2) + x * ribDistance + ribRadius, skinDepth + blockDepth + ribRadius + ribOffset, skinDepth])
                    cylinder (r = ribRadius, h = blockHeight * 2);
            }
        }
    }
}

// Mounting lips
for (x = [0 : nrOfMounts - 1]) {
    difference () {
        union () {
            translate (v = [x * distScrews, - holeOuterR, 0]) {
                cube ([mountWidth, holeOuterR * 2 + (blockDepth + 2 * skinDepth) * nrOfRows + rowDist * (nrOfRows - 1), skinDepth]);

                translate (v = [holeOuterR, 0, 0])
                    cylinder (r = holeOuterR, h = skinDepth);

                translate (v = [holeOuterR, holeOuterR * 2 + ((blockDepth + 2 * skinDepth) * nrOfRows) + (rowDist * (nrOfRows - 1)), 0])
                    cylinder (r = holeOuterR, h = skinDepth);
            }
        }

        // holes:
        translate (v = [x * distScrews, - holeOuterR, -1]) {
            translate (v = [holeOuterR, 0, 0])
                cylinder (r = holeInnerR, h = skinDepth + 2);

            translate (v = [holeOuterR, holeOuterR * 2 + (blockDepth + 2 * skinDepth) * nrOfRows + (rowDist * (nrOfRows - 1)), 0])
                cylinder (r = holeInnerR, h = skinDepth + 2);
        }
    }
}

module burtBridgeHouse(sizeX, sizeY, sizeZ) {
    // this will generate a smooth bridge with a 4 degree angle
    // use this as a negative cube in cases where it would form a bridge
    // assuming y is the stupid dimension that's just every wide everywhere

    intersection () {
        // The main block, the desired shape
        cube ([sizeX, sizeY, sizeZ]);

        // intersect with what's possible to print:
        union () {
            // top diamond shape:
            // half a diagonal: sqrt(pow(sizeX / 2, 2) * 2)
            // whole diagonal;  sqrt(pow(sizeX, 2) * 2)
            translate (v = [(- sqrt(pow(sizeX / 2, 2) * 2) / 2) + (sizeX / 2), 0, sizeZ - sqrt(pow(sizeX / 2, 2) * 2) / 2])
                rotate(a = [0, 45, 0])
                    cube([(sizeX / 2), sizeY, sizeX / 2]);

            // middle part is a cylinder:
            translate(v = [sizeX / 2, sizeY, sizeZ - sqrt(pow(sizeX / 2, 2) * 2)])
                rotate(a = [90, 0, 0])
                    cylinder (r = sizeX / 2, h = sizeY);

            // bottom cube for extra bass // it extends way below the bottom, but that's being cut off by the intersection with the main cube:
            translate(v = [0, 0, - sqrt(pow(sizeX / 2, 2) * 2)])
                cube([sizeX, sizeY, sizeZ]);
        }
    }
}

```


[User]
Alright, so I'm looking to design a rock climbing hold, and I've got this basic idea in mind. I need a parametric OpenSCAD model that I can easily adjust later. I'm thinking of a hold that has a generally rounded, blob-like shape, but with a flat back that will mount to the wall. It also needs a counterbored hole that goes all the way through for a bolt.

The basic shape should be created by combining a few spheres together, with some scaling, translating, and differences. To get a better idea of how the pieces should go together, I'll describe the steps I took in my provided design. First there should be a large central sphere, then a cylinder centered on the same origin extending out from it. Then, I need to add in 3 more scaled spheres that sit at different points along the Z axis, the last of which is at z=41 and scaled down more than the rest, which adds some nice variation.

Finally, I need to cut out a flat bottom using a cube so it will sit flat against the wall. I also want to cut the bolt hole by subtracting the bolt shape. The bolt itself consists of a cylinder and a wider cylinder for the head, so use that design.
Use the BOLTS library for bolt generation. Finally, cut the mounting hole through the center of the hold using a cylinder. It'd also be great if the bolt parameters were easy to adjust as parameters, like bolt diameter, bolt head diameter, and overall bolt length.

Can you design this in a way that I can modify the overall size and shape of the blob, the bolt parameters, and the mounting hole diameter easily? Thanks!

[Assistant]
Rock_Hold.scad:
```
//Connor Kmiec
//Rock Wall Hold Project - MY4777
// Bolt for rock wall assignment
// Inane imperial units inexplicably in use in a free state: 3/8" - 16x2-1/2"
// All measurements below in mm

//Bolt head diamter with clearance for tool
B=25;

// Bolt head height
h=8;

// Bolt overall length
l=69.5;

// diamter
d=11;

$fn=100;

module bolt(){
union(){
		translate([0,0,l-0.1])cylinder(h=h, r=B/2); //space for head
		cylinder(h=l, r=d/2); // bolt shaft
		}
					}

difference(){
union(){
translate([0,0,20])sphere(30, $fn=100);
cylinder(h = 40, r1 = 30, r2 = 30, center = true,$fn=100);
translate([0,0,-15])scale([1,1,0.33])sphere(35, $fn=100);
translate([0,0,5])scale([1,1,0.33])sphere(35, $fn=100);
translate([0,0,25])scale([1,1,0.33])sphere(34, $fn=100);
translate([0,0,41])scale([1,1,0.33])sphere(28, $fn=100);

};
translate([0,0,-70])cube([1000,1000,100],center=true);
translate([0,0,-40])bolt();
translate([0,0,135])cylinder(h = 200, r1 = 12.5, r2 = 12.5, center = true,$fn=100);
}

```


[User]
Okay, I'm looking to create a parametric OpenSCAD design that generates various polyhedral forms found in the cubic crystal system. I've got some existing code, but it's a bit clunky and I want something more flexible and easier to customize, and I'd like the preview to render properly.

Basically, I want to be able to choose from 15 different shapes: the cube, rhombic dodecahedron, tetrahexahedron, pentagonal dodecahedron, octahedron, tetrahedron, icositetrahedron, triakis tetrahedron, triakis octahedron, deltoid dodecahedron, hexakis octahedron, diakisdodecahedron, hexatetrahedron, pentagonal icositetrahedron, and finally the tetrahedral pentagonal dodecahedron.

These shapes can be defined by their Miller indices, which represent the normal vectors of their faces. I'd also like to be able to specify the distance of each face from the origin, which I think is what's causing the preview to be small currently. Some of these shapes also have specific symmetry operations that need to be applied to the base face definitions. For example the pentagonal dodecahedron only uses the subset of faces where the Miller index is in the same order as the base face, while other require even/odd face filtering.

I have a basic understanding of OpenSCAD, but I don't have much experience working with complex geometry and transformations like this. I'm also very interested in a flexible design that will allow me to easily extend this to create my own forms in the future.

Here's a breakdown of what I need:

*   **Parametric Selection:** A parameter to select the form from the list of 15.
*   **Size Control:** A parameter to control the overall size of the generated shape.
*   **Face Distance Control:** A parameter or a set of parameters to control the distance of each face from the origin. Ideally a list or even a dictionary would be useful, so I can experiment with varying distances for each face.
*   **Miller Indices:** The code should be able to create all 15 of the shapes described from their Miller indices:

    *   Cube: \[1, 0, 0]
    *   Rhombic dodecahedron: \[1, 1, 0]
    *   Tetrahexahedron: \[1, 2, 0]
    *   Pentagonal dodecahedron: \[1, 2, 0] (with order filtering)
    *   Octahedron: \[1, 1, 1]
    *   Tetrahedron: \[1, 1, 1] (with parity filtering)
    *   Icositetrahedron: \[2, 1, 1]
    *   Triakis tetrahedron: \[2, 1, 1] (with parity filtering)
    *    Triakis octahedron: \[2, 2, 1]
    *   Deltoid dodecahedron: \[2, 2, 1] (with parity filtering)
    *   Hexakis octahedron: \[3, 2, 1]
    *   Diakisdodecahedron: \[3, 2, 1] (with order filtering)
    *   Hexatetrahedron: \[3, 2, 1] (with parity filtering)
    *   Pentagonal icositetrahedron: \[3, 2, 1] (with gyroid symmetry)
    *   Tetrahedral pentagonal dodecahedron: \[3, 2, 1] (with order and parity filtering)
*   **Symmetry Handling:** The code should be able to handle the symmetry operations (full, tetrahedral, gyroid, trapezohedral etc) needed for the various forms. This includes being able to derive the list of faces from the initial miller indices using expansion, permutations, and combinations and finally, filtering based on order, parity, or direction.
*   **Modular Design:** I'd prefer the code to be modular, making it easy to add new forms and symmetry operations later on.
*   **Preview:** I'd like the preview to display the forms with a decent size, not the tiny version I'm seeing in my current script. I think this is related to the fact the preview is rendering all faces, which I don't want.
*   **Coloring:** it would be cool if each form was a unique color, ideally this could be controlled with a list of colors that cycled.

I don't need any external libraries for this, just pure OpenSCAD. I think with the right functions, this should be possible in a clear way. I'm really looking for a well-structured and maintainable solution. If you have an idea about how best to manage the complexity, I'm all ears.

I think that about covers it. Please let me know if you need any clarification or have questions for me.

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

   cubic system forms

   see http://kitwallace.tumblr.com/tagged/crystal

   Kit Wallace October 2015

   doesnt work in Thiniverse customiser - preview is very small

*/

form=5; // [0:cube,1:rhombic dodecahedron,2:tetrahexahedron,3:pentagonal dodecahedron,4:octahedron,5:tetrahedron,6:icositetrahedron,7:triakis tetrahedron,8:triakis octahedron,9:deltoid dodecahedron,10:hexakis octahedron,11:diakisdodecahedron,12:hexatetrahedron,13:pentagonal icositetrahedron,14:tetrahedral pentagonal dodecaheron]

/* [orientation] */
//experimentation needed since size varies with form
size=20; // [1:40]

// basic functions

function flatten(l) = [ for (a = l) for (b = a) b ] ;

function vcontains(val,list) =
     search([val],list)[0] != [];

function distinct(list,dlist=[],i=0) =  // return only distinct items of list
      i==len(list)
         ? dlist
         : vcontains(list[i],dlist)
             ? distinct(list,dlist,i+1)
             : distinct(list,concat(dlist,[list[i]]),i+1)
      ;

function sum(list,i=0) =
      i < len(list)
        ?  list[i] + sum(list,i+1)
        :  0;

// solid construction

module orient_to(centre, normal) {
      translate(centre)
      rotate([0, 0, atan2(normal.y, normal.x)]) //rotation
      rotate([0, atan2(sqrt(pow(normal.x, 2)+pow(normal.y, 2)),normal.z), 0])
      children();
}

module face(normal, d=1, size=20) {
   orient_to([0,0,0],normal)
       translate([0,0, d + size/2])
            cube([10*size,10*size,size],center=true);
}

module solid(faces,d=1,color="lightblue",size=5) {
 /* faces is a list of normals (Miller indices)
    d is either a scaler, the distance of each face from the origin or a list of distances, one for each face
 */
 color(color)
    difference() {
     sphere(size,center=true);
     for(i = [0:len(faces)-1])  {
       face = faces[i];
       fd = len(d) == undef ? d : d[i];
       face(face,d=fd,size=size);
     }
 }
}

// functions to expand a form into faces using eg perms and combs

function perm3(l) =
// lazy until I code general perms with duplicates
 distinct(
   [[l[0],l[1],l[2]],
   [l[0],l[2],l[1]],
   [l[1],l[0],l[2]],
   [l[1],l[2],l[0]],
   [l[2],l[0],l[1]],
   [l[2],l[1],l[0]]
]);

function combs(list,n=0) =
   n < len(list)-1
   ? [for (j=list[n])
       for (sl= combs(list,n+1))
           concat(j,sl)
     ]
   : list[n] ;

function expand(list) =
// needs a better name
  [for (x= list)
      x== 0 ? 0 : [x,-x]
  ];

// face generators

function shift(face,k=1) = [face[k%3],face[(k+1)%3],face[(k+2)%3]];

function cycle(face) =
    [face,shift(face,1),shift(face,2)];

function full_symmetry(form) =
   distinct(flatten([for (comb = combs(expand(form))) perm3(comb)]));

function tetra_symmetry(form) =
   distinct(flatten([for (face = [form,[form[1],form[0],form[2]]]) combs(expand(face))]));

function gyroid_symmetry(form,even=true) =
    concat(parity_filter(distinct(flatten([for (face = cycle(form)) combs(expand(face))])),even),
           parity_filter(distinct(flatten([for (face = cycle([form[0],form[2],-form[1]])) combs(expand(face))])), ! even)
    );

function opposite(face) =
   [for (a=face)
       a==0 ? 0 : - a];

function mirror(face) =  [ face,opposite(face)];

function switch(face) = [face[1],face[0],face[2]];

function trapezohedral_symmetry(form) =
 concat(
    parity_filter(combs(expand(form)),form),
    parity_filter(combs(expand(switch(form))),mirror(form))
    );

// bit of a hack - sb a filter
function rotate_z(form) = [-form[1],form[0],form[2]];

function rotate_z4(form) =
   let (mform=[form[0],form[1],-form[2]])
   [form,
    rotate_z(form),
    rotate_z(rotate_z(form)),
    rotate_z(rotate_z(rotate_z(form))),
    mform,
    rotate_z(mform),
    rotate_z(rotate_z(mform)),
    rotate_z(rotate_z(rotate_z(mform)))
   ];

 // filters

function parity(face) =
    let(parity = sum( [for (i=face) i > 0 ? 1 : 0]))
    parity % 2 == 0 ;

function parity_filter(faces,form) =
    [for (face=faces) if (parity(face) == parity(form) ) face];

function unsigned(face) = [abs(face[0]),abs(face[1]),abs(face[2])];

function same_order(form,face) =
    form == face || form==shift(face) || form==shift(shift(face));

function order_filter(faces,form) =
    [for (face=faces)
        if (same_order(unsigned(form),unsigned(face))) face
    ];

function hemi_filter(faces,axis,form) =
     let(asign=sign(form[axis]))
     [for (face=faces)
          if(sign(face[abs(axis)])==asign) face
     ];

// face construction
function filter_faces(form,faces,modifiers,i=0) =
    i < len(modifiers)
       ? let(filter=modifiers[i])
         let(filtered_faces =
             filter=="order"
             ? order_filter(faces,form)
             : filter=="parity"
             ? parity_filter(faces,form)
             : filter=="hemiz"
             ? hemi_filter(faces,2,form)
             : faces)
         filter_faces(form,filtered_faces,modifiers,i+1)
       : faces;

function form_faces(form,base,modifiers) =
    let(base_faces =
         base=="full"
       ? full_symmetry(form)
       : base=="tetra"
       ? tetra_symmetry(form)
       : base=="gyroid"
       ? gyroid_symmetry(form)
       : base=="trapezoid"
       ? trapezohedral_symmetry(form)
       : base=="mirror"
       ? mirror(form)
       : base=="pedion"
       ? [form]
       : base=="rotate_z4"
       ? rotate_z4(form)
       : [form])
     let(faces = filter_faces(form,base_faces,modifiers) )
     faces;

// crystal rendering
COLORS=["lightpink","lime","aquamarine","khaki","silver","lightsalmon","lightgreen","orange","cadetblue","tan","chartreuse","violet"];

module c_render(crystal) {
    forms=crystal[1];
    intersection_for (i=[0:len(forms)-1])
       c_render_part(crystal,i);
}

module c_render_selected(crystal,ds) {
    forms=crystal[1];
    intersection_for (i=[0:len(forms)-1]) {
       if (ds[i] != 0) c_render_part(crystal,i,ds[i]);
           }
}

module c_render_part(crystal,k,ds,label=false) {
    data=crystal[0];
    forms=crystal[1];
    scale(data[1])
      {
         form_spec=forms[k];
         form=form_spec[0];
         d = ds==undef ? form_spec[1] : ds;
         base = form_spec[2] == "" || form_spec[2] == undef  ?  data[2] : form_spec[2];
         modifiers=form_spec[3] == undef ? [] : form_spec[3] ;
         name = form_spec[4] == undef ? "" :   form_spec[4];
         ci= k % len(COLORS);
         color = COLORS[ci]== undef ? "green" : COLORS[ci];
         faces=form_faces(form,base,modifiers);
  //       echo(form_spec);
         if(label) color("black") {
             translate([0,0,-3.5]) rotate([45,0,25]) scale(0.05) text(name,halign="center",font="Georgia:style=Regular"   );
             translate([0,0,-4.5]) rotate([45,0,25]) scale(0.05) text(str(form),halign="center",font="Georgia:style=Regular"   );
         }
         echo(name,color,form,d,base,modifiers, len(faces),faces);
         solid(faces,d,color);
      }
}

// data
/*
   the data structure has the format:
       [header [form]*]
   header = [name,scale,default_base symmetry,class]
   form =[miller indices, d, base ("" = default_base), [modifiers], name]

*/
// Cubic system

cubic_system = [
    ["cubic system",[1,1,1], "full"],
    [
      [[1,0,0],1,"",[],"cube"],
      [[1,1,0],1,"",[],"rhombic dodecahedron"],
      [[1,2,0],1,"",[],"tetrahexahedron"],
      [[1,2,0],1,"",["order"],"pentagonal dodecahedron"],
      [[1,1,1],1,"",[],"octahedron"],
      [[1,1,1],1,"",["parity"],"tetrahedron"],
      [[2,1,1],1,"",[],"icositetrahedron"],
      [[2,1,1],1,"",["parity"],"triakis tetrahedron"],
      [[2,2,1],1,"",[],"triakis octahedron"],
      [[2,2,1],1,"",["parity"],"deltoid dodecahedron"],
      [[3,2,1],1,"",[],"hexakis octahedron"],
      [[3,2,1],1,"",["order"],"diakisdodecahedron"],
      [[3,2,1],1,"",["parity"], "hexatetrahedron"],
      [[3,2,1],1,"gyroid",[], "pentagonal icositetrahedron"],
      [[3,2,1],1,"",["parity","order"],"tetrahedral pentagonal dodecaheron"]
    ]
];

scale(size)  c_render_part(cubic_system,form);

```


[User]
I'm looking to create a parametric design for a microscope stage, specifically for a DIY webcam microscope project. I've got some existing designs as a starting point, but want to make it fully parametric and easy to customize. I've included the general idea in the previous scad file, so hopefully it's clear how the different parts relate to each other. The aim is for it to be easily adjustable and adaptable to different microscopes and object sizes.

Here's what I need:

**Overall Structure:**

The design will consist of a base plate, a back plate with holders, and an object plate. The object plate should have a central hole for viewing objects, and the entire system should be adjustable using screw mechanisms. We should account for non-DIN standard screws (like the ones I use), so we'll want to parameterize everything screw related. Also, I'm working with metric units.

**Specific Components and Parameters:**

1.  **Base Plate:**
    *   `Microscope_Width`: Overall width of the base plate.
    *   `Microscope_Depth`: Overall depth of the base plate.
    *   `Base_Material`: Thickness of the base plate.

2.  **Back Plate:**
    *   `Microscope_Height`: Height of the back plate.
    *   `Plate_Width`: Width of the back plate.
    *  `Base_Material`: Thickness of the back plate.

3. **Back Plate Holder:**
   * `Holder_Height`: Height of the holder that extends from the base.
   *  `Holder_Notch_Width`: Width of the notch on the base for the holder.
   *  `Base_Material`: Thickness of the back plate holder.

4.  **Object Plate:**
    *   `Object_Plate_Depth`: Overall depth of the object plate.
    *   `Object_Plate_Width`: Overall width of the object plate.
    *   `Plate_Material`: Thickness of the object plate.
    *   `Object_Hole_Width`: Width of the central viewing hole in the object plate.
    *   `Object_Hole_Depth`: Depth of the central viewing hole in the object plate.
    *    `Object_Hole_Position`: Position of the object hole on the plate.

5. **Wheel:**
   * `Wheel_Diameter`: Diameter of the adjustment wheel
   *  `Plate_Material`: Thickness of the wheel.

6.  **Screw Dimensions (for all screw locations):**
    *   `Screw_Diameter`: Diameter of the screws (e.g., 3 for M3 or similar).
    *   `Screw_Length`: Length of the screws.
    *   `Nut_Height`: Height of the nuts.
    *   `Nut_Width`: Width of the nuts.

**Key Features and Considerations:**

*   **Rounded Corners:** All main plates should have rounded corners for a smoother aesthetic.
*   **Screw Holes:** All screw holes should be designed with clearance for easy assembly.
*   **Nut recesses:** The BackPlateHolder and ObjectPlate should have recesses for the nuts to sit in.
*   **Adjustability:** The object plate should be adjustable up and down along the BackPlate.
*   **Object plate side supports:** The ObjectPlate should have side supports along the Z axis.
*   **Modular Design:** It would be great if we can build this design up in modules.

**Output:**

I'd like the final output to be an OpenSCAD file (or files, if modular makes more sense) that generates an STL file when rendered, as well as DXF files to verify the shapes.

**Libraries:**

I do not require any specific libraries for this design.

Could you help me create these OpenSCAD files?

[Assistant]
HackteriaMicroscopyStage_updated_screws.scad:
```
// Microscopy Hack-Stage
// hackteria.org
//
// by GaudiLabs
// Modified by dusjagr

/* Botes about screw dimensions
Screw_Diameter = 3; //[3:5] 4.6 for Taiwan 3/16x1/2"
Screw_Length = 12; //[8:24] 12 for Taiwan 3/16x1/2"
Nut_Height = 3; // 3.8 for Taiwan 3/16x1/2"
Nut_Width = 6; // 8 for Taiwan 3/16x1/2"
*/

//LABELS FOR CUSTOMIZER

// Adjust parameters here:

Output_Type = "STL"; //[DXF,STL]
Microscope_Width = 80; //[80:200]
Microscope_Depth = 90; //[80:150]
Microscope_Height = 44; //[28:120]

Object_Plate_Depth = 78; //[70:120]
Object_Plate_Width = 70; //[70:110]
Plate_Width=Object_Plate_Width+10;
Object_Hole_Width = 32; //[15:45]
Object_Hole_Depth = 20; //[15:40]

Wheel_Diameter = 22; //[20:50]

/*[Material]*/

Base_Material = 4;	//[3:8]
Plate_Material = 4;	//[2:6]
Screw_Diameter = 3; //
Screw_Length = 12; //
Nut_Height = 3; //
Nut_Width = 6; //

/*[Hidden]*/

Holder_Notch_Width=25;
Holder_Height=20;
Object_Hole_Position = 32;

$fs=0.1;

if(Output_Type=="single")
{
    BackPlate();
}

if(Output_Type=="STL")
{
rotate(90,[0,0,1])
union()
{
BasePlate();

translate([0,-Microscope_Depth/2+Base_Material+1+(Base_Material/2),(20/2)+(Base_Material/2)])
rotate(90,[1,0,0])
BackPlateHolder();

translate([0,-Microscope_Depth/2+1+(Base_Material/2),(Microscope_Height/2)+(Base_Material/2+2)])
rotate(90,[1,0,0])
BackPlate();

translate([0,-(Microscope_Depth-Object_Plate_Depth)/2+Base_Material+1,Holder_Height+Base_Material/2+1+Plate_Material/2+floor(((Microscope_Height-Holder_Height)*1/3)/10)*10+2
])
ObjectPlate();

translate([0,-(Microscope_Depth-Object_Plate_Depth)/2+Base_Material+1+Object_Plate_Depth/2-8,Holder_Height+Base_Material/2+1+Plate_Material/2+floor(((Microscope_Height-Holder_Height)*1/3)/10)*10+10])
Wheel();

 /*
translate([0,(-Microscope_Depth)/2+Base_Material+1+Object_Hole_Position,Base_Material/2])
Cam();
*/
}
}

if(Output_Type=="DXF")
{

projection(cut=true)
BasePlate();

translate([0,-Microscope_Depth/2-Microscope_Height/2-2,0])
projection(cut=true)
BackPlate();

translate([0,Microscope_Depth/2+Holder_Height/2+6,0])
projection(cut=true)
BackPlateHolder();

translate([-Microscope_Width/2-Object_Plate_Width/2-2,0,0])
projection(cut=true)
ObjectPlate();

translate([-Microscope_Width/2-Object_Plate_Width/2-23,Object_Plate_Depth/2+Wheel_Diameter/2+2,0])
projection(cut=true)
Wheel();

 translate([-Microscope_Width/2-Object_Plate_Width/2+23,Object_Plate_Depth/2+Wheel_Diameter/2+2,0])
projection(cut=true)
Wheel();

translate([-Microscope_Width/2-Object_Plate_Width/2+0,Object_Plate_Depth/2+Wheel_Diameter/2+2,0])
projection(cut=true)
Wheel();

}

// MODULES ///////////////////////////////

module Cam()
{
projection(cut=true)
union()
{
translate([0,0,15/2])
roundedRect([35, 25, 15], 2);
translate([0,0,15/2+10])
cylinder(h = 10, r1 = 15/2, r2 = 15/2, center = true);

}
}

module Wheel() //modified to have a hole
{
 difference()
{
  cylinder(h = Plate_Material, r1 = Wheel_Diameter/2, r2 = Wheel_Diameter/2, center = true);
    cylinder(h = Plate_Material+2, r1 = Screw_Diameter*0.75/2, r2 = Screw_Diameter*0.75/2, center = true);
  }
}

module ObjectPlate()
color("LightGreen")
{

difference()
{
rounded2Rect([Object_Plate_Width, Object_Plate_Depth, Plate_Material], 5);
translate([0,-Object_Plate_Depth/2+Object_Hole_Position,0])
roundedRect([Object_Hole_Width, Object_Hole_Depth, Plate_Material+2], 3);

translate([0,Object_Plate_Depth/2-8,0])
cylinder(h = Plate_Material+2, r1 = Screw_Diameter*0.75/2, r2 = Screw_Diameter*0.75/2, center = true);

translate([Object_Plate_Width/2,Object_Plate_Depth/2-13,0])
cylinder(h = Plate_Material+2, r1 = 4/2, r2 = 4/2, center = true);

translate([-Object_Plate_Width/2,Object_Plate_Depth/2-13,0])
cylinder(h = Plate_Material+2, r1 = 4/2, r2 = 4/2, center = true);

translate([0,-Object_Plate_Depth/2+(12/2),0])
cube([Screw_Diameter*1.07,Screw_Length,Plate_Material+2],true);

translate([0,-Object_Plate_Depth/2+(12/2),0])
cube([Nut_Width,Nut_Height*1.07,Plate_Material+2],true); // Nut

}

translate([(45/2),-Object_Plate_Depth/2-((Base_Material+1)/2),0])
cube([25,Base_Material+1,Plate_Material],true);

translate([-(45/2),-Object_Plate_Depth/2-((Base_Material+1)/2),0])
cube([25,Base_Material+1,Plate_Material],true);

}

module BackPlateHolder()
{ color("pink")
difference()
{
union()
{
rounded2Rect([Microscope_Width, Holder_Height, Base_Material], 5);
translate([-(5+(Microscope_Width-80)/8+Holder_Notch_Width/2),-(Holder_Height/2+(Base_Material/2)),0])
cube([Holder_Notch_Width,Base_Material,Base_Material],true);
translate([(5+(Microscope_Width-80)/8+Holder_Notch_Width/2),-(Holder_Height/2+(Base_Material/2)),0])
cube([Holder_Notch_Width,Base_Material,Base_Material],true);
}
union()
{
translate([0,-(20/2)+(12/2),0])
cube([Screw_Diameter*1.07,Screw_Length,Base_Material+2],true);
translate([0,-4,0])
cube([Nut_Width,Nut_Height*1.07,Base_Material+2],true); //dimension of Nut

translate([(45/2),5.5,0])
cylinder(h = Base_Material+2, r1 = Screw_Diameter*0.75/2, r2 = Screw_Diameter*0.75/2, center = true);

translate([-(45/2),5.5,0])
cylinder(h = Base_Material+2, r1 = Screw_Diameter*0.75/2, r2 = Screw_Diameter*0.75/2, center = true);

// Extra Holes

if (((Microscope_Width-Plate_Width)-20)/2>4)
{
translate([-(((Microscope_Width-Plate_Width)-20)/2+Plate_Width)/2,4,0])
cylinder(h = Base_Material, r1 = Screw_Diameter*0.75/2, r2 = Screw_Diameter*0.75/2, center = true);

translate([(((Microscope_Width-Plate_Width)-20)/2+Plate_Width)/2,4,0])
cylinder(h = Base_Material, r1 = Screw_Diameter*0.75/2, r2 = Screw_Diameter*0.75/2, center = true);

translate([-(((Microscope_Width-Plate_Width)-20)/2+Plate_Width)/2,-4,0])
cylinder(h = Base_Material, r1 = Screw_Diameter*1.07/2, r2 = Screw_Diameter*1.07/2, center = true);

translate([(((Microscope_Width-Plate_Width)-20)/2+Plate_Width)/2,-4,0])
cylinder(h = Base_Material, r1 = Screw_Diameter*1.07/2, r2 = Screw_Diameter*1.07/2, center = true);
}

}
}
}

module BackPlate()

{color("LightBlue")
difference()
{
rounded2Rect([Plate_Width, Microscope_Height, Base_Material], 7);

union()
{
translate([0,0,-Base_Material/2])
linear_extrude(height=Base_Material+2)
hull()
{
translate([-45/2,-Microscope_Height/2+6,0])
circle(Screw_Diameter*1.07/2,true);

translate([-45/2,-Microscope_Height/2+6+11,0])
circle(Screw_Diameter*1.07/2,true);

}
}

union()
{
translate([0,0,-Base_Material/2])
linear_extrude(height=Base_Material+2)
hull()
{
translate([45/2,-Microscope_Height/2+6,0])
circle(Screw_Diameter*1.07/2,true);

translate([45/2,-Microscope_Height/2+6+11,0])
circle(Screw_Diameter*1.07/2,true);
}
}

    translate([0,-Microscope_Height/2+10,0])
    cylinder(h = Base_Material+2, r1 = 4, r2 = 4, center = true);

    translate([0,-Microscope_Height/2+2,0])
    cube([8, 16, Plate_Material+2], true);

for (y=[0:floor((Microscope_Height-Holder_Height-Plate_Material-4)/10)])
{
translate([45/2,-Microscope_Height/2+Holder_Height+Plate_Material/2+1+10*y,0])
cube([25,Plate_Material,Base_Material+2],true);

translate([-45/2,-Microscope_Height/2+Holder_Height+Plate_Material/2+1+10*y,0])
cube([25,Plate_Material,Base_Material+2],true);

translate([0,-Microscope_Height/2+Holder_Height+Plate_Material/2+1+10*y,0])
cylinder(h = Base_Material+2, r1 = Screw_Diameter*1.07/2, r2 = Screw_Diameter*1.07/2, center = true);

}

}

}

module BasePlate()
{color("deeppink")
difference(){
rounded2Rect([Microscope_Width, Microscope_Depth, Base_Material], 5);
translate([(5+(Microscope_Width-80)/8+Holder_Notch_Width/2),-Microscope_Depth/2+Base_Material+1+(Base_Material/2),0])
cube([Holder_Notch_Width,Base_Material,20],true);
translate([-((5+(Microscope_Width-80)/8+Holder_Notch_Width/2)),-Microscope_Depth/2+Base_Material+1+(Base_Material/2),0])
cube([Holder_Notch_Width,Base_Material,20],true);
translate([0,-Microscope_Depth/2+Base_Material+1+(Base_Material/2),0])
cylinder(h = Base_Material+2, r1 = Screw_Diameter*1.07/2, r2 = Screw_Diameter*1.07/2, center = true);

}

}

// size - [x,y,z]
// radius - radius of corners
module rounded2Rect(size, radius)
{
	x = size[0];
	y = size[1];
	z = size[2];

	translate([0,0,-z/2])
	linear_extrude(height=z)
	hull()
	{
		// place 4 circles in the corners, with the given radius
		translate([(-x/2)+(radius), (-y/2)+(radius), 0])
		square([2*radius,2*radius],true);

		translate([(x/2)-(radius), (-y/2)+(radius), 0])
		square([2*radius,2*radius],true);

		translate([(-x/2)+(radius), (y/2)-(radius), 0])
		circle(r=radius);

		translate([(x/2)-(radius), (y/2)-(radius), 0])
		circle(r=radius);
	}

}

// size - [x,y,z]
// radius - radius of corners
module roundedRect(size, radius)
{
	x = size[0];
	y = size[1];
	z = size[2];

	translate([0,0,-z/2])
	linear_extrude(height=z)
	hull()
	{
		// place 4 circles in the corners, with the given radius
		translate([(-x/2)+(radius), (-y/2)+(radius), 0])
		circle(r=radius);

		translate([(x/2)-(radius), (-y/2)+(radius), 0])
		circle(r=radius);

		translate([(-x/2)+(radius), (y/2)-(radius), 0])
		circle(r=radius);

		translate([(x/2)-(radius), (y/2)-(radius), 0])
		circle(r=radius);
	}
}

```


[User]
I'm looking to design a parametric adapter for my old iPhone 4/5 Brodit car mount so that I can use it with my iPhone 6. I need the adapter to have a slot that will accommodate the iPhone 6 with a case on, so that thickness should be adjustable. The adapter also needs to have a base that will fit into the existing Brodit mount. I have an existing design using OpenSCAD, but I want to make it more parametric and flexible.

Here’s a breakdown of what I need:

1.  **iPhone 6 Holding Body:**
    *   This should be a box with adjustable length, width (for the case), and height. It will serve as the main holding structure for the iPhone 6.
    *   The width needs to be an adjustable parameter to account for different case thicknesses. I was using 9mm originally, but it should be an variable.
    *   The length needs to be a variable.
    *   I need to have the option to set rounded corners on the slot.

2. **Brodit Mount Base:**
    *   This needs to be a rectangular base that will fit into the iPhone 4/5 Brodit mount. I need to specify the length, width and height of this base, and the position relative to the iphone 6 body.
    *   I need to be able to add a custom text label to the base, maybe "iPhone 6".

3.  **Alignment and Stability Features:**
    *   I want to add optional slanted or phased edges at the top of the iphone 6 holding box to provide a little extra grip/alignment. This should be adjustable or toggled on/off. I had 45 degree angles before, but it should be a customizable angle.
    *   I also had slanted features on the adapter mount itself for alignment, which should also be optional and their angle adjustable. I used 20 degrees before but want that as an adjustable parameter.

4.  **Parametric Design:**
    *   Everything should be adjustable via parameters at the beginning of the file. This includes all dimensions, offsets, and the angle of the slanted/phased features.
    *   Units should be in mm.
    *   I'd prefer the code be well-commented so I can easily understand and modify it in the future.

I would like this written using vanilla OpenSCAD if possible, as I don't have any other libraries set up. Thanks!

[Assistant]
iPhone6_Adaptor.scad:
```
// Adaptor for iPhone6 on iPhone 4/5 Brodit Mount

length = 50;  // body for iPhone6
width = 9;    // slot for iPhone6 with case

difference(){
  cube([77,length,14],center=true);  // body for iPhone 6
  translate([0,0,0]) cube([66,length,10],center=true);
  translate([0,-4,0]) cube([72,length,width],center=true);  // slot
  translate([0,0,10]) cube([66,length,10],center=true);
  translate([40,0,7]) rotate([0,45,0]) cube([5,length,5],center=true);  // phase top
  translate([-40,0,7]) rotate([0,45,0]) cube([5,length,5],center=true);  // phase top
}

translate([0,((length/2)*-1)+20,-9]) cube([50,40,4],center=true); // middle part
difference(){
  translate([0,((length/2)*-1)+20,-15]) cube([59,40,8],center=true); // adaptor iPhone 5
  translate([30,((length/2)*-1)+38,-11]) rotate([-20,0,0]) cube([10,5,2],center=true);  // phase
  translate([-30,((length/2)*-1)+38,-11]) rotate([-20,0,0]) cube([10,5,2],center=true); // phase
  translate([-24,((length/2)*-1),-17]) rotate([90,0,0]) linear_extrude(height = 1 , convexity = 110) text("iPhone 6", size=4, font="Liberation Sans");
}

```


[User]
Hey, I'm working on a model rocket design and I need a way to generate body tubes of different sizes and lengths. I've already written a basic OpenSCAD file, but it's really clunky with all those if statements.  I'd like to make it more parametric so I can easily specify the body tube size and length without having to edit the code directly.

The body tube sizes I need are based on the standard Estes sizes: 13.8mm (BT-5), 18.7mm (BT-20), 24.8mm (BT-50), 33.7mm (BT-55), 34.2mm (BT-56), 41.6mm (BT-60), 56.3mm (BT-70), 66.04mm (BT-80), and 100mm (BT-101). These are the outer diameters, and the tubes have a standard wall thickness. I've got a rough idea of the inner diameters too, but you can derive them by subtracting a standard wall thickness.

Could you create a parametric OpenSCAD file (or files) that lets me specify the tube size (using the BT designations or the diameter) and the length, and generates the corresponding body tube? I'd like it to be easy to use. I don't need any fancy features, just a simple hollow cylinder with the correct dimensions.  I'm not using any special libraries, so it should just use base OpenSCAD functions.

[Assistant]
Body_Tube.scad:
```
tube_size = 13.8; //[13.8:BT-5, 18.7:BT-20, 24.8:BT-50, 33.7:BT-55, 34.2:BT-56, 41.6:BT-60, 56.3:BT-70, 66.04:BT-80, 100:BT-101]

//How long do you want the tube to be (mm)?
length = 125;

if (tube_size==13.8) {
difference(){
cylinder(h=length, r=13.8/2, center=false, $fn=100);
    cylinder (h=length, r=13.2/2, center=false, $fn=100);
}
}

if (tube_size==18.7) {
difference(){
cylinder(h=length, r=18.7/2, center=false, $fn=100);
    cylinder (h=length, r=18/2, center=false, $fn=100);
}
}

if (tube_size==24.8) {
difference(){
cylinder(h=length, r=24.8/2, center=false, $fn=100);
    cylinder (h=length, r=24.1/2, center=false, $fn=100);
}
}

if (tube_size==33.7) {
difference(){
cylinder(h=length, r=33.7/2, center=false, $fn=100);
    cylinder (h=length, r=32.6/2, center=false, $fn=100);
}
}

if (tube_size==34.2) {
difference(){
cylinder(h=length, r=34.2/2, center=false, $fn=100);
    cylinder (h=length, r=33.1/2, center=false, $fn=100);
}
}

if (tube_size==41.6) {
difference(){
cylinder(h=length, r=41.6/2, center=false, $fn=100);
    cylinder (h=length, r=40.5/2, center=false, $fn=100);
}
}

if (tube_size==56.3) {
difference(){
cylinder(h=length, r=56.3/2, center=false, $fn=100);
    cylinder (h=length, r=55.4/2, center=false, $fn=100);
}
}

if (tube_size==66.04) {
difference(){
cylinder(h=length, r=66.04/2, center=false, $fn=100);
    cylinder (h=length, r=65.7/2, center=false, $fn=100);
}
}

if (tube_size==100) {
difference(){
cylinder(h=length, r=100/2, center=false, $fn=100);
    cylinder (h=length, r=99/2, center=false, $fn=100);
}
}
```