[User]
I'm looking to create a customizable ripple effect in OpenSCAD, similar to what's shown in the provided files, but I need it to be more flexible and have some additional features. I'd like to have a few preset options but also be able to define my own ripple centers and parameters.

Here's what I'm imagining:

**Core Functionality:**

*   **Multiple Ripple Sources:** I need to be able to generate multiple wave ripples that are added together.
*   **Customizable Ripple Function:** I'd like to use the basic sine wave ripple function as provided in the examples, but also have the ability to swap in different functions if needed.
*   **Design Presets:**
    *   **Random:** The ripple centers are randomly placed within a specified area. I need to be able to control the number of random points and the seed for consistent generation.
    *   **Radial:** The ripple centers are arranged in a circle with a given radius, and I can control how many ripples there are and their rotation.
    *   **Grid:** The ripple centers are on a square grid. I need to specify the grid spacing, and the number of rows and columns.
    *   **Custom:** The ripple centers are explicitly specified by their coordinates. I also need to be able to control the depth (amplitude) and shift of each point individually in this mode, similar to what's in the v1.1 example.
*   **Global Parameters:**
    *   **Extent:** A parameter to control how much of the function is shown.
    *   **Separation:** The maximum spacing between ripple centers in the random mode, and radial separation in radial mode, and spacing between rows/columns in grid mode.
    *   **Depth:** The maximum depth/amplitude of the ripples.
    *   **Shift:** A shift applied to the sine waves to change the overall wave pattern.
    *   **Number of Drops:** The number of ripple centers for random and radial designs, and for specifying the number of custom points to use.
    *   **Dimension:** The size of the resulting model in mm (square).
    *   **Resolution:** The number of scan lines used to generate the 3D surface.
    *   **Z Height:** The height of the base, effectively truncating ripples below a specified level.

**Additional Features:**

*   **Height Coloring:** Like in the v1.1 example, I would like the surface to be colored based on height for better visualization. I need control of the lowest and highest points for the height color mapping.
*   **Manifold Output:** Ensure the final output is a manifold solid for 3D printing, using techniques to deal with the overlapping of the grid/triangles like the tiny 'ff' value in the examples.

**Library:**

*   I'd like to use the BOSL library for any math utilities that might be useful, but otherwise, it doesn't have to rely on external libraries.

I'd like all of the above organized into a single SCAD file using named modules to aid clarity. Can you help me generate the necessary code?

[Assistant]
customizable_ripples_v1.1.scad:
```
//
// Customizable Ripples
// version 1.1   11/11/2016
// by DaoZenCiaoYen @ Thingiverse
//
// remix of: http://www.thingiverse.com/thing:24897
// OpenSCAD 3D surface plotter, z(x,y)
// Dan Newman, dan newman @ mtbaldy us
//

// preview[view:south east, tilt:top diagonal]

/* [Main] */
design = 0 ; // [0:Random, 1:Radial, 2:Custom]
// how much of the function to show (zoom)
extent = 6 ; // [2:25]
// max distance between drops
separation = 12 ; // [0:50]
// max amplitude of the waves
depth = 20 ; // [0:25]
// shifts the sine waves
shift = 15 ; // [0:100]
// applies to all design types
number_of_drops = 3 ; // [1:6]

/* [Radial Settings] */
// rotates all drops
rotation = 0 ; // [0:90]

/* [Random Design Settings] */
seed = 76 ; // [0:99]

/* [Custom Design Settings] */
// [x,y,depth,shift]
point1 = [-10,7,10,20] ;
// [x,y,d,s]
point2 = [10,-7,10,20] ;
// [x,y,d,s]
point3 = [10,7,10,20] ;
// [x,y,d,s]
point4 = [-10,-7,10,20] ;
// [x,y,d,s]
point5 = [0,7,10,20] ;
// [x,y,d,s]
point6 = [0,-7,10,20] ;

/* [Size and Shape] */
// size, in mm (square)
dimension = 80 ; // [20:10:120]
// resolution, in scan lines
resolution = 40 ; // [5:60]
// height (negative is truncated) in mm
z_height = 4 ; // [1:20]

/* [Hidden] */
pi = 3.14159265358979;
ff = 0.001 ; // overlap to aid manifold processing

size = extent ;
nx = shift ; // center shift
sz = depth ; // amplitude
sep = separation ; // separation
px = number_of_drops ; // max points
res = resolution ;
dim = dimension ;
rng = size*pi ;
sh = sqrt(3)/2*sep ;
hs = sh/2 ;
z_max = 2;

da = [
  [ // set 0 (random)
    rands(-sep,sep,px,seed), // x
    rands(-sep,sep,px,seed+1), // y
    rands(4,sz,px,seed), // sz
    rands(0,nx,px,seed), // n
    px-1], // p
  [ // set 1 (regular)
    [for (i = [rotation:360/px:359+rotation]) (px==1?0:separation)*cos(i)], // x
    [for (i = [rotation:360/px:359+rotation]) (px==1?0:separation)*sin(i)], // y
    [sz,sz,sz,sz,sz,sz], // sz
    [nx,nx,nx,nx,nx,nx], // n
    px-1], // p
  [ // set 2 (custom)
    [point1[0],point2[0],point3[0],point4[0],point5[0],point6[0]], // x
    [point1[1],point2[1],point3[1],point4[1],point5[1],point6[1]], // y
    [point1[2],point2[2],point3[2],point4[2],point5[2],point6[2]], // sz
    [point1[3],point2[3],point3[3],point4[3],point5[3],point6[3]], // n
    px-1] // p
  ];

// A wave ripple function
function zr(x,y,s,n) = s*sin(180*(sqrt(x*x+y*y)+n)/pi)/sqrt((x*x+y*y)+n);

// Other example functions
function z2(x,y) = cos(x*y)*(x*x-y*y)/2000*depth;
function z3(x,y) = sqrt(cos(abs(x)*10)+cos(abs(y)*10));

// Multiple ripples added together
function zao(x,y,o,p) = (p<0 ? 0 : zao(x,y,o,p-1) +
  zr(x+da[o][0][p],y+da[o][1][p],da[o][2][p],da[o][3][p])) ;
function za(x,y,o) = zao(x,y,o,da[o][4]);

// which settings (da) to use
function z(x,y) = max(-z_height,za(x,y,design));

// other example functions
//function z(x,y) = max(-z_height,z2(x,y));
//function z(x,y) = max(-z_height,z3(x,y));
//function z(x,y) = max(-z_height,z2(x,y)+z3(x,y));
//function z(x,y) = max(-z_height,z2(x,y)+za(x,y,design));

// Plot the function in 3d
3dplot([-rng,+rng],[-rng,+rng],[res,res],-z_height-3,[dim,dim]);

//
// The 3d surface generation code
//

// Pyramid vertices (template)
//
pyramid_vertices = [ // these aren't actually used below
  [0,0,0], [1,0,0], [0,0,1], [1,0,1],
  [0,1,0], [1,1,0], [0,1,1], [1,1,1],
  [0.5,0.5,1.5] ]; // center added for 9 faces

// The faces of the pyramid (indices of points above)
pyramid_faces = [
  [0,1,5,4],[0,2,3,1],[1,3,7,5],[7,6,4,5],[6,2,0,4],
  [2,8,3],[3,8,7],[7,8,6],[6,8,2]];

// 3dplot -- the 3d surface generator
//
// x_range -- 2-tuple [x_min, x_max], the minimum and maximum x values
// y_range -- 2-tuple [y_min, y_max], the minimum and maximum y values
//    grid -- 2-tuple [grid_x, grid_y] indicating the number of grid cells
//              along the x and y axes
//   z_min -- Minimum expected z-value; used to bound the underside of the surface
//    dims -- 2-tuple [x_length, y_length], the physical dimensions in millimeters

function z1(z)=(max(-z_max,min(z_max,z))+z_max)/(z_max*2) ;
function c(z)=[z1(z),z1(z),z1(z)] ;

module 3dplot(x_range, y_range, grid, z_min, dims)
{
  dx = ( x_range[1] - x_range[0] ) / grid[0];
  dy = ( y_range[1] - y_range[0] ) / grid[1];

  scale([dims[0]/(max(x_range[1],x_range[0])-min(x_range[0],x_range[1])),
         dims[1]/(max(y_range[1],y_range[0])-min(y_range[0],y_range[1])),1])
  translate([-(x_range[0]+x_range[1])/2, -(y_range[0]+y_range[1])/2, -z_min])
  for ( x = [x_range[0] : dx  : x_range[1]] )
  {
    for ( y = [y_range[0] : dy : y_range[1]] )
    {
      color(c(z(x+dx/2,y+dy/2)))
      polyhedron(
        points=[
          [x-ff,y-ff,z_min], // 0:[0,0,0]
          [x+dx,y-ff,z_min], // 1:[1,0,0]
          [x-ff,y-ff,z(x-ff,y-ff)], // 2:[0,0,1]
          [x+dx,y-ff,z(x+dx,y-ff)], // 3:[1,0,1]
          [x-ff,y+dy,z_min], // 4:[0,1,0]
          [x+dx,y+dy,z_min], // 5:[1,1,0]
          [x-ff,y+dy,z(x-ff,y+dy)], // 6:[0,1,1]
          [x+dx,y+dy,z(x+dx,y+dy)], // 7:[1,1,1],
          [x+dx/2,y+dy/2,z(x+dx/2,y+dy/2)] // 8:[0.5,0.5,1.5]
        ],
        faces=pyramid_faces);
    }
  }
}
```
customizable_ripples_v1.scad:
```
//
// Customizable Ripples
// version 1.0   3/19/2016
// by DaoZenCiaoYen @ Thingiverse
// (Steve Van Ausdall)
//
// remix of: http://www.thingiverse.com/thing:24897
// OpenSCAD 3D surface plotter, z(x,y)
// Dan Newman, dan newman @ mtbaldy us
//

// preview[view:south east, tilt:top diagonal]

/* [Main] */
design = 0 ; // [0:Random, 1:Square, 2:Triangle, 3:Custom]
// how much of the function to show (zoom)
extent = 10 ; // [5:25]
// max distance between points
separation = 18 ; // [0:50]
// max amplitude of the waves
depth = 10 ; // [0:25]
// shifts the sine waves
shift = 40 ; // [0:100]

/* [Random Design Settings] */
random_points = 3 ; // [1:5]
seed = 36 ; // [0:99]

/* [Custom Design Settings] */
custom_points = 5 ; // [1:5]
// [x,y,d,s]
point1 = [0,0,10,20] ;
// [x,y,d,s]
point2 = [10,0,6,30] ;
// [x,y,d,s]
point3 = [-10,0,6,30] ;
// [x,y,d,s]
point4 = [0,10,6,30] ;
// [x,y,d,s]
point5 = [0,-10,6,30] ;

/* [Size and Shape] */
// size, in mm (square)
dimension = 80 ; // [20:10:120]
// resolution, in scan lines
resolution = 50 ; // [5:50]
// height (negative is truncated) in mm
z_height = 4 ; // [1:20]

/* [Hidden] */
pi = 3.14159265358979;
ff = 0.001 ; // overlap to aid manifold processing

size = extent ;
nx = shift ; // center shift
sz = depth ; // amplitude
sep = separation ; // separation
px = random_points ; // max points
res = resolution ;
dim = dimension ;
rng = size*pi ;
sh = sqrt(3)/2*sep ;
hs = sh/2 ;

da = [
  [ // set 0 (random)
    rands(-sep,sep,px,seed), // x
    rands(-sep,sep,px,seed+1), // y
    rands(4,sz,px,seed), // sz
    rands(0,nx,px,seed), // n
    random_points-1], // p
  [ // set 1 (square)
    [-sep,-sep,sep,sep], // x
    [-sep,sep,sep,-sep], // y
    [sz,sz,sz,sz], // sz
    [nx,nx,nx,nx], // n
    3], // p
  [ // set 2 (triangle)
    [-sep,sep,0], // x
    [-sh,-sh,sh], // y
    [sz,sz,sz], // sz
    [nx,nx,nx], // n
    2], // p
  [ // set 3 (custom)
    [point1[0],point2[0],point3[0],point4[0],point5[0]], // x
    [point1[1],point2[1],point3[1],point4[1],point5[1]], // y
    [point1[2],point2[2],point3[2],point4[2],point5[2]], // sz
    [point1[3],point2[3],point3[3],point4[3],point5[3]], // n
    custom_points-1] // p
  ];

// A wave ripple function
function zr(x,y,s,n) = s*sin(180*(sqrt(x*x+y*y)+n)/pi)/sqrt((x*x+y*y)+n);

// Other example functions
function z2(x,y) = cos(x*y)*(x*x-y*y)/2000*depth;
function z3(x,y) = sqrt(cos(abs(x)*10)+cos(abs(y)*10));

// Multiple ripples added together
function zao(x,y,o,p) = (p<0 ? 0 : zao(x,y,o,p-1) +
  zr(x+da[o][0][p],y+da[o][1][p],da[o][2][p],da[o][3][p])) ;
function za(x,y,o) = zao(x,y,o,da[o][4]);

// which settings (da) to use
function z(x,y) = max(-z_height,za(x,y,design));

// other example functions
//function z(x,y) = max(-z_height,z2(x,y));
//function z(x,y) = max(-z_height,z3(x,y));
//function z(x,y) = max(-z_height,z2(x,y)+z3(x,y));
//function z(x,y) = max(-z_height,z2(x,y)+za(x,y,design));

// Plot the function in 3d
3dplot([-rng,+rng],[-rng,+rng],[res,res],-z_height-3,[dim,dim]);

//
// The 3d surface generation code
//

// Pyramid vertices (template)
//
pyramid_vertices = [ // these aren't actually used below
  [0,0,0], [1,0,0], [0,0,1], [1,0,1],
  [0,1,0], [1,1,0], [0,1,1], [1,1,1],
  [0.5,0.5,1.5] ]; // center added for 9 faces

// The faces of the pyramid (indices of points above)
pyramid_faces = [
  [0,1,5,4],[0,2,3,1],[1,3,7,5],[7,6,4,5],[6,2,0,4],
  [2,8,3],[3,8,7],[7,8,6],[6,8,2]];

// 3dplot -- the 3d surface generator
//
// x_range -- 2-tuple [x_min, x_max], the minimum and maximum x values
// y_range -- 2-tuple [y_min, y_max], the minimum and maximum y values
//    grid -- 2-tuple [grid_x, grid_y] indicating the number of grid cells
//              along the x and y axes
//   z_min -- Minimum expected z-value; used to bound the underside of the surface
//    dims -- 2-tuple [x_length, y_length], the physical dimensions in millimeters

module 3dplot(x_range, y_range, grid, z_min, dims)
{
  dx = ( x_range[1] - x_range[0] ) / grid[0];
  dy = ( y_range[1] - y_range[0] ) / grid[1];

  scale([dims[0]/(max(x_range[1],x_range[0])-min(x_range[0],x_range[1])),
         dims[1]/(max(y_range[1],y_range[0])-min(y_range[0],y_range[1])),1])
  translate([-(x_range[0]+x_range[1])/2, -(y_range[0]+y_range[1])/2, -z_min])
  for ( x = [x_range[0] : dx  : x_range[1]] )
  {
    for ( y = [y_range[0] : dy : y_range[1]] )
    {
      polyhedron(
        points=[
          [x-ff,y-ff,z_min], // 0:[0,0,0]
          [x+dx,y-ff,z_min], // 1:[1,0,0]
          [x-ff,y-ff,z(x-ff,y-ff)], // 2:[0,0,1]
          [x+dx,y-ff,z(x+dx,y-ff)], // 3:[1,0,1]
          [x-ff,y+dy,z_min], // 4:[0,1,0]
          [x+dx,y+dy,z_min], // 5:[1,1,0]
          [x-ff,y+dy,z(x-ff,y+dy)], // 6:[0,1,1]
          [x+dx,y+dy,z(x+dx,y+dy)], // 7:[1,1,1],
          [x+dx/2,y+dy/2,z(x+dx/2,y+dy/2)] // 8:[0.5,0.5,1.5]
        ],
        faces=pyramid_faces);
    }
  }
}
```


