[User]
Hey, I'm looking to get a customizable corner shelf designed in OpenSCAD, similar to the one I saw on codeandmake.com. It needs to be parametric so I can adjust things like the shelf radius, angle, thickness, and bevel. I also want to control the bracket size, number of support arms, and screw hole details.

Specifically, I need the following parameters to be adjustable:

**Shelf:**

*   `Shelf_Radius`: The radius of the shelf.
*   `Shelf_Angle`: The angle covered by the shelf (e.g., 90 degrees for a right-angle corner).
*   `Shelf_Thickness`: The thickness of the shelf itself.
*   `Bevel_Percentage`: How much beveling there is at the edges, expressed as a percentage.
*   `Bracket_Thickness`: Thickness of the brackets that attach to the wall.
*   `Arms`: Number of supporting arms underneath the shelf.
*   `Arm_Length_Percentage`:  The length of those support arms, as a percentage of the shelf radius.

**Screws:**

*   `Screw_Holes_Per_Bracket`: Number of screw holes on each bracket.
*   `Screw_Hole_Shift_Percent`:  How far to shift the screw holes towards the outer edge, as a percentage.
*   `Screw_Hole_Padding`:  Padding around each screw hole.
*   `Screw_Hole_Diameter`: Diameter of the actual screw hole.
*  `Screw_Head_Diameter`: Diameter of the screw head.
*  `Screw_Head_Countersink_Angle`: Angle of countersink.

**Printing:**

*   `Print_Orientation`:  Orientation for printing (Top up, Top down, or Side).

I'd like the design to be reasonably optimized for 3D printing, ideally without needing supports. Could you generate the OpenSCAD file(s) for this? I'd like the code to be clear and well-commented so I can understand how it works and modify it if needed.

Thanks in advance!

[Assistant]
codeandmake.com_Corner_Shelf_v1.1.scad:
```
/*
 * Copyright 2022 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Corner Shelf by Code and Make (https://codeandmake.com/)
 *
 * https://codeandmake.com/post/fully-customizable-corner-shelf
 *
 * Corner Shelf v1.1 (23 February 2022)
 */

/* [Shelf] */

// Radius of the shelf
Shelf_Radius = 150; // [50:1:300]

// Angle covered by the shelf
Shelf_Angle = 90; // [60:1:300]

// Thickness of the shelf
Shelf_Thickness = 10; // [1:1:20]

// Amount of bevel as a percentage
Bevel_Percentage = 50; // [0:1:100]

// Thickness of the bracket
Bracket_Thickness = 5; // [1:1:20]

// Number of arm supports
Arms = 1; // [0:1:10]

// Length of arm supports as a percentage
Arm_Length_Percentage = 80; // [0:1:100]

/* [Screws] */

// Number of screw holes per bracket
Screw_Holes_Per_Bracket = 2; // [2:1:5]

// Amount to shift screw holes towards the outside as a percentage
Screw_Hole_Shift_Percent = 20; // [0:1:100]

// Amount to pad each screw hole
Screw_Hole_Padding = 4; // [0:1:10]

// Diameter of the screw hole
Screw_Hole_Diameter = 4; // [2:0.1:10]

// Diameter of the screw head
Screw_Head_Diameter = 8; // [3:0.1:20]

// Screw countersink angle (82 and 90 are common)
Screw_Head_Countersink_Angle = 90; // [0:0.1:180]

/* [Print Orientation] */

// Orientate for optimum printing
Print_Orientation = 2; // [0: None - Top up, 1: Fipped - Top down, 2: Side]

module cornerShelf() {
  $fn = 60;

  screwDiameter = max(Screw_Hole_Diameter, Screw_Head_Diameter);
  bracketHeight = screwDiameter + (Screw_Hole_Padding * 2);
  shelfBevelRadius = min(Shelf_Radius, Shelf_Thickness) * (Bevel_Percentage / 100);
  bracketBevelRadius = min(Shelf_Radius, bracketHeight) * (Bevel_Percentage / 100);
  screwHoleShift = (Screw_Hole_Shift_Percent / 100 / 2) * Shelf_Radius;
  firstScrewHoleX = (screwDiameter / 2) + Bracket_Thickness + Screw_Hole_Padding + screwHoleShift;
  lastScrewHoleX = Shelf_Radius - (screwDiameter / 2) - bracketBevelRadius - Screw_Hole_Padding;
  maxScreHoleDistance = lastScrewHoleX - firstScrewHoleX;
  screwHoleSpacing = maxScreHoleDistance / Screw_Holes_Per_Bracket;

  module shelf() {
    rotate([0, 0, -90]) {
      translate([-Shelf_Radius, 0, bracketHeight]) {
        brackets();
        shelfExtruded();
        arms();
      }
    }
  }

  module shelfExtruded() {
    rotate_extrude(convexity = 10, angle = Shelf_Angle, $fn = 200) {
      shelfProfile(Shelf_Thickness, shelfBevelRadius);
    }
  }

  module shelfProfile(thickness, bevelRadius) {
    square([Shelf_Radius, thickness - bevelRadius]);
    square([Shelf_Radius - bevelRadius, thickness]);

    translate([Shelf_Radius - bevelRadius, thickness - bevelRadius, 0]) {
      intersection() {
        square([bevelRadius, bevelRadius]);
        circle(r = bevelRadius);
      }
    }
  }

  module arms() {
    if (Arms) {
      translate([0, 0, -bracketHeight]) {
        intersection() {
          union() {
            for (i=[0:Arms - 1]) {
              rotate([0, 0, Shelf_Angle / (Arms + 1) * (i + 1)]) {
                arm();
              }
            }
          }

          translate([0, 0, bracketHeight]) {
            mirror([0, 0, 1]) {
              linear_extrude(height = bracketHeight, convexity = 10) {
                projection() {
                  shelfExtruded();
                }
              }
            }
          }
        }
      }
    }
  }

  module arm() {
    innerRadius = (Shelf_Angle < 180 ? Bracket_Thickness / sin(Shelf_Angle / 2) : Bracket_Thickness);

    hull() {
      intersection() {
        cylinder(r = innerRadius, h = bracketHeight);
        translate([0, -Bracket_Thickness / 2, 0]) {
          cube([innerRadius, Bracket_Thickness, bracketHeight]);
        }
      }

      translate([innerRadius + ((Shelf_Radius - innerRadius) * Arm_Length_Percentage / 100) - 1, -Bracket_Thickness / 2, bracketHeight]) {
        cube([1, Bracket_Thickness, 1]);
      }
    }
  }

  module brackets() {
    intersection() {
      union() {
        bracket();

        mirror([0, 1, 0]) {
          rotate([0, 0, -Shelf_Angle]) {
            bracket();
          }
        }

        mirror([0, 0, 1]) {
          cylinder(r = Bracket_Thickness, h = bracketHeight);
        }
      }

      mirror([0, 0, 1]) {
        linear_extrude(height = bracketHeight, convexity = 10) {
          projection() {
            shelfExtruded();
          }
        }
      }
    }
  }

  module bracket() {
    rotate([-90, 0, 0]) {
      difference() {
        linear_extrude(height = Bracket_Thickness, convexity = 10) {
          shelfProfile(bracketHeight, bracketBevelRadius);
        }
        translate([0, bracketHeight / 2, Bracket_Thickness]) {
          for (i=[0:Screw_Holes_Per_Bracket - 1]) {
            translate([firstScrewHoleX + (screwHoleSpacing / 2) + (screwHoleSpacing * i), 0, 0]) {
              screwHole();
            }
          }
        }
      }
    }
  }

  module screwHole() {
    translate([0, 0, -Bracket_Thickness]) {
      translate([0, 0, -0.5]) {
        cylinder(d = (Screw_Head_Countersink_Angle ? Screw_Hole_Diameter : screwDiameter), h = Bracket_Thickness + 1);
      }

      if(Screw_Head_Countersink_Angle) {
        countersinkHeight = tan((180 - (Screw_Head_Countersink_Angle)) / 2) * (Screw_Head_Diameter / 2);
        translate([0, 0, Bracket_Thickness - countersinkHeight]) {
          cylinder(d2 = Screw_Head_Diameter, d1 = 0, h = countersinkHeight);
        }
      }

      translate([0, 0, Bracket_Thickness - 0.005]) {
        cylinder(d = screwDiameter, h = 1);
      }
    }
  }

  if (Print_Orientation == 0) {
    shelf();
  } else if (Print_Orientation == 1) {
    translate([0, 0, Shelf_Thickness + bracketHeight]) {
      mirror([0, 0, 1]) {
        shelf();
      }
    }
  } else if (Print_Orientation == 2) {
    translate([Shelf_Thickness + bracketHeight, 0, 0]) {
      rotate([0, -90, 0]) {
        shelf();
      }
    }
  }
}

cornerShelf();

echo("\r\tThis design is completely free and shared under a permissive license.\r\tYour support is hugely appreciated: codeandmake.com/support\r");

```


[User]
I'd like to create a customizable OpenSCAD design for printing text, kind of like those 3D printed letter decorations you see at parties. I want to be able to set the text, its height, and depth, as well as choose from a few different fonts, and select bold or italics. I think it'd be great if the letters were automatically centered, both horizontally and vertically, within the overall extruded block, to simplify printing a single block.

I also want to be able to choose the font family like "Arial", "Courier New", "DejaVu Sans", "Source Serif Pro Black", or "Times New Roman" as well as have the option for "Bold", "Italic", "Bold Italic" or none.

Could you generate the OpenSCAD code for me? I don't need any special external libraries. Just a single `.scad` file would be perfect.

[Assistant]
Letters.scad:
```
//-------------------------------------------------
// Letters
// Feb. 4 - 2022, Per Lütkemeyer, lytkemeyer@gmail.com
//-------------------------------------------------

// Customization
Height = 30;
Dept = 10;
Font = "Arial"; // ["Arial", "Courier New", "DejaVu Sans", "Source Serif Pro Black", "Times New Roman"]
Type  = "Bold"; // ["", "Bold", "Italic", "Bold Italic"]
Text = "Hello";
Style = str(Font, ":", "style=",Type);

//Text
translate([0,Height/2-0.1,0]) linear_extrude(Dept) text(Text, halign="center", font=Style, valign="center", size=Height);

```


[User]
I'd like to create a customizable toothbrush holder for my family, and I'd like it to have the name of each family member printed on it. The design should be parametric so I can adjust things if needed, and I want to be able to specify the names of the users. Here’s what I'm thinking:

The holder should have a back wall, a shelf that sticks out from the wall, and slots in the shelf to hold toothbrushes. The number of slots should match the number of names I provide. Each slot should be wide enough for both standard and electric toothbrushes. The names should be printed on the front of the back wall, above the shelf, and be centered above each slot. The back wall should have rounded corners.

Specifically, I have a few measurements I'd like to make configurable:

*   **Center-to-Center Width (cc_w):** The horizontal spacing between toothbrush slots.
*   **Labels Text:** A list of strings, with each string being a name to be printed on the holder. The number of toothbrush slots should automatically match the number of labels.
*   **Shelf Thickness (shelf_t):** How thick the shelf is.
*   **Shelf Depth (shelf_d):** How far the shelf sticks out from the back wall (not including the back wall itself).
*   **Slot Depth (slot_d):** How deep the toothbrush slots go into the shelf, which should be a little less than the shelf depth.
*   **Slot Width (slot_w):** The diameter of the toothbrush slots.
*   **Corner Radius (corner_r):** The radius of the rounded inward corners where the shelf meets the back wall.
*   **Lip Radius (lip_r):** The radius of a small lip at the front edge of the shelf.
*   **Back Wall Height Over Shelf (back_wall_h_over):** The height of the back wall above the shelf.
*   **Back Wall Height Under Shelf (back_wall_h_under):** The height of the back wall below the shelf.
*    **Back Wall Thickness (back_wall_t):** How thick the back wall is.
*   **Rounded Corner Radius (rounded_corners_r):** The radius of the rounded corners on the back wall itself.
*   **Labels Thickness (labels_t):** How thick the extruded names are.
*   **Labels Height (labels_h):** The size of the letters.

I think that about covers it! Please let me know if there are any questions.

