[User]
Okay, I'm looking to design a modular shower shelf system using OpenSCAD. I have a few design ideas and some existing code that I've been tinkering with, but I'd like to start from scratch and get a more flexible design. I want to be able to print it in pieces and connect them together.

Here's what I'm envisioning:

**Core Components:**

1.  **Main Shelf:**
    *   This is the main part that will hold the shower speaker or whatever else.
    *   It should be a rectangular shelf with a lip on the front edge, and should have a customizable depth and width.
    *   The back of the shelf should have attachment points for the hanger arms.

2.  **Hanger Arms:**
    *   These arms will hook over the shower door or wall and attach to the back of the shelf.
    *   They need to have a customizable hook depth and height, and also some sort of connector mechanism to attach to the shelf and additional extension arms.
   *  I need to be able to specify if I want extra supporting perches for the hanging arms, and if so how long they should be.

3.  **Extension Arms**
    *   These arms can extend the distance of the main shelf from the door or wall.
    *   They should have a connector mechanism at each end to allow them to connect with the hanger arms and other extension arms.

4.  **Mounting Blocks:**
    *   These are simple blocks that are used to attach the shelf and extension arms to the hanger arms. I want to be able to specify the length of these blocks.
    *   These should use the same connector mechanism as the hanger and extension arms.

**Connector System:**
*   I want to use a male/female connector system that allows the different pieces to snap together.
*   The male connector should have a small rod with a cross-piece and the female connector should have a corresponding hole with a matching cross-piece slot.
*   I want the connector to be parametric so I can adjust the size of the rods and cross-pieces.

**Key Parameters (should be customizable):**

*   `shelf_depth`: Depth of the main shelf.
*   `shelf_width`: Width of the main shelf.
*   `shelf_thickness`: Thickness of the shelf.
*   `shelf_lip_size`: Size of the lip on the front of the shelf.
*   `hook_depth`: Depth of the hook on the hanger arms.
*  `hook_height`: Height of the hook on the hanger arms
*   `arm_thickness`: Thickness of the hanger and extension arms.
*   `connector_rod_size`: Size of the rod on the male connector.
*   `connector_cross_piece_size`: Size of the cross-piece on the male connector.
* `extra_hanger_perch`: boolean that adds extra hanger perches
* `extra_perch_length`: length of the extra perches

**Other Considerations:**

*   I'd like to have a way to specify the thickness of the plastic (e.g., `thickness = 3mm`) which affects all the parts.
*   I want to add small beads/fillets on the corners to reduce sharp edges.
*   I want to be able to toggle the connector system on or off - in case I want to print a single piece instead of a modular design.
*    I'd like a test profile option for each piece so I can print just a small slice to test fit before printing the full part.

So, to summarize, could you generate the OpenSCAD code for a parametric, modular shower shelf system as described? I'd like to be able to customize all the dimensions and have the connector system included. I'm looking to have these as separate files for each of the components. I would rather not have any external libraries (MCAD, BOSL, etc.) used if possible.

[Assistant]
shower_shelf_v3.scad:
```
// monitor_shelf
// Thing that lets you place small items on the top edge of your
// computer monitor
//
// Rick Rofail
// rick.rofail at gmail.com
// Distributed under GPL version 2
// <http://www.gnu.org/licenses/gpl-2.0.html>
//
// Designed to use customizer at thingiverse
// <http://www.makerbot.com/blog/2013/01/23/openscad-design-tips-how-to-make-a-customizable-thing/>
// INCLUDING LEGOBRICK MODULES FROM
// building Lego bricks - rdavis.bacs@gmail.com
// measurements taken from:
//   http://www.robertcailliau.eu/Lego/Dimensions/zMeasurements-en.xhtml
// all copyrights and designs are property of their respective owners.

// K272HL
//monitor_thickness = 24;
//shelf_depth = 44;
//front_length = 7.5;
//back_length = 20;

// HP LP2465 -
//monitor_thickness = 49;
//shelf_depth = 65;
//back_length = 17.2;
//front_length = 17.2;

// XG270HU -
//monitor_thickness = 19.5;
//shelf_depth = 50;
//back_length = 20;
//front_length = 6;

// Generate just a narrow test profile to ensure it fits your monitor
test_profile = 0; // [0: Full width, 1: Test profile]

// Thickness of the plastic in mm
thickness = 3.0;  // thickness

// Thickness of monitor at top edge (mm)
monitor_thickness = 52;

// Depth of the perch shelf (mm).
shelf_depth = 65;

// Thickness of the perch shelf (mm).
shelf_thickness = 4;

// Length of front leg
front_length = 0;

// Length of back leg
back_length = 50;

// Monitor back wedge (degrees: 0 means back is perp. to top edge, >0 means it is slanted)
monitor_back_slope = 0;

// Monitor top wedge (degrees: >0 means that the top slopes way instead of being perpendicular to the screen)
monitor_top_wedge = 0;

// Width of the perch shelf (mm).
shelf_width = 10;

//Size of the shelf lip bead. Default 1.2 for a small lip.
shelf_lip_size = 0;

//Depth of the hook size - mine is 48 mm
hook_depth=48;

//Hieight of the hook - dropping it 40 mm below top
hook_height=100;

// Radius of bead along joints
bead = shelf_lip_size * thickness;

// epsilon to prevent problems with coincident planes
eps = 0.01;

// LEGO settings
/////////
h_pitch = 8.0;   // horizontal unit
v_pitch = 9.6;   // vertical unit
tol = 0.1;       // "play" in x and y directions
k_dia = 4.8;     // knob diameter
k_height = 1.8;  // knob height
k_n = 40;         // knob resolution
wall = 1.2;      // wall thickness

brick_cyl_ex = 8*sqrt(2)-2*2.4;
brick_cyl_in = 4.8;
beam_cyl = 3.0;

module Perch() // Top level module
{
    rotate([90,0,0]) union() {
        // Front is in the xy plane
//        translate([-bead*0.72,0,bead*0.72]) rotate([90,0,0]) cylinder(h=shelf_width-eps,r=bead,center=true); //front bead
        translate([-(shelf_depth/4.8),0,bead+thickness])rotate([90,0,0]) cylinder(h=shelf_width-eps,r=bead,center=true); //front bead

        translate([-thickness,-shelf_width/2,-front_length+eps]) cube([thickness, shelf_width, front_length]); //front riser
        rotate([0,monitor_top_wedge,0]) {
            union(){
                translate([-shelf_depth/4,-shelf_width/2,0]) cube([shelf_depth+ 2*thickness, shelf_width, shelf_thickness]); //top plane

                translate([monitor_thickness+thickness,-shelf_width/2,thickness]) //back riser
                    rotate([0,180-monitor_back_slope-monitor_top_wedge,0])
                        cube([thickness,shelf_width,back_length]); //back riser
                translate([shelf_depth+thickness-(shelf_depth/4),(shelf_width-eps)/2,bead+thickness])
                    rotate([90,0,0]) cylinder(h=shelf_width-eps,r=bead,center=false);
            }
        }
     translate([55,0,0])rotate([90,180,0]) linear_extrude(height = shelf_width, center = true, convexity = 10, twist = 0)
polygon(points=[[0,0],[40,0],[0,40],[4,4],[30,4],[4,30]], paths=[[0,1,2],[3,4,5]]);
      //hook section for shower door
      translate([49,-shelf_width/2,0])rotate([0,0,0]) union() {
          cube([thickness*2, shelf_width, hook_height]); //back riser for hook
          translate([0,0,hook_height-thickness])cube([hook_depth+thickness*2+thickness*2, shelf_width, thickness*2]); //back riser for hook
          translate([hook_depth+thickness+thickness,0,hook_height-hook_height/3])    cube([thickness*2, shelf_width, hook_height/3]); //back riser for hook

      }
    }
}

module Profile()
{
    intersection() {
        Perch();
        cube([1000,1000,2],center=true);
    }
}
// Rotate it so that ends up on the printer bed in the right orientation

if (test_profile == 1) {
    Profile();
} else {

    Perch();
}

```
shower_shelf_v4-holder.scad:
```
t = 3;
w = 150;
h = 70;
l = 1;
// Radius of bead along joints
bead = l * t;
// Radius of front bead along joints
bead2 = t/4 * t;
// epsilon to prevent problems with coincident planes
eps = 0.01;
 union() {
     translate([0,w/2,0]) rotate([90,0,0]) cylinder(h=w-eps,r=bead,center=true);
    // translate([t/2,w/2,h]) rotate([90,0,0]) cylinder(h=w-eps,r=bead2,center=true);
cube([t,w,h]);
 }
```
shower_shelf_v12-rods.scad:
```

// Generate just a narrow test profile to ensure it fits your monitor
test_profile = 0; // [0: Full width, 1: Test profile]

hook_height=170;  //Height of the hook - dropping it 40 mm below top
thickness = 3.0;  // thickness
shelf_width = 10; // Width of the perch shelf (mm).
extra_hanger_perch = 1; // [0: No extra perches, 1: Add extra hanger perches for stability]
extra_perch_length = 12; //if adding extra perches, this is how large they will be in mm

module Rod() //rod module
{

    union() {
        if(extra_hanger_perch) {
        translate([thickness*2+extra_perch_length-0.1,0,hook_height/3-10])rotate([0,0,90]) union() {
          //cube([thickness*2, thickness*2, hook_height/2]);
          translate([0,0,0]) rotate([0,90,00]) cube([thickness*2, extra_perch_length, shelf_width ]);
          translate([0,0,hook_height/4]) rotate([0,90,00]) cube([thickness*2, extra_perch_length, shelf_width]);
          translate([0,0,hook_height/2]) rotate([0,90,00]) cube([thickness*2, extra_perch_length, shelf_width]);
            cube([shelf_width, thickness*2, hook_height/2]);
              }
          }
        difference() {
                    cube([thickness*2, shelf_width, hook_height]);
            //add back support rods - 12mm

                    femaleConnector();
                }
                 translate([0,0,hook_height]) {
                     maleConnector();
                 }
            }
}

module Perch() // Top level module
{
    rotate([90,0,0]) union() {
        translate([0,0,0]) {
            Rod();
        }
        translate([30,0,0]) {
            Rod();
        }
    }
}
module maleConnector()
{
    translate([2.2,0,0]) cube([thickness*2-4.4, shelf_width-2, 6.2]); //-male rod
    translate([0,0,6.2]) cube([thickness*2, shelf_width-2, 2]); //-male - cross piece
}

module femaleConnector()
{ //be sure to take this as the difference
    translate([1.5,0,0]) cube([thickness*2-3, shelf_width-2, 7.2]); //-female rod
    translate([0,0,4.4]) cube([thickness*2+2, shelf_width-1.7, 3.6]); //-female - cross piece
}

module Profile()
{
    intersection() {
        Perch();
        cube([1000,1000,2],center=true);
    }
}

if (test_profile == 1) {
    Profile();
} else {

    Perch();
}

```
shower_shelf_v12.scad:
```
// monitor_shelf
// Thing that lets you place small items on the top edge of your
// computer monitor
//
// Rick Rofail
// rick.rofail at gmail.com
// Distributed under GPL version 2
// <http://www.gnu.org/licenses/gpl-2.0.html>
//
// Designed to use customizer at thingiverse
// <http://www.makerbot.com/blog/2013/01/23/openscad-design-tips-how-to-make-a-customizable-thing/>
// INCLUDING LEGOBRICK MODULES FROM
// building Lego bricks - rdavis.bacs@gmail.com
// measurements taken from:
//   http://www.robertcailliau.eu/Lego/Dimensions/zMeasurements-en.xhtml
// all copyrights and designs are property of their respective owners.

// K272HL
//monitor_thickness = 24;
//shelf_depth = 44;
//front_length = 7.5;
//back_length = 20;

// HP LP2465 -
//monitor_thickness = 49;
//shelf_depth = 65;
//back_length = 17.2;
//front_length = 17.2;

// XG270HU -
//monitor_thickness = 19.5;
//shelf_depth = 50;
//back_length = 20;
//front_length = 6;

// Generate just a narrow test profile to ensure it fits your monitor
test_profile = 0; // [0: Full width, 1: Test profile]

include_connector = 1; // [0: No connectors, 1: Use Connectors]
// Thickness of the plastic in mm
thickness = 3.0;  // thickness

// Thickness of monitor at top edge (mm)
monitor_thickness = 52;

// Depth of the perch shelf (mm).
shelf_depth = 65;

// Thickness of the perch shelf (mm).
shelf_thickness = 4;

// Length of front leg
front_length = 0;

// Length of back leg
back_length = 50;

// Monitor back wedge (degrees: 0 means back is perp. to top edge, >0 means it is slanted)
monitor_back_slope = 0;

// Monitor top wedge (degrees: >0 means that the top slopes way instead of being perpendicular to the screen)
monitor_top_wedge = 0;

// Width of the perch shelf (mm).
shelf_width = 10;

//Size of the shelf lip bead. Default 1.2 for a small lip.
shelf_lip_size = 0;

//Depth of the hook size - mine is 48 mm
hook_depth=48;

//Hieight of the hook - dropping it 40 mm below top
hook_height=130;

// Radius of bead along joints
bead = shelf_lip_size * thickness;

// epsilon to prevent problems with coincident planes
eps = 0.01;

// LEGO settings
/////////
h_pitch = 8.0;   // horizontal unit
v_pitch = 9.6;   // vertical unit
tol = 0.1;       // "play" in x and y directions
k_dia = 4.8;     // knob diameter
k_height = 1.8;  // knob height
k_n = 40;         // knob resolution
wall = 1.2;      // wall thickness

brick_cyl_ex = 8*sqrt(2)-2*2.4;
brick_cyl_in = 4.8;
beam_cyl = 3.0;

module Perch() // Top level module
{
    rotate([90,0,0]) union() {
        // Front is in the xy plane
//        translate([-bead*0.72,0,bead*0.72]) rotate([90,0,0]) cylinder(h=shelf_width-eps,r=bead,center=true); //front bead
        translate([-(shelf_depth/4.8),0,bead+thickness])rotate([90,0,0]) cylinder(h=shelf_width-eps,r=bead,center=true); //front bead

        translate([-thickness,-shelf_width/2,-front_length+eps]) cube([thickness, shelf_width, front_length]); //front riser
        rotate([0,monitor_top_wedge,0]) {
            union(){
                translate([-shelf_depth/4,-shelf_width/2,0]) cube([shelf_depth+ 2*thickness, shelf_width, shelf_thickness]); //top plane

                translate([monitor_thickness+thickness,-shelf_width/2,thickness]) //back riser
                    rotate([0,180-monitor_back_slope-monitor_top_wedge,0])
                        cube([thickness,shelf_width,back_length]); //back riser
                translate([shelf_depth+thickness-(shelf_depth/4),(shelf_width-eps)/2,bead+thickness])
                    rotate([90,0,0]) cylinder(h=shelf_width-eps,r=bead,center=false);
            }
        }
     translate([55,0,0])rotate([90,180,0]) linear_extrude(height = shelf_width, center = true, convexity = 10, twist = 0)
polygon(points=[[0,0],[40,0],[0,40],[4,4],[30,4],[4,30]], paths=[[0,1,2],[3,4,5]]);
      //hook section for shower door
      translate([49,-shelf_width/2,0])rotate([0,0,0]) union() {
          translate([0,0,0])cube([thickness*2, shelf_width, hook_height-50]); //back riser for hook - bottom platform section
          translate([2.2,0,80]) {
              translate([0,0,0]) cube([thickness*2-4.4, shelf_width-2, 6.2]); //-male rod
              translate([-2.2,0,6.2]) cube([thickness*2, shelf_width-2, 2]); //-male - cross piece
          }// cube([thickness*2-4, shelf_width-2, 5]); //back riser for hook - bottom platform section-male
          difference() {
              translate([0,0,100])cube([thickness*2, shelf_width, hook_height-100]); //back riser for hook - top hook section
              translate([1.5,0,100]) { // cube([thickness*2-3, shelf_width-1.5, 6]); //back riser for hook - top hook section-FEmale
                translate([0,0,0]) cube([thickness*2-3, shelf_width-2, 7.2]); //-female rod
                translate([-1.5,0,4.4]) cube([thickness*2+2, shelf_width-1.7, 3.6]); //-female - cross piece
               }
          }
          translate([0,0,hook_height-thickness])cube([hook_depth+thickness*2+thickness*2, shelf_width, thickness*2]); //back riser for hook
          translate([hook_depth+thickness+thickness,0,hook_height-hook_height/3])    cube([thickness*2, shelf_width, hook_height/3]); //back riser for hook

      }
     //add back support rods - 12mm
      translate([61,-shelf_width/2,-40])rotate([0,0,0]) union() {
          cube([thickness*2, shelf_width, 80]);
          translate([-6,0,0]) rotate([0,90,00]) cube([thickness*2, shelf_width, 12]);
          translate([-6,0,44]) rotate([0,90,00]) cube([thickness*2, shelf_width, 12]);
          translate([-6,0,80]) rotate([0,90,00]) cube([thickness*2, shelf_width, 12]);
      }
    }
}

module Rod(leng) //rod module
{
    union() {
        difference() {
                    cube([thickness*2, shelf_width, leng]);
                    femaleConnector();
                }
                 translate([0,0,leng]) {
                     maleConnector();
                 }
            }
}

module Profile()
{
    intersection() {
        Perch();
        cube([1000,1000,2],center=true);
    }
}
// Rotate it so that ends up on the printer bed in the right orientation

module maleConnector()
{
    translate([2.2,0,0]) cube([thickness*2-4.4, shelf_width-2, 6.2]); //-male rod
    translate([0,0,6.2]) cube([thickness*2, shelf_width-2, 1]); //-male - cross piece
}

module femaleConnector()
{ //be sure to take this as the difference
    translate([1.5,0,0]) cube([thickness*2-3, shelf_width-2, 7.2]); //-female rod
    translate([0,0,4.4]) cube([thickness*2+2, shelf_width-1.7, 3.6]); //-female - cross piece
}

if (test_profile == 1) {
    Profile();
} else {

    Perch();
}

```