[User]
I need an OpenSCAD design for a parametric oil filter wrench. I want to be able to customize it based on the filter I need to use it on. I'd like to specify the number of faces on the filter, the diameter of the filter measured either face-to-face (for even numbers of faces) or face-to-vertex (for odd numbers), the usable depth of the wrench, the ratchet drive size, wall thickness, and bottom thickness.

The wrench should have an internal polygon that fits the filter, with some added slop for tolerance (0.66mm total diameter slop), and an outer polygon which, if I specify, can be rounded. The ratchet drive part should be integrated into the base of the wrench. I want to be able to select 1/4", 3/8", or 1/2" drives. The drive needs to be a standard size, and also has some slop added. The drive hole should go the proper depth. The filter hole should have some depth and the drive should have some depth. The height of the drive should be greater than the bottom thickness.

Could you generate the necessary OpenSCAD file(s) for this? I'm not using any special libraries. I need to make a custom filter wrench.

[Assistant]
parametric_filter_wrench_v6.scad:
```
// A parametric filter wrench tool for OpenSCAD
//
// Erik Ness
// erik@nessnation.com
//
// NOTE:  All dimensions in mm except ratchet size
//
// Version 6:  2017 03 29 Added 1/4" drive, did not build or test it.
//             Not recommended, but requested by a user.
//
// version 5:  Use face-to-face measurement for even number of sides

//-------------------------------------------
//        User-entered parameters
//
//  Formatted for thingiverse customizer.
//-------------------------------------------

// Number of faces on filter body:
num_faces = 12;                     // [6:30]

// Diameter of filter body in mm.  Measure from face to face (even) or face to vertex (odd).
filter_diameter_mm = 72;

// Depth of usable portion of tool in mm.  (Height above bottom and drive).
usable_tool_depth_mm = 29;

// Ratchet drive size in inches.
drive_size_inches = 0.5;            // [0.25, 0.375, 0.5]

// Thickness of tool wall in mm.
wall_thickness_mm = 6;

// Thickness of tool bottom in mm.
bottom_thickness_mm = 4;

// Make the outside round?
round_outside = 0;                  // [0:No,1:Yes]

/* [Hidden] */

$fn=50;

// Compute the radius from center to inner corner:
angle = 180 / num_faces;
r_to_face_if_odd_mm = (cos(angle) / (1+cos(angle))) * filter_diameter_mm;
R_if_even_mm = (filter_diameter_mm / 2) / cos(angle);
is_odd = (num_faces % 2);
radius_to_corners_mm = is_odd ? filter_diameter_mm - r_to_face_if_odd_mm : R_if_even_mm;     // from center to "corner", not face
filter_slop_r_mm = 0.33;

//echo (radius_to_corners_mm);

// 1/2" drive is exactly 8.98mm radius
// 3/8" drive is exactly 6.74mm radius
// 1/4" drive is (maybe) 4.49mm radius (not recommended, not tested)
drive_hole_r_mm = (drive_size_inches < 0.3) ?  4.49 :     // 1/4" drive
                  (drive_size_inches > 0.4) ?  8.98 :     // 1/2" drive
                  6.74;                                   // 3/8" drive

// 1/2" drive is 16mm tall
// 3/8" drive is 11mm tall
// 1/4" drive is  9mm tall
drive_height_mm = (drive_size_inches < 0.3) ?  9.00 :     // 1/4" drive
                  (drive_size_inches > 0.4) ? 16.00 :     // 1/2" drive
                  11.00;                                  // 3/8" drive

drive_hole_slop_r_mm = 0.33;
drive_thickness_r_mm = drive_hole_r_mm;

outside_faces = round_outside ? 100 : num_faces;
outside_height_mm = usable_tool_depth_mm + max(drive_height_mm,bottom_thickness_mm);

difference()
{
    union()
    {
        difference()
        {
            // Outside body:
            linear_extrude(outside_height_mm)
                my_regular_polygon(outside_faces, radius_to_corners_mm+wall_thickness_mm);

            // Main Polygon hole:
            translate([0,0,bottom_thickness_mm])
                linear_extrude(outside_height_mm - bottom_thickness_mm)
                    offset(filter_slop_r_mm)
                        my_regular_polygon(num_faces, radius_to_corners_mm);
        }

        // Drive body:
        linear_extrude(drive_height_mm)
            offset(drive_hole_slop_r_mm)
                my_regular_polygon(16,drive_hole_r_mm+drive_thickness_r_mm);
    }

    // Drive hole:
    linear_extrude(drive_height_mm)
        offset(drive_hole_slop_r_mm)
            my_regular_polygon(4,drive_hole_r_mm);
}

module my_regular_polygon(faces, radius)
{
    $fn = faces;
    circle(radius);
}

```


[User]
Okay, I'm looking to design a modular box system in OpenSCAD, and I think I have a pretty good idea of what I want. I'd like a box that can have an optional cover, and I need it to be parametric so I can adjust the size and height. I'm also hoping to have some kind of connector system on the sides so I can attach multiple boxes together.

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

*   **`Object_Height`**: The height of the main box part, with a range from 50mm to 200mm.
*   **`Object_Size`**: The side length of the main box, and I'd like presets at 50mm, 100mm, 150mm, and 200mm.
*  **`Object_Type`**: A selector, where 1 creates only the box, 2 creates only the lid, and 3 creates both the box and the lid.
*   **`Cover_Height`**: The height of the cover, independent of the `Object_Height` but intended to be shorter. I'm thinking 25mm will be good as a default.
*   **`Wall_Tickness`**: The thickness of the box walls, which I think 2mm should work as a default, but I need to be able to change it.

I'm also planning on having rounded corners, with a radius of 5mm for the edges of the box and cover. I need connectors on the sides, and I'm thinking they should be 10mm wide and 5mm deep with a thickness of 2mm. The connectors should interlock, and be designed so they can connect multiple boxes together.

The box should be hollow with the defined wall thickness. The cover should be a snug fit to the box, with a small spacing of 0.5mm between the cover and the box body, and should sit on top of the box.

For the connectors, I think a single set of interlocking male and female connectors at each side would be good. The quantity of connector pairs per side should depend on the `Object_Size`. For `Object_Size` of 50, it should have 1 pair; for 100, it should have 2 pairs; for 150, 3 pairs, and for 200, 4 pairs.

I'd like the code to generate both the box and cover (if requested with `Object_Type`), and when both are requested, I'd like them to be positioned side-by-side with a little spacing. I think 1mm between the box and cover is good.