[Assistant]
tinaw_parametric_toothbrush_holder.scad:
```
// --- Parameters ---

$fn=50;

cc_w = 40 ; // c/c measurement btw toothbrushes centers

labels_text = ["Arthur", "Julie", "Mommy", "Daddy" ]; // Label names
shelf_t = 4; // horisontal shelf thickness
shelf_d = 20; // depth of horisontal shelf (not total)
slot_d = 17; // slot depth, smaller than shelf_d (toothbrush heads are abt 14 - 15,5 mm deep, oral-B electric toothbrush head 13.8 mm deep)
slot_w = 8.7 ; // slot width diameter. Toothbrushes have abt 4.5 - 6 mm wide necks, oral-B electric toothbrush head 8 mm wide neck, 8.5 mm works for both on my Wanhao i3.
corner_r = 3; // radius for rounding of inward corners between wall and shelf
lip_r = 2; // radius of front upper lip of shelf

back_wall_h_over = 20;// back wall height over shelf, toothbrush heads are abt 25-33 mm high, Oral-b abt 14 mm high
back_wall_h_under = 5; // back wall heigt under shelf
back_wall_t = 4; // back wall thicknes
rounded_corners_r = 7; // rounded corners radius on back wall
labels_t = 2; // letters thickness
labels_h = 8; // letters height

// --- code ---

toothb_no = len(labels_text);
slot_r = slot_w/2;
total_d = back_wall_t + shelf_d;
back_wall_w = toothb_no*cc_w ; // total width
back_wall_h = back_wall_h_over + shelf_t + back_wall_h_under;// total back wall height,
shelf_bottom_x = back_wall_h - back_wall_h_over;

rotate([0,270,0]) translate([0, 0, -back_wall_h]) toothbrush_holder() ;

// --- modules ---

 module labels() {
        for (a = [0:toothb_no-1]) {
            translate([shelf_t,cc_w/2+a*cc_w,shelf_bottom_x+shelf_t+corner_r+2])
            rotate([0, -90, 180])
            color("black")
            linear_extrude(height = labels_t)
            rotate([0, 0, -90])
            text(labels_text[a], size=labels_h, halign="center");
        }
}

module back_wall() {

    difference() {
        cube([back_wall_t, back_wall_w, back_wall_h]);

        translate([-1,back_wall_w-rounded_corners_r+0.01,back_wall_h+0.01]) rotate([270,0,0]) corner_punch(rounded_corners_r, back_wall_t); //will be 2 mm thicker than wall_t i e 4 mm + 2 mm

        translate([-1,-0.01,(back_wall_h+0.01-rounded_corners_r)])corner_punch(rounded_corners_r, back_wall_t); //will be 2 mm thicker than wall_t i e 4 mm + 2 mm

        translate([-1,-0.01+rounded_corners_r,-0.01]) rotate([90,0,0]) corner_punch(rounded_corners_r, back_wall_t); //will be 2 mm thicker than wall_t i e 4 mm + 2 mm

        translate([-1,0.01+rounded_corners_r+back_wall_w-rounded_corners_r,-0.01+rounded_corners_r]) rotate([180,0,0]) corner_punch(rounded_corners_r, back_wall_t); //will be 2 mm thicker than wall_t i e 4 mm + 2 mm
    }
}

module toothbrush_holder() {
    union() {
        difference() {
            union() {
                back_wall();
                shelf();
            }
            toothbrush_slots();
        }
        labels();
    }
}

module shelf() {
    difference() {
    union() {
        // shelf
        translate([0, 0, shelf_bottom_x]) cube([total_d, back_wall_w, shelf_t]);
        // inward rounded corner under shelf
        translate([corner_r+back_wall_t,0,shelf_bottom_x-corner_r]) rotate([0,270,0]) difference() {
            cube([corner_r+1, back_wall_w, corner_r+1]);
            translate([0,-1,0]) rotate([270,0,0]) cylinder (back_wall_w+2, r=corner_r);
        }
        // inward rounded corner over shelf
        translate([corner_r+back_wall_t,0,shelf_bottom_x+corner_r+shelf_t]) rotate([0,180,0]) difference() {
            cube([corner_r+1, back_wall_w, corner_r+1]);
            translate([0,-1,0]) rotate([270,0,0]) cylinder (back_wall_w+2, r=corner_r);
        }
        // front upper lip of shelf
        translate([total_d - lip_r,0,shelf_bottom_x+shelf_t]) rotate([0,180,0]) rotate([270,0,0]) cylinder (back_wall_w, r=lip_r);
    }
        // rounding under lip of shelf
        u_lip_r = lip_r+1.5;
translate([total_d-u_lip_r,-1,u_lip_r+shelf_bottom_x]) rotate([0,90,0]) difference() {
            cube([u_lip_r+1, back_wall_w+2, u_lip_r+1]);
            translate([0,-1,0]) rotate([270,0,0]) cylinder (back_wall_w+4, r=u_lip_r);
        }
        }
}

 module toothbrush_slots() {
     union() {

        for (a = [0:toothb_no-1]) {
            translate([slot_r + total_d - slot_d,cc_w/2+a*cc_w,shelf_bottom_x-4])  union() {
            cylinder (shelf_t+8, r=slot_r, center = false);
            translate([0,-slot_r,0]) cube([slot_d, 2*slot_r, shelf_t+8], center = false);
            }
        }

        for (a = [0:toothb_no-1]) {
            translate([slot_r + total_d - slot_d,cc_w/2+a*cc_w,shelf_bottom_x+slot_r-2]) linear_extrude(height=10, scale=[1,2.4], slices=20, twist=0) {
                union() {
                    translate([0,-slot_r,0]) square([slot_d, 2*slot_r], center = false);
                    circle (r=slot_r, center = false);
                }
            }
        }
    }
}
 module corner_punch(corner_rad,wall_t) {
  rotate([90,0,270]) translate([-corner_rad,0,-wall_t-2]) difference() {
         cube([corner_rad, corner_rad, wall_t+2]); // 2 mm thicker than wall_t
        translate([0,0,-1]) cylinder(wall_t+4, r=corner_rad);
  }
 }
```


[User]
Hi, I'm looking to get some OpenSCAD files made for 3D printing quest markers for the Skyrim board game. I've got some specific parameters I need to be able to adjust, so it needs to be parametric.

The marker should essentially be a triangle with a rhombus shape in the middle, and I need two versions: a flat, 2D version and a 3D version that is sort of an inverted pyramid. Both need a base at the bottom.

Here’s the breakdown of the parameters I want to be able to control:

*   **`marker_type`**: A dropdown to choose between "2d" and "3d".
*   **`marker_height`**:  The total height of the marker including the base.
*   **`marker_thickness`**:  The thickness for the 2D markers.
*   **`triangle_ratio`**: The ratio between the triangle's width and height.
*   **`base_thickness`**: How thick the base of the marker is.
*   **`base_width`**:  Let me specify the width of the base. If I set this to 0, the base should match the triangle's width.
*   **`marker_cutoff`**:  How much the marker's bottom sinks into the base, as a percentage (0-100%).
*   **`surface_angle`**:  An angle for the top surface of the 3D marker.
*   **`recess_depth`**:  The depth of the recesses on the sides of the triangle and on the rhombus in the middle of the sides.

For the 2D version, it's basically a triangle outline with a rhombus shape in the middle and a base. The 3D version is more complex. It should look like an inverted pyramid with a triangular base. The sides will have that rhombus shape recessed in and also some other triangle cutout recess features. I want to be able to control all the sizes with the parameters I listed above.

I'm not sure what libraries would be best to use for this but I do not need to control the material with any library files. I expect this design to be a single .scad file or possibly a small number of .scad files if you think it's better to divide the design that way.

