[User]
I'd like a parametric design for a customizable holder, primarily intended for remote controls but versatile enough for other uses. It should have a main box section, a hook for attaching to something like a couch armrest, and an optional tablet on top of the hook.

For the box, I need to be able to set the overall height and depth. The width should be configurable based on a list of widths for individual compartments, plus a wall thickness between each. I also want to be able to label each compartment with text, and I need to control the text size and font.

The hook needs adjustable width, height, and depth. There should also be a setting for the height of the hook's mounting point on the box and a choice for the hook's construction: either "separate" (for gluing to the box), "separate printable" (a printable separate piece), or "unibody" (integrated into the box, which would require supports when printing).

Finally, the tablet on top of the hook should have an adjustable frame height (or zero for just a print platform).

I'd also like to be able to select which parts are displayed: the box, left hook, right hook, and the tablet. It would be great if each part could be exported separately, or all together as a single STL.

Could you provide this as an OpenSCAD file? I don't need it broken into different files; a single file should work fine.

[Assistant]
remote-control.scad:
```
/*
Customizable Holder for Remote Controls or any 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.

Update

2021-11-26: Tablet to attach on top of the hooks added.

Description

This holder was originally intended for remote controls, which you attach to the couch armrest.

In addition, it is possible to use the holder for all sorts of other purposes. This is especially possible due to the customizability of the 3D model. For example, you can also configure a holder for tools and material of the 3D printer or something for the garden, the workshop, the garage or the household.

Ultimately, the 3D model is a box, which can be subdivided as desired, and a holding device.

How to configure the box:

1. Set the general height and depth of the box.

2. Subdivision is done by a list of width specifications. It is important to keep the format: At the beginning and at the end of the list are square brackets and between them a comma-separated list of width specifications.

3. You can designate the individual subdivisions. The order of the entries corresponds to the list of width specifications. If you do not want any designations, enter the following there: `[""]`

4. The text size of the designations and the font used can also be set. For font selection, use the menu item "Help/ Font list" in OpenSCAD, select a font there and copy it to the clipboard. Then paste the font name into the "font" input field. It is important that you remove the quotation marks.

How to configure the hook for attachment:

All specifications refer to the inside of the hook, i.e. if you measure, for example, the width of your armrest, you can enter exactly this value. The walls of the hook are added around it.

1. Enter the width and height of the hook. The height is measured from the top edge of the box.

2. Enter the depth of the hook. This would be, for example, the width of your armrest.

3. Enter the height of the hook's attachment.

4. Set the type of hook. "Separate" is intended for mounting the hook to the box by glue. To make it easier to print, select "Separate printable". With the "Unibody" option, the hook becomes a part of the box. The latter can only be printed by support structures.

How to configure the tablet for attachment on top of the hook:

- Set the frame height of the tablet to 0, if you like to get a print tablet.
- Otherwise you can use this value to set the frame of the tablet.

Select the parts:

By selecting the parts, you can generate individual STL files for box and hook or generate a complete STL file for all components. This might be useful to place the parts on your print bed.

Help others:

Since I'm sure you have some good ideas for configuring mounts for various purposes, it would be great if you would share them with us.

Especially for people who do not configure, but only print finished STL files, would certainly be happy about suitable models.

So feel free to share your configurations via Make.

*/

// Wall Thickness
wall_thickness = 2.5;

/* [Box] */

// Height of Box
box_height = 60;

// Depth of Box
box_depth = 33;

// Widths of Remotes
remotes_widths = [45, 48, 54, 54, 39];

// Acronyms or Names for Remotes (use few letters)
remotes_names = ["Lights", "DVB", "BluRay", "Audio", "TV"];

// Text Size
text_size = 10;

// Font (use OpenSCAD menu "Help/Font list" and remove quote signs)
font = "Helvetica:style=Bold";

/* [Hook] */

// Width of Hook
hook_width = 30;

// Height of Hook
hook_height = 80;

// Depth of Hook
hook_depth = 100;

// Height of Hook Fixure
hook_fixure_height = 60;

// Hook mounting type
hook_type = "separate"; // [separate:Separate, printable:Separate printable, unibody:Unibody]

/* [Tablet] */

// Height of tablet frame
tablet_frame_height = 5;

/* [Parts] */

// Box
display_box = true;

// Left Hook
display_hook_left = true;

// Right Hook
display_hook_right = true;

// Tablet
display_tablet = true;

/* [Hidden] */

// Functions

function sumup_left(vector, count, sum = 0) =
  count == 0
    ? sum
    : sumup_left(vector, count - 1, sum + vector[count - 1]);

function sumup_value_when_vector_not_null(vector, value, count, sum = 0) =
  count == 0
    ? sum
    : sumup_value_when_vector_not_null(vector, value, count - 1, sum + (vector[count - 1] == 0 ? 0 : value));

// Calculated values

box_width =
  sumup_left(remotes_widths, len(remotes_widths))
  + sumup_value_when_vector_not_null(remotes_widths, abs(wall_thickness), len(remotes_widths));

hook_mounting_height = abs(box_height) / 2 + abs(wall_thickness);

hook_total_height = abs(hook_height) + hook_mounting_height;

hook_separation_margin = 2 * abs(wall_thickness);

hook_separation_height =
  hook_total_height > hook_fixure_height
  ? hook_total_height
  : hook_fixure_height;

// Modules

module box(name, wall, width, depth, height, text_size, font) {
  translate([width / 2, 0, 0])
  difference() {
    cube([width + 2 * wall, depth + 2 * wall, height + 2 * wall], center = true);
    translate([0, 0, wall]) cube([width, depth, height + wall], center = true);
    translate([0, -depth / 2 -wall / 2, 0]) {
      rotate([90, 0, 0]) {
        linear_extrude(wall) {
          text(name, size = text_size, font = font, halign = "center", valign="center");
        }
      }
    }
  }
}

module hook(width, depth, height, fixure_height, mounting_height, wall) {
  rotate([90, 0, 90]) {
    linear_extrude(width) {
      polygon([
        [0, 0],
        [0, height + mounting_height + wall],
        [wall * 2 + depth, height + mounting_height + wall],
        [wall * 2 + depth, height + mounting_height - fixure_height],
        [wall + depth, height + mounting_height - fixure_height],
        [wall + depth, height + mounting_height],
        [wall, height + mounting_height],
        [wall, 0]
      ]);
    }
  }
  if (mounting_height > 0) {
    translate([0, - wall, mounting_height])
    cube([width, wall, wall]);
  }
}

module tablet(width, depth, wall, border_height) {
  difference() {
    cube([width, depth, wall + border_height]);
    translate([wall, wall, wall]) {
      cube([width - 2 * wall, depth - 2 * wall, border_height]);
    };
  };
}

// Macros

module hook_with_position(x = 0) {
  rotate([0, hook_type == "printable" ? -90 : 0, 0])
  translate([
    hook_type == "printable" ? - abs(box_height) / 2 - abs(wall_thickness) * 2 : 0,
    0,
    hook_type == "printable" ? - box_width : 0
  ])
  translate([
    hook_type == "printable" ? -x + abs(wall_thickness) : 0,
    hook_type == "printable" ? 2 * abs(wall_thickness) : 0,
    hook_type == "printable" && x > 0 ? hook_separation_height + hook_separation_margin : 0
  ])
  translate([
    x,
    abs(box_depth) / 2 + (hook_type == "unibody" ? 0 : abs(wall_thickness)),
    (hook_type == "unibody" ? hook_mounting_height : 0)
  ]) {
    hook(
      abs(hook_width),
      abs(hook_depth),
      abs(hook_height),
      abs(hook_fixure_height),
      hook_type == "unibody" ? 0 : hook_mounting_height,
      abs(wall_thickness)
    );
  }
}

// Main

if (display_box) {
  for(i = [0:len(remotes_widths) - 1]) {
    translate([
      sumup_left(remotes_widths, i) + sumup_value_when_vector_not_null(remotes_widths, abs(wall_thickness), i),
      0,
      0
    ]) {
      if (remotes_widths[i] > 0) {
        box(remotes_names[i], abs(wall_thickness), abs(remotes_widths[i]), abs(box_depth), abs(box_height), abs(text_size), font);
      }
    }
  }
}

if (display_hook_left) {
  hook_with_position(-abs(wall_thickness));
}

if (display_hook_right) {
  hook_with_position(box_width - abs(hook_width));
}

if (display_tablet) {
  translate([
    - abs(wall_thickness),
    abs(box_depth) * 0.5 + (hook_type == "unibody" ? 0 : abs(wall_thickness)),
    hook_type == "printable"
      ? - abs(box_height) * 0.5 - abs(wall_thickness)
      : abs(hook_height) + abs(hook_mounting_height) + abs(wall_thickness)
  ])
  translate([0, 0, hook_type == "unibody" ? - abs(wall_thickness) : 0])
  translate([0, hook_type == "printable" ? abs(hook_depth) + 5 * abs(wall_thickness) : 0, 0])
  tablet(
    abs(box_width) + abs(wall_thickness),
    abs(hook_depth) + 2 * abs(wall_thickness),
    abs(wall_thickness),
    abs(tablet_frame_height)
  );
}

```


[User]
Okay, I'd like to create a simple OpenSCAD model for quickly printing out circles of different diameters. I need it to be parametric, so I can easily change the diameter in the customizer. The main purpose is to help me visualize the size of different smartwatches on my wrist, but I want it to be versatile enough for other applications too.

The model should produce a flat, disc-like shape. I need to specify the diameter of the circle, let's call it `diameter`. I'd also like to add an option to generate just an outline instead of a solid circle. This is useful for larger circles, as it saves on filament and print time. If I select "outline only", then I should specify the `outline` width, which is the space between the two circles forming the outline.

When not creating only an outline, I would like to have the diameter in millimeters displayed in the center of the circle. The text should be readable and not too large, maybe something like `text_size`. I'll probably set a default for that. The final thing I need is to make sure the text is nicely centered.

I think I'll need a few variables in the customizer: `diameter`, `text_size`, `outline_only` (with options "yes" and "no"), and `outline`. The default for `outline_only` should be "no".

I don't need anything very complex, just those basic features. I don't think I need any libraries for that. Can you generate this for me?

[Assistant]
circle.scad:
```

/* [Basic] */

// Diameter
diameter = 42;

// Text Size
text_size = 10;

/* [Additional Options] */

// Generate Outline only
outline_only = "no"; // [no,yes]

// Outline size
outline = 2.5;

/* [Hidden] */
$fn = 60;

difference() {
  linear_extrude(0.6)circle(d = diameter);
  if (outline_only == "yes") {
    linear_extrude(0.6)circle(d = diameter - outline);
  } else {
    translate([0,0,0.4])linear_extrude(0.2)text(str(diameter), size = text_size, halign="center", valign="center");
  }
};

```


[User]
Hey, I'd like to generate a 3D model using OpenSCAD. I'm envisioning a grid of cubes, where each cube's color and height is determined by its position in the grid. The grid should be parameterized by `MaxX` and `MaxY`, which should default to 36 each, but allow me to change them.