[User]
Okay, so I'm trying to design a customizable bracket for my Rubbermaid filament storage system, based on the TUSH remix and Jimbo70's design. Basically, I need an OpenSCAD file that lets me adjust the length, the width of the gaps (valleys) in the bracket, and the width of the peaks. I also want the option to add screw tabs on the ends and a center hole.

Specifically, I need these parameters to be customizable:

*   `rail_length_max`: the maximum length of the overall rail.
*   `gap_length`: the size of the gaps or valleys in the rail.
*   `peak_length`: the size of the peaks in the rail.
*   `rail_width`: how wide the rail should be.
*   `screw_tabs`: a toggle to add or remove screw tabs on the ends (should be a yes/no option).
*   `center_hole`: a toggle to add or remove a center hole (should also be a yes/no option).
*   `screw_radius`: the radius of the screw holes, if screw tabs are enabled.

The design consists of a main rail with alternating peaks and gaps. I need it to also be able to optionally draw screw tabs on the ends, each with a hole to attach to the bins. If the screw tabs are enabled, their length should match the rail width. The center hole (if enabled) should be slightly larger than an M4 screw and a countersink should be added to allow the screw to sit flat within the bracket itself.

I don't need a complicated UI or anything, just a clean, customizable OpenSCAD file that I can use to adjust these parameters. I'm also assuming the screw holes will just be cylinders and don't need to be tapped or any complex shape like that, and the center hole will use a similar implementation. I'm not planning on using any libraries beyond the basic OpenSCAD features.

Can you help me generate this OpenSCAD file? I can tell you more if you need more details.

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

        Super Customizable Lego Technic Beam
        Modified by Christopher Litsinger
        January 2018

    Inspired by TUSH - A remix of many!
    by spongybob1958, published Sep 7, 2017
    https://www.thingiverse.com/thing:2521463
*/

/* [Customize] */
//the maximum length of the overall rail
rail_length_max=80;
//the size of the gaps
gap_length=3.03;
//the size of the peaks
peak_length=2.535;
//how wide should the rail be
rail_width = 19.5;
//do you want screw tabs on the end?
screw_tabs = "no"; // [yes, no]
//do you want a center m4 hole?
center_hole="yes"; //[yes, no]
//what is the radius for the screws you're using to attach the rail
screw_radius = 3;

// preview[view:south, tilt:top]
// Model - Start

tab_offset = (screw_tabs == "yes") ? rail_width : 0;

segment_height = max(gap_length, peak_length);

num_segments = floor((rail_length_max - tab_offset)/(gap_length+peak_length));

module draw_tabs() {
    difference() {
        translate([num_segments*(gap_length+peak_length) + peak_length, rail_width/2, 0]) {
            cylinder(r=rail_width/2, h=segment_height*2, $fn=32);
            }
        translate([num_segments*(gap_length+peak_length) + peak_length - rail_width/2, 0, -1]) {
                cube([rail_width/2,rail_width, segment_height * 3]);
            }
        translate([num_segments*(gap_length+peak_length) + peak_length + screw_radius, rail_width/2, -1]) {
            cylinder(r=screw_radius, h=segment_height*3, $fn=32);
            }
        }
    difference() {
        translate([0, rail_width/2, 0]) {
            cylinder(r=rail_width/2, h=segment_height*2, $fn=32);
            }
        translate([0, 0, -1]) {
                cube([rail_width/2,rail_width, segment_height * 3]);
            }
        translate([-screw_radius, rail_width/2, -1]) {
            cylinder(r=screw_radius, h=segment_height*3, $fn=32);
            }
        }

}

module draw_center_hole() {
    translate([(num_segments*(gap_length+peak_length) + peak_length)/2, rail_width/2, -1]) {
        cylinder(r=1.989, h = segment_height *3, $fn=64);
        }
    translate([(num_segments*(gap_length+peak_length) + peak_length)/2, rail_width/2, segment_height - (segment_height/2)]) {
        cylinder(r=3.5, h=segment_height*2+1, $fn=6);
        }
}

difference() {
    union() {
        cube([(num_segments*(gap_length+peak_length) + peak_length), rail_width, segment_height]);
        for (ii = [0:num_segments]) {
                translate([ii*(gap_length+peak_length), 0, segment_height]) {
                    cube([(peak_length), rail_width, segment_height]);
                }
            }

        if (screw_tabs == "yes") {
            draw_tabs();
            }
        }
    if (center_hole == "yes") draw_center_hole();
}

```


[User]
I'm looking to create a customizable glass bed clamp for my 3D printer, and I'd like to use OpenSCAD for this. I need something that can handle various bed sizes, glass thicknesses, screw positions, and offer different mounting options. I've seen a few designs out there, but I really want a parametric version I can tweak easily.

Here’s what I’m hoping the design can achieve:

**Core Functionality:**

*   **Parametric Bed and Glass Dimensions:** I should be able to input the dimensions of my printer's bed (`bed_dimensions` – x, y, z) and the glass plate (`bed_glass_dimensions` – x, y, z). Also the `bed_glass_clearance` parameter should account for the optional space between the bed and glass.
*   **Screw Positioning:** I need to be able to specify the position of the bed screws (`bed_screw_position` – x, y, z) relative to the bed's front left corner, and have the design account for this in the clamp. This screw location can be set in the design. Additionally, I need to specify screw head and bolt dimensions (`screw_bolt_dimensions` and `screw_head_dimensions`), for the screw cutouts.
*   **Screw Notch Customization:** It’s important that the design includes a customizable screw notch. This should allow me to stretch it (`screw_notch_stretch`) in the y direction, offset it (`screw_notch_offset`), and even flip its orientation (`screw_notch_flip_p`) from x to y.
*   **Automatic Screw Notch Fitting:** I would like to have an option (`screw_notch_auto_fit_p`) to have the screw notch automatically adjust in height to account for the material under the screw head (`screw_notch_auto_fit_thickness`). This way the screw can be used to fix the clamp, or if disabled, a simple notch is placed in the material. There should also be a parameter for the clearance of the notch (`screw_notch_clearance`).
*   **Fillets:** The clamp should have an option for fillets (`clamp_fillet_radius`) to reduce sharp edges. The glass itself should also allow for fillet setting (`bed_glass_fillet_radius`)
*   **Clearance Options:** I need some parameters for clearance adjustments: `clamp_to_bed_clearance` (x, y, z) and `clamp_to_glass_clearance` (x, y, z), to tweak the fit for looser or tighter mounting.
*  **Clamp Enclosure:** The clamp should be able to enclose the glass with a given size (`clamp_glass_closure` - x, y, z). The z value should define the top thickness of the clamp.
*   **Glass Slice Feature:** I would like an option (`clamp_glass_slice` - x, y, z) to add a "slice" on top of the glass if needed (to keep the glass down). The z value of this parameter should override the `clamp_glass_closure` z value. The size of this "slice" can be set independently and the clamp should be automatically raised to create space for this. Also the maximum width of the slice should be configurable (`clamp_glass_slice_max_width`).
*   **Under Bed Bracket:** It would be nice to specify a width of a bracket below the bed (`clamp_bed_bracket_width`) for extra support.
*   **Base Thickness:** I need to set a base material thickness parameter (`thickness`).

**Additional Features**
*   **Print Orientation:** I want to be able to mirror the model (`x_mirror_p`) for printing and rotate the model (`x_rotate_p`).
*   **Print Resolution:** The design needs to use a resolution parameter (`resolution`) to define surface detail for printing.
*   **Demo Mode:** I would like to have an option for a demo mode (`x_demo_mode_p`) that will print four clamps with a bed to visualize the fit.

I would like a parametric OpenSCAD design that uses a modular approach so the code can be easier to maintain. The design should not rely on external libraries. Could you generate the `.scad` file(s) for me?

[Assistant]
Custom_Glass_Clamp_v1.3.scad:
```
/* == Customizer Settings ================================================ */
/*[Basics]*/