[Assistant]
skyrim-quest-marker.scad:
```
/*
= Skyrim quest marker

Primarily designed for use with
https://boardgamegeek.com/boardgame/342372/elder-scrolls-v-skyrim-adventure-game[The Elder Scrolls V: Skyrim - The Adventure Game].

Version: 1.0

Skyrim quest marker © 2022 by Gunnar Strand is licensed under CC BY-SA 4.0
*/

// Type to generate
marker_type = "3d";  // [2d:2D, 3d:3D]
// Marker height including base
marker_height = 24.0;
// Thickness for 2D markers
marker_thickness = 2.0;

/* [Advanced] */

// Ratio between triangle width & height
triangle_ratio = 1.3;
// Thickness of the base
base_thickness = 2;
// Override base width if > 0
base_width = 0;
// Marker's depth into the base (%)
marker_cutoff = 6; // [0:100]
// The angle for the top surface
surface_angle = 5; // [0:45]
// Recess depth
recess_depth = 0.7;

/* [Hidden] */

// Triangle bottom cutoff ratio
cutoff_ratio = 1.0 - (marker_cutoff / 100);
// Calculated triangle height is marker height = (height * cutoff_ratio)) + thickness
triangle_height = (marker_height - base_thickness) / cutoff_ratio;
// Triangle with is calculated from Theight = Twith * Tratio
triangle_width = triangle_height / triangle_ratio;
// The side impression ratio
side_impression_ratio = 0.9;
// The ratio of the top rhombus vs. the marker
rhombus_ratio = 0.52;
rhombus_width = rhombus_ratio * triangle_width;
rhombus_height = rhombus_width * (triangle_ratio * 0.8) * 2;
// Height of the top surface
surface_height = tan(surface_angle) * triangle_width / 2;
// This is how thick the border for the recess is
border_width = (1 - side_impression_ratio) * triangle_width;

triangular_cutout_ratio = 0.2;
triangular_cutout_width = triangle_width * triangular_cutout_ratio;
triangular_cutout_depth = triangular_cutout_width * triangle_ratio;

module make_side_shape_2d(height, width, cutout_width, cutout_depth, top_x) {
    // Create a 2D polygon of the side triangle.
    // param height: the triangle height
    // param width: the triangle width
    // param cutout_width: the width of the cutout slit
    // param cutout_depth: the depth of the cutout slit
    // param top_x: the top triangle height
    polygon([[0, 0],
            [height, - width / 2],
            [height + top_x, - cutout_width / 2],
            [height + top_x - cutout_depth, 0],
            [height + top_x, cutout_width / 2],
            [height, width / 2]
        ],
    convexity = 4);
}

module make_side_shape(thickness, height, width, top_height, border = 0, angled = false) {
    // The triangle side shape with recess on the top side, blank on the bottom.
    // param thickness: thickness of the shape
    // param height: the triangle height
    // param width: the triangle width
    // param top_height: the top triangle height
    // param border: generate with this offset if set
    cutout_ratio = triangular_cutout_ratio;
    cutout_width = width * cutout_ratio;
    cutout_depth = cutout_width * triangle_ratio;
    top_x = top_height * (1 - cutout_ratio);
    angle = atan(top_height / (width / 2));
    scale = angled ? 0.94 : 1.0;

    if (angled) {
        translate([0, 0, thickness]) {
            rotate([180, 0, 0]) {
                linear_extrude(thickness, scale = scale) {
                    if (border > 0) {
                        offset(delta = - border) {
                            make_side_shape_2d(height, width, cutout_width, cutout_depth, top_x);
                        }
                    } else {
                        make_side_shape_2d(height, width, cutout_width, cutout_depth, top_x);
                    }
                }
            }
        }
    } else {
        linear_extrude(thickness, scale = scale) {
            if (border > 0) {
                offset(delta = - border) {
                    make_side_shape_2d(height, width, cutout_width, cutout_depth, top_x);
                }
            } else {
                make_side_shape_2d(height, width, cutout_width, cutout_depth, top_x);
            }
        }
    }
}

module make_rhombus_2d(height, width) {
    // Create a 2D rhombus.
    // param height: the rhombus height
    // param width: the rhombus width
    polygon([[0, 0],
            [height / 2, - width / 2],
            [height, 0],
            [height / 2, width / 2],
        ]);
}

module make_rhombus(height, width, thickness, border = 0) {
    // Create a 3D rhombus.
    // param height: the rhombus height
    // param width: the rhombus width
    // param thickness: the rhombus thickness
    // param border: make this rhombus offset from the size
    linear_extrude(thickness) {
        if (border > 0) {
            offset(delta = - border) {
                make_rhombus_2d(height, width);
            }
        } else {
            make_rhombus_2d(height, width);
        }
    }
}

module make_rhombus_shape(height, width, thickness, recess, border) {
    // Create a 3D rhombus with recess.
    // param height: the rhombus height
    // param width: the rhombus width
    // param thickness: the rhombus thickness
    // param recess: the recess depth
    // param border: border size for the recess
    difference() {
        make_rhombus(height, width, thickness);
        translate([0, 0, thickness - recess]) {
            make_rhombus(height, width, thickness, border);
        }
    }
}

module make_side(thickness = marker_thickness) {
    // Create the quest marker side.
    // param thickness: the thickness of the marker
    cutout_x = (triangle_height - (triangle_height * side_impression_ratio)) / 1.2;
    rotate([0, - 90, 0]) {
        union() {
            difference() {
                make_side_shape(thickness, triangle_height, triangle_width, surface_height);
                translate([0, 0, thickness - recess_depth]) {
                    make_side_shape(thickness, triangle_height, triangle_width, surface_height,
                    border = border_width);
                }
            }
            translate([triangle_height - rhombus_height / 2, 0, 0]) {
                difference() {
                    make_rhombus_shape(rhombus_height, rhombus_width, marker_thickness,
                    recess_depth,
                    border_width);
                    translate([- triangle_height - surface_height + rhombus_height / 2, 0, 0.1]) {
                        make_side_shape(thickness, triangle_height, triangle_width, surface_height)
                        ;
                    }
                }
            }
        }
    }
}

module marker_2d() {
    // Create a complete 2D quest marker with base.
    union() {
        translate([0, 0, - marker_cutoff + base_thickness]) {
            difference() {
                union() {
                    make_side();
                    rotate([0, 0, 180]) {
                        make_side();
                    }
                }
                translate([0, 0, marker_cutoff / 2 - base_thickness + 0.1])
                    cube(marker_cutoff, center = true);
            }
        }
        if (base_width > 0) {
            cylinder(h = base_thickness, r = base_width / 2);
        } else {
            cylinder(h = base_thickness, r = triangle_width / 2);
        }
    }
}

module make_triangle(width) {
    // Create a unilateral triangle.
    // param width: distance from the center to the vertices
    circle(r = width * sqrt(3) / 2, $fn = 3);
}

module make_bilateral_triangle(width, height) {
    // Create a bilateral triangle along the X-axis with the tip in origo.
    // param width: triangle width
    // param height: the height of the triangle
    polygon([[0, 0], [height, - width / 2], [height, width / 2]]);
}

module make_pyramid(height, width, border = 0, recess = 0.8) {
    // Create a pyramid with a triangular base.
    // param height: pyramid height
    // param width: distance from the base center to the vertices
    dist = width / 2;
    side = sqrt(width * width - (dist * dist));

    recess_height = sqrt(side * side + height * height);

    angle = atan(dist / height);
    difference() {
        linear_extrude(height = height, scale = 0.001) {
            make_triangle(width);
        }
        if (border > 0) {
            for (a = [0, 1, 2]) {
                rotate([0, 0, 60 + a * 120]) {
                    // FIXME make proper calculation of position. This is just fake.
                    translate([recess / 2, 0, height - 2 * border]) {
                        rotate([0, - angle * 0.88, 0]) {
                            rotate([0, 90, 0]) {
                                linear_extrude(recess * 2) {
                                    make_bilateral_triangle(2 * side, recess_height);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

module triangular_cutout(length, width, height) {
    // Create a triangular bar for making a cutout in the marker to surface.
    // param length: bar length
    // param width: bar width
    // param height: bar height
    translate([0, 0, height / 2]) {
        rotate([0, 90, 60]) {
            linear_extrude(length) {
                make_bilateral_triangle(width, height);
            }
        }
    }
}

module make_prism(height, width) {
    // Create a triangular prism.
    // param height: prism height
    // param width: prism width
    // TODO support recess in the prism
    union() {
        make_pyramid(height, width, border = border_width);
        rotate([180, 0, 0]) {
            make_pyramid(height, width, border = border_width);
        }
    }
}

module make_3d_core() {
    // Create the inverted pyramid shape of the quest marker.
    difference() {
        translate([0, 0, - surface_height * 2]) {
            make_pyramid(triangle_height + surface_height * 2, triangle_width * 2.5 / 3);
        }
        rotate([180, 0, 60]) {
            difference() {
                translate([0, 0, triangle_width + 0.01]) {
                    cube(triangle_width * 2, center = true);
                }
                make_pyramid(surface_height * 2, triangle_width * 2);
            }
        }
        for (a = [0, 1, 2]) {
            rotate([0, 0, a * 120]) {
                triangular_cutout(triangle_width, triangle_width / 2.5,
                    triangular_cutout_depth * 2.2);
            }
        }
    }
}

module marker_3d() {
    // Create the 3D quest marker
    // FIXME some values are hard-coded, and some are not properly calculated
    recess_angle = 90 - atan(triangle_width / 3 / triangle_height);
    union() {
        difference() {
            translate([0, 0, triangle_height - marker_cutoff + base_thickness]) {
                rotate([180, 0, 0]) {
                    union() {
                        difference() {
                            make_3d_core();
                            for (a = [0, 1, 2]) {
                                rotate([0, 0, a * 120]) {
                                    translate([- border_width * sin(recess_angle) + recess_depth *
                                        2, 0, triangle_height - border_width * 3]) {
                                        rotate([0, recess_angle, 180]) {
                                            translate([- border_width * 3, 0, 0]) {
                                                // TODO make the top of the cutout angeled to avoid overhang
                                                make_side_shape(recess_depth * 2, triangle_height,
                                                triangle_width,
                                                surface_height,
                                                border = border_width, angled = true);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        translate([0, 0, - surface_height * 2]) {
                            make_prism(rhombus_height / 1.8, rhombus_width * 0.8);
                        }
                    }
                }
            }
            translate([0, 0, - marker_cutoff / 2 + 0.1])
                cube(marker_cutoff, center = true);
        }
        if (base_width > 0) {
            cylinder(h = base_thickness, r = base_width / 2);
        } else {
            cylinder(h = base_thickness, r = triangle_width / 2);
        }
    }
}

if (marker_type == "2d") {
    marker_2d();
} else {
    marker_3d();
}

```


[User]
I'm looking to generate a truss structure in OpenSCAD, and I need it to be configurable with several parameters. I'd like to be able to choose between three different truss types: I-beam, Pratt, and Lattice. I need to be able to adjust the overall height, width, and length of the truss. Additionally, the top and bottom caps of the truss should have configurable width and thickness. I also need to be able to specify the width of the internal support structures, and the number of segments the truss is divided into. I'd like this all to be parametric, so I can easily tweak all of these dimensions.

Can you create an OpenSCAD file (or files, if that makes more sense) that can generate this? I'd like it to use the built-in OpenSCAD functions as much as possible.

[Assistant]
Truss.scad:
```
  //////////////////////////////////////////////
 // Pratt or Lattice or I-beam Truss - V 1.3 //
//////////////////////////////////////////////

/* Use the OpenScad configuration utility */

/* [Truss Body] */
Tr_Height = 20;  // [10:.01:50]
Tr_Width  = 3;   // [1:.01:20]
Tr_Length = 190; // [10:.01:300]
Tr_Segs   = 6;   // [2:30]

/* [Cap] */
Tr_CapWid = 4;   // [1:.01:10]
Tr_CapThk = 2;   // [1:.01:10]

/* [Supports] */
Tr_SupType   = 1;   // [0:IBeam,1:Pratt,2:Lattice]
Tr_SupWid = 2;   // [.5:.01:10]

PL_Truss(H=Tr_Height,W=Tr_Width,L=Tr_Length,CW=Tr_CapWid,CT=Tr_CapThk,SW=Tr_SupWid,S=Tr_Segs,Ty=Tr_SupType);

//--------------------------------------
// Pratt/Lattice/Ibeam Truss
//
// Call with H  = Truss height
//           W  = Truss Width
//           L  = Truss Length
//           S  = # of truss support segments
//           CW = Cap Width
//           CT = Cap Thickness
//           SW = Truss supports width
//                Auto centered on Caps
//           Ty  = 0 = Pratt type
//               = 1 = Pratt type
//               = 2 = Lattice type
//
module PL_Truss(H=20,W=4,L=50,CW=4,CT=1.5,SW=1.5,S=4,Ty=1) {

MW2= SW/2;
H1 = H-CT;
L1 = L-MW2;
L2 = L-SW;
Cntr = (L-SW)/2;

   render()
   intersection(convexity=7) {
      translate([0,0,-50])
      cube([L,H,100]);

      translate([0,CT/2,0]) {
         linear_extrude(CW) {
            Line_Seg_2d([0,H1],[L,H1],CT);
            Line_Seg_2d([L,0],[0,0],CT);
         }

         translate([0,0,(CW-SW)/2])
         linear_extrude(SW) {
            if (Ty==0) {
               square([L,H1]);
            } else {

               for (i=[MW2:L2/S:L]) {
                  Line_Seg_2d([i,0],[i,H1],SW);
               }

               if (Ty==1) {
                  for (i=[MW2:L2/S:L*(1-1/S)]) {
                     if (i < Cntr) {
                        Line_Seg_2d([i,0],[i+L1/S,H1],SW);
                     } else {
                        Line_Seg_2d([i,H1],[i+L1/S,0],SW);
                     }
                  }
               } else {
                  for (i=[MW2:L2/S:L*(1-1/S)]) {
                     Line_Seg_2d([i,0],[i+L1/S,H1],SW);
                     Line_Seg_2d([i,H1],[i+L1/S,0],SW);
                  }
               }
            }
         }
      }
   }
}

//----------------------------------------------------
// Generate a line segment between two arbitrary points
//
// Call with P0,P1 = (x,y) points to connect
//           width = 1 = width of line segment
//           cap0 = false = cap P0 with circle
//           cap1 = false = cap p1 with circle
//
module Line_Seg_2d(P0,P1,width=1,cap0=false,cap1=false) {

   hwidth = width/2;

   if (P0.y == P1.y) {

      polygon([P0-[0,hwidth],P1-[0,hwidth],
              P1+[0,hwidth],P0+[0,hwidth]]);

   } else {

      slope = (P0.x-P1.x) / (P1.y-P0.y);
      s=hwidth*[1,slope]/sqrt(1+slope*slope);
      polygon([ P0+s,P1+s,P1-s,P0-s]);

   }

   if (cap0 == true) translate(P0) circle(d=width);
   if (cap1 == true) translate(P1) circle(d=width);

}

```


[User]
I'd like to create a customizable badge, like a keychain tag. It should have a rectangular shape with rounded corners, and I need to be able to specify the text on the badge, as well as its overall size. I also want the option to include a hole for a keyring.

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

*   **`Content`**: The text to be displayed on the badge.
*   **`Font`**: The font used for the text. I'd prefer to use common fonts like "Arial Rounded MT Bold," but it'd be cool if I could choose any font on my system.
*   **`Padding`**: The space between the text and the edge of the badge.
*   **`Length`**: The length of the rectangular badge.
*   **`Width`**: The width of the rectangular badge.
*  **`Roundness`**: A value that controls how rounded the corners of the badge are. A higher value means rounder corners.
*   **`Hole_Size`**: The diameter of the keyring hole. If this is set to 0, no hole is included.
*   **`Height`**: The overall thickness/height of the badge. This should also be applied to the text using linear extrusion.

The badge should have a solid base with the text cut out of the top. If `Hole_Size` is greater than 0, there should be a cylinder hole at the top, centered on the width and close to the end of the length. I’d like the code to handle the rounded corners of the badge with a `roundedcube()` function. I think that's all - I look forward to seeing what you come up with!