The color for each cube should be calculated using `color( [0.5+sin(10*i)/2, 0.5+sin(10*j)/2, 0.5+sin(10*(i+j))/2] )`, where `i` and `j` represent the x and y position of the cube in the grid, starting from zero. The size of each cube should be 1x1x(11+10*cos(10*i)*sin(10*j)).

Could you write the necessary OpenSCAD code for this? I don't need any external libraries.

[Assistant]
customizer.scad:
```
// Max X
MaxX=36;

// Max Y
MaxY=36;

for(i=[0:MaxY]) {
    for(j=[0:MaxX]) {
        color( [0.5+sin(10*i)/2, 0.5+sin(10*j)/2, 0.5+sin(10*(i+j))/2] )
        translate( [i, j, 0] )
        cube( size = [1, 1, 11+10*cos(10*i)*sin(10*j)] );
    }
}
```


[User]
Hey, I'm looking for an OpenSCAD design for a customizable tray. I need to be able to control the overall size of the tray (length, width, and height), as well as the thickness of the floor, walls, and any internal dividers. I'd also like the option to inset the front of the tray, which is useful for when it sits in another container with a lid.

The tray should have configurable dividers going in two directions, creating a grid of compartments. I need to be able to set the position and length of each divider, expressed as a percentage of the tray's overall dimensions. It would also be nice to add text labels to the front of the tray for the columns, and to the side of the tray for the rows. These labels should be customizable, and it should be possible to rotate them 90 degrees.

I don't have specific code to give you, but I've attached the description of a design that includes the features I'm looking for. This is mostly for reference to make sure you know what I mean. I'd also like for the design to use the Liberation Sans font and include a variable to set the size and thickness of the labels. Let me know if you have any questions.

[Assistant]
Tray__118.scad:
```
/*
   ParamTray - Customizable Tray
   G. A. Tielke, August 2021

   Creates 3d-printable tray.
   The size and other settings are parameters
   that can be set by the user.

   This design was initially inspired by:
        Small stuff organizer - screws, nuts, fastener 1.4
        by Zvedak July 14, 2021
        https://www.thingiverse.com/thing:4908289

These were designed to fit the hinged storage box,
    see my "ParamBox" project. They can also be used separately.

Dividers can be in two directions:
 -Column "C" dividers:
   These add dividers going in the Y axis direction,
     creating seperate areas to the left & right of the divider.
   The starting percents are as a percentage of the entire tray length.
   They each have a length as a percentage of the entire tray width.
 -Row "R" dividers:
   These add dividers going in the X axis direction,
     creating seperate areas to the front & rear of the divider.
   The starting percents are as a percentage of the entire tray width.
   They each have a length as a percentage of the entire tray length.

Text labels can also be printed in two directions:
 -Column labels print across the front face of the tray,
   centered on each Column.
 -Row labels print across the right side of the tray,
   centered on each Row.
 -Labels can be printed horizontally or rotated 90 degrees vertically.

Because having "n" dividers creates "n+1" sections to the tray,
there can be one more Column labels than Column dividers.
Similarly there can be one more Row labels than Row dividers.

The front can be inset, which means the body of the tray
has a width that is smaller than the floor portion.
This helps trays fit in a hinged-top box.

*/

/* [Tray Size] */
// Length on x axis
tray_length = 60; //[0:1:220]
// Width on y axis
tray_width = 45; //[0:1:220]
// Height on z axis
tray_height = 10; //[0:1:250]

/* [Thickness and Inset] */
// Thickness of bottom surface
floor_thick = 1; //[0:1:10]
// Thickness of side walls
wall_thick = 1; //[0:1:10]
// Thickness of dividers
divider_thickness = 1; //[0:1:10]
// Inset on front side, or zero
front_inset = 0; //[0:1:50]

/* [Text font settings] */
// Text font size
lblsize = 4.1; //[0:0.1:10]
// Text thickness
lblthick = 0.8; //[0:0.1:3]
// Rotate Row text 90 degrees
R_lbl_rotate = true;
// Rotate Column text 90 degrees
C_lbl_rotate = true;

/* [Column Dividers - with labels on front face] */
// Offsets as percent of tray length
C_offset_pcts = [0,0,0,0,0,0,0,0,0];
// Starting Column offsets, as percent of tray width
C_start_pcts = [0,0,0,0,0,0,0,0,0];
// Column ending position, 100% for full width
C_end_pcts = [100,100,100,100,100,100,100,100,100];
// Labels in front of each Column:
C_labels = ["", "", "", "", "", "", "", "", "", "", ""];

/* [Row dividers - with labels on side face] */
// Offsets as percent of tray width
R_offset_pcts = [0,0,0,0,0,0,0,0,0];
// Row starting position, as percent of tray length
R_start_pcts = [0,0,0,0,0,0,0,0,0];
// Row ending position, 100% for full length
R_end_pcts = [100,100,100,100,100,100,100,100,100];
// Labels in front of each Row:
R_labels = ["", "", "", "", "", "", "", "", "", "", ""];

/* [Hidden] */

// Number of sections in x & y directions
X_Dividers = min([for (r=[8:-1:0]) (C_offset_pcts[r]==0) ? r : 9]);
Y_Dividers = min([for (r=[8:-1:0]) (R_offset_pcts[r]==0) ? r : 9]);

// Front inset cannot exceed half the tray width
FI = (front_inset > (tray_width/2)) ? tray_width/2 : front_inset;

//
// Create the tray body:
//
// Outside tray shape:
translate([0,FI,0]) {
    difference () {
        // Add the body of the tray:
        cube([tray_length,tray_width-FI,tray_height]);
        // Subtracting this:
        translate([wall_thick-.01,wall_thick-.01,floor_thick-.01]) {
            cube([tray_length-2*wall_thick+.015,tray_width-2*wall_thick+.015-FI,tray_height+.015]); }
    }
};
// Add the floor:
cube([tray_length,tray_width-FI,floor_thick]);

//
// Add dividers between sections:
//
// Add dividers in x direction:
if (X_Dividers > 0) {
    // Add each divider:
    for(i=[1:X_Dividers]) {
        // Calculate offset to left edge of divider:
        DOff=C_offset_pcts[i-1]/100.*tray_length;
        // Calculate the starting point for the divider:
        DStart=C_start_pcts[i-1]/100.;
        // Calculate the length of the divider:
        x1=C_end_pcts[i-1]/100.-DStart;
        DLen = (x1 < 0) ? 0 : x1;
        // Add this divider at the calculated offset:
        translate([DOff,FI+DStart*(tray_width-FI),0]) {
            cube([divider_thickness,
            DLen*(tray_width-FI),
            tray_height]);
        }
    }
}

// Add dividers in y direction:
if (Y_Dividers > 0) {
    for(i=[1:Y_Dividers]) {
        // Calculate offset to front edge of divider:
        DOff2=FI + R_offset_pcts[i-1]/100.*(tray_width-FI)
            -divider_thickness/2;

        // Calculate the starting point for the divider:
        DStart2=R_start_pcts[i-1]/100.;
        // Calculate the length of the divider:
        x2=R_end_pcts[i-1]/100.-DStart2;
        DLen2 = (x2 < 0) ? 0 : x2;

        // Add this divider at the calculated offset:
        translate([DStart2*(tray_length),DOff2,0]) {
            cube([DLen2*tray_length,divider_thickness,tray_height]);
        }
    }
}

//
// Add Text to front of the tray:
//
lblfont = "Liberation Sans";

if (wall_thick > 0) {

    // Prepare X-axis text parameter vector:
    rX= (R_lbl_rotate) ? 90 : 0;
    txtlistX =([for (i=[0:X_Dividers])
        [i+1, wall_thick + (
            ((i<1) ? 0 : C_offset_pcts[i-1])
            + ((i==X_Dividers) ? 100 : C_offset_pcts[i])
        )/200.*tray_length,
        C_labels[i]] ]);
    // Print text from parameter vector:
    for (tparam = txtlistX) {
        n = tparam[0];
        translate([tparam[1],.5+FI,tray_height/2])
            rotate([90,rX,0])
            linear_extrude(lblthick+.5)
            text(text = tparam[2], font = lblfont, size = lblsize,
                halign = "center", valign = "center");
    };

    //
    // Add Text to side of the tray:
    //
    // Prepare Y-axis text parameter vector:
    rY= (C_lbl_rotate) ? 90 : 0;
    txtlistY =([for (i=[0:Y_Dividers])
        [i+1, wall_thick + (
            ((i<1) ? 0 : R_offset_pcts[i-1])
            + ((i==Y_Dividers) ? 100 : R_offset_pcts[i])
        )/200.*(tray_width-FI),
        R_labels[i]] ]);
    // Print text from parameter vector:
    for (tparam = txtlistY) {
        n = tparam[0];
        translate([tray_length-.5,FI+tparam[1],tray_height/2])
            rotate([90,rY,90])
            linear_extrude(lblthick+.5)
            text(text = tparam[2], font = lblfont, size = lblsize,
                halign = "center", valign = "center");
    };

}

```


[User]
Hi, I'd like to design a customizable, hinged storage box for 3D printing using OpenSCAD. I'd like it to have parameters that control the overall size, wall thickness, and some other features, and I'm hoping you can help me write the code.

Here's what I'm thinking:

**Overall Box Dimensions:**
*   `box_length`: The length of the box along the x-axis.
*   `box_width`: The width of the box along the y-axis.
*   `box_height`: The overall height of the box along the z-axis.
*   `ht_diff`:  A difference in height between the top and bottom portions of the box. This allows for a lid that is not as deep as the container.
*   `floor_thick`: The thickness of the top and bottom panels.
*   `wall_thick`: The thickness of the side walls.
*   `fit_tol`:  Tolerance or spacing around moving parts like the hinges and the locking mechanism.

**Brim Features:**
*   `brim_ht`: The height of an optional brim added to the top and bottom edges.
*   `brim_width`: The width of the optional brim.
*   `roundradius`: Radius for rounding the corners of the box.
*   `do_seal_bevel`: A boolean to add or remove a sealing bevel to the top of the box sections.

**Vertical Support Features:**
*   `support_w`: Width of optional vertical support rectangles placed on the outside of the box.
*   `support_t`:  Thickness of the optional vertical support rectangles.

**Text Feature:**
*   `lbltext1`: Text to be printed on the front left panel.
*  `lbltext2`: Text to be printed on the front center panel.
*  `lbltext3`: Text to be printed on the front right panel.
*   `lblsize`: Font size of the text.

**Hinges:**
* The box should have two hinges, positioned along one of the long sides.
* These should be created using cylinders and clearances and work right off the printer without needing hardware.
* There will also be support structures for the hinge.

**Locking Mechanism:**
* The box will have a sliding hasp lock, with a cylinder sliding inside a hollow space.
* The hasp will have a little handle on the outside to move it.

**Additional Requirements:**

