[User]
Hey, I'm looking for some help designing a set of parametric screwdriver bits in OpenSCAD. I've got a bunch of different bit types in mind, and I'd like to be able to customize their size, length, and spacing, and even add a slot for a magnet.

Specifically, I need to be able to generate these bit types:

*   **Hex:** Standard hexagonal bit.
*   **Double Hex:** Two overlapping hex shapes.
*   **Hex Socket:** A hexagonal socket.
*   **Square:** Standard square bit.
*   **Square Socket:** A square socket.
*   **Double Square:** Two overlapping square shapes.
*   **Star:** A star-shaped bit.

For each bit, I need these parameters:

*   **`bit_type`:** A selection to choose from the bit types above.
*   **`magnet_slot`:** A boolean (true/false) to indicate whether or not to include a magnet slot.
*   **`magnet_diameter`:** The diameter of the magnet to be inserted.
*   **`magnet_height`:** The height of the magnet.
*   **`sizes`:** A list of the bit sizes to generate, it should render all the provided sizes.
*   **`bit_size`:** The diameter of the base cylinder of the bit.
*   **`tip_length`:** The length of the bit's tip.
*  **`bit_length`:** The length of the main part of the bit (between the base and the tip).
*   **`bit_spacing`:** The space between each bit when they are arranged in an array.
*   `number`: The total number of bits in the set.

I'd like the bits arranged in a grid, with the number of columns (`xc`) being equal to the total number of bits (`number`), and the number of rows (`yc`) being the rounded square root of the number of bits.  Each bit should also have a small notch on its sides to make them easier to use with bit holders and prevent rotation. The base of the bit (the part that inserts into the driver) should have a diameter specified by `bit_size`.

I'm also hoping that you can include a basic `ngon` function for the polygons, and a simple function for generating the base. I'd also like the individual bits to be named so that I can select them easily. I think those are the important details!

It would be fantastic if the design was fully parametric. The file should use named module for each bit type. If this is too much for a single file, then multiple files would be acceptable. I'd like to use the `MCAD` library.

[Assistant]
Hex_bits.scad:
```
// Hex bits

bit_type = "Hex"; // [Hex, Double Hex, Hex Socket, Square, Square Socket, Double Square, Star]
magnet_slot = "false"; // [true, false]
magnet_diameter = 6;
magnet_height = 3;
sizes = [1.5,2,2.5,3,4,5];
number = len(sizes);
bit_size = 7;
tip_length = 6;
bit_length = 14;
bit_spacing = 2;
xc = number;
yc = round(sqrt(number));
count = number;

if(bit_type == "Hex"){
    build_hex();
}

else if(bit_type == "Hex Socket"){
    build_hex_socket();
}

else if(bit_type == "Double Hex"){
    build_dbl_hex();
}

else if(bit_type == "Square"){
    build_square();
}

else if(bit_type == "Square Socket"){
    build_square_socket();
}

else if(bit_type == "Double Square"){
    build_dbl_square();
}

if(bit_type == "Star"){
    build_star();
}

module build_hex(){

    for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
    difference(){
        union(){

    base(x,y);
    sizes = sizes*1.16;
    translate([x*(bit_size+bit_spacing), y*(bit_size+bit_spacing), tip_length+bit_length]) scale([1,1,.5]) sphere($fn=6,d=sizes[y+(yc*x)]);

    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(6, sizes[y+(yc*x)]/2));

    }
    notch_cut(x, y);
    }
}
}
count = count-x*yc;
}
}

module build_hex_socket(){
    for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
        sizes = sizes*1.16;
    difference(){
    union(){
    base(x,y);
    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length+1]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(30, sizes[y+(yc*x)]/2+1));

        translate([x*(bit_size+bit_spacing), y*(bit_size+bit_spacing), bit_length+2]) scale([1,1,.5]) sphere($fn=6,d=sizes[y+(yc*x)]);
    }

    translate([x*(bit_size+bit_spacing), y*(bit_size+bit_spacing), bit_length+2]) scale([1,1,.5]) sphere($fn=6,d=sizes[y+(yc*x)]);

    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length+2]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(6, sizes[y+(yc*x)]/2));
    notch_cut(x, y);
    }
    echo(county, "add");
}
echo(count);
}
count = count-x*yc;
}
}

module build_dbl_hex(){

    for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
    difference(){
        union(){
    base(x,y);
   sizes = sizes*1.16;
    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(6, sizes[y+(yc*x)]/2));
        translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) rotate(90) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(6, sizes[y+(yc*x)]/2));
    }
    notch_cut(x,y);
}
    echo(county, "add");
}
echo(count);
}
count = count-x*yc;
}
}

module build_square(){
for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
    difference(){
        union(){
        base(x,y);
       sizes = sizes*1.1;
        translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) linear_extrude (height = tip_length, center = false, convexity = 10) rotate(45) polygon(ngon(4, sizes[y+(yc*x)]/2));
    }
    notch_cut(x,y);
    }
    echo(county, "add");
}
echo(count);
}
count = count-x*yc;
}

}

module build_square_socket(){
    for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
    difference(){
    union(){
    base(x,y);
        sizes = sizes*1.1;
    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length+1]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(30, sizes[y+(yc*x)]/2+1));

        translate([x*(bit_size+bit_spacing), y*(bit_size+bit_spacing), bit_length+2]) scale([1,1,.5]) sphere($fn=6,d=sizes[y+(yc*x)]);
    }

    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length+2]) linear_extrude (height = tip_length, center = false, convexity = 10) rotate(45) polygon(ngon(4, sizes[y+(yc*x)]/2));

    notch_cut(x, y);
    }
    echo(county, "add");
}
echo(count);
}
count = count-x*yc;
}
}

module build_dbl_square(){
for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
    difference(){
        union(){
        base(x,y);
        sizes = sizes*1.1;
        translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) linear_extrude (height = tip_length, center = false, convexity = 10) rotate(45) polygon(ngon(4, sizes[y+(yc*x)]/2));
        translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(4, sizes[y+(yc*x)]/2));

    }
    notch_cut(x,y);
    }
    echo(county, "add");
}
echo(count);
}
count = count-x*yc;
}

}

module base(x,y){

       difference(){
        union(){
    if(bit_type == "Hex Socket" || bit_type == "Square Socket"){
        translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) cylinder($fn=6, height = 1, r1 = bit_size*1.16/2, r2 = sizes[y+(yc*x)]/2+1);
    }
    else{
     translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) cylinder($fn=6, height = 1, r1 = bit_size*1.16/2, r2 = sizes[y+(yc*x)]/2);
    }
    linear_extrude(height = bit_length,     center = false) translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),0]) polygon(ngon(6, bit_size*1.16/2));
}
 if(magnet_slot == "true"){
            translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),1]) cylinder($fn=30, height = magnet_height+.4, r1 = magnet_diameter/2+.2, r2 = magnet_diameter/2+.2);
        }

}
}
module build_star(){

    for (x = [0:xc-1]){
    for(y = [0:yc-1]){
    county = count-y;
    if(county > 0){
    difference(){
        union(){
    base(x,y);
   sizes = sizes*1.16;
    translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(3, sizes[y+(yc*x)]/2));
        translate([x*(bit_size+bit_spacing),y*(bit_size+bit_spacing),bit_length]) rotate(180) linear_extrude (height = tip_length, center = false, convexity = 10) polygon(ngon(3, sizes[y+(yc*x)]/2));
    }
    notch_cut(x,y);
}
    echo(county, "add");
}
echo(count);
}
count = count-x*yc;
}
}

module notch_cut(x, y){
    // Notch Cut
        translate([x*(bit_size+bit_spacing)-bit_size/2,y*(bit_size+bit_spacing),bit_length/2]) rotate([45, 45, 45])cube(size = .2, center = true);
    translate([x*(bit_size+bit_spacing)+bit_size/2,y*(bit_size+bit_spacing),bit_length/2]) rotate([45, 45, 45])cube(size = .2, center = true);
        translate([x*(bit_size+bit_spacing)-bit_size/4,y*(bit_size+bit_spacing)-bit_size/2.3,bit_length/2]) rotate([45, 45, 45])cube(size = .2, center = true);
    translate([x*(bit_size+bit_spacing)+bit_size/4,y*(bit_size+bit_spacing)+bit_size/2.3,bit_length/2]) rotate([45, 45, 45])cube(size = .2, center = true);
    translate([x*(bit_size+bit_spacing)+bit_size/4,y*(bit_size+bit_spacing)-bit_size/2.3,bit_length/2]) rotate([45, 45, 45])cube(size = .2, center = true);
    translate([x*(bit_size+bit_spacing)-bit_size/4,y*(bit_size+bit_spacing)+bit_size/2.3,bit_length/2]) rotate([45, 45, 45])cube(size = .2, center = true);
}
function ngon(num, r) =
    [for (i=[0:num-1], a=i*360/num) [ r*cos(a), r*sin(a)]];
```


[User]
Hey, I'm looking to create a tool socket generator in OpenSCAD, and I need a bit of help getting started. I've got a general idea, but I want to make sure it's parametric and flexible.

Basically, I need to be able to generate sockets of various sizes, and I want to have options for both standard hex and double-hex profiles.  I'd like to specify whether I'm working in Imperial or Metric units and have the sizes adjust accordingly. I also need to control the base size of the socket, the depth of the base, the length of the socket, the spacing between sockets when multiple are generated, and whether it should have straight walls or tapered walls.

Here's a bit more detail:

*   **Socket Type:** Should have options for "Hex" or "Double Hex".
*   **Units:** Should have options for "Imperial" or "Metric" units.
*   **Base Size:**  A numeric value for the base of the socket (e.g., diameter).
*   **Base Depth:** A numeric value for the depth of the base.
*   **Socket Sizes:** A list of numeric values representing the sizes of the sockets themselves. If I enter three values, it will generate three socket profiles.
*   **Socket Length:**  A numeric value for the length of the socket.
*   **Socket Style:**  Options for "Straight" or "Tapered".
*   **Spacing:** A numeric value defining the spacing between the generated sockets when they are in multiple.
*   **Output:** I'd like to be able to define a list of the socket sizes to be generated, and have them laid out on the x, y plane.
*   **Libraries:** I'd like to leverage BOSL2, if appropriate.

I think that covers the main bits. Can you help me get the parametric OpenSCAD file(s) for this?

