[User]
Hey, I'm looking to create a customizable 2D origami chicken design using OpenSCAD. I've seen a design that's pretty close to what I want, and I'd like to make my own version with more flexibility.

The basic idea is that the design will consist of an outline and inner cut lines all defined by 2D points in a 2D plane. I want to be able to customize the overall size of the chicken, the height of the extruded shape (since I want to 3D print it), the thickness of the outer outline and the thickness of the inner cut outlines. I want to have rounded corners for the inner cut lines.

Specifically:

*   **Overall Size:** I'd like to set a maximum size for the longest side of the chicken, and the other side will scale proportionally to keep the aspect ratio correct.

*   **Model Height:** I need to be able to set how thick the extruded model is.

*   **Outline Thickness:** I need to specify how thick the outer outline should be.

*   **Inner Cut Outline Thickness:** I need to set the thickness of the inner cut lines.

*  **Inner Cut Edge Radius:** I want to control the radius of the rounded corners of the inner cut lines.

*   **Flip Option:** I need a simple option to flip the model along the Y axis.

The basic shape of the chicken is defined by points, and the cut lines are also defined by polygons using the same points. I have a list of the points used for the outer shape as well as the polygons I need to cut out from the middle:

**Outer Points**
```
A1 = [233, 648];
A2 = [283, 534];
A3 = [244, 488];
A4 = [462, 269];
A5 = [587, 325];
A6 = [570, 440];
A7 = [884, 772];
A8 = [903, 751];
A9 = [935, 776];
A10 = [1423, 424];
A11 = [1687, 437];
A12 = [1792, 210];
A13 = [1826, 442];
A14 = [1841, 557];
A15 = [1505, 757];
A16 = [1603, 1207];
A17 = [1323, 1468];
A18 = [1254, 1704];
A19 = [1154, 1663];
A20 = [840, 1806];
A21 = [255, 1231];
A22 = [427, 704];
A23 = [323, 586];
```

**Inner Points**

```
B1 = [524, 398];
B2 = [852, 1543];
B3 = [1363, 1327];
B4 = [1146, 1422];
```

**Polygons**

```
C1 = [A1, A2, A23];
C2 = [A2, A3, B1, A22, A23];
C3 = [A3, A4, A5, A6, B1];
C4 = [B1, A6, A7, A21];
C5 = [A7, A21, A20, B2];
C6 = [A7, A8, B4, B2];
C7 = [A8, B4, B3, A17, A16, A9];
C8 = [B4, B3, A17, A18, A19, B2];
C9 = [B2, A20, A19];
C10 = [A9, A10, A15, A16];
C11 = [A10, A11, A13, A14, A15];
C12 = [A11, A12, A13];
```

I need the final design to be a linear extrusion of the 2D shapes, and the script should rescale the model based on the `max_size` parameter and keep the aspect ratio.

I don't need any special libraries for this one, just standard OpenSCAD. Could you generate the OpenSCAD file for me?

[Assistant]
customizable_origami_chicken.scad:
```
/*
 * Customizable Origami - Chicken - https://www.thingiverse.com/thing:2750175
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-01-08
 * 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.6; //[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.5; //[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 = [233, 648];
A2 = [283, 534];
A3 = [244, 488];
A4 = [462, 269];
A5 = [587, 325];
A6 = [570, 440];
A7 = [884, 772];
A8 = [903, 751];
A9 = [935, 776];
A10 = [1423, 424];
A11 = [1687, 437];
A12 = [1792, 210];
A13 = [1826, 442];
A14 = [1841, 557];
A15 = [1505, 757];
A16 = [1603, 1207];
A17 = [1323, 1468];
A18 = [1254, 1704];
A19 = [1154, 1663];
A20 = [840, 1806];
A21 = [255, 1231];
A22 = [427, 704];
A23 = [323, 586];

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

// Inner Points
B1 = [524, 398];
B2 = [852, 1543];
B3 = [1363, 1327];
B4 = [1146, 1422];

// Polygons
C1 = [A1, A2, A23];
C2 = [A2, A3, B1, A22, A23];
C3 = [A3, A4, A5, A6, B1];
C4 = [B1, A6, A7, A21];
C5 = [A7, A21, A20, B2];
C6 = [A7, A8, B4, B2];
C7 = [A8, B4, B3, A17, A16, A9];
C8 = [B4, B3, A17, A18, A19, B2];
C9 = [B2, A20, A19];
C10 = [A9, A10, A15, A16];
C11 = [A10, A11, A13, A14, A15];
C12 = [A11, A12, A13];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12];

min_x = A1[0];
min_y = A12[1];
max_x = A14[0];
max_y = A20[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 design a 3D printable air filter box for my 3D printer enclosure. I have a 120mm PC fan and a Shop-Vac 5-Gallon Cartridge Filter, and I need the box to connect to both of those and also a 1 1/4" shop vac hose.

The filter has a 195mm diameter rubber ring and is open on one side with a solid plastic backing on the other. I want the box to sit on the rubber ring, and the PC fan to blow air into the filter through the box. The shop vac hose will connect to a nozzle on the side, sucking air from the inside of the box and pushing it out to my enclosure.

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

*   **`shrink_fix`**: A small value to add to dimensions to account for shrinkage, adjustable from 0.1 to 0.6 in increments of 0.1.
*   **`xwide`**: Width of the fan on the X-axis, starting at 120mm, but adjustable with a minimum of 10 and max of 200 in steps of 5.
*   **`ywide`**: Width of the fan on the Y-axis, also starting at 120mm and also adjustable like `xwide`.
*  **`thickness`**: Wall thickness of the box, minimum of 1, maximum of 4 in steps of 1.
*   **`boxheight`**: Height of the fan box. Minimum of 10, max of 80, steps of 10.
*   **`tubecutout`**: Diameter of the hose opening, starting at 40mm. Minimum of 20, max of 100, steps of 1.
*   **`plastic_tube_id`**: Internal diameter of the hose, starting at 33. Min 20, max 100, steps of 1.
*   **`fan_outer_dia`**: Thickness of the fan shroud, min of 1, max of 20, steps of 1.
*   **`fan`**: Length (width really) of the fan, starting at 120 and also adjustable like `xwide`.
*   **`air_filter_dia`**: Diameter of the air filter, starting at 190mm, with a minimum of 100 and a maximum of 300 in steps of 10.
*   **`resolution`**: Resolution of the cylinder, starting at 44, min of 12, max of 88, steps of 4.

The design should have a few key parts:

1.  A base ring that sits on the air filter's rubber ring.
2.  A box structure to hold the fan, with walls connecting the base and the top plate.
3. A top plate with a circular cutout for the hose connector.
4.  A nozzle on the top plate that has both a straight section and a tapered part to improve the seal of the hose, and a few small rings around the top to provide some grip.

I'd like the whole thing to be designed in a single, parametric SCAD file, if that's possible. I don't want to use any external libraries.

[Assistant]
air_blower_case.scad:
```
/* [3D printer air filter settings]*/
// Markham Thomas   Jan 9th, 2018
// Openscad code to generate a fan box to hold a 120mm 12v PC chassis fan
// Uses a shopvac filter (solid plastic on one end and open at the other) 195mm in dia with 20mm rubber ring
// The 120mm fan goes into the fan box and blows into the shopvac filter creating a vacuum.  1 1/4" shopvac hose goes onto the box and into the 3d printer enclosure
// add a small amount to account for shrinkage
shrink_fix = 0.4;       //[0.1:.1:0.6]
// width of the fan on X axis
xwide = 120 + shrink_fix; //[10:5:200]
// width of the fan on Y axis
ywide = 120 + shrink_fix; //[10:5:200]
// wall thickness
thickness = 2;          //[1:1:4]
// height of the fan (vertical) plus dead space (fan size again is good fit)
boxheight = 50;         //[10:10:80]
// diameter of the hose opening (larger than your hose diameter by 30%)
tubecutout = 40;        //[20:1:100]
// diamter of the flexible hose (internal ID, smaller than tubecutout)
plastic_tube_id = 33;   //[20:1:100]
// fan shroud thickness at thinest point
fan_outer_dia = 5;      //[1:1:20]
// square fan assumed, enter fan length (should be same as width)
fan = 120 + shrink_fix; //[10:5:200]
// diameter of the air filter
air_filter_dia = 190;   //[100:10:300]
// resolution of the cylinder used for the vacuum hose
resolution = 44;               //[12:4:88]

$fn = resolution;
translate([air_filter_dia, 0, -boxheight]) {
// rings on tube nozzle to help hold the vacuum hose on
for (i=[0,4,9]) {
    translate([xwide/2,ywide/2,boxheight+18+i]) {
        difference() {
            cylinder(h=2,r=(plastic_tube_id+thickness+2)/2);
            cylinder(h=2,r=(plastic_tube_id)/2);
        }
    }
}

// tube nozzle (tapered part after straight part to help seal)
translate([xwide/2,ywide/2,boxheight]) {
    difference() {
        cylinder(h=20,r1=(tubecutout+thickness)/2,r2=plastic_tube_id/2);
        cylinder(h=20,r1=(tubecutout)/2,r2=(plastic_tube_id-thickness-2)/2);
    }
}

// straight part of tube nozzle
translate([xwide/2,ywide/2,boxheight+18]) {
    difference() {
        cylinder(h=12,r1=plastic_tube_id/2,r2=plastic_tube_id/2);
        cylinder(h=12,r=(plastic_tube_id/2)-thickness);
    }
}

// top plate with tube nozzle cutout
translate([0,0,boxheight]) {
    difference() {
        cube([xwide+thickness*2,ywide+thickness*2,thickness]);
        translate([xwide/2,ywide/2,0]) cylinder(r=tubecutout/2,h=thickness);
    }
}
}
// Note: had to adjust to get the box edges to meet up.  I adjusted by 2mm so if you change the thickness adjust this value also
// origin X wall
cube([xwide+thickness,thickness, boxheight]);
// origin Y wall
cube([thickness,ywide+thickness,boxheight]);  // wall thickness
// farside from origin X wall
translate([0,ywide+thickness,0]) cube([xwide+thickness,thickness, boxheight]);
// farside from origin Y wall
translate([xwide+thickness,0,0]) cube([thickness,ywide+thickness*2, boxheight]);