I’d like to use the `hull()` function to generate the rounded corners, and would prefer the files not use any other libraries.

Could you generate an OpenSCAD file that defines these parameters and creates this modular box system?

[Assistant]
modular_box.scad:
```

/* [Configurations] */
Object_Height = 50; // [50:200]
Object_Size = 50; // [50: 50mm, 100: 100mm, 150: 150mm, 200: 200mm]
Object_Type = 3; // [1: Box, 2: cover, 3: all]
Cover_Height = 25;
Wall_Tickness = 2;// 5mm is good enough

/* [hidden] */
$fn = 50;
Cover_Spacing = 0.5;
Rounded_Corner = 5;
Connector_Tickness = 2;
Connector_Width = 10;
Connector_Depth = 5;
Object_Side = Object_Size - Connector_Depth * 2;
Border_Width = Connector_Width * 0.5 + Connector_Depth;
Total_Width = Connector_Depth * 2 + Object_Side;

print();

module print() {
    if  (Object_Type == 1) {
        caixa();
    }
    if  (Object_Type == 2) {
        translate([Connector_Depth ,Object_Side + Connector_Depth,Cover_Height]) rotate([180,0,0]) tampa(0);
    }
    if  (Object_Type == 3) {
        caixa();
        translate([Total_Width + 1,Object_Side,Cover_Height]) rotate([180,0,0]) tampa(0);
    }
}

module caixa(){
    translate([Connector_Depth, Connector_Depth, 0])
    difference(){
        roundedcube(Object_Side, Object_Side, Object_Height, Rounded_Corner,Rounded_Corner,Rounded_Corner,Rounded_Corner);
        translate([Wall_Tickness, Wall_Tickness, Wall_Tickness]) roundedcube(Object_Side - Wall_Tickness * 2, Object_Side - Wall_Tickness * 2, Object_Height + 1,Rounded_Corner, Rounded_Corner, Rounded_Corner, Rounded_Corner);
    // Recorte da tampa
        translate([0,-0,(Object_Height + 1) - Cover_Height + (Wall_Tickness * 2)]) tampa(Cover_Spacing);
    }
    allConnectors();
}

module tampa(folga){
    difference(){
    translate([-folga/2,-folga/2,0]) roundedcube(Object_Side + folga, Object_Side + folga, Cover_Height, Rounded_Corner,Rounded_Corner,Rounded_Corner,Rounded_Corner);
    translate([(Wall_Tickness + folga)/2, (Wall_Tickness + folga) /2, -Wall_Tickness]) roundedcube(Object_Side - Wall_Tickness - folga, Object_Side - Wall_Tickness - folga, Cover_Height , Rounded_Corner, Rounded_Corner, Rounded_Corner, Rounded_Corner);
    }
}

module roundedcube(xdim ,ydim ,zdim,rdim1, rdim2, rdim3, rdim4){
    hull(){
        translate([rdim1,rdim1,0]) cylinder(r=rdim1, h=zdim);
        translate([xdim-rdim2,rdim2,0]) cylinder(r=rdim2, h=zdim);

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

module mConnector() {
    linear_extrude((Object_Height + 1) - Cover_Height + (Wall_Tickness * 2))
    polygon(
        points = [
            [-Connector_Width / 2+ Connector_Tickness, 0],
            [Connector_Width / 2 - Connector_Tickness, 0],
            [Connector_Tickness / 2, Connector_Depth],
            [-Connector_Tickness / 2, Connector_Depth]
        ], center = true);
}

module fConnector() {
    difference() {
        cube([Connector_Width, Connector_Depth, (Object_Height + 1) - Cover_Height + (Wall_Tickness * 2)]);
        translate([Connector_Width / 2, 0, 0])
        scale(1.1)
        mConnector();
    }
}

module sideConnectors(pairs) {
    for (i = [0:pairs - 1]) {
        translate([Border_Width + Connector_Width + 50 * i, Connector_Depth, 0])
        rotate([0, 0, 180])
        fConnector();
        space_connectors = 10;
        translate([Border_Width + Connector_Width * 1.5 + space_connectors + 50 * i, 0, 0])
        mConnector();
    }

}

function pairQtt() =
    (Object_Size == 50) ? 1 :
        (Object_Size == 100) ? 2 :
            (Object_Size == 150) ? 3 : 4;

module allConnectors() {

    pairs = pairQtt();

    sideConnectors(pairs);
    translate([50 * pairs, 0, 0]) rotate([0, 0 , 90])
    sideConnectors(pairs);
    translate([0, 50 * pairs, 0]) rotate([0, 0 , -90])
    sideConnectors(pairs);
    translate([50  * pairs, 50  * pairs, 0]) rotate([0, 0 , 180])
    sideConnectors(pairs);
}

```


[User]
Hey, I'm looking for an OpenSCAD design for a customizable license plate, kind of like the ones Muzz64 made, but with a few more options. I've got some existing code that I can share with you for reference if that helps, but ultimately, I need a parametric design that I can adjust myself using the customizer interface.

Here's what I want it to do:

1.  **Basic Plate Shape:** The plate should be a rounded rectangle, basically a box with rounded edges. I need to be able to control the overall dimensions (length, width, and thickness) and the radius of the rounded edges.

2.  **Mounting Holes:** There should be four mounting holes, two near the top and two near the bottom. I need to be able to adjust the horizontal and vertical position of these holes, as well as the diameter.

3.  **Multiple Text Lines:** I need to be able to add three separate lines of text to the plate. Each text line should be able to be fully customized with its own:
    *   Text string
    *   Font (I'd like to be able to choose from a wide list of fonts - maybe something like the Google fonts library if that's possible?)
    *   Font style (Regular, Bold, Italic)
    *   Font size
    *   Vertical position
    *   Letter spacing

4.  **Text Alignment:** The text should be centered horizontally. I also need to be able to move the top and bottom lines vertically, but the middle one should remain static in the center.

I'd also like it to use the `boxes.scad` module from the MCAD library.

Let me know if that's possible! Thanks!

[Assistant]
LicencePlate.scad:
```
//V1.0 Initial release
//V1.1 Moved holes to align with Muzz64's plate.
//Thinned the plate out a few mm
//V1.2 Added multiple lines
//V1.3 Allowed different fonts, size, etc on different lines
//V1.4 Updated list of fonts - borrwed from https://www.thingiverse.com/thing:739573
// - a down stripped 'main' font list with 250 fonts(many Thanks to tbuser for giving me the list(http://www.thingiverse.com/download:1335652) of the installed fonts)
//V1.5 Minor updates: Default font set to a built in one. Default font size reset to a more manageable size.
//V1.6 The top and bottom lines can be moved vertically through a small range. And....It doesn't work. NFI why.
//V1.7 Think I fixed the issue above (had the slider the wrong way around).

use <MCAD/boxes.scad>

//CUSTOMIZER VARIABLES
// preview[view:south, tilt:top]

//Line 1
    text1 = "Insert";
//Line 2
    text2 = "Your Name";
//Line3
    text3 = "Here";

//CUSTOMIZER VARIABLES END

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

styleTop="Regular"; //[Regular, Bold, Italic]

fontstyleTop = str(fontTop,":",styleTop);

//Height of characters [mm]
fontsizeTop=8;  //[5:9]

//Top Text Position
TopY = 18; //[12:20]

letter_spacingTop = 1; //[-1:5]
letterspacingTop = 1.0+letter_spacingTop/10;

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

styleMid="Regular"; //[Regular, Bold, Italic]

fontstyleMid = str(fontMid,":",styleMid);

//Height of characters [mm]
fontsizeMid=8;  //[5:16]

letter_spacingMid = 1; //[-1:5]
letterspacingMid = 1.0+letter_spacingMid/10;

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

styleBot="Regular"; //[Regular, Bold, Italic]

fontstyleBot = str(fontBot,":",styleBot);

//Height of characters [mm]
fontsizeBot=8;  //[5:9]

//Bottom Text Position
BotY=-10; //[-12:-6]

letter_spacingBot = 1; //[-1:5]
letterspacingBot = 1.0+letter_spacingBot/10;

difference (){
    $fn=100;
    roundedBox([94,47,3],4,true);
    translate([0,0,1.5]) roundedBox([89,42,3],3,true);
    translate([-30,17,-5]) cylinder(h=10, r=2);
    translate([-30,-17,-5]) cylinder(h=10, r=2);
    translate([30,17,-5]) cylinder(h=10, r=2);
    translate([30,-17,-5]) cylinder(h=10, r=2);
}
translate([0,TopY,-1]){
    $fn=100;
    linear_extrude(2.5) text(text1, fontsizeTop, font = fontstyleTop, valign = "top", halign = "center", spacing = letterspacingTop);
}
translate([0,0,-1]){
    $fn=100;
    linear_extrude(2.5) text(text2, fontsizeMid, font = fontstyleMid, valign = "center", halign = "center", spacing = letterspacingMid);

}
translate([0,BotY,-1]){
    linear_extrude(2.5) text(text3, fontsizeBot, font = fontstyleBot, valign = "top", halign = "center", spacing = letterspacingBot);
}
```


[User]
I want to design a clip that attaches to a wire rack and has a cleat for holding wires and cords.

Here's what I have in mind:

The clip part should be designed to go around two parallel wires. The distance between the *outer* edges of these two wires is going to be a parameter called `lipWidth`. The diameter of each of those wires should be `wireWidth`. There should be a notch in the clip to give it some flex so it's easier to attach and detach - let's call that `doFlexNotch`, and it can be a boolean. The overall width of the clip is called `width`, and should be a parameter too. I had plans for another set of wires and spacing in mind, but let's ignore those parameters for now, `wireSpacing` and `smallWireWidth`.

The cleat part should stick out from the clip. The length of the cleat (along the wire rack) will be `cleatLength`, how far it sticks out from the clip will be `cleatDepth`, and its thickness (going around the wire rack) should be `cleatThickness`.

Finally, I want the option of having a cord clip on the end of the cleat, so let's add a boolean parameter `doCordClip`. If that's true, then there should be a cord clip with a diameter parameter called `cordDiameter`.

So, to recap, I want parameters for:

*   `lipWidth` (distance between outer edges of the main wires)
*   `wireWidth` (diameter of the main wires)
*   `doFlexNotch` (boolean for adding the flex notch)
*   `width` (overall width of the clip)
*   `cleatLength` (length of the cleat)
*   `cleatDepth` (how far the cleat extends from the clip)
*   `cleatThickness` (thickness of the cleat)
*   `doCordClip` (boolean for adding cord clip)
*   `cordDiameter` (diameter of cord clip, if present)

I'd prefer for you to write separate modules for the clip and cleat and call them `clip` and `cleat` respectively.