[Assistant]
Sockets.scad:
```
// Sockets

type = "Double Hex"; // [Hex, Double Hex]
base_size = .5;
base_depth = .5;
socket_sizes = [13/16,1/2,1];
socket_length = .6;
style = "Straight"; //[Tapered, Straight]
spacing = 15;
number = len(socket_sizes);
units = "Imperial"; //[Imperial, Metric]

xc = number;
yc = round(sqrt(number));
count = number;
if(units=="Imperial"){
    if(type == "Hex"){
        build_socket_imperial();
    }
    if(type == "Double Hex"){
        build_socket_imperial_double();
    }
}
else{
    if(type == "Hex"){
        build_socket_metric();
    }
    if(type == "Double Hex"){
        build_socket_metric_double();
    }
}
module build_socket_metric(){

    for(x=[0:xc-1]){
        for(y=[0:yc-1]){
            county= count-y;
            if(county>0){
                base_size = base_size*1.1;
                socket_sizes = socket_sizes*1.16;
                difference(){
                    union(){
                        translate([x*(base_size+         spacing),y*(base_size+spacing),base_depth+1]) linear_extrude (height = socket_length, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));

                        if(style == "Straight" && socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));
                        }
                        else
                            {
                        translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, (base_size+2)/2));
                        }
                        if(socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-2]) cylinder($fn=30, h = 3, r1 = socket_sizes[y+(yc*x)]/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                        }
                        else{
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth]) cylinder($fn=30, h = 3, r1 = base_size/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                            }

                    }
               translate([x*(base_size+spacing),y*(base_size+spacing),-.1]) linear_extrude (height = base_depth+.5, center = false, convexity = 10) polygon(ngon(4, base_size/2));
                    translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-.5]) linear_extrude (height = socket_length+2, center = false, convexity = 10) polygon(ngon(6, socket_sizes[y+(yc*x)]/2));
                }

            }
        }
        count = count-x*yc;
    }
}

module build_socket_metric_double(){

    for(x=[0:xc-1]){
        for(y=[0:yc-1]){
            county= count-y;
            if(county>0){
                base_size = base_size*1.1;
                socket_sizes = socket_sizes*1.16;
                difference(){
                    union(){
                        translate([x*(base_size+         spacing),y*(base_size+spacing),base_depth+1]) linear_extrude (height = socket_length, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));

                        if(style == "Straight" && socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));
                        }
                        else
                            {
                        translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, (base_size+2)/2));
                        }
                        if(socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-2]) cylinder($fn=30, h = 3, r1 = socket_sizes[y+(yc*x)]/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                        }
                        else{
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth]) cylinder($fn=30, h = 3, r1 = base_size/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                            }

                    }
               translate([x*(base_size+spacing),y*(base_size+spacing),-.1]) linear_extrude (height = base_depth+.5, center = false, convexity = 10) polygon(ngon(4, base_size/2));
                    translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-.5]) linear_extrude (height = socket_length+2, center = false, convexity = 10) polygon(ngon(6, socket_sizes[y+(yc*x)]/2));
                    translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-.5]) rotate(30) linear_extrude (height = socket_length+2, center = false, convexity = 10) polygon(ngon(6, socket_sizes[y+(yc*x)]/2));
                }

            }
        }
        count = count-x*yc;
    }
}

module build_socket_imperial(){

    for(x=[0:xc-1]){
        for(y=[0:yc-1]){
            county= count-y;
            if(county>0){
                conv = 25.4;
                base_size = (base_size*conv)*1.1;
                base_depth = base_depth*conv;
                socket_sizes = (socket_sizes*conv)*1.16;
                socket_length = socket_length*conv;
                spacing = spacing;
                difference(){
                    union(){
                        translate([x*(base_size+spacing),y*(base_size+spacing),base_depth]) linear_extrude (height = socket_length, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));

                        if(style == "Straight" && socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));
                        }
                        else
                            {
                        translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, (base_size+2)/2));
                        }
                        if(socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-2]) cylinder($fn=30, h = 2, r1 = socket_sizes[y+(yc*x)]/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                        }
                        else{
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth]) cylinder($fn=30, h = 3, r1 = base_size/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                            }
                    }
               translate([x*(base_size+spacing),y*(base_size+spacing),-.1]) rotate (45) linear_extrude (height = base_depth+.1, center = false, convexity = 10) polygon(ngon(4, base_size/2));
                    translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-.1]) linear_extrude (height = socket_length+1, center = false, convexity = 10) polygon(ngon(6, socket_sizes[y+(yc*x)]/2));

                    }

            }
        }
        count = count-x*yc;
    }
}

module build_socket_imperial_double(){

    for(x=[0:xc-1]){
        for(y=[0:yc-1]){
            county= count-y;
            if(county>0){
                conv = 25.4;
                base_size = (base_size*conv)*1.1;
                base_depth = base_depth*conv;
                socket_sizes = (socket_sizes*conv)*1.16;
                socket_length = socket_length*conv;
                spacing = spacing;
                difference(){
                    union(){
                        translate([x*(base_size+spacing),y*(base_size+spacing),base_depth]) linear_extrude (height = socket_length, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));

                        if(style == "Straight" && socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, socket_sizes[y+(yc*x)]/2+1));
                        }
                        else
                            {
                        translate([x*(base_size+spacing),y*(base_size+spacing),0]) linear_extrude (height = base_depth, center = false, convexity = 10) polygon(ngon(30, (base_size+2)/2));
                        }
                        if(socket_sizes[y+(yc*x)] > base_size){
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-2]) cylinder($fn=30, h = 2, r1 = socket_sizes[y+(yc*x)]/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                        }
                        else{
                            translate([x*(base_size+spacing),y*(base_size+spacing),base_depth]) cylinder($fn=30, h = 3, r1 = base_size/2+1, r2 = socket_sizes[y+(yc*x)]/2+1);
                            }
                    }
               translate([x*(base_size+spacing),y*(base_size+spacing),-.1]) rotate (45) linear_extrude (height = base_depth+.1, center = false, convexity = 10) polygon(ngon(4, base_size/2));
                    translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-.1]) linear_extrude (height = socket_length+1, center = false, convexity = 10) polygon(ngon(6, socket_sizes[y+(yc*x)]/2));
                    translate([x*(base_size+spacing),y*(base_size+spacing),base_depth-.1]) rotate(30) linear_extrude (height = socket_length+1, center = false, convexity = 10) polygon(ngon(6, socket_sizes[y+(yc*x)]/2));

                    }

            }
        }
        count = count-x*yc;
    }
}

function ngon(num, r) =
    [for (i=[0:num-1], a=i*360/num) [ r*cos(a), r*sin(a)]];
```


[User]
Okay, so I'm really interested in this stereographic projection thing I saw. I've got this idea for a pendant, and I think it would look really cool if I could project some text onto a curved surface like in the example I saw. The example was making some kind of Chinese character pendant, but I want to use letters instead.

Essentially, I want to be able to take any 4-letter string and project each letter onto its own little rounded square, arranged in a square pattern. The projection should be similar to the provided example, where it looks like the characters are being projected onto the inside of a sphere, and then the squares are cut out so that the projection is visible. I'd need to be able to specify the text, the overall size of the pendant, the font to use for the letters (I want to use a standard sans-serif), and maybe the extrusion depth of the letters for 3D printing. Also, I'd like to be able to choose whether or not there's a shadow underneath.