// the bottom circular plate that connects to the shopvac rubber ring
difference() {
    translate([xwide/2,ywide/2,0]) cylinder(h=thickness, r=air_filter_dia/2,center=false);
    cube([fan+thickness,fan+thickness,thickness],false);
}
```


[User]
Hey, I'm looking for some help creating a customizable Lego Technic beam generator in OpenSCAD. I've seen some cool stuff out there but I need something more flexible. I want to be able to make L-shaped brackets, T-shaped brackets, intersecting beams with overhang, and enclosed squares.

Here's a breakdown of what I need:

**Basic Beam Properties:**
*   **Pitch:** The distance between holes (8mm).
*   **Hole Radii:** Two radii for the holes, one for the main hole (2.5mm) and one for a countersink (3.05mm), as well as a depth (0.85mm).
*   **Beam Height:** The height of the beam itself (7.8mm).
*   **Beam Depth:** The depth of the countersink (0.85mm)
*   **Beam Width:** The width of the beam (7.3mm).
*   **Plus Width:** The width of the notched part of a plus hole (2mm).
*   **Overhang:** This is a small extension used for the overhanging shape and would be 0.05mm.

**Hole Types:**
*   **Round Holes:** Represented by the character "o"
*   **Plus Holes:** Represented by the character "+" (notched axle hole)
*   **Blank Space:** Represented by any other character (e.g., "x").

**Beam Shapes:**
*   **L-shape:**  Two beams connected at a 90 degree angle.
*   **T-shape:**  Three beams connected, with two on one axis and one perpendicular to them at their center point.
*   **"#" shape:** Two intersecting beams that can have overhang on all four ends - this could probably be more clear, but think of a cross with beams extended out of each end.
*    **O-shape (Square):** Four beams connected to form a closed square shape.
*   **Straight beams:** By setting one of the two hole parameters to a single character, you should be able to produce a straight beam.

**Customization:**

*   **`x_axis_holes`:** A string defining the types of holes along the "horizontal" direction.
*   **`y_axis_holes`:** A string defining the types of holes along the "vertical" direction.
*   **`x_overhang`:** The number of holes the # shape over hangs on the x axis.
*  **`y_overhang`:** The number of holes the # shape over hangs on the y axis.
* All of these parameters should be customizable.

**Output Requirements**
* I would like the final product to be configurable with just a single variable that specifies the shape. For example, "L", "T", "O", or "#", and it should use the strings provided to create the desired shape.
*   The output should be a single solid object.

It would also be great if you could use the MCAD library, which I've used in the past for other projects, and if the code could use the same variable naming conventions I've provided, that would be really helpful for understanding how the generated code works.

Thanks in advance for your help with this! Let me know if anything is unclear.

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

        Super Customizable Lego Technic Beam
        Modified by Christopher Litsinger
        January 2018

        Based on Even More Customizable Straight LEGO Technic Beam
        which in turn was Based on Customizable Straight LEGO Technic Beam
             and Parametric LEGO Technic Beam by "projunk" and "stevemedwin"
        www.thingiverse.com/thing:1119651
        Modified by Sam Kass
        November 2015

        Customizable Straight LEGO Technic Beam
        Based on Parametric LEGO Technic Beam by "projunk"
        www.thingiverse.com/thing:203935
        Modified by Steve Medwin
        January 2015
*/

$fn=50*1.0;

/*  Parameters modified for best print on
    Steve Medwin's Replicator 2 with PLA
    from his original design,
    with Sam Kass' "Plus" measurements
*/

Pitch = 8*1.0;
Radius1 = 5.0/2;
Radius2 = 6.1/2;
Height = 7.8*1.0;
Depth = 0.85*1.0;
Width = 7.3*1.0;
Plus_Width = 2.0*1.0;

Overhang = 0.05*1.0;

/* [Customize] */
//the "shape" of the brick to print: can be L, T, or O. You can also create straight beam by setting the y axis holes to a one character string
beamShape = "#"; // [L, T, O, #]

//The holes to print along the x-axis. This also determined the width of the peice. Use the character "o" (lowercase letter, not the number) to represent a round hole and a "+" (the plus symbol) to represent a notched axle hole. Any other character will create a blank space - I use "x" for readability.
x_axis_holes = "o+xox+o";
//The holes to print along the y-axis. This uses the same symbology as above. You should probably make sure the intersecting symbols match
y_axis_holes = "o+xox+o";
//the number of spaces you want overhanging each intersection along the x axis. This is only processed by the "#" shape
x_overhang = 1;
//the number of spaces you want overhanging each intersection along the y axis. This is only processed by the "#" shape
y_overhang = 2;

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

primaryHoles = x_axis_holes;
secondaryHoles = y_axis_holes;

module hole() {
    union() {
        //core
        cylinder(r=Radius1,h=Height);

        //top countersink
        translate([0,0,Height-Depth+Overhang])
            cylinder(r=Radius2,h=Depth);

        //bottom countersink
        translate([0,0,-Overhang/2])
            cylinder(r=Radius2,h=Depth);

        translate([0,0,Depth-Overhang])
            cylinder(h=(Radius2 - Radius1), r1=Radius2, r2=Radius1);
    }
}

module plus() {
    union() {
        translate([-Plus_Width/2, -Radius1, -Overhang])
            cube([Plus_Width, Radius1*2, Height+Overhang*2]);
        translate([-Radius1, -Plus_Width/2, -Overhang])
            cube([Radius1*2, Plus_Width, Height+Overhang*2]);
    }
}

module drawSolidBeam(holeCount) {
    union() {
        beamLength = (holeCount-1) * Pitch;
        cube([beamLength, Width, Height]);
        //rounded ends are nice
        translate([0, Width/2,0]) {
            cylinder(r=Width/2, h=Height);
        }
        translate([(holeCount-1) * Pitch, Width/2,0]) {
            cylinder(r=Width/2, h=Height);
        }
    }
}

module drawHoles(holePattern) {
    for (holeIndex = [1:len(holePattern)]) {
        translate([(holeIndex-1)*Pitch, Width/2,0]) {
            if (holePattern[holeIndex-1] == "+") {
                plus();
                }
            else if (holePattern[holeIndex-1] == "o") {
                hole();
            }
        }
    }
}

module drawBeam(holePattern) {
    difference() {
        drawSolidBeam(len(holePattern));
        drawHoles(holePattern);
    }
}

module drawBeams(xHoles="+o+", yHoles="+ooo+", shape="T") {
    xLength = (len(xHoles)-1) * Pitch;
    yLength = (len(yHoles)-1) * Pitch;
    yOffset = (shape != "#") ? 0 : -y_overhang * Pitch;
    xOffset = (shape != "#") ? ((shape != "T") ? 0: -xLength/2) : -x_overhang * Pitch;
    union() {
        translate(xOffset,0,100) {
            drawBeam(xHoles);
        }
        translate([Width/2-xOffset,Width/2+yOffset,0]) {
            rotate([0,0,90]) {
                drawBeam(yHoles);
                }
            }
        if ((shape == "U") || (shape == "O") || (shape == "#")) {
            translate([0,yLength+yOffset*2, 0]) {
                drawBeam(xHoles);
            }
        }

        if ((shape == "O") || (shape == "#")) {
            translate([xLength+Width/2+xOffset, Width/2+yOffset, 0]) {
                rotate([0,0,90]) {
                    drawBeam(xHoles);
                }
            }
        }
	}
}

drawBeams(primaryHoles,secondaryHoles,beamShape);

```


[User]
I'd like to create a customizable 2D origami unicorn design that I can cut out of a material like acrylic or wood, based on the Thingiverse model by mightynozzle. It needs to be parametric so I can easily adjust various aspects of the design.

Specifically, I'd like to be able to control:

*   **Overall size:** The longest side (either width or height) of the unicorn should be a parameter that can be set in millimeters, and the other side should scale proportionally. Let's call this `max_size_in_millimeter`.
*   **Model height:** I need to be able to set the thickness of the material I'll be cutting, which should be a parameter named `model_height_in_millimeter`.
*   **Outline thickness:** There should be two outline parameters. The outer outline thickness should be `outline_size_in_millimeter` and the inner outline should be `inline_size_in_millimeter`.
*   **Inner outline roundness:** I'd like to be able to control the roundness of the ends of the inner outlines, which should be the parameter `inline_edge_radius_in_millimeter`.
*   **Flip option:** I need the ability to flip the whole design along the y-axis (a simple mirror), which would be a boolean option of "yes" or "no" called `flip_model`.

The general shape of the unicorn will be based on the coordinates provided in the original SCAD file which is shown below. It would be great if you could handle all of the coordinate calculations for me, since that's a bit tedious to convert into parameters.

```
// Outer Points
A1 = [306, 392];
A2 = [374, 419];
A3 = [687, 642];
A4 = [676, 559];
A5 = [732, 468];
A6 = [757, 509];
A7 = [790, 565];
A8 = [782, 638];
A9 = [863, 581];
A10 = [862, 521];
A11 = [897, 574];
A12 = [1029, 549];
A13 = [1011, 592];
A14 = [1142, 641];
A15 = [1129, 690];
A16 = [1225, 703];
A17 = [1212, 732];
A18 = [1309, 802];
A19 = [1289, 829];
A20 = [1379, 894];
A21 = [1350, 928];
A22 = [1480, 1011];
A23 = [1446, 1061];
A24 = [1534, 1172];
A25 = [1432, 1205];
A26 = [1323, 1235];
A27 = [1142, 1500];
A28 = [908, 1558];
A29 = [954, 1460];
A30 = [952, 1270];
A31 = [805, 1074];
A32 = [738, 1125];
A33 = [649, 1128];
A34 = [561, 1170];
A35 = [500, 1233];
A36 = [416, 1232];
A37 = [349, 1149];
A38 = [365, 1079];
A39 = [565, 825];
A40 = [517, 815];
A41 = [532, 764];
A42 = [598, 698];
A43 = [337, 448];

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, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43];

// Inner Points
B1 = [682, 705];
B2 = [940, 668];
B3 = [1133, 795];
B4 = [884, 854];
B5 = [753, 811];
B6 = [680, 904];
B7 = [586, 890];
B8 = [637, 828];
B9 = [461, 1108];
B10 = [750, 670];
B11 = [377, 453];

// Polygons
C1 = [A43, A1, B11];
C2 = [A1, A2, B11];
C3 = [B11, A2, A3, B1];
C4 = [B1, B11, A43, A42];
C5 = [A4, A5, A6];
C6 = [A6, A7, B10, A4];
C7 = [A7, A8, B10];
C8 = [A4, B10, B1, A3];
C9 = [A8, A9, A10, A11, A12];
C10 = [A8, A12, A13];
C11 = [A8, A13, A14];
C12 = [A8, A14, A15, B2];
C13 = [B2, A15, A16, A17];
C14 = [B2, A17, A18, A19];
C15 = [B2, A19, A20, A21, B3];
C16 = [B3, A21, A22, A23];
C17 = [B3, A23, A24];
C18 = [B3, A24, A25];
C19 = [B3, A25, A26];
C20 = [B3, A26, A27];
C21 = [A28, A29, A27];
C22 = [A29, A30, A27];
C23 = [A30, B4, A27];
C24 = [B4, B3, A27];
C25 = [B4, A8, B2, B3];
C26 = [B10, A8, B4];
C27 = [B4, A30, A31];
C28 = [A31, B5, B4];
C29 = [B5, B10, B4];
C30 = [B1, B10, B5];
C31 = [B1, B5, B8];
C32 = [B8, B5, B6, B7];
C33 = [A39, B8, B7];
C34 = [A39, B1, B8];
C35 = [A39, A40, B1];
C36 = [A40, A41, B1];
C37 = [A41, A42, B1];
C38 = [A39, B7, A38];
C39 = [B7, B6, B9, A38];
C40 = [A38, B9, A37];
C41 = [B9, A36, A37];
C42 = [B9, A35, A36];
C43 = [A35, A34, B9];
C44 = [B9, A33, A34];
C45 = [B9, B6, A33];
C46 = [B6, A32, A33];
C47 = [A32, A31, B6];
C48 = [B6, B5, A31];

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, C27, C28, C29, C30, C31, C32, C33, C34, C35, C36, C37, C38, C39, C40, C41, C42, C43, C44, C45, C46, C47, C48];
```