// in mm [x,y,z]
bed_dimensions = [310,370,4.5];

// in mm [x,y,z], relative to front left corner bed (z = 0, screw head above bed, ignored when screw notch auto fit active)
bed_screw_position = [35, 20, 0];

// in mm [x,y,z]
bed_glass_dimensions = [310,310,4];

// in mm, optional clearance between bed and glass
bed_glass_clearance = 0.0;

// in mm, set 0 for no fillet
bed_glass_fillet_radius = 0;

/*[Screws]*/
// in mm [diameter, height], bolt height excluding screw head
screw_bolt_dimensions = [4.5,30];

// in mm [diameter, height]
screw_head_dimensions = [9, 1.8];

// in mm, stretch screw notch in y direction (0 for round notch only)
screw_notch_stretch = 8; // [0:25]

// in mm, 0 centered on screw
screw_notch_offset = -2; // [-25:25]

// boolean, flip screw notch from x to y axis (relevant only if stretch > 0)
screw_notch_flip_p = "yes"; // [yes,no]

// in mm, clearance between screw and screw notch (added to radius of screw and screw head)
screw_notch_clearance = 0.5;

// boolean, fit screw notch automatically, false if screw notch should only be inside (screw can't be used to fix clamp)
screw_notch_auto_fit_p = "yes"; // [yes,no]

// in mm, material thicknes below screw head (only used if screw notch auto fit is active)
screw_notch_auto_fit_thickness = 2;

/*[Details]*/
// in mm, set 0 for no fillet
clamp_fillet_radius = 2; //[0:5]

// in mm [x,y,z], optionally tweak clearance between clamp and bed for looser(+)/tighter(-) fit
clamp_to_bed_clearance = [0.2,0.2,0.2];

// in mm [x,y,z], optionally tweak clearance between clamp and glass for looser(+)/tighter(-) fit, z only relevant if glass slice is added
clamp_to_glass_clearance = [-1.5,-1.5,0];

// in mm [x,y,z], clamp enclosing the glass where z = top thickness (ignored if slice is added)
clamp_glass_closure = [55,25,3];

// in mm [x,y,z], if x/y and z > 0 auto raise clamp and add slice on top of glass, thickness = z (offset from top of glass, overrides closure height)
clamp_glass_slice = [3,3,3];

// in mm [x,y], limit glass slice x/y width relative to glass corner, set to 0 for full size slice (full brackte x/y)
clamp_glass_slice_max_width = [15,15];

// in mm, width of the bracket below the bed (not affected by clearance, capped by clamp dimensions)
clamp_bed_bracket_width = 5;

// in mm, thickness of base material
thickness = 3; //[1:10]

/*[Print]*/
// Surface detail level
resolution = 35; // [20:Draft, 35:Normal, 50:Smooth]

// toggle clamp orientation? (mirror model, print both orientations 2 times)
x_mirror_p = "no"; // [yes,no]

// rotate clamp? (flip over) for printing?
x_rotate_p = "no"; // [yes,no]

// toggle demo mode? (show 4 clamps and print bed)
x_demo_mode_p = "no"; // [yes,no]

/* == Render ============================================================= */
// map yes/no strings to boolean
screw_notch_flip = screw_notch_flip_p == "yes";
screw_notch_auto_fit = screw_notch_auto_fit_p == "yes";
x_demo_mode = x_demo_mode_p == "yes";
x_mirror = x_mirror_p == "yes";
x_rotate = x_rotate_p == "yes";

// render
mirror(x_mirror ? [1,0,0] : [0,0,0])  {
    rotate(x_rotate ? [-180,0,0] : [0,0,0]) {
        if (x_demo_mode) {
            color("grey") PrintBedClampFit();
            color("blue") PrintBedClamps();
        } else {
            color("blue") PrintBedClamp();
        }
    }
}

/* == Demo of Bed + Clamps =============================================== */
// demo print bed
module PrintBedClampFit() {
    bed_screw_position = screw_notch_auto_fit
            ? lvmult([1,1,0],bed_screw_position) + [0,0,screw_notch_auto_fit_thickness + clamp_to_bed_clearance[2]]
            : bed_screw_position;
    translate(clamp_to_bed_clearance) {
        PrintBedWithGlass(bed=bed_dimensions, glass=bed_glass_dimensions,
                          screw_pos=bed_screw_position,
                          screw=screw_bolt_dimensions, screw_head=screw_head_dimensions,
                          glass_clear=bed_glass_clearance,
                          $fn=resolution);
    }
}
// demo clamps
module PrintBedClamps() {
    PrintBedClamp();
    mirror([1,0,0]) { translate([-bed_dimensions[0]-2*clamp_to_bed_clearance[0],0,0]) { PrintBedClamp(); } }
    mirror([0,1,0]) { translate([0,-bed_dimensions[1]-2*clamp_to_bed_clearance[1],0]) { PrintBedClamp(); } }
    mirror([1,0,0]) { mirror([0,1,0]) { {
        translate([-bed_dimensions[0]-2*clamp_to_bed_clearance[0],-bed_dimensions[1]-2*clamp_to_bed_clearance[1],0]) {
            PrintBedClamp();
        }
    } } }
}

/* == Clamp Modules ====================================================== */
// FIXME: pritty ugly and slow solution
module PrintBedClamp() {
    slice_auto_fit = max(clamp_glass_slice[0],clamp_glass_slice[1]) > 0 && clamp_glass_slice[2] > 0;
    slice_auto_z = (slice_auto_fit ? bed_glass_dimensions[2] + clamp_glass_slice[2] : clamp_glass_closure[2]);
    // base dimensions
    x = (bed_dimensions[0] - bed_glass_dimensions[0])/2 + clamp_glass_closure[0] + clamp_to_bed_clearance[0];
    y = (bed_dimensions[1] - bed_glass_dimensions[1])/2 + clamp_glass_closure[1] + clamp_to_bed_clearance[1] ;
    z = (clamp_bed_bracket_width > 0 ? thickness : 0) + 2*clamp_to_bed_clearance[2] + bed_dimensions[2] + slice_auto_z;

    bed = bed_dimensions + lvmult([1,1,2],clamp_to_bed_clearance);
    glass = bed_glass_dimensions + lvmult([1,1,2],clamp_to_bed_clearance)
            + [clamp_to_glass_clearance[0],
               clamp_to_glass_clearance[1],
               bed_glass_clearance-clamp_to_glass_clearance[2]];
    module PBCSoftCube(size) {
        SoftCubeLazy(size, clamp_fillet_radius, $fn=resolution);
    }
    module PBCBaseBox() {
        translate(-[thickness,thickness,(clamp_bed_bracket_width > 0 ? thickness : 0)]) {
            PBCSoftCube([x,y,z]);
        }
    }
    module PBCBedCutout() {
        bed_screw_position =
            [bed_screw_position[0] + clamp_to_bed_clearance[0],
             bed_screw_position[1] + clamp_to_bed_clearance[1],
             screw_notch_auto_fit ? (screw_notch_auto_fit_thickness + clamp_to_bed_clearance[2]) : bed_screw_position[2]];
        PrintBedWithGlass(bed=bed, glass=glass,
                          screw_pos=bed_screw_position + (screw_notch_flip?[0,screw_notch_offset,0,0]:[screw_notch_offset,0,0]),
                          screw=screw_bolt_dimensions+[screw_notch_clearance,0],
                          screw_head=screw_head_dimensions+[screw_notch_clearance,screw_notch_auto_fit?slice_auto_z:0],
                          glass_clear=0,
                          screw_stretch=screw_notch_stretch, screw_stretch_flip=screw_notch_flip,
                          $fn=resolution);
    }
    module PBCGlassSlice() {
        union() {
            //clamp_glass_slice_max_width
            translate(lvmult(bed,[1,1,0])/2 - lvmult(glass,[1,1,0])/2 + [0,0,bed[2]+bed_glass_clearance]) { // glass position
                translate([clamp_glass_slice[0],clamp_glass_slice[1],clamp_glass_slice[2]]) {
                    PBCSoftCube(glass); // x/y base slice
                }
                if (clamp_glass_slice_max_width[0] > 0)
                    translate([max(clamp_glass_slice[0],clamp_glass_slice_max_width[0]),0,clamp_glass_slice[2]]) {
                        PBCSoftCube(glass); // x slice
                    }
                if (clamp_glass_slice_max_width[1] > 0)
                    translate([0,max(clamp_glass_slice[1],clamp_glass_slice_max_width[1]),clamp_glass_slice[2]]) {
                        PBCSoftCube(glass); // y slice
                    }
            }
        }
    }
    module PBCBelowBedCutout() {
        if (clamp_bed_bracket_width > 0) {
            translate([clamp_bed_bracket_width, clamp_bed_bracket_width, -thickness - clamp_to_bed_clearance[2]]) {
                cube([x,y,thickness + clamp_to_bed_clearance[2]]);
            }
        }
    }

    // test: visualize notches
    //PBCBaseBox();
    //PBCZSlice();
    //PBCBedCutout();
    //PBCBelowBedCutout();

    // final clamp (base box with cutouts)
    difference() {
        PBCBaseBox();
        PBCBedCutout();
        if (slice_auto_fit) PBCGlassSlice();
        PBCBelowBedCutout();
    }
}

/* == Simple Print Bed Representation ==================================== */
/* A simplified representation of a print bed with screws and glass plate
 bed                 the print bed dimensions [x,y,z]
 screw_pos           the [x,y,z] screw (holes) position, offset relative to front left corner of print bed, (z optional,
                     default: 0, screw head on top of bed)
 screw               screw dimensions [d,h] (bolt only, screw head not considered)
 screw_head          screw head dimensions [d,h]
 glass               the glass dimensions [x,y,z]
 screw_hole_clear    optional screw hole clearance (radius, default: 0)
 glass_clear         optional clearance between glass and bed (default: 0)
 screw_stretch        stretch screw (default: 0, only sencible if model is used for cutout)
 screw_stretch_flip  stretch screw x/y directly flip (default: false, only sencible if model is used for cutout)
*/
module PrintBedWithGlass(bed, glass, screw_pos, screw, screw_head,
                         screw_hole_clear=0, glass_clear=0, screw_stretch=0, screw_stretch_flip=false) {
    screw_pos = [screw_pos[0],screw_pos[1],(screw_pos[2]==undef?0:screw_pos[2])]; // 2d to 3d
    screw_pos_off = screw_pos + [0,0,-screw[1]+bed[2]]; // screw offset, z relative to bed
    // print bed
    PrintBed(bed=bed, screw_pos=screw_pos, screw=screw, screw_head=screw_head,
             screw_hole_clear=screw_hole_clear, screw_stretch=screw_stretch, screw_stretch_flip=screw_stretch_flip);
    // glass plate with screw holes (if coliding)
    difference() {
        translate(lvmult(bed,[1,1,0])/2 - lvmult(glass,[1,1,0])/2 + [0,0,bed[2]+glass_clear]) {
            SoftCubeLazy(glass, bed_glass_fillet_radius); // glas plate
        }
        translate(screw_pos_off) { // screw holes (if colliding)
            SimpleScrewRect(rect=bed-lvmult(screw_pos,[2,2]),
                            screw=screw+[screw_hole_clear*2,0],
                            head=screw_head+[screw_hole_clear*2,0]);
        }
    }
}
//PrintBedWithGlass(bed=[200, 200, 4], glass=[160,200,3], screw_pos=[15, 15], screw=[3,30], screw_head=[7,1.5]);
//PrintBedWithGlass(bed=[200, 200, 4], glass=[200,190,3], screw_pos=[20, 20,3+0.4], screw=[3,30], screw_head=[7,1.5],
//                  screw_hole_clear=0.2, glass_clear=0.2);