[Assistant]
Key_Badge.scad:
```
/* [Badge Text] */
Content = "Garage";
// Use Google Font in MakerBot Customizer
Font = "Arial Rounded MT Bold";
Padding = 1;

/* [Badge Size] */
Length = 70;
Width = 14;
Roundness = 0.5;

/* [Badge Properties] */
// Set 0 to disable
Hole_Size = 2;

/* [Hidden] */
Height = 2;

difference() {
    translate([0, 0, 0]) {
        roundedcube([Length, Width, Height], true, Roundness);
        if (Hole_Size > 0)
            translate([-Length / 2 + Hole_Size / 2, Width / 2 - Hole_Size / 2, -Height / 2])
                cylinder(Height, Hole_Size + 2, Hole_Size + 2);
    }

    translate ([0, 0 , 0]) {
        linear_extrude(Height / 2, convexity = 4) {
            resize([0, Width - Padding * 2], auto = true)
                text(
                    Content,
                    valign = "center",
                    halign = "center",
                    font = Font
                );
        }
     }

     if (Hole_Size > 0) {
         translate([-Length / 2 + Hole_Size / 2, Width / 2 - Hole_Size / 2, -Height / 2 - 0.5]) {
            cylinder(Height + 1, Hole_Size, Hole_Size);
         }
     }
}

// More information: https://danielupshaw.com/openscad-rounded-corners/

// Set to 0.01 for higher definition curves (renders slower)
$fs = 0.015;

module roundedcube(size = [1, 1, 1], center = false, radius = 0.5, apply_to = "all") {
	// If single value, convert to [x, y, z] vector
	size = (size[0] == undef) ? [size, size, size] : size;

	translate_min = radius;
	translate_xmax = size[0] - radius;
	translate_ymax = size[1] - radius;
	translate_zmax = size[2] - radius;

	diameter = radius * 2;

	obj_translate = (center == false) ?
		[0, 0, 0] : [
			-(size[0] / 2),
			-(size[1] / 2),
			-(size[2] / 2)
		];

	translate(v = obj_translate) {
		hull() {
			for (translate_x = [translate_min, translate_xmax]) {
				x_at = (translate_x == translate_min) ? "min" : "max";
				for (translate_y = [translate_min, translate_ymax]) {
					y_at = (translate_y == translate_min) ? "min" : "max";
					for (translate_z = [translate_min, translate_zmax]) {
						z_at = (translate_z == translate_min) ? "min" : "max";

						translate(v = [translate_x, translate_y, translate_z])
						if (
							(apply_to == "all") ||
							(apply_to == "xmin" && x_at == "min") || (apply_to == "xmax" && x_at == "max") ||
							(apply_to == "ymin" && y_at == "min") || (apply_to == "ymax" && y_at == "max") ||
							(apply_to == "zmin" && z_at == "min") || (apply_to == "zmax" && z_at == "max")
						) {
							sphere(r = radius);
						} else {
							rotate =
								(apply_to == "xmin" || apply_to == "xmax" || apply_to == "x") ? [0, 90, 0] : (
								(apply_to == "ymin" || apply_to == "ymax" || apply_to == "y") ? [90, 90, 0] :
								[0, 0, 0]
							);
							rotate(a = rotate)
							cylinder(h = diameter, r = radius, center = true);
						}
					}
				}
			}
		}
	}
}
```


[User]
I want to design a customizable storage box that can be 3D printed, and I need some help generating the OpenSCAD files. I've seen some examples, and I want something like the "ParamBox" design, but with a few changes and more modularity.

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

**Overall Box Structure:**

*   **Base and Lid:** The box should consist of two separate parts: a base and a lid, which can be printed independently. I'd like a parameter to choose whether to print the base, the lid, or both.
*   **Dimensions:**
    *   `box_length`: Length of the box along the x-axis.
    *   `box_width`: Width of the box along the y-axis.
    *   `box_height`: Height of the base part of the box.
    *   `lid_height`: Height of the lid part of the box.
    *   `floor_thick`: Thickness of the bottom and top surfaces.
    *   `wall_thick`: Thickness of the side walls.
*   **Corner Rounding:** A `roundradius` parameter to control the rounding radius of all corners.
*   **Sealing Bevel:** An option (`do_seal_bevel`) to add a bevel on the top edges of both the base and the lid for better sealing.
*   **Brim:** A `brim_ht` parameter to add a brim around the bottom and top edges of the box to help with bed adhesion. The width should be the same as the height. I need an option to disable it as well.

**Locking Mechanism:**

*   **Hasp Width:**  The width of the hasp should be determined automatically, based on box length, for example being 12 if the box length is greater than 105, otherwise 6.
*   **Hasp Shift:** The horizontal position of the hasp (along the box length axis) should also be determined automatically, being zero if the box length is greater than 105, and otherwise being 50 - half the box length.
*   **Lock Design:** The lock should consist of cylindrical pieces on the base and a sliding part that fits in from the front. The cylinders on the box should be hollow so the sliding lock can move through them, and have small supports. The slider should have a handle and small break-away holders for printing.
*   **Placement:** The lock should be placed at the front center of the box, with the hasp on the lid aligned with the hasp on the base, to close the box.

**Vertical Supports:**

*   **Support Dimensions:** Parameters `support_w` (width) and `support_t` (thickness) to add vertical support rectangles on the front, back and sides of the box.  These should be optional (i.e. if either dimension is 0, they should not be generated).

**Text Labels:**

*   **Text Input:** Three string parameters: `lbltext1`, `lbltext2`, and `lbltext3` to place text labels on the front face of the base. If supports are present, then these should print left, center, and right of the front supports. If supports are not present, print only `lbltext1` at the center.
*   **Text Size:** Parameter `lblsize` to control the font size.
*   **Text Font:** Use "Liberation Sans" font.

**Modular Design:**

*   I want to make sure I can easily import each part in a separate file in my larger design later. Let's make at least two separate `.scad` files: one for the base and another for the lid.
*   I'd prefer to use standard OpenSCAD libraries where applicable, instead of writing functions from scratch.  I'm okay if you need to write a few modules, but please keep them minimal.

I think that covers it. Let me know if you have any questions, and I'm excited to see what you come up with!

[Assistant]
ParamBox_111.scad:
```
/*
   ParamBox
   G. A. Tielke, August 2021
   Version 2, February 2022

   Creates 3d-printable storage box.
   The size and other settings can be set by the user.

   See the ParamTray project for printing trays to fit in this box.
   ================================================================================
   ======================================================= Set window width here >>
*/

/* [Select Items to Create] */
// Create Base (0=No Base):
print_base = 1; // [0:1:1]
// Create Top (0=No Top):
print_top = 1; // [0:1:1]

/* [Box Overall Size] */
// Length on x axis
box_length = 118; //[60:1:220]
// Width on y axis
box_width = 61; //[10:1:220]
// Height of base part of box
box_height = 30; //[25:1:220]
// Height of box lid
lid_height = 15; //[10:1:220]
// Thickness of bottom & top surfaces
floor_thick = 1; //[0:1:10]
// Thickness of side walls
wall_thick =1; //[1:1:10]

/* [Brim on top and bottom edges] */
// Height & Width of brim additions, 0 for none
brim_ht = 2; //[0:1:5]

// Radius for corner rounding
roundradius = 3; //[0:1:5]
// Add sealing bevel to top of box sections
do_seal_bevel = 1; // [0:1:1]

/* [Verticle support sizes] */
// Width of support, 0 for none
support_w = 10;  //[0:1:30]
// Thickness of supports, 0 for none
support_t = 1; //[0:1:5]

/* [Text for front face] */
// Text for left panel
lbltext1 = "";
// Text for center panel
lbltext2 = "";
// Text for right panel
lbltext3 = "";
// Text font size
lblsize = 5.1;

/* [Hidden] */

brim_width = brim_ht; // Force them to be the same.
do_brim = (brim_ht > 0);
do_support = (support_t > 0) && (support_w > 0);

// Width of locking hasp attached to top lid:
hasp_width = (box_length > 105) ? 12 : 6;
// Shift locking hasp left for smaller length boxes:
hasp_shift = (box_length > 105) ? 0 : (50-box_length/2);

lblfont = "Liberation Sans";

/*
  OUTLINE OF THE STEPS TO CREATE THE BOX:
  1-Create the bottom (base) portion
  2-Add lock mechanism to the bottom box
  3-Create the top (lid) portion
  4-Add lock hasp to the lid part
  5-Add Text to front of the base box
*/

//
// 1-Create the base part of the box:
//
if (print_base > 0) difference() {
    translate([0,0,0]) {
        // Base part of the box:
          createbox(boxtype="B", boxht=box_height);

		// Add lid hooks in back of bottom box:
		for(n=[1:2]) {
			translate([box_length*n/3-5,box_width+brim_width,
				box_height]) {
				translate([0,0,-brim_ht-.8])
					color("blue") cube([10,support_t+.25,brim_ht*2+1.6]);
				translate([0,-brim_width+.707,-2*brim_ht-.707]) rotate([45,0,0])
					color("red") cube([10,brim_width*1.4,1]);
				translate([0,-brim_width+0*0.707-1,2*brim_ht+1]) rotate([-45,0,0])
					color("orange") cube([10,brim_width*1.4+1.4,1]);
				}
		};

		// Add lid hooks to the sides of bottom box:
		for(n=[1:2]) {
			nsign = (n < 2) ? -1 : +1;
			translate([box_length*(n-1)+nsign*brim_width,box_width/2+nsign*5,
				box_height]) rotate([0,0,-nsign*90]) {
				translate([0,0,-brim_ht-.8])
					color("yellow") cube([10,support_t+.25,brim_ht*2+.8]);
				translate([0,-brim_width+.707,-2*brim_ht-.707]) rotate([45,0,0])
					color("red") cube([10,brim_width*1.4,1]);
				}
		}
    }

    // Subtract out for locking hasp when top lid closed:
    translate([box_length/2-hasp_width/2-.5-hasp_shift,
    -brim_width-.1,
    box_height-2*brim_ht-.4]) {
        color("orange") cube([hasp_width+1,brim_width+.2,2*brim_ht+.5]);
    }

    // Subtract for sealing bevel on top of the bottom box:
    if (do_seal_bevel > 0) {
        translate([wall_thick-1.25,
        wall_thick-1.25,
        box_height-1.25]) color("gray")
            cube([box_length-2*wall_thick+2.5,box_width-2*wall_thick+2.5+.5,1.3]);
	}
};

//
// 2-Add lock mechanism to the bottom box:
//
// Starting just left of hasp opening
if (print_base > 0)
	translate([box_length/2-hasp_width/2-.5-hasp_shift,
	-4.5-support_t,                  // Move forward if supports are used
	box_height-2*brim_ht-.4]) {      // Move down if brim is used

    // Add lock cylinders:
    // Use hull() to combine with a small support.
    color("green") difference() {
        translate([0,0,0]) {
            // Leftmost lock cylinder:
            translate([-6,0,0]) hull() {
                rotate([0,90,0]) cylinder(h=6,r=4,$fn=60);
                translate([0,4+support_t,-8]) cube([6,1,8]);
            };
            // Center lock cylinder: more width for strength
            translate([hasp_width+1,0,0]) hull() {
                rotate([0,90,0]) cylinder(h=10,r=4,$fn=60);
                translate([0,4+support_t,-8]) cube([10,1,8]);
            };
            // Rightmost lock cylinder:
            translate([2*hasp_width+23,0,0]) hull() {
                rotate([0,90,0]) cylinder(h=6,r=4,$fn=60);
                translate([0,4+support_t,-8]) cube([6,1,8]);
            };
        };
        // Subtract the insides of the lock cylinders:
        translate([-6.1,0,0]) rotate([0,90,0])
            cylinder(h=2*hasp_width+38,r=3.,$fn=60);
    };

    // Add block below slider:
    color("orange") translate([hasp_width+17,-1,-6]) hull() {
        roundedplate(plength=hasp_width,
            pwidth=support_t+4.9,pheight=1,pradius=1);
        translate([0,4.5+support_t+.8,-4]) cube([12,1,5]);
    };

    // Add slider part of the lock:
    translate([8,0,0]) {
        // Long cylinder:
        color("blue") translate([-6,0,0]) rotate([0,90,0])
            cylinder(h=2*hasp_width+33,r=2.5,$fn=60);

        // Small handle part:
        color("red") translate([hasp_width+13,0,0]) rotate([0,0,0]) {
			translate([-2.5,-3,0]) cube([5,6,9]);
        }

        // Small break-away holders:
        color("violet") translate([0,-0.5,-5.5]) {
            // - vertical parts:
            translate([-6,0,0]) cube([1,1,3.5]);
            translate([hasp_width+9,0,0]) cube([1,1,3.5]);
            translate([2*hasp_width+26,0,0]) cube([1,1,3.5]);
            // - horizontal parts:
            translate([-6,0,0]) cube([1,support_t+5.2,1]);
            translate([2*hasp_width+26,0,0]) cube([1,support_t+5.2,1]);
        }
    }
};

//
// 3-Create top lid part of the box:
//
if (print_top > 0) difference() {
    translate([0,0,0]) {
		// Create the lid portion:
        translate([0,box_width+10+2,0]) createbox(boxtype = "T",
			boxht=lid_height);
        // Add sealing bevel on top:
        if (do_seal_bevel > 0) difference() {
            translate([wall_thick-1,
            box_width+10+2+wall_thick-1,
            lid_height]) color("brown")
                cube([box_length-2*wall_thick+2,box_width-2*wall_thick+2,1]);
            translate([wall_thick,
            box_width+10+2+wall_thick,
            lid_height-.05])
                cube([box_length-2*wall_thick,box_width-2*wall_thick,1.1]);
        }
    }
}

//
// 4-Add lock hasp to the lid part of the box:
//
if (print_top > 0) translate([box_length/2-hasp_width/2-hasp_shift,
    box_width*2+10,
    lid_height + brim_ht]) {

    color("blue") translate([0,2,7])
        rotate([0,90,0])
        roundedplate(plength=15.5,pwidth=1+support_t,
        pheight=hasp_width,pradius=1);

    color("indigo") hull() {
        translate([0,2,5])
            roundedplate(plength=hasp_width,pwidth=3+support_t,
            pheight=2,pradius=1);
        translate([0,2,5-support_t])
            roundedplate(plength=hasp_width,pwidth=2,
            pheight=1,pradius=1);
    };

    color("green") translate([0,1.3,-8.5]) {
        cube([hasp_width,2,4]);
        translate([0,1.,-1]) rotate([45,0,0]) cube([hasp_width,1.4,1.4]);
	}
}

//
// 5-Add Text to front of lower box:
//   If supports are printed, use all three text strings:
//
if (print_base > 0)  {
	txtlist_supports = [
		[box_length/3-support_w/2-2, "right", lbltext1],
		[box_length/2, "center", lbltext2],
		[box_length*2/3+support_w/2+2, "left", lbltext3]
	];
	// If no supports, use only the first text string:
	txtlist_none = [
		[box_length/2, "center", lbltext1]
	];

	if (do_support) {
		for (tparam = txtlist_supports) printtext(x_offset=tparam[0],
			h_align=tparam[1], textstring=tparam[2]);
	} else {
		for (tparam = txtlist_none) printtext(x_offset=tparam[0],
			h_align=tparam[1], textstring=tparam[2]);
	}
}

//
//  DEFINE MODULES USED IN THE ABOVE CODE:
//

module roundedplate(plength,pwidth,pheight,pradius) {
    // Creates a flat rectangular shape with rounded corners.
    hull() {
        translate([pradius,pradius,0])
            cylinder(r=pradius,h=pheight,$fn=60);
        translate([plength-pradius,pradius,0])
            cylinder(r=pradius,h=pheight,$fn=60);
        translate([pradius,pwidth-pradius,0])
            cylinder(r=pradius,h=pheight,$fn=60);
        translate([plength-pradius,pwidth-pradius,0])
            cylinder(r=pradius,h=pheight,$fn=60);
    }
}

module createbox(boxtype, boxht) {
    // This creates a box, using the "roundedplate" module to round the corners.
    // It also adds lower & upper brims, and support rectagles around the sides.
	// Boxtype should be "B" or "T" for bottom vs top.
    difference () {
        translate([0,0,0]) {
            // First add the body of the box:
            roundedplate(plength=box_length,
                pwidth=box_width,
                pheight=boxht,
                pradius=roundradius);

            // Add in the lower brim, use hull combination to get bevel:
            if (do_brim) hull() {
                translate([-brim_width,-brim_width,0]){
                    roundedplate(plength=box_length+2*brim_width,
                        pwidth=box_width+2*brim_width,
                        pheight=brim_ht,
                        pradius=roundradius); }
                translate([0,0,brim_ht]){
                    roundedplate(plength=box_length,
                        pwidth=box_width,
                        pheight=brim_ht,
                        pradius=roundradius);
                }
            }

            // Add in the upper brim, use hull combination to get bevel:
            if (do_brim) hull() {
                translate([-brim_width,-brim_width,boxht-brim_ht]){
                    roundedplate(plength=box_length+2*brim_width,
                        pwidth=box_width+2*brim_width,
                        pheight=brim_ht,
                        pradius=roundradius); }
                translate([0,0,boxht-2*brim_ht]){
                    roundedplate(plength=box_length,
                        pwidth=box_width,
                        pheight=brim_ht,
                        pradius=roundradius);
                }
            }

            // Add support rectangles in front:
            if (do_support && boxtype == "B") for(n=[1:2])
                {translate([box_length*n/3-support_w/2,-support_t,0])
                    {color("cyan") cube([support_w,support_t+.25,boxht]); } };

            // Add support rectangles in back:
            if (do_support) for(n=[1:2])
                {translate([box_length*n/3-support_w/2,box_width-.25,0])
                    {color("cyan") cube([support_w,support_t+.25,boxht]); } };

            // Add support rectangle on left & right:
            if (do_support) {
                translate([-support_t,box_width/2-support_w/2,0])
                    {color("cyan") cube([support_t+.25,support_w,boxht]); }
                translate([box_length-.25,box_width/2-support_w/2,0])
                    {color("cyan") cube([support_t+.25,support_w,boxht]); }
            }
        }

        // Subtract out the inside area:
        translate([wall_thick-.01,wall_thick-.01,floor_thick-.01]) {
            roundedplate(plength=box_length-2*wall_thick+.015,
                pwidth=box_width-2*wall_thick+.015,
                pheight=boxht+.015,
                pradius=wall_thick); }
    }
}

module printtext(x_offset, h_align, textstring) {
    // Prints text on vertical surface, sinks in 0.5mm
    // Text stands out by 0.8mm
    translate([x_offset,0.5,brim_ht+brim_width+4]) rotate([90,0,0])
        linear_extrude(1.3)
            text(text = textstring, font = lblfont, size = lblsize,
                halign = h_align, valign = "center");
};

```