I'm not asking for any particular libraries here but I assume that OpenSCAD's built in functions are what I should expect to use, unless you think something else is important.

Thanks!

[Assistant]
customizable_origami_unicorn.scad:
```
/*
 * Customizable Origami - Unicorn - https://www.thingiverse.com/thing:2752212
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-01-10
 * 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.6; //[0.5:0.1:20]

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

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.4; //[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 = [306, 392];
A2 = [374, 419];
A3 = [687, 642];
A4 = [676, 559];
A5 = [732, 468];
A6 = [757, 509];
A7 = [790, 565];
A8 = [782, 638];
A9 = [863, 581];
A10 = [862, 521];
A11 = [897, 574];
A12 = [1029, 549];
A13 = [1011, 592];
A14 = [1142, 641];
A15 = [1129, 690];
A16 = [1225, 703];
A17 = [1212, 732];
A18 = [1309, 802];
A19 = [1289, 829];
A20 = [1379, 894];
A21 = [1350, 928];
A22 = [1480, 1011];
A23 = [1446, 1061];
A24 = [1534, 1172];
A25 = [1432, 1205];
A26 = [1323, 1235];
A27 = [1142, 1500];
A28 = [908, 1558];
A29 = [954, 1460];
A30 = [952, 1270];
A31 = [805, 1074];
A32 = [738, 1125];
A33 = [649, 1128];
A34 = [561, 1170];
A35 = [500, 1233];
A36 = [416, 1232];
A37 = [349, 1149];
A38 = [365, 1079];
A39 = [565, 825];
A40 = [517, 815];
A41 = [532, 764];
A42 = [598, 698];
A43 = [337, 448];

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, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43];

// Inner Points
B1 = [682, 705];
B2 = [940, 668];
B3 = [1133, 795];
B4 = [884, 854];
B5 = [753, 811];
B6 = [680, 904];
B7 = [586, 890];
B8 = [637, 828];
B9 = [461, 1108];
B10 = [750, 670];
B11 = [377, 453];

// Polygons
C1 = [A43, A1, B11];
C2 = [A1, A2, B11];
C3 = [B11, A2, A3, B1];
C4 = [B1, B11, A43, A42];
C5 = [A4, A5, A6];
C6 = [A6, A7, B10, A4];
C7 = [A7, A8, B10];
C8 = [A4, B10, B1, A3];
C9 = [A8, A9, A10, A11, A12];
C10 = [A8, A12, A13];
C11 = [A8, A13, A14];
C12 = [A8, A14, A15, B2];
C13 = [B2, A15, A16, A17];
C14 = [B2, A17, A18, A19];
C15 = [B2, A19, A20, A21, B3];
C16 = [B3, A21, A22, A23];
C17 = [B3, A23, A24];
C18 = [B3, A24, A25];
C19 = [B3, A25, A26];
C20 = [B3, A26, A27];
C21 = [A28, A29, A27];
C22 = [A29, A30, A27];
C23 = [A30, B4, A27];
C24 = [B4, B3, A27];
C25 = [B4, A8, B2, B3];
C26 = [B10, A8, B4];
C27 = [B4, A30, A31];
C28 = [A31, B5, B4];
C29 = [B5, B10, B4];
C30 = [B1, B10, B5];
C31 = [B1, B5, B8];
C32 = [B8, B5, B6, B7];
C33 = [A39, B8, B7];
C34 = [A39, B1, B8];
C35 = [A39, A40, B1];
C36 = [A40, A41, B1];
C37 = [A41, A42, B1];
C38 = [A39, B7, A38];
C39 = [B7, B6, B9, A38];
C40 = [A38, B9, A37];
C41 = [B9, A36, A37];
C42 = [B9, A35, A36];
C43 = [A35, A34, B9];
C44 = [B9, A33, A34];
C45 = [B9, B6, A33];
C46 = [B6, A32, A33];
C47 = [A32, A31, B6];
C48 = [B6, B5, A31];

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, C27, C28, C29, C30, C31, C32, C33, C34, C35, C36, C37, C38, C39, C40, C41, C42, C43, C44, C45, C46, C47, C48];

min_x = A1[0];
min_y = A1[1];
max_x = A24[0];
max_y = A28[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]
I need a parametric OpenSCAD design for a spray can guard, something to put over a can of hairspray to protect my 3D printer when I use the hairspray for bed adhesion. I'd like to be able to adjust the parameters for different sized cans.

Specifically, the design should consist of a ring that fits snugly around the top of the can, with a slightly larger stopper ring on top of that. There should be a funnel extending from the side of the ring, angling downwards. The funnel should have an opening towards the bottom so the spray comes out only down towards the build plate. Finally, there should be a cutout on the side of the main ring where the spray nozzle will be, and a corresponding bevel to make sure I can still press the nozzle.

I'd like the following parameters to be configurable:
*   `CanDiameter`: The diameter of the spray can.
*   `HoleFromTop`: The vertical distance from the top of the can to the center of the spray outlet.
*   `FunnelRadius`: The radius of the wide end of the funnel.
*   `FunnelLength`: The length of the funnel.

I do not need any additional libraries. I'd prefer that the design does not rely on any external files. I'd like all the code to be in a single file. I also want to use a very high `$fn` value, say 200, to make the curves look very smooth.

[Assistant]
SprayGuard.scad:
```
// ****************************************************************************
// Spray Guard - put this on hair spray cans to protect the printer
// Author: Peter Holzwarth
// ****************************************************************************
// https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language

CanDiameter= 49;
HoleFromTop= 14;
FunnelRadius= 50;
FunnelLength= 60;
$fn=200;

SprayGuard();

// ****************************************************************************
// Spray Guard
// ****************************************************************************
module SprayGuard() {
    r= CanDiameter/2;
    difference() {
        union() {
            // Ring around the can
            CanRing(2,40);
            // Smaller stopper ring at the top
            translate([0,0,40]) CanRing(4,2);
            // Make sure there is no hole above the can cover
            intersection() {
                CanRing(2,80);
                translate([0,0,7]) rotate([0,-90,0]) FunnelAdd();
            }
        }
        // beveling to reach the spray button
        translate([0,-r-2.01,40]) rotate([0,40,0]) translate([-10,0,0])
            cube([CanDiameter,CanDiameter+4.02,CanDiameter]);
        // Spray out opening
        translate([-r-2,0,40-HoleFromTop]) rotate([0,90,0]) cylinder(r=5,h=10);
    }
    difference() {
        translate([0,0,7]) rotate([0,-90,0]) SprayFunnel();
        // remove can space
        cylinder(r=r,h=60);
    }
}

// The ring around the can
module CanRing(th, h) {
    pipe(CanDiameter/2+2,th,h);
}

// The front side funnel
module SprayFunnel() {
    intersection() {
        // Spray funnel
        difference() {
            FunnelAdd();
            FunnelRem();
        }
        // rounded "cap style"
        translate([FunnelLength,FunnelLength,0]) rotate([90,0,0])
            cylinder(r= FunnelLength,h= 2*FunnelLength);
    }
}

module FunnelAdd() {
    cylinder(r1=20,r2=FunnelRadius,h=FunnelLength);
}

module FunnelRem() {
    translate([0,0,-0.01]) cylinder(r1=18,r2=FunnelRadius-2,h=FunnelLength+0.02);
}

// ////////////////////////////////////////////////////////////////
// a pipe - a hollow cylinder
module pipe(outerRadius, thickness, height) {
    difference() {
        cylinder(h=height, r=outerRadius);
        translate([0, 0, -0.1]) cylinder(h=height+0.2, r=outerRadius-thickness);
    }
}
```


[User]
I'd like a parametric OpenSCAD design for a 2D origami lion, similar to the one described on Thingiverse. The design should allow for adjustments to the overall size, the height of the model, and the thickness of both the outer and inner outlines. Specifically:

*   **Overall Size:** The design should be scalable, allowing the user to set a maximum size for the longest side of the lion. The shorter side should automatically scale in proportion.
*   **Height:**  The height of the 2D model should be adjustable to allow for different thicknesses when 3D printing, or when creating a layered design.
*   **Outline Thickness:** The outer and inner outline thicknesses should be independently customizable.
*   **Inner Outline Edges:** The ends of the inner outlines should have adjustable roundness (fillets).
*   **Mirroring:** It should be possible to flip or mirror the design along the y-axis.
*   **Polygon Data:** The design will need to use hardcoded 2D point data for both the outer outline and internal cut polygon shapes. I'll provide that data now, exactly as it is provided in the existing Thingiverse file:

```
// Outer Points
A1 = [327, 438];
A2 = [479, 345];
A3 = [498, 281];
A4 = [731, 237];
A5 = [711, 290];
A6 = [938, 343];
A7 = [905, 379];
A8 = [1199, 487];
A9 = [1340, 454];
A10 = [1453, 427];
A11 = [1588, 510];
A12 = [1569, 518];
A13 = [1585, 575];
A14 = [1675, 556];
A15 = [1661, 630];
A16 = [1555, 642];
A17 = [1479, 531];
A18 = [1446, 539];
A19 = [1455, 595];
A20 = [1434, 803];
A21 = [1322, 965];
A22 = [1249, 965];
A23 = [1248, 935];
A24 = [1286, 915];
A25 = [1309, 821];
A26 = [1262, 738];
A27 = [813, 768];
A28 = [804, 849];
A29 = [736, 965];
A30 = [635, 965];
A31 = [632, 950];
A32 = [682, 922];
A33 = [699, 784];
A34 = [644, 706];
A35 = [488, 658];
A36 = [452, 504];
A37 = [368, 523];

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, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37];