/* A simplified representation of a print bed with screws
 bed                 the print bed dimensions [x,y,z]
 screw_pos           the [x,y,z] screw (holes) position, offset relative to front left corner of print bed, (z optional,
                     default: 0, screw head on top of bed)
 screw               screw dimensions [d,h] (bolt only, screw head not considered)
 screw_head          screw head dimensions [d,h]
 screw_hole_clear    optional screw hole clearance (radius, default: 0)
 screw_stretch        stretch screw (default: 0, only sencible if model is used for cutout)
 screw_stretch_flip  stretch screw x/y directly flip (default: false, only sencible if model is used for cutout)
*/
module PrintBed(bed, screw_pos, screw, screw_head, screw_hole_clear=0, screw_stretch=0, screw_stretch_flip=false) {
    screw_pos = [screw_pos[0],screw_pos[1],(screw_pos[2]==undef?0:screw_pos[2])]; // 2d to 3d
    screw_pos_off = screw_pos + [0,0,-screw[1]+bed[2]]; // screw offset, z relative to bed
    // print bed with screw holes
    difference() {
        cube(bed); // print bed
        translate(screw_pos_off) { // screw holes
            SimpleScrewRect(rect=bed-lvmult(screw_pos,[2,2]),
                            screw=screw+[screw_hole_clear*2,0],
                            head=screw_head+[screw_hole_clear*2,0],
                            screw_stretch=screw_stretch, screw_stretch_flip=screw_stretch_flip);
        }
    }
    // screws
    translate(screw_pos_off) {
        SimpleScrewRect(rect=bed-lvmult(screw_pos,[2,2]),
                        screw=screw, head=screw_head,
                        screw_stretch=screw_stretch, screw_stretch_flip=screw_stretch_flip);
    }
}
//PrintBed(bed=[200, 200, 4], screw_pos=[20, 20], screw=[3,30], screw_head=[7,1.5]);
//PrintBed(bed=[200, 200, 4], screw_pos=[10, 20,-1.2], screw=[3,30], screw_head=[7,1.5], screw_hole_clear=0.2);
//PrintBed(bed=[200, 200, 4], screw_pos=[20, 20], screw=[3,30], screw_head=[7,1.5], screw_stretch=4, screw_stretch_flip=true);

/* == Simple Screw / Screw Notch ========================================= */
/* 4 SimpleScrews positioned in a rectangle
 rect  rectangle dimensions, a SimpleScrew is positiond in each corner [x,y]
 screw               screw dimensions [d,h] (bolt only, screw head not considered)
 head                screw head dimensions [d,h]
 screw_stretch        stretch screw (default: 0, sencible if model is used for cutout)
 screw_stretch_flip  stretch screw x/y directly flip (default: false, sencible if model is used for cutout)
*/
module SimpleScrewRect(rect, screw, head, screw_stretch=0, screw_stretch_flip=false) {
    rotate([0,0,screw_stretch_flip?0:90]) {
        SimpleScrewStretched(screw, head, screw_stretch);
    }
    translate(lvmult([1,0],rect)) {
        rotate([0,0,screw_stretch_flip?0:90]) {
            SimpleScrewStretched(screw, head, screw_stretch);
        }
    }
    translate(lvmult([0,1],rect)) {
        rotate([0,0,screw_stretch_flip?0:90]) {
            SimpleScrewStretched(screw, head, screw_stretch);
        }
    }
    translate(lvmult([1,1],rect)) { // ignore 3rd dimension
        rotate([0,0,screw_stretch_flip?0:90]) {
            SimpleScrewStretched(screw, head, screw_stretch);
        }
    }
}
//SimpleScrewRect(rect=[50,100], screw=[3,30], head=[7,1.5], stretch=15);

/* A simplified screw tretched in y axis
   Can be used (difference) to add a screw notch. Screw and head needs to be tweeked
   accordingly (clearance, material thickness, etc.)
 screw  screw dimensions [d,h] (bolt only, screw head not considered)
 head   screw head dimensions [d,h]
 stretch  distance between the center (screw axis) of two combined screws
*/
module SimpleScrewStretched(screw, head, stretch) {
    union() {
        translate(-[0,stretch/2,0]) {
            SimpleScrew(screw, head);
        }
        // screw head guide
        translate([0,0,head[1]/2 + screw[1]]) {
            cube([head[0],
                  stretch,
                  head[1]],
                  center=true);
        }
        // screw guide
        translate([0,0,screw[1]/2]) {
            cube([screw[0],
                  stretch,
                  screw[1]],
                  center=true);
        }
        translate([0,stretch/2,0]) {
            SimpleScrew(screw, head);
        }
    }
}
//SimpleScrewStretched(screw=[3,30], head=[7,1.5], stretch=15);

/* A simplified screw
 screw  screw dimensions [d,h] (bolt only, screw head not considered)
 head   screw head dimensions [d,h]
*/
module SimpleScrew(screw, head) {
    union() {
        // screw head guide
        translate([0,0,screw[1]]) {
            cylinder(d=head[0], h=head[1]);
        }
        // screw guide
        cylinder(d=screw[0], h=screw[1]);
    }
}
//SimpleScrew(screw=[3,30], head=[7,1.5]);

/* == Fillet ============================================================= */
/* cube with softened (z-axis) edges, lazy version
 size    [x,y,z]
 radius  fillet radius, standard cube if <= 0, limited to x/y dimensions (fully rounded x/y edges)
 expand  fillet, size defines outer dimensions (false, default) or add radius to x/y size (true)
 center  center cube (default: false)
 - based on https://www.thingiverse.com/thing:9347
*/
module SoftCubeLazy(size, radius, expand=false, center=false) {
    if (radius <= 0) { // standard cube, no fillet
        cube(size, center);
    } else {
        x = size[0]; y = size[1]; z = size[2];
        r = min(x/(expand ? 1 : 2), y/(expand ? 1 : 2), radius); // maximum radius (must not exceed x/y dimensions)
        off = r / (expand ? 2 : 1);
        translate (center ? [0,0,-z/2] : [x/2,y/2,0]) {
            linear_extrude(height=z) hull() {
                // place 4 circles in the corners, with the given radius
                translate([-x/2 + off, -y/2 + off, 0]) circle(r);
                translate([ x/2 - off, -y/2 + off, 0]) circle(r);
                translate([-x/2 + off,  y/2 - off, 0]) circle(r);
                translate([ x/2 - off,  y/2 - off, 0]) circle(r);
            }
        }
    }
}
//SoftCubeLazy([20,20,20], 2, $fn=50);
//SoftCubeLazy([40,10,20], 220, center=true, $fn=50);
//SoftCubeLazy([20,10,20], 200, expand=true, center=true, $fn=50);

/* cube with softened (z-axis) edges, strict version
 size    [x,y,z]
 radius  fillet radius, standard cube if <= 0, must be <= 1/2* min(x,y) or <= min(x,y) if expand = true
 expand  fillet, size defines outer dimensions (false, default) or add radius to x/y size (true)
 center  center cube (default: false)
 - based on https://www.thingiverse.com/thing:9347
*/
module SoftCube(size, radius, expand=false, center=false) {
    x = size[0]; y = size[1]; z = size[2];
    assert(radius >= 0, "radius must be >= 0");
    if (expand) {
        assert(radius <= x, "radius must be <= x when expand = true");
        assert(radius <= y, "radius must be <= y when expand = true");
    }  else {
        assert(radius <= x/2, "radius must be <= x/2 when expand = false");
        assert(radius <= y/2, "radius must be <= y/2 when expand = false");
    }
    if (radius <= 0) { // standard cube, no fillet
        cube(size, center);
    } else {
        off = radius / (expand ? 2 : 1);
        translate (center ? [0,0,-z/2] : [x/2,y/2,0]) {
            linear_extrude(height=z) hull() {
                // place 4 circles in the corners, with the given radius
                translate([-x/2 + off, -y/2 + off, 0]) circle(radius);
                translate([ x/2 - off, -y/2 + off, 0]) circle(radius);
                translate([-x/2 + off,  y/2 - off, 0]) circle(radius);
                translate([ x/2 - off,  y/2 - off, 0]) circle(radius);
            }
        }
    }
}
//SoftCube([20,20,20], 2, $fn=50);
//SoftCube([40,10,20], 5, center=true, $fn=50);
//SoftCube([20,10,20], 10, expand=true, center=true, $fn=50);

/* == Matrix Math ======================================================== */
/* lazy vector multiplication, multiply up to 4 vectors with 2 or 3 dimensions
   v1 is used to identify max dimensions
   if v2 to v4 have more dimensions they are ignored
   if v2 to v4 have less dimensions 1 is assumumed */
function lvmult(v1, v2=[1,1,1], v3=[1,1,1], v4=[1,1,1]) =
    v1[2] == undef
      ? [v1[0]*v2[0]*v3[0]*v4[0],
         v1[1]*v2[1]*v3[1]*v4[1]]
      : [v1[0]*v2[0]*v3[0]*v4[0],
         v1[1]*v2[1]*v3[1]*v4[1],
         v1[2]*(v2[2]==undef?1:v2[2])*(v3[2]==undef?1:v3[2])*(v4[2]==undef?1:v4[2])];
//echo(lvmult([2,3],[3,4]));
//echo(lvmult([10,20,30],[2,3]));
//echo(lvmult([10,20,30],[2,3,4],[10,10,10],[2,2,2]));
//echo(lvmult([2,3],[3,4,1]));

/* lazy vector division, divide up to 4 vectors with 2 or 3 dimensions
   v1 is used to identify the dimensions
   if v2 to v4 have more dimensions they are ignored
   if v2 to v4 have less dimensions 1 is assumumed */
function lvdiv(v1, v2=[1,1,1], v3=[1,1,1], v4=[1,1,1]) =
    v1[2] == undef
      ? [v1[0]/v2[0]/v3[0]/v4[0],
         v1[1]/v2[1]/v3[1]/v4[1]]
      : [v1[0]/v2[0]/v3[0]/v4[0],
         v1[1]/v2[1]/v3[1]/v4[1],
         v1[2]/(v2[2]==undef?1:v2[2])/(v3[2]==undef?1:v3[2])/(v4[2]==undef?1:v4[2])];
//echo(lvdiv([10,20,30],[2,3,4]));
//echo(lvdiv([10,20,30],[2,3,4],[10,10,10],[2,2,2]));
//echo(lvdiv([2,3],[3,4,1]));

```


[User]
Hey, I'm looking to create a parametric pipe cutting jig using OpenSCAD. I've seen some designs online, and I have a good idea of what I need but don't really have the time to create it myself.

Basically, it's a jig that holds a pipe or rod at a specific angle for cutting with a jigsaw or other tool. I need to be able to customize the following parameters:

*   **pipe\_diam:** The diameter of the pipe or rod being cut. I need to ensure there's enough clearance so it's not too tight.
*   **angle:** The cutting angle. I need to be able to specify any angle between say 15 and 90 degrees.
*   **jig\_width:** The distance from the cutting guide to the jig's edge. This will depend on my jigsaw's foot.
*   **jig\_length:** The length of the cutting guide. Longer is usually better for stability.
*   **jig\_depth:** How deep the blade can cut. I want to ensure there's enough clearance to cut through without hitting the jig itself.
*   **bolt\_diam:** The diameter of the bolts/holes for mounting the jig to a workbench, if necessary.
*   **wall:** The general wall thickness. I want to ensure it's sturdy.
*   **slope:** This would allow for either a mirrored "uphill" or "downhill" orientation, depending on my preference.

The jig should have the following features:

*   A central channel/hole to hold the pipe or rod, with a little extra clearance
*   A guide that is angled and offset for the jigsaw foot to slide against.
*   Rails along the sides for mounting the jig to a workbench, if needed.
*   Chamfered edges where appropriate for easy insertion.

Could you please create the OpenSCAD files necessary to generate this jig, including parameters? I'd prefer that you don't rely on any external libraries, it's not needed for this type of design. Thanks so much!

[Assistant]
pipe-cutting-jig.scad:
```
// pipe cutting jig
// by Stellar Innovation
// http://www.thingiverse.com/stellarinnovation/about
// licensed under the Creative Commons - Attribution license.

pipe_diam = 26; // [3.0:0.1:40.0]
angle = 60;     // [15:90]
jig_width = 32; // [20:100]
jig_length=120; // [50:150]
jig_depth = 70; // [20:100]
bolt_diam = 5;  // [3:0.1:8]
wall = 6;       // [3:0.5:10]
slope = "uphill";  // [uphill,downhill]

if (slope=="uphill")
  mirror([1, 0, 0])
    PipeCuttingJigPart();
else
  PipeCuttingJigPart();

module PipeCuttingJigPart()  {
  width = max(pipe_diam + 2*wall, jig_length*sin(angle));
  depth = max(pipe_diam + 2*wall, jig_depth);
  offset_y = depth - wall - 0.5*pipe_diam;
  guide_height = wall/sin(angle);
  extra_height = width*cos(angle)/sin(angle);
  height = jig_width/sin(angle) + guide_height + extra_height;
  corner_r = 1.5;
  slot_width = 2.4;

