[User]
I'd like to design a plant marker that I can customize. I want to be able to change the text on the marker, the font, the overall thickness, the height of the text extrusion, the length and width of the marker, and the font size.

Specifically, the marker should have a rectangular base with a triangular stake at one end. The text should be extruded on top of the rectangular base. The triangular stake is extruded at a lower height than the text, so it's flush with the top of the rectangular base under the text extrusion.

The parameters I need to control are:

*   `plantname`: The text to be displayed on the marker.
*   `fontname`: The font to use for the text. I want the full selection of fonts available within OpenSCAD's text module.
*   `thickness`: The total thickness of the marker, including the text.
*   `text_extrude`: The height the text is extruded above the base.
*   `length`: The total length of the rectangular base (not including the stake.)
*   `fontsize`: The height of the font characters.
*  `width`: The width of the rectangular base (and the triangular stake).

I'd like the overall design to be pretty similar to the example I'm providing. The important part for me is getting all of the parameters customizable. I also need a single .scad file that includes all of the code needed to generate the marker - I don't want any libraries beyond what is built-in to OpenSCAD.

[Assistant]
plantmarkers.scad:
```
/*
* Name: PlantMarkers.scad
* Author: Michael Kruger
* Brief:
*
* This SCAD file can be used to generate plant markers
* This file can be used in the MakerBot Customizer
*
* License: MIT License
*
* Copyright (c) 2020 Michael Kruger, Krugaroo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
 V1.0 First Version
*/

//Text on Label
plantname = "Yolo Wonder";

// Font to use
fontname="Play"; //[Abril Fatface,Aclonica,Acme,Advent Pro,Akronim,Aladin,Alegreya,Alegreya Sans,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Amaranth,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arvo,Asap,Astloch,Asul,Averia Libre,Averia Serif Libre,Bangers,Basic,Belgrano,Berkshire Swash,Bigshot One,Bilbo Swash Caps,Black Ops One,Bonbon,Bowlby One SC,Brawler,Bubblegum Sans,Butterfly Kids,Cabin Condensed,Caesar Dressing,Cagliostro,Calligraffitti,Capriola,Carter One,Changa One,Chango,Chelsea Market,Cherry Cream Soda,Chewy,Chicle,Chivo,Clicker Script,Coming Soon,Concert One,Condiment,Cookie,Courgette,Covered By Your Grace,Crimson Text,Dancing Script,DejaVu Sans,DejaVu Serif,Dhurjati,Doppio One,Dosis,Droid Sans,Eagle Lake,Electrolize,Emilys Candy,Encode Sans,Encode Sans Compressed,Euphoria Script,Exo,Exo 2,Faster One,Federo,Finger Paint,Fjord One,Fontdiner Swanky,Freckle Face,Fruktur,Gabriela,Geo,Germania One,Give You Glory,Gloria Hallelujah,Goudy Bookletter 1911,Graduate,Grand Hotel,Great Vibes,Griffy,Hanalei Fill,Happy Monkey,Henny Penny,Hind,IM Fell English SC,Indie Flower,Irish Grover,Italianno,Jacques Francois Shadow,Jolly Lodger,Josefin Slab,Joti One,Judson,Just Another Hand,Kalam,Kameron,Karma,Kavoon,Knewave,Kranky,Kristi,Laila,Lakki Reddy,Lancelot,Lato,Leckerli One,Ledger,Lekton,Lemon One,Liberation Sans,Libre Caslon Text,Life Savers,Lilita One,Lily Script One,Limelight,Lobster,Lobster Two,Londrina Outline,Londrina Shadow,Londrina Solid,Lora,Love Ya Like A Sister,Loved by the King,Lovers Quarrel,Luckiest Guy,Lusitana,Macondo,Macondo Swash Caps,Mako,Marck Script,Margarine,Marko One,Maven Pro,McLaren,MedievalSharp,Merienda One,Merriweather,Mervale Script,Metal Mania,Metrophobic,Milonga,Miltonian Tattoo,Miss Fajardose,Molle,Montez,Montserrat,Mr De Haviland,Mystery Quest,Neucha,New Rocker,Niconne,Nosifer,Nothing You Could Do,Noto Sans Oriya,Noto Serif,Nova Square,Nunito,Old Standard TT,Oleo Script,Oleo Script Swash Caps,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Over the Rainbow,Overlock,Oxygen,Pacifico,Paprika,Parisienne,Patrick Hand SC,Paytone One,Peralta,Permanent Marker,Piedra,Pirata One,Play,Playball,Poetsen One,Poppins,Press Start 2P,Princess Sofia,PT Mono,Qwigley,Racing Sans One,Raleway,Rancho,Ranga,Ribeye,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rubik One,Sail,Salsa,Sansita One,Sarina,Satisfy,Schoolbell,Seaweed Script,Sevillana,Shadows Into Light,Shadows Into Light Two,Share,Six Caps,Skranji,Source Sans Pro,Spicy Rice,Stardos Stencil,Stoke,Syncopate,Teko,Terminal Dosis,The Girl Next Door,Tillana,Timmana,Titillium Web,Ubuntu,Ultra,Underdog,UnifrakturCook,UnifrakturMaguntia,Vampiro One,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,Waiting for the Sunrise,Wallpoet,Wellfleet,Wendy One,Yellowtail,Yesteryear,Zeyada]

// Thickness of the marker including text [mm]
thickness = 6;
// Extrude Height of text [mm]
text_extrude = 3;
// Height of marker [mm]
length = 80;
// Height of font [mm]
fontsize = 9;
// Width of the marker [mm]
width = 14;

// Text
translate([1,(width-fontsize)/2,0]){
    linear_extrude(height = thickness) {
        text(text=plantname,font=fontname,size=fontsize);
    }
}

// Label Bar
cube([length,width,thickness-text_extrude]);

// Triangle
translate([length,0,0]){
    linear_extrude(height = thickness-text_extrude) {
        polygon(points=[[0,0],[20,width/2],[0,width]], paths=[[0,1,2]]);
    }
}
```


[User]
Hey, I need an OpenSCAD design for a bread slicing guide. I've got some pretty specific requirements.

First off, it needs to be parametric, so I can easily adjust it for different loaf sizes and slice thicknesses. I need to define the following parameters:

*   `LoafWidth`: The maximum width of the bread loaf.
*   `LoafHeight`: The maximum height of the bread loaf.
*   `SliceWidth`: The desired width of a single bread slice.
*   `SliceCount`: The number of slices I want the guide to produce.
*   `WallThickness`: The thickness of the guide walls.
*   `FloorHeight`: The minimum height of the guide floor.
*   `KnifeSlotWidth`: The width of the slots for the knife.
*   `OvercutChannelDepth`: How deep the knife slot extends below the floor.
*   `SlotSupports`: A boolean to enable or disable slot supports.
*   `SlotSupportWidth`: The width of the slot supports.
*   `SlotSupportSpacing`: The space between slot supports.

The basic structure is going to be a box with vertical slots for the knife. The first slot should act as a full vertical guide, and each successive slot should have a base that the loaf can rest on. The slots should be rounded at the top. The very first vertical guide needs a horizontal "shelf" to hold the bread. It should also have channels beneath the floor of the bread to allow the knife to fully slice through.

Also, the supports for the knife slots should be optional and also parametric. The support should extend from the back of the slots to both side walls.

The design should also include an assertion that the `SliceWidth` must be greater than `KnifeSlotWidth`, this just to avoid nonsense.

Let me know if you need anything clarified!

[Assistant]
BreadSlicer.scad:
```
/*[Bread Settings]*/
//The maximum width of a bread loaf to slice in this guide
LoafWidth = 140; //[0:1:500]

//The maximum height of bread to slice in this guide
LoafHeight = 140; //[0:1:500]

//The desired width in mm of a bread slice for this guide
SliceWidth = 16; //[0:0.125:100]

//The maximum width of a bread loaf to slice in this guide
SliceCount = 8; //[0:1:50]

/*[Guide Settings]*/

//The width of the guide walls in mm
WallThickness=3;//[0:0.125:20]

//The minimum height of the guide floor in mm
FloorHeight=5;//[0:0.125:20]

//The width of the knife slots in mm.
KnifeSlotWidth=3; //[0:0.125:20]

//The depth of a channel in mm below the bread into which the knife can over cut
OvercutChannelDepth = 3; //[0:0.125:20]

//Whether to print breakaway supports for your slots
SlotSupports = true;

//The width in mm of slot supports
SlotSupportWidth = .5; //[0:0.125:3]

//The space in mm between slot supports
SlotSupportSpacing = 10; //[0:1:100]

IsSlotWidthOk = assert(KnifeSlotWidth<SliceWidth,"SliceWidth must exceed KnifeSlotWidth");

OuterWidth = LoafWidth+2*WallThickness;
MaxFloorHeight = FloorHeight +  OvercutChannelDepth;
MinFloorHeight = FloorHeight;
SliceGuideWidth = SliceWidth - KnifeSlotWidth;
FilletRadius = SliceGuideWidth / 2;
OuterHeight = LoafHeight + MaxFloorHeight + FilletRadius;

//First slice Back Wall
cube([OuterWidth,WallThickness,OuterHeight]);

//First slice Right Wall
translate([0,WallThickness,0])cube([WallThickness,FilletRadius+KnifeSlotWidth/2,OuterHeight]);
translate([0,WallThickness+FilletRadius+KnifeSlotWidth/2,0])cube([WallThickness,FilletRadius,OuterHeight-FilletRadius]);
translate([0,WallThickness+FilletRadius+KnifeSlotWidth/2,OuterHeight-FilletRadius])rotate([0,90,0])cylinder(WallThickness,FilletRadius,FilletRadius);

//First slice Left Wall
translate([OuterWidth-WallThickness,WallThickness,0])cube([WallThickness,FilletRadius+KnifeSlotWidth/2,OuterHeight]);
translate([OuterWidth-WallThickness,WallThickness+FilletRadius+KnifeSlotWidth/2,0])cube([WallThickness,FilletRadius,OuterHeight-FilletRadius]);
translate([OuterWidth-WallThickness,WallThickness+FilletRadius+KnifeSlotWidth/2,OuterHeight-FilletRadius])rotate([0,90,0])cylinder(WallThickness,FilletRadius,FilletRadius);

//First slice Floor
translate([WallThickness,WallThickness,0])cube([LoafWidth,SliceWidth - KnifeSlotWidth/2,MaxFloorHeight]);

NextSliceYOffset = WallThickness + SliceGuideWidth + KnifeSlotWidth/2;
for(i=[0:SliceCount-2]) {
    CurrentSliceYOffset = i*SliceWidth + NextSliceYOffset;
    //Slice Channel Floor
    translate([0,CurrentSliceYOffset,0])cube([OuterWidth,KnifeSlotWidth,MinFloorHeight]);

    //Slice Floor
    translate([WallThickness,CurrentSliceYOffset+KnifeSlotWidth,0])cube([LoafWidth,SliceGuideWidth,MaxFloorHeight]);

    //Slice right wall
    translate([0,CurrentSliceYOffset+KnifeSlotWidth,0])cube([WallThickness,SliceGuideWidth,OuterHeight-FilletRadius]);
    translate([0,CurrentSliceYOffset+KnifeSlotWidth+FilletRadius,OuterHeight-FilletRadius])rotate([0,90,0])cylinder(WallThickness,FilletRadius,FilletRadius);

    //Slice left wall
    translate([OuterWidth-WallThickness,CurrentSliceYOffset+KnifeSlotWidth,0])cube([WallThickness,SliceGuideWidth,OuterHeight-FilletRadius]);
    translate([OuterWidth-WallThickness,CurrentSliceYOffset+KnifeSlotWidth+FilletRadius,OuterHeight-FilletRadius])rotate([0,90,0])cylinder(WallThickness,FilletRadius,FilletRadius);

    //Slot supports
    if(SlotSupports) {
        for (SlotSupportOffset=[MinFloorHeight+SlotSupportSpacing+SlotSupportWidth:SlotSupportSpacing+SlotSupportWidth:OuterHeight-FilletRadius-MinFloorHeight-SlotSupportWidth]){
            translate([0,CurrentSliceYOffset,SlotSupportOffset])cube([WallThickness,KnifeSlotWidth,SlotSupportWidth]);
            translate([OuterWidth-WallThickness,CurrentSliceYOffset,SlotSupportOffset])cube([WallThickness,KnifeSlotWidth,SlotSupportWidth]);
        }
    }
}

```