// Inner Points
B1 = [560, 586];
B2 = [687, 620];
B3 = [760, 604];
B4 = [940, 496];
B5 = [810, 410];
B6 = [677, 452];
B7 = [721, 504];
B8 = [627, 414];

// Polygons
C1 = [A3, A4, A5, B8];
C2 = [A3, B8, B1, A2];
C3 = [A2, B1, A35, A36];
C4 = [A1, A2, A36, A37];
C5 = [B8, B6, B7, B2, A34, B1];
C6 = [B1, A34, A35];
C7 = [A34, B2, B3, A27, A28, A33];
C8 = [A28, A29, A32, A33];
C9 = [B2, B3, B4, B5, B6, B7];
C10 = [B8, A5, A6, A7, B5, B6];
C11 = [A7, A8, A26, A27, B3, B4, B5];
C12 = [A8, A9, A19, A20, A25, A26];
C13 = [A20, A21, A24, A25];
C14 = [A9, A10, A11, A12, A13, A16, A17, A18];
C15 = [A13, A14, A15, A16];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15];
```

It would be best if the code was well-commented so it's easy to understand. I don't think any libraries are needed for this, just standard OpenSCAD functionality.

[Assistant]
customizable_origami_lion.scad:
```
/*
 * Customizable Origami - Lion - https://www.thingiverse.com/thing:2753473
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-01-11
 * 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.7; //[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 = [327, 438];
A2 = [479, 345];
A3 = [498, 281];
A4 = [731, 237];
A5 = [711, 290];
A6 = [938, 343];
A7 = [905, 379];
A8 = [1199, 487];
A9 = [1340, 454];
A10 = [1453, 427];
A11 = [1588, 510];
A12 = [1569, 518];
A13 = [1585, 575];
A14 = [1675, 556];
A15 = [1661, 630];
A16 = [1555, 642];
A17 = [1479, 531];
A18 = [1446, 539];
A19 = [1455, 595];
A20 = [1434, 803];
A21 = [1322, 965];
A22 = [1249, 965];
A23 = [1248, 935];
A24 = [1286, 915];
A25 = [1309, 821];
A26 = [1262, 738];
A27 = [813, 768];
A28 = [804, 849];
A29 = [736, 965];
A30 = [635, 965];
A31 = [632, 950];
A32 = [682, 922];
A33 = [699, 784];
A34 = [644, 706];
A35 = [488, 658];
A36 = [452, 504];
A37 = [368, 523];

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, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37];

// Inner Points
B1 = [560, 586];
B2 = [687, 620];
B3 = [760, 604];
B4 = [940, 496];
B5 = [810, 410];
B6 = [677, 452];
B7 = [721, 504];
B8 = [627, 414];

// Polygons
C1 = [A3, A4, A5, B8];
C2 = [A3, B8, B1, A2];
C3 = [A2, B1, A35, A36];
C4 = [A1, A2, A36, A37];
C5 = [B8, B6, B7, B2, A34, B1];
C6 = [B1, A34, A35];
C7 = [A34, B2, B3, A27, A28, A33];
C8 = [A28, A29, A32, A33];
C9 = [B2, B3, B4, B5, B6, B7];
C10 = [B8, A5, A6, A7, B5, B6];
C11 = [A7, A8, A26, A27, B3, B4, B5];
C12 = [A8, A9, A19, A20, A25, A26];
C13 = [A20, A21, A24, A25];
C14 = [A9, A10, A11, A12, A13, A16, A17, A18];
C15 = [A13, A14, A15, A16];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15];

min_x = A1[0];
min_y = A4[1];
max_x = A14[0];
max_y = A22[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 an OpenSCAD design for a paperclip, but I want it to be fully parametric so I can easily adjust the dimensions. I've got a few specific parameters in mind.

Firstly, I'd like to define the overall length of the clip. Then, I need to be able to specify the clip's width as a percentage of that overall length. The thickness of the wire should also be configurable, of course. I also need to control the position of the center loop along the length as a percentage of the total length, as well as the lengths of the start and end wire pieces, again as percentages of the total length.

I'm picturing a standard paperclip shape, with a left loop, a right loop, and a center loop connecting the left and right sides. The wire then continues out from either side of the clip.

Could you generate the OpenSCAD code that lets me control all these parameters? I don't need any external libraries. Thanks!

[Assistant]
paperclip-build.scad:
```
/* [Paperclip Specs] */

//length of clip (mm)
clip_length = 70;

//height of clip as a percentage of total length
clip_width_percentage = 25; //[1:100]

//Thickness of wire
wire_diameter = 2;

//Centre curve position as a percentage of total length (from left)
centre_loop_percent_offset = 45; //[1:100]

//Wire end position as a percentage of total length
end_wire_length_percent = 50; //[1:100]

//Wire start position as a percentage of total length
start_wire_length_percent = 70; //[1:100]

/* [Hidden] */
clip_width = clip_length * (clip_width_percentage / 100);

ll_out_r = clip_width / 2;
ll_out_x = clip_width / 2;
ll_out_y = clip_width / 2;

ll_in_r = (clip_width / 2) - wire_diameter;
ll_in_x = ll_out_x;
ll_in_y = ll_out_y;

rl_out_r = ll_out_r -  wire_diameter;
rl_out_x = clip_length - rl_out_r;
rl_out_y = clip_width - rl_out_r;

rl_in_r =  rl_out_r - wire_diameter;
rl_in_x = rl_out_x;
rl_in_y = rl_out_y;

cl_out_r = rl_out_r -  wire_diameter;
cl_out_x = ((centre_loop_percent_offset) / 100) * clip_length;
cl_out_y = rl_out_y - wire_diameter;

cl_in_r = rl_out_r - wire_diameter - wire_diameter;
cl_in_x = cl_out_x;
cl_in_y = cl_out_y;

arm_1_w = clip_length - ll_out_r - rl_out_r;
arm_1_h = wire_diameter;
arm_1_x = ll_out_r;
arm_1_y = clip_width - wire_diameter;

arm_2_w = (clip_length - cl_in_x) * (end_wire_length_percent / 100);
arm_2_h = wire_diameter;
arm_2_x = cl_in_x;
arm_2_y = cl_in_y + cl_in_r;

arm_3_w = (clip_length - cl_out_x - rl_out_r);
arm_3_h = wire_diameter;
arm_3_x = arm_2_x;
arm_3_y = arm_2_y - (cl_in_r * 2) - wire_diameter;

arm_4_w = (clip_length - ll_out_r) * (start_wire_length_percent / 100);
arm_4_h = wire_diameter;
arm_4_x = rl_out_r + wire_diameter;
arm_4_y = 0;
module left_loop() {
    difference() {
        difference() {
            translate([ll_out_x, ll_out_y, 0])
                cylinder(wire_diameter, ll_out_r, ll_out_r, false);

            translate([ll_in_x, ll_in_y, -1])
                cylinder(wire_diameter+2, ll_in_r, ll_in_r, false);
        }

        translate([ll_out_x, 0, -ll_out_r])
            cube(ll_out_r * 2);
    }
}

module right_loop() {
    difference() {
        difference() {
            translate([rl_out_x, rl_out_y, 0])
                cylinder(wire_diameter, rl_out_r, rl_out_r, false);

            translate([rl_in_x, rl_in_y, -1])
                cylinder(wire_diameter+2, rl_in_r, rl_in_r, false);
        }
        translate([clip_length - (rl_out_r * 3), clip_width-(rl_out_r*2), -rl_out_r])
            cube(rl_out_r * 2);
    }

}

module centre_loop() {
    difference() {
        difference() {
            translate([cl_out_x, cl_out_y, 0])
                cylinder(wire_diameter, cl_out_r, cl_out_r, false);

            translate([cl_in_x, cl_in_y, -1])
                cylinder(wire_diameter+2, cl_in_r, cl_in_r, false);
        }

        translate([cl_out_x, (cl_out_y-cl_out_r), -cl_out_r])
            cube(cl_out_r * 2);
    }
}

module arm_1() {
    translate([arm_1_x, arm_1_y, 0])
        cube([arm_1_w, arm_1_h, wire_diameter]);
}

module arm_2() {
    translate([arm_2_x, arm_2_y, 0])
        cube([arm_2_w, arm_2_h, wire_diameter]);
}

module arm_3() {
    translate([arm_3_x, arm_3_y, 0])
        cube([arm_3_w, arm_3_h, wire_diameter]);
}

module arm_4() {
    translate([arm_4_x, arm_4_y, 0])
        cube([arm_4_w, arm_4_h, wire_diameter]);
}

union() {
    left_loop();
    right_loop();
    centre_loop();
    arm_1();
    arm_2();
    arm_3();
    arm_4();
}

```


[User]
Hi, I'm looking for some help designing a parametric label holder that clips onto wire shelving, specifically the kind used in ClosetMaid systems. I've got some measurements and a basic idea of how it should work, but I need it to be flexible enough to handle different label widths.

Here’s the breakdown:

*   **Label Area:** The label itself should be recessed slightly. I'm using Brother label tape, which is typically 12mm high. I want a small ridge around the label area so it's slightly inset. There should be a little space at the top and bottom of the label area as well.
*   **Clips:** The clips will need to grab onto the wires of the shelving. ClosetMaid wire shelves usually have wires about 3.4 mm in diameter, so I'd want to account for that with a little extra tolerance. The clips need to be spaced such that they are always behind the label area and line up with the wire spacing, which is roughly 16mm center-to-center. The number of clips needed should be based on the overall width of the label holder, maximizing the spacing between the clips. The clip itself is a curved arc that wraps around the wire. I'm not sure if it's better to model that using a `linear_extrude` or a `rotate_extrude`, but I want to be sure the tolerances will allow it to work. I will need to define the wall thickness, too.
*   **General Construction:** The label holder should be a flat plate with the clips mounted on the back. It's important that the entire thing is printable and robust - I'm guessing at a minimum 1.5 mm wall thickness.

I'd like to be able to adjust the following parameters:

*   `width`: The total width of the label holder
*   `label_ht`: The height of the label tape (12 mm is standard)
*   `ridge`: The width of the ridge around the label
*  `thickness`: The thickness of the main plate
*   `clip_width`: The depth/width of the clip
*  `wall_thickness`: The thickness of the walls for the clip
*   `wire_diameter`: The diameter of the wire on the shelf (around 3.5mm)
*   `clip_spacing`: The standard 16 mm spacing

I'm hoping you can provide me with the OpenSCAD code for this. I'd like it to be parametric and easily customizable for different label sizes. I would prefer it all in one .scad file if possible. I do not need you to use any external libraries or files. Thanks!

[Assistant]
ClosetMaid_clip_R1.scad:
```
//Width of the clip (mm)
width = 76.2;  // label width (mm)