  difference() {
    union() {
      // main block
      translate([-0.5*width, -offset_y])
        ClampBlock(width, depth, height - extra_height, height, corner_r);

      guide_depth = 0.5*pipe_diam + 2*wall;
      difference() {
        // guide
        translate([-0.5*width, 0])
          cube([width, guide_depth, guide_height+extra_height]);

        // slope of guide
        h0 = 0.5*extra_height;
        cut_length = 1.01*width/sin(angle);
        translate([0, 0, h0 + guide_height])
          rotate([0, 90-angle])
            translate([-0.5*cut_length, 0])
              cube([cut_length, guide_depth, 2*extra_height]);
        translate([0, 0, h0])
          rotate([0, 90-angle])
            translate([-0.5*cut_length, 0, -2*extra_height])
              cube([cut_length, guide_depth, 2*extra_height]);
      }

    }
    // hole for the pipe
    cylinder(d=pipe_diam, h=height, $fn=120);
    // chamfer
    cylinder(d1=pipe_diam + 2*corner_r, d2=pipe_diam, h=corner_r, $fn=120);

    // Slot used to clamp the pipe
    translate([-0.5*slot_width, 0])
      cube([slot_width, 0.5*depth+2*wall, height]);
  }

  // Rails
  fancy_corners = corner_r*(1 + tan(0.5*angle));
  tangent = (wall + 0.5*bolt_diam)*(tan(90-0.5*angle) - 1);
  rail_height = height - extra_height - max(fancy_corners, tangent);
  translate([0.5*width, -offset_y])
    Rail(rail_height, wall);
  translate([-0.5*width, -offset_y])
    mirror([1,0,0])
      Rail(rail_height, wall);
}

module ClampBlock(width, depth, h1, h2, corner_r) {
  // "fancy" right corner
  dz1 = corner_r*tan(0.5*angle);
  dx1 = corner_r*(1-cos(angle));
  // "fancy" left corner
  dz2 = corner_r*tan(90-0.5*angle);
  dx2 = corner_r*(1+cos(angle));

  difference() {
    // main block
    cube([width, depth, h2]);

    // leaning cut
    cut_length = 1.01*width/sin(angle);
    translate([0, 0, h2])
      rotate([0, 90-angle])
          cube([cut_length, depth + wall, 2*max(h2 - h1, width)]);

    // Cut outs for fancy corners
    translate([width-dx1, 0, h1-dz1])
      cube([dx1, depth, corner_r]);
    translate([0, 0, h2-dz2])
      cube([dx2, depth, dz2]);
  }

  // fancy corners
  translate([width-corner_r, 0, h1-dz1])
    rotate([-90,0])
      cylinder(r=corner_r, h=depth, $fn=12);
  translate([corner_r, 0, h2-dz2])
    rotate([-90,0])
      cylinder(r=corner_r, h=depth, $fn=12);
}

module Rail(height, thickness) {
  width = bolt_diam + 2*thickness;
  r = 0.5*width;
  fillet_r = 1.5;
  difference() {
    union() {
      // main rail
      cube([width, thickness, height - r]);
      translate([0, 0, height - r]) {
        // rounded end
        rotate([-90, 0])
          translate([r, 0])
            cylinder(d=width, h=thickness, $fn=60);
        // fills in gap (makes round end a quarter circle)
        cube([r, thickness, r]);
      }
      // fillet
      cube([fillet_r, thickness+fillet_r, height + fillet_r]);
    }

    // slot
    translate([r, 0, r - 0.5*bolt_diam])
      rotate([90, 0]) {
        slot_h = height - r;
        bolt_r = 0.5*bolt_diam;
        translate([-bolt_r, 0, -thickness])
          cube([bolt_diam,  slot_h - bolt_diam, 2*thickness]);
        cylinder(d=bolt_diam, h=2*thickness, $fn=30, center=true);
        translate([0, slot_h - bolt_diam])
          cylinder(d=bolt_diam, h=2*thickness, $fn=30, center=true);
      }

    // fillet
    translate([fillet_r, thickness+fillet_r])
      cylinder(r=fillet_r, h=height + fillet_r, $fn=12);
    translate([fillet_r, 0, height+fillet_r])
      rotate([90, 0])
        cylinder(r=fillet_r, h=3*thickness, center=true, $fn=12);
  }
}

```


[User]
Okay, I'm working on a project where I need corner brackets for connecting square tubing, specifically 20mm square tubing with a 1.2mm wall thickness. I've got a design in mind that should be strong and easy to 3D print, but I'm not great at OpenSCAD myself, so I need your help.

My main goals are:
1.  The bracket should have prongs that slide *inside* the square tubing.
2.  The prongs should have a rounded profile, like a cylinder with rounded ends, to make insertion smoother and to add strength.
3.  The design should print in an orientation that doesn't require support, and so that each layer provides strength to all three prongs.
4.  The prongs should extend into the tubing about 1.5 times the outside dimension of the tube, so about 30mm.
5.  I need a small clearance between the prongs and the inner tube to allow it to slide in, something like 0.2mm should work.
6.  The edges of the prongs should be rounded with a radius of about 2mm.

I've provided you with an example file but it has some quirks to it. It uses a hull() to create the prong shapes which makes it a bit hard to adjust. I would like to create the prongs using a standard prism/extrude operation so that the shapes can be adjusted more easily.

I was hoping you could create a parametric OpenSCAD file (or files) for this where I can easily change the following parameters:
*   `tube_size`: the outside dimension of the square tube.
*   `wall_thickness`: the wall thickness of the tube.
*   `prong_length`: the length of the prongs extending into the tube.
*   `clearance`: the clearance between the prongs and the tube.
*   `prong_round_radius`: the radius of the rounding on the prongs.

The file should not require any libraries outside of the default OpenSCAD install. It'd be great if the code was well-commented to understand how everything works, too. Thanks!

[Assistant]
corner_bracket.scad:
```
// Outside dimension of the square tube
a = 20;
// Wall thickness of the tube
b = 1.2;
// How far the prongs should extend into the tube. Ideally, about 1.5 times the dimension of the tube.
c = 30;
// Clearance. More clearance makes the prongs fit looser. 0.2 produces a sliding fit on my printer.
d = 0.2;
// Radius of the rounding on the prongs. 2 is about right.
f = 2;

// Nice rounding on the round edges
$fs=0.02;

// plug cross section
e = a-b-b-d-d;

// Rounded top cylinder
module rts(h, r) {
    cylinder(h-r, r=r);
    translate([0,0,h-r]) sphere(r=r);
}

// One prong
module prong() {
    translate([b+d, b+d,a]) hull() {
        translate([f,f,0]) rts(c, f);
        translate([e-f,f,0]) rts(c, f);
        translate([f,e-f,0]) rts(c, f);
        translate([e-f,e-f,0]) rts(c, f);
    }
}

// All three prongs and connection, rotated to print without support
difference() {
    rotate(a=atan(sqrt(2)), v=[1,1,0]) union() {
        cube([a, a, a], center=false);
        prong();
        rotate([-90,0,0]) translate([0,-a,0]) prong();
        rotate([0,-90,0]) translate([0,0,-a]) prong();
    };
    translate([0,0,-4*a]) cube([a*8, a*8, a*8], center=true);
}

```


[User] I need a custom tag generator for my kegerator. I'd like to be able to specify the height, width, thickness, hole diameter, fillet radius, and loop pad size. The tag should have a rounded rectangular shape with fillets on each corner, a loop at the top for attaching to a hose, and a center text label for indicating the tap number. There should also be a central piece on the tag that can be used to add a little extra material in the middle - make this a parameter that can be set to zero to disable it. The loop should have the hole, as well as some round fillet pieces connecting it to the main rectangular body. Please generate the OpenSCAD files for this, using the "text" function and "linear_extrude" for the text. I don't need any special libraries.

[Assistant]
tag.scad:
```
HEIGHT=40;
WIDTH=30;
HOLE=5;
THICKNESS=2;
FILLET=2;
LOOP_PAD=3;
CENTER_PIECE=2; // 0 for none
TAG="4";

hideTheNoneParameters();
module hideTheNoneParameters() {
    $fn=50;
    cornerFilletXOffset = WIDTH/2-FILLET;
    cornerFilletYOffset = HEIGHT-FILLET;
    holePad=HOLE+LOOP_PAD;

    difference() {
        union() {
            // Corner fillets
            translate([-cornerFilletXOffset, FILLET, 0])
                cylinder(h=THICKNESS, r=FILLET, center=true);
            translate([cornerFilletXOffset, FILLET, 0])
                cylinder(h=THICKNESS, r=FILLET, center=true);
            translate([-cornerFilletXOffset, cornerFilletYOffset, 0])
                cylinder(h=THICKNESS, r=FILLET, center=true);
            translate([cornerFilletXOffset, cornerFilletYOffset, 0])
                cylinder(h=THICKNESS, r=FILLET, center=true);
            // Base fillings
            translate([0, HEIGHT/2, 0]) {
                cube([WIDTH-2*FILLET, HEIGHT, THICKNESS], center=true);
                cube([WIDTH, HEIGHT-2*FILLET, THICKNESS], center=true);
            }
            // Loop
            translate([0, HEIGHT+HOLE, 0]) {
                cylinder(r=holePad, h=THICKNESS, center=true);
                translate([0, -holePad/2, 0])
                    cube([2*holePad, holePad, 2], center=true);
            }
            // Loop fillet - the block
            translate([holePad+LOOP_PAD/2, HEIGHT+LOOP_PAD/2, 0])
                cube([LOOP_PAD, LOOP_PAD, THICKNESS],  center=true);
            translate([-(holePad+LOOP_PAD/2), HEIGHT+LOOP_PAD/2, 0])
                cube([LOOP_PAD, LOOP_PAD, THICKNESS],  center=true);
        }
        // Loop fillet
        translate([holePad+LOOP_PAD, HEIGHT+LOOP_PAD, 0])
            cylinder(r=LOOP_PAD, h=THICKNESS+1,  center=true);
        translate([-(holePad+LOOP_PAD), HEIGHT+LOOP_PAD, 0])
            cylinder(r=LOOP_PAD, h=THICKNESS+1,  center=true);

        // Loop hole
        translate([0, HEIGHT+HOLE, 0])
            cylinder(r=HOLE, h=THICKNESS+1, center=true);

        // Text
        translate([0, HEIGHT/2, 0]) {
            linear_extrude(height=THICKNESS+1, center=true) {
                text(TAG, font = "Liberation Sans:style=Bold", size=30, halign="center", valign="center");
            }
        }
    }

    translate([0, HEIGHT/2])
        cube([CENTER_PIECE, HEIGHT-2, THICKNESS], center=true);
}
```


[User]
Hey, I'm looking for an OpenSCAD design for a customizable wire grommet. I've seen a couple on Thingiverse but they're not quite what I need. I'd like it to be parametric so I can easily change the dimensions and have some options for locking it together.

Here's what I'm imagining:

*   **Basic Shape:** It should be a two-part design, a top and a bottom, that fit together. The overall shape should be cylindrical.
*   **Grommet Diameter:** I need to be able to set the outer diameter of the grommet that fits into the table or desk hole.
*   **Hole Diameter:** I need to control the size of the access hole in the center where the wires will pass through.
*   **Hole Depth:** The depth of the bottom part should be adjustable, determining how far it protrudes below the mounting surface.
*   **Top Depth:** The top part should have a specified height and a slight bevel to the outside edge.
*   **Locking Tabs:** This is the tricky bit. I'd like to have an option to add locking tabs to the top and bottom, so they click together securely.
    *   The top tabs will protrude below the main top section
    *   The bottom tabs will protrude outside the main bottom section
    *   I should be able to choose whether the top has tabs or not.
    *   I should be able to choose whether the bottom has tabs or not.
    *   The tabs will lock into slots on the other piece.
*  **Text on Top:** It would be really helpful if I could add some text on the lid, configurable for size, position, and spacing.

I've seen some examples that use `write.scad` for text, so you'll need that, and also `build_plate.scad` to provide a visual reference of the size of the build plate.

Could you generate the OpenSCAD code for this? Let me know if you need more information.

[Assistant]
Customizable_Wire_Grommet_TNH+GE_1.41.scad:
```
// Customizable Wire Access Grommet v1.3
// by TheNewHobbyist 2014 (http://thenewhobbyist.com)
// http://www.thingiverse.com/thing:273159
// remixed by GreenEllipsis 2018
//
// "Customizable Wire Access Grommet" is licensed under a
// Creative Commons Attribution-NonCommercial 3.0 Unported License.
//
// Description:
// Updated version of my previous design (thing:7902). These should press fit securely
// together.
//
// Usage:
// Use the sliders to select your desired diameter (in mm) for the grommet
// itself and the access hole cut into it.
//
// Enter text if desired for lid.
//
// Change Log:
// v1.0 CREATED
// v1.1 ADDED write.scad generated text on lid of grommet
// v1.2 UPDATED views for Customizer App
// v1.3 UPDATED diameter of table hole (thanks for the heads up daverees)
// v1.4 UPDATED by Green Ellipsis to add locking prongs and customizable hole depth. Made model more parametric in general.
// v1.41 BUG FIXES by Green Ellipsis

  //////////////////////
 // Customizer Stuff //