[User]
I'm looking to create a fully customizable tube junction, similar to the one on codeandmake.com, but with a few key differences and additional features. I need this to be fully parametric and generated using OpenSCAD.

First off, I need the ability to handle both round and rectangular tubes, and for each, I'd need to independently control the inside diameter (for round tubes) or inside width and height (for rectangular tubes). The material thickness should be variable too, of course. Also, the junction needs to support straight, T-shape, and cross-shape configurations, so similar to the existing design’s `Configuration` option, I need that.

Each end of the tube needs to be able to be beveled by a user specified percentage. Additionally, I need a hole for a grub screw, which will be manually tapped after printing, and the diameter for that needs to be customizable. The minimum tube length also needs to be parametric.

Now, here's where it gets a bit different. I'd like to add a few features:
1.  **Adjustable Angle:** Instead of always having 90 degree angles for T and Cross junctions, I'd like to be able to specify the angle between the tubes, especially useful for T-junctions. This means a single `Tube_Angle` variable should be added.
2.  **Filleted Edges**: I need a way to control the fillet radius on the external edges of the junction, particularly where the tubes meet. I'm imagining this would be a `Fillet_Radius` variable. I also need this fillet to apply to the *inside* edges.
3.  **Bolt Holes:** I need to be able to add bolt holes to the face of each tube end. I'd like to specify the number of holes, the hole diameter, and the radius at which the holes are placed from the center of the tube. This should be controllable, and ideally there would be a way to specify hole parameters for each tube.
4.  **Mounting Flange Option**: Finally, it would be great to have an option to add a mounting flange at each end of the tube, with customizable dimensions (e.g. flange diameter or size, flange thickness, bolt hole patterns on the flange, and bolt hole diameter on the flange).

For libraries, I'd anticipate that this would need a good geometry library for the fillets, so perhaps the `BOSL2` library would be most useful. I also think `MCAD` might be helpful for the bolt hole calculations.

I'm hoping you can provide a well-structured, modular design. Ideally, each feature will be its own module and the `tubeJunction` module can be called to generate the junction.

Please let me know if you have any questions!