//Height of the label maker tape (standard Brother is 12 mm)
label_ht = 12; //standard size is 12 mm for a Brother Label

ridge = 2*1; //width of the ridge around the label
height = label_ht + 2* ridge + 2; // 1 mm for top and bottom and additional for ridge
thickness = 2*1; //thickness (mm) of the plate
clip_width = 4*1;
clip_spacing = 16*1;
wire_diameter = 3.5*1; // ClosetMaid standard width is 3.4 mm (#10 BWG) (0.1 mm for tolerance)
wall_thickness = 1.5*1; // wall thickness of clip (mm)

//establish the number of wires to maximize the spacing of the clips
spacing = floor(width/clip_spacing);

num_wire_spacing = spacing > (width -2*(wire_diameter/2+wall_thickness))/clip_spacing ? spacing -1 : spacing;

//combine the clip and plate
union(){
//create the plate for the label
difference(){
linear_extrude(height = thickness) square([width,height]);
translate([ridge,ridge,thickness -0.5]) linear_extrude(height=0.5) square([width-ridge*2,height-ridge*2]);
}

//create the dual clips
translate([(width-clip_spacing*num_wire_spacing)/2,0,0]) union(){
translate([num_wire_spacing*clip_spacing,(height-clip_width)/2,thickness-0.5]) rotate([0,90,90]) standard_clip(clip_spacing, clip_width, wire_diameter, wall_thickness);

translate([0,(height-clip_width)/2,thickness-0.5]) rotate([0,90,90]) standard_clip(clip_spacing, clip_width, wire_diameter, wall_thickness);
}

}

//create a standard clip
module standard_clip(clip_spacing, clip_width, wire_diameter, wall_thickness){

translate([wire_diameter/2+wall_thickness,0,0]) union(){
arc(wall_thickness,clip_width,wire_diameter/2+wall_thickness,180);
rotate([0,0,30]) arc(wall_thickness,clip_width,wire_diameter/2+wall_thickness,30);
rotate([0,0,180]) arc(wall_thickness,clip_width,wire_diameter/2+wall_thickness,30);
}
}

/*
 * Excerpt from...
 *
 * Parametric Encoder Wheel
 *
 * by Alex Franke (codecreations), March 2012
 * http://www.theFrankes.com
 *
 * Licenced under Creative Commons Attribution - Non-Commercial - Share Alike 3.0
*/

module arc( height, depth, radius, degrees ) {
    // This dies a horible death if it's not rendered here
    // -- sucks up all memory and spins out of control
    render() {
        difference() {
            // Outer ring
            rotate_extrude($fn = 100)
                translate([radius - height, 0, 0])
                    square([height,depth]);

            // Cut half off
            translate([0,-(radius+1),-.5])
                cube ([radius+1,(radius+1)*2,depth+1]);

            // Cover the other half as necessary
            rotate([0,0,180-degrees])
            translate([0,-(radius+1),-.5])
                cube ([radius+1,(radius+1)*2,depth+1]);

        }
    }
}
```


[User]
Hey, I need an OpenSCAD design for a customizable project box, and I'd like to make sure it's parametric. I've got some pretty specific needs, and I'd really appreciate it if you could help me get this right. I've got two SCAD files here that do almost what I want, but I need to merge the functionality from both of them. I would also like to be able to do this from scratch without needing to download and modify these files.

First off, I need to be able to specify the box's overall width and depth (X and Y dimensions), and also the height. I also need to specify a wall thickness - it'll be the same for all the walls.  I'll also want to have an adjustable setting to control for plastic shrinkage, so if you could add a shrink compensation variable, that'd be great.

I want the option of having internal mounting posts, too, and these are pretty important. They should be cylindrical, and I need to be able to set their diameters, their heights, and the diameter of the screw holes in the posts.  I also need to be able to position them. There will always be four posts in the corners. The way I'm used to defining their positions is by their offsets from their *nearest* sidewalls. So, post #1 is nearest to the origin, and it has x and y offsets from the X and Y axis walls, respectively. Then, we move clockwise around the box, so post #2 has offsets from the X and Y axis walls, and so on. Could you make sure to implement the positions this way?

Additionally, I need to be able to specify cutouts in each of the four side walls. Each cutout will be a rectangle and should be measured from the nearest origin, but from the wall thickness itself not the outside edge. So, I need the x and z position of the bottom left corner (or the bottom right depending on the side wall) of the cutout, the width and height of the cutout. I need this to be independent for each wall; that is, cutouts don't have to be the same size. I need to be able to enable or disable cutouts for each sidewall as well.

Finally, I want options for ventilation holes on both the base and lid, and I need to be able to control whether there is a lid or not. If you could use linear vent slots along the length of each plate for the vents, that'd be awesome. Also, I need a chamfer option, so that I can specify an amount to chamfer all the edges of the box and the lid.

I think that's all I need. Could you generate the OpenSCAD code for this? I don't need any special libraries for this, I don't think.

[Assistant]
generic_case_chamf.scad:
```
/* [Generic case generator settings]*/
// Markham Thomas   Jan 10th, 2018
// Version 1.2
// Updated: Jan 17th, 2018 to support chamfering
// Updated: Jan 13th, 2018 to support cutouts (holes) in all 4 side-walls
// Openscad code to generate a project case with mounting screw holes
// add a small amount to account for shrinkage
// The post numbering is:   (where zero is the origin)
//   Y   ------------
//   Y   | 2        3 |
//   Y   | 1        4 |
//   Y   -------------|
//   OXXXXXXXXXXXX
// NOTE: each post if they exist are measured from their closest wall for both x and y distances
shrink_fix = 0.5;       //[0.1:0.1:0.6]
// width of the case along X axis
xwidth = 85; //[10:5:200]
// width of the case along Y axis
ywidth = 57; //[10:5:200]
// case wall thickness
thickness = 2;          //[1:1:4]
// case height (if need outside height exact add thickness to this value)
caseheight = 12;         //[5:5:100]
// select if support posts needed (offsets are measured from inside wall to center of post)
posts = 1; //[0:false,1:true]
// select if air vents wanted in baseplate
base_plate_vents = 1; //[0:false,1:true]
// select if air vents wanted in top plate
top_plate_vents = 1; //[0:false,1:true]
// resolution of the cylinder used for the the posts inside the case
resolution = 28;               //[12:4:88]
//The X offset of post #1 from its closest Y wall (post nearest the origin)
xpost1_offset = 4;   //[1:0.5:100]
//The Y offset of post #1 from its closets X wall (post closest to origin)
ypost1_offset = 4;   //[1:0.5:100]
//The X offset of post #2 from its closest Y wall (clockwise from 1st)
xpost2_offset = 4;   //[1:0.5:100]
//The Y offset of post #2 from its closest X wall (clockwise from 1st)
ypost2_offset = 4;  //[1:0.5:100]
//The X offset of post #3 from its closest Y wall (clockwise from 2nd)
xpost3_offset = 25;   //[1:0.5:100]
//The Y offset of post #3 from its closets X wall (clockwise from 2nd)
ypost3_offset = 4;    //[1:0.5:100]
//The X offset of post #4 from its closest Y wall (clockwise from 3rd)
xpost4_offset = 25;   //[1:0.5:100]
//The Y offset of post #4 from its closest X wall (clockwise from 3rd)
ypost4_offset = 4;  //[1:0.5:100]
//Diameter of post
post_dia = 5;     //[1:0.5:5]
//diameter of screw hole in the post
post_hole_dia = 3;  //[1:0.5:4]
//height of the post
post_height = 5;    //[2:0.5:10]
//select if a lid is wanted
lid = 1; //[0:false,1:true]
//select true if you wanted chamfered edges
chamfer = 1;//[0:false,1:true]
//amount of chamfer (keep it small)
cham_val = 0.2;//[0.1:0.1:0.5]
/* [Cutouts] */
//Cutouts are all measured from the nearest origin wall - thickness of that wall
//Select true if cutouts are wanted on the X wall that's along the X axis
Xorig_cutout = 0; //[0:false,1:true]
//Select true if cutouts are wanted on the X wall away from the X axis
Xfar_cutout = 0; //[0:false,1:true]
//Select true if cutouts are wanted on the Y wall that's along the Y axis
Yorig_cutout = 0; //[0:false,1:true]
//Select true if cutouts are wanted on the Y wall away from the Y axis
Yfar_cutout = 1; //[0:false,1:true]
//Xorig_cutout bottom left X value
Xorig_cutout_bleft_x = 3; //[5:1:100]
//Xorig_cutout bottom left Z height above base - thickness
Xorig_cutout_bleft_z = 1; //[5:1:100]
//Xorig_cutout width on X axis
Xorig_cutout_width_x = 80; //[5:1:100]
//Xorig cutout height on Z axis
Xorig_cutout_height_z = 6; //[5:1:100]
//Xfar_cutout bottom right X value (facing the far X wall from outside the box)
Xfar_cutout_bright_x = 3; //[5:1:100]
//Xfar_cutout bottom right Z height above base - thickness
Xfar_cutout_bright_z = 2; //[5:1:100]
//Xfar_cutout width on X axis
Xfar_cutout_width_x = 80; //[5:1:100]
//Xfar_cutout height on Z axis
Xfar_cutout_height_z = 6; //[5:1:100]
//Yorig_cutout bottom right Y value
Yorig_cutout_bright_y = 3; //[5:1:100]
//Yorig_cutout bottom left Z height above base - thickness
Yorig_cutout_bright_z = 0; //[5:1:100]
//Yorig_cutout width on Y axis
Yorig_cutout_width_y = 52; //[5:1:100]
//Yorig cutout height on Z axis
Yorig_cutout_height_z = 10; //[5:1:100]
//Yfar_cutout bottom right Y value
Yfar_cutout_bleft_y = 3; //[5:1:100]
//Yfar_cutout bottom left Z height above base - thickness
Yfar_cutout_bleft_z = 0; //[5:1:100]
//Yfar_cutout width on Y axis
Yfar_cutout_width_y = 52; //[5:1:100]
//Yfar cutout height on Z axis
Yfar_cutout_height_z = 10; //[5:1:100]