*   The box should be created in two main parts, a bottom container part, and a shorter lid.
*   Use rounded corners where appropriate.
*   The design should be easily printable, without needing supports or a raft.
*   The design should be parameterized, such that the user can specify the overall size of the box, the thickness of the walls and the top and bottom surfaces, the height difference between the top and bottom halves of the box, a tolerance amount for moving parts, and the brim and support rectange features.

I'm thinking that it will probably be useful to define modules like `roundedplate`, `createbox`, and `printtext` to create the basic shapes and handle text printing.

I don't have any libraries in mind, but maybe you know of a good library or two I could use? I'd like to keep the code as clean and easy to read as possible if that's okay. I'm hoping you can provide the full OpenSCAD code for this!

[Assistant]
ParamBox_034.scad:
```
/*
   ParamBox
   G. A. Tielke, August 2021

   Creates 3d-printable hinged 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 screen width here >>
*/

/* [Box Overall Size] */
// Length on x axis
box_length = 118; //[60:1:200]
// Width on y axis
box_width = 61; //[5:1:200]
// Height on z axis
box_height = 40; //[30:1:200]
// Difference between heights
ht_diff = 10; // [0:1:50]
// Thickness of bottom & top surfaces
floor_thick = 1; //[0:1:10]
// Thickness of side walls
wall_thick =1; //[1:1:10]
// Tolerance around moving parts:
fit_tol = 0.5; //[0.5:0.5:2.0]

/* [Brim on top and bottom edges] */
// Height of brim additions, 0 for none
brim_ht = 2; //[0:1:5]
// Thickness of brim additions, 0 for none
brim_width = 2; //[0:1:3]
// Radius for corner rounding
roundradius = 3; //[0:1:5]
// Add sealing bevel to top of box sections
do_seal_bevel = true;

/* [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] */

// Height difference cannot exceed half of total height:
    test = ht_diff > (box_height/2);
    // If test is true use box_heght/2, else use ht_diff
    ht_diff2 = test ? (box_height/2) : ht_diff;

delta = ht_diff2 / 2;
do_brim = (brim_ht > 0) && (brim_width > 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);

// Notes on "fit_tol": Space between fitted or moving parts. Several uses:
//  --Between top & bottom boxes so lid closes better (ignores values over 1.0)
//  --Hinge rotating parts
//  --Sliding lock parts
// 0.5 is tight but will work at low print speeds.
// Higher values may allow faster print speeds.

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(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.
    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) 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); }
    }
}

/*
  The overall box is created in two parts: the bottom box, and the top box.

  The top portion is shorter than the bottom box. This is handled
  by dividing the height in half and adding or subtracting "delta" units.

  Cylinders are added for the hinge portions, with part of the hinge attached
  to the top box and part attached to the bottom box.
  Clearance amounts are used to allow the free movement of the two halves
  of the hinge mechanism.

*/

// Create the bottom part of the box:
fit_tol2 = (fit_tol>1.0) ? fit_tol : 1.0;
difference() {
    translate([0,0,0]) {
        // Bottom part of the box:
        createbox(boxht=box_height/2 + delta - fit_tol2);

        for(n=[1:2]) { // Repeat, for left & right hinges:
            translate([box_length*n/3-5,box_width+(3.5/2)+1,box_height/2]) {

                //Add cylinder for rotating hinge (later hollowed out):
                rotate([0,90,0]) {color("red") cylinder(h=10,r=3.5,$fn=60);}

                // Add a bit of support to improve printing:
                translate([0,-3.5,-5])
                          rotate([-35,0,0]) color("green") cube([10,2.5,4]);
            }
        }
    }

    // Clear space for rotating parts:
    for(n=[1:2]) { // Repeat, for left & right hinges:
        // Subtract clearance for cylinders attached to top part of box:
        // Start at center of each hinge area:
        translate([box_length*n/3-5,box_width+3,box_height/2]) {
            // Move left or right to moving hinge area:
            translate([-10.25-fit_tol/2,0,0]) rotate([0,90,0]) {
                // Subtract cylindrical space:
                color("red") cylinder(h=10.25+fit_tol,r=3.5+fit_tol,$fn=60);}
            // Repeat for other side:
            translate([10-fit_tol/2,0,0]) rotate([0,90,0]) {
                color("red") cylinder(h=10.25+fit_tol,r=3.5+fit_tol,$fn=60);}
        }
        // Subtract out for rotating inside (hidden) hinge:
        translate([box_length*n/3-5.1,box_width+(3.5/2)+1,box_height/2])
            color("green") rotate([0,90,0]) {
                cylinder(h=10.5,r=(4.5/2)+fit_tol/2-.5,$fn=60);}
    };

    // 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+delta-2*brim_ht-.5]) {
        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)
        translate([wall_thick-1.25,
        wall_thick-1.25,
        box_height/2+delta-1.25 - fit_tol2]) color("gray")
            cube([box_length-2*wall_thick+2.5,box_width-2*wall_thick+2.5+.5,1.3]);

};

//
// Add lock mechanism to the bottom box:
//
// Starting just left of hasp opening
translate([box_length/2-hasp_width/2-.5-hasp_shift,
-4.5-support_t,                          // Move forward if supports are used
box_height/2+delta-2*brim_ht-.5]) {      // 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=2.5+fit_tol/2,$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("blue") translate([hasp_width+13,0,0]) rotate([0,0,0]) {
            cylinder(h=10,r=2.5,$fn=60);
            translate([0,0,10]) sphere(r=3.2,$fn=60);
        }

        // 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]);
        }
    }
};

// Create top part of the box:
difference() {
    translate([0,0,0]) {
        // Add sealing bevel on top:
        translate([0,box_width+3.5+2,0]) createbox(boxht=box_height/2 - delta);
        if (do_seal_bevel) difference() {
            translate([wall_thick-1,
            box_width+3.5+2+wall_thick-1,
            box_height/2-delta]) color("brown")
                cube([box_length-2*wall_thick+2,box_width-2*wall_thick+2,1]);
            translate([wall_thick,
            box_width+3.5+2+wall_thick,
            box_height/2-delta-.05])
                cube([box_length-2*wall_thick,box_width-2*wall_thick,1.1]);
        }
    }

    for(n=[1:2]) { // Repeat, for left & right hinges:
        // Subtract clearance for cylinders attached to bottom part of box:
        translate([box_length*n/3-5,box_width+3,box_height/2]) {
            translate([-.25,-.5,0])
                rotate([0,90,0])  cylinder(h=10.5,r=4,$fn=60);
        }
    }
}

// Add hinge parts to the top part of the box:
for(n=[1:2]) { // Repeat, for left & right hinges:
    // Start at center of each hinge:
    translate([box_length*n/3-5,box_width+(3.5/2)+1,box_height/2]) {

        // Moving Pin part of the hinge:
        translate([-2,0,0]) rotate([0,90,0]) {cylinder(h=14,r=(3.5/2),$fn=60);}

        // Add hinge and supports - Left & Right sides of this hinge:
        for(i=[0:1]) {// Repeat, for two sides of the current hinge:
            translate([10.25-i*20.5,0,0]) {
                difference () { translate([0,0,0]) {
                    rotate([0,90,0]) color("blue") {
                        cylinder(h=10,r=(3.5),$fn=60);};
                    // Add supports:
                    translate([0,-1.75,-(delta+5)])
                        color("green") cube([10,2.5,delta+3]);
                    translate([0,2.7,-(delta+11.5)])
                        rotate([35,0,0]) color("orange") cube([10,2.5,8]);
                    translate([0,2.7,-(delta+9.5)])
                        rotate([35,0,0]) color("orange") cube([10,2.5,8]);
                    translate([0,2.7,-(delta+7.5)])
                        rotate([35,0,0]) color("orange") cube([10,2.5,8]);

                    }
                    // Erase excess that may be in the inside area:
                    translate([-2,2.7+wall_thick,-box_height/2+floor_thick+0.1])
                        color("red") cube([15,10,box_height/2-delta]);
                }
            }
        }
    }
}

//
// Add lock hasp to the top part of the box:
//
translate([box_length/2-hasp_width/2-hasp_shift,
    box_width*2+3.5,
    box_height/2 - delta + 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]);
}

// Add Text to front of lower box:
// If supports are printed, use all three text strings:
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]
];

lblfont = "Liberation Sans";
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]);
};

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'd like to create a customizable label or sign with two lines of text. I have a basic idea of the parameters I'd like, but I need help generating the OpenSCAD code.

Here's what I envision:

*   **Basic Shape:** A rectangular plaque with rounded ends, similar to a stretched pill shape. It should have a flat top and bottom, and a consistent depth.
*   **Dimensions:** I need to be able to specify the width and height of the label in millimeters.
*   **Text:** The key feature is two lines of text. I should be able to set the text for each line independently. I also need to set the font, and font size.
*   **Font:** I want to use a font name that OpenSCAD will understand (for example from Google Fonts).
*   **Text Alignment:** The two lines of text should be centered horizontally and vertically positioned at the bottom and the top of the label respectively.
*   **Extrusion:** The text should be extruded to a height of 1.5 mm.

The final output should be easily customized to change text content, label size, and font. The code should be well-commented.

I would prefer the core functionality to be a module that can be called and parameterized.

Could you please provide the OpenSCAD code for this?

[Assistant]
label-2lines.scad:
```
// label.scad
// library for parametric Label, Tag, Sign, ID, Marker, Plaque
// Author: Tony Z. Tonchev, Michigan (USA)
// last update: November 2018
// Updated to have 2 lines by Amber, Aug 2021

Message = "First Line";
Message2 = "Second Line";

// (in mm)
Label_Width = 120;

// (in mm)
Label_Height = 50;

// Character Height (in mm)
Font_Size = 16;

/* [Font Details] */