Here's a summary of the parameters I need:
*   **`txt`**: The four-character string.
*   **`size`**: The overall size of the pendant.
*   **`font`**: The font to use. (let's start with "Arial")
*   **`depth`**: The extrusion depth for the text.
*   **`shadow`**:  A boolean flag (or string like "YES"/"NO") to enable or disable the shadow.
*   **`shadow_depth`**: The depth for the shadow extrusion.

The squares containing the characters should be arranged as they were in the example code, with the top left character in the upper left quadrant and so on. I'm not sure if the stereographic projection function from the example is necessary, so you can use something simpler if you have one. I really just need the end result to look similar!

I'm hoping you can generate a working OpenSCAD file, or set of files if necessary, that accomplishes this. I'm not using any specific libraries at the moment, but if you need to, feel free to pull from a common one.

[Assistant]
chinese_4_char_idioms.scad:
```
txt = "GGGG";
size = 100;
fn = 24;
shadow = "YES"; // [YES, NO]
base_height = 2;

module stereographic_projection(side_leng_shadow, fn) {
    $fn = fn;

    half_side_length = side_leng_shadow / 2;
    outer_sphere_r = half_side_length / 3;
    a = atan(sqrt(2) * half_side_length / (2 * outer_sphere_r));
    inner_sphere_r = outer_sphere_r * sin(a);

    intersection() {
        translate([0, 0, outer_sphere_r]) difference() {
            sphere(outer_sphere_r);
            sphere(outer_sphere_r / 2 + inner_sphere_r / 2);

            translate([0, 0, outer_sphere_r / 2])
                linear_extrude(outer_sphere_r)
                    circle(inner_sphere_r * sin(90 - a));
        }

        linear_extrude(outer_sphere_r * 2, scale = 0.01) children();
    }
}

module chinese_4_char_idioms(txt, size) {
    frame_width = 0.225 * size;

    for(i = [0:3]) {
        offset_x = size * 0.8 * (i == 1 || i == 2 ? 1 : -1) +
                   frame_width / 2 * (i == 0 || i == 3 ? 1 : -1);
        offset_y = size * 0.8 * (i == 0 || i == 1 ? 1 : -1) +
                   frame_width / 2 * (i == 0 || i == 1 ? -1 : 1);

        translate([offset_x, offset_y, 0]) intersection() {
            union() {
                rotate(-135 - 90 * i) scale([1.15, 1, 1])
                    text(txt[i], size = size, font = "微軟正黑體:style=Bold", valign = "center", halign = "center");

                difference() {
                    square(size * 1.6, center = true);
                    square(size * 1.15, center = true);
                }

               /* // patch for "恭喜發財"
                if(txt[i] == "財") {
                    translate([-size / 2.15, -size / 10, 0]) square([size / 7.5, size / 6]);
                }
                if(txt[i] == "發") {
                    translate([size / 10, size / 2.5, 0]) square([size / 8.25, size / 8]);
                }*/
            }
            square(size * 1.6, center = true);
        }
    }
}

stereographic_projection(size * 2.975, fn)
    chinese_4_char_idioms(txt, size);

if(shadow == "YES") {
    color("red") linear_extrude(base_height) chinese_4_char_idioms(txt, size);
}
```


[User]
Hey, I'm looking to generate a calibration print for my 3D printer to help dial in the backlash compensation. I have a design in mind based on the "QuickBacklash20.scad" file I found online, but it's a little inflexible, and I'd like to make it more parametric so I can tweak it more easily for different printers and filaments.

Here's how I envision it:

The design consists of a grid of test samples. Each sample will have a few key features:

1.  **A base line**: A horizontal rectangle, just a single layer tall, along the x-axis.
2.  **A vertical line**: A short vertical rectangle coming off the base line.
3.  **An angled line**: An angled line segment that goes upwards from the vertical line and increases in length as the backlash compensation value increases.
4.  **A vertical line**: Another vertical line after the angled line.
5.  **Another angled line**: An angled line segment that goes downwards from the vertical line and decreases in length as the backlash compensation value increases.
6. **A vertical line**: Another vertical line coming off the second angled line.
7.  **Another base line**: A horizontal rectangle to complete the sample.
8. **Connecting line** For all but the first row, there should be a line connecting the previous row.

Each sample in the grid should have an increased value of backlash compensation. The backlash value should increase based on its position in the grid.
The samples should be arranged in rows and columns, with the backlash compensation value incrementing by a fixed amount along both the rows and columns.  I want to set the increment, starting backlash value, and the number of samples on each axis.

I'd also like the option to set a few parameters like:

*   `Rows`: The number of rows in the grid.
*   `Backlashstartvalue`: The starting backlash compensation value.
*   `wallheight`: The layer height of all the printed lines.
*   `wallthickness`: The thickness of the lines.

I'd like to be able to change the color of different elements, as well. I'd like them to be roughly the same as in the original file - red, green, pink, purple, yellow, blue, brown and black.

And finally, there should be a cube (or other shape) to mark zero at one end of the rows. I'd like to make this parametric too.

It would be awesome if you could generate this as a parametric OpenSCAD file. I don't expect you to use any specific libraries, but if you think any of the standard ones (like BOSL) might be helpful for this project, feel free.

[Assistant]
QuickBacklash20.scad:
```
// Calibrate X axis
// Set backlash compensation to 0 in your software while sampling an axis.
// Each step up increases backlash offset with 0.01
// Each step right increases backlash offset with 0.10
// locate the figure with the smallest offset value and add backlash offset to it. This calculated value is your backlash offset to be entered in the printer sotware.
// E.g. if the correct figure is number 7 to the right and number 4 from the bottom and backlashstartvalue is 0.7:
// 0.7 + 0.03 + 0.5 = 1.23
// To make files for  calibrating the Y axis turn the print 90 degrees in the slicer.

/* [Size and start point] */
//Number of strips to print.
Rows = 20; //[1:1:20]
//What is the starting point? Make sure that the end-value is no more than 1.99 (Rows/10+Backlashstartvalue <= 2) because the "reset-loops" are only 2 mm
Backlashstartvalue = 0.00; // [0.0:0.1:1.9]
/* [Print thickness and height] */
//Suggestion: Wallheight = Nozzle diameter.
wallheight = 0.35; //[0.2:0.05:0.8]

//Suggestion: Wallthickness = 2 or 2.5 times the Wallheight. Those are values that work for me. Your mileage may vary a lot. Your slicer of course needs to be set acordingly so the print is made in a single layer. Fatter lines stick better to the plate but thinner lines are easier to interpret.
wallthickness = 0.85; //[0.2:0.05:1.6]

//Each sample
module unit(sx, sy, bl)
{
color("red")
    translate([(sx+0), (sy+0), 0])
        cube([3, wallthickness, wallheight], center=false);

color("green")
    translate([(sx+0), (sy+0), 0])
        cube([wallthickness, 1, wallheight], center=false);

color("pink")
   linear_extrude(height = wallheight, center = false, convexity = 10, twist = 0)
    polygon(points=[[sx,sy+1],[sx+wallthickness,sy++1],[sx+bl+wallthickness,sy+3],[sx+bl,sy+3]]);

color("purple")
    translate([(sx+bl), (sy+3), 0])
        cube([wallthickness, 2, wallheight], center=false);

color("yellow")
    linear_extrude(height = wallheight, center = false, convexity = 10, twist = 0)
   polygon(points=[[sx+bl,sy+5],[sx+bl+wallthickness,sy+5],[sx+wallthickness,sy+7],[sx,sy+7]]);

color("blue")
    translate([(sx+0), (sy+7), 0])
            cube([wallthickness, 1, wallheight], center=false);

color("brown")
    translate([(sx+0), (sy+8-wallthickness), 0])
        cube([3, wallthickness, wallheight], center=false);

//Connect each sample
    if (sy>0)
     {
color("black")
    translate([(sx+3-wallthickness), (sy-2), 0])
        cube([wallthickness, 2, wallheight], center=false);
     }
    }

//draw y strips
for (soffsy=[0:10:(Rows*10-10)])
{
    //draw 10 samples
   for (soffsx=[0:10:90])
    {

        sbl = (Backlashstartvalue + soffsy/100+ soffsx/1000);

        echo("Backlash is  ", sbl);

      unit(soffsy/2, soffsx, sbl  );
    }
}

// The blob that marks zero
//color("black")
    translate([(1.6), (3), 0])
        cube([(3*wallthickness), (3*wallthickness), wallheight], center=false);

```


[User]
I need a parametric OpenSCAD design for a ribbon cable guide, similar to the one I found on Thingiverse (http://www.thingiverse.com/thing:52025) but with some specific changes and flexibility. The design should allow the cable to be installed by sliding it in from the open side and should be compatible with different rod diameters. I want to be able to customize both the cable width and the rod diameter.

Here are the specific requirements:

1.  **Rod Interface:**
    *   The guide should have a circular opening for mounting onto a rod.
    *   I need to be able to adjust the diameter of this circular opening using a parameter (`rodDiameter` or something similar).
    *   The rod opening should be a difference of two cylinders to create a lip. The smaller cylinder should not be centered within the larger cylinder and should be shifted slightly to one side.
    *   I also need to cut a rectangular hole in the lip on the small cylinder side to allow insertion of the guide onto a rod. The size of the hole should be derived from the `rodDiameter` parameter.
    *   The wall of the inner cylinder should be a minimum thickness for structural integrity, defined by a `wallThickness` parameter.

2.  **Cable Channel:**
    *   The guide should have a channel for the ribbon cable to pass through.
    *   I need to be able to adjust the width of the cable channel using a parameter (`cableWidth`).
    *   The cable channel should have rounded corners on the enclosed side (a half cylinder).
     * The cable channel should have an open end on the other side.
    *   The top of the cable channel should be covered by an overhang to hold the ribbon cable in place.

3.  **General:**
    *   The design should be parametric, allowing easy adjustment of all specified dimensions using variables.
    *   I need the design to be robust, easy to print, and usable with standard FDM printers.
    *   The guide should be relatively thin (around 3mm, but this could be a parameter `guideThickness`)
    *   I don't need any specific mounting holes.
    *   Please use the BOSL2 library if applicable.

I'm not sure how to use libraries like that so if you could include any relevant library statements/calls needed that would be great.

[Assistant]
customizableRibbonCableGuide.scad:
```
cableWidth=16;  // in mm
rodDelimiter=10; // in mm

// No more changes from here

outerRadius=(rodDelimiter-1+6)/2;
innerRadius=(rodDelimiter-1)/2;

difference() {
    cylinder (r=outerRadius, h=3, $fn=120);
    cylinder (r=innerRadius, h=3, $fn=120);
    translate ([innerRadius*-0.67, innerRadius/1.35, 0]) cube ([innerRadius*1.33, outerRadius-((rodDelimiter-1)/2.7), 3]);

}

difference() {
    union() {
        translate ([(cableWidth-1)/-2, (outerRadius-2+7)*-1, 0]) cube ([(cableWidth+2.5), 7, 3]);
        translate ([(cableWidth-1)/-2, (outerRadius-2+3.5)*-1, 0]) cylinder (r=3.5, h=3, $fn=120);
    }
    translate ([(cableWidth/2+1)*-1, (outerRadius-2+5)*-1, 0]) cube ([(cableWidth+2), 3, 3]);
    translate ([(cableWidth/2+1), (outerRadius-2+3.5)*-1, 0]) cube ([2, 1, 3]);
}
```


[User]
Hi, I'd like to design a customizable hook system for hanging various items. I have a basic design in mind, but I'd like it to be a bit more flexible and have it parameterized in OpenSCAD.

Here are the core components:

1.  **Base:** This is a rectangular prism (a cube that has been extruded), which will serve as the mounting base for the hooks. I'd need parameters for:
    *   `CubeWidth`: Total width of the base
    *   `CubeDepth`: Depth of the base
    *   `CubeHeight`: Height of the base

2.  **Hooks:** These are created from two basic parts, a cylindrical section and a spherical cap. The number of hooks are calculated by dividing `CubeWidth` by `DistanceBetweenHooks` and rounding. Parameters I need are:
    *   `CylinderHeight`: Height of the cylindrical part of the hook
    *   `CylinderRadius`: Radius of the cylinder
    *   `SphereRadius`: Radius of the sphere that forms the hook end
    *   `DistanceBetweenHooks`: Distance between the center of each hook cylinder
        *   The hooks should be centered on the base.

The whole structure should be made using `union()` in OpenSCAD. I would like the number of hooks to be calculated from the parameters, so the spacing between the start of the first hook and the left edge of the base, and the end of the last hook and the right edge of the base should be equal, which means that if `DistanceBetweenHooks` does not divide exactly into `CubeWidth` you should calculate `cubeBorderSize = (CubeWidth-numHooks*DistanceBetweenHooks)/2`.
    *   The cylinder should be translated `[i*DistanceBetweenHooks+cubeBorderSize+DistanceBetweenHooks/2,CubeDepth/2,CubeHeight]`
    *   The sphere should be translated `[i*DistanceBetweenHooks+cubeBorderSize+DistanceBetweenHooks/2,CubeDepth/2,CylinderHeight+CubeHeight+SphereRadius/2]`
I do not need any other libraries other than the basics in OpenSCAD to get it working, could you help me with the scad file?

[Assistant]
Hooks.scad:
```
// Copyright by Drato Lesandar @ www.robotmama.de
//
// Customizable Hanger
//
// Calculates number of hooks automatically, if you want other parameters,
// send a mail to info@robotmama.de or via Thingiverse
//

//(mm)
CylinderHeight = 10;
//(mm)
CubeWidth = 210;
//(mm)
CubeDepth = 20;
//(mm)
CubeHeight = 2;
//(mm)
DistanceBetweenHooks = 34;
//(mm, used 7 in image with bigger hooks)
SphereRadius = 3.5;
//(mm, used 5 in image with bigger hooks)
CylinderRadius = 2.5;
numHooks = round(CubeWidth / DistanceBetweenHooks);
cubeBorderSize = (CubeWidth-numHooks*DistanceBetweenHooks)/2;
union() {
    cube([CubeWidth,CubeDepth,CubeHeight],false);
    // Cylinder
    for(i=[0:numHooks-1]) translate([i*DistanceBetweenHooks+cubeBorderSize+DistanceBetweenHooks/2,CubeDepth/2,CubeHeight]) cylinder(CylinderHeight, CylinderRadius, CylinderRadius, false, $fn=100);
    // Spheres
    for(i=[0:numHooks-1]) translate([i*DistanceBetweenHooks+cubeBorderSize+DistanceBetweenHooks/2,CubeDepth/2,CylinderHeight+CubeHeight+SphereRadius/2]) sphere(SphereRadius, $fn=100);
}
```


[User]
Hey, I'm looking for a customizable ring generator. I have an existing OpenSCAD file that does some of what I want, but it's a bit clunky and I'd like to start over with something cleaner and more parametric.

Essentially, I need to be able to specify the following:

*   **Ring Size:** This should be based on a lookup table for different countries (United States, Canada, Mexico, United Kingdom, Ireland, Australia, New Zealand, South Africa, Italy, Spain, Netherlands, Switzerland, India, China, South America, Japan, France, Germany, Austria, Belgium, and Scandinavia). I'd like to be able to input the size as a string like "7 1/4" or just "9" and have the code automatically find the correct internal diameter. I'd prefer to not have to manually convert ring sizes to diameters.
*   **Ring Height:**  This is simply the height of the ring in millimeters, an easy numeric input.
*   **Ring Thickness:** This is the thickness of the ring material, also in millimeters.
*   **Text Inscription:** I'd like to be able to specify text to be inscribed on both the outside and inside of the ring. There should also be boolean toggles to enable or disable either inscription.

I don't need the text to be super fancy; just a simple extrusion or cutout (your choice). I'm not looking for anything like text warping, just plain text along the ring's circumference.

Could you generate the necessary SCAD files, including any libraries I'll need? I'm not picky about the libraries, so use whatever seems easiest for this kind of project. If a standard library exists that is suitable, please use that. The key is that I'd like the files to be easy to read and the code to be clean.

[Assistant]
anySizeRingTemplate.scad:
```
/* [Ring Maker] */
// this thing is a remix based off of Ring Sizer published by teinturman at
// http://www.thingiverse.com/thing:2031257

//bare in mind that printers often print weird, so it might scaled in your slicer or cleaned up

//BEGIN CUSTOMIZER VARIABLES
/*[Sizing]*/
Country="United States"; //[United States,Canada,Mexico,United Kingdom,Ireland,Australia,New Zealand,South Africa,Italy,Spain,Netherlands,Switzerland,India,China,South America,Japan,France,Germany,Austria,Belgium,Scandinavia]
//Format half sizes like that, regular sizes no spaces, always use capital letters if needed.
sizeValue= "7 1/4";

/* [Ring Options] */
//Height of the ring in MM
ringheight=5;
//thickness of the ring
thickness=3;//[1:0.5:10]

/* [Text Options] */
//Well work later... Kinda lazy right now.
OutsideText="Happy";
InscribeOutsideText=true;//[true,false]
InsideText="St. Valentin";
//END CUSTOMIZER VARIABLES

/* [Hidden] */
US_Countries=["US","United States","Canada","Mexico"];
UK_Countries=["UK","United Kingdom","Ireland","Australia","New Zealand","South Africa"];
Spain_Countries=["ES","Italy","Spain","Netherlands","Switzerland"];
India_Countries=["IN","India"];
China_Countries=["CI","China","South America"];
Japan_Countries=["JP","Japan"];
ISO_Countries=["EU","France","Germany","Austria","Belgium","Scandinavia"];
//https://en.wikipedia.org/wiki/Ring_size

//USSizes_All =[12.04,12.24  ,12.45,12.65  ,12.85  ,13.06  ,13.26 ,13.46  ,13.67  ,13.87  ,14.07 ,14.27  ,14.48  ,14.68  ,14.88 ,15.09  ,15.29  ,15.49  ,15.7   ,15.9   ,16.1   ,16.31  ,16.51  ,16.71  ,16.92  ,17.12  ,17.32  ,17.53  ,17.73  ,17.93  ,18.14  ,18.34  ,18.54  ,18.75  ,18.95  ,19.15  ,19.35  ,19.56  ,19.76  ,19.96   ,20.17   ,20.37   ,20.57  ,20.78   ,20.98   ,21.18   ,21.39  ,21.59   ,21.79   ,22      ,22.2   ,22.4    ,22.61   ,22.81   ,23.01  ,23.22   ,23.42   ,23.62   ,23.83  ];
//USValues_All=["1/2","3/4"  ,"1"  ,"1 1/4","1 1/2","1 3/4","2"   ,"2 1/4","2 1/2","2 3/4","3"   ,"3 1/4","3 1/2","3 3/4","4"   ,"4 1/4","4 1/2","4 3/4","5"    ,"5 1/4","5 1/2","5 3/4","6"    ,"6 1/4","6 1/2","6 3/4","7"    ,"7 1/4","7 1/2","7 3/4","8"    ,"8 1/4","8 1/2","8 3/4","9"    ,"9 1/4","9 1/2","9 3/4","10"   ,"10 1/4","10 1/2","10 3/4","11"   ,"11 1/4","11 1/2","11 3/4","12"   ,"12 1/4","12 1/2","12 3/4","13"   ,"13 1/4","13 1/2","13 3/4","14"   ,"14 1/4","14 1/2","14 3/4","15"   ];
//UKValues_All=["A"  ,"A 1/2","B"  ,"B 1/2","C"    ,"C 1/2","D"   ,"D 1/2","E"    ,"E 1/2","F"   ,"F 1/2","G"    ,"G 1/2","H"   ,"H 1/2","I"    ,"J"    ,"J 1/2","K"    ,"K 1/2","L"    ,"L 1/2","M"    ,"M 1/2","N"    ,"N 1/2","O"    ,"O 1/2","P"    ,"P 1/2","Q"    ,"Q 1/2","R"    ,"R 1/2","S"    ,"S 1/2","T"    ,"T 1/2","U"     ,"U 1/2" ,"V"     ,"V 1/2","W"     ,"W 1/2" ,"X"     ,"X 1/2","Y"     ,"Z"  ];
//China_All   =[""   ,""     ,"1"  ,""     ,""     ,""     ,"2"   ,""     ,"3"    ,""     ,"4"   ,"5"    ,""     ,"6"    ,"7"   ,""     ,"8"    ,""     ,"9"    ,""     ,"10"   ,""     ,"11"   ,"12"   ,"13"   ,""     ,"14"   ,""     ,"15"   ,""     ,"16"   ,""     ,"17"   ,""     ,"18"   ,""     ,"19"   ,""     ,"20"   ,"21"    ,"22"    ,""      ,"23"   ,""      ,"24"    ,""      ,"25"   ,""      ,"26"    ,""      ,"27"   ,""      ,""      ,""      ,""     ,""      ,""      ,""      ,""     ];
//India_All   =[""   ,""     ,""   ,""     ,""     ,"1"    ,"2"   ,""     ,"3"    ,"4"    ,""    ,"5"    ,""     ,"6"    ,""    ,"7"    ,"8 1/2","9"    ,""     ,"10"   ,""     ,"11"   ,"12"   ,""     ,"13"   ,""     ,"14"   ,"15"   ,""     ,"16"   ,"17"   ,""     ,"18"   ,"19"   ,""     ,"20"   ,"21"   ,""     ,"22"   ,"23"    ,""      ,"24"    ,"25"   ,""      ,"26"    ,""      ,"27    ,"28"    ," "     ,"29"    ,"30"   ,""      ,"31"    ,"32"    ,""     ,"33"    ,""      ,"34"    ,"35"   ];
//Spain_All   =[""   ,""     ,""   ,""     ,"0.5"  ,"1"    ,"1.75","2.25" ,"3"    ,"3.5"  ,"4.25","4.75" ,"5.5"  ,"6"    ,"6.75","7.5"  ,"8"    ,"8.75" ,"9.25" ,"10"   ,"10.5" ,"11.25","11.75","12.5" ,"13.25","13.75","14.5" ,"15"   ,"15.75","16.25","17"   ,"17.5" ,"18.25","19"   ,"19.5" ,"20.25","20.75","21.5" ,"22"   ,"22.75" ,"23.25" ,"24"    ,"24.75","25.25" ,"26"    ,"26.5"  ,"27.25","27.75" ,"28.5"  ,"29"    ,"29.75","30.5"  ,"31"    ,"31.75" ,"32.25","33"    ,"33.5"  ,"34.25" ,"34.75"];
//source : https://www.kuberbox.com/blog/international-ring-size-conversion-chart/

$fn=100;

if (search([Country],US_Countries)[0]>0)
{
  USValues_All=["1/2","3/4"   ,"1"  ,"1 1/4"  ,"1 1/2"  ,"1 3/4"  ,"2"     ,"2 1/4"  ,"2 1/2"  ,"2 3/4"  ,"3"     ,"3 1/4"  ,"3 1/2"  ,"3 3/4"  ,"4"     ,"4 1/4"  ,"4 1/2"  ,"4 3/4" ,"5"     ,"5 1/4"  ,"5 1/2" ,"5 3/4"  ,"6"      ,"6 1/4" ,"6 1/2"  ,"6 3/4"  ,"7"      ,"7 1/4"  ,"7 1/2"  ,"7 3/4" ,"8"      ,"8 1/4" ,"8 1/2"  ,"8 3/4" ,"9"     ,"9 1/4"  ,"9 1/2"  ,"9 3/4" ,"10"     ,"10 1/4"  ,"10 1/2"  ,"10 3/4" ,"11"     ,"11 1/4" ,"11 1/2"  ,"11 3/4" ,"12"     ,"12 1/4" ,"12 1/2"  ,"12 3/4"  ,"13"     ,"13 1/4"   ,"13 1/2"  ,"13 3/4" ,"14"     ,"14 1/4"  ,"14 1/2"  ,"14 3/4"  ,"15"      ];
  USSizes_All =[12.04,12.24   ,12.45,12.65    ,12.85    ,13.06    ,13.26   ,13.46    ,13.67    ,13.87    ,14.07   ,14.27    ,14.48    ,14.68    ,14.88   ,15.09    ,15.29    ,15.49   ,15.7    ,15.9     ,16.1    ,16.31    ,16.51    ,16.71   ,16.92    ,17.12    ,17.32    ,17.53    ,17.73    ,17.93   ,18.14    ,18.34   ,18.54    ,18.75   ,18.95   ,19.15    ,19.35    ,19.56   ,19.76    ,19.96     ,20.17     ,20.37    ,20.57    ,20.78    ,20.98     ,21.18    ,21.39    ,21.59    ,21.79     ,22        ,22.2     ,22.4       ,22.61     ,22.81    ,23.01    ,23.22     ,23.42     ,23.62     ,23.83     ];
  ring(USSizes_All[search([str(sizeValue)],USValues_All)[0]]);
}

else if (search([Country],ISO_Countries)[0]>0)
{
  EUValues_All =["44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71"];
  EUSizes_All  =[14.01,14.33,14.65,14.97,15.29,15.61,15.92,16.24,16.56,16.88,17.2,17.52,17.83,18.15,18.47,18.79,19.11,19.43,19.75,20.06,20.38,20.7,21.02,21.34,21.66,21.97,22.29,22.61];
  //source : http://www.cartier.fr/fr/services/le-guide-cartier/guide-des-tailles/guide-des-tailles-bagues/-10402.html
  ring(EUSizes_All[search([str(sizeValue)],EUValues_All)[0]]);
}

else if (search([Country],Spain_Countries)[0]>0)
{
  SpainValues_All =["0.5", "1"  , "1.75", "2.25", "3"  , "3.5", "4.25", "4.75", "5.5", "6"  , "6.75", "7.5", "8"  , "8.75", "9.25", "10", "10.5", "11.25", "11.75", "12.5", "13.25", "13.75", "14.5", "15" , "15.75", "16.25", "17" , "17.5", "18.25", "19" , "19.5", "20.25", "20.75", "21.5", "22" , "22.75", "23.25", "24" , "24.75", "25.25", "26" , "26.5", "27.25", "27.75", "28.5", "29", "29.75", "30.5", "31" , "31.75", "32.25", "33" , "33.5", "34.25", "34.75"];
  SpainSizes_All  =[12.85, 13.06, 13.26 , 13.46 , 13.67, 13.87, 14.07 , 14.27 , 14.48, 14.68, 14.88 , 15.09, 15.29, 15.49 , 15.7  , 15.9, 16.1  , 16.31  , 16.51  , 16.71 , 16.92  , 17.12  , 17.32 , 17.53, 17.73  , 17.93  , 18.14, 18.34 , 18.54  , 18.75, 18.95 , 19.15  , 19.35  , 19.56 , 19.76, 19.96  , 20.17  , 20.37, 20.57  , 20.78  , 20.98, 21.18 , 21.39  , 21.59  , 21.79 , 22  , 22.2   , 22.4  , 22.61, 22.81  , 23.01  , 23.22, 23.42 , 23.62  , 23.83  ];
  ring(SpainSizes_All[search([str(sizeValue)],SpainValues_All)[0]]);
}

else if (search([Country],UK_Countries)[0]>0)
{
  UKValues_All=["A"  , "A 1/2", "B"  , "B 1/2", "C"  , "C 1/2", "D"  , "D 1/2", "E"  , "E 1/2", "F"  , "F 1/2", "G"  , "G 1/2", "H"  , "H 1/2", "I"  , "J"  , "J 1/2", "K" , "K 1/2", "L"  , "L 1/2", "M"  , "M 1/2", "N"  , "N 1/2", "O"  , "O 1/2", "P"  , "P 1/2", "Q"  , "Q 1/2", "R"  , "R 1/2", "S"  , "S 1/2", "T"  , "T 1/2", "U"  , "U 1/2", "V"  , "V 1/2", "W"  , "W 1/2", "X"  , "X 1/2", "Y"  , "Z"  , "Z 1/2", "Z1", "Z2" , "Z3" , "Z4" ];
  UKSizes_All =[12.04, 12.24  , 12.45, 12.65  , 12.85, 13.06  , 13.26, 13.46  , 13.67, 13.87  , 14.07, 14.27  , 14.48, 14.68  , 14.88, 15.09  , 15.29, 15.49, 15.7   , 15.9, 16.1   , 16.31, 16.51  , 16.71, 16.92  , 17.12, 17.32  , 17.53, 17.73  , 17.93, 18.14  , 18.34, 18.54  , 18.75, 18.95  , 19.15, 19.35  , 19.56, 19.76  , 19.96, 20.17  , 20.37, 20.57  , 20.78, 20.98  , 21.18, 21.39  , 21.59, 21.79, 22     , 22.4, 22.81, 23.01, 23.42];
  ring(UKSizes_All[search([str(sizeValue)],UKValues_All)[0]]);
}

else if (search([Country],India_Countries)[0]>0)
{
  IndiaValues_Main   =["1"      ,"2"     ,"3"      ,"4"      ,"5"      ,"6"      ,"7"      ,"8 1/2"  ,"9"     ,"10"     ,"11"     ,"12"     ,"13"     ,"14"     ,"15"     ,"16"    ,"17"     ,"18"     ,"19"    ,"20"     ,"21"     ,"22"     ,"23"      ,"24"     ,"25"     ,"26"      ,"27"      ,"28"     ,"29"      ,"30"     ,"31"      ,"32"     ,"33"      ,"34"      ,"35"      ];
  IndiaSizes_Main    =[13.06    ,13.26   ,13.67    ,13.87    ,14.27    ,14.68    ,15.09    ,15.29    ,15.49   ,15.9     ,16.31    ,16.51    ,16.92    ,17.32    ,17.53    ,17.93   ,18.14    ,18.54    ,18.75   ,19.15    ,19.35    ,19.76    ,19.96     ,20.37    ,20.57    ,20.98     ,21.39    ,21.59    ,22        ,22.2     ,22.61     ,22.81    ,23.22     ,23.62     ,23.83     ];
  ring(IndiaSizes_Main[search([str(sizeValue)],IndiaValues_Main)[0]]);
}

else if (search([Country],China_Countries)[0]>0)
{
  ChinaValues_Main   =["1"  ,"2"     ,"3"      ,"4"     ,"5"      ,"6"      ,"7"     ,"8"      ,"9"     ,"10"    ,"11"     ,"12"    ,"13"     ,"14"     ,"15"     ,"16"     ,"17"     ,"18"    ,"19"     ,"20"     ,"21"      ,"22"      ,"23"     ,"24"      ,"25"    ,"26"      ,"27"     ];
  ChinaSizes_Main    =[12.45,13.26   ,13.67    ,14.07   ,14.27    ,14.68    ,14.88   ,15.29    ,15.7    ,16.1    ,16.51    ,16.71   ,16.92    ,17.32    ,17.73    ,18.14    ,18.54    ,18.95   ,19.35    ,19.76    ,19.96     ,20.17     ,20.57    ,20.98     ,21.39   ,21.79     ,22.2     ];
  ring(ChinaSizes_Main[search([str(sizeValue)],ChinaValues_Main)[0]]);
}

else if (search([Country],Japan_Countries)[0]>0)
{
  JapanSizes_All    =[12.37,13.21   ,13.61    ,14.05   ,14.36    ,14.56    ,14.86    ,15.27    ,15.7     ,16       ,16.51   ,16.92    ,17.35    ,17.75    ,18.19    ,18.53   ,18.89   ,19.41    ,19.84   ,20.02    ,19.96     ,20.68    ,21.08    ,21.49    ,21.89    ,22.33     ];
  JapanValues_All   =["1"  ,"2"     ,"3"      ,"4"     ,"5"      ,"6"      ,"7"      ,"8"      ,"9"      ,"10"     ,"12"    ,"13"     ,"14"     ,"15"     ,"16"    ,"17"     ,"18"    ,"19"     ,"20"     ,"21"      ,"22"    ,"23"     ,"24"     ,"25"     ,"26"     ,"27"  ];
  //JapanSource="http://www.ringsizes.co/"
  ring(JapanSizes_All[search([str(sizeValue)],JapanValues_All)[0]]);
}

else
  ring(sizeValue);

module ring(diameter){
  rotate_extrude(){
    translate([diameter/2+thickness,0])
      scale([thickness,ringheight])
        translate([0,1])
          circle(r =1);
  }
}
```


[User]
Hey there, I'm looking to generate a customizable phone holder using OpenSCAD. I'd like it to be parametric so I can easily adjust it for different phone sizes.

Basically, the holder should be a rounded box with an opening in the middle to hold the phone. I need to be able to adjust:

*   The width, thickness, and height of the main holder.
*   The thickness of the walls of the holder.
*   The height and width of a lip at the front of the holder.
*   Whether or not there's a hole in that front lip, and how wide it should be.
*   Whether there's a hole in the bottom of the holder for charging or speakers, and its size.

I'd like to be able to specify the following variables:

`pWidth`:  Item's width (X-axis)
`pThick`: Item's thickness (Y-axis)
`HHolder`: Mount/Holder height (Z-axis)
`WallThick`: Thickness of the walls
`HLip`: Height of the front lip
`WLip`: Width of the front lip
`FHole`:  Whether or not there's a front hole on the lip (1 = yes, 0 = no)
`FWidth`: Front hole lip length
`BHole`: Whether or not there's a bottom hole for charging/speakers (1 = yes, 0 = no)
`BWidth`: Width of the rim of the bottom hole
`BThick`: Thickness of the rim of the bottom hole

I'm planning on using this with a separate mounting system, so the holder itself just needs to be the main part. Also, it would be useful to use the `boxes.scad` library from the MCAD library to get the rounded box functionality.

Could you generate the OpenSCAD code for this? Thanks!

[Assistant]
Customizeable_Phone_Holder.scad:
```
echo(version=version());
/*
Customizable Phone Holder
Created by: Zeakfury
Created date: 01/16/2017
*/

// Include Boxes library to get easy rounded boxes
include <MCAD/boxes.scad>

//Viewer
rotate([0,0,180])
render()
Item_Holder();

//Setup Variables

/* [Item Dimensions] */
//- Item's Width (X-Axis)
pWidth = 83.5;

//- Item's Thickness (Y-Axis)
pThick = 11;

//- Mount/Holder Height (Z-Axis)
HHolder = 40;

//- Thickness of the walls for the Mount
WallThick = 3;//

/* [Supports] */
//- Height of Horizontal Front Lip
HLip = 10;//

//- Width of Vertical Front Lip
WLip = 20;//

//- Front Hole on Lip (0=No 1=Yes)
FHole = 1;// [1:Yes,0:No]

//- Front Hole Lip Length
FWidth = 5;//

/* [Bottom Hole] */
//- Bottom Hole for charger/speakers (0=No 1=Yes)
BHole = 1;// [1:Yes,0:No]

//- Width for Rim of Hole to Hold Item
BWidth = 2;

//- Thick for Rim of Hole to Hold Item
BThick = 2;

//Create Body
module Item_Holder() {
    //rotate([pTilt*-1,0,0]){
        difference(){
            //Main Shape
            union(){
                roundedBox([pWidth+WallThick*2,pThick+WallThick*2,HHolder+WallThick], 2, true, $fn=40);

            }
            //Remove Parts
            union(){
                //Phone Hole
                translate([0,0,WallThick])
                    color("green")
                cube([pWidth,pThick,HHolder+WallThick], true);
                //Lip Height
                translate([-(pWidth-WLip)/2,pThick/2,WallThick/2-(HHolder/2-HLip)])
                    color("blue")
                cube([pWidth-WLip,WallThick,HHolder-HLip], false);
                //Lip Hole
                if (FHole == 1 && BHole == 1 && BThick <= pThick){
                    translate([-(pWidth-FWidth*2-WLip)/2,(pThick/2-BThick),-(HHolder+WallThick)/2])
                        color("pink")
                    cube([pWidth-(FWidth*2)-WLip,WallThick+(BThick),HLip+WallThick],false);
                    }else if (FHole == 1 && (BHole == 0 || BThick > pThick)){
                    translate([-(pWidth-FWidth*2-WLip)/2,(pThick/2),-(HHolder+WallThick)/2])
                        color("pink")
                    cube([pWidth-(FWidth*2)-WLip,WallThick,HLip+WallThick],false);}
                //Bottom Hole
                if (BHole == 1 && BWidth < pWidth && BThick < pThick) {
                    translate([-(pWidth-(BWidth*2))/2,-(pThick-(BThick*2))/2,-(HHolder+WallThick)/2])
                        color("red")
                    cube([pWidth-(BWidth*2),pThick-(BThick*2),WallThick],false);}

            }
         }

        //}
}

```


[User]
I'm looking to create some bases for my papercraft buildings for Dropzone Commander. I've been using some corner pieces, but they're a bit fiddly, and I'd rather have a full base that the buildings slot into. I need it to be parametric so I can easily adjust it to fit the various building sizes I have.

Here's what I'm envisioning:

*   **Building Sizes:** The bases should accommodate three standard building sizes: 71mm x 109mm, 109mm x 109mm, and 109mm x 180mm. These should be adjustable as parameters.
*   **Slot:** There needs to be a slot in the base that the building sits in. The slot should be slightly larger than the building size to allow for the thickness of the paper. I’d like to be able to set how high the slot is above the sidewalk surface, as well as the thickness of the building material. The building material is doubled in some spots, so the slot needs to be a bit wider to allow for that.
*   **Sidewalk:** The base needs a sidewalk section that extends out from the building slot. I'd like to control how far the sidewalk extends outwards, as well as its height, so I can create bases that are heavy enough to not move around easily.
*   **Sidewalk Texture:** To make it look nicer, the sidewalk should have grooves cut into it, sort of like a tiled pattern. The depth of these grooves should also be adjustable as a parameter, and should be less than the overall sidewalk height.
*  **Sidewalk Squares:** The number of squares should scale according to the size of the base, to keep them roughly similar in appearance regardless of the building size. Specifically, 18 squares is good for the 180mm length, 10 for the 109mm length, and 7 for the 71mm length. The width should scale to match.

It would be really great if I could set the following parameters:

*   `width`: The width of the building (71, 109, or 180mm).
*   `length`: The length of the building (71, 109, or 180mm).
*  `slot_height`: How high above the sidewalk the slot should be.
*   `paper`: The thickness of the paper used for the buildings.
*   `sidewalk_width`: How far the sidewalk extends from the building slot.
*   `sidewalkHeight`: The height of the sidewalk.
*   `groove_depth`: The depth of the grooves in the sidewalk.
*  `sidewalk_squares`: The number of sidewalk squares along the length (this should be set automatically).

I’m hoping that OpenSCAD can do all of this. I’m not really familiar with any particular libraries. Could you generate the necessary OpenSCAD file(s)?

[Assistant]
Building_sidewalk.scad:
```
//CUSTOMIZER VARIABLES
// Building sizes are 71mmx109mm, 109mmx109mm or 109mmx180mm
// The width of the building.
width=109; //[71:71 mm / 2 3/4", 109:109mm / 4 1/4", 180:180mm / 7"]
// The length of the building.
length=180; //[71:71 mm / 2 3/4", 109:109mm / 4 1/4", 180:180mm / 7"]
// How high above the sidewalk to make the slot for the building to fit in, in mm. 3 is recommended.
slot_height=3; //[1:5]
// How thick is the material of the building in mm. Note that the building is double-thik in places. 2 mm recommended.
paper=2;
// How much should the sidewalk stick out from the building, in mm. 5 is standard.
sidewalk_width=5;
// How high is the sidewalk, in mm. 1.5 is standard.
sidewalkHeight=1.5;
// How deep to make the grooves for the sidewalk texture. Should be less than sidewalk height. 0.5 is standard.
groove_depth=0.5;
// Number of sidewalk squares along the length. 18 is standard for 7". 10 is standard for 4". The number is scaled for the width.
sidewalk_squares= length==180 ? 18 : length==109 ? 10 : 7;
//CUSTOMIZER VARIABLES END

// number of sidewalk squares along the width
sidewalk_squares_width = round(sidewalk_squares*width/length);

// How wide is the sidewalk - include room for the slot.
base_width=sidewalk_width+3*paper;

// Outer perimeter of the whole thing.
outer_width=width+3*paper+2*base_width;
outer_length=length+3*paper+2*base_width;

// Outer perimeter of the building slot
outerSlotWidth=width+3*paper;
outerSlotLength=length+3*paper;

// Outer perimeter of the bit to remove in the middle.
innerWidth=width-3*paper;
innerLength=length-3*paper;

module sidewalk() {
    //Sidewalk
    difference() {
        // base
        cube([outer_length, outer_width, sidewalkHeight]);
        //remove from base
        translate([base_width+3*paper, base_width+3*paper,-1]) cube([innerLength,innerWidth,slot_height+2]);

        // x-axis groove nearest street
        translate([groove_depth,groove_depth,sidewalkHeight-groove_depth]) {
            cube([outer_length-1, 0.5, groove_depth+1]);
        }
        translate([groove_depth,outer_width-1,sidewalkHeight-groove_depth]) {
            cube([outer_length-1, 0.5, groove_depth+1]);
        }
        // y-axis groove
        translate([groove_depth,groove_depth,sidewalkHeight-groove_depth]) {
            cube([0.5, outer_width-1, groove_depth+1]);
        }
        translate([outer_length-1,groove_depth,sidewalkHeight-groove_depth]) {
            cube([0.5, outer_width-1, groove_depth+1]);
        }

        // sidewalk squares Length
        for(x=[0:1:sidewalk_squares]) {
            translate([base_width+x*outerSlotLength/sidewalk_squares, groove_depth+0.5, sidewalkHeight-groove_depth])
                cube([groove_depth,base_width-groove_depth-0.5,groove_depth+1]);
            translate([base_width+x*outerSlotLength/sidewalk_squares, outer_width-base_width-groove_depth-0.5, sidewalkHeight-groove_depth])
                cube([groove_depth,base_width-groove_depth-0.5,groove_depth+1]);
        }
        // sidewalk squares Width
        for(x=[0:1:sidewalk_squares_width]) {
            translate([groove_depth, base_width+x*outerSlotWidth/sidewalk_squares_width, sidewalkHeight-groove_depth])
                cube([base_width-groove_depth-0.5,groove_depth,groove_depth+2]);
            translate([outer_length-base_width-groove_depth, base_width+x*outerSlotWidth/sidewalk_squares_width, sidewalkHeight-groove_depth])
                cube([base_width-groove_depth-0.5,groove_depth,groove_depth+2]);
        }
    }
}
module buildingSlot() {
    translate([base_width, base_width, sidewalkHeight]) {
        difference() {
            // outer building Slot
            cube([outerSlotLength, outerSlotWidth,slot_height]);
            // inner building Slot
            translate([3*paper,3*paper,-1]) cube([innerLength,innerWidth,slot_height+2]);
            // Lengthwise building slot
            translate([paper,paper,0]) cube([length+paper,paper,slot_height+1]);
            translate([paper,width+paper,0]) cube([length+paper,paper,slot_height+1]);
            // width-wise building slot
            translate([paper,paper,0]) cube([paper, width+paper,slot_height+1]);
            translate([length+paper,paper,0]) cube([paper, width+paper,slot_height+1]);
        }
    }
}

sidewalk();
buildingSlot();

```


[User]
Hey, I'm looking for some help designing a customizable toroidal helix in OpenSCAD. I've got a pretty good idea of what I want, but I'm not great with the math and I'd rather not spend a ton of time figuring out the exact equations myself.

Basically, I want to create a tube that wraps around in a torus shape, but also winds around the torus a certain number of times like a spring or a DNA helix. I'd like to be able to control the following:

*   **Windings:** The number of times the helix wraps around the torus. This will probably be a smaller integer, like 0-5.
*   **Revolutions:** The number of full revolutions the tube makes around the central axis of the torus. This will be a bigger number, maybe 0-20.
*   **Torus Radius (R):** The radius of the torus itself, measured from the central axis to the center of the tube's path.
*   **Tube Radius (r):** The radius of the tube as it wraps around, like how thick the spring wire is.
*  **Tube Thickness (fattness):**  The overall thickness of the tube, controlled by the radius of the spheres that get used for the hull.
*   **Resolution:** The resolution of the sphere along the tube path. More spheres means longer render times.
*   **Winding Direction:** A parameter to specify if the tube winds clockwise or counterclockwise. Think of this as a simple 1 or -1 value.

I'd like to use the `hull()` function to create the tube, and I'd rather not try to do this with a rotating cube. The user should be able to control these parameters via variables. I am not familiar with other libraries or modules, so let's keep it all in one file for now. Could you help me generate the OpenSCAD code for this?

[Assistant]
customizable_torus.scad:
```
//it's torus time

//number of windings, keep windings low if revs is high
windings = 1; //[0:5]

//number of revolutions around the z axis
revs = 10; //[0:20]

//central radius from the z axis to the center of the helix
R = 9; //[0:20]

//radius of the helix
r = 6; //[0:10]

//size of the spheres(fattness of the tubes)
fattness = 8; //[1:30]

//tube resolution. higher resolution is a longer render
resolution = 10; //[10:20]

//direction of the winding. -1 or 1
direction = 1; //[1, -1]

for(t=[0:359*revs])
{
	hull()
	{
		translate([cos(t)*(R-r*cos(360+direction*(windings+1/revs)*t)),
				   sin(t)*(R-r*cos(360+direction*(windings+1/revs)*t)),
				   r*sin(360+direction*(windings+1/revs)*t)])
		{
			sphere($fn=resolution, .1*fattness, true);
		}
		translate([cos(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))),
				   sin(t+1)*(R-r*cos(360+direction*(windings+1/revs)*(t+1))),
				   r*sin(360+(windings+1/revs)*direction*(t+1))])
		{
			sphere($fn=resolution, .1*fattness, true);
		}
	}
}
```


[User]
I'm looking to design a parametric practice mute for brass instruments, like trombones, trumpets, and flugelhorns. I want it to be highly customizable through parameters so I can adjust the fit and sound for different instruments.

Here's what I'm envisioning:

**Overall Shape and Dimensions:**

*   The mute should have a generally bulbous shape, with a narrower top that goes inside the instrument's bell, a wider mid-section, and a base that extends outside the bell.
*   I need parameters for:
    *   `mute_top_radius`: The radius of the top of the mute (the part inside the bell).
    *   `mute_wide_radius`: The radius of the widest part of the mute.
    *   `mute_base_radius`: The radius of the base of the mute that sticks out of the bell.
    *   `mute_flare`: A parameter to control the flare of the main body of the mute.
    *   `mute_bottom_flare`: A parameter to control the flare of the bottom part of the mute.
    *   `mute_top_height`: The height of the top part of the mute.
    *   `mute_bottom_height`: The height of the bottom part of the mute.

**Muting Tube:**

*   The mute should have a small, internal tube to restrict airflow and mute the sound.
*   I'd like parameters for:
    *   `hole_diameter_top`: The diameter of the muting tube at the top.
    *   `hole_diameter_small`: The diameter of a smaller section within the muting tube.
    *   `hole_diameter_bottom`: The diameter of the muting tube at the bottom.

**Bell Fit:**

*   I need an option to create a tapered area at the base of the mute for better fit in the instrument's bell.
*   I need a boolean parameter to control whether or not to render this fit area: `render_better_fit_area` (values should be "yes" or "no").
*   If this is enabled, I need parameters for:
    *   `tapered_area_height`: The height of the tapered area.
    *   `tapered_area_width`: The width of the tapered area
    * `tapered_area_flare`: The flare for the tapered area.

**Wall Thickness:**

*   A parameter to set the overall wall thickness of the mute: `bell_wall_thickness`.

**Detail and Text:**

*   I need parameters for controlling the resolution and detail of the generated mute (for development vs. printing):
    *   `$fn`: Steps for rotate_extrude calls (for general resolution).
    *   `steps`: Steps for the bessel curve, increases mute detail
*   I also need an option to write text on the mute:
    *   `write_text`: A boolean ("yes" or "no") to enable/disable text.
    *   `text_to_write`: The text string.
    *   `letter_height`: The height of the text from the bottom.
    *   `letter_rotation`:  The rotation of the text to fit the mute.

**Hidden Parameters (For your reference):**

*   `mute_input`: An array defining bessel curves for the mute's profile.
*   `render_cork`:  A boolean to render the cork, used for visualization purposes.
*   `cork_thickness`: The thickness of the cork for the fit area.

**Libraries:**

*   I expect that you'll use the `BOSL` library for some of the advanced geometry and transformation functions and the standard library functions included with OpenSCAD.

I need the output to be a single, parametric `.scad` file that I can open and customize using the customizer. Please make sure the code is well-commented. I'd like to be able to tweak all of those parameters in the customizer, so they should all be declared at the top of the file.

[Assistant]
practice_mute_v1.1.scad:
```
/* [Mute Dimensions] */
//the radius of the top of the mute, that is inside the bell
mute_top_radius=25;// [5:0.5:100]
//the radius of the widest part of the mute
mute_wide_radius=49;// [5:0.5:200]
//the radius of the base/bottom of the mute that sticks out of the bell
mute_base_radius=25;// [5:0.5:100]

//the flare of the mute. Changes the shape.
mute_flare=0.6; // [0:0.02:8]

//the flare of the bottom of the mute. Changes the shape
mute_bottom_flare=-0.6; // [-4:0.02:0]
//the height of the top part of the mute
mute_top_height=108;
//the height of the bottom part of the mute
mute_bottom_height=40;

/* [Muting tube] */
//the diameters of the small tube used to mute
hole_diameter_top = 3.8;
//It contains a smaller area, the diameter of that is configurable here
hole_diameter_small=3.5;
//the diameter of the bottom of the muting tube
hole_diameter_bottom = 4.6;

/* [Bell fit] */
//sometimes the taper of the bell is different than that of the mute. Set to true for a different fit area of the mute, false to remove it.
render_better_fit_area="yes"; // [yes, no]
//the height of the tapered area that fits the bell. It's the outside shape only
tapered_area_height = 20;
tapered_area_width=3.55;
tapered_area_flare=0.6;

/* [Wall thicknesses] */
//the wall thickness of the mute. If you increase the diameter, you might want to increase this.
bell_wall_thickness = 1.2;

/* [DETAIL PARAMETERS] */
//steps for all rotate_extrude calls. For development: 20 is enough. For printing set to 300
$fn = 300;
//steps of the bessel curve for loop. Increases mute detail.
steps=100;

/* [Text on mute] */
//write text on mute
write_text="no"; // [no, yes]
//the text on the mute
text_to_write="PrintBone";
//the height of the text on the mute from the bottom
letter_height=52;
//rotation of the text so it fits well on the mute
letter_rotation=-21;

/* [Hidden]*/
//the mute, as a series of bessel curves
mute_input = [
    ["BESSEL", mute_top_radius, mute_wide_radius, mute_flare, mute_top_height],
    ["BESSEL", mute_wide_radius, mute_base_radius, mute_bottom_flare, mute_bottom_height]
];
//the thickness of the cork used, for visualization
render_cork = false;
cork_thickness = 1.6;

//the curve (not yet a polygon, just a set of points on a line for now!) of the mute
bell_profile = create_bell_profile(mute_input, steps);

//it's possible to render a bell profile of a trombone to check the fit of the mute.
// This is the printbone, but you can render any trombone you want of course
render_bell_profile = false;

bell_input = [
//part of the printbone, for reference
    ["BESSEL", 15.07, 22.28, 0.894, 150.42],
    ["BESSEL", 22.28, 41.18, 0.494, 96.85],
    ["BESSEL", 41.18, 8.5*25.4/2, 1.110, 55.93]
];
bell_height = sum_length(mute_input, 0);
bell_profile_full = create_bell_profile(bell_input, 50);

cork_bessel = [
    ["BESSEL", bell_profile[0][0], bell_profile[0][0]+tapered_area_width, tapered_area_flare, tapered_area_height],
    ["CONE", bell_profile[0][0]+tapered_area_width, bell_radius_at_height(bell_profile, bell_height-tapered_area_height-2.2), 2.2]
];

cork_profile = create_bell_profile(cork_bessel, 50);

render_bell_profile=false;

//tests if the mute will fit. should fit both of these
/* approximation (not perfect) of a german style trumpet*/
bell_input = [
["BESSEL", 29.9/2, 35.8/2, 0.9, 40],
["BESSEL", 35.8/2, 45.8/2, 0.9, 30],
["BESSEL", 45.8/2, 78.2/2, 0.7, 30],
["BESSEL", 78.2/2, 139/2, 0.9, 20]
];

/* rough generic modern trumpet */
bell_input = [
["BESSEL", 11.2/2, 130/2, 0.6, 606]
];
bell_height = sum_length(mute_input, 0);
bell_profile_full = create_bell_profile(bell_input, 200);

//for(i = [80:-5:0]) {
//    echo(i, "mm ", bell_radius_at_height(bell_profile_full, i)*2);
//}

cork_bessel = [
    ["BESSEL", bell_profile[0][0], bell_profile[0][0]+tapered_area_width, tapered_area_flare, tapered_area_height],
    ["CONE", bell_profile[0][0]+tapered_area_width, bell_radius_at_height(bell_profile, bell_height-tapered_area_height-2.2), 2.2]
];

cork_profile = create_bell_profile(cork_bessel, 50);

/**
 *gives a [start:step:end] array that guarantees to include end. uglyness :)
 */
function array_iterator(start, step, end) =
    let(result = [for (i=[start:step:end]) i ])
    result[len(result)-1] == end ? result :
    concat(
        result,
        [end]
    );

/*
Module to render a bell based on multiple bessel curves
 To create a bessel curve:
 bessel_curve(throat_radius=10.51, mouth_radius=108.06, length=200, flare=0.78, wall_thickness=3)

 To create a bell profile, do the following:
Array of input. First element defines type:
["CYLINDER", radius, length]
["CONE", r1, r2, length]
["BESSEL", r_small, r_large, flare, length]

bell_input = [
    ["CYLINDER", 10/2, 40],
    ["CONE", 10.2/2, 10.3/2, 15],
    ["CONE", 10.3/2, 12.7/2, 44],
    ["BESSEL", 14.7/2, 23/2, 1.260, 223],
    ["BESSEL", 23/2, 37/2, 0.894, 72],
    ["BESSEL", 37/2, 61.8/2, 0.7, 36.6],
    ["BESSEL", 61.8/2, 8.5*25.4/2, 1, 14.37],
];

bell_polygon = create_bell_profile(bell_input, steps=100);

rotate_extrude()
extrude_line(bell_polygon, wall_thickness=2, solid=false, normal_walls=true);
*/

/*
#rotate_extrude()
bessel_curve(throat_radius=6.51, mouth_radius=94/2, length=400, flare=0.9, wall_thickness=3, solid=true, steps=100);

bell_input = [
    ["CYLINDER", 10.3/2, 40],
    ["CONE", 10.2/2, 10.3/2, 15],
    ["CONE", 10.3/2, 12.7/2, 44],
    ["BESSEL", 12.7/2, 23/2, 1.260, 223],
    ["BESSEL", 23/2, 37/2, 0.894, 72],
    ["BESSEL", 37/2, 61.8/2, 0.7, 36.6],
    ["BESSEL", 61.8/2, 94/2, 1, 14.37],
];

bell_polygon = create_bell_profile(bell_input, steps=200);

rotate_extrude($fn=200)
extrude_line(bell_polygon, wall_thickness=2, solid=false);*/

function create_bell_profile(input, steps=100) =
    concat_array(
        [
            for (i =[0:len(input)-1])
                translate_cylinder_input(input, i, steps)
        ]
    );

function concat_array(input, i=0) =
    i >= len(input) ?
        [] :
        concat(input[i], concat_array(input, i+1));
            ;

// Haven't found a better way to define this in openscad. It works...
function translate_cylinder_input(input, i, steps) =
    let(value=input[i])
    value[0] == "CYLINDER" ?
            [
                [value[1], -sum_length(input, i)],
                [value[1], -sum_length(input, i+1)]
            ]
            : translate_cone_input(input, i, steps);
            ;

function translate_cone_input(input, i, steps) =
    let(value=input[i])
    value[0] == "CONE" ?
            [
                [value[1], sum_length(input, i)],
                [value[2], sum_length(input, i+1)]
            ]
            : translate_bessel_input(input, i, steps);
            ;

function translate_bessel_input(input, i, steps) =
    let(value=input[i])
    value[0] == "BESSEL" ?
//            [value[1], -sum_length(input, i)]
            2d_bessel_polygon(translation=sum_length(input, i+1),  throat_radius=value[1], mouth_radius=value[2], length=value[4], flare=value[3], steps=steps)
            : "ERROR";
            ;

// sum the length parameter of all input curves of point i and later. Length is always last
// input is array of instructions
function sum_length(input, i, sum = 0) =
    i >= len(input) ? sum : sum_length(input, i+1, sum + input[i][len(input[i])-1]);

function cut_curve(curve, min_height, max_height) =
    cut_curve_at_height2( //bell_polygon,
        cut_curve_at_height(curve, min_height, max_height)
        , min_height, max_height);

/*
Renders a cone shaped tube.
wall is wall thickness
*/
module conic_tube(h, r1, r2, wall, center = false) {
  difference() {
          cylinder(h=h, r1=r1+wall, r2=r2+wall, center=center);
          cylinder(h=h, r1=r1, r2=r2, center=center);
  }
}

module conic_tube_conic_wall(h, r1, r2, wall1, wall2, center = false) {
  difference() {
          cylinder(h=h, r1=r1+wall2, r2=r2+wall1, center=center);
          cylinder(h=h, r1=r1, r2=r2, center=center);
  }
}

/*
* Bessel horn bell equation from
* http://www.acoustics.ed.ac.uk/wp-content/uploads/Theses/Braden_Alistair__PhDThesis_UniversityOfEdinburgh_2006.pdf
*/

module bessel_curve(translation=0, throat_radius, mouth_radius, length, flare, wall_thickness, solid=true, steps=100) {

   2d_bessel = 2d_bessel_polygon(translation, throat_radius, mouth_radius, length, flare, steps);
   extrude_line(2d_bessel, wall_thickness, solid);

}

EPSILON = 0.00000000001;
function abs_diff(o1, o2) =
    abs(o1-o2);

//from a single line, make a wall_thickness wide 2d polygon.
//translates along the normal vector without checking direction, so be careful :)
module extrude_line(input_curve, wall_thickness, solid=false, remove_doubles=true, normal_walls=true) {
    //remove consecutive points that are the same. Can't have that here or we'll have very strange results

    extrude_curve = remove_doubles ? concat([input_curve[0]], [for (i = [1:1:len(input_curve)-1]) if(abs_diff(input_curve[i][1], input_curve[i-1][1]) > EPSILON || abs_diff(input_curve[i][0], input_curve[i-1][0]) > 0.001) input_curve[i]]) : input_curve;
//        echo("walls normal?", normal_walls);
    outer_wall =  [for (i = [len(extrude_curve)-1:-1:1])
                    extrude_curve[i] + get_thickness_vector(normal_walls, wall_thickness, extrude_curve, i)
                    ];

    //make sure we have a horizontal edge both at the top and bottom
    //to ensure good printing and gluing possibilities
    bottom_point = [extrude_curve[len(extrude_curve)-1]+[wall_thickness, 0]];
    top_point = [extrude_curve[0]+[wall_thickness, 0]];

    outer_curve = concat(
            bottom_point,
            outer_wall,
            top_point
    );

    if(!solid) {
        // a bug in openscad causes small polygons with many points to render a MUCH lower resolution.
        //so scale up by factor 100
        scale([0.01, 0.01, 0.01])
        polygon( points=
           concat(
            [ for (x=extrude_curve) [x[0]*100, x[1]*100]],
            [ for (x=outer_curve) [x[0]*100, x[1]*100]]
            )
        );
    } else {
        scale([0.01, 0.01, 0.01])
      polygon( points=
       concat(
          [[0, bottom_point[0][1]*100]],
          [ for (x=outer_curve) [x[0]*100, x[1]*100]],
          [[0, top_point[0][1]*100]]
        )
    );
    }
}

function get_thickness_vector (normal_walls, wall_thickness, extrude_curve, i) =
        let( normal_vector = unit_normal_vector(extrude_curve[i-1], extrude_curve[i]))
        (normal_walls) ?
            normal_vector * wall_thickness
        : (
                //horizontal walls need special treatment in this case
                normal_vector == [0,1] ? [0,-wall_thickness]:
                [wall_thickness, 0]
        );

function 2d_bessel_polygon(translation=0, throat_radius, mouth_radius, length, flare, steps=30) =

    //inner curve of the bell
    let(
        b = bessel_b_parameter(throat_radius, mouth_radius, length, flare),
        x_zero = bessel_x_zero_parameter(throat_radius, b, flare),
        step_size = (length)/steps
    )

    [for (i = array_iterator(x_zero, step_size, x_zero + length))
         [bell_diameter(b, i, flare), -(i-(x_zero+length))] + [0, translation]
    ];

function bell_diameter(B, y, a) =
//   B/pow(y + y_zero,a);
   B*pow(-y,-a);

function bessel_b_parameter(r0, r1, d, gamma) =
    pow(
    (d/
        (
            pow(r0, -1/gamma) -
            pow(r1, -1/gamma)
        )
    ), gamma);

function bessel_x_zero_parameter(r0, b, gamma) =
    - pow(r0/b, -1/gamma);

function unit_normal_vector(p1, p2) =
    let(
        dx = p2[0]-p1[0],
        dy = p2[1]-p1[1]
        )
        [-dy, dx]/norm([-dy,dx]);

function cut_curve_at_height(curve, min_height, max_height) =
    concat(
        [
            for (i = [0:1:len(curve)-2])
                if(curve[i+1][1] >= min_height)// && curve[i][1] <= max_height)
                   curve[i]
        ],
        [for (i = [len(curve)-1]) if(curve[i][1] >= min_height) curve[i]]
    );

function cut_curve_at_height2(curve, min_height, max_height) =

    concat(
        [for (i = [0]) if(curve[i][1] <= max_height) curve[0]],
        [
        for (i = [1:1:len(curve)-1])
            if( curve[i][1] <= max_height)
               curve[i]
        ]
    );

function radius_at_height(curve, height) =
        lookup(-height, reverse_key_value(curve));
      /* [for (i = [1:1:len(curve)-1])
            if( curve[i-1][1] <= height && curve[i][1] >= height)
               curve[i][0]
        ][0]
            ;*/

function reverse_key_value(array) =
    [for (i = [len(array)-1:-1:1])
        [-array[i][1], array[i][0]]
    ];

if(render_bell_profile) {
    translate([0, 0, 35])
rotate([90,0,0])
//rotate_extrude()
    extrude_line(input_curve=bell_profile_full, wall_thickness=bell_wall_thickness, solid=false, remove_doubles=true, normal_walls=true);
}

if(write_text == "yes") {
    translate([0,0,letter_height])
        rotate([0,0,0])
        writeOnMute(
            text=text_to_write,
            radius=radius_at_height(bell_profile, letter_height)+bell_wall_thickness-0.4,
            letter_rotation=letter_rotation,
            h=8.5);
}

module writeOnMute(text,radius,letter_rotation, h=5, t=1, east=0, west=0, space =1.0, font){
    bold=0;
	center=false;
	rotate=0;			// text rotation (clockwise)

    pi2=PI*2;
    up =0;		 //mm up from center on face of cube
	down=0;

	wid=(.125* h *5.5 * space);
	widall=wid*(text_width(text, 0, len(text)-1))/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360*(1-abs(rotate)/90);
	//angle of half width of text

	function mmangle(radius)=(widall/(pi2*radius)*360);
    translate([0,0,up-down])
    rotate(east-west,[0,0,1])
    for (r=[0:len(text)-1]){
        rotation_width = text_width(text, 0, r);
        letter_width = text_width_one_letter(text, r);

        rotate(-90+(rotation_width*NAngle(radius)),[0,0,1])
        translate([radius,0,-r*((rotate)/90*wid)+(text_width(text, 0, len(text)-1))/2*((rotate)/90*wid)])
        rotate([0,letter_rotation,0])
        rotate(90,[1,0,0])
        //this might look like it should be 90 + letter_width/2, but
        //letter width includes a bit of spacing. Not nice, but hey, I'm not doing a full
        //font kerning implementation here :)
        rotate(93, [0,1,0])
        linear_extrude(height=t)
        text(text[r], center=true, size=h, font=font);
//echo("zloc=",height/2-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid));
    }

}
//the text/write module does not provide spacing or kerning data
//so here it is for the default font. Set to 1 for monospaced fonts for all letters :)
font_spacing_data = [
["a", 1.15],
["b", 1.12],
["c", 1.1],
["d", 1.1],
["e", 1.2],
["f", 0.7],
["g", 1],
["h", 1.1],
["i", 0.55],
["j", 0.7],
["k", 1],
["l", 0.6],
["m", 1.75],
["n", 1.24],
["o", 1.17],
["p", 1.2],
["q", 1],
["r", 0.83],
["s", 1.1],
["t", 0.8],
["u", 1.3],
["v", 1],
["w", 1],
["x", 1.2],
["y", 1],
["z", 1],
["A", 1.4],
["B", 1.4],
["C", 1.4],
["D", 1.4],
["E", 1.4],
["F", 1.4],
["G", 1.4],
["H", 1.4],
["I", 1.4],
["J", 1.2],
["K", 1.4],
["L", 1.35],
["M", 1.8],
["N", 1.4],
["O", 1.4],
["P", 1.45],
["Q", 1.4],
["R", 1.4],
["S", 1.4],
["T", 1.3],
["U", 1.3],
["V", 1.3],
["W", 1.3],
["X", 1.3],
["Y", 1.3],
["Z", 1.3],
[" ", 0.8],
["'", 0.42]
];

function text_width(string, index, max_len) =
    max_len == 0 ? 0 :
    (index >= max_len-1 ?
        text_width_one_letter(string, index) :
        text_width_one_letter(string, index) + text_width(string, index+1, max_len));

function text_width_one_letter(string, index) =
    font_spacing_data[search(string[index], font_spacing_data)[0]][1];

rotate_extrude()
union(){
    extrude_line(bell_profile, bell_wall_thickness, solid=false, remove_doubles=true, normal_walls=false);
    muting_tube();
    //bottom
    mute_bottom();
    if(render_better_fit_area == "yes") {
        difference() {
            cork_profile();

            solid_mute_profile();
        }
    }

}

//render the cork to test fit
if(render_cork) {
    %rotate_extrude()
    difference() {
        cork_profile(bell_wall_thickness+cork_thickness);
    solid_mute_profile();
   }
}

module mute_bottom(){
    radius_at_top_of_bottom = bell_radius_at_height(bell_profile, bell_wall_thickness)+bell_wall_thickness;
    radius_a_bit_higher = bell_radius_at_height(bell_profile, bell_wall_thickness*2.5)+bell_wall_thickness;
    polygon(points=[[hole_diameter_bottom,0], [mute_base_radius,0],
        [radius_a_bit_higher, bell_wall_thickness*2.5],
        [radius_at_top_of_bottom-4, bell_wall_thickness],
//[radius_at_top_of_bottom, bell_wall_thickness],
        [hole_diameter_bottom, bell_wall_thickness]]);
}

module muting_tube() {
    tube_outside_radius = hole_diameter_top+bell_wall_thickness*1.5;
    polygon([
        //bottom edge of tube
        [hole_diameter_bottom, 0], [tube_outside_radius+bell_wall_thickness*2, 0],
        [tube_outside_radius, 5],
        //top edge of tube
        [tube_outside_radius, mute_bottom_height], [hole_diameter_top, mute_bottom_height],
        //and slightly smaller part near bottom
        [hole_diameter_top, 6], [hole_diameter_small, 2]
   ]);
}

module cork_profile(thickness=bell_wall_thickness) {
    translate([0, bell_height-sum_length(cork_bessel, 0)])
        //rotate_extrude()
        extrude_line(input_curve=cork_profile, wall_thickness=thickness, solid=true, remove_doubles=true, normal_walls=false);
}

module solid_mute_profile() {
    extrude_line(bell_profile, bell_wall_thickness, solid=true, normall_walls=false);
}

function bell_radius_at_height(curve, height) =
    radius_at_height( curve, height);
```


[User]
I'm looking to create a parametric corner bracket for 90-degree joins. I need the ability to customize the bracket's width, length, and thickness. I also need a hole in the center of each plate and a way to add or remove a support rib. Additionally, there needs to be an option for a single or dual bracket. The design should essentially consist of two plates joined at a 90-degree angle.

Here are the specific requirements:

*   **Customizable Dimensions:**
    *   `br_width`: The width of the plates.
    *   `br_length`: The length of the plates.
    *   `br_thickness`: The thickness of the plates.
*   **Hole:** A circular hole should be centered on each plate, with its diameter defined by `br_hole`.
*   **Support Rib:** An option to add a support rib connecting the two plates. This should be controlled by a boolean parameter `br_support` ("yes" or "no"). The support rib should be a simple triangle between the two plates.
*   **Dual Bracket:** An option to create a second set of plates attached to the main set, mirroring along an axis to the side. Should be controlled with the boolean parameter `br_dual`.
*   **90-Degree Corner:** The two plates should always join at a 90-degree angle.
*   **OpenSCAD:** The design should be created in OpenSCAD so I can modify it easily.

Could you generate an OpenSCAD file or files for this? I'm not looking for anything complicated, just a way to generate the basic shape with the options described. I'm not using any libraries currently.

[Assistant]
anglebracket_custom.scad:
```
/////---Variables----//////

br_width = 15;
br_length = 15;
br_thickness = 2;
br_hole = 5;
br_support = "yes"; //[yes,no]
br_dual = "yes"; //[yes,no]

/////---Render---/////

bracket();

//cube([width,length,thickness],center=true);
//translate([width/2,0,length/2])rotate([0,90,0])cube([width,length,thickness],center=true);
//translate([width/2,0,0])rotate([90,0,0])cylinder(d=thickness,h=length,center=true, $fn=30);

/////---Modules---/////

module plate(w,l,h)
{
   difference()
   {
       union()
       {
           cube([br_width,br_length,br_thickness],center=true);
           translate([br_width/2,0,0])rotate([90,0,0])cylinder(d=br_thickness,h=br_length,center=true, $fn=30);

       }
       cylinder(d=br_hole,h=br_thickness+1,center=true,$fn=30);
   }
}

module bracket()
{
    plate(br_width,br_length,br_thickness);
translate([br_width/2,0,br_width/2])rotate([0,90,0])plate(br_width,br_length,br_thickness);

    if (br_support == "yes")
    {
        hull()
        {
            translate([(br_width/2)-(br_thickness/2),(br_length/2)-(br_thickness/2),0])cube(br_thickness,center=true);
            translate([(-br_width/2)+(br_thickness/2),(br_length/2)-(br_thickness/2),0])cube(br_thickness,center=true);
            translate([br_width/2,(br_length/2)-(br_thickness/2),(br_width)-(br_thickness/2)])cube(br_thickness,center=true);
        }
    }
    mirror([0,1,0])
    {
       if (br_dual == "yes")
    {
        hull()
        {
            translate([(br_width/2)-(br_thickness/2),(br_length/2)-(br_thickness/2),0])cube(br_thickness,center=true);
            translate([(-br_width/2)+(br_thickness/2),(br_length/2)-(br_thickness/2),0])cube(br_thickness,center=true);
            translate([br_width/2,(br_length/2)-(br_thickness/2),(br_width)-(br_thickness/2)])cube(br_thickness,center=true);
        }
    }
    }
}
```


[User]
Hi, I'm looking for some OpenSCAD code to generate flexible motor mounts for quadcopter brushless motors. I've seen some designs out there, but I want something fully customizable.

Specifically, I need to be able to control the following parameters:

*   **Motor Diameter:** The diameter of the motor being mounted.
*   **Thickness:** The thickness of the soft mount itself.
*   **Center Hole Diameter:** The diameter of the hole in the center of the mount, for the motor shaft.
*   **Bolt Hole Diameter:** The diameter of the bolt holes.
*   **Horizontal Hole Spacing:** The distance between the left and right bolt holes, center-to-center.
*   **Vertical Hole Spacing:** The distance between the top and bottom bolt holes, center-to-center.

The mount should be a circular disc with cutouts around the perimeter (like the original designs, I think using `difference` and `translate` of circles would work well for that). The bolt holes should be evenly spaced around the center, and the user should be able to easily change the parameters from the top of the file.

It would be great if the code created a single module for the soft mount itself, and used that module in the main `linear_extrude`. I'm not sure how to do this, but I've seen it done before. If you can make it flexible to use other libraries like `MCAD` I'd be interested, but I don't expect that to be necessary. A simple parametric design should be fine.

[Assistant]
softmount_customizer.scad:
```
// Firewall Customizer
// written by Dave Halderman
// 2017-10-03

//Motor diameter (mm)
motor_dia = 22; //[9:1:35]

//Thickness of softmount (mm)
thickness = 2; //[0.5:0.5:2.5]

//Diameter of center hole (mm)
center_hole_dia = 8; //[0:0.5:16]

//Diameter of bolt holes
bolt_hole_dia = 3.3; //[2.2:M2, 3.3:M3, 4.4:M4]

//Spacing of left/right holes (mm - center to center)
horiz_hole_spacing = 19; //[5:1:25]

//Spacing of top-bottom holes (mm - center to center)
vert_hole_spacing = 16; //[5:1:25]

/* [Hidden] */
$fn=150;
cut_offset = 1.5;

linear_extrude(thickness) {
    difference() {
        minkowski () {
            main_body();
            circle(r=1);
        }
        circle(r=center_hole_dia/2);
        rotate([0,0,45]) translate([horiz_hole_spacing/2,0,0]) circle(r=bolt_hole_dia/2);
        rotate([0,0,225]) translate([horiz_hole_spacing/2,0,0]) circle(r=bolt_hole_dia/2);
        rotate([0,0,135]) translate([vert_hole_spacing/2,0,0]) circle(r=bolt_hole_dia/2);
        rotate([0,0,315]) translate([vert_hole_spacing/2,0,0]) circle(r=bolt_hole_dia/2);
    }
}

module main_body() {
    difference() {
        circle(r=(motor_dia/2));
        translate([motor_dia/cut_offset,0,0]) circle(r=(motor_dia/2)-2);
        translate([-motor_dia/cut_offset,0,0]) circle(r=(motor_dia/2)-2);
        translate([0,motor_dia/cut_offset,0]) circle(r=(motor_dia/2)-2);
        translate([0,-motor_dia/cut_offset,0]) circle(r=(motor_dia/2)-2);
    }
}
```