xwide = xwidth + shrink_fix;
ywide = ywidth + shrink_fix;

// chamfered edges
module mcube(v=[1,1,1],b=1) {
    if (chamfer) {
        translate([v[0]/2,v[1]/2,v[2]/2]) {
            hull() {        // use hull and sweep a sphere past the object
                for(x=[-(v[0]/2-b),(v[0]/2-b)]){
                    for(y=[-(v[1]/2-b),(v[1]/2-b)]){
                        for(z=[-(v[2]/2-b),(v[2]/2-b)]) {
                            translate([x,y,z]) sphere(b);
                        }
                    }
                }
            }
        }
    } else {
        cube([v[0],v[1],v[2]]);
    }
}

$fn = resolution;
// origin X wall
if (Xorig_cutout) {
    difference() {
        mcube([xwide+thickness,thickness, caseheight],cham_val);
        translate([Xorig_cutout_bleft_x + thickness,0,Xorig_cutout_bleft_z+thickness]) cube([Xorig_cutout_width_x,thickness,Xorig_cutout_height_z]);
    }
} else {
    mcube([xwide+thickness*2,thickness, caseheight],cham_val);
}
// X wall opposite the origin X wall, bottom right of cutout facing the wall, measure from origin Y
if (Xfar_cutout) {
    translate([0,ywide+thickness,0]) {
        difference() {
            mcube([xwide+thickness,thickness, caseheight],cham_val);
            translate([Xfar_cutout_bright_x + thickness,0,Xfar_cutout_bright_z+thickness]) cube([Xfar_cutout_width_x,thickness,Xfar_cutout_height_z]);
        }
    }
} else {
    // farside from origin X wall
    translate([0,ywide+thickness,0]) mcube([xwide+thickness*2,thickness, caseheight],cham_val);
}
// Origin Y wall, measure from origin so bottom right of cutout box
if (Yorig_cutout) {
    difference() {
        mcube([thickness,ywide+thickness*2, caseheight],cham_val);
        translate([0,Yorig_cutout_bright_y+thickness,Yorig_cutout_bright_z+thickness]) cube([thickness,Yorig_cutout_width_y,Yorig_cutout_height_z]);
    }
} else {
    mcube([thickness,ywide+thickness*2, caseheight],cham_val);
}
// Y wall opposite the Origin Y wall, measure from X-axis so bottom left coords of cutout box
if (Yfar_cutout) {
    translate([xwide+thickness,0,0]) {
        difference() {
            mcube([thickness,ywide+thickness*2, caseheight],cham_val);
            translate([0,Yfar_cutout_bleft_y+thickness,Yfar_cutout_bleft_z+thickness]) cube([thickness,Yfar_cutout_width_y,Yfar_cutout_height_z]);
        }
    }
} else {
    // farside from origin Y wall
    translate([xwide+thickness,0,0]) mcube([thickness,ywide+thickness*2, caseheight],cham_val);
}

// offset can be zero if near origin, or further if we are doing the lid (xwide*10)
module vent(length, width, offset) {
    for (a=[0:4:20]) {
        translate([offset+length/2+thickness,a+ywide/3,0]) cube([length, width, thickness]);
    }
}

// base plate of project box
if (base_plate_vents) {
    difference() {
        mcube([xwide+thickness*2, ywide + thickness*2,thickness],cham_val);
        vent(xwide/2,2,0);
    }
} else {
    mcube([xwide+thickness*2, ywide + thickness*2,thickness],cham_val);
}

module post(post_d,hole_d,post_h) {
    difference() {
        cylinder(r=post_d/2,h=post_h,center=false);
        cylinder(r=hole_d/2,h=post_h,center=false);
    }
}

// post offsets are all measured from their closest 2 walls in X and Y
if (posts) {
    translate([xpost1_offset+thickness,ypost1_offset+thickness,thickness]) post(post_dia,post_hole_dia,post_height);
    translate([xpost2_offset+thickness,(ywide+thickness)-ypost2_offset,thickness]) post(post_dia,post_hole_dia,post_height);
    translate([(xwide+thickness)-xpost3_offset,(ywide+thickness)-ypost3_offset,thickness]) post(post_dia,post_hole_dia,post_height);
    translate([(xwide+thickness)-xpost4_offset,ypost4_offset+thickness,thickness]) post(post_dia,post_hole_dia,post_height);
}

// lid is a module so we can diff vents if needed
module lid() {
    translate([xwide+thickness*10,0,0]) {
        mcube([xwide+thickness*2,ywide+thickness*2,thickness],cham_val);          // lid
        difference() {                                                  // lid inner ribs
            translate([thickness+shrink_fix/2,thickness+shrink_fix/2,thickness]) cube([xwide-shrink_fix,ywide-shrink_fix,thickness]);
            translate([thickness*2,thickness*2,thickness]) cube([xwide-thickness*2,ywide-thickness*2,thickness]);
        }
    }
}

// lid has ribs that should help it stick onto the top of the project box
if (lid && top_plate_vents) {
        difference() {
            lid();
            vent(xwide/2,2,xwide+thickness*10);
        }
} else {
    lid();
}

```
generic_case.scad:
```
/* [Generic case generator settings]*/
// Markham Thomas   Nov 12th, 2018
// Defaults are now for Raspberry PI 3+
// Version 1.4
// Updated: Nov 12th, 2018 defaults to RPI 3, bug fix for corner post measurements
//   (now each corner post is properly measured from its closest PCB edge to hole center
// Updated: Feb 14th, 2018 bug fix on post3
// Updated: Jan 17th, 2018 to support chamfering
// Updated: Jan 13th, 2018 to support cutouts (holes) in all 4 side-walls
// Openscad code to generate a project case with mounting screw holes
// add a small amount to account for shrinkage
// The post numbering is:   (where zero is the origin)
//   Y   ------------
//   Y   | 2        3 |
//   Y   | 1        4 |
//   Y   -------------|
//   OXXXXXXXXXXXX
// NOTE: each post if they exist are measured from their closest wall for both x and y distances
shrink_fix = 0.5;       //[0.1:0.1:0.6]
// width of the case along X axis
// typically for a rectangle make the Xwidth the long side
xwidth = 87; //[10:5:200]
// width of the case along Y axis
ywidth = 58; //[10:5:200]
// case wall thickness
thickness = 2;          //[1:1:4]
// case height (if need outside height exact add thickness to this value)
caseheight = 24;         //[5:5:100]
// select if support posts needed (offsets are measured from inside wall to center of post)
posts = 1; //[0:false,1:true]
// select if air vents wanted in baseplate
base_plate_vents = 1; //[0:false,1:true]
// select if air vents wanted in top plate
top_plate_vents = 1; //[0:false,1:true]
// resolution of the cylinder used for the the posts inside the case
resolution = 56;               //[12:4:88]
//The X offset of post #1 from its closest Y wall (post nearest the origin)
xpost1_offset = 3.5;   //[1:0.5:100]
//The Y offset of post #1 from its closets X wall (post closest to origin)
ypost1_offset = 3.5;   //[1:0.5:100]
//The X offset of post #2 from its closest Y wall (clockwise from 1st)
xpost2_offset = 3.5;   //[1:0.5:100]
//The Y offset of post #2 from its closest X wall (clockwise from 1st)
ypost2_offset = 3.5;  //[1:0.5:100]
//The X offset of post #3 from its closest Y wall (clockwise from 2nd)
xpost3_offset = 23;   //[1:0.5:100]
//The Y offset of post #3 from its closets X wall (clockwise from 2nd)
ypost3_offset = 3.5;    //[1:0.5:100]
//The X offset of post #4 from its closest Y wall (clockwise from 3rd)
xpost4_offset = 23;   //[1:0.5:100]
//The Y offset of post #4 from its closest X wall (clockwise from 3rd)
ypost4_offset = 3.5;  //[1:0.5:100]
//Diameter of post
post_dia = 6;     //[1:0.5:6]
//diameter of screw hole in the post
post_hole_dia = 3;  //[1:0.5:4]
//height of the post
post_height = 5;    //[2:0.5:10]
//select if a lid is wanted
lid = 1; //[0:false,1:true]
//select true if you wanted chamfered edges
chamfer = 0;//[0:false,1:true]
//amount of chamfer (keep it small)
cham_val = 0.2;//[0.1:0.1:0.5]
/* [Cutouts] */
//Cutouts are all measured from the nearest origin wall - thickness of that wall
//Select true if cutouts are wanted on the X wall that's along the X axis
Xorig_cutout = 1; //[0:false,1:true]
//Select true if cutouts are wanted on the X wall away from the X axis
Xfar_cutout = 0; //[0:false,1:true]
//Select true if cutouts are wanted on the Y wall that's along the Y axis
Yorig_cutout = 1; //[0:false,1:true]
//Select true if cutouts are wanted on the Y wall away from the Y axis
Yfar_cutout = 1; //[0:false,1:true]
//Xorig_cutout bottom left X value
Xorig_cutout_bleft_x = 6; //[1:1:100]
//Xorig_cutout bottom left Z height above base - thickness
Xorig_cutout_bleft_z = 5; //[1:1:100]
//Xorig_cutout width on X axis
Xorig_cutout_width_x = 58; //[1:1:100]
//Xorig cutout height on Z axis
Xorig_cutout_height_z = 10; //[1:1:100]
//Xfar_cutout bottom right X value (facing the far X wall from outside the box)
Xfar_cutout_bright_x = 3; //[1:1:100]
//Xfar_cutout bottom right Z height above base - thickness
Xfar_cutout_bright_z = 2; //[1:1:100]
//Xfar_cutout width on X axis
Xfar_cutout_width_x = 80; //[1:1:100]
//Xfar_cutout height on Z axis
Xfar_cutout_height_z = 4; //[1:1:100]
//Yorig_cutout bottom right Y value
Yorig_cutout_bright_y = 21; //[1:1:100]
//Yorig_cutout bottom left Z height above base - thickness
Yorig_cutout_bright_z = 2; //[1:1:100]
//Yorig_cutout width on Y axis
Yorig_cutout_width_y = 14; //[1:1:100]
//Yorig cutout height on Z axis
Yorig_cutout_height_z = 6; //[1:1:100]
//Yfar_cutout bottom right Y value
Yfar_cutout_bleft_y = 2; //[1:1:100]
//Yfar_cutout bottom left Z height above base - thickness
Yfar_cutout_bleft_z = 0; //[1:1:100]
//Yfar_cutout width on Y axis
Yfar_cutout_width_y = 84; //[1:1:100]
//Yfar cutout height on Z axis
Yfar_cutout_height_z = 24; //[1:1:100]