// Platform specific font name (In Customizer: http://www.google.com/fonts)
Font_Name="Lucida Handwriting"; //[ABeeZee,Abel,Abril Fatface,Aclonica,Acme,Actor,Adamina,Advent Pro,Aguafina Script,Akronim,Aladin,Aldrich,Alef,Alegreya,Alegreya Sans,Alegreya Sans SC,Alegreya SC,Alex Brush,Alfa Slab One,Alice,Alike,Alike Angular,Allan,Allerta,Allerta Stencil,Allura,Almendra,Almendra Display,Almendra SC,Amarante,Amaranth,Amatic SC,Amethysta,Amiri,Anaheim,Andada,Andika,Angkor,Annie Use Your Telescope,Anonymous Pro,Antic,Antic Didone,Antic Slab,Anton,Arapey,Arbutus,Arbutus Slab,Architects Daughter,Archivo Black,Archivo Narrow,Arimo,Arizonia,Armata,Artifika,Arvo,Asap,Asset,Astloch,Asul,Atomic Age,Aubrey,Audiowide,Autour One,Average,Average Sans,Averia Gruesa Libre,Averia Libre,Averia Sans Libre,Averia Serif Libre,Bad Script,Balthazar,Bangers,Basic,Battambang,Baumans,Bayon,Belgrano,Belleza,BenchNine,Bentham,Berkshire Swash,Bevan,Bigelow Rules,Bigshot One,Bilbo,Bilbo Swash Caps,Bitter,Black Ops One,Bokor,Bonbon,Boogaloo,Bowlby One,Bowlby One SC,Brawler,Bree Serif,Bubblegum Sans,Bubbler One,Buda,Buenard,Butcherman,Butterfly Kids,Cabin,Cabin Condensed,Cabin Sketch,Caesar Dressing,Cagliostro,Calligraffitti,Cambay,Cambo,Candal,Cantarell,Cantata One,Cantora One,Capriola,Cardo,Carme,Carrois Gothic,Carrois Gothic SC,Carter One,Caudex,Cedarville Cursive,Ceviche One,Changa One,Chango,Chau Philomene One,Chela One,Chelsea Market,Chenla,Cherry Cream Soda,Cherry Swash,Chewy,Chicle,Chivo,Cinzel,Cinzel Decorative,Clicker Script,Coda,Coda Caption,Codystar,Combo,Comfortaa,Coming Soon,Concert One,Condiment,Content,Contrail One,Convergence,Cookie,Copse,Corben,Courgette,Cousine,Coustard,Covered By Your Grace,Crafty Girls,Creepster,Crete Round,Crimson Text,Croissant One,Crushed,Cuprum,Cutive,Cutive Mono,Damion,Dancing Script,Dangrek,Dawning of a New Day,Days One,Dekko,Delius,Delius Swash Caps,Delius Unicase,Della Respira,Denk One,Devonshire,Dhurjati,Didact Gothic,Diplomata,Diplomata SC,Domine,Donegal One,Doppio One,Dorsa,Dosis,Dr Sugiyama,Droid Sans,Droid Sans Mono,Droid Serif,Duru Sans,Dynalight,Eagle Lake,Eater,EB Garamond,Economica,Ek Mukta,Electrolize,Elsie,Elsie Swash Caps,Emblema One,Emilys Candy,Engagement,Englebert,Enriqueta,Erica One,Esteban,Euphoria Script,Ewert,Exo,Exo 2,Expletus Sans,Fanwood Text,Fascinate,Fascinate Inline,Faster One,Fasthand,Fauna One,Federant,Federo,Felipa,Fenix,Finger Paint,Fira Mono,Fira Sans,Fjalla One,Fjord One,Flamenco,Flavors,Fondamento,Fontdiner Swanky,Forum,Francois One,Freckle Face,Fredericka the Great,Fredoka One,Freehand,Fresca,Frijole,Fruktur,Fugaz One,Gabriela,Gafata,Galdeano,Galindo,Gentium Basic,Gentium Book Basic,Geo,Geostar,Geostar Fill,Germania One,GFS Didot,GFS Neohellenic,Gidugu,Gilda Display,Give You Glory,Glass Antiqua,Glegoo,Gloria Hallelujah,Goblin One,Gochi Hand,Gorditas,Goudy Bookletter 1911,Graduate,Grand Hotel,Gravitas One,Great Vibes,Griffy,Gruppo,Gudea,Gurajada,Habibi,Halant,Hammersmith One,Hanalei,Hanalei Fill,Handlee,Hanuman,Happy Monkey,Headland One,Henny Penny,Herr Von Muellerhoff,Hind,Holtwood One SC,Homemade Apple,Homenaje,Iceberg,Iceland,IM Fell Double Pica,IM Fell Double Pica SC,IM Fell DW Pica,IM Fell DW Pica SC,IM Fell English,IM Fell English SC,IM Fell French Canon,IM Fell French Canon SC,IM Fell Great Primer,IM Fell Great Primer SC,Imprima,Inconsolata,Inder,Indie Flower,Inika,Irish Grover,Istok Web,Italiana,Italianno,Jacques Francois,Jacques Francois Shadow,Jim Nightshade,Jockey One,Jolly Lodger,Josefin Sans,Josefin Slab,Joti One,Judson,Julee,Julius Sans One,Junge,Jura,Just Another Hand,Just Me Again Down Here,Kalam,Kameron,Kantumruy,Karla,Karma,Kaushan Script,Kavoon,Kdam Thmor,Keania One,Kelly Slab,Kenia,Khand,Khmer,Khula,Kite One,Knewave,Kotta One,Koulen,Kranky,Kreon,Kristi,Krona One,La Belle Aurore,Laila,Lakki Reddy,Lancelot,Lateef,Lato,League Script,Leckerli One,Ledger,Lekton,Lemon,Liberation Sans,Libre Baskerville,Life Savers,Lilita One,Lily Script One,Limelight,Linden Hill,Lobster,Lobster Two,Londrina Outline,Londrina Shadow,Londrina Sketch,Londrina Solid,Lora,Love Ya Like A Sister,Loved by the King,Lovers Quarrel,Luckiest Guy,Lusitana,Lustria,Macondo,Macondo Swash Caps,Magra,Maiden Orange,Mako,Mallanna,Mandali,Marcellus,Marcellus SC,Marck Script,Margarine,Marko One,Marmelad,Martel Sans,Marvel,Mate,Mate SC,Maven Pro,McLaren,Meddon,MedievalSharp,Medula One,Megrim,Meie Script,Merienda,Merienda One,Merriweather,Merriweather Sans,Metal,Metal Mania,Metamorphous,Metrophobic,Michroma,Milonga,Miltonian,Miltonian Tattoo,Miniver,Miss Fajardose,Modak,Modern Antiqua,Molengo,Molle,Monda,Monofett,Monoton,Monsieur La Doulaise,Montaga,Montez,Montserrat,Montserrat Alternates,Montserrat Subrayada,Moul,Moulpali,Mountains of Christmas,Mouse Memoirs,Mr Bedfort,Mr Dafoe,Mr De Haviland,Mrs Saint Delafield,Mrs Sheppards,Muli,Mystery Quest,Neucha,Neuton,New Rocker,News Cycle,Niconne,Nixie One,Nobile,Nokora,Norican,Nosifer,Nothing You Could Do,Noticia Text,Noto Sans,Noto Serif,Nova Cut,Nova Flat,Nova Mono,Nova Oval,Nova Round,Nova Script,Nova Slim,Nova Square,NTR,Numans,Nunito,Odor Mean Chey,Offside,Old Standard TT,Oldenburg,Oleo Script,Oleo Script Swash Caps,Open Sans,Open Sans Condensed,Oranienbaum,Orbitron,Oregano,Orienta,Original Surfer,Oswald,Over the Rainbow,Overlock,Overlock SC,Ovo,Oxygen,Oxygen Mono,Pacifico,Paprika,Parisienne,Passero One,Passion One,Pathway Gothic One,Patrick Hand,Patrick Hand SC,Patua One,Paytone One,Peddana,Peralta,Permanent Marker,Petit Formal Script,Petrona,Philosopher,Piedra,Pinyon Script,Pirata One,Plaster,Play,Playball,Playfair Display,Playfair Display SC,Podkova,Poiret One,Poller One,Poly,Pompiere,Pontano Sans,Port Lligat Sans,Port Lligat Slab,Prata,Preahvihear,Press Start 2P,Princess Sofia,Prociono,Prosto One,PT Mono,PT Sans,PT Sans Caption,PT Sans Narrow,PT Serif,PT Serif Caption,Puritan,Purple Purse,Quando,Quantico,Quattrocento,Quattrocento Sans,Questrial,Quicksand,Quintessential,Qwigley,Racing Sans One,Radley,Rajdhani,Raleway,Raleway Dots,Ramabhadra,Ramaraja,Rambla,Rammetto One,Ranchers,Rancho,Ranga,Rationale,Ravi Prakash,Redressed,Reenie Beanie,Revalia,Ribeye,Ribeye Marrow,Righteous,Risque,Roboto,Roboto Condensed,Roboto Slab,Rochester,Rock Salt,Rokkitt,Romanesco,Ropa Sans,Rosario,Rosarivo,Rouge Script,Rozha One,Rubik Mono One,Rubik One,Ruda,Rufina,Ruge Boogie,Ruluko,Rum Raisin,Ruslan Display,Russo One,Ruthie,Rye,Sacramento,Sail,Salsa,Sanchez,Sancreek,Sansita One,Sarina,Sarpanch,Satisfy,Scada,Scheherazade,Schoolbell,Seaweed Script,Sevillana,Seymour One,Shadows Into Light,Shadows Into Light Two,Shanti,Share,Share Tech,Share Tech Mono,Shojumaru,Short Stack,Siemreap,Sigmar One,Signika,Signika Negative,Simonetta,Sintony,Sirin Stencil,Six Caps,Skranji,Slabo 13px,Slabo 27px,Slackey,Smokum,Smythe,Sniglet,Snippet,Snowburst One,Sofadi One,Sofia,Sonsie One,Sorts Mill Goudy,Source Code Pro,Source Sans Pro,Source Serif Pro,Special Elite,Spicy Rice,Spinnaker,Spirax,Squada One,Sree Krushnadevaraya,Stalemate,Stalinist One,Stardos Stencil,Stint Ultra Condensed,Stint Ultra Expanded,Stoke,Strait,Sue Ellen Francisco,Sunshiney,Supermercado One,Suranna,Suravaram,Suwannaphum,Swanky and Moo Moo,Syncopate,Tangerine,Taprom,Tauri,Teko,Telex,Tenali Ramakrishna,Tenor Sans,Text Me One,The Girl Next Door,Tienne,Timmana,Tinos,Titan One,Titillium Web,Trade Winds,Trocchi,Trochut,Trykker,Tulpen One,Ubuntu,Ubuntu Condensed,Ubuntu Mono,Ultra,Uncial Antiqua,Underdog,Unica One,UnifrakturCook,UnifrakturMaguntia,Unkempt,Unlock,Unna,Vampiro One,Varela,Varela Round,Vast Shadow,Vesper Libre,Vibur,Vidaloka,Viga,Voces,Volkhov,Vollkorn,Voltaire,VT323,Waiting for the Sunrise,Wallpoet,Walter Turncoat,Warnes,Wellfleet,Wendy One,Wire One,Yanone Kaffeesatz,Yellowtail,Yeseva One,Yesteryear,Zeyada]

/* [Hidden] */

$fn=50;
TZT_Msg=Message;
TZT_Msg2=Message2;
TZT_Width=Label_Width;
TZT_Height=Label_Height;
TZT_Fnt=Font_Name;
TZT_Fsz=Font_Size;

TZT_PLATE ();
linear_extrude(height = 1.5) {
    text(TZT_Msg2,size=TZT_Fsz,font=TZT_Fnt,halign="center",valign="top");
}

linear_extrude(height = 1.5) {
    text(TZT_Msg,size=TZT_Fsz,font=TZT_Fnt,halign="center",valign="bottom");
}

// I did the same thing twice here. One line beeing "bottom" and the other line being "top", it seems to work, although counter-intuitively to what I expected. I still don't understand this code, so there might be a better way of adding a second line to the sign. -Amber