[Assistant]
codeandmake.com_Tube_Junction_v0.2.scad:
```
/*
 * Copyright 2022 Code and Make (codeandmake.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Tube Junction by Code and Make (https://codeandmake.com/)
 *
 * https://codeandmake.com/post/tube-junction
 *
 * Tube Junction v0.2 (4 August 2022)
 */

/* [General] */

// The type of junction
Configuration = 3; // [1: Straight, 3: T-Shape, 4: Cross-Shape]

// Thickness of the material
Material_Thickness = 3; // [2:0.5:5]

/* [Tube] */

// The shape of the tube
Tube_Profile = 1; // [1:Round, 2:Rectangular]

// The inside diameter of the round tube
Round_Tube_Inside_Diameter = 22.5; // [5:0.001:50]

// The inside width (X/Y axis) of the rectangular tube
Rectangular_Tube_Inside_Width = 22.5; // [5:0.001:50]

// The inside height (Z axis) of the rectangular tube
Rectangular_Tube_Inside_Height = 22.5; // [5:0.001:50]

// The minimum length of the tube
Min_Tube_Length = 25.4; // [5:0.001:50]

// The amount to bevel the end of the tube (as a percentage)
Tube_Bevel_Percentage = 100; // [0:1:100]

// Grub screw hole diameter. Not threaded. Will require manual tapping.
Grub_Screw_Hole_Diameter = 3; // [0:0.1:8]

module tubeJunction() {
  $fn = 60;
  fnHigh = ($preview ? 60 : 200);

  tubeBevelRadius = Material_Thickness * (Tube_Bevel_Percentage / 100) / 2;
  Tube_Angle = 90;

  module roundTube() {
    translate([0, 0, (Round_Tube_Inside_Diameter / 2) + Material_Thickness]) {
      difference() {
        union() {
          translate([0, 0, -((Round_Tube_Inside_Diameter / 2) + Material_Thickness)]) {
            difference() {
              cylinder(r = (Round_Tube_Inside_Diameter / 2) + Material_Thickness, h = ((Round_Tube_Inside_Diameter / 2) + Material_Thickness + Min_Tube_Length - tubeBevelRadius), $fn = fnHigh);
              translate([0, 0, -0.05]) {
                cylinder(r = (Round_Tube_Inside_Diameter / 2), h = (Round_Tube_Inside_Diameter / 2) + Material_Thickness + Min_Tube_Length + 0.1, $fn = fnHigh);
              }
            }
          }

          translate([0, 0, Min_Tube_Length - tubeBevelRadius]) {
            intersection() {
              cylinder(r = (Round_Tube_Inside_Diameter / 2) + Material_Thickness, h = Material_Thickness / 2, $fn = fnHigh);
              rotate_extrude(convexity = 10, $fn = fnHigh) {
                translate([(Round_Tube_Inside_Diameter / 2) + tubeBevelRadius, 0, 0]) {
                  hull() {
                    circle(r = tubeBevelRadius);
                    translate([Material_Thickness - (tubeBevelRadius * 2), 0, 0]) {
                      circle(r = tubeBevelRadius);
                    }
                  }
                }
              }
            }
          }
        }

        translate([0, 0, (Min_Tube_Length / 2) - (Material_Thickness / 4)]) {
          rotate([0, -90, 0]) {
            cylinder(d = Grub_Screw_Hole_Diameter, h = (Round_Tube_Inside_Diameter / 2) + Material_Thickness + 0.1);
          }
        }
      }
    }
  }

  module rectangularTubeBevelEdge(length, offset) {
    rotate([90, 0, 0]) {
      linear_extrude(height = length, center = true, convexity = 10) {
        translate([offset + tubeBevelRadius, 0, 0]) {
          hull() {
            circle(r = tubeBevelRadius);
            translate([Material_Thickness - (tubeBevelRadius * 2), 0, 0]) {
              circle(r = tubeBevelRadius);
            }
          }
        }
      }
    }
  }

  module rectangularTubeBevelCorner() {
    translate([Rectangular_Tube_Inside_Height / 2, Rectangular_Tube_Inside_Width / 2, 0]) {
      intersection() {
        cube(size = [Material_Thickness, Material_Thickness, Material_Thickness]);
        rotate_extrude(convexity = 10, $fn = fnHigh) {
          // + 0.0001 is needed to avoid errors in OpenSCAD
          translate([tubeBevelRadius + 0.0001, 0, 0]) {
            hull() {
              circle(r = tubeBevelRadius);
              translate([Material_Thickness - (tubeBevelRadius * 2), 0, 0]) {
                circle(r = tubeBevelRadius);
              }
            }
          }
        }
      }
    }
  }

  module rectangularTubeBevel() {
    rectangularTubeBevelEdge(Rectangular_Tube_Inside_Width, Rectangular_Tube_Inside_Height / 2);

    mirror([1, 0, 0]) {
      rectangularTubeBevelEdge(Rectangular_Tube_Inside_Width, Rectangular_Tube_Inside_Height / 2);
    }

    rotate([0, 0, -90]) {
      rectangularTubeBevelEdge(Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width / 2);
    }

    rotate([0, 0, 90]) {
      rectangularTubeBevelEdge(Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width / 2);
    }

    rectangularTubeBevelCorner();

    mirror([1, 0, 0]) {
      rectangularTubeBevelCorner();
    }

    mirror([0, 1, 0]) {
      rectangularTubeBevelCorner();
    }

    mirror([1, 0, 0]) {
      mirror([0, 1, 0]) {
        rectangularTubeBevelCorner();
      }
    }
  }

  module rectangularTube() {
    rotate([0, 90 - Tube_Angle, 0]) {
      translate([0, 0, ((Rectangular_Tube_Inside_Width / 2) + Material_Thickness)]) {
        difference() {
          union() {
            difference() {
              translate([0, 0, -((Rectangular_Tube_Inside_Width / 2) + Material_Thickness)]) {
                union() {
                  hull() {
                    translate([Rectangular_Tube_Inside_Height / 2, Rectangular_Tube_Inside_Width / 2, 0]) {
                      cylinder(r = Material_Thickness, h = ((Rectangular_Tube_Inside_Width / 2) + Material_Thickness + Min_Tube_Length - tubeBevelRadius));
                    }
                    translate([Rectangular_Tube_Inside_Height / 2, -Rectangular_Tube_Inside_Width / 2, 0]) {
                      cylinder(r = Material_Thickness, h = ((Rectangular_Tube_Inside_Width / 2) + Material_Thickness + Min_Tube_Length - tubeBevelRadius));
                    }
                    translate([-Rectangular_Tube_Inside_Height / 2, Rectangular_Tube_Inside_Width / 2, 0]) {
                      cylinder(r = Material_Thickness, h = ((Rectangular_Tube_Inside_Width / 2) + Material_Thickness + Min_Tube_Length - tubeBevelRadius));
                    }
                    translate([-Rectangular_Tube_Inside_Height / 2, -Rectangular_Tube_Inside_Width / 2, 0]) {
                      cylinder(r = Material_Thickness, h = ((Rectangular_Tube_Inside_Width / 2) + Material_Thickness + Min_Tube_Length - tubeBevelRadius));
                    }
                  }
                }
              }

              translate([0, 0, ((Min_Tube_Length + tubeBevelRadius) / 2) - 0.05]) {
                cube(size = [Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width, (Min_Tube_Length + tubeBevelRadius) + 0.1], center = true, $fn = fnHigh);
              }
            }

            translate([0, 0, Min_Tube_Length - tubeBevelRadius]) {
              intersection() {
                translate([-(Rectangular_Tube_Inside_Height + (Material_Thickness * 2)) / 2, -(Rectangular_Tube_Inside_Width + (Material_Thickness * 2)) / 2, 0]) {
                  cube([Rectangular_Tube_Inside_Height + (Material_Thickness * 2), Rectangular_Tube_Inside_Width + (Material_Thickness * 2), Material_Thickness / 2], $fn = fnHigh);
                }
                rectangularTubeBevel();
              }
            }
          }

          translate([0, 0, (Min_Tube_Length / 2) - (Material_Thickness / 4)]) {
            rotate([0, -90, 0]) {
              cylinder(d = Grub_Screw_Hole_Diameter, h = (Rectangular_Tube_Inside_Height / 2) + Material_Thickness + 0.1);
            }
          }
        }
      }
    }
  }

  if(Tube_Profile == 1) {
    difference() {
      union() {
        if (Configuration == 3 || Configuration == 4) {
          rotate([0, 90, 0]) {
            roundTube();
          }
        }
        rotate([-90, 90, 0]) {
          roundTube();
        }
          rotate([90, 90, 0]) {
            roundTube();
          }
        if (Configuration == 4) {
          rotate([180, 90, 0]) {
            roundTube();
          }
        }
      }

      if (Configuration == 3 || Configuration == 4) {
        rotate([0, 90, 0]) {
          translate([0, 0, -0.05]) {
            cylinder(r = (Round_Tube_Inside_Diameter / 2), h = (Round_Tube_Inside_Diameter / 2) + Material_Thickness + 0.1, $fn = fnHigh);
          }
        }
      }
      rotate([-90, 90, 0]) {
        translate([0, 0, -0.05]) {
          cylinder(r = (Round_Tube_Inside_Diameter / 2), h = (Round_Tube_Inside_Diameter / 2) + Material_Thickness + 0.1, $fn = fnHigh);
        }
      }
      rotate([90, 90, 0]) {
        translate([0, 0, -0.05]) {
          cylinder(r = (Round_Tube_Inside_Diameter / 2), h = (Round_Tube_Inside_Diameter / 2) + Material_Thickness + 0.1, $fn = fnHigh);
        }
      }
      if (Configuration == 4) {
        rotate([180, 90, 0]) {
          translate([0, 0, -0.05]) {
            cylinder(r = (Round_Tube_Inside_Diameter / 2), h = (Round_Tube_Inside_Diameter / 2) + Material_Thickness + 0.1, $fn = fnHigh);
          }
        }
      }
    }
  }

  if(Tube_Profile == 2) {
    difference() {
      union() {
        if (Configuration == 3 || Configuration == 4) {
          rotate([0, 90, 0]) {
            rectangularTube();
          }
        }
        rotate([-90, 90, 0]) {
          rectangularTube();
        }
        rotate([90, 90, 0]) {
          rectangularTube();
        }
        if (Configuration == 4) {
          rotate([180, 90, 0]) {
            rectangularTube();
          }
        }
      }

      if (Configuration == 3 || Configuration == 4) {
        rotate([0, 90, 0]) {
          translate([0, 0, (((Rectangular_Tube_Inside_Width / 2) + Material_Thickness) / 2) - 0.05]) {
            cube(size = [Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width, (Rectangular_Tube_Inside_Width / 2) + Material_Thickness + 0.2], center = true, $fn = fnHigh);
          }
        }
      }
      rotate([-90, 90, 0]) {
        translate([0, 0, (((Rectangular_Tube_Inside_Width / 2) + Material_Thickness) / 2) - 0.05]) {
          cube(size = [Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width, (Rectangular_Tube_Inside_Width / 2) + Material_Thickness + 0.2], center = true, $fn = fnHigh);
        }
      }
      rotate([90, 90, 0]) {
        translate([0, 0, (((Rectangular_Tube_Inside_Width / 2) + Material_Thickness) / 2) - 0.05]) {
          cube(size = [Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width, (Rectangular_Tube_Inside_Width / 2) + Material_Thickness + 0.2], center = true, $fn = fnHigh);
        }
      }
      if (Configuration == 4) {
        rotate([180, 90, 0]) {
          translate([0, 0, (((Rectangular_Tube_Inside_Width / 2) + Material_Thickness) / 2) - 0.05]) {
            cube(size = [Rectangular_Tube_Inside_Height, Rectangular_Tube_Inside_Width, (Rectangular_Tube_Inside_Width / 2) + Material_Thickness + 0.2], center = true, $fn = fnHigh);
          }
        }
      }
    }
  }
}

tubeJunction();

echo("\r\tThis design is completely free and shared under a permissive license.\r\tYour support is hugely appreciated: codeandmake.com/support\r");

```


[User]
I'd like to design a customizable stand for my devices using OpenSCAD. I've seen a design that does something similar, but I need it to be completely parametric, so I can easily adjust it for different devices.

Here's how I'd like the stand to work:

**Basic Parameters:**

*   **`width`**:  The width of the device the stand will hold.
*   **`depth`**: The depth of the device the stand will hold.
*   **`stopper_height`**: The height of the stopper at the front of the stand to prevent the device from sliding off.
*   **`angle`**:  The desired angle at which the device should be displayed.

**Foot Configuration:**

*   **`foot_depth`**: The depth of the foot at the bottom of the stand, to prevent sliding.
*   **`foot_orientation`**: An option to choose where the foot is positioned: `"behind"`, `"centered"`, or `"infront"` relative to the stand's leg.

**Advanced Configuration:**

*   **`stand_thickness`**: The thickness of the stand's walls/structure.
*   **`height`**: The height/thickness of the platform where the device sits.
*   **`$fn`**: The number of fragments used for curves/circles.

**Reduce Filament (Optional):**

*   **`decrease_percentage`**: A percentage value (50-95) that affects how much material will be cut out to reduce filament usage.
*   **`decrease_table`**: A boolean to enable reduction of material on the platform where the device sits.
*  **`decrease_back`**: A boolean to enable reduction of material on the back support leg of the stand.

The stand will consist of a back plate (leg), a table plate where the device rests, a stopper at the front, and a foot. I'd like to be able to adjust all of these dimensions. The back support should smoothly connect to the base and use a rotation to create the angled shape.

Can you generate the necessary OpenSCAD files for this design, including the parametric definitions and structures, such that everything is fully customizable? I do not expect any external libraries to be used.

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

Universal Stand
Customizable stand for your devices and other stuff.