//////////////////////

/* [Grommet Settings] */

//Select the diameter of the hole in table in mm
Grommet_Diameter = 40; // [20:90]

//Select the diameter if the access hole in mm
Hole_Diameter = 20; // [5:50]

//Select the depth of the grommet in mm
Hole_Depth = 13; //[4:250]

/* [Text] */

//Rotate model to see text
Top_Text = ""; //

// Default is 8
Font_Size = 8; // [5:20]

Letter_Spacing = 1.3; // [1:Close, 1.3:Normal, 1.6:Far, 2:Very Far]

/* [Build Plate] */

//For display only, doesn't contribute to final object
build_plate_selector = 0; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//When Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//When Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

/* [Locking Tabs] */

// Include tabs in top and slots in bottom.
locking_top = 0; //[0:No,1:Yes]

//* Include tabs in the bottom to lock to underside of hole.
locking_bottom = 0; //[0:No,1:Yes]

/* [Hidden] */

$fn=120;

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

  /////////////////////////////////
 // No talking in the libraries //
/////////////////////////////////

 use <utils/build_plate.scad>
 use <write/Write.scad>

  ////////////////////
 // Moduletown USA //
////////////////////

shell_thickness = 3;
top_inner_radius = ((Grommet_Diameter/2)/1.14)-shell_thickness;
top_outer_radius = ((Grommet_Diameter/2)/1.14)-.1;
top_depth = 4;
tab_stem_radius = shell_thickness/4;
tab_stem_height = tab_stem_radius*4;
tab_radius = tab_stem_radius*3/2;

module tab_cutout() {
    // cut a recess for the tab
    translate([-shell_thickness*1.1/2,0,-tab_stem_height/2+tab_radius]) cube([shell_thickness*1.1, tab_stem_radius*3, tab_stem_height-tab_radius], center=true);
}

// The tab will have its tab stem outer edge flush with the x-axis, will be centered on the y-axis and have the bottom of the tab at z=0. The stem will extend below z=0.
module tab() {
    // tab stem
    translate([-tab_stem_radius,0,-tab_stem_height+tab_radius]) {
        cylinder(r=tab_stem_radius, h=tab_stem_height, center=false);
        // the tab itself
        translate([tab_radius-tab_stem_radius,0,tab_stem_height]) rotate([90,0,0])
            cylinder(r=tab_radius, h=tab_stem_radius*2, center=true);
    }
}

module solid_top(){
	translate([0,0,1.5]) cylinder(r1=(Grommet_Diameter/2)*1.2, r2=(Grommet_Diameter/2)*1.25,h=shell_thickness, center=true);
    if (locking_top == 0) {
        translate([0,0,5]) cylinder(r=top_outer_radius, h=top_depth, center=true);
    } else {
        difference() {
            translate([0,0,5]) cylinder(r=top_outer_radius, h=top_depth, center=true);
            translate([-(top_outer_radius),0,shell_thickness+top_depth]) rotate([0,0,180]) tab_cutout();
            translate([0,-(top_outer_radius),shell_thickness+top_depth]) rotate([0,0,-90]) tab_cutout();
            translate([0,(top_outer_radius),shell_thickness+top_depth]) rotate([0,0,+90]) tab_cutout();
        }
        // create tabs
        translate([-(top_outer_radius),0,shell_thickness+top_depth])  rotate([0,0,+180]) tab();
        translate([0,-(top_outer_radius),shell_thickness+top_depth]) rotate([0,0,-90]) tab();
        translate([0,(top_outer_radius),shell_thickness+top_depth]) rotate([0,0,+90]) tab();
    }
}

module full_top(){
    union(){
		difference(){
			solid_top();
			translate([0,0,5.25]) cylinder(r=top_inner_radius, h=5, center=true);
			translate([Grommet_Diameter*.25,0,0]) cylinder(r=Hole_Diameter/2, h=40, center=true);
			translate([Grommet_Diameter*.6,0,0]) cube([Grommet_Diameter*.75, Hole_Diameter, 40], center=true);
			rotate([180,0,0]) writecylinder(Top_Text,[0,0,0],Grommet_Diameter/1.5,0,space=Letter_Spacing,east=-90,face="top",center=true, h=Font_Size);
		}
	}
}

module solid_bottom(){
	cylinder(r=(Grommet_Diameter/2)*1.25, h=shell_thickness, center=false);
    if (locking_bottom == 0) {
        cylinder(r=(Grommet_Diameter/2), h=shell_thickness+Hole_Depth, center=false);
    } else {
        difference() {
        	cylinder(r=(Grommet_Diameter/2), h=shell_thickness+Hole_Depth, center=false);
            // tab cutouts
            translate([(Grommet_Diameter/2),0,shell_thickness+Hole_Depth]) rotate([0,0,0]) tab_cutout();
            translate([-(Grommet_Diameter/2),0,shell_thickness+Hole_Depth]) rotate([0,0,180]) tab_cutout();
            translate([0,-(Grommet_Diameter/2),shell_thickness+Hole_Depth]) rotate([0,0,-90]) tab_cutout();
            translate([0,(Grommet_Diameter/2),shell_thickness+Hole_Depth]) rotate([0,0,+90]) tab_cutout();
        }
        // create tabs
        translate([(Grommet_Diameter/2),0,shell_thickness+Hole_Depth])  rotate([0,0,0]) tab();
        translate([-(Grommet_Diameter/2),0,shell_thickness+Hole_Depth])  rotate([0,0,+180]) tab();
        translate([0,-(Grommet_Diameter/2),shell_thickness+Hole_Depth]) rotate([0,0,-90]) tab();
        translate([0,(Grommet_Diameter/2),shell_thickness+Hole_Depth]) rotate([0,0,+90]) tab();
    }

}

module full_bottom(){
	union(){
		difference(){
			solid_bottom();
			// center hole
            cylinder(r=(Grommet_Diameter/2)/1.14, h=250, center=false);
			// tab slot
            if (locking_top == 1) {
                translate([0,0,top_depth]) cylinder(r=(Grommet_Diameter/2)/1.14+tab_radius, h=tab_radius*2, center=false);
            }
		}
	}
}

  //////////////////////////
 // Put it all together! //
//////////////////////////

if (preview_tab == "Text"){
translate([-Grommet_Diameter*.8,0,0]) full_top();
translate([Grommet_Diameter*.8,0,0]) full_bottom();
}

else if (preview_tab == "Build plate"){
translate([-Grommet_Diameter*.8,0,0]) full_top();
translate([Grommet_Diameter*.8,0,0]) full_bottom();
build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);
}

else{
	translate([-Grommet_Diameter*.8,0,0]) full_top();
	translate([Grommet_Diameter*.8,0,0]) full_bottom();
	build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);
}

```


[User]
I'm looking to create a design for a 3D-printable item that consists of four hearts arranged in a circular pattern. Each heart should have some customizable text on it, and there should be an option to add a hole at the top for turning it into a necklace.

Here are the specifics:

*   **Hearts:** There should be four hearts arranged in a circle (at 0, 90, 180, and 270 degrees, if that makes sense). Each heart should have a rounded, almost puffy look, like it's been made with a minkowski operation with a sphere.
*   **Text:** Each heart needs space for custom text on it. This text should be arranged in a rotated position so that it's aligned with the heart's orientation. The text should be able to accommodate both single-line and double-line text. When using two lines, the slash '/' character will indicate where to break the line. The text should be extruded with linear_extrude. The font for the text needs to be "cousine".
*   **Necklace Hole:** I need a toggle option to add a small hole to each heart. This should go at the top of each heart, and it needs to have rounded edges. When the necklace hole option is active, it should be a hole that goes through the entire part.
*   **Customization:** All the text strings, along with the option to include the necklace hole, should be customizable in the OpenSCAD customizer.  The text should also include a thickness parameter to control the width of text characters. The thickness of the text should also be customizable with the text parameter.

I'm looking for a single .scad file that includes all this. Can you help me with that?

[Assistant]
4_hearts_v2.scad:
```
necklace_hole=0;//[1:true,0:false]
//10 characters (optional slash /) 10 more characters
heart1="Customizer/Hearts";
//10 characters (optional slash /) 10 more characters
heart2="Be My/Valentine";
//10 characters (optional slash /) 10 more characters
heart3="Your text";
//10 characters (optional slash /) 10 more characters
heart4="Openscad/Dad";
/* [Hidden] */
face_number=30;
thickness=45;

module hole() {
   difference() {
      minkowski() {
         difference() {
            cylinder(3,1,1,center=true,$fn=face_number,center=true);
            cylinder(4,.99,.99,center=true,$fn=face_number,center=true);
         }
         sphere(.5,$fn=face_number);
      }
      translate([0,0,-5])cube(10,center=true);
   }
}

module heart_shape() {
   cube([10,10,1]);
   translate([0,5,0])cylinder(1,5,5,$fn=50);
   translate([5,0,0])cylinder(1,5,5,$fn=50);
}

module heart() {
   difference() {
      translate([-12,-12,0])
         minkowski() {
            heart_shape();
            sphere(1,$fn=face_number);
         }
      if(necklace_hole==1) {
         translate([-11.75,-11.75,0])cylinder(11,.9,.9,center=true,$fn=face_number);
      }
      translate([0,0,-20])cube([40,40,40],center=true);
   }
   if(necklace_hole==1) {
      translate([-11.75,-11.75,0])hole();
   }
}

module heart_text() {
   rotate([0,0,45]) {
      if(search("/",heart1)==[]) {
         //single line
         for(i=[0:1:len(heart1)]) {
            translate([i*thickness/14-len(heart1)*thickness/14/2,24,3])linear_extrude(2)text(font="cousine",heart1[i],thickness/10,$fn=50);
         }
      }
      else {
         //double line
         for(i=[0:1:search("/",heart1)[0]-1]) {
            translate([i*thickness/14-(search("/",heart1)[0])*thickness/14/2,27,3])linear_extrude(2)text(font="cousine",heart1[i],thickness/10,$fn=50);
         }
         for(i=[search("/",heart1)[0]+1:1:len(heart1)]) {
            translate([(i-search("/",heart1)[0]-1)*thickness/14-(len(heart1)-search("/",heart1)[0]-1)*thickness/14/2,20,3])linear_extrude(2)text(font="cousine",heart1[i],thickness/10,$fn=50);
         }
      }
   }
   rotate([0,0,135]) {
      if(search("/",heart2)==[]) {
         //single line
         for(i=[0:1:len(heart2)]) {
            translate([i*thickness/14-len(heart2)*thickness/14/2,24,3])linear_extrude(2)text(font="cousine",heart2[i],thickness/10,$fn=50);
         }
      }
      else {
         //double line
         for(i=[0:1:search("/",heart2)[0]-1]) {
            translate([i*thickness/14-(search("/",heart2)[0])*thickness/14/2,27,3])linear_extrude(2)text(font="cousine",heart2[i],thickness/10,$fn=50);
         }
         for(i=[search("/",heart2)[0]+1:1:len(heart2)]) {
            translate([(i-search("/",heart2)[0]-1)*thickness/14-(len(heart2)-search("/",heart2)[0]-1)*thickness/14/2,20,3])linear_extrude(2)text(font="cousine",heart2[i],thickness/10,$fn=50);
         }
      }
   }
   rotate([0,0,225]) {
      if(search("/",heart3)==[]) {
         //single line
         for(i=[0:1:len(heart3)]) {
            translate([i*thickness/14-len(heart3)*thickness/14/2,24,3])linear_extrude(2)text(font="cousine",heart3[i],thickness/10,$fn=50);
         }
      }
      else {
         //double line
         for(i=[0:1:search("/",heart3)[0]-1]) {
            translate([i*thickness/14-(search("/",heart3)[0])*thickness/14/2,27,3])linear_extrude(2)text(font="cousine",heart3[i],thickness/10,$fn=50);
         }
         for(i=[search("/",heart3)[0]+1:1:len(heart3)]) {
            translate([(i-search("/",heart3)[0]-1)*thickness/14-(len(heart3)-search("/",heart3)[0]-1)*thickness/14/2,20,3])linear_extrude(2)text(font="cousine",heart3[i],thickness/10,$fn=50);
         }
      }
   }
   rotate([0,0,315]) {
      if(search("/",heart4)==[]) {
         //single line
         for(i=[0:1:len(heart4)]) {
            translate([i*thickness/14-len(heart4)*thickness/14/2,24,3])linear_extrude(2)text(font="cousine",heart4[i],thickness/10,$fn=50);
         }
      }
      else {
         //double line
         for(i=[0:1:search("/",heart4)[0]-1]) {
            translate([i*thickness/14-(search("/",heart4)[0])*thickness/14/2,27,3])linear_extrude(2)text(font="cousine",heart4[i],thickness/10,$fn=50);
         }
         for(i=[search("/",heart4)[0]+1:1:len(heart4)]) {
            translate([(i-search("/",heart4)[0]-1)*thickness/14-(len(heart4)-search("/",heart4)[0]-1)*thickness/14/2,20,3])linear_extrude(2)text(font="cousine",heart4[i],thickness/10,$fn=50);
         }
      }
   }
}