[Assistant]
cleat_non_modular.scad:
```
// Distance between the outer edges of the two large wires that make up the lip
lipWidth=34.25;
// Diameter of the large wires that make up the lip
wireWidth=6.5;
// Add a notch in the clip so it has flex and doesn't break while putting it on
doFlexNotch=true;
//not used yet
//wireSpacing=16.9;
//smallWireWidth=3.5;
// how wide to make the hook/cleat
width=20;
// how long the actual cleat will be
cleatLength=60;
// how far to have the cleat extend from the clip
cleatDepth=15;
// how thick the cleat "arms" should be
cleatThickness=10;
// wether or not to do the cord clip
doCordClip=true;
// how big the cord clip should be only used if doCordClip=True;
cordDiameter=5;

module clip(_lip_width, _wire_radius, _do_flex_notch, _width, _wire_spacing, _small_wire_width) {
    difference() {
        cube([_wire_radius*4, _lip_width+(2*_wire_radius), _width]);
        translate([_wire_radius, _wire_radius*2, 0]) cube([_wire_radius*3, _lip_width-(2*_wire_radius), _width]);
        translate([_wire_radius*2, _wire_radius*2, 0]) cylinder(r=_wire_radius, h=_width, $fn=100);
        translate([_wire_radius*2,_lip_width, 0]) cylinder(r=_wire_radius, h=_width, $fn=100);
        if(_do_flex_notch) {
                translate([_wire_radius*2, _wire_radius*.9, 0]) cylinder(r=_wire_radius*0.3, h=_width, $fn = 100);
        }
        //comming soon
        if(_wire_spacing < _wire_radius) {
        }
    }
}
clip(lipWidth, wireWidth/2, doFlexNotch, width, wireSpacing, smallWireWidth);

module cleat(_cleat_length, _cleat_depth, _cleat_thickness, _do_cord_clip, _cord_diameter) {
    translate([-1*(_cleat_thickness+_cleat_depth), -(_cleat_length/2)+width/2,0])
        cube([_cleat_thickness, _cleat_length, width]);
    translate([-1*(_cleat_depth), width/2,width/2]) rotate([0,90,0])
        cylinder(r=width/2, h= _cleat_depth, $fn=100);
    if (_do_cord_clip) {
        difference() {
            translate([-1*(_cleat_thickness+_cleat_depth+_cord_diameter*.8),width/2-0.65*_cord_diameter,0])
                cube([_cord_diameter*.8, _cord_diameter*1.3, width]);
            translate([-1*(_cleat_thickness+_cleat_depth+_cord_diameter*.6),width/2,0])
                cylinder(r=_cord_diameter/2,h=width, $fn=100);
        }
    }
}
cleat(cleatLength, cleatDepth, cleatThickness, doCordClip, cordDiameter);
```


[User] I'd like to create a wedge shape with a hole through the thicker end. I need to be able to adjust the height of both the thick and thin ends, the length of the wedge, the width of the wedge, and the diameter of the hole. I'm envisioning something that looks like a simple inclined plane, but with a cylindrical hole passing perpendicular to the length. Could you generate an OpenSCAD file for me?

[Assistant]
parametrische_wig.scad:
```
/// alle maten in milimeters
/// Wouter 16-3-2016

hoogste = 7; //hoogste kant van de wig
lengte = 70; //lengte van de wig
breedte = 10; //breedte van de wig
laagste = 0.8; //laagste kant van de wig
gaatje = 4;

difference (){
hull(){
cylinder(d=hoogste, h=breedte);
translate([lengte-(hoogste/2)-(laagste/2),0,0]) cylinder(d=laagste, h=breedte);
}

translate ([0,0,-1]) cylinder (d=gaatje, h=breedte+2);
}
```


[User]
Hi there, I'm looking to create a parametric OpenSCAD design for a bandsaw insert. I have a basic design in mind that I've already coded, but I need it to be more flexible and easier to adjust for different saws and blade sizes.

Here's a breakdown of what I need:

The insert is essentially a circular plate that sits flush with the bandsaw table. It needs these components:

*   **Main Plate:** A circular disc that forms the top surface, with adjustable thickness and diameter.
*   **Bottom Lip:** A smaller-diameter circular lip that sits below the main plate, providing a snug fit in the bandsaw table's opening. This lip also needs adjustable thickness and diameter.
*   **Key/Bump:** A small cylindrical bump on the top of the main plate, intended to prevent the insert from rotating. This should have an adjustable diameter and position (potentially using angular coordinates).
*   **Blade Slot:** A thin, rectangular cut-out that allows the bandsaw blade to pass through. This needs adjustable width, depth, and offset from the center (for varying blade positions and bandsaw configurations.)
*   **Resolution:** The resolution of the circles should also be adjustable as a parameter.

My current code uses simple `cylinder` and `cube` primitives, but I’d like to make it more robust and easier to configure. I need parameters for:

*   `plate_thickness`
*   `plate_diameter`
*   `lip_thickness`
*   `lip_diameter`
*   `key_diameter`
*  `key_angle` (angle of the key relative to the X axis)
*  `key_radius` (radius of the key relative to the center)
*   `blade_width`
*   `cutaway_width`
*   `cutaway_depth`
*   `cutaway_offset`
*   `circle_resolution`

I'd like to be able to quickly modify all of these. Please organize it so all of the design parameters are at the beginning of the code.

It would be fantastic if you could create the design in a single .scad file.

I think that's everything. Thanks in advance!

[Assistant]
bandsaw_insert.scad:
```
thick=3; //thickness of plate to table
topdia=63; //diameter of plate

edge=2; //thickness of bottom edge
botdia=56; //diameter of the bottom edge

key=2.8; //diameter of bump for key

blade=1; //width of the blade metal

cutx=6.4; //width of cutaway for turning of blade
cuty=18; //depth of cutaway
offset=0; //offset direction of cutaway for blade
res=60;

difference(){
difference(){
union(){
cylinder(thick, d=topdia, $fn=res);
translate([0,0,thick]) cylinder(edge, d=botdia, $fn=res);
translate([(topdia/2),0,0]) cylinder(thick, d=key, $fn=res);
}
translate ([0,topdia/4, (thick+edge)/2]) cube(size=[blade, topdia/2, thick+edge], center=true);
}
translate ([-cutx/2,-offset/2,0]) cube(size=[cutx,cuty,thick+edge], center=false);
}
```


[User]
Hey, I need to design some router table inserts for my Bosch RA1171 router table. I've got a basic design concept already, but I'd really like a parametric OpenSCAD file so I can easily adjust the size of the center hole.

Here's what I'm looking for:

The insert should be a circular disc with these general dimensions and features:

*   **Overall Diameter:** Approximately 97.5mm with some smaller diameter portions that I'll describe below.
*   **Overall Height:** Around 9.35mm, with varying thickness across the insert.
*   **Main Body:** A cylindrical body with a diameter of 97.5mm, and a height of 2.5mm.
*   **Recessed Lip:** A recessed lip, with an inner diameter of 91mm, with the base of this lip a height of 2.5mm from the top of the main body, and the top of the lip at a height of 2.85mm from the top of the main body. So a 0.35mm thick lip.
*   **Top Surface:** On top of the lip is an additional surface with a diameter of 91mm and height of 4mm. Above this section is an additional small flange of 2mm height with a slightly larger diameter.
*   **Lip Overhang:** The small 2mm flange should overhang by 0.75mm on each side over the top of the lower 4mm section.
*   **Center Hole:** There should be a circular hole through the insert that can be adjusted to fit different router bits. I need to control the diameter of this hole.

I want the overall design to be quite precise, with relatively high resolution.

I would like the following parameters in my OpenSCAD file:

*   `bit_diameter_inches`: The diameter of the center hole in inches.
*   `tab_overhang`: The overhang of the tab on each side in mm, should default to 0.75mm
*   `resolution`: The number of segments used for cylinders, should default to 60.

Could you generate an OpenSCAD file based on these specifications? I'm pretty new to OpenSCAD, so the simpler the code the better!

[Assistant]
boschroutertableplates.scad:
```
//Bit diameter
in=1.5;
//overhang of tab
tabhang=.75;
//Resolution
res=60;
//Calculation
in2mm=in*25.4;
diatabhang=2*tabhang;

module insert(){
union(){
union(){
    cylinder(2.5, d=97.5, $fn=60);
    translate([0,0,2.5]) cylinder(2.85, d=91, $fn=60);
}
   difference(){
       union(){
           translate([0,0,5.35]) cylinder(4, d=91, $fn=res);
           translate([0,0,7.35]) cylinder(2, d=91+diatabhang, $fn=res);
       }
           translate([0,0,5.35]) cylinder(6, d=88, $fn=res);
}
}
}

difference(){
    insert();
    cylinder(5.35, d=in2mm, $fn=res);
}
```


[User]
Hey, I'm trying to design a modular base for tabletop gaming terrain, specifically something compatible with OpenForge. I've seen some designs, but I want to create something parametric so I can adjust it easily.

Essentially, I need a rectangular base that's made up of a grid of smaller squares. I want to be able to set the overall size of the base in terms of how many of these smaller squares it is, let's call that `x` and `y`. So a base that's 2x3 would have two small squares across and three deep. Each of these small squares should be 25mm each.

Additionally, I need to be able to optionally add edge pieces to any side of the rectangle. These edge pieces are used to attach to other tiles and so should be 12.5 mm each. I would want to be able to control which edges have these additions - left, right, front, back - with boolean parameters. So, if I set `left_edge` to true, I'd get the edge piece on the left side. The edges will be the same thickness as the rest of the base.

The base should have a filled in section. Around the border of the filled section (between the main fill and the edge pieces if they exist) should be a support structure that forms the grid. These supports should be 9.2mm x 9.2mm x 5.5mm. The overall base (not just the supports) should have a height of 6mm. I imagine this would be a two-layer thing, with the grid being inside the base and the fill covering the main space with a 1mm top border.  The grid should also fill up the edge areas with support pieces if they are requested.

It seems like this could be done with OpenSCAD's `for` loops and conditional statements. Can you help me generate an OpenSCAD file or files with this functionality? I'm not using any specific libraries right now.

[Assistant]
cut_stone_full_base.scad:
```
/* [Base Tile Size] */
x = 2; //[1,2,3,4,5,6]
y = 2; //[1,2,3,4,5,6]

/* [Edge Tile Support] */
// Size of edge tile addition, 9.2 is standard for openforge
/*
edge = 12.5;
left_edge = "false"; // [false,true]
right_edge = "false"; // [false,true]
front_edge = "false"; // [false,true]
back_edge = "false"; // [false,true]
*/

module stone_base(x,y, left_edge="false",right_edge="false",front_edge="false",back_edge="false",edge=12.5) {
    l = left_edge == "true"?edge:0;
    r = right_edge == "true"?edge:0;
    f = front_edge == "true"?edge:0;
    b = back_edge == "true"?edge:0;
    length = 25*x+l+r;
    width = 25*y+f+b;
    xblocks = floor(length / 10.2);
    yblocks = floor(width / 10.2);

    color("Grey") intersection() {
        union() {
            for (i = [0:xblocks]) {
                for (j = [0:yblocks]) {
                    if (i == 0 || j == 0 || i == xblocks || j == yblocks) {
                        translate([i*10.2,j*10.2,0]) cube([9.2,9.2,5.5]);
                    }
                }
            }
        }
        cube([length, width, 6]);
    }
    color("Grey") translate([1,1,0]) cube([length-2, width-2, 6]);
}

stone_base(x,y,left_edge,right_edge,front_edge,back_edge,edge);

```


[User]
Hey there! I'm looking to create some customizable bases for tabletop gaming, and I'd like to use OpenSCAD to do it. I've got some specific ideas in mind that I think could be really useful.

First off, the bases should be tileable and the base size should be adjustable. I'd like to be able to define the X and Y dimensions of the base in terms of tile units, and I'd like to specify the size of a single square tile, with options for 25mm, 1 inch (25.4mm) and "wyloch" (31.75mm) sizes.