module TZT_PLATE () {
    difference () {
        union () {
            cube ([TZT_Width,TZT_Height,3],true);
            for (TZT_i=[-2:4:2]) {
                translate ([TZT_Width/TZT_i,0,0]) {
                    cylinder (3,TZT_Height/2,TZT_Height/2,true);
                }
                translate ([(TZT_Width+TZT_Height)/TZT_i,0,0]) {
                    cylinder (3,3,3,true);
                }
            }
        }
        translate ([0,0,1.5]) {
            union () {
                cube ([TZT_Width,TZT_Height-3,3],true);
                for (TZT_i=[-2:4:2]) {
                    translate ([TZT_Width/TZT_i,0,0]) {
                        cylinder (3,TZT_Height/2-1.5,TZT_Height/2-1.5,true);
                    }
                    translate ([(TZT_Width+TZT_Height+1)/TZT_i,0,0]) {
                        cylinder (10,1,1,true);
                    }
                }
            }
        }
    }
}

```


[User]
Okay, I'd like to create a parametric OpenSCAD design for printing text with a breakaway support bar. I'm envisioning something where the text is raised, connected to a thin bar by small struts, and then the bar can be snapped off after printing, leaving the text behind.

Here's a breakdown of what I need:

**Core Functionality:**

*   **Text Input:**  The design should take text as input. This text will be the 3D text printed.
*   **Font Selection:** I need to be able to specify the font, including the style (like bold, italic etc.). I'll need to use standard fonts that OpenSCAD supports, as listed under SCAD HELP and FONT LIST.
*   **Text Size:**  The font size should be adjustable.
*  **Text Extrusion:** The text should be extruded to a given height.

*   **Support Bar:** A horizontal bar should run underneath the text, serving as a temporary support. This bar needs to be:
    *   Adjustable in length
    *   Adjustable in height above the print surface
    *   Adjustable in thickness (top to bottom)
*   **String Connectors:** Thin connectors should link the text to the support bar. These should be:
    *   Adjustable in length (from the bar to the letter)
    *   Adjustable in thickness
    *   Adjustable in height above the print surface
    *   Have a thin "bridge" connecting to the font, with its own adjustable height above the print surface
    *   The "bridge" should also have an angled cut at the end where it connects to the text, to allow for easy breaking.
    *   The length of the bridge should be adjustable
*   **String Offsets:**  I need to specify the horizontal positions (offsets from the left of the bar) where the string connectors attach to the bar.  I need to be able to add these as a comma-separated list, enclosed by square brackets like `[8, 11, 22]`.
 *   **Low Line Connectors:** I need a second set of string connectors that are lower to hit the bottoms of letters like p,q,y.  The length from the bar to the letter should be adjustable.  The vertical position of these string connectors should be adjustable as an offset from the bar. I also need a list of offsets for these, separate from the main string offsets. The offset list should work the same way as the main string offsets.

*   **Offset Adjustment:** When the bar length is adjusted, all the string connector positions move relative to the bar length, but I want to keep their absolute position as close as possible to where they were initially. I need a parameter to offset the string connector positions by some fraction of the change in the bar length to achieve this. This will prevent the need to re-enter all the string offsets when adjusting the bar length.

**Optional Features:**

*   **STL Import:** Optionally, I should be able to import an STL file as a sizing reference. I'll need to provide the file path. The import position needs to be adjustable so that I can position the STL reference relative to the text I am printing.
*   **Pre-made Shape:** I would like to include an option to print a specific shape, in this case an arrow with the text "Fix It" inside it. The arrow should be customizable in size.

**Important Notes:**

*   The design should be parametric so all the dimensions can be modified.
*   The program needs to allow for a good sampling/quality of the curves of the letters.
*   The string connectors should have minimal contact with the letters to make the break away easy.
*   I'd like the ability to easily adjust the spacing of the connectors so that they touch the correct part of each letter.

I don't need any specific libraries, just the base OpenSCAD functions.

Could you generate the necessary OpenSCAD files for this design? Let me know if you have any questions.

[Assistant]
Build_Text_on_a_Break-Away-Bar.scad:
```
//Build text on a breakaway bar / text card / 3D text string / glue on 3D text/ 3D text with Guides guide
// This will allow you to print Raised text and keep it properly aligned and spaced while you glue it down.
// After you glue it down use a sharp knife to separate the guide bar.

//Printing Notes:
// NO SUPPORTS NEEDED.
// The program does a lot but you need to enter the offset of the supports
// Prints one line at a time
// I removed the double line option. Fonts behave differently.  The double line option requirements may confuse users.
// with new option of string_distance_to_low_font, when in use it and string_dist_to_font may both need adjusting when the other is changed.

// Before you start customzing offsets
// Set your bar length
// Set your font size
// set your string_dist_to_font
// set your bar_adjust_Closer
// Do your offsets

// I will explain how to use this in a video.  The video is longer than it will take you to adjust.  I send time showing you how to use the options.

//===================== Author ====================
//Initial version created by  AlwaysTinkering V1.0 7/2021  https://www.youtube.com/channel/UC27SvMnOzIKx8oxlgZc5AEQ   https://www.thingiverse.com/alwaystinkering/designs https://www.prusaprinters.org/social/116733-alwaystinkering/prints
//================== Version 1.2 ==================
// v1.1 moved some bar controls into customizer that were in the main code only.
// v1.2 Added low_line_offsets to have minimal contact points with low letter bottoms
// =========== How to run this code ================
// This is an openscad file.  The program is open source and available at https://www.openscad.org/downloads.html
// Press F5 to refresh.  View and uncheck "Hide Customizer" to see customizer input screen.
// OpensCAD program F6 to generate/render and then STL export
// Slice your STL in your slicer and print

//////////////// START of Parameters, Customizer Compliant //////////////

// sampling / quality of curves the higher the number the longer rendering times
$fn=90;

// what do you want to print
what_to_print = "single_line";  //[single_line, arrow]

//Enter text to use in Single Line or First of Double Line
text_first_line = "COMPLAINT BUTTON";

//font size used for first line and SINGLE line
first_line_font_size = 13;

//font to use.  See fonts under SCAD HELP and FONT LIST.  I usually insert from that list and then copy what I want.
font_name_to_use = "Century Gothic:style=Bold";

//Length of the Bar. Should be longer than font and shorter than your bed.  You can always cut it down.
bar_length = 174;

//If you already setup your text connectors and then after you change the bar_length... all your positions will shift by 50% of your length delta in length.  This will allow you to adjust it back w/o having to retype the numbers.
offset_adjustment = .50;

//height of the bar... height off the print surface
bar_height = .8;

//bar thickness... the bar thickness top to bottom as the letters go.
bar_thick = 1.5;

//Not all font letters end at the same spot, this will adjust your string closer to so you can touch all the letters
bar_adjust_Closer = .65;

//Height of the font you are printing
font_extrude_thickness =  1.2;

//height of the attach sring... height off the print surface
string_hgt = .8;

//The thickness of final jump (bridge) connecting to the font, we want at least one or two print layers after the angel cut.   String_hgt - this will be the distance of the jump off the plate.
string_jump_conn_hgt = .5;

//string thickness
string_thick = .8;

//total length of piece going from bar to font
string_dist_to_font = 2.8;

//this is the length of the thin end that will jump to the font
string_jump_length = 1.5;

//FIX IT Arrow Font size .. for my initial project
arrow_font_size = 9.5;

// If you need to import an STL to size your font
import_sizing_stl = "no"; //[yes, no]

// Full path to Sizing STL to import
stl_file_to_import = "G:/Toys_Puzzles/DominoTrain/ew_nose.3mf";

//Offsets for connectors from left.  Separate by comma. Must start with [ and end with ]
first_line_offsets = [8,11,22,25,32,45, 48.5, 50, 59, 63, 66 , 76, 79 , 80.1 ,85, 92, 98.2, 100, 110, 113, 122,  125, 132.0, 133.5, 139.5, 140.9, 149.5, 153, 161,169];

//This the distance from the Bar to the bottom of low letters like P, q, y
string_distance_to_LOW_font = 1.5;

//This is the offsets for LOW lines to hit the bottom of letters like P, q, y  Separate by comma. Must start with [ and end with ]. [] is None.
low_line_offsets = [ ];

/* [Hidden] */
// ============= END OF INPUT VARIABLES ================

//if (what_to_print== "double_line") Double_Line();

if (what_to_print== "single_line") {

    Single_Line();

    }//if

if (what_to_print== "arrow") fixit();

//This module will print a Single Line
module Single_Line(){

    if (import_sizing_stl == "yes"){
        translate([0,10,-23])
        rotate([00,-90,0])
        import(stl_file_to_import);
    }

     linear_extrude( font_extrude_thickness )
     text(str(text_first_line, "" )  ,size= first_line_font_size ,font=font_name_to_use, halign="center",valign="center");

     translate([0, -first_line_font_size/2 -string_dist_to_font,0])
    {
        setline();

            // ========== DEFINE SINGLE LINE CONNECTORS OFFSETS HERE =============
        for (offset = first_line_offsets )
            // ========== DEFINE SINGLE LINE CONNECTORS OFFSETS HERE =============

         addconnect(offset, (string_dist_to_font  - string_jump_length )/2, string_dist_to_font );

       // translate([0, -first_line_font_size + string_distance_to_LOW_font ,0])
        {
           // ========== DEFINE SINGLE LOW LINE CONNECTORS OFFSETS HERE =============
        for (offset = low_line_offsets )
            // ========== DEFINE SINGLE LOW LINE CONNECTORS OFFSETS HERE =============
            addconnect(offset, max((string_distance_to_LOW_font  - string_jump_length )/2, 0) , string_distance_to_LOW_font );

        }
    } //trans

} //mod

//Sets the BAR once under the text
module setline( line_vert_offset = 0 ){
    // The bar is pushed Y fron center on X to above X and then up by the closer value, this was to support linear movement with distance to font changes..
     translate([line_vert_offset , -bar_thick/2 +bar_adjust_Closer , bar_height /2])
     cube([  bar_length ,  bar_thick , bar_height ], center = true);

} //mod

 //adds the connection from the Text Line to the Letter
//Somewhat universal as you specify the offset on your line vertical offset
 module addconnect(con_offset, line_vert_offset, this_string_dist_to_font ){

    translate([ -bar_length/2 + string_thick /2 + con_offset + offset_adjustment, line_vert_offset + bar_adjust_Closer , string_hgt /2])

    //notch the jump to the text
  {
     difference(){
         union(){ //bridge and string
       // the main connection box... it cannot be 0, but should not grow until > jump length
        translate([-string_thick/2, 0, 0  ])
        cube([  string_thick , max(this_string_dist_to_font  - string_jump_length, .1 ) , string_hgt ], center = true);

    // the bridge
         translate([ -string_thick/2 , this_string_dist_to_font/2 , (string_hgt-string_jump_conn_hgt)/2  ])
       cube([  string_thick  ,  string_jump_length ,string_jump_conn_hgt  ], center = true);
         } //un

    //cut diagonal so support breaks off easier
        translate([-string_thick/2  , this_string_dist_to_font/2  , string_hgt  - string_jump_conn_hgt + string_jump_conn_hgt * .8])
         rotate([-30,0,0])
         cube([  string_thick +.1, string_thick * 7.3, string_hgt ], center = true);

    } //diff

    } //trans

} //module

 //adds the connection from the Text Line to the Letter