[User]
I'd like to create a parametric measuring cylinder using OpenSCAD. I need it to have a few key features: a spout (or "beak"), a handle, and an optional stand. I also want it to be able to display multiple measurement scales, like milliliters and fluid ounces.

Here are the details:

**Overall Dimensions:**

*   **Volume:** I need to be able to specify the target volume in milliliters. Let's say I want to be able to set a variable called `volume` that defaults to 100ml, but can be set anywhere between 10 and 2000 ml.
*   **Radius:** The radius of the cylinder (not including the wall thickness) should also be a variable called `radius`, defaulting to 18mm, and adjustable between 5mm and 75mm.
*   **Wall Thickness:**  I need a variable called `thickness` to control the thickness of the cylinder walls, which should default to 1.6mm and be adjustable from 0.5mm to 5mm in 0.1mm increments.

**Beak/Spout:**

*   **Length:**  The length of the beak from the edge of the cylinder should be controlled by `beak_length` defaulting to 15mm, and adjustable between 5 and 50mm.
*   **Angle:** The beak needs to be an angled portion of the cylinder and the angle of the beak relative to the cylinder, controlled by variable called `beak_angle` that defaults to 45 degrees and is adjustable between 1 degree and 45 in 0.1 degree increments.

**Stand (Optional):**

*   **Radius:** The radius of the stand needs to be a variable called `stand`, representing the amount of the increase in radius at the base. The default is 20mm and must be adjustable between 0mm and 30mm.
*   **Height:**  The height of the stand, called `stand_height`, which can be set to 0 to remove it entirely. Let's set the default to 0mm and allow it to be changed to between 0 and 30mm.

**Measurements & Text:**