The bases should also support OpenLOCK connections. I want to choose between having openlock connections as a standard "true", a triplex option or not having them at all. In terms of the connections themselves, I'd like to have the option for both regular single OpenLOCK clips and a triplex version. The system needs to support the standard positive and negative connection pieces as well as connection supports.

In addition to openlock, I'd like to include magnet holes in the bases. I should be able to adjust the diameter of the magnet holes, with an option to set it to zero to eliminate them entirely. I need to be able to set a priority to decide whether magnets or openlock clips win when the two would overlap.

I'd also like some options for the base style. I'd like to choose between a "plain" base and one that looks like it's made of "stone" blocks. I need to be able to specify the shape of the tile. I'd like to be able to choose between "square", "diagonal", and "curved" bases.

Finally, I would like to have an option to include support for "dynamic floors" for a particular style of terrain that involves placing small support beams into holes cut into the base.

I'm not sure if this all makes sense, but I think it should be enough to get started. I'm primarily interested in generating the `.scad` files to define this design, and I'd like to make sure that they're parametric. It seems like the best way to do this would be to have a primary `.scad` file that includes modules and functions. I'm also not sure if any extra libraries are needed for this. Could you please create the SCAD code? Thanks so much!

[Assistant]
bases.scad:
```
/* [Base Tile Size] */
x = 2; //[1,2,3,4,5,6]
y = 2; //[1,2,3,4,5,6]

/* [Square Basis] */
// What is the size in mm of a square?
square_basis = "inch"; // [25mm:Dwarven Forge/Hirstarts, inch:OpenLOCK, wyloch:Wyloch]

/* [OpenLOCK] */
openlock = "true";// [true,triplex,false]

/* [Magnets] */
// Size of hole for magnet.  6 works well for 5mm buckyball style magnets.  0 to eliminate.
magnet_hole = 6;

/* [Priority] */
// Do you want openlock or magnets to win when the two conflict
priority = "openlock"; // [openlock,magnets]

/* [Style] */
// What should the base look like on the exterior
style = "plain"; // [stone,plain]

/* [Shape] */
// What type of tile is this for
shape = "square"; // [square,diagonal,curved]

/* [Dynamic Floors] */
// Add support for dynamic floors
dynamic_floors = "false";

/*
 * Openlock connection bay
 */
module openlock_chamber(buffer=0) {
    translate([-buffer,-7,1.4]) cube([2+buffer,7*2,4.2]);
    hull() {
        translate([0,-6,1.4]) cube([2,6*2,4.2]);
        translate([3+0.01,-5,1.4]) cube([2,5*2,4.2]);
    }
    translate([5,-5,1.4]) cube([8,5*2,4.2]);
    translate([7.55,-5.25,1.4]) cube([6,5.5*2,4.2]);
}

module openlock_supports(buffer=0) {
    translate([0-buffer*2,-0.5,1.4-buffer]) cube([10+buffer*2,1,4.2+buffer*2]);
}

module openlock_positive() {
    translate([0,-8,0]) cube([2,16,6]);
}

module openlock_negative() {
    difference() {
        openlock_chamber(1);
        //openlock_supports(1);
    }
}

module magnet_positive(magnet_hole=5.5) {
    if (magnet_hole > 0) {
        translate([magnet_hole/2+1,0,0]) cylinder(6,magnet_hole/2+1,magnet_hole/2+1, $fn=100);
    }
}

module magnet_negative(magnet_hole=5.5) {
    if (magnet_hole > 0) {
        translate([magnet_hole/2+1,0,1]) cylinder(8,magnet_hole/2,magnet_hole/2, $fn=100);
        translate([magnet_hole/2+1,0,-1]) cylinder(10,.9,.9,$fn=50);
    }
}

module center_connector_positive(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if (edge == 1) {
        if (priority == "openlock" && (single || triplex)) {
            openlock_positive(magnet_hole);
        } else {
            magnet_positive(magnet_hole);
        }
    } else {
        if (priority == "openlock" && triplex) {
            openlock_positive(magnet_hole);
        } else {
            magnet_positive(magnet_hole);
        }
    }
}

module center_connector_negative(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if (edge == 1) {
        if (priority == "openlock" && (single || triplex)) {
            openlock_negative(magnet_hole);
        } else {
            magnet_negative(magnet_hole);
        }
    } else {
        if (priority == "openlock" && triplex) {
            openlock_negative(magnet_hole);
        } else {
            magnet_negative(magnet_hole);
        }
    }
}

module joint_connector_positive(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if(single || triplex) {
        openlock_positive();
    }
}

module joint_connector_negative(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if(single || triplex) {
        openlock_negative();
    }
}

module openlock_base(x,y,square_basis,
        shape="square",style="plain",magnet_hole=6,openlock="true",priority="openlock",dynamic_floors="false") {
    single = openlock == "true" ? true : false;
    triplex = openlock == "triplex" ? true : false;
    df = dynamic_floors == "true" ? true : false;
    edge_width = magnet_hole >= 5.55 ? magnet_hole + 1 : 6.55;
    difference() {
        union() {
            if (style == "stone") {
                stone_base(x,y,square_basis,shape,edge_width);
            } else if (style == "plain") {
                plain_base(x,y,square_basis,shape,edge_width);
            }
            if (df) {
                cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([square_basis*x-square_basis/2-4.75,0,0]) cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([0,square_basis*y-square_basis/2-4.75,0]) cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([square_basis*x-square_basis/2-4.75,square_basis*y-square_basis/2-4.75,0]) cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([square_basis/2+3.75,square_basis/2+3.75,0]) cube([square_basis*x-(square_basis/2+3.75)*2,square_basis*y-(square_basis/2+3.75)*2,6]);
                if (x > 2) {
                    for ( i = [2 : x-1] ) {
                        translate([(i-.5)*square_basis-9.5/2,0,0]) cube([9.5,square_basis/2+4.75,6]);
                        translate([(i-.5)*square_basis-9.5/2,square_basis*y-square_basis/2-4.75,0]) cube([9.5,square_basis/2+4.75,6]);
                    }
                }
                if (y > 2) {
                    for ( i = [2 : y-1] ) {
                        translate([0,(i-.5)*square_basis-9.5/2,0]) cube([square_basis/2+4.75,9.5,6]);
                        translate([square_basis*x-square_basis/2-4.75,(i-.5)*square_basis-9.5/2,0]) cube([square_basis/2+4.75,9.5,6]);
                    }
                }
            }

            for ( i = [0 : y-1] ) {
                translate([0,square_basis*(i+1)-square_basis/2,0]) center_connector_positive(y,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*x,square_basis*(i+1)-square_basis/2,0]) rotate([0,0,180]) center_connector_positive(y,i,magnet_hole,single,triplex,priority);
                }
            }
            if (y > 1) {
                for ( i = [1 : y-1] ) {
                    translate([0,square_basis*i,0]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    if (shape == "square") {
                        translate([square_basis*x,square_basis*i,0]) rotate([0,0,180]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    }
                }
            }
            for ( i = [0 : x-1] ) {
                translate([square_basis*(i+1)-square_basis/2,0,0]) rotate([0,0,90]) center_connector_positive(x,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*(i+1)-square_basis/2,square_basis*y,0]) rotate([0,0,-90]) center_connector_positive(x,i,magnet_hole,single,triplex,priority);
                }
            }
            if (x > 1) {
                for ( i = [1 : x-1] ) {
                    translate([square_basis*i,0,0]) rotate([0,0,90]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    if (shape == "square") {
                        translate([square_basis*i,square_basis*y,0]) rotate([0,0,-90]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    }
                }
            }
        }

        for ( i = [0 : y-1] ) {
            translate([0,square_basis*(i+1)-square_basis/2,0]) center_connector_negative(y,i,magnet_hole,single,triplex,priority);
            if (shape == "square") {
                translate([square_basis*x,square_basis*(i+1)-square_basis/2,0]) rotate([0,0,180]) center_connector_negative(y,i,magnet_hole,single,triplex,priority);
            }
        }
        if (y > 1) {
            for ( i = [1 : y-1] ) {
                translate([0,square_basis*i,0]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*x,square_basis*i,0]) rotate([0,0,180]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                }
            }
        }
        for ( i = [0 : x-1] ) {
            translate([square_basis*(i+1)-square_basis/2,0,0]) rotate([0,0,90]) center_connector_negative(x,i,magnet_hole,single,triplex,priority);
            if (shape == "square") {
                translate([square_basis*(i+1)-square_basis/2,square_basis*y,0]) rotate([0,0,-90]) center_connector_negative(x,i,magnet_hole,single,triplex,priority);
            }
        }
        if (x > 1) {
            for ( i = [1 : x-1] ) {
                translate([square_basis*i,0,0]) rotate([0,0,90]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*i,square_basis*y,0]) rotate([0,0,-90]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                }
            }
        }
        if(df) {
            for ( i = [0 : x-1] ) {
                for ( j = [0 : y-1] ) {
                    translate([i*square_basis, j*square_basis,0]) translate([square_basis/2,square_basis/2,6-2.1]) cylinder(2.5,5.5/2,5.5/2, $fn=100);
                }
            }
        }
    }
}

module plain_base(x,y,square_basis,shape,edge_width) {
    difference() {
        intersection() {
            translate([0,0,0]) cube([square_basis*x, square_basis*y, 6]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([x,y,1]) cylinder(8,square_basis,square_basis,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis,0,0]) rotate([0,0,45]) {
                    cube([10.2/2,square_basis*x*2,6]);
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,6]);
                }
            }
        }

        intersection() {
            translate([edge_width,edge_width,0]) translate([1,1,-1]) cube([square_basis*x-((edge_width+1)*2),square_basis*y-((edge_width+1)*2),8]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([((x*square_basis)-edge_width)/square_basis,((y*square_basis)-edge_width)/square_basis,1]) cylinder(8,square_basis,square_basis,$fn=200);
            }
        }
    }
    if(shape == "diagonal") {
        intersection() {
            translate([x*square_basis,0,0]) rotate([0,0,45]) {
                cube([10.2/2,square_basis*x*2,6]);
                mirror([1,0,0]) cube([10.2/2,square_basis*x*2,6]);
            }
            translate([0,0,0]) cube([square_basis*x, square_basis*y, 6]);
        }
    }
}

module stone_base(x,y,square_basis,shape,edge_width) {
    module generate_stones() {
        intersection() {
            union() {
                for (i = [0:xblocks]) {
                    for (j = [0:yblocks]) {
                        translate([i*10.2,j*10.2,0]) cube([9.2 + (i==xblocks ? 10.2 : 0),9.2 + (j==yblocks ? 10.2 : 0),5.5]);
                    }
                }
            }
            cube([length, width, 6]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([x,y,1]) cylinder(8,square_basis,square_basis,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis,0,0]) rotate([0,0,45]) {
                    cube([10.2/2,square_basis*x*2,6]);
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,6]);
                }
            }
        }
    }

    module generate_interior() {
        intersection() {
            translate([1,1,0]) cube([length-2, width-2, 6]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([x,y,1]) cylinder(8,square_basis-0.5,square_basis-0.5,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis,0,0]) rotate([0,0,45]) {
                    cube([10.2/2-1,square_basis*x*2,6]);
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,6]);
                }
            }
        }
    }

    length = square_basis*x;
    width = square_basis*y;
    xblocks = floor(length / 10.2);
    yblocks = floor(width / 10.2);

    difference() {
        union() {
            generate_stones();
            generate_interior();
        }
        intersection() {
            translate([edge_width,edge_width,0]) translate([1,1,-1]) cube([square_basis*x-((edge_width+1)*2),square_basis*y-((edge_width+1)*2),8]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([((x*square_basis)-edge_width)/square_basis,((y*square_basis)-edge_width)/square_basis,1]) cylinder(8,square_basis,square_basis,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis-sqrt(5.1*5.1+5.1*5.1),0,-1]) rotate([0,0,45]) {
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,8]);
                }
            }
        }
    }
}

function keyLookup (data, key) = search(key, data, num_returns_per_match=1)[0];

basis = [
    ["25mm", 25],
    ["inch", 25.4],
    ["wyloch", 31.75]
];
square_basis_number = basis[keyLookup(basis, [square_basis])][1];

color("Grey") openlock_base(x,y,square_basis_number,shape=shape,style=style,magnet_hole=magnet_hole,openlock=openlock,priority=priority,dynamic_floors=dynamic_floors);

```