//Somewhat universal as you specify the offset on your line vertical offset
 module addconnect_fixed(con_offset, line_vert_offset ){

    translate([ -bar_length/2 + string_thick /2 + con_offset + offset_adjustment, line_vert_offset + bar_adjust_Closer , string_hgt /2])

    //notch the jump to the text
  {
     difference(){
         union(){ //bridge and string
       // the main connection box
        translate([-string_thick/2, 0, 0  ])
        cube([  string_thick , string_dist_to_font  - string_jump_length, string_hgt ], center = true);

    // the bridge
         translate([ -string_thick/2 , string_dist_to_font/2 , (string_hgt-string_jump_conn_hgt)/2  ])
       cube([  string_thick  ,  string_jump_length ,string_jump_conn_hgt  ], center = true);
         } //un

    //cut diagonal so support breaks off easier
        translate([-string_thick/2  , string_dist_to_font/2  , string_hgt  - string_jump_conn_hgt + string_jump_conn_hgt * .8])
         rotate([-30,0,0])
         cube([  string_thick +.1, string_thick * 7.3, string_hgt ], center = true);

    } //diff

    } //trans

} //module

//Arrow with FIXIT in the text
module fixit(){

    translate([0,200,0])
    {

    translate([20,0,0])
    {
    rotate([0,0,180])
    scale([.65,1,1])
    cylinder( h=.8, d=39, center=true, $fn=3);
    translate([16,0,0])
    cube([22, 18, .8], center=true) ;
    }

    translate([22,0,00])
    rotate([00,0,90])
    linear_extrude( font_extrude_thickness )
    text(str("Fix", "" )  ,size= arrow_font_size, "Century Gothic:style=Bold", halign="center",valign="center");

     translate([34,0,000])
    rotate([00,0,90])
    linear_extrude( font_extrude_thickness )
    text(str("It!", "" )  ,size= arrow_font_size,"Century Gothic:style=Bold", halign="center",valign="center");

      }

} //mod fix it

```


[User]
Okay, I'm looking to create a highly customizable temperature tower for 3D printing, and I want to be able to control various test elements independently. I'd like it to be parametric, of course, so I can easily adjust it for different filaments and printer setups.

Here's what I need:

**Core Structure:**

*   A tower composed of multiple levels. The number of levels, `Levels`, should be a parameter.
*   Each level should have a defined depth, `levelDepth`, and height, `levelHeight`, both of which are parameters.
*   There should be a starting temperature, `startTemp`, and a temperature increment per level, `tempIncrement`.  A `tempOrder` parameter should allow the user to choose if the temperature should ascend or descend through the tower.
*   The base of the tower needs to be customizable with `baseType` parameter, allowing the choice of none, rounded, or basic (square). A parameter `baseMargin` to add a margin around the base would be useful.
*   For rendering quality, I'd like a `Detail` parameter to control the number of facets in rounded objects.
*   I will need a `Font` parameter to control which font is used.

**Temperature Display:**

*   A temperature indicator on each level using text. This element should be controlled by an `enableTemperature` parameter.
*   A `temperatureWidth` parameter will control the width of the temperature display. The text size should scale automatically based on the width and height of the level so it is always readable.

**Bridging Test:**

*   A bridge test component on each level, enabled by a `enableBridge` parameter.
*   The bridge test should have adjustable `bridgeDistance` and `bridgeThickness` parameters, and `bridgeSupportWidth` parameter.

**Stringing Test:**

*   A stringing test using cones, enabled by a `enableStringing` parameter.
*   The stringing cones should have a `coneStartRadius`, `coneEndRadius`, and `coneAmmount` parameters and a `stringingSupportWidth` parameter.

**Overhang Test:**

*   An overhang test with adjustable angle and distance, controlled by a `enableOverhang` parameter.
*   The overhang test needs an `overhangAngle`, `overhangDistance`, `overhangSteps`, and `overhangShelfThickness` parameters, and an `overhangSupportWidth` parameter.

**Additional Notes:**

*   I'd like to be able to enable or disable each of the test elements independently, and their position on each level should be based on the previous components that are enabled, and the `baseMargin`.
*   It's important that the code handles the case where the overhang height is more than a level's height by adjusting the overhang appropriately and moving it up to the correct height.
*   I don't need any specific libraries for this.
*   There should be a comment stating that some of the `Experimental` variables such as `baseHeight` and the supports haven't been fully implemented and changing them might break the tower.
*   The code should take care to make sure the supports for the test elements don't interfere with the text component.

Essentially, I'm looking for a flexible temperature tower generator that I can use to test different aspects of 3D printing based on different materials. Can you create an OpenSCAD file (or files) that handles all of this? Let me know if you need clarification.

[Assistant]
Customizable_Temperature_Tower.scad:
```
/* [Basic] */
// Number Of Levels
Levels = 10;
// Temperature Increment Per block
tempIncrement = 5;
// Starting Temperature
startTemp = 225;
// Temperature Ascending Or Descending
tempOrder = -1; // [-1:Descending, 1:Ascending]
//Type Of Base On the Tower
baseType = 1; // [0:None, 1:Rounded, 2:Basic]
// Depth Of Each Layer (Values Less Than coneStartRadius Or 4 May Cause Issues)
levelDepth = 10;
// Height Of Each Layer (Values Less Than 3 Or More Than 25 May Cause Isues)
levelHeight = 10;

/* [ Temperature Block ] */
enableTemperature = 1; // [0, 1]
//Width Of The Temperature Component (Larger Width Allows For Bigger Text - Scales Automatically)
temperatureWidth = 10;
/* [ Bridging Test ] */
enableBridge = 1; // [0, 1]
// Distance Of Bridge
bridgeDistance = 40;
// Thickness Of Bridge
bridgeThickness = 2;
/* [ Stringing Test] */
enableStringing = 1; // [0, 1]
// Stringing Cone Start Radius
coneStartRadius = 3;
//Stringing Cone End Radius
coneEndRadius = 0;
// Number Of Stringing Cones
coneAmmount = 2;
/* [ Overhang Test ] */
enableOverhang = 1; // [0, 1]
// Max Overhang Angle
overhangAngle = 90; // [1:90]
// Total Distance Of Overhang
overhangDistance = 10;
// Number Of Angle Steps In Overhang
overhangSteps = 10;
// Thickness Of The Top Of The Overhang
overhangShelfThickness = 0.5;

/* [Advanced] */
// Detail Of Round Components (High Values Effect Render Time Significantly)
Detail = 20;
// Extra Margin around the base
baseMargin = 10;
// Font
Font = "Liberation Sans:bold";

$fn = Detail;
/* [Experimental] */
//Support For These Variables Haven't Properly Been Added So Changing Values Too Much Could Break Things
NOTE = "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^";

baseHeight = 1;
bridgeSupportWidth = 8;

stringingSupportWidth = 8;
overhangSupportWidth = 8;

//Create Empty Module To Stop Below Variables From Being Shown In The Customizer
module __Customizer_Limit__ () {}

stringingWidth = coneStartRadius*coneAmmount*2;
baseDepth = levelDepth+baseMargin;

module tower()
{
    // Create The Base And Pass In The Width Based Of Which Modules Are Enabled And How Large Each One Is
    base((temperatureWidth*enableTemperature)+(bridgeDistance*enableBridge+bridgeSupportWidth)+(enableStringing*(stringingWidth+stringingSupportWidth))+(enableOverhang*(overhangSupportWidth/2+overhangDistance))+baseMargin);

    // Itterate Through Each Level And Create Enabled Blocks
    for (x = [0:Levels-1])
    {
        // Create Temperature Block If Enabled
        if (enableTemperature == 1)
        {
             translate([baseMargin/2, baseMargin/2, x*levelHeight+1])
            {
            temperature(x, startTemp+(x*(tempIncrement*tempOrder)));
            }
        }

        // Create Bridge Test If Enabled
        if (enableBridge == 1)
        {
            translate([(enableTemperature*temperatureWidth)+baseMargin/2, baseMargin/2, x*levelHeight+1])
            {
                bridge();
            }
        }

        // Create Stringing Test If Enabled
        if (enableStringing == 1)
        {
            translate([(enableTemperature*temperatureWidth)+(enableBridge*(bridgeDistance+bridgeSupportWidth))+baseMargin/2, baseMargin/2, x*levelHeight+1])
            {
                stringing();
            }
        }

        // Create Overhang Test If Enabled
        if (enableOverhang == 1)
        {
            translate([(enableTemperature*temperatureWidth)+(enableBridge*(bridgeDistance+bridgeSupportWidth))+(enableStringing*(stringingSupportWidth+coneStartRadius*coneAmmount*2))+baseMargin/2, baseMargin/2, x*levelHeight+1])
            {
                overhang();
            }
        }
    }
}

//Module For Creating The Overhang Test
module overhang()
{
    //Add Support Tower For Attaching The Component
    translate([0, 0, 1]) cube([stringingSupportWidth/2,levelDepth,levelHeight-1]);
    translate([1, 1, 0]) cube([stringingSupportWidth/2-1,levelDepth-2,1]);

    translate([0, 0, 0])
    {
        //Use Triganometry To Calculate How Long And High Each Overhang Test Needs To Be
        a = 180-90-overhangAngle;
        b = overhangDistance*sin(a)/sin(90);
        dist = overhangDistance-b; //Distance Of Overhang

        height = overhangDistance*sin(overhangAngle)/sin(90); //Height Of Overhang

        // If The Height Of The OverHang Is Less Than The Height Of Each Level
        if (height <= levelHeight)
        {
            difference()
            {
                translate([overhangSupportWidth/2, 0, 0])
                {
                    cube([dist-0.01, levelDepth, height]);
                }

                translate([overhangSupportWidth/2+overhangDistance, levelDepth+1, -overhangShelfThickness])
                {
                        //Create A 2D Sqaure The Length Of The Overhang And Rotate Extrude It To overhangAngle Setting $fn To Equal overhangSteps Multiplied By The Ammount Of OverhangAngles Needed To Make A Full 360 Degrees
                    rotate([90, -(90+(90-overhangAngle)), 0]) rotate_extrude(angle = overhangAngle, $fn = overhangSteps*(360/overhangAngle)) square([overhangDistance, levelDepth+2]);
                }
            }
        }
        else // If The Height Of The OverHang Is More Than The Height Of Each Level, Cut The Bottom Of The OverHang Block Off To Match The Height Of The Layer And Move It Up To Match The Height Of The Layer
        {
            translate([0, 0, -(height-levelHeight)])
            {
                difference()
                {
                    translate([overhangSupportWidth/2, 0, 0])
                    {
                        cube([dist-0.01, levelDepth, height]);
                    }

                    translate([overhangSupportWidth/2+overhangDistance, levelDepth+1, 0])
                    {

                        //Create A 2D Sqaure The Length Of The Overhang And Rotate Extrude It To overhangAngle Setting $fn To Equal overhangSteps Multiplied By The Ammount Of OverhangAngles Needed To Make A Full 360 Degrees
                        rotate([90, -(90+(90-overhangAngle)), 0]) rotate_extrude(angle = overhangAngle, $fn = overhangSteps*(360/overhangAngle)) square([overhangDistance, levelDepth+2]);
                    }
                    translate([overhangSupportWidth/2-1, -1, -1]) cube([dist+1, levelDepth+2, height-levelHeight]);
                }
            }
        }
    }

}