difference() {
   for(i=[0:90:270]) {
      rotate([0,0,i])scale(2)heart();
   }
   heart_text();
}

```


[User]
I'd like to create a customizable 2D origami model of a retro rocket using OpenSCAD. I've seen a similar design, and I'd like to specify some key parameters.

The overall design should be based on a series of points that define an outer polygon and inner polygons. The coordinates for these points are provided in the original .scad file, and I can copy those over. The rocket shape is a bit complex, so the script will need to handle multiple polygons.

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

*   **`max_size_in_millimeter`**: The maximum dimension (either width or height) of the model. The shorter side should scale proportionally.
*   **`model_height_in_millimeter`**: The thickness of the extruded 2D shape.
*   **`outline_size_in_millimeter`**: The thickness of the outer outline.
*   **`inline_size_in_millimeter`**: The thickness of the inner outlines.
*   **`inline_edge_radius_in_millimeter`**: The rounding radius for the ends of the inner outlines.
*   **`flip_model`**: A toggle to flip the model along the vertical axis. I'd like to be able to choose "yes" or "no".

The script should scale the original coordinates to match `max_size_in_millimeter`, and extrude the shape by `model_height_in_millimeter`. The outer outline should be created by offsetting the main outer polygon, and the inner outlines should be created by offsetting the inner polygons using the provided inner edge radius, and then offset again to create the desired inner outline thickness. The inner polygons should be subtracted from the outer polygon to form the final shape.

I'm not sure if this is complex enough to use BOSL2, but I'd like to avoid using libraries unless necessary. Please provide an .scad file that implements this. Thanks!

[Assistant]
customizable_origami_retro_rocket.scad:
```
/*
 * Customizable Origami - Retro Rocket - https://www.thingiverse.com/thing:2782789
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-02-05
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

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

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.9; //[0.5:0.1:20]

// Thickness of the inner outline.
inline_size_in_millimeter = 0.8; //[0.5:0.1:20]

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.6; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [663, 15];
A2 = [799, 426];
A3 = [851, 615];
A4 = [883, 824];
A5 = [882, 1027];
A6 = [864, 1251];
A7 = [1258, 1514];
A8 = [1312, 1951];
A9 = [1027, 1742];
A10 = [794, 1724];
A11 = [765, 1800];
A12 = [712, 1813];
A13 = [651, 1817];
A14 = [600, 1812];
A15 = [555, 1800];
A16 = [525, 1725];
A17 = [278, 1748];
A18 = [39, 1951];
A19 = [78, 1517];
A20 = [438, 1250];
A21 = [426, 1030];
A22 = [435, 828];
A23 = [469, 624];
A24 = [521, 434];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24];

// Inner Points
B1 = [656, 421];
B2 = [655, 613];
B3 = [541, 618];
B4 = [572, 427];
B5 = [747, 422];
B6 = [788, 612];
B7 = [809, 826];
B8 = [820, 1027];
B9 = [655, 1026];
B10 = [653, 824];
B11 = [514, 827];
B12 = [511, 1028];
B13 = [515, 1252];
B14 = [809, 1251];
B15 = [660, 1255];
B16 = [655, 1727];
B17 = [131, 1525];
B18 = [1214, 1524];
B19 = [759, 1719];
B20 = [563, 1717];

// Polygons
C1 = [A24, A1, B4];
C2 = [B4, A1, B1];
C3 = [B1, A1, B5];
C4 = [B5, A1, A2];
C5 = [A24, A23, B3, B4];
C6 = [B1, B2, B6, B5];
C7 = [A3, A4, B7, B6];
C8 = [B2, B10, B11, B3];
C9 = [B11, B12, A21, A22];
C10 = [B10, B9, B8, B7];
C11 = [B9, B15, B13, B12];
C12 = [B8, B14, A6, A5];
C13 = [B15, B16, B20, B13];
C14 = [B15, B16, B19, B14];
C15 = [B13, B17, A19, A20];
C16 = [A19, A18, B17];
C17 = [B17, A17, A18];
C18 = [B17, B13, B20, A16, A17];
C19 = [B14, B18, A9, A10, B19];
C20 = [B14, A6, A7, B18];
C21 = [A7, A8, B18];
C22 = [B18, A8, A9];
C23 = [A16, A15, A14, B20];
C24 = [B20, B16, A13, A14];
C25 = [B16, B19, A12, A13];
C26 = [B19, A10, A11, A12];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, /*C15, C16,*/ C17, C18, C19, /*C20, C21,*/ C22, C23, C24, C25, C26];