[User]
Hey, I'm looking to create a customizable Android figurine, similar to the classic Android logo, but I want it to be 3D printable with snap-fit assembly. I've seen a few designs floating around, but I'd really like to have one that's very configurable and robust and that doesn't rely on glue. I want to be able to change the overall size, add custom text on the body, and have the arms rotate, and the legs should be a good size so that the figure is stable when standing.

Here's a breakdown of what I'm picturing:

**Overall Structure:**

*   The figurine should be composed of several parts: head, body, two arms, two legs, and a base.
*   I'd like each part to be printable without supports, and all of the parts should be designed to easily snap together without glue.
*   I'm hoping to be able to define a single parameter that would change the overall size of the figurine.
*   I'd like some flexibility in what part I am rendering. For example, I'd like to be able to render all the parts, or just the body, or just the arms for testing.

**Specific Part Details:**

*   **Head:** Should resemble the classic Android head shape, with the two antennae. The neck should be designed to snap into the body, ensuring a good fit.
*   **Body:** A cylindrical body with recesses for the arms and legs to attach. I would like two lines of customizable text that can be embossed on the body. It should have an opening at the top for the neck to connect with the head. The depth of the embossing should be a configurable parameter.
*   **Arms:**  These should attach to the body with a ball and socket type joint to allow them to rotate.
*   **Legs:**  They should attach firmly to the body, with a simple snap fit. I'd like to make them configurable so they can be adjusted to ensure the figure is stable.
*   **Base:**  A stable platform that the figure can stand on. It should also have recesses for the legs to rest in, and they should be placed to make the figure stand up straight.

**Customization:**

*   **Overall Size:** I want to be able to specify the approximate assembled height (e.g., 125mm, 200mm). The entire figure should scale proportionally from this base height.
*   **Text:** Two lines of text on the body (top and bottom) should be configurable with custom text strings, font, and font size. I'd like to be able to control the vertical position of the text so it looks good on the body, and the depth of the embossing.
*   **Render Modes:**  I'd like to be able to render just individual parts, as well as a preview that is all of the parts assembled, and a preview that is an exploded view so I can see how all the parts fit together. I would like to have one final mode where it renders all of the parts for a single print.
*   **Render Quality:** I want a way to specify the quality of the render, to help when testing, or for final, high resolution renders.
*   **Font Choice**: I'd like to be able to choose from a few different fonts, including orbitron, knewave, and a few others.

**Libraries**
I know that the `Write` library would be helpful for adding text, so please be sure to use that in your design. I'm not really sure if any other libraries would be helpful here.

This should allow others to make their own Android figurines with a personal touch.

[Assistant]
EverydayPineapple-AndroidGuy-customizer.scad:
```

// Slightly Better Android Guy
// Customized by EverydayPineapple from vorpal's
// design with a few improvements.
// 1. made the legs fit
// 2. made the leg holes go all the way through

//
// Customizable Android Guy Box with Text by Vorpal
//
// Based on Thingiverse thing:7734 "Android Guy Box with Base" by rhmorrison
// which itself was based on thing:5917 "Android Guy Box" by irdfang
// which was inspired by thing:1902 "Android Guy" by xtremd but reimplemented in openscad
//
// This project also uses thing:16193 "Write" by HarlanDMii
//
// My contributions are:
//
// 1. Made it all into a single openscad program that is customizable using makerbot customize.
//
// 2. Made it so the arms are moveable. The other versions have fixed arms because it's a
//    square peg. I also made a socket and cut-ball arrangement so the parts just snap
//    together without glue. Although you may need to heat up the body hole to get the arms in.
//
// 3. Made numerous small adjustments to the sizes of things to make them more closely match
//    the proportions of the real android logo. The prior versions were a little too tall.
//
// 4. Added the ability to emboss 2 lines of text on the body. This was originally done so I
//    could make trophy-like gifts for my son's NJ Governor School team who wrote some Android
//    apps for Erikson Telecom. I made a large sized version for the mentor of the group.
//
// 5. Made it so the script could either generate individual parts or generate the entire
//    project on a single platen which is printable with no supports. Also added two "preview"
//    modes that are not meant to be printed. One shows the entire thing assembled, the other
//    is an exploded view. Again, don't try to print those, you would need tons of supports.
//

use <write/Write.scad>

//
// The parameters below may be changed by the customizer
//
// BEGIN CUSTOMIZER

/* [Android Guy Parameters] */

//select part(s) to render
parts_to_render = 8; // [1:head, 2:body, 3:arm, 4:leg, 5:base, 6:preview_assembled, 7:preview_exploded, 8:all]

// Draft for preview, production for final
Render_Quality = 24;    // [24:Draft,60:Production,100:UltraPremium]

// mm
text_height=8; // [6:15]

text_font = "orbitron.dxf";//[write/Letters.dxf,write/orbitron.dxf,write/knewave.dxf,write.braille.dxf,write/Blackrose.dxf]

// top line of text
text1 = "@EvrydyPineapple";
//bottom line of text
text2 = "";
//move the text up by this much, mm
text_shift = 0; // [-20:20]

// approx. height when assembled, mm
Project_Size = 125; // [100:250]

// END CUSTOMIZER

//
// The parameters below are not meant to be changed by the customizer
//

arm_r = 9*1;
// how deep do the letters cut
emboss_depth = 3*1;
$fn = Render_Quality;
leg_h = 25*1;
scale_factor = 156*1;  // at project_size of this size the scaling factor is 1

module body() {
	difference(){
		union(){
			cylinder(r=35,h=53);
			translate([0,0,-14]) cylinder(r=21,h=70);
			rotate_extrude(convexity = 15) translate([21,0,0]) circle(r=14);
		}

		// hollow it out
		translate([0,0,-7]) cylinder(r=31.5,h=78);

		// holes for arms
		translate([0,0,36]) {
			rotate(90, [0,1,0]) cylinder(r=5, h=80, center=true);
		}

		// holes for legs
		translate([14.7,0,-28]) cylinder(r=8.4,h=30);
		translate([-14.7,0,-28]) cylinder(r=8.4,h=30);

		writecylinder(text1,[0,0,0],radius=35,height=50,t=3,up=text_shift+1.2*text_height/2,h=text_height,font=text_font);
		writecylinder(text2,[0,0,0],radius=35,height=50,down=0-text_shift+1.2*text_height/2,t=3,h=text_height,font=text_font);
	}
}

module arm() {
	rotate([90,270,0]){
	union(){
		rotate(90, [0,1,0]) translate([-2,0,10]) difference() {
			union() {
				cylinder(r=4.5, h=10, center=true);
			 	translate([0,0,5]) cylinder(r1=4.5,r2=5.5, h=2, center=true);
			 	translate([0,0,8.5]) cylinder(r1=5.5,r2=3, h=5, center=true);
			}
		}
		cylinder(r=arm_r,h=28);
		sphere(r=arm_r);
		translate([0,0,28])sphere(r=arm_r);
		}
	}
}

module base() {
	union() {
		rotate([180,0,0]) {
			difference(){
				union(){
					cylinder(r=35,h=70);
					translate([0,0,-14]) cylinder(r=21,h=70);
					rotate_extrude(convexity = 10)
					translate([21,0,0])
						circle(r=14);
				}
				translate([0,0,50])
				cube([100,100,100], center=true);
				translate([14.7,0,-44])
					cylinder(r=9,h=45);
				translate([-14.7,0,-44])
					cylinder(r=9,h=45);
			}
		}
		cylinder(r1=50,r2=47,h=6);
	}
}

module head() {
	rotate([0,180,0]){
	union(){
		translate([0,0,-5]) cylinder(r=31.25, h=16);
		translate([0,0,-5])
		difference(){
			sphere(r=35);
			cylinder(r=35,h=35);
			translate([15,-25,-16]) sphere(r=5);
			translate([-15,-25,-16]) sphere(r=5);
		}
		translate([-20,0,-51]) rotate([0,15,0]) cylinder(r=3,h=20);
		translate([20,0,-51]) rotate([0,-15,0]) cylinder(r=3,h=20);
		translate([20,0,-51]) sphere(r=3,h=20);
		translate([-20,0,-51]) sphere(r=3,h=20);
		}
	}
}

module leg() {
	union(){
		cylinder(r=8.9,h=leg_h);
		translate([0,0,leg_h]) cylinder(r=8.3,h=8);
		translate([0,0,leg_h]) rotate_extrude(convexity = 10) translate([5.5,0,0]) circle(r=4);
	}
}

color("LightGreen")
scale([Project_Size/scale_factor, Project_Size/scale_factor, Project_Size/scale_factor]) {

	if (parts_to_render == 1) {
		head();
	}
	if (parts_to_render == 2) {
		body();
	}
	if (parts_to_render == 3) {
		arm();
	}
	if (parts_to_render == 4) {
		leg();
	}
	if (parts_to_render == 5) {
		base();
	}

	if (parts_to_render == 6) {
		// approximate how it would look assembled
		union() {
			base();
			translate([14.5,0,28+leg_h/2]) rotate([0,180,0]) leg();
			translate([-14.5,0,28+leg_h/2]) rotate([0,180,0]) leg();
			translate([0,0,50]) body();
			translate([44,0,88]) rotate([90,0,-90]) arm();
			translate([-44,0,84]) rotate([90,180,90]) arm();
			translate([0,0,105]) head();
		}
	}

	if (parts_to_render == 7) {
		// exploded parts view
		union() {
			base();
			translate([14.5,0,1.3*(28+leg_h/2)]) rotate([0,180,0]) leg();
			translate([(-14.5),0,1.3*(28+leg_h/2)]) rotate([0,180,0]) leg();
			translate([0,0,1.5*(50)]) body();
			translate([1.5*(44),0,1.3*88]) rotate([90,0,-90]) arm();
			translate([1.5*(-44),0,1.3*84]) rotate([90,180,90]) arm();
			translate([0,0,1.4*105]) head();
		}
	}

	if (parts_to_render == 8) {
		// create a production plate layout with all parts
		translate([100,-30,11]) head();
		translate([0,70,14])    body();
		translate([50,0,arm_r])    arm();
		translate([50,80,arm_r]) arm();
		translate([80,50,0]) leg();
		translate([80,80,0]) leg();
		translate([-20,-20,0]) base();
	}

} // end scale
```