//Module For Creating The Stringing Test
module stringing()
{
    //Add Support Tower For Attaching The Component
    translate([0, 0, 1]) cube([stringingSupportWidth/2,levelDepth,levelHeight-1]);
    translate([1, 1, 0]) cube([stringingSupportWidth/2-1,levelDepth-2,1]);

    translate([stringingWidth+stringingSupportWidth/2, 0, 0])
    {
        translate([0, 0, 1]) cube([stringingSupportWidth/2,levelDepth,levelHeight-1]);
        translate([0, 1, 0]) cube([stringingSupportWidth/2-1,levelDepth-2,1]);
    }

    translate([stringingSupportWidth/2, 1, 0]) cube([stringingWidth, levelDepth-2, levelHeight/8]);

    //Create coneAmmount Number Of Cones And Space Them So Base Of The Cones Touch Each Other
    for (n = [1:coneAmmount])
    {
        translate([coneStartRadius*2*n-coneStartRadius+stringingSupportWidth/2, levelDepth/2, 0]) cylinder(levelHeight-levelHeight/8, coneStartRadius, coneEndRadius);
    }
}

//Module For Creating The Bridging Test
module bridge()
{
    //Add Support Tower For Attaching The Component
    translate([0, 0, 1]) cube([bridgeSupportWidth/2,levelDepth,levelHeight-1]);
    translate([0, 1, 0]) cube([bridgeSupportWidth/2,levelDepth-2,1]);

    translate([bridgeDistance+bridgeSupportWidth/2, 0, 0])
    {
        translate([0, 0, 1]) cube([4,levelDepth,levelHeight-1]);
        translate([0, 1, 0]) cube([bridgeSupportWidth/2,levelDepth-2,1]);
    }

    translate([bridgeSupportWidth/2, 1, (levelHeight/2)-(bridgeThickness)/2]) cube([bridgeDistance, levelDepth-2, bridgeThickness]);

    difference()
    {
        translate([bridgeSupportWidth/2, 1, levelHeight/2])
        {
            rotate([-90, 0, 0]) cylinder(levelDepth-2, levelHeight/1.5, levelHeight/1.5, $fn = 3);
        }
        //Remove The Top Half Of The Triangles From The Champhered Supports So That The Top Of The Bridges Are Flat
        translate([-levelHeight/2, 0, levelHeight/2]) cube([bridgeDistance+bridgeSupportWidth+levelHeight, levelDepth, levelHeight]);
        //Remove The Tips Of The Triangles From The Bottom Of The Champhered Supports That Protrude Below The Layer
        translate([-levelHeight/2, 0, -levelHeight+1]) cube([bridgeDistance+bridgeSupportWidth+levelHeight, levelDepth, levelHeight]);
    }

    difference()
    {
        translate([bridgeDistance+bridgeSupportWidth/2, 1, levelHeight/2])
        {
            rotate([-90, 180, 0]) cylinder(levelDepth-2, levelHeight/1.5, levelHeight/1.5, $fn = 3);
        }
        //Remove The Top Half Of The Triangles From The Champhered Supports So That The Top Of The Bridges Are Flat
        translate([-levelHeight/2, 0, levelHeight/2]) cube([bridgeDistance+bridgeSupportWidth+levelHeight, levelDepth, levelHeight]);
        //Remove The Tips Of The Triangles From The Bottom Of The Champhered Supports That Protrude Below The Layer
        translate([-levelHeight/2, 0, -levelHeight+1]) cube([bridgeDistance+bridgeSupportWidth+levelHeight, levelDepth, levelHeight]);
    }
}

//Module For Creating The Temperature Block
module temperature(x, temp)
{
    difference()
    {
        translate([0, 0, 1]) cube([temperatureWidth, levelDepth, levelHeight-1]);

        translate([0.5, 0.5, 1.5])
        {
            // Check If The Width Of The Temperature Block Will Be The Limiting Factor For Temperature
            if (temperatureWidth/2.5 <= levelHeight/2)
            {
                //Create, Scale And Extrude The Text Into The Block
                rotate([90, 0, 0]) linear_extrude(2) text(str(temp), font = Font, size=temperatureWidth/2.5);
            }
            // If The Height Of The Temperature Block Will Be The Limiting Factor For Temperature
            else
            {
                //Create, Scale And Extrude The Text Into The Block
                rotate([90, 0, 0]) linear_extrude(2) text(str(temp), font = Font, size=levelHeight/2);
            }
        }
    }
        translate([1, 1, 0]) cube([temperatureWidth-2, levelDepth-2, levelHeight-1]);
}

//Module For Creating The Base
module base(width)
{
    //If baseType = 0 Don't Create Any Base

    //Create Rounded Base
    if (baseType == 1)
    {
        translate([width/2, baseDepth/2, baseHeight/2])
        {
            rounded_rectangle(width, baseDepth, baseHeight, 5);
        }
    }
    //Create Square Base
    else if (baseType == 2)
    {
        cube([width, baseDepth, 1]);
    }
}

//Module For Creating Rounded Rectangles
// Created By papachristoumarios - https://www.thingiverse.com/thing:213733
// Licensed under theGNU - GPLlicense.
module rounded_rectangle(x,y,z,roundness) {
    intersection() {
        semi_rounded_rectangle(x,y,z,roundness);
        mirror([1,0,0]) semi_rounded_rectangle(x,y,z,roundness);

    }
}

// Module For Creating Rounded Rectangles
// Created By papachristoumarios - https://www.thingiverse.com/thing:213733
// Licensed under theGNU - GPLlicense.
module semi_rounded_rectangle(x,y,z,roundness) {

    difference() {
        cube([x,y,z],center=true);
        translate([-x/2,-y/2,0]) rounded_edge(roundness,z+1);
        rotate([0,0,-180]) translate([-x/2,-y/2,0]) rounded_edge(roundness,z+1);
        rotate([0,0,90]) translate([x/2,y/2,0]) rounded_edge(roundness,z+1);

    }
}

// Module For Creating Rounded Edges
// Created By papachristoumarios - https://www.thingiverse.com/thing:213733
// Licensed under theGNU - GPLlicense.
module rounded_edge(r, h) {
    translate([r / 2, r / 2, 0])

        difference() {

				cube([r + 0.01, r + 0.01, h], center = true);

            translate([r/2, r/2, 0])
                cylinder(r = r, h = h + 1, center = true);
        }
}

//Create Tower
tower();
```


[User]
Hey there, I'm looking for a parametric OpenSCAD design for a simple, rounded rectangular nametag. I want to be able to easily adjust the overall size, the thickness, the corner radius, and the text on the tag.

Specifically, the nametag should have a rounded rectangular shape with a thickness, created with a `hull` of cylinders. I'd like to have a small hole at one of the corners for attaching it to something, which should be made with a `cylinder` subtracted from the main body. The text should be centered on the tag, and raised a small amount (like, say, 1 mm or less) above the surface. I'd like to be able to specify the text, the text size, and the font.

I'd like the following parameters to be configurable: `width`, `height`, `thickness`, `corner_radius`, `hole_diameter`, `hole_offset_x`, `hole_offset_y`, `text`, `text_size`, and `text_font`.

Could you generate the necessary OpenSCAD files for this, please? I think it should be doable with just one file. I don't need any special libraries beyond the built-in OpenSCAD functions.

[Assistant]
Nametag.scad:
```
module roundedcube(xdim ,ydim ,zdim,rdim){
    hull(){
        translate([rdim,rdim,0])cylinder(h=zdim,r=rdim);
        translate([xdim-rdim,rdim,0])cylinder(h=zdim,r=rdim);

        translate([rdim,ydim-rdim,0])cylinder(h=zdim,r=rdim);
        translate([xdim-rdim,ydim-rdim,0])cylinder(h=zdim,r=rdim);
    }
}

$fn=50;
width=80;
height=40;
thickness=2;
text="Name";
text_size=20;
difference(){
    roundedcube(width,height,thickness,5);
    translate([5,height-5,0])
        cylinder(d=5,h=thickness);
}
translate([width/2,height/2,thickness])
color("Blue")
    linear_extrude(1)
        text(text, size=text_size, halign="center", valign="center");

```


[User]
Hi, I'm trying to design some steel structures using OpenSCAD and I need help creating a parametric library. I've already got a library that uses DXF files for the cross-sections, but I'd prefer a library with profiles defined directly in SCAD for more flexibility and control.

I'm looking to build a library for commonly used steel profiles, like RHS (Rectangular Hollow Section), SHS (Square Hollow Section), and PFC (Parallel Flange Channel). I also need to be able to create angles (like Equal Angle and Unequal Angle). I want each profile to be a module where I can specify the length as a parameter, for example `RHS(length=100)`.

I'd like the library to be modular, allowing for future expansion and addition of more complex profiles. I would like to use `linear_extrude()` for the basic profiles like RHS and SHS to define their lengths.

Also, I need functionality to create curved steel sections as well. I would like to be able to specify a bend radius and bend angle, essentially creating an arc segment from any profile I define. I have been using `rotate_extrude` to try to create these profiles in the past, but I suspect there might be more flexible options.

Finally, I need the library to be easy to use. Ideally, there should be a function for each profile where I can specify its dimensions (e.g., `RHS(width=100, height=50, thickness=5, length=200)`, and that there is the ability to specify the radius and bend in a `curve_profile` function (e.g `curve_profile(profile_name, length, radius, bend_angle)`)

I'm imagining the final library will contain a primary library file, and then a library for each family of profiles. For example, an `RHS.scad`, `SHS.scad`, `PFC.scad` and so on, with a master `SteelLibrary.scad` to combine them all.

My current library references a separate file called steel.txt to keep track of all the profiles, but it would be great to move that information into the code itself.

Could you help me create this parametric library? I'm looking for a fairly complete solution with a variety of parametric profiles and the ability to create curved sections using any of those profiles.

[Assistant]
Test.scad:
```
use <ENGCAD/ENGCAD.scad>