xwide = xwidth + shrink_fix;
ywide = ywidth + shrink_fix;

// chamfered edges
module mcube(v=[1,1,1],b=1) {
    if (chamfer) {
        translate([v[0]/2,v[1]/2,v[2]/2]) {
            hull() {        // use hull and sweep a sphere past the object
                for(x=[-(v[0]/2-b),(v[0]/2-b)]){
                    for(y=[-(v[1]/2-b),(v[1]/2-b)]){
                        for(z=[-(v[2]/2-b),(v[2]/2-b)]) {
                            translate([x,y,z]) sphere(b);
                        }
                    }
                }
            }
        }
    } else {
        cube([v[0],v[1],v[2]]);
    }
}

$fn = resolution;
// origin X wall
if (Xorig_cutout) {
    difference() {
        mcube([xwide+thickness,thickness, caseheight],cham_val);
        translate([Xorig_cutout_bleft_x + thickness,0,Xorig_cutout_bleft_z+thickness]) cube([Xorig_cutout_width_x,thickness,Xorig_cutout_height_z]);
    }
} else {
    mcube([xwide+thickness*2,thickness, caseheight],cham_val);
}
// X wall opposite the origin X wall, bottom right of cutout facing the wall, measure from origin Y
if (Xfar_cutout) {
    translate([0,ywide+thickness,0]) {
        difference() {
            mcube([xwide+thickness,thickness, caseheight],cham_val);
            translate([Xfar_cutout_bright_x + thickness,0,Xfar_cutout_bright_z+thickness]) cube([Xfar_cutout_width_x,thickness,Xfar_cutout_height_z]);
        }
    }
} else {
    // farside from origin X wall
    translate([0,ywide+thickness,0]) mcube([xwide+thickness*2,thickness, caseheight],cham_val);
}
// Origin Y wall, measure from origin so bottom right of cutout box
if (Yorig_cutout) {
    difference() {
        mcube([thickness,ywide+thickness*2, caseheight],cham_val);
        translate([0,Yorig_cutout_bright_y+thickness,Yorig_cutout_bright_z+thickness]) cube([thickness,Yorig_cutout_width_y,Yorig_cutout_height_z]);
    }
} else {
    mcube([thickness,ywide+thickness*2, caseheight],cham_val);
}
// Y wall opposite the Origin Y wall, measure from X-axis so bottom left coords of cutout box
if (Yfar_cutout) {
    translate([xwide+thickness,0,0]) {
        difference() {
            mcube([thickness,ywide+thickness*2, caseheight],cham_val);
            translate([0,Yfar_cutout_bleft_y+thickness,Yfar_cutout_bleft_z+thickness]) cube([thickness,Yfar_cutout_width_y,Yfar_cutout_height_z]);
        }
    }
} else {
    // farside from origin Y wall
    translate([xwide+thickness,0,0]) mcube([thickness,ywide+thickness*2, caseheight],cham_val);
}

// offset can be zero if near origin, or further if we are doing the lid (xwide*10)
module vent(length, width, offset) {
    for (a=[0:4:20]) {
        translate([offset+length/2+thickness,a+ywide/3,0]) cube([length, width, thickness]);
    }
}

// base plate of project box
if (base_plate_vents) {
    difference() {
        mcube([xwide+thickness*2, ywide + thickness*2,thickness],cham_val);
        vent(xwide/2,2,0);
    }
} else {
    mcube([xwide+thickness*2, ywide + thickness*2,thickness],cham_val);
}

module post(post_d,hole_d,post_h) {
    difference() {
        cylinder(r=post_d/2,h=post_h,center=false);
        cylinder(r=hole_d/2,h=post_h,center=false);
    }
}

// post offsets are all measured from their closest 2 walls in X and Y
if (posts) {
    translate([xpost1_offset+thickness,ypost1_offset+thickness,thickness]) post(post_dia,post_hole_dia,post_height);
    translate([xpost2_offset+thickness,(ywide+thickness)-ypost2_offset,thickness]) post(post_dia,post_hole_dia,post_height);
    translate([(xwide+thickness)-xpost3_offset,(ywide+thickness)-ypost3_offset,thickness]) post(post_dia,post_hole_dia,post_height);
    translate([(xwide+thickness)-xpost4_offset,ypost4_offset+thickness,thickness]) post(post_dia,post_hole_dia,post_height);
}

// lid is a module so we can diff vents if needed
module lid() {
    translate([xwide+thickness*10,0,0]) {
        mcube([xwide+thickness*2,ywide+thickness*2,thickness],cham_val);          // lid
        difference() {                                                  // lid inner ribs
            translate([thickness+shrink_fix/2,thickness+shrink_fix/2,thickness]) cube([xwide-shrink_fix,ywide-shrink_fix,thickness]);
            translate([thickness*2,thickness*2,thickness]) cube([xwide-thickness*2,ywide-thickness*2,thickness]);
        }
    }
}

// lid has ribs that should help it stick onto the top of the project box
if (lid && top_plate_vents) {
        difference() {
            lid();
            vent(xwide/2,2,xwide+thickness*10);
        }
} else {
    lid();
}