[User]
Hey, I'm looking to create a customizable powerpole connector plate and I think OpenSCAD is the way to go. I'd like it to be able to hold multiple boxes of powerpole connectors, and I need to be able to customize the size of each box as well as the overall plate.

Specifically, I envision a design where I can define:

*   **The number of boxes:** Up to three separate boxes for powerpole connectors.
*   **Box dimensions:** For each box, I'd like to specify the width (number of connectors wide) and the height (number of connectors tall). I should be able to set these independently for each box. If I don't want a certain box, I should be able to disable it.
*   **Support:** I'd like to add an amount of support material around the boxes. This should be customizable in how much is added.
*   **Connector fit:** I need to adjust the internal margin within the powerpole box, to allow for tolerances between prints. I need to be able to modify the internal margin.
*   **Powerpole depth:** I need to adjust the depth of the powerpole box, determining how far it extends behind the plate.
*   **Plate Depth:** The overall depth of the plate, including the border and screw holes.
*  **Plate Thickness:** The thickness of the main (middle) part of the plate.
*   **Plate Dimensions:** The overall width and height of the plate should be configurable.
*   **Plate Border:** The width of the border around the plate.
*   **Screw Holes:** I need to include screw holes, and I should be able to specify:
    *   The shank radius of the screw hole
    *   The radius of the countersink
    *   The depth of the countersink
    *   The distance between the screws
    *  Be able to disable them entirely.
*  **Corners:** I need to be able to specify the corner radius (or disable them completely).

I'd also like to utilize the `MCAD/boxes.scad` library from the MCAD library. It has a helpful `roundedBox` function that I can use for the main plate, and I'd like to keep using it.

Could you generate the necessary OpenSCAD files to achieve this? Let me know if you have any questions or if I've missed anything.

[Assistant]
powerpole_combined_customizable.scad:
```

// all dimentions in mm

// The number of connectors wide for box 1
box1_w = 2; // [0:6]
// The number of connectors tall for box 1
box1_h = 2; // [0:6]
// The number of connectors wide for box 2 (0 to disable box)
box2_w = 2; // [0:6]
// The number of connectors tall for box 2 (0 to disable box)
box2_h = 2; // [0:6]
// The number of connectors wide for box 3 (0 to disable box)
box3_w = 0; // [0:6]
// The number of connectors tall for box 3 (0 to disable box)
box3_h = 0; // [0:6]

// The amount of extra spuport to add around each box
support=0; // [0:9]

// The thickness of the margin inside the powerpole box (adjust down if it's too tight, up if it's too loose)
pp_margin=0.75;

// The length desired for each powerpole box (how far behind the box to extend); 25mm will completely cover the powerpoles
pp_depth=25;

// How deep to make the plate total (the depth of the border and screw holes)
plate_depth=5;

// The thickness of the main (middle) part of the plate
plate_thickness=2;

// The width of the plate (side to side). def 70.5mm copied from levitron standard
plate_width=70.5;

// The height of the plate (top to bottom). def 115mm copied from levitron standard
plate_height=115;

// the width of the plate border
plate_border=4;

// The radius of the screw; note most printers will actually print this a bit smaller than
// specified due to expansion, so adjust this up if the screws don't fit. Actual exact value
// for most boxes would be 1.75, but we added an extra .5 diameter because it didn't fit.
// Set this to 0 to disable the screw holes
plate_screw_shank=2;

// The radius of the top of the countersink hole for the screw
plate_screw_top=3.75;

// How deep the counter-sink for the screw should go
plate_screw_top_depth=2;

// The radius of the rounded corners on the plate. 0 for squared corners
plate_corners=3;

// The distance between the screws (83.3mm is standard for US wall boxes)
screw_distance = 83.3;

include <MCAD/boxes.scad>

// all dimentions in mm

module powerpole_box(width=2, height=2, box_only=false, length=25, margin=0.75, support=0) {
    $fa=5;
    $fs=0.2;

    wall_width = 2;
    indent_wall_width = 1;
    indent_margin = margin; // This gives us extra space to play with inside the connector so it isn't too tight
    indent_adj_width = indent_wall_width*indent_margin;
    indent_adj_gap = indent_wall_width*(1-indent_margin);
    combined_wall_width = wall_width+indent_wall_width;
    combined_wall_width_with_margin = wall_width + indent_adj_width;

    pp_diameter = 9;
    pp_length = length;
//    pp_length=15;

    pin_diameter=2.65;
    pin_radius = pin_diameter / 2;
    pin_offset = 10;

    pp_indent_width = 5;
    pp_indent_offset = (pp_diameter-pp_indent_width)/2;

    box_width = pp_diameter * width;
    box_height = pp_diameter * height;

    full_width = box_width + wall_width*2;
    full_height = box_height + wall_width*2;

    // This allows you to use the box_only mode to subtract and have it leave visible holes even in preview mode
    // since the walls won't line up perfectly and cause issues.
    v_offset = box_only ? -0.001 : 0;

    // Center the bottom of the box on the origin to make it easier to use in other models
    translate([-(full_width/2), -(full_height/2), v_offset])
    difference() {

        // Draw the outside box
        union() {
            cube([full_width, full_height, pp_length]);
            if (!box_only) {
                difference() {
                    // First Draw four boxes to add support
                    union() {
                        translate([-support, -support, 0]) {
                            cube([support, full_height + (support * 2), support]);
                            cube([full_width + (support * 2), support, support]);
                        }
                        translate([full_width+support, full_height+support, 0]) {
                            rotate([0,0,180]) cube([support, full_height + (support * 2), support]);
                            rotate([0,0,180]) cube([full_width + (support * 2), support, support]);
                        }
                    }
                    // Next chop those off so only half a box remains to give a slant
                    translate([-support, -support, 0]) {
                        rotate([0,-45,0]) cube([support*2, full_height + (support * 2), support]);
                        rotate([45,0,0]) cube([full_width + (support * 2), support*2, support]);
                    }
                    translate([full_width+support, full_height+support, 0]) {
                        rotate([0,-45,180]) cube([support*2, full_height + (support * 2), support]);
                        rotate([45,0,180]) cube([full_width + (support * 2), support*2, support]);
                    }
                }
            }
        }

        if (!box_only) {
            // Hollow out box_width + the indent_margin
            translate([combined_wall_width_with_margin, combined_wall_width_with_margin, -0.5]) cube([box_width-indent_adj_width*2, box_height-indent_adj_width*2, pp_length+1]);

            // Open the notches for the housings
            for (x = [0:width-1]) {
                offset=wall_width+(pp_diameter * x)+pp_indent_offset;
                translate([offset,wall_width,-0.5])
                    cube([pp_indent_width, indent_wall_width, pp_length+1]);
                translate([offset,full_height-wall_width-indent_wall_width,-0.5])
                    cube([pp_indent_width, indent_wall_width, pp_length+1]);
            }
            for (y = [0:height-1]) {
                offset=wall_width+(pp_diameter * y)+pp_indent_offset;
                translate([wall_width,offset,-0.5])
                    cube([indent_wall_width, pp_indent_width, pp_length+1]);
                translate([full_width - wall_width - indent_wall_width, offset,-0.5])
                    cube([indent_wall_width, pp_indent_width, pp_length+1]);
            }

            if (width>1) {
                // Add holes for the pin(s)
                for (x = [1:width-1]) {
                    translate([wall_width+(pp_diameter*x), -0.5, pin_offset])
                        rotate([-90,0,0])
                        cylinder( box_height + combined_wall_width*2+1, pin_radius, pin_radius );
                }
            }

            if (height>1) {
                // Add holes for the pin(s)
                for (y = [1:height-1]) {
                    translate([-0.5, wall_width+(pp_diameter*y), pin_offset])
                        rotate([0,90,0])
                        cylinder( box_width + combined_wall_width*2+1, pin_radius, pin_radius );
                }
            }
        }
    }
}

//powerpole_box(support=7, support=7, width=3, height=2);

// size - [x,y,z]
// radius - radius of corners
module bottomrounded_box(size, radius)
{
    intersection() {
        translate([size[0]/2, size[1]/2, size[2]])
            roundedBox([size[0], size[1], size[2]*2], radius);
        cube(size);
    }
}

module wall_plate(depth=4.5,
                  thickness=2,
                  width=70.5,
                  height=115,
                  border=4,
                  screw_separation = 83.3,
                  screw_shank=2,
                  screw_top=3.5,
                  screw_top_depth=2,
                  corners=5) {
    plate_width = width;
    plate_height = height;
    plate_depth = depth;
    plate_border_width = border;
    plate_middle_thickness = thickness;
    screw_distance = screw_separation;
    screw_base = screw_shank;
    screw_top = screw_top;
    screw_taper_depth = screw_top_depth;

    // calculate the plate offsets
    plate_padding_x = plate_width / 2;
    plate_padding_y = plate_height / 2;

    translate([-plate_padding_x, -plate_padding_y, 0]) difference() {
        union() {
            difference() {
                bottomrounded_box([plate_width, plate_height, plate_depth], corners);
                // Subtract the middle/base area
                translate([plate_border_width, plate_border_width, plate_middle_thickness])
                    cube([plate_width - (plate_border_width*2), plate_height - (plate_border_width * 2), plate_depth - plate_middle_thickness + 0.01]);
            }

            // Draw cylinders for the screw holes
            if (screw_base > 0) {
                screw_guide_radius = screw_base + plate_border_width;
                translate([plate_width / 2, plate_height / 2 - screw_distance / 2, 0]) {
                    cylinder(plate_depth, screw_guide_radius, screw_guide_radius);
                }
                translate([plate_width / 2, plate_height / 2 + screw_distance / 2, 0]) {
                    cylinder(plate_depth, screw_guide_radius, screw_guide_radius);
                }
            }
        }

        if (screw_base > 0) {
            // Draw the two screw holes
            translate([plate_width / 2, plate_height / 2 - screw_distance / 2, -0.01]) {
                cylinder(plate_depth + 0.05, screw_base, screw_base);
                cylinder(screw_taper_depth, screw_top, screw_base);
            }
            translate([plate_width / 2, plate_height / 2 + screw_distance / 2, -0.01]) {
                cylinder(plate_depth+0.05, screw_base, screw_base);
                cylinder(screw_taper_depth, screw_top, screw_base);
            }
        }
    }
}

//powerpole_box(2,2,length=5);

$fa=5;
$fs=0.2;

box1 = box1_w&&box1_h;
box2 = box2_w&&box2_h;
box3 = box3_w&&box3_h;

boxes = box1 && box2 && box3 ? [[box1_w,box1_h],[box2_w,box2_h],[box3_w,box3_h]] :
    box1 && box2 ? [[box1_w,box1_h],[box2_w,box2_h]] :
    box1 ? [[box1_w,box1_h]] : [];

screw_padding = 5;
usable_space = screw_distance - screw_padding;
separation = usable_space / len(boxes);
padding = separation / 2;
echo(separation);

// Draw the plate
difference() {
    wall_plate( depth=plate_depth,
                thickness=plate_thickness,
                width=plate_width,
                height=plate_height,
                border=plate_border,
                screw_separation=screw_distance,
                screw_shank=plate_screw_shank,
                screw_top=plate_screw_top,
                screw_top_depth=plate_screw_top_depth,
                corners=plate_corners);

    for (x=[0:len(boxes)-1]) {
        pos = (separation * x) - (usable_space / 2) + padding;
        echo(usable_space/2 - pos);
        translate([0,pos, 0])
            powerpole_box(width=boxes[x][0],height=boxes[x][1],margin=pp_margin,length=pp_depth,box_only=true);
    }
}

for (x=[0:len(boxes)-1]) {
    pos = (separation * x) - (usable_space / 2) + padding;
    echo(usable_space/2 - pos);
    translate([0,pos, 0])
        powerpole_box(width=boxes[x][0],height=boxes[x][1],margin=pp_margin,length=pp_depth,support=support,box_only=false);
}

```