// Usage <module>(l);//l=length you require
// by Wes Wilcox
//trial section add / the /* to test and // to the /*
/*
$fn=10;// mod this to suit - 30 is default - 100 is flawless
translate([200,0,0])100508RHS(100);
translate([300,0,0])10010SHS(100);
translate([400,0,0])20026EA(100);
250PFC (50);
//gettig a direction
translate([-100,0,0])rotate([0,-90,0])15014UB(200);
//making a curve in any section
// first translate and/or rotate moves to your postion start
//Second translate  on the z axis is the radius of the bend
// the "for" statement last function "1:1:x" is set to your desired bend angle.
*/
/*
//..........................................
//this translate rotate function if uncommented
//increases the elements from 1 to 90!(90 Degrees)
//..........................................
translate([726,75,100]){
for(i = [ 1:1:90 ])
{rotate([0,i,0])
translate([0,0,175])rotate([90,-90,90])75PFC (6);}}
*/
///*
//.........................................
// if you place the dxf file you are using
//in your saved scad file directory you can
//use this to render a curve with 1 element
//.........................................
// the translate fuunction gives the radius at x
//
$fn=360;// change this to suit - try 10
translate([237.5,75,237.5])rotate([0,-90,90])rotate_extrude(angle=3600,convexity=10)translate([200,0,0])import(file = "75PFC.dxf");
//*/
```


[User]
Hey there! I'm looking to design a custom planter, and I'd like to have it generated as an OpenSCAD file, or a set of OpenSCAD files, that I can modify parametrically. Here's what I have in mind.

The planter should consist of two main parts: an outer pot and an inner soil holder. Both parts should be generated by the same parameters. It's important that I can choose whether to print the outer pot, the inner soil holder, or both. So I'll need a `print_outer` and `print_inner` boolean variable at the top of the file.

The outer pot should be based on a vertically divided polygon, basically a stack of slightly different polygons. I would like to specify the height `h`, the outer width `w`, and the thickness of the outer walls `so`. The base of the outer pot should be a solid disk, and I want to specify its thickness separately as `sb`. The number of divisions around the circle `nd` and the number of vertical divisions `nv` should be configurable.

I need the option to define a custom pot shape based on a radius increment list. This list, `radius_addition`, would be a list of values that are added to the base radius at each vertical division point. There should be a multiplier `rmu` for this list. A boolean `use_custom_radius` should control if we use that list or not. If `use_custom_radius` is false, the pot should be a straight cylinder.

Also, I'd like to use some random noise to make the outer pot a bit less uniform. I need to control the amount of random noise with a variable called `rn`. The code should generate the random offsets based on a seed which is the same every time I re-render, so the same shape will be generated given the same parameters. I need to have the option to use more complex polygons made of four triangles each for the main outer part, so we should have `use_advanced_polygons` as a boolean parameter. The inner rim should be at a certain margin distance `mir` from the inner radius, and be a certain depth `dir` from the top.

For the inner soil holder, I want to specify the height `hi`, which will be smaller than the outer pot height. I'll also need the thickness of the bottom `sbi` and the thickness of the inner walls `si`. The number of divisions around the circle for the inner part should match that of the outer, so it should have the same value as `nd`, which we will call `ne`. I also need to define a width ratio `wr` relative to the outer width, and the actual soil holder width `wi` should be automatically calculated. The inner soil holder should have water holes, and I need to be able to specify the number of holes `nwh` and their radius `whr`.

Finally, we should define a variable `e` for the error of the printer, it will be a global setting and used to make the tolerances.

I don't need any specific libraries for this design, just the standard OpenSCAD primitives.

Could you generate the OpenSCAD code for me?

[Assistant]
poly_planter.scad:
```
//
// what to print
//

print_outer = true;
print_inner = true;

//
// global variables
//

//error of printer in mm
e = 0.3;

//
// variables for outer part
//

//height
h = 90;
//outer width
w = 90;

//strength of outer walls
so = 6;

//strength bottom
sb = 1.5;

//number of circle divisions
nd = 32;
//number of vertical divisions
nv = 8;

//use radius increment list for custom outer pot shape
use_custom_radius = true;
//multiplier for radius increase list (for extremer/less extreme shapes)
rmu = 10.0;
//radius increments using custom radius
radius_addition = [0.3*rmu,0.7*rmu, 1.0*rmu, 1.2*rmu, 1.33*rmu, 1.41*rmu, 1.45*rmu, 1.45*rmu, 1.45*rmu, ]; //pod shape
//radius_addition = [0.3*rmu,0.7*rmu, 1.0*rmu, 1.2*rmu, 1.35*rmu, 1.2*rmu, 1.0*rmu, 0.7*rmu, 0.2*rmu, 0.1*rmu, 0.2*rmu, 0.7*rmu, 1.2*rmu]; //vase shape

//polyhedra with more sides
use_advanced_polygons = true;

//amount of random noise
rn = 6;

//margin inner ring
mir = 1.5;
//depth inner ring
dir = 2.0;

//
// variables for inner part
//

//height inner part
hi = h - 5;

//strength bottom inner
sbi = 0.9;

//strength of inner walls
si = 0.8;

//divisions of inner holder
ne = nd;

//width ratio of inner soil holder
wr = 0.8;

//number of water holes
nwh = nd/2;
//water hole radius
whr = 1.5;

//
//do not change
//

//random points for polyhedron offsets
rnds = rands(-rn/2,rn/2,nd*(nv+1));

// this inner width (width of soil holder)
wi = wr * w;

// this radius of outer width
r = w/2;

// radius of inner width (soil holder)
ri = wi/2;

// height step
hs = h/nv;

//degrees to turn in loop
c = 360/nd;

function get_i_smooth(arr, perc) = let(ifloat = perc * (len(arr)-1), iint = floor(ifloat), m1 = ifloat - iint, m2 = 1-m1) iint < len(arr)-1 ? m2*arr[iint] + m1*arr[iint+1] : arr[len(arr)-1];

//prints one polyhedron on a specific coordinate in vertical and horizontal pod coordinate space
module element(v,d,so) {
            din = (d+1)%nd;
            gh = 0; //very small gap horizontally
            gv = 0; //very small gap vertically

            tri =  use_custom_radius ? r + get_i_smooth(radius_addition,v/(nv-1)) : r; //radius of inner vector
            tro = tri + so;
            triu = use_custom_radius ? r + get_i_smooth(radius_addition,(v+1)/(nv-1)) : r; // radius of upper polygons inner vector
            trou = triu + so;

            trim = (tri + triu) / 2.0;
            trom = (tro + trou) / 2.0;

            on = rnds[v*nd+d]; //offset normal
            os = rnds[v*nd+din]; //offset side
            ou = rnds[(v+1)*nd+d]; //offset upper
            ous = rnds[(v+1)*nd+din]; //offset upper side
            om = (on+os+ou+ous)/4.0;
            if(use_advanced_polygons) {
                polyhedron(points=[
                [cos(c*d)*(tri+on),-sin(c*d)*(tri+on),v*hs],
                [cos(c*din-gh)*(tri+os),-sin(c*din-gh)*(tri+os),v*hs], // one to the side
                [cos(c*d)*(triu+ou),-sin(c*d)*(triu+ou),(v+1)*hs-gv], //one up
                [cos(c*din-gh)*(triu+ous),-sin(c*din-gh)*(triu+ous),(v+1)*hs-gv], // one up and one to the side

                [cos(c*d)*(tro+on),-sin(c*d)*(tro+on),v*hs],
                [cos(c*din-gh)*(tro+os),-sin(c*din-gh)*(tro+os),v*hs], // one to the side
                [cos(c*d)*(trou+ou),-sin(c*d)*(trou+ou),(v+1)*hs-gv], //one up
                [cos(c*din-gh)*(trou+ous),-sin(c*din-gh)*(trou+ous),(v+1)*hs-gv], // one up and one to the side

                [cos(c*d+c*0.5)*(trim+om),-sin(c*d+c*0.5)*(trim+om),v*hs+hs*0.5],
                [cos(c*d+c*0.5)*(trom+om),-sin(c*d+c*0.5)*(trom+om),v*hs+hs*0.5],

                ]
                ,faces=[
                [0,2,8], [0,8,1], [8,3,1], [8,2,3], //inner face with 4 triangles
                [4,9,6], [9,7,6], [9,5,7], [4,5,9], //outer face with 4
                [0,1,4], [1,5,4], //bottom face
                [6,3,2], [6,7,3], //top face
                [2,0,4], [6,2,4], //left face
                [3,5,1], [3,7,5], //right face
                ]);
            } else {
                polyhedron(points=[
                [cos(c*d)*(tri+on),-sin(c*d)*(tri+on),v*hs],
                [cos(c*din-gh)*(tri+os),-sin(c*din-gh)*(tri+os),v*hs], // one to the side
                [cos(c*d)*(triu+ou),-sin(c*d)*(triu+ou),(v+1)*hs-gv], //one up
                [cos(c*din-gh)*(triu+ous),-sin(c*din-gh)*(triu+ous),(v+1)*hs-gv], // one up and one to the side

                [cos(c*d)*(tro+on),-sin(c*d)*(tro+on),v*hs],
                [cos(c*din-gh)*(tro+os),-sin(c*din-gh)*(tro+os),v*hs], // one to the side
                [cos(c*d)*(trou+ou),-sin(c*d)*(trou+ou),(v+1)*hs-gv], //one up
                [cos(c*din-gh)*(trou+ous),-sin(c*din-gh)*(trou+ous),(v+1)*hs-gv], // one up and one to the side
                ]
                ,faces=[
                [0,2,1], [2,3,1], //inner face with 2 triangles
                [4,5,6], [7,6,5], //outer face
                [0,1,4], [1,5,4], //bottom face
                [6,3,2], [6,7,3], //top face
                [2,0,4], [6,2,4], //left face
                [3,5,1], [3,7,5], //right face
                ]);
            }

    }

//print outer pod
if(print_outer) {
//print botton part
    difference(){
        cylinder(sb+dir,500,500);
        for(d = [0:(nd)-1]) {
            element(0,d,500);
        }
        ricutout = use_custom_radius ? ri + radius_addition[0] : ri;
        translate([0,0,sb]) cylinder(dir,ricutout+mir+e,ricutout+mir+e);
    }

    //main cylinder
    for(v = [0:(nv)-1]) {
        for(d = [0:(nd)-1]) {
            element(v,d,so);
        }
    }
} //print outer

//print inner part
if(print_inner){
    tx = use_custom_radius ? w + 2* radius_addition[len(radius_addition)-1]+rn/2+1 : w+rn/2+1;
    translate([tx,0,0]) {
        ricutout = use_custom_radius ? ri + radius_addition[0] : ri;
        cylinder(sbi,ricutout,ricutout,$fn=ne);

        translate([0,0,sbi]) {
            difference() {
                for(v = [0:nv-1]) {
                tri = use_custom_radius ? ri + get_i_smooth(radius_addition,v/(nv-1)) -si : ri -si; //radius of inner
                tro = tri + si;
                triu = use_custom_radius ? ri + get_i_smooth(radius_addition,(v+1)/(nv-1)) -si : ri -si; // radius of upper
                trou = triu + si;
                difference(){
                    translate([0,0,v*hs])cylinder(hs,tro,trou,$fn=ne);
                    translate([0,0,v*hs])cylinder(hs,tri,triu,$fn=ne);
                }
    }
                    translate([0,0,hi]) cylinder(500,500,500); //cut out upper part to have height hi (height inner)
                    for(i = [-90:360/nwh:269]) { //cut out water holes
                    translate([0,0,whr])rotate([90,0,i])cylinder(500,whr,whr);
                }
            }
        }
    }
}

```