```


[User]
I'm looking to generate a customizable 2D origami bison model using OpenSCAD. I want to be able to control the overall size, the thickness of the outer and inner outlines, and the roundness of the inner outline edges. I also need to be able to flip the model horizontally.

Specifically, I'd like to have the following adjustable parameters:

*   `max_size_in_millimeter`: This will determine the maximum length of the longest side of the bison. The other dimension should scale proportionally.
*   `model_height_in_millimeter`: The thickness/height of the final extruded model.
*   `outline_size_in_millimeter`:  The thickness of the outer outline of the bison.
*   `inline_size_in_millimeter`: The thickness of the inner cut lines.
*   `inline_edge_radius_in_millimeter`: The radius of the rounded edges on the inner cut lines.
*   `flip_model`: A boolean/string option to flip the model horizontally.

The design is based on a predefined set of coordinates for the outer shape and the inner cut lines. I'm providing those below (as arrays). It would be ideal to keep the core logic in a module to allow potential reuse/modification.

Outer Points:
```
A1 = [622, 1050];
A2 = [546, 946];
A3 = [500, 970];
A4 = [263, 743];
A5 = [337, 536];
A6 = [461, 498];
A7 = [479, 548];
A8 = [528, 453];
A9 = [516, 411];
A10 = [697, 235];
A11 = [914, 261];
A12 = [1319, 369];
A13 = [1504, 408];
A14 = [1674, 547];
A15 = [1630, 655];
A16 = [1654, 666];
A17 = [1680, 1003];
A18 = [1604, 719];
A19 = [1593, 744];
A20 = [1500, 825];
A21 = [1570, 908];
A22 = [1550, 1200];
A23 = [1523, 1262];
A24 = [1450, 1262];
A25 = [1513, 1211];
A26 = [1490, 956];
A27 = [1490, 886];
A28 = [1443, 867];
A29 = [1347, 784];
A30 = [905, 879];
A31 = [903, 986];
A32 = [878, 994];
A33 = [904, 1138];
A34 = [855, 1217];
A35 = [839, 1262];
A36 = [766, 1262];
A37 = [753, 1251];
A38 = [816, 1197];
A39 = [772, 967];
A40 = [707, 950];
A41 = [625, 727];
A42 = [566, 728];
A43 = [639, 895];
A44 = [606, 918];
```
Inner Points:
```
B1 = [741, 422];
B2 = [918, 719];
B3 = [1321, 728];
B4 = [444, 726];
B5 = [520, 675];
B6 = [447, 621];
B7 = [572, 566];
B8 = [784, 493];
B9 = [815, 547];
```

Polygons (using the above defined points):
```
C1 = [A5, A6, B6, A4];
C2 = [B6, B4, A4];
C3 = [B4, A42, A43, A44, A2, A3, A4];
C4 = [A44, A1, A2];
C5 = [B4, B6, A6, A7, B5];
C6 = [A7, A8, B7, A41, A42, B4, B5];
C7 = [A9, A10, A11, B2, B9, B8, B1];
C8 = [A9, B1, B8, B7, A8];
C9 = [B8, B9, A41, B7];
C10 = [B9, B2, A41];
C11 = [B2, A30, A31, A32, A39, A40, A41];
C12 = [A32, A33, A34, A37, A38, A39];
C13 = [A34, A35, A36, A37];
C14 = [A11, A12, B3, B2];
C15 = [B2, B3, A29, A30];
C16 = [A12, A13, A14, A15, A18, A19, B3];
C17 = [A15, A16, A17, A18];
C18 = [A19, A20, A28, A29, B3];
C19 = [A28, A20, A21, A27];
C20 = [A27, A21, A22, A25, A26];
C21 = [A22, A23, A24, A25];
```

The design should first create a polygon based on the outer points, then cut out the inner polygons.  The inner polygons should have rounded corners. Finally, the whole thing should be extruded to the specified height. I don't need any external libraries for this, I believe this can be achieved with just the core OpenSCAD functionality.

Could you generate the OpenSCAD code for this? Thanks!

[Assistant]
customizable_origami_bison.scad:
```
/*
 * Customizable Origami - Bison - https://www.thingiverse.com/thing:2755003
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-01-12
 * 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.4; //[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 = [622, 1050];
A2 = [546, 946];
A3 = [500, 970];
A4 = [263, 743];
A5 = [337, 536];
A6 = [461, 498];
A7 = [479, 548];
A8 = [528, 453];
A9 = [516, 411];
A10 = [697, 235];
A11 = [914, 261];
A12 = [1319, 369];
A13 = [1504, 408];
A14 = [1674, 547];
A15 = [1630, 655];
A16 = [1654, 666];
A17 = [1680, 1003];
A18 = [1604, 719];
A19 = [1593, 744];
A20 = [1500, 825];
A21 = [1570, 908];
A22 = [1550, 1200];
A23 = [1523, 1262];
A24 = [1450, 1262];
A25 = [1513, 1211];
A26 = [1490, 956];
A27 = [1490, 886];
A28 = [1443, 867];
A29 = [1347, 784];
A30 = [905, 879];
A31 = [903, 986];
A32 = [878, 994];
A33 = [904, 1138];
A34 = [855, 1217];
A35 = [839, 1262];
A36 = [766, 1262];
A37 = [753, 1251];
A38 = [816, 1197];
A39 = [772, 967];
A40 = [707, 950];
A41 = [625, 727];
A42 = [566, 728];
A43 = [639, 895];
A44 = [606, 918];

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, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44];

// Inner Points
B1 = [741, 422];
B2 = [918, 719];
B3 = [1321, 728];
B4 = [444, 726];
B5 = [520, 675];
B6 = [447, 621];
B7 = [572, 566];
B8 = [784, 493];
B9 = [815, 547];

// Polygons
C1 = [A5, A6, B6, A4];
C2 = [B6, B4, A4];
C3 = [B4, A42, A43, A44, A2, A3, A4];
C4 = [A44, A1, A2];
C5 = [B4, B6, A6, A7, B5];
C6 = [A7, A8, B7, A41, A42, B4, B5];
C7 = [A9, A10, A11, B2, B9, B8, B1];
C8 = [A9, B1, B8, B7, A8];
C9 = [B8, B9, A41, B7];
C10 = [B9, B2, A41];
C11 = [B2, A30, A31, A32, A39, A40, A41];
C12 = [A32, A33, A34, A37, A38, A39];
C13 = [A34, A35, A36, A37];
C14 = [A11, A12, B3, B2];
C15 = [B2, B3, A29, A30];
C16 = [A12, A13, A14, A15, A18, A19, B3];
C17 = [A15, A16, A17, A18];
C18 = [A19, A20, A28, A29, B3];
C19 = [A28, A20, A21, A27];
C20 = [A27, A21, A22, A25, A26];
C21 = [A22, A23, A24, A25];

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

min_x = A4[0];
min_y = A10[1];
max_x = A17[0];
max_y = A36[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]
I'd like to create a sign with a tilted base that also includes some text. Here's what I'm thinking:

The sign will have a base that consists of a flat part, a curved corner, then another flat part that's angled upward. Imagine it's like a flat bar that bends, with rounded edges at the bend. I need to be able to specify the thickness of the whole thing, the angle of the tilt, and the radius of the curve. I also need control over the lengths of the flat segments before and after the curve.

Specifically, I need the following parameters:

*   **`thickness`**: The overall thickness of the sign.
*   **`angle`**: The tilt angle in degrees of the angled section.
*   **`R1`**: The outer radius of the curved corner. The inner radius `R2` should just be `R1 - thickness`.
*   **`A`**: The length of the flat base segment before the curve.
*  **`B`**: The length of the tilted flat segment after the curve.
*   **`C`**: The overall width (length) of the sign.
*   **`text`**: The text that will be displayed on the sign.
*   **`font`**: The font to use for the text. I'd like to be able to use a standard system font, such as "Calibri", and ideally, have control over bold and italics (i.e. “Bold”, “Italic”, “Bold Italic” or "Blank" for no style).
*  **`language`**: The language for the text.
*   **`size`**: The size of the text.
*   **`D`**: A vertical shift for the text (to move the text up or down on the face of the sign)

The text needs to be placed on the tilted surface, and it should be centered along the length and also the width of the tilted section, and should be extruded to the specified `thickness`. The sign itself should have a constant `thickness`.

I'd prefer for this to all be in one .scad file. I'm not using any particular libraries and would prefer to avoid that.

[Assistant]
Sign.scad:
```
//Thickness of the plate
thickness = 5;
//Tilt angle in degrees
angle = 130;
//Fillet radius, should have larger value than thickness
R1 = 15;
R2 = R1 - thickness;
//Length of the base part
A = 40;
//Length of the tilt part
B = 20;
//Width of the sign
C = 200;
text = "EXPERIMENT IN PROGRESS";
//Font of the text
font = "Calibri";
language = "en";
//Style of the text, options: Blank, 'Bold', 'Bold Italic', 'Italic'
style = "Bold";
// Size of the text
size = 13;
//Vertical shift of the text
D = 0;

coordR1 = [ for (a1 = [ 0 :1: angle ]) let (b1 = R1*sin(a1), c1 = R1*cos(a1) ) [ b1, c1 ] ];
coordR2 = [ for (a2 = [ 0 :1: angle ]) let (b2 = R2*sin(angle-a2), c2 = R2*cos(angle-a2)) [ b2, c2 ] ];

points=concat(coordR1,[[R1*sin(angle)+A*sin(angle+90),R1*cos(angle)+A*cos(angle+90)],[R2*sin(angle)+A*sin(angle+90),R2*cos(angle)+A*cos(angle+90)]],coordR2,[[-B,R2],[-B,R1]]);

rotate([0, 0, 180])rotate([0, 90, 0])rotate([0, 0, angle-90]) union(){
 linear_extrude(height = C, center = true, convexity = 10, slices = 20, scale = 1.0){
    polygon(points); }

translate([-D-B,R2,0]) rotate([-90, 90, 0]) linear_extrude(height = thickness,  convexity = 10, slices = 20, scale = 1.0){
    text(text, font = str(font,":style=",style), size = size, halign = "center", language = language);  }
}

```


[User]
I'm looking to design some blinders that can clip onto my glasses to block out peripheral light. I've already got a basic design in mind, but I'd like to make it parametric using OpenSCAD so I can easily adjust the fit and dimensions. I'd really appreciate your help in creating the code.

Here's the basic idea:

The blinder has two main parts: a curved shield and a clip. The shield will have a generally curved shape, constructed using the hull of a few cylinders to get a smooth, rounded form. The clip will consist of a horizontal section that wraps around the glasses arm and a vertical section that provides some extra stability. I need to be able to control the size and position of the shield, as well as the dimensions of the clip.

Here are some specific parameters I need to be able to control:

*   **`CORNER_RADIUS`**: The radius of the cylinders used to construct the shield.
*   **`SHEILD_THICKNESS`**: The thickness of the shield.
*   **`CLIP_LENGTH`**: The length of the clip.
*   **`CLIP_THICKNESS`**: The thickness of the clip.
*  **`CLIP_HEIGHT`**: The height of the vertical part of the clip.
*   **`ARM_WIDTH`**: The width of the glasses arm (this will be used to create the correct opening size in the clip).
*  **`MIRROR`**: A boolean value that, when true, mirrors the entire design over the x axis, to create a left-side blinder, otherwise will output the right side.
*  **`ONLY_PRINT_CLIP`**: A boolean value that, when true, will cause the code to only render the clip (not the shield) so that users can quickly iterate on the correct clip size.

The shield's basic form is constructed using a hull of four cylinders with `CORNER_RADIUS` at these approximate positions when `MIRROR` is set to false:
* Top-front: `[-45, 5, 0]`
* Top-back: `[30, 5, 0]`
* Bottom-back: `[30, -20, 0]`
* Bottom-front: `[-45, -40, 0]`

The clip's horizontal part starts at `[0,0,0]` and then stretches in the positive X axis, with a length of `CLIP_LENGTH`. Its Y axis thickness is `CLIP_THICKNESS` and its Z axis width is `ARM_WIDTH + CLIP_THICKNESS + SHEILD_THICKNESS`. The vertical clip is located at the same X/Y position as the horizontal clip, and at a Z offset of `SHEILD_THICKNESS + ARM_WIDTH`.  It's a cube with a dimension of `[CLIP_LENGTH, CLIP_THICKNESS, CLIP_HEIGHT]`, rotated `[90, 0, 0]` around the X axis.

When `ONLY_PRINT_CLIP` is true, I need to output only the clip. To do that, create the clip as usual, then intersect it with a large cube that roughly matches the size of the overall glasses attachment but is guaranteed to encompass all clip elements, so that users can test the clip sizing without printing the rest of the design. An appropriate size would be a cube centered on [0,0,0], with dimensions of `[CLIP_LENGTH + 10, 100, SHEILD_THICKNESS + ARM_WIDTH + CLIP_THICKNESS]`

I'd like the code to be well-organized and easy to understand. I don't have any libraries that I need to use at the moment. It would be good if you could provide the code in a single .scad file for ease of use. I believe that the above description encompasses all of the desired functionality. Thanks so much!

[Assistant]
blinders.scad:
```
$fn=50;

CORNER_RADIUS = 4;

// thickness of the shield
SHEILD_THICKNESS = 1.5;

// length, thickness and height of the clip that attaches to the glasses
CLIP_LENGTH = 20;
CLIP_THICKNESS = 1;
CLIP_HEIGHT = 10;

// width of the glasses arm
ARM_WIDTH = 2;

// by default the blinder for the right is rendered. Enable mirroring to render the left side
MIRROR = false;

//  only render the arm clip in order to test sizing.
ONLY_PRINT_CLIP = false;

module blinder() {
  // shield
  hull() {
      translate([-45, 5, 0]) cylinder(SHEILD_THICKNESS, r = CORNER_RADIUS); // top - front
      translate([30, 5, 0]) cylinder(SHEILD_THICKNESS, r = CORNER_RADIUS); // top - back
      translate([30, -20, 0]) cylinder(SHEILD_THICKNESS, r = CORNER_RADIUS); // bottom - back
      translate([-45, -40, 0]) cylinder(SHEILD_THICKNESS, r = CORNER_RADIUS); // bottom - front
  }

  // clip - horizontal part
  cube([CLIP_LENGTH, CLIP_THICKNESS, ARM_WIDTH + CLIP_THICKNESS + SHEILD_THICKNESS]);

  // clip - vertical part
  translate([0, 0, SHEILD_THICKNESS + ARM_WIDTH]) rotate([90, 0, 0]) cube([CLIP_LENGTH, CLIP_THICKNESS, CLIP_HEIGHT]);
}

if (ONLY_PRINT_CLIP) {
  intersection() {
    blinder();
    translate([-5, -(CLIP_HEIGHT + 5), 0]) cube([CLIP_LENGTH + 10, 100, SHEILD_THICKNESS + ARM_WIDTH + CLIP_THICKNESS]);
  }
} else {
  if (MIRROR) {
    mirror([1, 0, 0]) blinder();
  } else {
    blinder();
  }
}

```