[User]
I'm looking to create a parametric stand for my bottle trays, and I'd like it to be customizable. I've got a design in mind, and I'd like to specify the inside dimensions, wall thickness, and where the openings will be.

Specifically, I need the stand to have the following parameters:

*   **`insideLength`**: The internal length of the stand.
*   **`insideWidth`**: The internal width of the stand.
*   **`insideHeight`**: The internal height of the stand.
*   **`wallThick`**: The thickness of the walls.

I also want to be able to control the openings in the stand. I'd like to be able to choose between these options for `Opening`:

*   **`0`**: Creates a closed cage (no openings).
*   **`1`**: Opens along the length (x-axis).
*   **`2`**: Opens on one side (y-axis).
*   **`3`**: Opens along both sides (forming a "U" shape).
*   **`4`**: Opens at both ends.

The stand should have a base platform, and the holes for the shelves to slot into. For the shelves, I want there to be holes on the x- and y- axis, and these should be symmetrical. The holes should have a diameter of `holeDia`, which will be set to 24, and should be automatically spaced so that they fill the space and are evenly spaced. I'm happy for there to be an offset from the edges of the stand, but I don't think that should be parametric.

I'm not worried about the complexity of the code, just that it should be clear, well commented and easy to use. I'm happy to use libraries such as BOSL2 if they will help.

[Assistant]
parametric_bottle_shelf.scad:
```
// Sizes

insideLength=150;
insideWidth =150;
insideHeight= 90;
wallThick=3;

// Options

Opening = 1; //[0:makes a cage with no opening, 1:open side along the length, 2:open at one end
             // 3:open at both sides, 4:open at both ends]

/*[Hidden]*/
holeDia = 24; //this is optimum and shouldn't be changed

// calculated variables

outsideLength=insideLength + (wallThick*2);
outsideWidth=insideWidth + (wallThick*2);
outsideHeight=insideHeight+wallThick;

holeSpacing = holeDia+(wallThick*2);

numberOfHolesLong=floor(insideLength/holeSpacing);
numberOfHolesWide=floor(insideWidth/holeSpacing);
numberOfHolesTall=floor(insideHeight/holeSpacing);

xoffset = (insideLength-(numberOfHolesLong*holeSpacing)+(wallThick*2))/2; // used to make holes
yoffset = (insideWidth -(numberOfHolesWide*holeSpacing)+(wallThick*2))/2; //symetrical side to side
zoffset = (outsideHeight -(numberOfHolesTall*holeSpacing)+wallThick)/2;

istart = holeSpacing/2+xoffset; // start position of first hole i=x axis
jstart = holeSpacing/2+yoffset; // j= y axis
kstart = holeSpacing/2+zoffset; // k=z axis

step = holeSpacing;

imax = insideLength-wallThick;
jmax = insideWidth-wallThick;
kmax = insideHeight-wallThick;

shelf(); // This only gets called once so needn't have been a module

if (Opening!=1 && Opening!=3) // only add first x side if Opening is not 1 or 3
xside();

if (Opening!=3) // only add second x side if Opening is not 3
translate ([0,outsideWidth-wallThick,0])
xside();

if (Opening!=2 && Opening!=4) // only add first y side if Opening is not 2 or 4
yside();

if (Opening!=4) // only add second y side if Opening is not 4
translate ([outsideLength-wallThick,0,0])
yside();

module shelf(){
difference(){
cube ([outsideLength, outsideWidth, wallThick]);
for (i=[istart:step:imax]){
    for (j=[jstart:step:jmax]){
        translate ([i,j,-1])
        cylinder (d=holeDia, h=wallThick+2);

            }// end of i
        }// end of j
    }// end of difference

} // end of module shelf

module xside(){

difference(){
cube ([outsideLength,wallThick,outsideHeight]);
   for (i=[istart:step:imax]){
    for (k=[kstart:step:kmax]){
           translate ([i,wallThick+1,k])
           rotate ([90,0,0])
           cylinder (d=holeDia, h=outsideWidth+2);

            }// end of i
        }// end of k

}// end of difference

}// end of module xside

module yside(){

difference(){
cube ([wallThick,outsideWidth,outsideHeight]);
   for (j=[jstart:step:jmax]){
    for (k=[kstart:step:kmax]){
           translate ([-1,j,k])
           rotate ([0,90,0])
           cylinder (d=holeDia, h=outsideLength+2);

            }// end of i
        }// end of k

}// end of difference

}// end of module yside

```


[User]
I'm looking to design a mounting bracket for a C14 power inlet, similar to the one I've already drafted but I'd like to make it fully parametric. I’d like the main plate to have rounded edges and be adjustable in length, width, and thickness. I need to accommodate a standard C14 inlet, which is 19.5mm x 27.3mm, but I want to parameterize those dimensions too, in case I need to fit a slightly different plug in the future.

The C14 inlet should be centered vertically on the plate, but I need to set a horizontal offset from the edge. The mounting screw holes should be placed symmetrically with respect to the center of the plate along the edges, and I'd also like to define their diameter and the distance between the pairs of screw holes, as well as their vertical offset from the edges of the plate. I need four mounting screw holes.

Additionally, I'd like the bracket to have some supporting vertical and horizontal extrusions. The horizontal ones will be along the edges of the top and bottom, and the vertical ones along the sides. I'd like these extrusions to also be fully parameterized. I'd also like a small, parameterized offset between the extrusions and edges of the main plate.

I would like the final result to use the `MCAD` library, with an overall design that has a single main plate with rounded corners, the aforementioned horizontal and vertical extrusions, a cutout for the C14 inlet, and mounting holes for screws, all fully parametric. I am not looking for a library, just for the files needed to generate the design described.

Could you please generate the necessary OpenSCAD files for me?

[Assistant]
Sides_Bottom_Bracket_rear_C14.scad:
```
length=80;
//opening size, a C14 appliance inlet is 19.5x27.3
open_x=27.4;
open_y=19.6;
screw_dist=40;

screw_m=3.1;

$fn=60;

difference(){
    union(){
        //plate
        intersection() {
            cube([length,60,4]);
            //round edges
            translate([0,4,0])union(){
                //corners
                translate([4,0,4])sphere(4);
                translate([4,52,4])sphere(4);
                translate([length-4,52,4])sphere(4);
                translate([length-4,0,4])sphere(4);
                //sides
                translate([4,0,0])cube([length-8,52,4]);
                translate([4,0,4])rotate(a=-90, v=[1,0,0])cylinder(r=4, h=52);
                translate([length-4,0,4])rotate(a=-90, v=[1,0,0])cylinder(r=4, h=52);
                translate([4,0,4])rotate(a=90, v=[0,1,0])cylinder(r=4, h=length-8);
                translate([4,52,4])rotate(a=90, v=[0,1,0])cylinder(r=4, h=length-8);
            }
        }
        //vertical extrusion support
        translate([length-13,0,4])cube([5,60,1]);
        //horizontal extrusion supports
        translate([0,7.5,4])cube([length-20,5,1]);
        translate([0,47.5,4])cube([length-20,5,1]);
    }
    //mounting holes
    translate([length-10.5,10,-0.1])cylinder(r=screw_m/2, h=5.2);
    translate([length-10.5,50,-0.1])cylinder(r=screw_m/2, h=5.2);
    translate([10,10,-0.1])cylinder(r=screw_m/2, h=5.2);
    translate([10,50,-0.1])cylinder(r=screw_m/2, h=5.2);
    //(c14) plug opening
    translate([10+screw_dist,30,-0.1])cylinder(r=1.55, h=4.2);
    translate([10,30,-0.1])cylinder(r=1.55, h=4.2);
    translate([(10+screw_dist/2)-(open_x/2),30-open_y/2,-0.1])cube([open_x,open_y,4.2]);
}
```


[User]
I'd like to design a pair of round glasses that can be 3D printed in one piece, without needing any supports. They should be adjustable to fit both kids and adults. I'd like to be able to tweak several parameters to achieve this.

Specifically, I need to control:

*   **Lens diameter:** The size of the lenses themselves.
*   **Temple size (width):** The overall width of the glasses, including the frames that sit on the sides of the head.
*   **Pupil distance:** The distance between the centers of the two lenses.
*   **Glasses thickness:** The thickness of the material used for the frames around the lenses and the nose bridge.
*   **Temple length:** The length of the arms that go over the ears.
*   **Lens thickness** How far the lenses protrude from the frame.

I'd prefer this to be a parametric design so I can easily change all of these values. I would like to use OpenSCAD to create the design. Please provide me with the complete set of OpenSCAD files necessary to render this design. I don't have any preference on which libraries are used, but please let me know if any are required.

[Assistant]
RoundGlasses.scad:
```
//Lens diameter
gdiam=47.5;
//Temple size (width of glasses).
tsize=135;
//Pupil distance
pd=70;
//Glasses thickness
th=4;
//Temple length
lscales=150;
//Thickness of the lenses
gheight=5;

$fn=64;

module EyeCylinder()
{
        difference()
        {
            union()
            {
                cylinder(d=gdiam+th*2, h=gheight);
                NosePad();
            }
            LensHole();
        }
}

module  LensHole()
{
    translate([0,0,-.1])
    cylinder(d=gdiam, h=gheight*2.2, center=true);
}

module NosePad()
{
    rotate([0,0,-25])
    intersection()
    {
        translate([gdiam/2,0,th/2])

        scale([1,1,.35])
        rotate([0,90,0])
        cylinder(r=15, h=th*2, center=true);

        scale(100) // The lower half only
        translate([-.5,-.5,-1])
        cube(1);

        cylinder(d=gdiam+th*2, h=gheight*15, center=true); // Inside the lens cylinder
    }
}

module Eye()
{
    EyeCylinder();
    translate([0,0,gheight])
    mirror([0,0,1])
    {
        offs=(tsize-pd)/2;

        translate([-offs,0,0])
        scale([offs-(gdiam+2*th)/2, gheight, gheight])
        translate([.65,0,.5])
        cube(1, center=true);

        translate([-offs,0,])
        scale([gheight,gheight,lscales])
        translate([0,0,.5])
        cube(1,center=true);
    }
}

module TwoEyes()
{
    translate([-pd/2,0,gheight]) // Center
    mirror([0,0,1])
    union()
    {
        Eye();
        translate([pd,0,0])
        mirror([1,0,0]) // Not necessary for a round lens
        Eye();
    }
}

module RoundGlasses()
{
    difference()
    {
        cylinder(d=gdiam+th*2, h=gheight);
        LensHole();
        translate([-pd/2,0,0])
        LensHole();
        translate([pd/2,0,0])
        LensHole();
        translate([-pd/2,-pd,-pd/2])
        cube(pd);
    }
    TwoEyes();
}

RoundGlasses();

```