min_x = A18[0];
min_y = A1[1];
max_x = A8[0];
max_y = A8[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
Hey, I'm looking to get some OpenSCAD files generated for a modular box system, specifically designed to hold a set of hexagonal tiles, like the ones used in the Palago board game. I've got a set of tiles I've been printing and want a configurable box to hold them, but the existing options aren't flexible enough for me.

Here's what I need:

1.  **Parametric Tile Configuration:** I need to be able to specify the total number of tiles, the height of each tile, and the radius of each tile (assuming they're regular hexagons). I also want to be able to specify how the tiles are arranged within the box, which I'll describe using a "configuration" parameter. The configuration could be:
    *   1: Solo (single hexagonal container)
    *   2: Duo (two hexagonal containers side-by-side)
    *   3: Tri (three hexagonal containers in a row)
    *   4: Quad (four hexagonal containers in a row)
    *   5: Pent (five hexagonal containers in a row)
    *   6: Hex (six hexagonal containers in a ring around a center container)
    *   7: Sept (seven hexagonal containers in a row)

2.  **Box and Lid:** For each configuration I need a box and a lid. I need to be able to select whether I want to generate both, just the box, or just the lid, using a "show" parameter:
    *   1: Both (generate both the box and the lid)
    *   2: Box (generate only the box)
    *   3: Lid (generate only the lid)

3.  **Tolerance and Wall Thickness:** I need to be able to control the tolerance (the amount of extra space added around the tiles for easier fit), and the wall thickness. Both of these should be input variables.

4.  **Modular Construction:** The box should consist of the configured number of individual tile containers, arranged according to the specified configuration, and a single matching lid. Each container should have walls on all sides. The lid should fit over the containers, with a small tolerance around the outside.

5.  **OpenSCAD Files:**
    * I don't need to control anything like file name or location; just need the code.
    * I need to be able to alter the tile radius, the tolerance, and the wall thickness through the use of input parameters.
    * I would prefer for the code to be as compact as possible.
    * It would be very convenient if all of the functions were contained in a single .scad file.

I think that's it for now. Could you generate the OpenSCAD file that would allow me to do this? I would prefer that you do not use any libraries.

[Assistant]
Palago_Box_And_Lid_v2.scad:
```
//Tiles Total
tiles = 90;
//Tile Height
t_height = 2.5;
//Tile Radius
t_rad = 20.25;
//Configuration [1:Solo,2:Duo,3:Tri,4:Quad,5:Pent,6:Hex,7:Sept]
config = 6;
//Show [1:Both,2:Box,3:Top]
show = 1;
tol = 1;
walls = 2;

//%import("tile_black.stl");
//%import("tile_white.stl");

if(config == 1){
    if(show == 1){
        SoloBox();
        translate([0,0,(t_height * ceil(tiles/config))- ((t_height * ceil(tiles/config))/4)]){
            SoloTop();
        }
    }
    if(show == 2){
        SoloBox();
    }
    if(show == 3){
        translate([0,0,walls+(t_height * ceil(tiles/config))/4]){
            rotate([180,0,0]){
                SoloTop();
            }
        }
    }
} else {
    if(config == 6){
        if(show == 1){
            HexBox();
            translate([0,0,(t_height * ceil(tiles/config))- ((t_height * ceil(tiles/config))/4)]){
                HexTop();
            }
        }
        if(show == 2){
            HexBox();
        }
        if(show == 3){
            translate([0,0,walls+(t_height * ceil(tiles/config))/4]){
                rotate([180,0,0]){
                    HexTop();
                }
            }
        }
    } else {
        if(show == 1){
            MultiBox();
            translate([0,0,(t_height * ceil(tiles/config))- ((t_height * ceil(tiles/config))/4)]){
                MultiTop();
            }
        }
        if(show == 2){
            MultiBox();
        }
        if(show == 3){
            translate([0,0,walls+(t_height * ceil(tiles/config))/4]){
                rotate([180,0,0]){
                    MultiTop();
                }
            }
        }
    }
}

module SoloTop(){
    difference(){
        translate([0,0,0]){
            linear_extrude(height = walls+(t_height * ceil(tiles/config))/4){
                circle(r = t_rad + (tol*2) + (walls*2),$fn = 6);
            }
        }
        translate([0,0,0]){
            linear_extrude(height = (t_height * ceil(tiles/config))/4){
                circle(r = t_rad + (tol*2) + walls,$fn = 6);
            }
        }
    }
}

module SoloBox(){
    translate([0,0,0]){
        difference(){
            linear_extrude(height = t_height * ceil(tiles/config)){
                circle(r = t_rad + tol + walls,$fn = 6);
            }
            translate([0,0,walls]){
                linear_extrude(height = t_height * ceil(tiles/config)){
                    circle(r = t_rad + tol,$fn = 6);
                }
            }
        }
    }
}

module MultiTop(){
    difference(){
        union(){
            translate([0,0,0]){
                linear_extrude(height = walls+(t_height * ceil(tiles/config))/4){
                    circle(r = t_rad + (tol*2) + (walls*2),$fn = 6);
                }
            }
            for(i = [0:(config-2)]){
                rotate([0,0,60 * i]){
                    translate([(t_rad + tol + (walls/2)) + (sin(360/12)*(t_rad + tol + (walls/2))),(cos(360/12)*(t_rad + tol + (walls/2))),0]){
                        linear_extrude(height = walls+(t_height * ceil(tiles/config))/4){
                            circle(r = t_rad + (tol*2) + (walls*2),$fn = 6);
                        }
                    }
                }
            }
        }
        union(){
            translate([0,0,0]){
                linear_extrude(height = (t_height * ceil(tiles/config))/4){
                    circle(r = t_rad + (tol*2) + walls,$fn = 6);
                }
            }
            for(i = [0:(config-2)]){
                rotate([0,0,60 * i]){
                    translate([(t_rad + tol + (walls/2)) + (sin(360/12)*(t_rad + tol + (walls/2))),(cos(360/12)*(t_rad + tol + (walls/2))),0]){
                        linear_extrude(height = (t_height * ceil(tiles/config))/4){
                        circle(r = t_rad + (tol*2) + walls,$fn = 6);
                        }
                    }
                }
            }
        }
    }
}

module MultiBox(){
    translate([0,0,0]){
        difference(){
            linear_extrude(height = t_height * ceil(tiles/config)){
                circle(r = t_rad + tol + walls,$fn = 6);
            }
            translate([0,0,walls]){
                linear_extrude(height = t_height * ceil(tiles/config)){
                    circle(r = t_rad + tol,$fn = 6);
                }
            }
        }
    }
    for(i = [0:(config-2)]){
        rotate([0,0,60 * i]){
            translate([(t_rad + tol + (walls/2)) + (sin(360/12)*(t_rad + tol + (walls/2))),(cos(360/12)*(t_rad + tol + (walls/2))),0]){
                difference(){
                    linear_extrude(height = t_height * ceil(tiles/config)){
                        circle(r = t_rad + tol + walls,$fn = 6);
                    }
                    translate([0,0,walls]){
                        linear_extrude(height = t_height * ceil(tiles/config)){
                            circle(r = t_rad + tol,$fn = 6);
                        }
                    }
                }
            }
        }
    }
}
module HexTop(){
    difference(){
        for(i = [0:(config-1)]){
            rotate([0,0,60 * i]){
                translate([(t_rad + tol + (walls/2)) + (sin(360/12)*(t_rad + tol + (walls/2))),(cos(360/12)*(t_rad + tol + (walls/2))),0]){
                    linear_extrude(height = walls+(t_height * ceil(tiles/config))/4){
                        circle(r = t_rad + (tol*2) + (walls*2),$fn = 6);
                    }
                }
            }
        }
        for(i = [0:(config-1)]){
            rotate([0,0,60 * i]){
                translate([(t_rad + tol + (walls/2)) + (sin(360/12)*(t_rad + tol + (walls/2))),(cos(360/12)*(t_rad + tol + (walls/2))),0]){
                    linear_extrude(height = (t_height * ceil(tiles/config))/4){
                    circle(r = t_rad + (tol*2) + walls,$fn = 6);
                    }
                }
            }
        }
    }
}

module HexBox(){
    for(i = [0:(config-1)]){
        rotate([0,0,60 * i]){
            translate([(t_rad + tol + (walls/2)) + (sin(360/12)*(t_rad + tol + (walls/2))),(cos(360/12)*(t_rad + tol + (walls/2))),0]){
                difference(){
                    linear_extrude(height = t_height * ceil(tiles/config)){
                        circle(r = t_rad + tol + walls,$fn = 6);
                    }
                    translate([0,0,walls]){
                        linear_extrude(height = t_height * ceil(tiles/config)){
                            circle(r = t_rad + tol,$fn = 6);
                        }
                    }
                }
            }
        }
    }
}
```


[User]
Hey there, I'm looking to design some replacement glass clamps for my Bibo 3D printer. I've got the basic idea and measurements, and I'm hoping you can help me generate a parametric OpenSCAD file, or maybe a few files, to make this work.

Essentially, it’s a clamp that holds the glass bed onto the aluminum heated bed. The clamps are mirror images of each other – I need both left and right versions. They'll need to have cutouts to accommodate the aluminum bed and the glass itself, plus a hole for a screw to attach it to the bed. I also want to include a little lip that goes over the edge of the glass to help hold it down and prevent any rocking.

Here's the breakdown of the parameters I'd like to be able to control:

*   **Overall Dimensions:** I need to be able to set the overall height, width, and length of the clamp.
*   **Aluminum Bed Cutout:** The clamp needs a cutout to fit around the aluminum bed. I'll need parameters for the X and Y position and the depth of this cutout. I would like to be able to add some slop to this so that if the cutout is slightly off it will still work.
*   **Screw Hole:** A hole is needed for a screw to attach the clamp to the aluminum bed, along with a countersink. Parameters for screw size, head size, countersink depth, and the X and Y offset of this hole are required.
*   **Glass Cutout:** The clamp needs a space for the glass bed to sit. Parameters for the X and Y dimensions of this are needed.
*   **Glass Lip:** I need a way to enable or disable a lip that holds the glass down, as well as set its X and Y dimensions.
*   **Plunger:** The clamp has a hole and depth adjustments for a spring loaded plunger, so I need to be able to set the X and Y position of this, as well as the screw size, washer diameter/thickness, spring diameter/length, and nut diameter/thickness for the plunger that goes into this hole.
*   **Text:** I'd also like to be able to write settings text and a version text onto the part and enable/disable these. I’d like to control the size and height of the text.

I'm thinking it might be helpful to have a separate module for the plunger, and maybe one for the version text.

I am not using any libraries right now, but if there is one that would help, please let me know. Thanks!

[Assistant]
GlassClamp3_lip.scad:
```
/**
 * Author: Randy Willard <Randyrw>
 * Description: Bibo Heated Bed Glass Holder
 * Date Created: 2/4/2018
 */
// All Default settings are the settings I am using on my Bibo printer
// Which is using original glass, aluminum plate and original glass holder parts(screws, nut, washer.
// It does not look like the holes in the aluminum plate are that accurate so you may need to play with the ScrewXPos and the ScrewYpos.   With the screw in and on the plate it should not wiggle much or at all. My right one does not wiggle at all and the left one wiggles less tha 1/32 inch.
// Too much play and the plunger screw will not be long enough to press against the glass to hold it down.
// I found if I have the screw too tight it may cause the glass to lift.
// 150  resolution lower number will compile quicker higher will probably better to a point
$fn=150;
Version="Clmp3 V2";  // Version will be written on Backside
//Is this the Left or Right Clamp?
LeftOrRight="Left";  //Left:Right
//Version
VersionTxt=str(LeftOrRight," ",Version);
font = "Liberation Sans";
//Settings
fonts="Basic";
letter_size = 3;
letter_height = .5;
//Debugging 0-NoBuild 1-Build Clamp
buildClamp=1;
//Numeric sizes are aproximately in mm, Overall clamp size
ClampHeight = 7.2; // [4:10]
ClampWidth = 33.5; // [4:40]
ClampLength = 30; // [4:40]
//aluminumn bed cutout Pos
AlumCutX=20; //[.5:4]
AlumCutY=15; //[.5:4]
//aluminumn bed cutout depth
AlumCutDepth=1.2; //[.5:4]
// Allow Alum Cornerslop
AlumSlopXY=5; //[.5:6]
//Screw Size to attach to bed
ScrewSize=3.5; // [2.5:5]
HeadSize=6.5;     //  [4:8]
CounterSinkDepth=1.5; //[.1:3]
//ScrewHole Offset X
ScrewXPos=2.5;   //[.1:10]
ScrewYPos=-2.5;   //[.1:10]
GlassThickness=3; //  [0:6]
//Glass Lip will help keep alum plate and glass together
//Use Glass Lip?   0-No or 1-Yes
GlassLip=1  ;     // [0:1]
//Lip to hold glass down
GlassLipX=3;      //[0:6]
GlassLipY=3;      //[0:6]
//CutOut for glass
GlassCutOutX=20;  //[5:30]
GlassCutOutY=8;   //[5:30]
//Plunger is the Screw,Washer,Spring and nut that press against glass to hold in place.
PlungerOffsetX=8;  //[6:15]
PlungerOffsetY=44;  //[30:50]
PlungerScrew=3;  //[2:5]
PlungerWasherDiameter=7.8;
PlungerWasherThick=1.3;
PlungerSpringDiameter=5.5;
PlungerSpringLength=8;
PlungerNutDiameter=5.1;
PlungerNutThick=2.5;
PlungerDepth=3.5;      //[.1:6]
PlungerDepthStep=.5;  //[.1:1]
//Write most Settings on top of clamp.
WriteSettings=1;  //0-No 1-Yes
//
if (LeftOrRight=="Right") {
    mirror([1,0,0]) {
    LClamp(1) ;
    }
} else {
    LClamp(1);
}
module LClamp(size) {
    if (buildClamp==1) {
        difference(){  //settings
        difference(){  //Version
        difference(){
        rotate(a=180,v=[1,0,0]){
        difference(){
        difference(){
        difference(){
        difference(){
        difference(){
            cube([ClampLength,ClampWidth,ClampHeight]); //MainPiece
            if (GlassLip==1 ){
                cube([GlassCutOutX,GlassCutOutY,GlassThickness+AlumCutDepth]);  //GlassCutOut
                cube([GlassCutOutX-GlassLipX,GlassCutOutY-GlassLipY,ClampHeight]);//GlassCutOutlip
            }else{
                cube([GlassCutOutX,GlassCutOutY,ClampHeight]);  //GlassCutOut
           //cube([GlassCutOutX-GlassLipX,GlassCutOutY-GlassLipY,ClampHeight]);  //GlassCutOut lip
            }
        }
        cube([AlumCutX,AlumCutY,AlumCutDepth]);  //AlumBedCutOut
        }
        translate([GlassCutOutX-ScrewXPos,10-ScrewYPos,0]) {
            cylinder(r=ScrewSize/2, h=ClampHeight,$fn=50);
            translate([0,0,ClampHeight-CounterSinkDepth]) {
                cylinder(r=HeadSize/2, h=CounterSinkDepth,$fn=50); //ScrewHole and countersink
            }
        }
        }
        translate([AlumCutX-AlumSlopXY/4,AlumCutY-AlumSlopXY/4,0]) {
            cylinder(r=AlumSlopXY/2, h=AlumCutDepth,$fn=50); //ScrewHole and countersink
        }
        }
        for (i = [0:PlungerDepthStep:PlungerDepth]) {
            translate([PlungerOffsetX,PlungerOffsetY,i]) {
                plunger(1) ;
            }
        }
        }
        }
        }
        writeVersion(1);
        }
        buildSettingsTxt(WriteSettings);
    }
    }
}  // end LClamp
module buildSettingsTxt(WriteSettings) {
   if (WriteSettings==1) {
    xx="x";
    letterdepth=.5;
    s=2.4 ; //size
    //wVx=6 ;
    if (LeftOrRight=="Left") {
        wVx=5;
        l=str("Clamp=",ClampHeight,xx,ClampWidth,xx,ClampLength );
        writeSettings(l,s,wVx,0,letterdepth);

        ll=str("AlumCut=",AlumCutX,xx,AlumCutY,xx,AlumCutDepth,xx,AlumSlopXY);
        writeSettings(ll,s,wVx,2,letterdepth);

        //lll=str("Screw=",ScrewSize,xx,HeadSize,xx,CounterSinkDepth,xx,ScrewXPos,xx,ScrewYPos);
        lll=str("Screw=",ScrewXPos,xx,ScrewYPos);
        writeSettings(lll,s,wVx,6,letterdepth);

        llll=str("GlassCut=",GlassCutOutX,xx,GlassCutOutY);
        writeSettings(llll,s,wVx,8,letterdepth);

        lllllll=str("Plngr3=",PlungerOffsetX,xx,PlungerOffsetY);
        writeSettings(lllllll,s,wVx,10,letterdepth);
        }
    if (LeftOrRight=="Right") {
    wVx=6;
    l=str("Clamp=",ClampHeight,xx,ClampWidth,xx,ClampLength );
    writeSettings(l,s,wVx,0,letterdepth);

    ll=str("AlumCut=",AlumCutX,xx,AlumCutY,xx,AlumCutDepth,xx,AlumSlopXY);
    writeSettings(ll,s,wVx,2,letterdepth);
    lll=str("Screw=",ScrewXPos,xx,ScrewYPos);
    writeSettings(lll,s,wVx,6,letterdepth);
    llll=str("GlassCut=",GlassCutOutX,xx,GlassCutOutY);
    writeSettings(llll,s,wVx,8,letterdepth);
    lllllll=str("Plngr3=",PlungerOffsetX,xx,PlungerOffsetY);
    writeSettings(lllllll,s,wVx,10,letterdepth);
    }
}
    }
module writeSettings(t,s,x,y,z){ // Write Settings on clamp
    //letter_height
    translate([ClampLength+.1-(s+(y*s)),(-AlumCutY*2)+x-8,-ClampHeight+z]) {
    rotate(a=180,v=[1,1,0]){
        Text(t,s);
    }
    }
}
module writeVersion(z){ //Write Version on Clamp
    //letter_height
    translate([ClampLength+.1-letter_height,-ClampWidth/2,-ClampHeight/2]) {
    rotate(a=270,v=[0,1,0]){
    rotate(a=180,v=[0,0,1]){
    rotate(a=180,v=[1,1,0]){
        Version(VersionTxt);
    }
    }
    }
    }
}
module plunger(Size) {
    PlungerDepth=15;
    rotate(a=90,v=[1,0,0]){
    cylinder(r=PlungerScrew/2,h=40); //plungerScrew
    translate([0,0,PlungerDepth]) {  //washer
    cylinder(r=PlungerWasherDiameter/2,h=PlungerWasherThick);
    }
    translate([0,0,PlungerDepth+PlungerWasherThick]) {  //spring
    cylinder(r=PlungerSpringDiameter/2,h=PlungerSpringLength);
    }
    translate([0,0,PlungerDepth+PlungerWasherThick+PlungerSpringLength]) {
    hexagon(PlungerNutDiameter, PlungerNutThick);
    }
    }
}
// size is the XY plane size, height in Z
module hexagon(size, height) {
  boxWidth = size/1.75;
  for (r = [-60, 0, 60]) rotate([0,0,r]) cube([boxWidth, size, height], true);
}
module Version(l) {  //Display Version Center
	linear_extrude(height = letter_height) {
             if (LeftOrRight=="Right") {
            mirror([1,0,0]) {
		text(l, size = letter_size, font = font, halign = "center", valign = "center", $fn = 16);
            }} else {
        text(l, size = letter_size, font = font, halign = "center", valign = "center", $fn = 16);
            }
        }
}
module Text(l,size) {  //Used to Display Settings
	linear_extrude(height = letter_height) {
        if (LeftOrRight=="Right") {
            mirror([1,0,0]) {
                text(l, size, font = fonts, halign = "right", valign = "top", $fn = 16);
            }
        } else {
            text(l, size, font = fonts, halign = "left", valign = "top", $fn = 16);
        }
    }
}
```