by IOIO72 aka Tamio Patrick Honma (https://honma.de)

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

Updates

2022-02-21: Add experimental feature Reduce Filament Consumption

Description

Whether you want to use a device in an angled position or present something in an optimal orientation, you can design a stand to suit your needs.

This model is customizable to generate STL files for your individual use case. Included in this package are some examples and inspirations for smartphones, tablets, notebooks, business cards, table name cards, print magazines, keyboards, etc.

Customization

Basic configuration:

1. Measure the `width` and `depth` of your device or object in millimeters and enter the values into the customizer.
2. Determine the height of the device at the front of the stand that will prevent the device or object from sliding off the stand. This can be the measured height of your device or object, if applicable. Enter the value of the `stopper height` into the customizer.
3. Enter the desired `angle` at which you want your device or object to be presented, which is the main purpose of the stand.

Foot configuration:

1. Define the `foot depth` to prevent the stand of sliding, especially concerning interactive devices. You should add a rubber tape on the bottom of the foot or a weight on top of it.
2. You are able to set the `foot orientation` behind, centered or in front of the stand leg.

Advanced configuration:

1. Define the `stand thickness` in relationship of the steadiness requirements and material consumption.
2. Define the `height` of the table plate for your device. The height is the thickness of the plate on which your device will be placed, if you will.
3. Set the number of fragments (`$fn`), especially to smooth or de-smooth the curve of the leg.

Reduce Filament Consumption (experimental) configuration:

1. Use these experimental parameters with caution. Be careful not to overstress your printer's ability to print overhangs. Also, find a good compromise between stand strength and filament reduction. You can also increase the `stand thickness` in the Advanced Configuration section.
2. The higher the `decrease percentage`, the larger the hole and the lower the steadiness of the stand.
3. To apply the filament consumption reduction to the table top of the stand, enable the `decrease table` option.
4. To apply the filament consumption reduction to the back plate (leg) of the stand, activate the `decrease back` option.

Tips:

* To test your configured stand, you could consider to cancel the print after some layers and test the angle and steadiness.
* If you use the stand for an interactive device, you should glue a rubber tape on the bottom of the foot to prevent the stand to slide away while using the device. To improve the adhesion, you may increase the depth of the foot in the foot options. Additionally you may add a weight on top of the foot.

Use OpenSCAD

As the Thingiverse customizer has some issues, it's better to use OpenSCAD instead.

1. **Download and install:** [OpenSCAD](http://openscad.org/) version 2021.01 or newer
2. **Download:** The *.scad file of this model.
3. **Start** OpenSCAD and **open** the *.scad file in it.
4. **Open the customizer** via the menu "Window/Customizer"

Now you can configure the model and use the `F5` key to render the preview of your changes.

Export your STL file:

If you're done with your model settings, you can export the STL file:

1. Render the mesh by pressing the `F6` key.
2. Wait until the rendering is finished. This might take some minutes.
3. Export the STL file by pressing the `F7` key.

Optionally save your configuration:

If you like to use your configuration as a template for further models, it's a good idea, to save your configuration:

1. Click the `+` symbol in the customizer, which you find beside the configuration selector drop-down in the second line of the customizer.
2. Give your configuration a name.

Use the drop-down menu to access your saved configurations.

Help others and post a Remix

Your configuration may be helpful for others. Consider to upload your STL file as a [remake of this model](https://www.thingiverse.com/thing:5245158/remix).
*/

/* [Basic] */

// Width of your device
width = 155;

// Depth of your device
depth = 63;

// Height of the bottom stopper ≈ device height
stopper_height = 12;

// Angle
angle = 35;

/* [Foot] */

// Depth of stand foot
foot_depth = 8;

// Foot orientation in relation to the leg of the stand
foot_orientation = "behind"; // ["behind", "centered", "infront":"in front"]

/* [Advanced] */

// Thickness of stand walls
stand_thickness = 1.8;

// Height of the table plate
height = 1.8;

// Number of fragments
$fn = 100; // [1:150]

/* [Reduce Filament Consumption (experimental)] */

// Percentage of decrease
decrease_percentage = 85; // [50:95]

// Decrease for table plate
decrease_table = false;

// Decrease for back plate
decrease_back = false;

function decrease(size, percent) = size * percent / 100;

module printable_rotation(width, height) {
  rotate([0, 90, 90])
  translate([-width, height, 0])
  children();
};

module stand(width, depth, height, thickness) {
  rotate_extrude(angle = angle) // extrudes to pribtable rotation
  translate([-height, 0, 0])
  rotate([0, 0, 90])
  translate([0, depth - thickness, 0])
  square([width, thickness]);
};

module stand_through_hole(through_hole, w, h) {
  if (through_hole) {
    rotate([180, 270, 90 - ((180 - angle) / 2)])
    translate([w, h, 0])
    rotate([180, 0, 0])
    scale([1, 1, 1000])
    children();
  } else {
    children();
  };
};

module reduce_filamant(reduce = false, through_hole = false, width, height, depth) {
  w = decrease(width, decrease_percentage);
  h = decrease(height, decrease_percentage);
  if (reduce) {
    difference() {
      children();
      stand_through_hole(through_hole, 0, height / 2)
      translate([width / 2, height / 2, -depth / 2])
      linear_extrude(depth * 2)
      resize([w, h])
      circle(r=w);
    };
  } else {
    children();
  };
};

/* Stand / Back Plate */
reduce_filamant(decrease_back, true, width, sin(angle) * depth, height)
stand(width, depth, height, stand_thickness);

/* Table Plate */
printable_rotation(width, height)
reduce_filamant(decrease_table, false, width, depth, height)
cube([width, depth, height]);

/* Stopper */
printable_rotation(width, height - stand_thickness)
cube([width, stand_thickness, stopper_height]);

/* Foot */
rotate([0, 0, angle])
translate([foot_orientation == "infront" ? foot_depth - stand_thickness : 0, 0, 0])
translate([foot_orientation == "centered" ? (foot_depth - stand_thickness) / 2 : 0, 0, 0])
printable_rotation(width, height + depth - stand_thickness)
cube([width, foot_depth, stand_thickness]);

```


[User]
I'd like to create a parametric rolling pin holder in OpenSCAD. I'm imagining a cradle-like structure that holds the pin, with a flat base for stability. The design should allow me to specify the rolling pin diameter, the length and width of the holder itself, and the height of the base. Additionally, it should be smooth, especially the curved part that holds the pin.

Here are the specific parameters I need to control:

*   `PinDiameter`: The diameter of the rolling pin that the holder will accommodate (in millimeters).
*   `PinHolderLength`: The overall length of the holder (in millimeters).
*   `PinHolderWidth`: The overall width of the holder (in millimeters).
*   `FooterHeight`: The height of the flat rectangular base (in millimeters).
*   `$fn`: This will control the smoothness of the curves, which would be an integer that controls the number of facets for circles and cylinders.

The main body of the holder should be formed by two intersecting, extruded trapezoidal shapes with a cylindrical subtraction in the intersection to create the cradle. I'd like one trapezoid extruded along the X axis and one along the Y. The flat base (footer) should be a rectangular prism under the entire structure. The design should be centered at the origin. The code should be well commented, as I am planning to modify it later. Please include the full set of generated .scad files.

[Assistant]
ParameterizedRollingPinHolder.scad:
```
////////////////////////////////////
//	USER-ADJUSTABLE PARAMETERS   //
//	 All units in millimeters    //
////////////////////////////////////

//	The diameter of the rolling pin
PinDiameter = 60;
//	The desired length of the rolling pin holder
PinHolderLength = 100;
//	The desired width of the rolling pin holder
PinHolderWidth = 80;
//	The height of the footer rectangle
FooterHeight = 2;
//	The smoothness of the extruded cylinder.  Set low while designing, set high when rendering.
$fn = 30;

///////////////////////////
//	CALCULATED VALUES   //
///////////////////////////
YZTrapezoidPoints = [[(-PinHolderWidth / 2), 0], [(PinHolderWidth / 2), 0], [(PinHolderWidth / 4), (PinDiameter / 1.75)], [-(PinHolderWidth / 4), (PinDiameter / 1.75)]];
XZTrapezoidPoints = [[-(PinHolderLength / 2), 0], [(PinHolderLength / 2), 0], [(PinHolderLength / 4), (PinDiameter / 1.75)], [-(PinHolderLength / 4), (PinDiameter / 1.75)]];

//	Output object
union() {
	//	Top rolling pin holder
	intersection() {
		//	YZ plane
		difference() {
			//	YZ trapezoid
			rotate([90, 0, 90])	linear_extrude(height = PinHolderLength, center = true)	polygon(YZTrapezoidPoints);

			//	YZ circle
			translate([0, 0, PinDiameter / 1.75])	rotate([0, 90, 0])	linear_extrude(height = PinHolderLength + 2, center = true)	circle(PinDiameter / 2, $fn = $fn);
		}

		//	XZ trapezoid
		rotate([90, 0, 0])	linear_extrude(height = PinHolderWidth, center = true)	polygon(XZTrapezoidPoints);
	}

	//	Footer cube
	translate([0, 0, -FooterHeight + 1])	cube([PinHolderLength, PinHolderWidth, FooterHeight], center = true);
}
```


[User]
Hey there, I'm looking to design a phone holder for use with a gamepad, and I want it to be customizable for different phone sizes. I have some specific ideas in mind, but I'm also open to suggestions.

Here's what I'm thinking:

*   **Core Structure:** The holder should be a kind of "cradle" that fits around the sides and part of the back of a phone. It will have a cutout to accommodate a gamepad which will sit behind the phone. The phone sits in front of the gamepad. It is similar to the included SCAD file case.scad but with a different structure.
*   **Parametric Dimensions:** I need to be able to control the following parameters easily, all in millimeters:
    *   `phone_width`: The width of the phone.
    *   `phone_depth`: The thickness of the phone.
    *   `gamepad_width`: The width of the gamepad (which sits behind the phone).
    *   `gamepad_depth`: The thickness of the gamepad.
    *   `holder_height`: The overall height of the holder.
    *   `wall_thickness`: The thickness of the material forming the holder.
    *   `spacing`: A gap (could be negative) between the back of the phone and the front of the gamepad.
    *   `corner_radius`: The radius of the rounded corners of the holder.
*   **Gamepad Support:** The design should include some way to support the gamepad behind the phone so that it doesn't just fall out. Perhaps some small "ledges" or supports, similar to the side holders in case.scad.
*   **Phone Security:** The phone should be held securely by the holder. There should be enough "wrap-around" on the sides to keep it from sliding out laterally. I don't need any top or bottom walls going across the screen, just sides and a support behind the phone for the gamepad.
*   **Light Slot:** I'd like a slot on one side for a small light or cable to pass through. This would be similar to the light slot in case.scad.
*   **Rounded Edges:** Everything should have rounded edges, which would increase comfort and make it feel less boxy.
*   **No Screen Wall:** I want no wall or support between the phone's screen and the gamepad, unlike the example SCAD file. This is intentional. I found the gamepad was too far from the phone in the example design.

I expect the output to be a modular OpenSCAD file, or files, that uses parameters to control all these aspects. I'm comfortable with some of the more advanced OpenSCAD features. Specifically, I'd expect your design to be using the `hull()` function to generate curved edges. The example code also uses a custom `roundedcube` module which I wouldn't mind seeing included or being replaced by a module from an external library. I know there is `roundcube` in BOSL2 but I'm not sure it can fully replace `roundedcube` from the provided SCAD file. I'm very open to you suggesting a better way of creating rounded cubes or other shapes.

Also, can you make sure to use `eps` variables for small numerical adjustments to avoid Z-fighting, and `fn` and `fs` for smoothness controls?

I would expect this project to require more than one .scad file.

Let me know if you need any more information. I am excited to see what you come up with!

[Assistant]
case.scad:
```
// Height
h = 45;
// Wall size
wall = 1.5;
// Phone slot width
phone_width = 80.5;
// Phone slot depth
phone_depth = 12;
// Space between back of pad and screen. Could be negative
spacing = -1;
// Chamfer radius
radius = 2;
//------------------------------

/* [Hidden] */

$fn = 20;
$fs = 1/$fn;

eps = 0.01;
eps2 = 2*eps;
eps3 = 3*eps;

phone_cutout = [phone_width, phone_depth, h-wall];
pad = [73, 35, 13];
light_slot = [10, 2, h];
r = pad.y / 2;
top_cutout_start = h;

// https://danielupshaw.com/openscad-rounded-corners/
module roundedcube(size = [1, 1, 1], center = false, radius = 0.5, apply_to = "all") {
	// If single value, convert to [x, y, z] vector
	size = (size[0] == undef) ? [size, size, size] : size;

	translate_min = radius;
	translate_xmax = size[0] - radius;
	translate_ymax = size[1] - radius;
	translate_zmax = size[2] - radius;

	diameter = radius * 2;

	module build_point(type = "sphere", rotate = [0, 0, 0]) {
		if (type == "sphere") {
			sphere(r = radius);
		} else if (type == "cylinder") {
			rotate(a = rotate)
			cylinder(h = diameter, r = radius, center = true);
		}
	}

	obj_translate = (center == false) ?
		[0, 0, 0] : [
			-(size[0] / 2),
			-(size[1] / 2),
			-(size[2] / 2)
		];

	translate(v = obj_translate) {
		hull() {
			for (translate_x = [translate_min, translate_xmax]) {
				x_at = (translate_x == translate_min) ? "min" : "max";
				for (translate_y = [translate_min, translate_ymax]) {
					y_at = (translate_y == translate_min) ? "min" : "max";
					for (translate_z = [translate_min, translate_zmax]) {
						z_at = (translate_z == translate_min) ? "min" : "max";

						translate(v = [translate_x, translate_y, translate_z])
						if (
							(apply_to == "all") ||
							(apply_to == "xmin" && x_at == "min") || (apply_to == "xmax" && x_at == "max") ||
							(apply_to == "ymin" && y_at == "min") || (apply_to == "ymax" && y_at == "max") ||
							(apply_to == "zmin" && z_at == "min") || (apply_to == "zmax" && z_at == "max")
						) {
							build_point("sphere");
						} else {
							rotate =
								(apply_to == "xmin" || apply_to == "xmax" || apply_to == "x") ? [0, 90, 0] : (
								(apply_to == "ymin" || apply_to == "ymax" || apply_to == "y") ? [90, 90, 0] :
								[0, 0, 0]
							);
							build_point("cylinder", rotate);
						}
					}
				}
			}
		}
	}
}
function base_dim() = [max(phone_cutout.x, pad.x)+2*wall, pad.z+phone_cutout.y+spacing, 2*(top_cutout_start-pad.y/4)];

module pad_cutout_cylinder() {
    cylinder(r2=pad.y/2, r1=pad.y/2, h=base_dim().y);
}

module side_holder(){
    translate([base_dim().x/2-pad.x/2 ,0,top_cutout_start-3])
        //rotate([90,0,0]) cylinder(r=3,h=2,center=true);
        rotate([0,-30,0]) roundedcube([5, 1, 5], radius=1, center=true);
}

//cube();
difference() {
    union() {
        // Base is big rounded cube. Pad cutout is located in its XY center.
        roundedcube(base_dim(), radius = radius);
        // bottom holder
        translate([base_dim().x/2, 0, (base_dim().z-pad.y)/2])
            //rotate([90,0,0]) cylinder(r=3,h=2,center=true);
            roundedcube([light_slot.x*2, light_slot.y, 6], radius=1.5, center=true);
        //side holders
        side_holder();
        translate([base_dim().x, 0, 0]) mirror([base_dim().x,0,0]) side_holder();
    }
    // Cutout base top to have shoulder button access
    translate([-eps, -eps, top_cutout_start]) scale(1+eps) cube([phone_cutout.x+2*wall, base_dim().y, base_dim().z]);

    // phone cutout
    translate([wall, pad.z+spacing-wall, wall+eps]) cube(phone_cutout);
    // small phone cutout
    translate([wall+phone_cutout.x/4, pad.z+spacing, 0]) cube([phone_cutout.x/2, phone_cutout.y*2, base_dim().z]);

    //pad cutout
    scale([1, 1+eps, 1]) translate([base_dim().x/2 + r - pad.x/2, base_dim().y, base_dim().z/2])
    rotate([90, 0, 0]) hull() {
        pad_cutout_cylinder();
        translate([pad.x - pad.y, 0, 0]) pad_cutout_cylinder();
    }

    //light slot
    translate([light_slot.y/2+base_dim().x/2 - light_slot.x/2, pad.z/3, 0]) hull() {
        cylinder(r=light_slot.y, h=light_slot.z);
        translate([light_slot.x - light_slot.y, 0,-eps]) cylinder(r=light_slot.y, h=light_slot.z);
    }
}

// TODO: cReAtIvE cutout
/*
    difference() {
        cube(phone_cutout.x);
        rotate([90,0,0]) intersection() {
            cylinder(r=phone_cutout.x/6, h=phone_cutout.y*2);
            cube(phone_cutout.x);
        }
    }
*/

```


[User]
I'm looking to design a vortex separator, and I'd like to use OpenSCAD to create a parametric model. I have some basic parameters in mind and how the parts will fit together, but I need the full OpenSCAD design generated.

Here's the breakdown of the design:

**Overall Structure:** The separator is composed of several distinct, printable parts: an output tube, a barrel with an intake tube, a vortex cone, and a base fixture. I'd like to be able to print each separately or all together.

**Key Parameters:**

*   `Diameter_Barrel_Chamber`: This controls the diameter of the main barrel chamber. I need a slider for the user to control this, with a range from 50mm to 2000mm in increments of 10mm (e.g., 50, 60, 70, etc.).
*   `Diameter_Intake_Pipe`: The diameter of the intake pipe. I'd like a slider for values ranging from 10mm to 200mm in 1mm increments.
*   `Length_Intake_Pipe`: The length of the intake pipe, adjustable from 10mm to 200mm in 1mm increments.
*   `Diameter_Exit_Pipe`: The diameter of the exit pipe. I need another slider going from 10mm to 200mm in 1mm increments.
*   `Length_Exit_Pipe_Protruding`: This sets the length of the exit pipe that sticks out above the barrel cap, also controlled by a slider going from 10mm to 200mm in 1mm increments.
*  `Wall_Width`: The width of all the walls; this will need to be controllable in increments of 0.1mm from 0.1mm to 10mm.
*   `Tolerance`: This is the extra space left for assembly, again from 0 to 10 in 0.1mm increments.
*   `Diameter_Bolt`: Radius of the bolt holes in the bottom, going from 0 to 100mm in 1mm increments.
*   `Fineness`: Number of polygon divisions for smooth curves, a slider from 10 to 200 in 1mm increments should do.
*   `Logo`: A simple on/off switch for the logo on the top of the part, with "Yes" or "No" options.
* `part`:  A pulldown menu offering the options: "Output:Output Tube", "Barrel:Barrel with Intake Tube", "Vortex:Vortex Cone", "Base:Base Fixture", and "All:All Parts"

**Specifics of each part:**

*   **Output Tube:** This is a simple tube extending from the top of the barrel.
*   **Barrel:** This is the main chamber body, with a cylindrical shape and the intake pipe branching off it. There should be a lip on the top that connects to the Output tube.
*   **Vortex Cone:** This is the cone section. It connects to the barrel from underneath. It should have a lip that connects to the barrel section and four bolt holes on the bottom.
*   **Base:** The base is a simple plate with four bolt holes that the vortex cone will connect to.
*   **Fitting:** Parts should fit together with clearance provided by the tolerance setting.

**Additional Considerations:**

*   The code needs to have a `print_part()` module to call.
*   A `tube()` module that takes inner, outer, and height parameters should be included to make it easy to create cylinders.
*   A `curvedText()` module should also be included so I can put the text on the cap. I can pass it the text, a radius, size, and spacing variables.
*   I need to be able to specify which part gets printed when the code is compiled.
*   The location of the intake pipe should be along the side of the barrel chamber, not centrally.
*  I'm using the "Liberation Serif" font for the text module.

Can you generate the necessary OpenSCAD code for this?

[Assistant]
vortex-thing.scad:
```
//Diameter of the barrel chamber
Diameter_Barrel_Chamber = 75;//[50:10:2000]
//Diameter of the intake pipe
Diameter_Intake_Pipe = 25; //[10:1:200]
//Length of the intake pipe
Length_Intake_Pipe = 50; //[10:1:200]
//Diameter of the exit pipe
Diameter_Exit_Pipe = 25; //[10:1:200]
//Length of the Exit pipe above the cap
Length_Exit_Pipe_Protruding = 30; //[10:1:200]
//All walls are set to this width. Best if it is a multiple of your nozzle diameter.
Wall_Width = 0.8; //[0.1:0.1:10]
//Extra space for fitting pieces together for 3D printing
Tolerance = 0.4;//[0:0.1:10]
//Radius of the hole for bolts, in MM.
Diameter_Bolt = 6;//[0:1:100]
//Number of polygon divisions. Higher is better quality but slower to render.
Fineness = 100; //[10:1:200]
//Remove Logo. If you don't want the logo on top you can remove it here.
Logo= "Yes"; //[Yes, No]

//This object is divided up into sections for easy 3D printing. Or you can have one solid part.
part = "All"; // [Output:Output Tube, Barrel:Barrel with Intake Tube, Vortex:Vortex Cone, Base:Base Fixture, All:All Parts]

/* [Hidden] */
Jc = Diameter_Barrel_Chamber / 2;
Sc = 5 * Diameter_Barrel_Chamber / 8;
Hc = Diameter_Barrel_Chamber / 2;
Lc = Diameter_Barrel_Chamber;
Zc = 2 * Diameter_Barrel_Chamber;
$fn=Fineness;

module tube(height, inner, outer) { difference(){
    cylinder(height, outer, outer, false);
    cylinder(height, inner, inner, false);
    }
};

module curvedText(txt, r=10, size=10, spacing=1) {
  a = 180 * size * spacing / (PI * r);
  for (i = [0:len(txt)-1])
    rotate([0,0,-(i+0.5)*a])
    translate([0,r])
    linear_extrude(3)
    text(txt[i], size=size, halign="center", valign="bottom", $fn=32, font="Liberation Serif");
}

print_part();

module print_part() {

if(part == "Output" || part == "All")
{
    //Exit tube fusion
    translate([0,0,Zc+Lc]) tube(Length_Exit_Pipe_Protruding, Diameter_Exit_Pipe/2, Diameter_Exit_Pipe/2+Wall_Width);
}

if(part == "Barrel" || part == "All")
{
    //Barrel Fusion
    union() {
    //Barrel Coupler
    translate([0,0,Zc-Wall_Width])
        tube(Wall_Width*2, Diameter_Barrel_Chamber/2+Wall_Width+Tolerance, Diameter_Barrel_Chamber/2+2*Wall_Width);
    difference() {
        //Lip
        translate([0,0,Zc+Wall_Width])
            cylinder(Wall_Width, Diameter_Barrel_Chamber/2+2*Wall_Width, Diameter_Barrel_Chamber/2+Wall_Width);
        //Barrel Profile
        translate([0,0,Zc-Wall_Width])
            cylinder(Lc+Wall_Width, Diameter_Barrel_Chamber/2+Wall_Width,Diameter_Barrel_Chamber/2+Wall_Width);
    }

    //Barrel Cut
    //Barrel
    difference() {
        translate([0,0,Zc])
            tube(Lc, Diameter_Barrel_Chamber/2, Diameter_Barrel_Chamber/2+Wall_Width);
        //Intake Profile
        translate([0,-(Diameter_Barrel_Chamber/2-Diameter_Intake_Pipe/2),Zc+Lc-Diameter_Intake_Pipe/2-Wall_Width])
            rotate([0,90,0])
            cylinder(Length_Intake_Pipe, Diameter_Intake_Pipe/2,Diameter_Intake_Pipe/2);
    }
    //Intake Cut
    //Intake Tube
    difference(){
        translate([0,-(Diameter_Barrel_Chamber/2-Diameter_Intake_Pipe/2),Zc+Lc-Diameter_Intake_Pipe/2-Wall_Width])
            rotate([0,90,0])
                tube(Length_Intake_Pipe, Diameter_Intake_Pipe/2, Diameter_Intake_Pipe/2+Wall_Width);
        //Barrel Profile
            //Barrel Tube
            translate([0,0,Zc+3/8*Diameter_Barrel_Chamber])
                cylinder(5/8*Lc, Diameter_Exit_Pipe/2, Diameter_Exit_Pipe/2+Wall_Width);
    }
    //Barrel Tube
    translate([0,0,Zc+3/8*Diameter_Barrel_Chamber])
        tube(5/8*Lc, Diameter_Exit_Pipe/2, Diameter_Exit_Pipe/2+Wall_Width);

    //Cap
    difference() {
        translate([0,0,Zc+Lc])
            tube(2+Wall_Width, Diameter_Exit_Pipe/2+Wall_Width+Tolerance, Diameter_Barrel_Chamber/2+Wall_Width);
        if(Logo == "Yes")
        {
        translate([0,0,Zc+Lc+Wall_Width])
        curvedText("Spaulding Separator", Diameter_Exit_Pipe/2+(Diameter_Barrel_Chamber/2-Diameter_Exit_Pipe/2)/2, Diameter_Barrel_Chamber/10, 0.6);
        }
    }

    //Exit Tube Socket
    translate([0,0,Zc+Lc-Wall_Width*2])
        tube(Wall_Width*2, Diameter_Exit_Pipe/2, Diameter_Exit_Pipe/2+3*Wall_Width);
    }
}

if(part == "Vortex" || part == "All")
{
    //Vortex Union
    union() {
    //Vortex
    difference() {
        cylinder(Zc, Jc/2+Wall_Width, Diameter_Barrel_Chamber/2+Wall_Width);
        cylinder(Zc, Jc/2, Diameter_Barrel_Chamber/2);
    }

    //Bottom Plate
    difference() {
        tube(2*Wall_Width, Jc/2, Jc+Wall_Width);
        translate([0,Jc*0.75+Wall_Width,0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        translate([0,-(Jc*0.75+Wall_Width),0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        translate([Jc*0.75+Wall_Width,0,0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        translate([-(Jc*0.75+Wall_Width),0,0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        }
    }
}

if(part == "Base" || part == "All")
{
    //Undermount plate
    translate([0,0,-10])
    difference() {
        tube(2*Wall_Width, Jc/2, Jc+Wall_Width);
        translate([0,Jc*0.75+Wall_Width,0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        translate([0,-(Jc*0.75+Wall_Width),0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        translate([Jc*0.75+Wall_Width,0,0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
        translate([-(Jc*0.75+Wall_Width),0,0])
            cylinder(Wall_Width*2, Diameter_Bolt/2, Diameter_Bolt/2);
    }
}
}
```