*   **Font Size:** The font size for text labels is controlled by `font_size`, with a default of 5mm, adjustable from 2mm to 10mm in 0.1mm increments.
*   **Scale Thickness:** The thickness of the lines representing the measurement ticks is specified by `scale_thickness`, defaulting to 1mm, and adjustable from 0.5mm to 3mm in 0.05mm increments.
*   **Maximum Tick Angle:** The maximum angle from the center of the cylinder that the tick marks reach, with a variable named `scale_maxangle` with a default of 45 degrees, adjustable between 10 and 90 degrees.
*   **Multiple Units:** I need to be able to specify multiple units of measurement. For example, ml, and fl oz(us). The names of the units can be specified as a comma separated list named `units` (e.g. "ml,floz(us)").
*   **Conversion Factor:** There should be a variable named `conversion_factor` that specifies a conversion factor for each unit, expressed as an array (e.g. `[1, 4.92892159375]`). The conversion factor should represent how much volume the smallest tick represents in the respective unit.
*   **Tick Relations:** A variable named `tick_relations`, which is an array of arrays, each element specifying how ticks relate to each other, representing a volume, where the lowest index is the smallest increment in that unit (e.g. `[[1, 5, 2, 5, 2], [1, 3, 2, 4]]` would represent, 1ml, 5ml, 10ml, 50ml, 100ml and for fluid ounces, teaspoon, tablespoon, fluid ounce and a gill.)
*   **Unit Tick:**  A variable named `tick_representing_unit` specifying which index in the `tick_relations` array represents a unit (e.g. `[-1, 2]` means the -1th, 1 ml, or smallest element in the first array and the 2nd, fluid ounce, of the second array, is the unit.
*   **Label Start:**  A variable named `tick_labels_start_at`, indicating which ticks should be labeled starting at 0, (e.g. `[2, 1]`).

**Handle:**

*   **Handle Thickness:** The thickness of the handle is specified by `handle_thickness` with a default value of 10, and must be adjustable from 5 to 20mm in 0.1mm increments.
*   **Handle Distance:** The distance the handle is from the edge of the measuring cylinder, set by variable `handle_distance`, defaulting to 20mm, and must be adjustable from 10 to 50mm.
*   **Handle Size:** the relative size of the handle along the z axis compared to the height of the measuring cylinder, controlled by the variable `handle_size`, set to 0.5, adjustable from 0.3 to 1 in 0.01 increments.
*  **Handle Angle:**  Angle at which the handle comes out from the side of the cylinder, controlled by the variable `handle_angle`, with default 60 degrees, adjustable from 30 to 90 degrees.

The code should be fully parametric, using variables to allow for easy customization of all dimensions. Also please use `$fn = 100` to increase the smoothness of the design. I'm not asking to use any libraries.

I think that covers everything. Let me know if you need any clarification.

[Assistant]
measuring_cylinder_v2.scad:
```
/* [dimensions] */
// Volume in ml
volume = 100; // [10:2000]
// Radius in mm, when changing it it may be necessary to adjust the tick labels or distances
radius = 18; // [5:75]
// Shell Thickness in mm
thickness = 1.6; // [0.5:0.1:5]
// Length of the beak in  mm
beak_length = 15; // [5:50]
// Broadness of the beak as angle of the whole circle
beak_angle = 45; // [1:0.1:45]
// Radius that is added to the base radius for the stand
stand = 20; // [0:30]
// Height of the stand in mm, set to 0 to remove
stand_heigth = 0; // [0:30]
// Font size in mm
font_size = 5; // [2:0.1:10]
// Scale Thickness in mm
scale_thickness = 1; // [0.5:0.05:3]
// Maximum angle for the tick representing the biggest number
scale_maxangle = 45; // [10:90]

handle_thickness = 10; // [5:0.1:20]
handle_distance = 20;  // [10:50]
handle_size = 0.5;     // [0.3:0.01:1]
handle_angle = 60;     // [30:90]

/* [measurement units] */
// Names of used units, separated by comma
units = "ml";
// Conversion factor for the smallest increment of volume
conversion_factor = [1];
// relation between the volume represented by a tick and the next one
tick_relations = [[ 1, 5, 2, 5, 2 ]];
// which of the ticks represent the unit, counting from 0, -1 if it is the base conversion factor
tick_representing_unit = [-1];
// the first tick that gets labeled, counting from 0
tick_labels_start_at = [2];

$fn = 100 * 1;
circle_area = pow(radius - thickness, 2) * PI;
height = volume * 1000 / circle_area;
splitunits = split(units);

beak_full_length = beak_length + thickness + radius * sin(beak_angle) / 2;
beak_diameter1 = radius * sin(beak_angle) * 2 + thickness * 2;
beak_diameter2 = thickness * (2 + beak_diameter1 / beak_full_length);
beak_position = -sqrt(pow(radius, 2) - pow(beak_diameter1 / 2, 2));
total_height = height +
               max(font_size * 1.5,
                   beak_diameter1 / 2 - (radius + beak_position) *
                                            (beak_diameter1 - beak_diameter2) /
                                            (2 * beak_full_length)) +
               scale_thickness * 1.5 + thickness;

translate([ 0, 0, stand_heigth ])
{
    difference()
    {
        union()
        {
            cylinder(r = radius, h = total_height);
            translate([ beak_position, 0, total_height ]) beak();
            handle();
        }
        translate([ 0, 0, thickness ])
            cylinder(r = radius - thickness, h = total_height);
        translate([ beak_position + thickness, 0, total_height - 0.01 ])
            rotate([ 0, -90, 0 ]) cylinder(
                d1 = beak_diameter1 -
                     thickness * (1 + beak_diameter1 / beak_full_length),
                d2 = thickness,
                h = beak_full_length + thickness + 0.02);
    }
    ticks();
}
stand();

module
ticks()
{
    for (u = [0:len(splitunits) - 1]) {
        ticks = tick_relations[u];
        unit_divisor = multipy_elements(ticks, tick_representing_unit[u]);
        rotate(360 * u / len(splitunits) + 180)
        {
            for (i = [1:volume / (conversion_factor[u] * ticks[0])]) {
                tick_volume = i * conversion_factor[u] * ticks[0];
                biggest_modulo = get_biggest_modulo(i, ticks, 1);
                tick_pos_z = tick_volume * 1000 / circle_area;
                translate([ 0, 0, tick_pos_z + thickness ])
                    tick(len(ticks), biggest_modulo + 1);
                if (biggest_modulo >= tick_labels_start_at[u]) {
                    translate([ 0, 0, tick_pos_z + thickness - font_size / 2 ])
                        textOnCylinder(str(
                            round(i * ticks[0] * 1000 / unit_divisor) / 1000));
                }
            }
            translate([ 0, 0, height + scale_thickness + font_size / 2 ])
                rotate(-scale_maxangle / 2 -
                       font_size / radius * 30 * len(splitunits[u]))
                    textOnCylinder(splitunits[u]);
        }
    }
}

module tick(max_mod, biggest_modulo)
{
    intersection()
    {
        difference()
        {
            union()
            {
                translate([ 0, 0, -scale_thickness / 2 ])
                    cylinder(r1 = radius,
                             r2 = radius + scale_thickness,
                             h = scale_thickness / 2);
                cylinder(r1 = radius + scale_thickness,
                         ,
                         r2 = radius,
                         h = scale_thickness / 2);
            }
            cylinder(r = radius - thickness / 2,
                     h = scale_thickness + 0.1,
                     center = true);
        }
        x = sin(scale_maxangle * biggest_modulo / max_mod) * radius +
            scale_thickness;
        y = cos(scale_maxangle * biggest_modulo / max_mod) * radius +
            scale_thickness;
        linear_extrude(scale_thickness + 0.1, center = true) polygon(points = [
            [ 0, 0 ],
            [ 0, radius + scale_thickness ],
            [ x / 2, (radius + scale_thickness + y) / 2 ] * 2,
            [ x, y ]
        ]);
    }
}

module textOnCylinder(t)
{
    for (l = [0:len(t) - 1]) {
        rotate([ 0, 0, font_size / radius * l * 60 + font_size * 2 ]) translate(
            [ font_size / 2, radius - scale_thickness / 2 - thickness / 2, 0 ])
            rotate([ 90, 0, 180 ])
                linear_extrude(scale_thickness + thickness / 2)
                    text(t[l], size = font_size);
    }
}

module
beak()
{
    rotate([ 0, -90, 0 ]) difference()
    {
        cylinder(
            d1 = beak_diameter1, d2 = beak_diameter2, h = beak_full_length);
        translate([ 0, -beak_diameter1 / 2 - 1, -1 ])
            cube([ beak_diameter1, beak_diameter1 + 2, beak_full_length + 2 ]);
    }
}

module
stand()
{
    difference()
    {
        cylinder(h = stand_heigth, r1 = radius + stand, r2 = radius);
        translate([ 0, 0, -0.01 ]) cylinder(
            h = stand_heigth - thickness,
            r1 = radius + stand -
                 (1 + stand / (2 * (stand_heigth + thickness))) * thickness,
            r2 = radius -
                 (1 + stand / (2 * (stand_heigth + thickness))) * thickness);
    }
}

module
handle()
{
    a = handle_distance / tan(handle_angle);
    l = handle_distance * cos(handle_angle);
    translate([
        radius + handle_distance,
        0,
        (total_height - height * handle_size) / 2 +
        a
    ])
    {
        cylinder(d = handle_thickness, h = height * handle_size - 2 * a);
        rotate([ 0, 180 + handle_angle, 0 ])
            cylinder(d = handle_thickness, h = handle_distance + l);
        sphere(r = handle_thickness / 2);
        translate([ 0, 0, height * handle_size - 2 * a ])
        {
            rotate([ 0, -handle_angle, 0 ])
                cylinder(d = handle_thickness, h = handle_distance + l);
            sphere(r = handle_thickness / 2);
        }
    }
}

function get_biggest_modulo(number, vector, startindex) =
    number % vector[startindex] == 0
        ? (startindex >= (len(vector) - 1)
               ? startindex
               : get_biggest_modulo(number / vector[startindex],
                                    vector,
                                    startindex + 1))
        : startindex - 1;

function multipy_elements(vector, endindex) =
    endindex < 0 ? 1
                 : vector[endindex] * multipy_elements(vector, endindex - 1);

function split(string) = let(
    positions = concat([-1], search(",", string, 0)[0], [len(string)]))[for (
    i = [0:len(positions) -
           2])[for (j = [positions[i] + 1:positions[i + 1] - 1]) string[j]]];
```


[User]
I'm looking to create a customizable tent peg design using OpenSCAD. I need a design that's parametric so I can easily adjust its dimensions and features.

Here's what I have in mind:

**General Structure:**

*   The main body of the peg should be a relatively simple, extruded shape.
*   The peg should have angled barbs along its length to improve grip in the ground.
*   The overall height of the peg, the number of barbs, and barb dimensions should all be adjustable parameters.
*   The thickness of the peg's body should also be parametric.

**Specific Features:**

1.  **Barbs:**
    *   I want to be able to control the number of barbs.
    *   Each barb should be a triangular shape, projecting outwards from the main body.
    *   The width of the barbs should be a parameter.
    *   The vertical spacing between barbs should be uniform and depend on the total height of the spike.
    *   I'd like a second set of smaller barbs at 90 degrees from the main barbs; the size should be proportional to the main barb width.
2.  **Hammer End:**
    *   I need an optional hammer end.
    *   When activated, it should create a flattened, circular head at the top of the peg, larger than the body of the peg for hammering purposes.
    *   The diameter of the hammer end should be a proportion of the barb width.
    *   This should be an optional feature.
3.  **Pipe Hook:**
    *   I'd also like the option to add a hook for holding down water pipes or similar.
    *   I should be able to specify the diameter of the pipe that the hook is meant to hold.
    *   The hook should be positioned close to the top of the peg body (below the hammer head, if present).
    *   I'd like to be able to create one hook or two opposing hooks.
    *   Hook shape should be a simple extrusion forming a partial circle.
    *   The hook wall thickness at its thinnest should be adjustable.
    *   The hook should also be an optional feature.

**Parameters I'd like to control:**

*   `barbsNo`: Number of side barbs.
*   `barbWidth`: Width of the main barbs.
*   `spikeHeight`: Full height of the spike (without hammer end).
*   `thickness`: Body thickness.
*   `hookThickness`: Thickness of the pipe hook at its thinnest point.
*   `hasHammerEnd`: Boolean to enable/disable the hammer end.
*    `hasPipeHook`: Boolean to enable/disable a single pipe hook.
*    `hasDoublePipeHook`: Boolean to enable/disable two opposing pipe hooks.
*   `pipeDiameter`: Diameter of the pipe for the hook.
*   `XvsY` A ratio between the perpendicular barb height and the lateral barb height.
*   `endScale` A value to scale the size of the hammer end head

I'm envisioning this as a single file, or perhaps a few small files if that makes sense. It looks like `linear_extrude` and `polygon` will be needed in addition to `difference`, `union`, `rotate`, `translate`, `circle`, `square` and a `for` loop.

[Assistant]
spike.v2.scad:
```
//number of side barbs
barbsNo = 3;
//barb width in mm
barbWidth = 20;      //mm
//full height of the spike (without hammer end) in mm
spikeHeight = 150;  //mm

//body thickness in mm
thickness = 5;    //mm
// hook wall thickness (at thinnest) in mm
hookThickness= 3; //mm

//generate the hammer end
hasHammerEnd = true;
//generate one pipe hook
hasPipeHook = false;
//generate two pipe hooks
hasDoublePipeHook = false;
//pipe diameter in mm
pipeDiameter = 16;

 // end of user modifiable settings
//perpendicular barb height vs lateral
XvsY = 0.6;
//scale of the hammer end
endScale = 0.8;
spikeH = spikeHeight/barbsNo;
vBarbs = barbsNo+1;
vBarbH = spikeHeight/vBarbs;
union () {
    drawBarbs ();
    if (hasHammerEnd) drawHammerEnd();
    if (hasPipeHook) drawPipeHook(pipeDiameter);
    if (hasDoublePipeHook) {
        drawPipeHook(pipeDiameter);
        rotate([0,180,0])
        drawPipeHook(pipeDiameter);
    }
}

module iTriangle(h,b,x=0,y=0,rotation=0,thickness = 3) {
    linear_extrude (height = thickness, center = true)
    rotate(rotation)
    polygon(points= [[x-b/2,y],[x+b/2,y],[x,y+h],[x-b/2,y]]);
}

module rTriangle (h,b,x=0,y=0,rotation=0,thickness = 3) {
    linear_extrude (height = thickness, center = true)
    rotate(rotation)
    polygon(points = [[x,y],[x+b,y],[x,y+h],[x,y]]);
}

module drawBarbs () {
    for ( i = [1:barbsNo]) {

        iTriangle(i*spikeH,barbWidth,0,spikeH*barbsNo - i*spikeH,0,thickness);
    };
    linear_extrude (height = thickness, center = true)
    polygon(points= [[-thickness/2,0],[-thickness/2,spikeH*barbsNo],[thickness/2,spikeH*barbsNo],[thickness/2,0]]);
    rotate([0,-90,0])

    for ( i = [1:vBarbs]) {
        rTriangle(i*vBarbH,barbWidth*XvsY,-thickness/2,vBarbH*vBarbs - i*vBarbH,0,thickness);
    }
}
module drawHammerEnd() {
    cubeSize = spikeH;
    difference(){
        rotate ([90,0,0])
        linear_extrude (height = thickness, center = false)
        scale ([endScale,endScale,1])
        circle(barbWidth);
            translate([0,0,-cubeSize-thickness/2])
           linear_extrude( height = cubeSize, center=false)
            square (cubeSize,true);
    }
}
module drawPipeHook(diam=16){
    difference() {

        baseW = barbWidth/2+diam+hookThickness;
        baseH = diam/2 + hookThickness*2;
        linear_extrude (height = thickness, center = true)
        polygon(points= [[0,0],[baseW,0],[baseW,baseH],[0,baseH]]);
            linear_extrude (height = thickness+1, center = true)
            translate ([diam/2+barbWidth/2,baseH-hookThickness])
            circle(d = diam);
    }
}
```


[User]
Hey, I'm looking to design a parametric filament spool holder that I can mount inside my IKEA STUVA cabinet. I want it to hold a standard 1kg filament spool using 608 bearings and be fairly rigid. I've seen some designs that press together, and that seems to work pretty well.

The holder should consist of two side supports that attach to the cabinet and four cradle pieces that hold the spool. I'd also like to include a filament guide that attaches to the side support.

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

*   **`mount_hole_pitch_z`**: Vertical distance between mounting holes on the side support (default 32mm).
*   **`mount_hole_number_z`**: Number of mounting holes on the side support vertically (default 4).
*   **`mount_hole_pitch_y`**: Horizontal distance between mounting holes on the side support (180 for STUVA front, 224 for STUVA rear).
*   **`backplate_x`**: Thickness of the side support backplate (default 3mm).
*  **`support_y`**: Thickness of the side support beams (default 10mm).
*  **`screw_hole_diameter`**: Diameter of the screw holes (default 4mm).
*   **`screw_head_diameter`**: Diameter of the screw head (default 6mm).
*   **`top_beam_x`**: Length of the top beam on the side support (default 90mm).
*   **`cradle_fatness`**: Thickness of the cradle pieces (default 3.5mm).
*   **`inter_bearing_y`**: Distance between the two bearing mounts on a cradle piece (default 120mm).
*   **`filament_guide_hole_number_z`**: Number of vertical mounting holes on the filament guide (default 3).
*   **`filament_spool_diameter`**: Diameter of the filament spool itself. Should be a hidden parameter and defaulted to 200mm.
*   **`bearing_inner_diameter`**: Inner diameter of the bearing. Should be a hidden parameter and defaulted to 8mm.
*   **`bearing_outer_diameter`**: Outer diameter of the bearing. Should be a hidden parameter and defaulted to 22mm.
*    **`bearing_x`**: Width of the bearing. Should be a hidden parameter and defaulted to 7mm.
*   **`render_quality`**: Variable used to control the `$fn` parameter for increased quality on renders (default 60, range 1-120).
*   **`part`**: Variable used to specify which pieces to render ( "All", "Side support only", "Cradle piece only", "Filament guide only").

I think that covers most of the core requirements. I'd like to be able to select which parts to render using the "part" variable.

The filament guide should have a torus-shaped guide to help prevent the filament from getting tangled.

I'm not sure what the best way to handle the bearing mounts on the cradle is, but I'd like to make sure they're snug but not too tight. Maybe a cylindrical recess?

I also need to be able to mount it correctly, so I think we need to be able to rotate and translate objects.

Finally, I don't need any external libraries.

Could you help me generate a parametric OpenSCAD file (or files) that I can use to print this? Let me know if you have questions!

[Assistant]
stuva-filament-holder.scad:
```
// Which components should be rendered?
part = "All"; // [ "All", "Side support only", "Cradle piece only", "Filament guide only"]

// Render quality
render_quality = 60; // [1:120]

// Z pitch of mounting holes - default is 32mm
mount_hole_pitch_z = 32;

// Number of mount holes side support should cover
mount_hole_number_z = 4;

// Y pitch of mounting holes

mount_hole_pitch_y = 224; // [ 180: STUVA front, 224: STUVA rear ]

// Thickness of side support backplate

backplate_x = 3;

// Thickness of side support beams

support_y = 10;

// Diameter of screw shaft

screw_hole_diameter = 4;

// Diameter of screw head

screw_head_diameter = 6;

// Length of side support top beam

top_beam_x = 90;

// Thickness of cradle parts - affects rigidity

cradle_fatness = 3.5;

// Distance between bearing mounts

inter_bearing_y = 120;

// Number of mount holes the filamount guide should cover;

filament_guide_hole_number_z = 3;

/* [Hidden] */

filament_spool_diameter = 200;

bearing_inner_diameter = 8;

bearing_outer_diameter = 22;

bearing_x = 7;

// Calculated variables

cradle_inner_diameter = filament_spool_diameter + bearing_outer_diameter / 2;

cradle_outer_diameter = filament_spool_diameter + bearing_outer_diameter + 10;

bearing_radius = (cradle_inner_diameter - (bearing_outer_diameter+4)/2) / 2;

interscrew_z = (mount_hole_pitch_z * (mount_hole_number_z - 1)) - screw_head_diameter - support_y;

triangle_length = pow(pow(interscrew_z, 2) + pow(top_beam_x/2, 2),0.5);

triangle_angle = atan(top_beam_x/2/interscrew_z);

inside_chord_length = mount_hole_pitch_y - support_y;

cradle_drop = 0.5 * pow((4 * pow(cradle_outer_diameter/2,2)) - pow(inside_chord_length,2),0.5);

bearing_mount_angle = 2 * asin(inter_bearing_y / (2 * bearing_radius));

$fn = render_quality;

print_parts();

module print_parts() {
    if ( part == "All" ) {
       all();
    } else if ( part == "Side support only" ) {
        side_support_only();
    } else if ( part == "Cradle piece only" ) {
        cradle_piece_only();
    } else if ( part == "Filament guide only" ) {
        filament_guide_only();
    }
}

module all() {
    support();
    translate([0,mount_hole_pitch_y, 0])
        support();
    translate([backplate_x + 1,mount_hole_pitch_y/2 + support_y/2, (mount_hole_pitch_z * (mount_hole_number_z - 1)) + support_y/2 - screw_head_diameter/2])
        cradle();
    translate([backplate_x + 1 + bearing_x + (cradle_fatness + 1) * 2,mount_hole_pitch_y/2 + support_y/2, (mount_hole_pitch_z * (mount_hole_number_z - 1)) + support_y/2 - screw_head_diameter/2])
        rotate([0,0,180])
            cradle();
    translate([backplate_x + top_beam_x - cradle_fatness - 20,mount_hole_pitch_y/2 + support_y/2, (mount_hole_pitch_z * (mount_hole_number_z - 1)) + support_y/2 - screw_head_diameter/2])
        cradle();
    translate([backplate_x + bearing_x + cradle_fatness + top_beam_x - 18,mount_hole_pitch_y/2 + support_y/2, (mount_hole_pitch_z * (mount_hole_number_z - 1)) + support_y/2 - screw_head_diameter/2])
        rotate([0,0,180])
            cradle();
    translate([0,0,mount_hole_pitch_z * (mount_hole_number_z)])
        filament_guide();
}

module side_support_only() {
    rotate([270,0,0])
        support();
}

module cradle_piece_only() {
    rotate([0,270,0])
        cradle();
}

module filament_guide_only() {
    rotate([90,0,0])
        filament_guide();
}

module filament_guide() {
    difference() {
        union() {
            filament_guide_backplate();
            filament_guide_torus();
        }
        filament_guide_screw_holes();
    }
    filament_guide_shaft();
}

module filament_guide_shaft() {
    translate([0,0,(mount_hole_pitch_z * (filament_guide_hole_number_z-1)/2)])
        cube([top_beam_x/2 + backplate_x - support_y*2, support_y, support_y]);
}

module filament_guide_screw_holes() {
    for (i=[0:mount_hole_number_z-1]) {
        translate([-0.05,support_y/2,i * mount_hole_pitch_z + support_y/2])
            rotate([0,90,0])
                cylinder(d1 = screw_hole_diameter, d2 = screw_head_diameter, h=backplate_x+0.1);
    }
}

module filament_guide_backplate() {
    union() {
        translate([0,0,support_y/2])
            cube([backplate_x, support_y, mount_hole_pitch_z * (filament_guide_hole_number_z - 1)]);
        translate([0,support_y/2, support_y/2])
            rotate([0,90,0])
                cylinder(h=backplate_x, d = support_y);
        translate([0,support_y/2, (support_y/2) + (mount_hole_pitch_z * (filament_guide_hole_number_z - 1))])
            rotate([0,90,0])
                cylinder(h=backplate_x, d = support_y);
    }
}

module filament_guide_torus() {
    translate([top_beam_x/2 + backplate_x,support_y/2, support_y/2 + (mount_hole_pitch_z * (filament_guide_hole_number_z-1)/2)])
        rotate([90,0,0])
            rotate_extrude(convexity = 10)
                translate([support_y*2, 0, 0])
                    circle(d = support_y);
}

module cradle() {
    cradle_sling();
    cradle_bearing_mounts();
    cradle_sling_tabs();
}

module cradle_sling_tabs() {
    translate([cradle_fatness,(mount_hole_pitch_y - support_y)/2 + support_y,0])
        rotate([0,0,180])
            cradle_sling_tab();
    translate([0,0 - (mount_hole_pitch_y + support_y)/2,0])
        cradle_sling_tab();

}

module cradle_sling_tab() {
    difference() {
        cube([cradle_fatness, support_y, support_y]);
            intersection() {
                translate([0 - cradle_fatness/2,0-support_y/2, support_y/2])
                cube([support_y, support_y, support_y]);
                rotate([0,270,0])
                translate([support_y/2,support_y/2,0-cradle_fatness*2.5])
                difference() {
                    cylinder(h = cradle_fatness * 3, d = support_y * 2);
                    translate([0,0,0-cradle_fatness/2])
                        cylinder(h = cradle_fatness * 4, d = support_y);
                }
            }
    }
}

module cradle_bearing_mounts() {
    translate([0,0,cradle_drop])
    union() {
        rotate([bearing_mount_angle/2,0,0])
        translate([0,0,0-bearing_radius])
            cradle_bearing_mount();
        rotate([0-bearing_mount_angle/2,0,0])
        translate([0,0,0-bearing_radius])
            cradle_bearing_mount();
    }
}

module cradle_bearing_mount() {
   rotate([0,90,0])
    union() {
    cylinder(h=cradle_fatness, d = bearing_outer_diameter + 4);
    translate([0,0,cradle_fatness])
        cylinder(h= 1, d = bearing_inner_diameter + 4);
    translate([0,0,cradle_fatness + 1])
        cylinder(h=(bearing_x - 1)/2, d = bearing_inner_diameter);
    }
}

module cradle_sling() {
    difference() {
        union() {
            translate([0,0,cradle_drop])
                rotate([0,90,0])
                union() {
                    difference() {
                        cylinder(h = cradle_fatness, d = cradle_outer_diameter);
                        translate([0,0,0-cradle_fatness/2])
                            cylinder(h = cradle_fatness * 2, d = cradle_inner_diameter);
                    }
                    translate([0,0,cradle_fatness])
                    difference() {
                        cylinder(h = cradle_fatness, d = cradle_outer_diameter);
                        translate([0,0,0-cradle_fatness/2])
                            cylinder(h = cradle_fatness * 2, d = cradle_outer_diameter - 2 * cradle_fatness);
                    }
                }
        }
        translate([0-cradle_fatness/2,0-cradle_outer_diameter/2,support_y])
            cube([cradle_fatness * 3, cradle_outer_diameter, cradle_outer_diameter]);
        }
}

module support() {
    difference() {
        union() {
            support_backplate();
            top_beam();
            triangle();
        }
        support_screw_holes();
        trim();
    }
}

module trim() {
    translate([0-support_y, 0-support_y/2, 0-support_y/2])
    cube([support_y, support_y * 2, mount_hole_pitch_z * (mount_hole_number_z - 1) + support_y * 2]);
}

module top_beam() {
    translate([backplate_x,0,(mount_hole_pitch_z * (mount_hole_number_z - 1)) - support_y/2 - screw_head_diameter/2])
        union() {
            cube([top_beam_x, support_y, support_y]);
            translate([top_beam_x-support_y/2, 0,support_y/2])
            cube([support_y, support_y, support_y]);
            translate([top_beam_x, 0, support_y*1.5])
                rotate([-90,0,0])
                    cylinder(d = support_y, h = support_y);
            translate([top_beam_x, 0, support_y/2])
                rotate([-90,0,0])
                    cylinder(d = support_y, h = support_y);
        }

}

module triangle() {
    translate([backplate_x,0,support_y + screw_head_diameter/2])
    rotate([0, triangle_angle, 0])
        translate([0-support_y/2,0,0])
            union() {
                cube([support_y, support_y, triangle_length]);
                translate([support_y/2, 0, 0])
                    rotate([-90,0,0])
                        cylinder(d = support_y, h = support_y);
                translate([support_y/2, 0, triangle_length])
                    rotate([-90,0,0])
                        cylinder(d = support_y, h = support_y);
            }
}

module support_backplate() {
    union() {
        translate([0,0,support_y/2])
            cube([backplate_x, support_y, mount_hole_pitch_z * (mount_hole_number_z - 1)]);
        translate([0,support_y/2, support_y/2])
            rotate([0,90,0])
                cylinder(h=backplate_x, d = support_y);
        translate([0,support_y/2, (support_y/2) + (mount_hole_pitch_z * (mount_hole_number_z - 1))])
            rotate([0,90,0])
                cylinder(h=backplate_x, d = support_y);
    }
}

module support_screw_holes() {
    for (i=[0:mount_hole_number_z-1]) {
        translate([-0.05,support_y/2,i * mount_hole_pitch_z + support_y/2])
            rotate([0,90,0])
                cylinder(d1 = screw_hole_diameter, d2 = screw_head_diameter, h=backplate_x+0.1);
    }
}
```


[User]
I need a pill bottle divider, something that can be inserted into a standard pill bottle to separate pills by day or type. I'm envisioning a cylinder with several dividing disks inside, essentially creating compartments.

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

*   **Number of Compartments:** I'd like to be able to specify how many compartments the divider has.
*   **Insert Diameter:** This needs to be adjustable to fit different pill bottles.
*   **Insert Length:** The overall length of the insert should be a parameter.
*   **Divider Width:** The thickness of the dividing disks needs to be adjustable.
*   **Wall Width:** I need to be able to specify the thickness of the outer cylinder wall.
*   **Open Percentage:** I'd like to control how much of the top of the divider is open. A higher percentage means more of the top is cut away, making it easier to access the pills, while lower percentage gives more structure on top.
*   **Flat Percentage:** A flat area on the bottom of the insert will keep the compartments more sealed when placed on a flat surface. This percentage would determine the size of this flat section at the base.
*  **String Holes:** I'd like to include small holes for a string or loop to aid in removing the insert from a bottle. They should be a specific size, spacing, and be optional.

Here's what I mean by 'percentage open' and 'percentage flat': If the `percent_open` was 30%, 30% of the diameter of the circle would be cut away at the top. Similarly, `percent_flat` of 10% would cause 10% of the circle diameter at the bottom to be removed.

For the string holes:

*   **Include Holes:** A boolean variable to turn the holes on or off.
*   **Hole Width:** The width of the holes.
*   **Hole Height:** The height of the holes.
*   **Hole Spacing:** The spacing between the two holes.

I would like all these parameters to be adjustable in the OpenSCAD file. I don't have any specific requirements for libraries, so any standard OpenSCAD functions would work well for the shapes. I don't need any special modules, but I would like the code to be organized into sections that make sense. I would expect the code to produce a single STL file.

[Assistant]
BottleDivider.scad:
```
// Number of compartments
num_compartments = 7; // [1:1:10]

// Diameter of insert (mm) (slightly smaller than inner diameter of pill bottle)
diameter = 36.5;

// Length of insert (mm)
length = 58;

// Width of spacers (mm)
width_spacer = 1.5;

// Open percentage (%)
percent_open = 33; // [0:100]

// Flat percentage (%)
percent_flat = 8; // [0:100]

// Width of wall (mm)
width_wall = 1.5;

/* [String Holes] */

// Include string holes
include_holes = 1; // [0:No, 1: Yes]

// Hole Width (mm)
width_hole = 2;

// Hole Height (mm)
height_hole = 1.5;

// Hole spacing (mm)
spacing_hole = 6;

// Calculated values
width_open = diameter * percent_open / 100;
width_flat = diameter * percent_flat / 100;
radius = diameter / 2;
num_spacers = num_compartments + 1;
width_compartment = (length - (num_spacers * width_spacer)) / num_compartments;
rotate([90,0,180])
{
    difference()
    {
        union()
        {
            difference()
            {
                // Full Insert
                cylinder(h=length, d=diameter);

                // Hollow out
                difference()
                {
                    // Inner cylinder
                    cylinder(h=length, d=diameter - (2 * width_wall));
                    // Leave bottom wall
                    translate([-radius, -radius + width_flat, 0])
                        cube([diameter, width_wall, length]);
                }
                // Cut off top open part
                translate([-radius, radius - width_open, 0])
                    cube([diameter, width_open, length]);
            }

            // Generate dividers
            for(i = [0:1:num_compartments])
            {
                offset = (width_compartment + width_spacer) * i;
                translate([0, 0, offset])
                    cylinder(h = width_spacer, d = diameter);
            }
        }
        // Cut off bottom flat part
        translate([-radius, -radius, 0])
            cube([diameter, width_flat, length]);

        // Cut out string holes
        if (include_holes)
        {
            translate([spacing_hole / 2, 0, 0])
                linear_extrude(height=width_spacer)
                    resize([width_hole, height_hole])
                        circle(d=1, $fn=20);
            translate([-spacing_hole / 2, 0, 0])
                linear_extrude(height=width_spacer)
                    resize([width_hole, height_hole])
                        circle(d=1, $fn=20);
        }
    }
}
```


[User]
I'm looking for an OpenSCAD design for a parametric box with a sliding lid that locks into place. The key feature is a locking mechanism with hooks on the sides of the lid that engage with anchors on the bottom part of the box. To open the box, you'd press buttons on the hooks and slide the lid open. I need to be able to adjust all the dimensions, thicknesses, and tolerances.

Specifically, I need the following parameters to be customizable:

*   **Outer Dimensions:** Box length (l), width (w), and height (h).
*   **Rounding:** A rounding radius (r) for the corners, with a corresponding `$fn` variable for the circle resolution. Also, a maximum overhang angle `max_angle` (for the rounded parts - 0 being no overhang) for the bottom part to account for the rounding and allow for printing without supports.
*   **Thicknesses:** Thickness of the bottom (bottom_t), top (top_t), and sides (side_t). The side thickness has a constraint; it must be greater than or equal to rail_min_t + rail_depth (which I'll describe next).
*   **Tolerances:** Various tolerances need to be adjustable:
    *   `rail_play`: Horizontal gap between the rail and the notch in the bottom part.
    *   `rail_vertical_play`: Vertical gap between the top of the rail and the notch.
    *   `front_play`: Horizontal gap between the front of the top part and the bottom part
    *   `hook_play`: Horizontal gap between the hook button and the anchor.
    *   `catch_play`: Horizontal gap between the "catching" part of the anchor and the hook.
    *   `back_play`: Horizontal gap between the back of the top part and the bottom part.
*   **Front Slot Profile:**
    *   `top_front_t`: Minimum thickness of the front of the bottom part, right below the slot for the top part.
    *   `front_support_t`:  Width of the flat surface of that front part that supports the top part.
    *   `front_slope`: Slope of the slot at the front of the bottom part
*   **Rail Parameters:** The lid slides in on rails.
    *  `rail_min_t`: Minimum thickness of the inner and outer rails
    *   `rail_depth`: Depth of the rail notch in the bottom part.
    *   `rail_straight_h`: Height of the straight sections of the rail profile
*   **Hook Parameters:** The locking mechanism.
    *   `button_l`: Length of the hook button.
    *   `spring_l`: Length of the spring section connecting the button and the hook.
    *   `hook_slope`: Slope of the hook front.
    *   `catch_slope`: Slope of the locking surface on the hook and anchor.
    *   `notch_t`: Minimum gap separating the hook from the rest of the top.
    *   `hook_opening_w`: Maximum width of the gap between the hook and the front part.
    *   `hook_l`: Length of the front part of the hook.
    *   `hook_t`: Width of the locking area on the hook.
    *   `hook_straight_h`: Length of the straight sections of the hook profile.
    *   `hook_w`: Minimum horizontal thickness of the hook itself.
    *   `anchor_min_t`: Minimum horizontal thickness of the anchor (distance between the side and the hook).

I need a `part` variable to choose whether to render the "bottom" part, the "top" part, "both" parts, or "closed_box" which renders both assembled.

I'd also like some simple consistency checks that output warnings to the console if invalid parameters are used (for example, if the bottom part is too short to fit the top part) -- just simple text-based warnings that use `echo`.

I'm not looking for any specific libraries to be used; the base OpenSCAD functionality is fine for this design.

[Assistant]
box.scad:
```
/* [View] */
// Part(s) to display
part="both"; //[bottom:Bottom only,top:Top only,both:Bottom and top,closed_box: Bottom and top together]

/* [Outer dimensions] */

// Box length
l=60;
// Box width
w=40;
// Box height
h=15;

/* [Edges rounding] */
// Rounding radius
r=3;
// Rounding resolution in steps per full turn
$fn=36;
// Overhang angle at the start of the print (0 means no overhang)
max_angle=60;

/* [Thickness] */
// Thickness of the floor
bottom_t=1.8;
// Thickness of the roof
top_t=1.8;
// Thickness of the sides. Must be >=rail_min_t+rail_depth (see rail parameters). Use exactly this value to align with the outer rail
side_t=1.8;

/* [Top part tolerances] */
// Horizontal gap between the rail and the notch
rail_play=0.2;
// Vertical gap between the top of the rail and the top of the notch
rail_vertical_play=0.1;
// Horizontal gap between the top part and the top front of the bottom part
front_play=0.3;
// Horizontal gap between the hook button and the anchor
hook_play=0.2;
// Horizontal gap between the "catching" part of the anchor and hook
catch_play=-0.2;
// Horizontal gap between the back of the top part and the bottom part
back_play=0.3;

/* [Front slot profile] */
// Minimum thickness of the top front of the bottom part
top_front_t=1.2;
// Horizontal width of the flat surface supporting the front of the top part (also constrained by the box side thickness and inner rounding radius)
front_support_t=1;
// Slope of the front slot (0 means vertical)
front_slope=0.5;

/* Computed */
box_cut=r*(1-sin(max_angle));

/* [Rail parameters] */
// Minimum thickness of the inner and outer rails
rail_min_t=1.2;
// Depth of the rail notch in the bottom part
rail_depth=0.6;
// Height of the two vertical sections of the rail profile, below and above the inclined section
rail_straight_h=0.4;
/* Computed */
rail_h=rail_depth+2*rail_straight_h;
profile_angle=atan(rail_depth/(rail_depth+rail_straight_h));

/* We use the same radius in all directions for simplicity, and choose it according to side_t. */
inner_r=max(0,r-side_t);

top_h=r-box_cut;
bottom_h=h-top_h;

/* [Hook parameters] */
// Length of the hook opening button
button_l=8;
// Length of the spring section
spring_l=4;
// Hook front slope
hook_slope=2;
// Locking slope
catch_slope=0.5;
// Minimum gap to separate the hook from the rest of the top part
notch_t=0.6;
// Maximum width of the gap between the hook and the front section of the top part
hook_opening_w=1.5;
// Hook front length
hook_l=2.5;
// Width of the locking area
hook_t=0.8;
// Length of the straight sections of the hook profile
hook_straight_h=0.6;
// Minimum horizontal thickness of the hook
hook_w=2;
// Minimum horizontal thickness of the anchor (i.e. distance between the side and the hook)
anchor_min_t=1.8;

/* Avoid exposing list literal: */
/* [Hidden] */

/* Computed */
anchor_h=2*hook_straight_h+hook_slope*hook_t;
hook_x_offset=-top_front_t-hook_l;
hook_y_offset=anchor_min_t;
hook_pos=[l/2+hook_x_offset,hook_y_offset-w/2];

/* Consistency checks */
warnings=[
     [bottom_h < r-box_cut+rail_h,
      "Bottom part shorter than top"],
     [top_front_t+top_t*front_slope<r*(1-cos(max_angle)),
      "Top part taller than bottom front"],
     [top_h < top_t,
      "Top part thickness greater than top part height"],
     [bottom_h-bottom_t-rail_h < inner_r,
      "Inner rounding extends above bottom part height"],
     [side_t<rail_min_t+rail_depth,
      "Bottom part thickness too small for the rail"],
     [hook_y_offset+hook_t>side_t+inner_r,
      "Anchor is unsupported"]
     ];

active_warnings=[for(w=warnings) if(w[0]) w[1]];

module warning(n,s) {
     s=str("Warning: ",s);
     echo(s);
     color("red")
	  rotate(-45)
	  translate([max(l,w)*1.5,0])
	  rotate([55,0,90])
	  translate([max(l,w)*-1.5,max(l,w)*n*-0.15])
	  linear_extrude(0.01)text(s,size=max(l,w)*0.1);
}

if (len(active_warnings)>0)
     for(i=[0:len(active_warnings)-1])
	  warning(i,active_warnings[i]);

module anchor()
     translate(hook_pos)
     polygon(
	  [[0,0],
	   [hook_l,hook_l/hook_slope],
	   [-hook_x_offset,hook_l/hook_slope],
	   [-hook_x_offset,-hook_y_offset],
	   [-anchor_h,-hook_y_offset],
	   [-anchor_h,0],
	   [-2*hook_straight_h,hook_t],
	   [-hook_straight_h,hook_t],
	   [-hook_straight_h-catch_slope*hook_t,0]]
	  );

module hook() {
     polygon(
	  [[0,0],
	   [hook_l-front_play,(hook_l-front_play)/hook_slope],
	   [hook_l-front_play,hook_w],
	   [-anchor_h-button_l-spring_l,hook_w+hook_opening_w-notch_t],
	   [-anchor_h-button_l-spring_l,hook_t],
	   [-anchor_h-hook_play,hook_t],
	   [-anchor_h-hook_play,hook_t-(anchor_h-2*hook_straight_h)/hook_slope],
	   [-2*hook_straight_h-hook_play,hook_t],
	   [-hook_straight_h+catch_play+catch_slope*hook_t,hook_t],
	   [-hook_straight_h+catch_play,0]]
	  );
     translate([-anchor_h-hook_play-button_l,-hook_y_offset])
	  square([button_l,hook_y_offset+hook_t]);
}

module hook_spring_ext()
     translate([-anchor_h-button_l-spring_l,-hook_y_offset])
     square([spring_l-hook_play-notch_t,hook_y_offset+hook_t-notch_t]);

/* +0.0001: workaround rendering issue */
module hook_negative() translate(hook_pos+[0,0]) difference() {
     translate([0,0,-rail_h]) linear_extrude(rail_h+top_h+0.0001) difference() {
	  polygon(
	       [[-anchor_h-button_l-spring_l,hook_w+hook_opening_w],
		[hook_l-front_play,hook_w+hook_opening_w],
		[hook_l-front_play,-hook_y_offset-0.0001],
		[-anchor_h-button_l-spring_l,-hook_y_offset-0.0001]]
	       );
	  hook();
     }
     linear_extrude(top_h+0.0001) hook_spring_ext();
}

module rail_profile(negative) {
     /* Thingiverse customizer does not support "let" */
     t=negative?(w/2):rail_min_t;
     vertical_play=negative?0:rail_vertical_play;
     offset=negative?0:rail_play;
     polygon(
	  [[0,0],
	   [rail_straight_h+vertical_play,0],
	   [rail_straight_h+rail_depth+vertical_play,rail_depth],
	   [2*rail_straight_h+rail_depth,rail_depth],
	   [2*rail_straight_h+rail_depth,rail_depth-t],
	   [rail_straight_h,-t],
	   [-top_h,-t],
	   [-top_h,offset],
	   [0,offset]]
	  );
}

module rail_chamfer(y_offset) translate([0,w/2-y_offset])
     rotate(45) translate([0,0,-rail_h]) cube([rail_depth,rail_depth*2,rail_h]);

module rail(negative)
     translate([l/2+hook_x_offset-anchor_h-(negative?0:hook_play),negative?0:-rail_play])
          difference() {
               translate([-l,w/2-rail_min_t-rail_depth])
		    rotate([0,90]) linear_extrude(l,center=false) rail_profile(negative);
	       rail_chamfer(rail_min_t+rail_depth);
	       if(!negative) {
		    y_offset=min(rail_min_t+rail_depth,hook_y_offset+hook_t-rail_play);
		    translate([-button_l,0]) mirror([1,0]) rail_chamfer(y_offset);
		    translate([-button_l-spring_l+hook_play,0]) rail_chamfer(y_offset);
	       }
}

module rails(negative=false) {
     rail(negative);
     mirror([0,1])rail(negative);
}

module back_side_cut(top) {
     offset=top?-rail_play:0;
     translate([-l/2,-w/2+rail_min_t-offset])
	  polygon(
	       [[0,rail_depth],[0,-side_t],[r,-side_t],[r,0],[r+rail_depth,rail_depth]]
	       );
}

module back_sides_cut(top) {
     back_side_cut(top);
     mirror([0,1]) back_side_cut(top);
}

module back_cut(top) {
     offset=top?-rail_play:0;
     translate([-l/2,-w/2+rail_min_t-offset+rail_depth])
     	  square([r+(top?back_play:0),w-2*(rail_min_t-offset+rail_depth)]);
}

module front_cut(top) {
     offset=top?-front_play:0;
     translate([offset,0]) rotate([90,0]) linear_extrude(w,center=true) {
	  if(top)
	       translate([l/2+hook_x_offset-anchor_h+front_play-hook_play,0])
		    square([-hook_x_offset+anchor_h+hook_play,top_h-top_t]);
	  else {
	       square_l=max(-hook_x_offset-hook_l+front_support_t,side_t);
	       translate([l/2-square_l,0])
		    square([square_l,top_h-top_t]);
	  }
	  translate([l/2+hook_x_offset+hook_l,top_h])
	       polygon(
		    [[0,-top_t-0.0001],
		     [-hook_x_offset-hook_l-offset+0.0001,-top_t-0.0001],
		     [-hook_x_offset-hook_l-offset+0.0001,0.0001],
		     [-top_t*front_slope,0.0001]]
		    );
     }
     /* In the bottom part, leave the front side walls up to the top thickness */
     if(!top)
	  difference() {
	       translate([l/2+hook_x_offset-anchor_h,-w/2])
		    cube([-hook_x_offset+anchor_h,w,top_h-top_t]);
	       translate([0,0,inner_r]) inside();
	  }
}

module inside()
     translate([0,0,(h-bottom_t-top_t)/2-(bottom_h-bottom_t)])
     box([l-2*side_t,w-2*side_t,h-bottom_t-top_t],inner_r);

module half(top=false) difference() {
     translate([0,0,h/2-bottom_h]) intersection() {
	  cube([l,w,h],center=true);
	  box([l,w,h+2*box_cut],r);
     }
     difference() {
	  union() {
	       translate([0,0,top?(-h/2):(h/2)]) cube([l,w,h],center=true);
	       /* For the bottom part, we also remove the top inner rounding, if any */
	       if(!top) translate([0,0,inner_r]) inside();
	  }
	  if(top) {
	       rails();
	       translate([-back_play,0,-rail_h]) linear_extrude(h) {
		    back_cut(top=true);
		    back_sides_cut(top=true);
	       }
	  }
	  else {
	       front_cut(top=false);
	       translate([0,0,-bottom_h]) linear_extrude(h) {
		    anchor();
		    mirror([0,1]) anchor();
	       }
	  }
     }
     if(top) {
	  front_cut(top=true);
	  hook_negative();
	  mirror([0,1]) hook_negative();
     } else {
	  rails(negative=true);
	  translate([0,0,-rail_h]) linear_extrude(rail_h) {
	       back_cut(top=false);
	       back_sides_cut(top=false);
	  }
     }
     difference() {
	  inside();
	  if(top) {
	       rails();
	       translate([-back_play,0,-rail_h]) linear_extrude(h) back_sides_cut(top=true);
	  }
     }
}

render()
rotate(180)
if(part=="top")
     rotate([180,0]) half(top=true);
else if(part=="bottom")
     half(top=false);
else if(part=="closed_box") {
     half(top=false);
     half(top=true);
} else {
     translate([0,w*0.6]) half(top=false);
     translate([0,-w*0.6]) rotate([180,0]) half(top=true);
}

module box_profile(h,r) {
     translate([0,r-h/2])
	  square([r,h-2*r]);
     for(i=[-1,1])
     translate([0,i*(h/2-r)])
	  intersection() {
	  circle(r);
	  translate([0,(i-1)/2*r])
	  square(r);
     }
}

module round(size,r)
     translate([size[0]/2-r,size[1]/2-r])
	  rotate_extrude(angle=90)
	  box_profile(size[2],r);

module box(size,r)
     if(r>=0.001)
	  hull() {
	       round(size,r);
	       mirror([1,0]) round(size,r);
	       mirror([0,1]) {
		    round(size,r);
		    mirror([1,0]) round(size,r);
	       }
	  }
     else
	  cube(size,center=true);

```


[User]
Hi, I'm looking for an OpenSCAD design for a shelf that will hang on an aluminum box section, like those used in 3D printers. I'd like the design to be parametric, so I can easily adjust the dimensions. I've seen a few on Thingiverse but wanted to make one with my specific needs.

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

*   **`boxsize`**: This is the width of the box section the shelf will mount onto. Common sizes are 20mm, 30mm, etc.
*   **`rearheight`**: The maximum height at the rear of the shelf.
*   **`frontheight`**: The height at the front of the shelf. This will typically be less than the rear height.
*   **`width`**: The overall width of the shelf.
*   **`depth`**: The depth of the flat shelf part extending forward.

Essentially, I need a shelf with a rear section that hooks over the box section, and a flat front tray. The rear part will need to have a cutout so it securely grips the box section on the top, and there is a small part below the cutout that rests against the bottom of the box section. The sides will extend down from the back to the front. I’d like rounded front corners for aesthetics, just like the attached file.

I'm not sure what's the best way to construct this in OpenSCAD, but the way I was trying included a lot of `translate` and `cube` commands, as well as `polyhedron` and `difference`. I was also using cylinders for the front corners.

I would really like to have this parameterized properly rather than hard-coded, so please do not submit a design with hard-coded values.

Also, please do not include the code that I included in my request. I am confident that you can create a parametric OpenSCAD design without needing my code.

Thanks!

[Assistant]
printerbox.scad:
```
// Aluminium box section width
boxsize=20; // [10:10mm,20:20mm,30:30mm]
// Rear height
rearheight=25; // [20:100]
// Front height
frontheight=10; // [5:100]
// Width
width=60; // [5:300]
// Depth of front shelf
depth=25; // [10:200]
/* [Hidden] */
$fn=70;
translate([0.5,0,0]) {
    cube([width-1,2,frontheight]); //front
}
translate([0.5,0.5,0]) {
    cube([width-1,depth-0.5,2]); // bottom
}
polyhedron( //left
  points=[ [0,0.5,0],[0,depth,0],[0,depth,rearheight],[0,0.5,frontheight],
    [1,0.5,0],[1,depth,0],[1,depth,rearheight],[1,0.5,frontheight] ],
  faces=[ [3,1,0],[3,2,1],
    [4,5,7],[5,6,7],
    [0,4,3],[4,7,3],
    [3,7,6],[6,2,3],
    [1,2,5],[2,6,5],
    [0,1,5],[0,5,4] ]
  );

 translate([width-1,0,0]) { // right
     polyhedron(
  points=[ [0,0.5,0],[0,depth,0],[0,depth,rearheight],[0,0.5,frontheight],
    [1,0.5,0],[1,depth,0],[1,depth,rearheight],[1,0.5,frontheight] ],
  faces=[ [3,1,0],[3,2,1],
    [4,5,7],[5,6,7],
    [0,4,3],[4,7,3],
    [3,7,6],[6,2,3],
    [1,2,5],[2,6,5],
    [0,1,5],[0,5,4] ]
  );
 }
// front corners
translate([0.5,0.5,0]) {cylinder(frontheight,0.5,0.5);}
translate([width-0.5,0.5,0]) {cylinder(frontheight,0.5,0.5);}

//middle/rear
translate([0,depth,0]) {
    difference() {
        cube([width,boxsize+4+0.5,rearheight]);
        translate([-1,2,-1]) { cube([width+2,boxsize+0.5,boxsize+1]); }
        translate([1,2,boxsize+2]) { cube([width-2,boxsize+0.5,rearheight]); }
    }
}

```


[User]
I need a parametric cable wall mount designed in OpenSCAD. It should be customizable for different cable diameters, screw sizes, and allow for multiple mounts to be stacked for printing. I'd like to be able to specify if I want one screw hole or two, and whether the screw holes should be counter-sunk.

Here are some more specific requirements:

*   **Cable Diameter:** This should be a primary parameter, so I can adjust the mount to fit different cable sizes.
*   **Screw Hole Diameter:**  I need to specify the diameter of the screw I'll be using.
*   **One or Two Screws:** A boolean parameter to switch between one screw mount or two screw mounts on opposite sides of the cable.
*   **Counter-sinking:** A boolean to enable/disable counter-sinking for the screw holes.
*   **Mount Quantity:** A number to specify how many mounts to generate, stacked on top of each other for printing efficiency.
*   **Mount Thickness:** I need to be able to adjust the thickness of the plastic used for the mount.
*   **Cable Reduced Height:** A parameter to reduce the height of the arch, which can increase the grip on the cable by pushing it towards the wall.
*   **Arch Part of Base:** A boolean to control whether the arch part of the mount should be considered part of the base, or exist slightly above it.
*   **Screw Hole Margin:** This should let me customize the space around the screw holes. It should default to SCREW_HOLE_DIAMETER+2.
*   **Screw Hole Extra Thickness:** Allow me to add additional thickness around the screw holes, for strength or use with long screws.
*    **Mount Quantity Spacing:** I need a parameter that controls the space between stacked mounts.
*   **$fn:** Should allow custom setting of the number of fragments, for smoother curves (but have a default value for preview vs rendering).

It would be great if the design used the base and arch modules, like in the example I saw. Please use modules to create the components, for easy modification and re-use. I'm not looking for any external libraries.

[Assistant]
Cable_Wall_Mount.scad:
```
// by MegaSaturnv

/////////////////////////////
// Customizable Parameters //
/////////////////////////////
/* [Basic] */
//Diameter of the cable
CABLE_DIAMETER = 7;

//Diameter of the screw used
SCREW_HOLE_DIAMETER = 4.1;

//Set to false to use a single screw on one side, rather than two (one on each side)
TWO_SCREWS = true;

//Change this to enable/disable counter-sinking
COUNTER_SINKING = true;

//Quantity of mounts to print. They will be stacked on top of each other for printing
MOUNT_QUANTITY = 4;

/* [Advanced] */
//Thickness of the plastic printed for the mount
MOUNT_THICKNESS = 2;

//Reduce the height given to the mounted cable. Used to grip the cable against the wall.
CABLE_REDUCED_HEIGHT = 1;

//Make the arch part of the base. Useful for small cable sizes, but may obscure the screw hole. Increase SCREW_HOLE_MARGIN below if needed (variable may not be visible in customizer and only seen in OpenSCAD because it is a calculated value)
ARCH_PART_OF_BASE = false;

//Margin around each screw hole. Default is SCREW_HOLE_DIAMETER + 2mm (good for counter-sinking)
SCREW_HOLE_MARGIN = SCREW_HOLE_DIAMETER+2;

//Give extra thickness to the screw holes. Useful for strength and screws that are too long. This is in addition to MOUNT_THICKNESS
SCREW_HOLE_EXTRA_THICKNESS = 1;

//Spacing between the stacked prints. Applies when printing multiple, specified by MOUNT_QUANTITY
MOUNT_QUANTITY_SPACING = 0.2;

//Use $fn = 24 if it's a preview. $fn = 96 for the render. Increase 96 to produce a smoother curve.
$fn = $preview ? 24 : 96;

//////////////////
// Calculations //
//////////////////
baseLength = SCREW_HOLE_DIAMETER+SCREW_HOLE_MARGIN;
baseWidth = SCREW_HOLE_DIAMETER+SCREW_HOLE_MARGIN;

/////////////
// Modules //
/////////////
module mountBase(Arg_baseHeight, Arg_screwDiameter, Arg_screwHoleMargin) {
	difference() {
		cube([Arg_baseHeight, Arg_screwDiameter+Arg_screwHoleMargin, Arg_screwDiameter+Arg_screwHoleMargin]);
		translate([-0.1, (Arg_screwDiameter+Arg_screwHoleMargin/2)-(Arg_screwDiameter/2), (Arg_screwDiameter+Arg_screwHoleMargin/2)-(Arg_screwDiameter/2)]) rotate([0, 90, 0]) cylinder(d=Arg_screwDiameter, h=Arg_baseHeight+0.2);
		if (COUNTER_SINKING) {
			translate([-0.1, (Arg_screwDiameter+Arg_screwHoleMargin/2)-(Arg_screwDiameter/2), (Arg_screwDiameter+Arg_screwHoleMargin/2)-(Arg_screwDiameter/2)]) rotate([0, 90, 0]) cylinder(d1=0, d2=Arg_screwDiameter*2, h=Arg_baseHeight+0.2);
		}
	}
}

module mountArch(Arg_cableDiameter, Arg_width, Arg_thickness, Arg_reducedHight=0) {
	translate([(Arg_cableDiameter/2)-CABLE_REDUCED_HEIGHT, (Arg_cableDiameter/2)+Arg_thickness, 0]) difference() {
		difference() {
			cylinder(d=Arg_cableDiameter+(2*Arg_thickness), h=Arg_width);
			translate([0, 0, -0.1]) cylinder(d=Arg_cableDiameter, h=Arg_width+0.2);
		}
		translate([(Arg_cableDiameter/-2)-Arg_thickness, (Arg_cableDiameter/-2)-Arg_thickness, -0.1]) cube([(Arg_cableDiameter/2)+Arg_thickness, Arg_cableDiameter+(2*Arg_thickness), Arg_width+0.2]);
	}
	cube([(Arg_cableDiameter/2)-Arg_reducedHight, Arg_thickness, Arg_width]);
	translate([0, Arg_cableDiameter+Arg_thickness, 0]) cube([(Arg_cableDiameter/2)-Arg_reducedHight, Arg_thickness, Arg_width]);
}

module mountBracket() {
	union() {
		//Base 1
		mountBase(MOUNT_THICKNESS+SCREW_HOLE_EXTRA_THICKNESS, SCREW_HOLE_DIAMETER, SCREW_HOLE_MARGIN);

		//Base 2
		if (TWO_SCREWS) {
			if (ARCH_PART_OF_BASE) {
				translate([0, baseLength+CABLE_DIAMETER, 0]) mountBase(MOUNT_THICKNESS+SCREW_HOLE_EXTRA_THICKNESS, SCREW_HOLE_DIAMETER, SCREW_HOLE_MARGIN);
			} else {
				translate([0, baseLength+CABLE_DIAMETER+(2*MOUNT_THICKNESS)-0.2, 0]) mountBase(MOUNT_THICKNESS+SCREW_HOLE_EXTRA_THICKNESS, SCREW_HOLE_DIAMETER, SCREW_HOLE_MARGIN);
			}
		}

		//Arch
		if (ARCH_PART_OF_BASE) {
			translate([0, baseLength-MOUNT_THICKNESS, 0]) mountArch(CABLE_DIAMETER, baseWidth, MOUNT_THICKNESS, CABLE_REDUCED_HEIGHT);
		} else {
			translate([0, baseLength-0.1, 0]) mountArch(CABLE_DIAMETER, baseWidth, MOUNT_THICKNESS, CABLE_REDUCED_HEIGHT);
		}
	}
}

////////////////
// Main Model //
////////////////
rotate([0, 0, 270])
for (i=[0:MOUNT_QUANTITY-1]) {
	translate([0, 0, i*(baseWidth + MOUNT_QUANTITY_SPACING)]) mountBracket();
}

```


[User]
Hey, I'm looking to get some help designing a customizable base for tabletop gaming, and I'd like it to have a hole in the center. I have a basic design in mind, but I need it to be fully parametric.

Essentially, I need a rectangular base with a cylindrical hole going through it. I'd like to be able to adjust the following:

*   **Base Width:** The width of the rectangular base.
*   **Base Length:** The length of the rectangular base.
*   **Hole Depth:**  The depth of the cylindrical hole (this should be adjustable and not go all the way through the base by default)
*  **Hole Diameter:** The diameter of the cylindrical hole.

I'd like the base to be 3.4mm tall overall.

It'd be great if the code were well-commented and easy to modify. I don't need anything super fancy, just a solid base with a hole that I can scale to my needs. The hole should be centered.

I'm new to OpenSCAD, so I'm hoping for a straightforward design without needing external libraries if possible.

[Assistant]
base_rectangular_with_hole_fixed_hole_diameter.scad:
```
width = 40; // [20:5:200]
// width of base

length = 40; // [20:5:200]
// length of base

hole_depth = 3;// [0:0.1:3.4]
// depth of the hole

hole_diameter = 30;// [0:1:200]
// diameter of the hole

CubePoints_outer = [
  [  0,         0,          0    ],  //0
  [ width,      0,          0    ],  //1
  [ width,      length,     0    ],  //2
  [  0,         length,     0    ],  //3
  [  1,         1,          3.4  ],  //4
  [ width-1,    1,          3.4  ],  //5
  [ width-1,    length-1,   3.4  ],  //6
  [  1,         length-1,   3.4  ]]; //7

  CubePoints_inner = [
  [  1.5,       1.5,          0    ],  //0
  [ width-1.5,  1.5,          0    ],  //1
  [ width-1.5,  length-1.5,     0    ],  //2
  [  1.5,       length-1.5,     0    ],  //3
  [  2.2,       2.2,          1.9  ],  //4
  [ width-2.2,    2.2,          1.9  ],  //5
  [ width-2.2,    length-2.2,   1.9  ],  //6
  [  2.2,         length-2.2,   1.9  ]]; //7

 /* [Hidden] */
CubeFaces = [
  [0,1,2,3],  // bottom
  [4,5,1,0],  // front
  [7,6,5,4],  // top
  [5,6,2,1],  // right
  [6,7,3,2],  // back
  [7,4,0,3]]; // left

  difference(){
    polyhedron( CubePoints_outer, CubeFaces );
    translate([width/2,length/2,3.4-hole_depth]){cylinder(h=5, r=hole_diameter/2,$fn=hole_diameter*20);}
  }

```


[User]
I'm looking to create a customizable base for tabletop gaming miniatures, and I've got some specific needs. I want it to be a rectangular base with a slot cut out, and I'd like to control the dimensions of the base, the position of the slot relative to the base's center, and the slot's rotation.

Here's what I envision:

*   **Base Shape:** Rectangular.
*   **Base Dimensions:** I need parameters for the width and the length of the base.
*   **Slot:** There should be a rectangular slot cut through the base.
*   **Slot Position:** The slot should be offset from the center of the base. I'll need a parameter for the offset distance, and I want this offset to be able to shift the slot along an arc around the center.
*   **Slot Rotation:** I need to be able to rotate the slot.
*   **Hollow Bottom:** The bottom should be hollow, creating a lip, and I would like to have parameters controlling the lip thickness, and the base height.
*   **Additional Details:**  I want a slightly raised lip around the perimeter of the base on the top, a smaller "inner" rectangle that is inset by some amount from the outer perimiter, this inner rectangle should be slightly raised, and the thickness of the base is relatively thin.
*   **Parametric Design:** I want everything controlled by parameters so I can easily adjust the size and features.

I'm thinking I'll need these parameters:

*   `base_width`:  The width of the rectangular base.
*   `base_length`: The length of the rectangular base.
*  `base_height`: The total height of the base
*   `slot_offset`: The distance the slot is offset from the center of the base.
*   `slot_rotation`: The rotation of the slot in degrees.
*   `lip_thickness`: The thickness of the bottom lip.
*   `inner_inset`: How much smaller is the "inner" rectangle than the outer rectangle
*   `inner_height`: The height of the inner rectangle.
*   `outer_lip_height`: The height of the raised lip around the outer edge

Could you please generate the OpenSCAD files for this design?

[Assistant]
base_rectangular_with_slot.scad:
```
width = 20; // [20:5:200]
// width of base

length = 20; // [20:5:200]
// length of base

offset = 1;// [0:0.5:20]
// slot offset from the middle

rotation = 0;// [0:5:90]
// slot rotation

  function get_length( a, b, rot ) = (
    (rot < atan(b/a))? (a/(cos(rot))):  (b/sin(rot))
  );

CubePoints_outer = [
  [  0,         0,          0    ],  //0
  [ width,      0,          0    ],  //1
  [ width,      length,     0    ],  //2
  [  0,         length,     0    ],  //3
  [  1,         1,          3.4  ],  //4
  [ width-1,    1,          3.4  ],  //5
  [ width-1,    length-1,   3.4  ],  //6
  [  1,         length-1,   3.4  ]]; //7

  CubePoints_inner = [
  [  1.5,       1.5,          0    ],  //0
  [ width-1.5,  1.5,          0    ],  //1
  [ width-1.5,  length-1.5,     0    ],  //2
  [  1.5,       length-1.5,     0    ],  //3
  [  2.2,       2.2,          1.9  ],  //4
  [ width-2.2,    2.2,          1.9  ],  //5
  [ width-2.2,    length-2.2,   1.9  ],  //6
  [  2.2,         length-2.2,   1.9  ]]; //7

  CubePoints_super = [
  [  -5,       -5,          0    ],  //0
  [ width+5,      -5,          0    ],  //1
  [ width+5,      length+5,     0    ],  //2
  [  -5,         length+5,     0    ],  //3
  [  -5,         -5,          5  ],  //4
  [ width+5,      -5,          5  ],  //5
  [ width+5,      length+5,     5  ],  //6
  [  -5,         length+5,     5  ]]; //7

 /* [Hidden] */
CubeFaces = [
  [0,1,2,3],  // bottom
  [4,5,1,0],  // front
  [7,6,5,4],  // top
  [5,6,2,1],  // right
  [6,7,3,2],  // back
  [7,4,0,3]]; // left

// structures:

union(){
difference(){
 union(){
     difference(){
        polyhedron( CubePoints_outer, CubeFaces );
        polyhedron( CubePoints_inner, CubeFaces );
      }
    translate([-offset*sin(rotation),offset*cos(rotation),0])
        translate([width/2, length/2,0])
            rotate([ 0, 0,rotation])
                translate([0,0,1.9])
                    cube(size = [get_length(width, length, rotation),4,3], center=true);
  }
   difference(){
    polyhedron( CubePoints_super, CubeFaces );
    polyhedron( CubePoints_outer, CubeFaces );
  }
  translate([-offset*sin(rotation),offset*cos(rotation),0])
        translate([width/2, length/2,0])
            rotate([ 0, 0,rotation])
                cube(size = [get_length(width, length, rotation),2,10], center=true);
}
     difference(){
        polyhedron( CubePoints_outer, CubeFaces );
        polyhedron( CubePoints_inner, CubeFaces );
         translate([2.2,2.2,0])
         cube(size = [width-4.4, length-4.4, 5]);
      }
      }
```


[User]
I need an OpenSCAD design for a clip to adjust the length of round elastic face mask straps. It's basically a small block with channels for the strap to go through, and little triangular teeth that press down on the strap to keep it from slipping.

The clip should be a rectangular prism, let's say around 12mm long, 12mm wide, and 5mm high. There will be a channel running lengthwise through the middle of the block that's sized for a 3.4mm diameter strap, plus a little extra for clearance - maybe 0.2mm more on each side of the diameter of the strap. This main channel should start about 1.8mm in from the front edge of the block. There should also be a cylinder cut out that overlaps this channel so the strap can actually enter and leave the channel, centered on the channel's height, oriented perpendicular to the main channel, and running completely through the width.

On top of that main channel, there should be a series of "clamps" – triangular teeth that extend downwards and press on the strap. These should be spaced evenly along the length of the block, starting about 1/6th of the length from the left edge and ending 5/6th from the left edge. The teeth themselves should be triangular polygons and extend down into the channel.

I'd like this to be fully parametric, so I can easily adjust the dimensions. Specifically, I need parameters for:

*   Overall length `l`
*   Overall width `w`
*   Overall height `h`
*   Diameter of the strap `d_strap`
*   Extra clearance for the strap channel `cutout_adj`
*   Distance the main channel is set back from the front `in_offset`
*   Number of clamp teeth `num_clamps`

I would like the design to use OpenSCAD's `difference()` module for the cutouts and extrusions for the clamps. Please do not use any external libraries.

[Assistant]
StrapClamp.scad:
```
$fa=1*1;
$fs=0.25*1;

w = 12;
h = 5;
l = 12;

cutout_adj = 0.2;

d_strap=3.4;
d_strap_channel = d_strap + cutout_adj;
dc = 1.75;

in_offset = 1.8;

difference() {
    cube([l, w, h]);

    translate([in_offset, 2, in_offset])
        cube([d_strap_channel, w-4, h]);

    translate([d_strap_channel/2+in_offset, -0.01, h/2])
        rotate([-90, 0, 0])
            cylinder(w+0.02, d=d_strap_channel);

    clamps(w/4+0.5);
    clamps(w*3/4-0.5);
}

module clamps(pos) {
    for(i = [d_strap/2:d_strap*2/3:l])
        translate([i, 0, 0])
            clamp(pos);
}

module clamp(pos) {

    translate([0, pos, 2])
        linear_extrude(h)
            polygon(points=[[d_strap, 0], [0, -d_strap/2], [0, d_strap/2]]);

}

```


[User]
I'd like to create a parametric OpenSCAD design for a fabric cutting template used for making DIY face masks. The template is intended to be printed in two halves and then glued together. I'm aiming for a design that I can easily adjust for different face sizes.

Here's what I have in mind:

**Overall Shape:** The template is essentially a rectangle with rounded cut-outs on each side along its length that are intended to have fabric laid over them and then trimmed. There should be a clear indication where to cut, and the fabric being trimmed should not be larger than the template. The two halves should have an overlap area where they are joined.

**Key Parameters:**

*   `overall_length`: Total length of the completed template.
*   `overall_width`: Total width of the completed template.
*   `template_thickness`: Thickness of the printed template.
*   `border_width`: Width of the 'frame' of the template, along the outer edges. This should leave a large open rectangle in the center of the template.
*   `overlap_width`: The width of the overlap region where the two halves join. This should result in a region where the two halves overlap by the overlap width on either side.
*  `corner_cutout_offset`: Length of the straight edges from the corner to where the curves begin.
*  `curve_border_width`: Width of the material bordering the curve.  This needs to be a bit more complicated so that we can have a clear cutting surface.

**Construction Details:**

1.  The template should be created using a difference operation.
2.  The main shape will be a rectangular prism.
3.  Inside the main shape will be a second, slightly shorter and narrower rectangle, that defines the 'frame' of the template (this is an empty space, the difference operation will create it as a cutout).
4.  The two halves of the template will be connected by an overlapping tab on one side, and a matching cutout for the tab on the other. The overlap tab should be added and the cutout created such that it is exactly even on both pieces of the template.
5. On each short edge there should be a set of lines cutting into the template at the corners. These lines should be mirrored on each side, and should be a mirror image of the lines on the other side, so there will be 4 lines all together. The cutting lines will have a right-angle to start from the corner and will then have a diagonal line at 45 degrees for a specified length, and then another short vertical line. These should be removed via a linear extrude. These cutouts should leave a slightly rounded opening.

I'm not too familiar with working with curves in OpenSCAD, so I'm looking for a good approach for the rounded corner cutouts - ideally they should form a smooth cutting surface once printed. I imagine a polygon with points could be effective.

I'd like the design to be parametric so I can create versions for small, medium, and large face sizes by changing the parameters. I don't require any fancy libraries, I believe everything should be achievable using the standard OpenSCAD language and standard modules.

Could you generate the necessary OpenSCAD code for this template?

[Assistant]
FaceMask_Cut_Template.mk2.scad:
```
$fa=1*1;
$fs=0.25*1;

// Overall length of template
l = 280;

// Overall width of template
w = 190;

// thickness (height) of template
thn = 4;

// width of template bars
w_rand = 9;

// overlap width (for glueing the two halves together)
w_overlap = 12;

// corner cut-out length
offset_marker = 50;

difference() {
    union() {
        difference() {
            cube([w, l, thn], center=true);
            cube([w-2*w_rand, l-2*w_rand, thn+0.02], center=true);

        }

        translate([0, 0, -thn/4])
            cube([w, w_overlap, thn/2], center=true);

        cube([w_overlap, l, thn], center=true);
    }

            translate([0, 0, thn/4+0.01])
                cube([w+0.02, w_overlap, thn/2+0.02], center=true);

    translate([0, l/2+w_overlap/2, 0])
        cube([w+0.02, l, thn+0.02], center=true);

    translate([0, 0, -thn]) {
        linear_extrude(thn*2)
            polygon(points=[[-w/2-0.02,-l/2-0.02], [-w/2-0.02,-l/2+offset_marker], [-w/2+offset_marker, -l/2-0.02]]);

        linear_extrude(thn*2)
            polygon(points=[[w/2+0.02,-l/2-0.02], [w/2+0.02,-l/2+offset_marker], [w/2-offset_marker, -l/2-0.02]]);
    }

}

translate([0, 0, -thn/2]) {
    linear_extrude(thn)
        polygon(points=[[-w/2,-l/2+offset_marker], [-w/2,-l/2+offset_marker+w_rand*sqrt(2)], [-w/2+offset_marker+w_rand*sqrt(2), -l/2], [-w/2+offset_marker, -l/2]]);

    linear_extrude(thn)
        polygon(points=[[w/2,-l/2+offset_marker], [w/2,-l/2+offset_marker+w_rand*sqrt(2)], [w/2-offset_marker-w_rand*sqrt(2), -l/2], [w/2-offset_marker, -l/2]]);
}

```


[User]
I need a custom parametric bench dog designed for woodworking. I'd like it to be configurable through parameters so I can adjust it to fit my workbench.

The bench dog should have a cylindrical shaft that fits into a hole on my workbench and a head that sits on top of the bench.

Here are the parameters I want to be able to control:
*   `shaft_diameter`: The diameter of the cylindrical shaft, in millimeters.
*   `shaft_length`: The length of the cylindrical shaft, in millimeters.
*   `head_thickness`: The thickness (or height) of the head, in millimeters.
*   `head_width`: The width of the head, in millimeters.
*   `head_length`: The length of the head, in millimeters.
*   `rounded_head`: A boolean (0 for false, 1 for true) determining if one side of the head should be rounded. If true, that rounded portion of the head should be a half-cylinder. The base of that cylinder will need to extend into the cube that forms the rest of the head.

I would like to make sure the rounded part of the head blends smoothly into the rest of the head. If the head isn't rounded, then the head should just be a rectangular prism.

I need this in OpenSCAD, please. I don't need any external libraries.

[Assistant]
bench_dog.scad:
```
/*
MIT License

Copyright (c) 2020 Frank Pape

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// Diameter of the bench dog's shaft, in mm.
shaft_diameter = 18.5;

// Length of the bench dog's shaft, in mm.
shaft_length = 50;

// Thickness (height) of the bench dog's head, in mm.
head_thickness = 12;

// Width of the bench dog's head, in mm.
head_width = 25;

// Length of the bench dog's head, in mm.
head_length = 25;

// Should one side of the head be rounded?
rounded_head = 1;  // [0:false, 1:true]

union() {
    // Bottom (on print bed). This becomes the edge of the guide that butts
    // up against the side of the workpiece.

    if (rounded_head) {
        head_radius = head_width/2;
        difference() {
            translate([head_radius, head_radius, 0]) {
                union() {
                    cylinder(h=head_thickness, r=head_radius, $fn=180);
                    translate([-head_radius, 0, 0]) {
                        cube([head_width, head_length-head_radius, head_thickness]);
                    }
                }
            }
            // Cut off any extra if the head_length is less than the head_width
            translate([0, head_length, 0]) {
                cube([head_width, head_length-head_radius, head_thickness]);
            }
        }
    } else {
        cube([head_width, head_length, head_thickness]);
    }

    translate([head_width/2, head_length/2, head_thickness]) {
        cylinder(h=shaft_length, r=shaft_diameter/2, $fn=180);
    }
}
```