[User]
I'm looking to design a custom phone dock that fits into a car's cup holder, and I'd like it to be parametric so I can adjust it for different phones and cars. I have some specific requirements and features in mind.

Essentially, I want a tapered cylinder that sits snugly in a cup holder, with a recess on the front angled back to hold the phone. The dock should also have a cutout for a charging cable plug and a channel to guide the cable out the back.

Here are the parameters I need:

*   **Cup Holder Dimensions:**
    *   `holder_top_diameter`: Diameter of the cup holder at the top.
    *   `holder_bottom_diameter`: Diameter of the cup holder at the bottom.
    *   `holder_height`: Height of the cup holder.

*   **Phone Dimensions:**
    *   `phone_x`: Width of the phone.
    *   `phone_y`: Depth of the phone.

*   **Dock Parameters:**
    *   `dock_angle`: Angle at which the phone leans back.
    *  `dock_z`: Depth at which the phone should be inset into the holder

*   **Back Rest:**
     *  `dock_rest`: Boolean, whether or not to have a back rest at all
    *   `dock_rest_z`: Height of the phone back rest.
    *   `dock_rest_x`: Width of the phone back rest.
    *   `dock_rest_y`: Depth of the phone back rest.

*   **Charge Plug Hole:**
    *   `plug`: Boolean, whether or not to have the hole at all
    *   `plug_x`: Width of the charging plug.
    *   `plug_y`: Depth of the charging plug.
    *   `plug_z`: Length of the charging plug (minus contacts).
    *   `plug_offset`: Distance of the charging plug from the front of the phone.

*   **Cable Channel:**
    *   `cable`: Boolean, whether or not to have the channel
    *   `cable_x`: Width of the cable routing channel.
    *   `cable_y`: Depth of the cable routing channel.

*   **Smoothness:**
    * `round_smoothness`: A variable to control the number of faces to create when rendering round objects

I also need:

*   The phone recess to be angled back as defined by `dock_angle`.
*   A shelf or support for the charging plug to stop it from being pushed down when the phone is inserted.
*   Some gouges to remove material where the phone dock isn't contacting the inside of the cup holder, to improve print quality

Please generate an OpenSCAD file that uses these parameters to create the phone dock. I'm not sure if there's a single library I should use but I would like to keep the code as modular as possible, using separate modules for the different parts of the design. I don't need any support for libraries like BOLTS.

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

Customisable cup holder adapter for a phone

Originally designed for Toyota Yaris cup holder to fit a Samsung Galaxy S8

(c) Matthias Liffers 2018

Released under CC-BY 4.0 license

All dimensions in millimetres

Changelog:

v0.1
 * First release

v0.2
 * Added side walls to dock rest to stop phone falling over when not plugged in
 * Added plug offset for phones where the plug is not dead centre along the y axis
 * Removed roundess from top

v1.0
 * modularised code
 * a bit more friendly for Thingiverse Customizer

v2.0
 * Converted from rounded shape to tapered shape
 * Added shelf to hold charging plug so that it doesn't get pushed down when the phone is inserted

*/

/* [ Basics ] */

// Diameter of cup holder
holder_top_diameter = 76;
// Diamater of cup holder bottom
holder_bottom_diameter = 70;
// Height of cup holder
holder_height = 60;

// Phone width
phone_x = 69;
// Phone Depth
phone_y = 9;

// Angle at which the phone should lean back
dock_angle = 20;
// Depth at which phone should be inset into the holder
dock_z = 15;

/* [ Back rest ] */

// Add back rest
dock_rest = true;
// Phone back rest height
dock_rest_z = 20;
// Phone back rest width
dock_rest_x = phone_x;
// Phone back rest depth
dock_rest_y = 5;

/* [ Charge plug hole ] */

plug = true; // Add charge plug hole
// Width of charging plug
plug_x = 12.2;
// Depth of charging plug
plug_y = 4.7;
// Length of charging plug, minus the contacts
plug_z = 19;
// Distance of charging plug from front of phone
plug_offset = 3.3;

/* [ Cable routing channel ] */

// Add cable routing channel
cable = true;
// Width of cable routing channel
cable_x = 3;
// Depth of cable routing channel
cable_y = 3;

// Smoothness of all rounded edges. Use a low number for faster rendering, increase when performing final render
round_smoothness= 72;

cos_d_a = cos(dock_angle);
sin_d_a = sin(dock_angle);
tan_d_a = tan(dock_angle);

holder_top_radius = holder_top_diameter/2;
holder_bottom_radius = holder_bottom_diameter/2;
dock_drop = (sin_d_a * phone_y / 2) - (cos_d_a * dock_z / 2);
dock_height_add = tan_d_a * (phone_y / 2 + dock_rest_y);
gouge_height = holder_height - ((cos_d_a * plug_z) + (cos_d_a * dock_z) - (sin_d_a * (phone_y - plug_offset))) - 5;
rest_setback = (sin_d_a * dock_z / 2) + (cos_d_a * phone_y / 2);

difference() {
    difference() {
        union() {
            // Main body
            cylinder( h = holder_height, r1 = holder_bottom_radius, r2 = holder_top_radius, $fn=round_smoothness);
                // Dock rest
                if (dock_rest)
                    create_dock_rest();
        }
        // Phone inset
        translate([(0 - phone_x) / 2, 0, holder_height + dock_drop])
            rotate(a = (0 - dock_angle), v = [1, 0, 0])
                translate ([0, 0 - (phone_y / 2), 0 - (dock_z / 2)])
                    union() {
                        cube([phone_x, phone_y, dock_z + 1]);
                        if (plug)
                            create_plug_hole();
                    }
        // Cable channel
        if (cable)
            create_cable_channel();
        // Bottom gouges
        translate([0 - (plug_y + 5) / 2, 0 - holder_top_radius, -1])
            cube([plug_y + 5, holder_top_diameter, gouge_height + 1]);
        translate([0 - holder_top_radius, 0 - (plug_y + 5) / 2, -1])
            cube([holder_top_diameter, plug_y + 5, gouge_height +1 ]);
    }
    // Trim entire cup holder down to just the radius and slice the top off the dock
    difference() {
        cylinder(h = holder_height + dock_rest_z * 2, r = holder_top_radius * 2, $fn = round_smoothness);
         cylinder(h = holder_height * 2, r1 = holder_bottom_radius, r2 = holder_top_radius + (holder_top_radius - holder_bottom_radius), $fn = round_smoothness);
    }
}

module create_dock_rest() {
    translate([0 - (dock_rest_x / 2), rest_setback, holder_height])
        rotate(a = (0 - dock_angle), v = [1, 0, 0])
            translate([0, 0, 0 - dock_height_add])
                union() {
                    cube([dock_rest_x, dock_rest_y, dock_rest_z + dock_height_add]);
                    translate([0 - dock_rest_y, 0 - phone_y, 0])
                        cube([dock_rest_y, phone_y + dock_rest_y, dock_rest_z + dock_height_add]);
                    translate([dock_rest_x, 0 - phone_y, 0])
                        cube([dock_rest_y, phone_y + dock_rest_y, dock_rest_z + dock_height_add]);
                }
}

module create_cable_channel() {
    translate([0 - (cable_x / 2), holder_top_radius -  2 * cable_y, -1])
        rotate(a = 0-atan((holder_top_radius - holder_bottom_radius)/ holder_height), v = [1,0,0])
            cube([cable_x, cable_y, holder_height +2]);
}

module create_plug_hole() {
    translate([phone_x / 2 - plug_x / 2, plug_offset, 0 - plug_z])
        union() {
            cube([plug_x, plug_y, plug_z + 1]);
            translate([plug_x/2 - plug_y/2 - 0.5, 0 - plug_offset, - 13])
                cube([plug_y + 1, plug_x + 1, plug_z + plug_z + 20]);
        }
}
```


[User]
I need to create a customizable cookie cutter, and I'd like to use OpenSCAD. I have a basic design in mind, but it needs to be fully parametric.

The cookie cutter will be based on a polygon defined by a list of points and a list of paths connecting those points. Something like `poly = [[[-1,1],[1,1],[1,-1],[-1,-1]],[[0,1,2,3]]]`, where the outer list's first element is the list of the points and the second is the list of the paths. I'd like to be able to specify this polygon as a variable in the OpenSCAD code.

I'd also like to be able to control the following parameters:

*   `size`: The overall size of the cookie cutter. The shape should be scaled to fit within a square of this size.
*   `rounded`: A boolean flag to switch between `offset()` with `delta` and `offset()` with just a value. This is because some OpenSCAD versions will not properly handle rounded edges (using just a value rather than `delta`).
*   `width`: The thickness of the cookie cutter's wall.
*   `height`: The total height of the cookie cutter.
*   `flangeWidth`: The width of a flange at the bottom of the cutter, used to give it some stability.
*   `flangeHeight`: The height of that flange.
*   `fn`: Number of fragments for curves.

The cookie cutter should be generated by extruding the polygon shape. It should have the flange on the bottom (as well as the main cutter edge). And, of course, the interior of the cutter should be subtracted out to make a hollow cutter.

The core logic should work like this:

1.  Calculate the bounding box of the polygon.
2.  Scale the polygon to fit within a square of the specified `size`.
3.  Create the flange by extruding the scaled shape and offsetting it using `flangeWidth`.
4.  Create the main cookie cutter wall by extruding the scaled shape and offsetting it using `width`.
5.  Subtract an extruded, slightly offset version of the scaled shape from the flange and wall to make the interior hollow.

The code also has a function `bounds(pts)` that calculates the minimum and maximum x and y coordinates of a set of points.

Could you generate the necessary OpenSCAD file or files to achieve this? I'm not currently using any external libraries so that wouldn't be necessary.

[Assistant]
cookie_maker.scad:
```
poly = [[[-1,1],[1,1],[1,-1],[-1,-1]],[[0,1,2,3]]]; //[draw_polygon:100x100]

//Cutter size (mm)
size = 30;
//Round edges of cutter?
rounded = "true"; // [false,true]
Brounded = (rounded == "true");
//width of cookie cutter body (mm)
width = 1.5;
//total height of the cookie cutter (mm)
height = 12.0;
//width of bottom flange (mm)
flangeWidth = 4.0;
//height of bottom border (mm)
flangeHeight = 1.2;
//arc segments/precision
$fn = 40; // [1:100]

function bounds(pts) =
    let (xs = [ for (i=[0:len(pts)-1]) pts[i][0] ], ys = [ for (i=[0:len(pts)-1]) pts[i][1] ])
	[ [min(xs), min(ys)], [max(xs), max(ys)] ];

module shape() {
	b = bounds(poly[0]);
	h = b[1][1] - b[0][1];
	w = b[1][0] - b[0][0];
	scale([size/max(h,w),size/max(h,w),1])
	translate([-b[0][0], -b[0][1]])
	polygon(poly[0], poly[1]);
}

difference(){
    if (Brounded) { //which offset style to use?
        linear_extrude(flangeHeight) offset(flangeWidth) shape(); //flange on top
        linear_extrude(height) offset(width) shape();             //outer edge of cutter
    } else {
        linear_extrude(flangeHeight) offset(delta=flangeWidth) shape(); //flange on top
        linear_extrude(height) offset(delta=width) shape();             //outer edge of cutter
    }
    translate([0,0,-0.1]) linear_extrude(height+0.2) shape(); //offset to subtract well
}

```


[User]
Hey, I'm looking to get some custom drawer dividers designed. I have a pretty clear idea of what I need but I'm not great with OpenSCAD, so I was hoping you could help me generate the necessary code.

Basically, the divider will be a flat piece with optional linear connectors on the ends and optional slots for perpendicular dividers. I'd like it to be fully customizable, with parameters for the following:

*   **Divider Length:** The overall length of the main section of the divider.
*   **Left/Top Connector:** A boolean to specify if a linear connector is present on the left/top end.
*   **Left/Top Connector Inverted:** A boolean to invert the orientation of the left/top connector.
*   **Right/Bottom Connector:** A boolean to specify if a linear connector is present on the right/bottom end.
*  **Right/Bottom Connector Inverted:** A boolean to invert the orientation of the right/bottom connector.
*   **Connector Positions:** An array of positions (measured from the left/top) along the divider's length, where perpendicular divider slots should be cut.
*   **Divider Height:** The height of the divider.
*   **Divider Thickness:** The thickness of the divider.
*   **Overlap Length:** The length of the connector overlap section.
*   **Connector Diameter:** The diameter of the circular knobs/holes on the linear connectors.
*   **Connector Count:** The number of knobs/holes on the linear connectors.
*   **Ignore Problems:** A boolean to ignore potential errors in the settings.

The linear connectors should have alternating knobs and holes, with the first one being a hole, and the first connector on an inverted connector should be a knob. I'd need to be able to specify if the linear connectors on the left/top and right/bottom are inverted. I think it would be good to have the connector overlap length configurable so that it can be adjusted as needed. I should also get some kind of warning if my input parameters are not working correctly like if the connector overlap length is smaller than the connector diameter or if I try to create more connectors than the height of the divider allows.

I would want to do this with OpenSCAD, I don't have any preference for which OpenSCAD library to use.

Could you generate the necessary OpenSCAD file(s) for me? Thanks!

[Assistant]
Customizeable_Drawer_Divider.scad:
```
//!OpenSCAD

//The length of the divider
Divider_Length = 140;
//Wether to create a linear connector on the left/top end
Left_Top_Connector = true;
//Wether to invert the left/top connector
Left_Top_Connector_Inverted = false;
//Wether to create a linear connector on the right/bottom end
Right_Bottom_Connector = true;
//Wether to invert the right/bottom connector
Right_Bottom_Connector_Inverted = true;
//The positions to create a slit of Divider_Thickness width for perpendicular connections at
Positions_Connectors = [35, 70, 105];

//The height of the divider
Divider_Height = 50;
//The thickness of the divider (Should give an even number if diveded by layer height)
Divider_Thickness = 1.2;
//The length of overlap regions for connecting
Overlap_Length = 20;
//The diameter of the holes and knobs for connecting (Sould be smaller than Overlap_Length
Diameter_Connectors = 10;
//The amount of connectors per overlap region (Must be smaller than Divider_Height divided by Diameter_Connectors
Amount_Connectors = 2;
//Wether to ignore problems that could result in a failing print
Ignore_Problems = false;

//Circle Resolution
$fn = 32;

//Internal Calculations
Reduced_Divider_Length = Divider_Length - (Left_Top_Connector ? Overlap_Length / 2 : 0) - (Right_Bottom_Connector ? Overlap_Length / 2 : 0);
Left_Top_Offset = Left_Top_Connector ? Overlap_Length / 2 : 0;

if (!Ignore_Problems
    && (   (Overlap_Length < Diameter_Connectors)
        || ((Divider_Height / Diameter_Connectors) < Amount_Connectors)
        )
    )
    translate([0, Divider_Height, 0])
        text("Warning! Print might not give a good result", halign="center", valign="center");
difference() {
    cube([Reduced_Divider_Length, Divider_Height, Divider_Thickness], center=true);

    for (x = Positions_Connectors)
        translate([-Reduced_Divider_Length/2+x-Left_Top_Offset, Divider_Height/4, 0])
            cube([Divider_Thickness, Divider_Height/2, Divider_Thickness], center=true);
}

if (Left_Top_Connector) {
    translate([-(Reduced_Divider_Length+Overlap_Length)/2, 0, 0]) {
        if (Left_Top_Connector_Inverted)
            mirror([0,0,1])
                Connector();
        else
            Connector();
    }
}

if (Right_Bottom_Connector) {
    translate([(Reduced_Divider_Length+Overlap_Length)/2, 0, 0]) {
        rotate([180,0,0]) {
            if (Right_Bottom_Connector_Inverted)
                mirror([0,0,1])
                    Connector();
            else
                Connector();
        }
    }
}

module Connector() {
    union(){
        difference(){
            translate([0, 0, -Divider_Thickness/4])
                cube([Overlap_Length, Divider_Height, Divider_Thickness/2], center=true);

            for (i = [0 : 2 : Amount_Connectors - 1])
                translate([0, -Divider_Height/2 + ((i+0.5)*Divider_Height/Amount_Connectors), -Divider_Thickness/4])
                    cylinder(h=Divider_Thickness/2, r1=(Diameter_Connectors-Divider_Thickness/2)/2, r2=(Diameter_Connectors+Divider_Thickness/2)/2, center=true);
        }

        for (i = [1 : 2 : Amount_Connectors - 1])
                translate([0, -Divider_Height/2 + ((i+0.5)*Divider_Height/Amount_Connectors), Divider_Thickness/4])
                    cylinder(h=Divider_Thickness/2, r1=(Diameter_Connectors+Divider_Thickness/2)/2, r2=(Diameter_Connectors-Divider_Thickness/2)/2, center=true);
    }
}
```


[User]
Hey, I'm looking to create a parametric, adjustable tap wrench, and I'd like it to have an animation feature. I've seen a design I really like, and I'm hoping you can help me replicate it and potentially make some adjustments.

The tap wrench has a main body with a square profile that's got a rounded edge. There are four segments that slide in and out of this body to grip the tap. The segments should move in a synchronized way, so when animated they either expand or contract from the center of the tap wrench.  The tap wrench is designed to hold taps, so it will need a hole in the center for inserting the tap, and a threaded rod or similar mechanism to tighten the segments around the tap. I think I'll need to provide the tap dimensions and thread diameter.

Specifically, I need the following parameters:

*   `max_adj_square`:  This should define the maximum size the square shape will grow when adjusted.
*   `square`: The overall size of the square that the segments fit inside.
*   `thickness`: The thickness of the main body and segments
*  `thread_dia`: The diameter of the threaded rod/shaft
* `tap_hole_size`: the diameter of the hole that accepts the tap
* `show`: An integer that selects the visibility of specific parts. This way I can check each segment and adjust things as needed.

I would like the following to be controlled with the `show` parameter:

*   `0`: Only show the main body of the wrench
*   `1`: Only show segment 1 of the wrench
*   `2`: Only show segment 2 of the wrench
*  `3`: Only show segment 3 of the wrench
*  `4`: Only show segment 4 of the wrench
*   `5`: Show all parts without animation
*   `6`: Show all parts with the animation
*   `7`: Show a top cover piece for the tap wrench

The animated adjustment should be achieved by controlling the position of the segments along the diagonal. The animation is controlled using `$t`, which is a standard OpenSCAD feature for animations, so I think I can handle that part if you can get the parametric movement working. Also, make sure to include a cover piece and holes for some screws. I'd like this design in one or multiple .scad files, your choice. I would like you to use the `offset` function to perform rounding if you choose to implement the round edges with it.

[Assistant]
tap_wrench_adjustable.scad:
```
////////////////////////////////////////////////
//  Animated Parametric adjustable Tap Wrench  /
////////////////////////////////////////////////
/// OpenSCAD File V1.0 by Ken_Applications /////
/////////  OpenSCAD version 2015.03-2 //////////
////////       21 - 01 - 2018              /////
////////////////////////////////////////////////

///////////////////////////////////////////////////////////
/// To activate animation, select "View->Animation" from the
/// menu and enter values into the appearing FPS and Steps input
/// fields (e.g. 5 FPS and 50 Steps for this animation).
////////////////////////////////////////////////////////////

////  Parameters //////////////////////////////
////////////////////////////////////////////////
// Maximum the square will grow to
max_adj_square=11;
// The size of the square the 4 segments fit into
square=33;
// Thickness
thickness=11;
//Thread diameter default... 6
thread_dia=6;
// The Tapping drill size... default 5
tap_hole_size=5;
// Show individual parts default... 6
show=6;// 0=body 1=segment1 2=segment2 3=segment3 4=segment4 5=all parts 6=all with animation 7=cover
////////////////////////////////////////////////
////////////////////////////////////////////////

module the_shape(){
round2d(external_rad,square/1.5){
square(square+add_0n,true);
square([square*4.6,handle_width],true);

}
}

$fn=100;
///// calculations ///
add_0n=square*0.25;
handle_width=square*0.36;
external_rad=(handle_width/2)-1;
hole_dia=square*0.5757;
adj=0.7071*max_adj_square;
s=(1+ sin(360*$t))/2; //this is for animation
////////////////////////////////////////
if (show==6 ) body();
if (show==5 ) body();
if (show==0 ) body();
if (show==7 ) cover();
if (show==6 ) translate([-(square/2)+thread_dia/2+2,0,((thickness-1)/2)+1])  adjuster();
if (show==5 )translate([-(square/2)+thread_dia/2+2,0,((thickness-1)/2)+1])adjuster();

//seg1 moving
 if (show==6 ) translate([-square/2,(square/2)-square-adj*s,1])seg1() ;
 // seg2 moving
 if (show==6 ) rotate([0,0,90]) translate([-square/2,(square/2)-square-adj*s,1])seg1() ;
// seg3 moving
 if (show==6 ) rotate([0,0,180]) translate([-square/2,(square/2)-square-adj*s,1])seg1() ;
// seg4 moving
  if (show==6 ) rotate([0,0,270]) translate([-square/2,(square/2)-square-adj*s,1])seg1() ;

module adjuster (){
  rotate([0,360*s,0]){
  color( "grey", 1.0 ) {
//threaded shaft
   rotate([90,0,0])   cylinder(h=square+add_0n+2, d1=thread_dia, d2=thread_dia, center=true);
//nut1
  translate([0,-(square/2)-add_0n/2,0])  rotate([90,0,0])   cylinder(h=5, d1=thread_dia*2.5, d2=thread_dia*2.5, center=false,$fn=6);
//nut2
  translate([0,(square/2)+5+add_0n/2,0])  rotate([90,0,0])   cylinder(h=5, d1=thread_dia*2.5, d2=thread_dia*2.5, center=false,$fn=6);
        }
    }
}

module cover(){
  difference(){
       union(){
 translate([0,0,thickness+0.1])
 linear_extrude(height=1.5)
 round2d(thread_dia,0){
 square([square+8,square+8],true);
 square([square+thread_dia*4,thread_dia*3],true);
 }
 }
 //hole in cover
    cylinder(h=thickness*5, d1=hole_dia, d2=hole_dia, center=true);
// 2 fixing holes in cover
translate([square/2+4,0,1]) cylinder(h=50,d1=thread_dia,d2=thread_dia);
translate([-(square/2+4),0,1]) cylinder(h=50,d1=thread_dia,d2=thread_dia);
 }
 }

if (show==1){
//segment 1 in position
  difference(){
 translate([-square/2,-square/2,1]) seg1();
  translate([-(square/2)+thread_dia/2+2,0,((thickness-1)/2)+1])  rotate([90,0,0])   cylinder(h=square*2, d1=tap_hole_size, d2=tap_hole_size, center=true);

  }
}

if (show==5){
//segment 1 in position
  difference(){
 translate([-square/2,-square/2,1]) seg1();
  translate([-(square/2)+thread_dia/2+2,0,((thickness-1)/2)+1])  rotate([90,0,0])   cylinder(h=square*2, d1=tap_hole_size, d2=tap_hole_size, center=true);
  }
}

if (show==2){
//segment 2 in position
difference(){
 translate([-square/2,-square/2,1]) rotate([0,0,90]) translate([0,-square,0]) seg1();
 clearance ();
}
}

if (show==5){
//segment 2 in position
difference(){
 translate([-square/2,-square/2,1]) rotate([0,0,90]) translate([0,-square,0]) seg1();
 clearance ();
}
}

if (show==3){
//segment 3 in position
 translate([square/2,square/2,1]) rotate([0,0,180]) seg1();
}
if (show==5){
//segment 3 in position
 translate([square/2,square/2,1]) rotate([0,0,180]) seg1();
}

if (show==4){
//segment 4 in position
difference(){
translate([-square/2,square/2,1]) rotate([0,0,-90])  seg1();
 clearance ();
}
}

if (show==5){
//segment 4 in position
difference(){
translate([-square/2,square/2,1]) rotate([0,0,-90])  seg1();
 clearance ();
}
}

module clearance (){
hull(){
  translate([-(square/2)+thread_dia/2+3,0,((thickness-1)/2)+1])  rotate([90,0,0])   cylinder(h=square*2, d1=thread_dia, d2=thread_dia, center=true);
  translate([-(square/2)+thread_dia/2-20,0,((thickness-1)/2)+1])  rotate([90,0,0])   cylinder(h=square*2, d1=thread_dia, d2=thread_dia, center=true);
 }
}

module seg1(){
difference(){
    color( "skyblue", 1.0 )
cube([square/2,square,thickness-1],false);
translate([0,0,thickness/2-.5]) rotate([0,0,45])cube([max_adj_square*50,max_adj_square,thickness],true);
  translate([0,0,-0.5]) rotate([0,0,-45]) cube([square,square,thickness]);
   translate([square/2+adj,square/2+adj,thickness/2-0.5]) rotate([0,0,-45]) cube([max_adj_square*50,max_adj_square,thickness],true);

   translate([square/2+adj,square/2+adj,-.1]) rotate([0,0,45]) cube([square,square,square]);

}
}

module body(){
difference(){
linear_extrude(height=thickness+0.3) the_shape();
translate([-square/2,-square/2,1]) cube([square,square,square],false);
     cylinder(h=thickness*5, d1=hole_dia, d2=hole_dia, center=true);

  translate([-(square/2)+thread_dia/2+2,0,((thickness-1)/2)+1])  rotate([90,0,0])   cylinder(h=square*2, d1=thread_dia, d2=thread_dia, center=true);

    translate([square/2+4,0,+3]) cylinder(h=50,d1=tap_hole_size,d2=tap_hole_size);
translate([-(square/2+4),0,+3]) cylinder(h=50,d1=tap_hole_size,d2=tap_hole_size);
}
}

//////""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
module round2d(OR=3,IR=1){
    offset(OR)offset(-IR-OR)offset(IR)children();
}

```


[User]
Hey, I need an OpenSCAD design for a tripod adapter plate that connects a tripod to a Panobot. I've got a couple of specific tripods I want to use it with, so it needs to be parametric.

The adapter consists of two main parts: a bottom section that fits the tripod, and a circular top section that attaches to the Panobot's gear. The bottom section has a sort of trapezoidal shape with different X and Y dimensions at the top and bottom, and the top of this section transitions into a flat circular disc, which is the mount point for the Panobot. There also needs to be a way to screw the plate onto the tripod, so I need to include some screw holes.

Here are the key dimensions, which I'll want to be able to change:

*   **TRIPOD_MOUNT_BOTTOM_DISTANCE_X:** The X dimension of the bottom face of the trapezoid.
*   **TRIPOD_MOUNT_BOTTOM_DISTANCE_Y:** The Y dimension of the bottom face of the trapezoid.
*   **TRIPOD_MOUNT_TOP_DISTANCE_X:** The X dimension of the top face of the trapezoid.
*   **TRIPOD_MOUNT_TOP_DISTANCE_Y:** The Y dimension of the top face of the trapezoid.
*   **TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE:** The height of the trapezoidal section.
*   **MOUNT_DISC_DIA:** The diameter of the circular disc on top.
*   **MOUNT_DISC_HEIGTH:** The thickness of the circular disc.
*   **MOUNT_DISC_SUPPORT:** This is optional, but I want to be able to add cylindrical supports on the sides of the trapezoid. I want to be able to control the radius of these supports.

I think I need the following constants to be exposed as parameters for the user:

*   **var_MOUNT_SCREW_DISTANCE:** The distance between the screw holes
*   **var_MOUNT_SCREW_DIA:** The diameter of the screw holes
*   **var_MOUNT_SCREW_SPACING:** The diameter of a countersunk volume around the screw holes, used to fit a screw head
*   **var_MOUNT_SCREW_HEAD_HEIGTH:** The height of the countersunk volume around the screw holes
*   **var_MOUNT_SCREW_LENGTH:** The length of the screw hole/countersunk volume - this can be fairly long

I'd also like to use the following derived parameter:

*   **var_MOUNT_DISC_SUPPORT_DISTANCE:** the distance from center of the mount to the disc support

I need at least 3 configuration presets as well:

1.  **Custom:** This is the default where each value is defined by the user
2.  **MindfabsAndoerTripod:** This should pre-fill the values as such: `[ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, 95 ], [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, 50 ], [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, 95 ], [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, 40 ], [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, 11 ], [ID_MOUNT_DISC_DIA, 102 ], [ID_MOUNT_DISC_HEIGTH, 6 ], [ID_MOUNT_DISC_SUPPORT, 4 ]`
3.  **RolleiC50i:** This should pre-fill the values as such:  `[ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, 50 ], [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, 38 ], [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, 50 ], [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, 30 ], [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, 7 ], [ID_MOUNT_DISC_DIA, 102 ], [ID_MOUNT_DISC_HEIGTH, 4 ], [ID_MOUNT_DISC_SUPPORT, 0 ]`

Could you generate this? It should be all in one file, and I don't need any libraries or special includes.

[Assistant]
PanobotMounts.scad:
```

// The Bottom Distance in X Direction for the Mount (see sketch)
TRIPOD_MOUNT_BOTTOM_DISTANCE_X = 44;
// The Bottom Distance in Y Direction for the Mount (see sketch)
TRIPOD_MOUNT_BOTTOM_DISTANCE_Y = 44;
// The Top Distance in X Direction for the Mount (see sketch)
TRIPOD_MOUNT_TOP_DISTANCE_X = 44;
// The Top Distance in Y Direction for the Mount (see sketch)
TRIPOD_MOUNT_TOP_DISTANCE_Y = 35;
// The Height of the Mount element (see sketch)
TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE = 9;

// The diameter of the central gear supporting structure.
MOUNT_DISC_DIA = 100;
// The height of the central gear supporting structure.
MOUNT_DISC_HEIGTH = 4;

//Choose custom or preset
presetValues = 1; // [1:Custom, 2:MindfabsAndoerTripod]

/* [Hidden] */

//Choose an additional support for the mount disc
MOUNT_DISC_SUPPORT = 0; // use it when you know what you are doing :)

$main=0;
$fn=200;

ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X = 0;
ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y = 1;
ID_TRIPOD_MOUNT_TOP_DISTANCE_X = 2;
ID_TRIPOD_MOUNT_TOP_DISTANCE_Y = 3;
ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE = 4;
ID_MOUNT_DISC_DIA = 5;
ID_MOUNT_DISC_HEIGTH = 6;
ID_MOUNT_DISC_SUPPORT = 7;

customConfig = [
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, TRIPOD_MOUNT_BOTTOM_DISTANCE_X ],
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, TRIPOD_MOUNT_BOTTOM_DISTANCE_Y ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, TRIPOD_MOUNT_TOP_DISTANCE_X],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, TRIPOD_MOUNT_TOP_DISTANCE_Y],
    [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE],
    [ID_MOUNT_DISC_DIA, MOUNT_DISC_DIA],
    [ID_MOUNT_DISC_HEIGTH, MOUNT_DISC_HEIGTH],
    [ID_MOUNT_DISC_SUPPORT, MOUNT_DISC_SUPPORT]
];

andoerConfig = [
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, 95 ],
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, 50 ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, 95 ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, 40 ],
    [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, 11 ],
    [ID_MOUNT_DISC_DIA, 102 ],
    [ID_MOUNT_DISC_HEIGTH, 6 ],
    [ID_MOUNT_DISC_SUPPORT, 4 ]
];

module PanobotMounts(config = customConfig) {

    var_TRIPOD_MOUNT_BOTTOM_DISTANCE_X = lookup(ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, config);
    var_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y = lookup(
      ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y,config);
    var_TRIPOD_MOUNT_TOP_DISTANCE_X = lookup(
      ID_TRIPOD_MOUNT_TOP_DISTANCE_X, config);
    var_TRIPOD_MOUNT_TOP_DISTANCE_Y = lookup(
      ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, config);
    var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE = lookup(
      ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, config);
    var_MOUNT_DISC_DIA = lookup(
      ID_MOUNT_DISC_DIA, config);
    var_MOUNT_DISC_HEIGTH = lookup(
      ID_MOUNT_DISC_HEIGTH, config);
    var_MOUNT_DISC_SUPPORT = lookup(
      ID_MOUNT_DISC_SUPPORT, config);

    //+-25mm, 4mm mount screw distance
    var_MOUNT_SCREW_DISTANCE = 50;
    var_MOUNT_SCREW_DIA = 4;
    var_MOUNT_SCREW_SPACING = 10;
    var_MOUNT_SCREW_HEAD_HEIGTH = 5;

    var_MOUNT_SCREW_LENGTH = 100;

    var_MOUNT_DISC_SUPPORT_DISTANCE = 25;

    small_height = 0.0000000000001;

    module tools() {
        for(i=[-1,+1])translate([i*var_MOUNT_SCREW_DISTANCE/2,0,0])cylinder(d=var_MOUNT_SCREW_DIA,h=var_MOUNT_SCREW_LENGTH,center=true);
        for(i=[-1,+1])translate([i*var_MOUNT_SCREW_DISTANCE/2,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE/2+var_MOUNT_SCREW_HEAD_HEIGTH/2])cylinder(d=var_MOUNT_SCREW_SPACING,h=var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE+var_MOUNT_SCREW_HEAD_HEIGTH+small_height,center=true);
        cylinder(d=20,h=var_MOUNT_SCREW_LENGTH,center=true);
    }

    module assembly() {
        union() {
            color("green")hull() {
                cube([var_TRIPOD_MOUNT_BOTTOM_DISTANCE_X,var_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y,small_height],center=true);
                translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE])cube([var_TRIPOD_MOUNT_TOP_DISTANCE_X,var_TRIPOD_MOUNT_TOP_DISTANCE_Y,small_height],center=true);
            }
            hull() {
                translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE])cube([var_TRIPOD_MOUNT_TOP_DISTANCE_X,var_TRIPOD_MOUNT_TOP_DISTANCE_Y,small_height],center=true);
                translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE+var_MOUNT_SCREW_HEAD_HEIGTH])cube([var_TRIPOD_MOUNT_TOP_DISTANCE_X,var_TRIPOD_MOUNT_TOP_DISTANCE_Y,small_height],center=true);
            }
            if (var_MOUNT_DISC_SUPPORT>0) {
                //add support to the sides of the mount, to make it more stable
                for(x=[-1,+1],y=[-1,+1])translate([x*var_MOUNT_DISC_SUPPORT_DISTANCE,y*var_TRIPOD_MOUNT_TOP_DISTANCE_Y/2,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE+var_MOUNT_SCREW_HEAD_HEIGTH-var_MOUNT_SCREW_HEAD_HEIGTH/2-var_MOUNT_DISC_SUPPORT/2])cylinder(d=20,h=var_MOUNT_DISC_SUPPORT + var_MOUNT_SCREW_HEAD_HEIGTH,center=true);
            }
            translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE + var_MOUNT_SCREW_HEAD_HEIGTH + var_MOUNT_DISC_HEIGTH/2-0.2])minkowski() {
                cylinder(d=var_MOUNT_DISC_DIA,h=small_height,center=true);
                sphere(d=var_MOUNT_DISC_HEIGTH,center=true);
            }
        }
    }

    difference() {
        assembly();
        #tools();
    }
}

if ($main!=1) {
    if (presetValues == 1) {
        PanobotMounts(customConfig);
    } else if (presetValues == 2) {
        PanobotMounts(andoerConfig);
    }
}
```
PanobotMounts.scad:
```

// The Bottom Distance in X Direction for the Mount (see sketch)
TRIPOD_MOUNT_BOTTOM_DISTANCE_X = 44;
// The Bottom Distance in Y Direction for the Mount (see sketch)
TRIPOD_MOUNT_BOTTOM_DISTANCE_Y = 44;
// The Top Distance in X Direction for the Mount (see sketch)
TRIPOD_MOUNT_TOP_DISTANCE_X = 44;
// The Top Distance in Y Direction for the Mount (see sketch)
TRIPOD_MOUNT_TOP_DISTANCE_Y = 35;
// The Height of the Mount element (see sketch)
TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE = 9;

// The diameter of the central gear supporting structure.
MOUNT_DISC_DIA = 100;
// The height of the central gear supporting structure.
MOUNT_DISC_HEIGTH = 4;

//Choose custom or preset
presetValues = 3; // [1:Custom, 2:MindfabsAndoerTripod, 3:RolleiC50i]

/* [Hidden] */

//Choose an additional support for the mount disc
MOUNT_DISC_SUPPORT = 0; // use it when you know what you are doing :)

$main=0;
$fn=200;

ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X = 0;
ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y = 1;
ID_TRIPOD_MOUNT_TOP_DISTANCE_X = 2;
ID_TRIPOD_MOUNT_TOP_DISTANCE_Y = 3;
ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE = 4;
ID_MOUNT_DISC_DIA = 5;
ID_MOUNT_DISC_HEIGTH = 6;
ID_MOUNT_DISC_SUPPORT = 7;

customConfig = [
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, TRIPOD_MOUNT_BOTTOM_DISTANCE_X ],
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, TRIPOD_MOUNT_BOTTOM_DISTANCE_Y ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, TRIPOD_MOUNT_TOP_DISTANCE_X],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, TRIPOD_MOUNT_TOP_DISTANCE_Y],
    [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE],
    [ID_MOUNT_DISC_DIA, MOUNT_DISC_DIA],
    [ID_MOUNT_DISC_HEIGTH, MOUNT_DISC_HEIGTH],
    [ID_MOUNT_DISC_SUPPORT, MOUNT_DISC_SUPPORT]
];

andoerConfig = [
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, 95 ],
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, 50 ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, 95 ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, 40 ],
    [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, 11 ],
    [ID_MOUNT_DISC_DIA, 102 ],
    [ID_MOUNT_DISC_HEIGTH, 6 ],
    [ID_MOUNT_DISC_SUPPORT, 4 ]
];

rolleic50iConfig = [
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, 50 ],
    [ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y, 38 ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_X, 50 ],
    [ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, 30 ],
    [ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, 7 ],
    [ID_MOUNT_DISC_DIA, 102 ],
    [ID_MOUNT_DISC_HEIGTH, 4 ],
    [ID_MOUNT_DISC_SUPPORT, 0 ]
];

module PanobotMounts(config = customConfig) {

    var_TRIPOD_MOUNT_BOTTOM_DISTANCE_X = lookup(ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_X, config);
    var_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y = lookup(
      ID_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y,config);
    var_TRIPOD_MOUNT_TOP_DISTANCE_X = lookup(
      ID_TRIPOD_MOUNT_TOP_DISTANCE_X, config);
    var_TRIPOD_MOUNT_TOP_DISTANCE_Y = lookup(
      ID_TRIPOD_MOUNT_TOP_DISTANCE_Y, config);
    var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE = lookup(
      ID_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE, config);
    var_MOUNT_DISC_DIA = lookup(
      ID_MOUNT_DISC_DIA, config);
    var_MOUNT_DISC_HEIGTH = lookup(
      ID_MOUNT_DISC_HEIGTH, config);
    var_MOUNT_DISC_SUPPORT = lookup(
      ID_MOUNT_DISC_SUPPORT, config);

    //+-25mm, 4mm mount screw distance
    var_MOUNT_SCREW_DISTANCE = 50;
    var_MOUNT_SCREW_DIA = 4;
    var_MOUNT_SCREW_SPACING = 10;
    var_MOUNT_SCREW_HEAD_HEIGTH = 5;

    var_MOUNT_SCREW_LENGTH = 100;

    var_MOUNT_DISC_SUPPORT_DISTANCE = 25;

    small_height = 0.0000000000001;

    module tools() {
        for(i=[-1,+1])translate([i*var_MOUNT_SCREW_DISTANCE/2,0,0])cylinder(d=var_MOUNT_SCREW_DIA,h=var_MOUNT_SCREW_LENGTH,center=true);
        for(i=[-1,+1])translate([i*var_MOUNT_SCREW_DISTANCE/2,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE/2+var_MOUNT_SCREW_HEAD_HEIGTH/2])cylinder(d=var_MOUNT_SCREW_SPACING,h=var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE+var_MOUNT_SCREW_HEAD_HEIGTH+small_height,center=true);
        cylinder(d=20,h=var_MOUNT_SCREW_LENGTH,center=true);
    }

    module assembly() {
        union() {
            color("green")hull() {
                cube([var_TRIPOD_MOUNT_BOTTOM_DISTANCE_X,var_TRIPOD_MOUNT_BOTTOM_DISTANCE_Y,small_height],center=true);
                translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE])cube([var_TRIPOD_MOUNT_TOP_DISTANCE_X,var_TRIPOD_MOUNT_TOP_DISTANCE_Y,small_height],center=true);
            }
            hull() {
                translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE])cube([var_TRIPOD_MOUNT_TOP_DISTANCE_X,var_TRIPOD_MOUNT_TOP_DISTANCE_Y,small_height],center=true);
                translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE+var_MOUNT_SCREW_HEAD_HEIGTH])cube([var_TRIPOD_MOUNT_TOP_DISTANCE_X,var_TRIPOD_MOUNT_TOP_DISTANCE_Y,small_height],center=true);
            }
            if (var_MOUNT_DISC_SUPPORT>0) {
                //add support to the sides of the mount, to make it more stable
                for(x=[-1,+1],y=[-1,+1])translate([x*var_MOUNT_DISC_SUPPORT_DISTANCE,y*var_TRIPOD_MOUNT_TOP_DISTANCE_Y/2,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE+var_MOUNT_SCREW_HEAD_HEIGTH-var_MOUNT_SCREW_HEAD_HEIGTH/2-var_MOUNT_DISC_SUPPORT/2])cylinder(d=20,h=var_MOUNT_DISC_SUPPORT + var_MOUNT_SCREW_HEAD_HEIGTH,center=true);
            }
            translate([0,0,var_TRIPOD_MOUNT_BOTTOM_TOP_DISTANCE + var_MOUNT_SCREW_HEAD_HEIGTH + var_MOUNT_DISC_HEIGTH/2-0.2])minkowski() {
                cylinder(d=var_MOUNT_DISC_DIA,h=small_height,center=true);
                sphere(d=var_MOUNT_DISC_HEIGTH,center=true);
            }
        }
    }

    difference() {
        assembly();
        #tools();
    }
}

if ($main!=1) {
    if (presetValues == 1) {
        PanobotMounts(customConfig);
    } else if (presetValues == 2) {
        PanobotMounts(andoerConfig);
    } else if (presetValues == 3) {
        PanobotMounts(rolleic50iConfig);
    }
}
```


[User]
I'm looking to create a customizable name key fob using OpenSCAD. I want to be able to control a few key parameters.

First, the overall dimensions of the fob body: length, width, and thickness. I'd also like to be able to specify the radius of the hole for the key loop, as well as the width of the loop itself (the difference between the inner and outer radius of the loop). The position of the hole should be adjustable too, specifically by specifying an offset percentage relative to the diameter of the hole.

Next, I'd like to add some text to the fob. I want to be able to specify what the text says, the font it uses, and how far it protrudes from (or is inset into) the surface of the fob. There should also be a configurable border between the text and the edges of the fob.

So basically, I need to control fob length, width, and thickness; hole radius and loop width; the hole offset; the text, font, text thickness, and text border spacing.

I'm hoping this can be set up so that the text can either protrude outward or be recessed into the surface of the fob depending on whether the text thickness is positive or negative.

I'm not familiar with any libraries beyond the built-ins, but I'm happy to use any libraries you recommend if it makes the design easier.

[Assistant]
SimpleNameFob.scad:
```
//key fob base length (X dimension)
fob_length = 50;

//key fob width (Y dimension)
fob_width = 20;

//key fob thickness (Z dimension)
fob_thickness = 3;

//radius of key loop hole
hole_radius = 5;

//width of key loop
loop_width = 3;

//offset of key loop hole - percent of hole diameter
hole_offset_percent = 50;   //[0:100]

//text to appear on the fob
name = "Christopher";

//thickness of text (Z dimension) - positive values will protrude, negaive values will inset
text_thickness = 1;

//border spacing between edge of fob and text
text_border = 3;

//text font to use (can be any Google fonts from: https://fonts.google.com/)
text_font = "Classic Comic";

difference() {
    fob();

    //if negative text_thickness, then sink text into face, and difference it from the fob
    //(if positive text_thickness, then nothing will be differenced from the fob)
    if (text_thickness < 0)
        translate([0, 0, text_thickness + .01])
            name();
}

//if positive text_thickness, then just render it at its default Z position on the face
if (text_thickness > 0)
    name();

//the rectangular body of the fob, with the offset key loop
module fob() {
    cube([fob_length, fob_width, fob_thickness]);

        translate([fob_length - hole_radius + 2*hole_radius * hole_offset_percent/100, fob_width/2, 0]) {
            difference() {
                cylinder(r=hole_radius + loop_width, h=fob_thickness);
                translate([0, 0, -.004])
                    cylinder(r=hole_radius, h=fob_thickness + .008);
            }
        }
}

//the name text, raised above, or inset into, the top surface of the fob
module name() {
    color("Blue")
        translate([fob_length/2, fob_width/2, fob_thickness - .004])
            resize([fob_length - 2*text_border, fob_width - 2*text_border, 0])
                //text_thickness could be negative, so take its absolute value for the extrude
                linear_extrude(abs(text_thickness))
                    text(name, font = text_font, halign="center", valign="center");
}

```


[User]
I'd like to create a customizable key fob using OpenSCAD, and I'm hoping you can help me with the code.

Essentially, I want a rounded rectangle base with a loop for a keychain, and some text on the surface. I'd like to be able to adjust a bunch of things via parameters:

*   **Fob Dimensions:** I want to be able to set the length (X), width (Y), and thickness (Z) of the main rectangular body of the fob.
*   **Key Loop:** This should be a circular or polygonal hole at one end, with a small amount of material surrounding it for strength. I'd like to specify the radius of the hole, the width of the surrounding loop material, and how far offset the hole is from the end (expressed as a percentage of the hole diameter). Also, the key loop shape should be customizable; the user should be able to set the number of sides (so it can be round, triangle, square, etc).
*   **Text:** The fob should have text on the surface. I need to be able to specify the text itself, the thickness of the text (positive values will have it extrude, negative values will have it inset), the font, and the border spacing between the text and the edge of the fob.
*   **Edge Roundness:** I'd like to control how rounded the corners of the fob are.
*   **Performance:** Obviously, I want to keep render times reasonable. I expect that the edge roundness and loop shape parameters can have the largest impact on rendering performance.

I don't need anything too fancy, but all of these parameters should be editable in the Customizer. I'm not using any libraries currently, so I don't think I have to worry about that part. I guess the most important thing is for the parameters to be fully exposed and configurable for the user.

Could you help me create the OpenSCAD code for this design?

[Assistant]
RoundedSimpleNameFob.scad:
```
//key fob base length (X dimension)
fob_length = 50;

//key fob width (Y dimension)
fob_width = 20;

//key fob thickness (Z dimension)
fob_thickness = 3;

//radius of key loop hole
hole_radius = 5;

//width of key loop
loop_width = 3;

//offset of key loop hole - percent of hole diameter
hole_offset_percent = 50;   //[0:100]

//text to appear on the fob
name = "Christopher";

//thickness of text (Z dimension) - positive values will protrude, negaive values will inset
text_thickness = 1;

//border spacing between edge of fob and text
text_border = 3;

//text font to use (can be any Google fonts from: https://fonts.google.com/)
text_font = "Classic Comic";

//$fn value to use in rendering fob edges - lower values yield faster results, but rougher edges, higher values yield smoother edges, but longer render times
edge_fn = 14; //[0:50]

//$fn value for rendering the shape of the loop - how many sides the full loop will have. Lower numbers will produce non-circular shapes (3 = triangle, 6 = hexagon, etc) and will render faster. Larger values will provide a smooth, circular loop, but will render slowly.
loop_fn = 8; //[3:50]

difference() {
    minkowski() {
        fob();
        sphere(r=fob_thickness/2, $fn=edge_fn);
    }
    if (text_thickness < 0)
        translate([0, 0, text_thickness + .01])
            name();
}
if (text_thickness > 0)
    name();

module fob() {
    translate([fob_thickness/2, fob_thickness/2, fob_thickness/2]) {
        cube([fob_length - fob_thickness, fob_width - fob_thickness, .001]);

        translate([fob_length - fob_thickness/2 - hole_radius + 2*hole_radius * hole_offset_percent/100, (fob_width - fob_thickness)/2, 0])
            difference() {
                cylinder(r=hole_radius + loop_width/2 + loop_width/2 - fob_thickness/2 + .001, h=.001, $fn=loop_fn);
                cylinder(r=hole_radius + loop_width/2 - (loop_width/2 - fob_thickness/2) - .001, h=.004, $fn=loop_fn);
            }
        }
}

module name() {
    color("Blue")
        translate([fob_length/2, fob_width/2, fob_thickness - .04])
            resize([fob_length - 2*text_border, fob_width - 2*text_border, 0])
                linear_extrude(abs(text_thickness))
                    text(name, font = text_font, halign="center", valign="center");
}

```


[User]
I need an OpenSCAD design for a customizable knob, like a replacement for a clock or radio button. I've seen a few designs that are close but I need one that's parameterized and matches what I need a bit more precisely.

Here are the features I'd like to be able to control:

*   **Overall Diameter (Knob_Diameter):**  The main diameter of the knob, something between 5 and 30mm.
*   **Knob Height (Knob_Height):** The overall height of the knob (without any additional mounting features), from 5 to 20mm.
*   **Inner Axis Length (Axis_Length):** The length of the inner post that goes into the device, which I need to be between 3 and 15mm long.
*   **Rounded Edge (Rounded):** The radius for rounding the top edges of the knob, between 1 and 3mm.
*   **Inner Axis Diameter (Axis_Diameter):** The diameter of the post that goes into the device, it should be at least 4mm smaller than the overall knob diameter. I need the diameter to also be adjustable and be easy to control and tweak.
*   **Axis Diameter Adjustment (Adjustment):**  A small adjustment to the inner axis diameter to compensate for printer tolerances, something like 0, 0.1, 0.2 or 0.3 mm.
*   **Optional Bottom Offset (add_offset):** An option to add a base or offset to the knob that increases the space between the main knob and the device (so it doesn't rub), either on or off.
*   **Offset Height (offset_Height):** If there is a bottom offset, make the height of that offset adjustable.
*  **Number of ridges (ridges):** Number of ridges around the knob.
*   **Optional Orientation Indicator (orientation_indicator):** An option to add a small indicator on the top of the knob - a small line and a dot.

I don't need any particular libraries for this one, it should be pretty basic. Could you generate the SCAD file(s) for me?

[Assistant]
Bouton_knob_clock.scad:
```
/* https://www.thingiverse.com/thing:2766977 */
/*Remix de https://www.thingiverse.com/thing:2282432 */
/* [Global] */
/* [Hidden] */
// Indicateur d'orientation ou non
orientation_indicator="non";// [oui,non]
$fn=50;
/* [Basic] */
//Diametre du bouton
Knob_Diameter=8; //[5:30]
//Hauteur du bouton
Knob_Height=8;//[5:20]
//Longueur de l'axe
Axis_Lenght=3;//[3:15]
//Arrondis
Rounded=1;//[1:3]
// Diamètre de l'axe interne (maxi diamètre du bouton moins 4mm)
Axis_Diameter=2;//
//Ajustement du diamètre de l'axe interne
Ajustment=0.1;//[0,0.1,0.2,0.3]
//Offset du bouton
add_offset="oui";// [oui,non]
//hauteur Offset
offset_Height=3.5;

// nombre de creux autour du bouton
ridges=6;

difference() {
  union() {
      // outer cylinder (main body)
      cylinder(r=Knob_Diameter/2,h=Knob_Height-Rounded);
      // top: center cylinder
      translate([0,0,Knob_Height-Rounded]) cylinder(r=Knob_Diameter/2-Rounded,h=Rounded);
      // top: rounded edge
      translate([0,0,Knob_Height-Rounded]) rotate_extrude(convexity = 10) translate([Knob_Diameter/2-Rounded,0,0])  circle(r=Rounded);
  }
  if (orientation_indicator == "oui") {
      // top: orientation indicator
      translate([0,0,Knob_Height]) rotate([-90,0,0]) cylinder(r=0.5,h=Knob_Diameter/2);
      // top: center "dot"
      translate([0,0,Knob_Height]) sphere(r=0.5);
  }
  // ridges around the perimeter
  for (i=[0:ridges-1]) translate([(Knob_Diameter+0.6)*sin(360*i/ridges)/2,(Knob_Diameter+0.6)*cos(360*i/ridges)/2,3]) cylinder(r=0.7,h=Knob_Height);

  // inside: the bottom part, this is always round (hollow cylinder)
  difference() {
     cylinder(r=(Axis_Diameter+Ajustment)/2,h=Axis_Lenght);
  }if (add_offset == "oui")
    difference(){
      difference() {
       translate([0,0,-1])cylinder(r=((Knob_Diameter+1)/2),h=offset_Height+1);
    translate([0,0,-1])cylinder(r=(Axis_Diameter/2+1.5),h=offset_Height+2);
   }
}
}

```


[User]
I'm looking to generate some customizable labels for my toolbox drawers, and I've got a pretty good idea of what I want but I need help writing the OpenSCAD code to generate them.

Essentially, I need a rectangular label with text on top of it. The label needs to have a defined length, height, and thickness, and the text needs to be centered, with its own thickness, font, and size parameters. I'd like to be able to control the position of the text within the label too so I can fine-tune where it sits.

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

*   **Label Text:**  The actual text that appears on the label (e.g., "Sockets", "Wrenches", etc.).
*   **Label Length:** The length of the rectangular base of the label.
*   **Label Thickness:** The thickness of the rectangular base of the label.
*   **Text Thickness:** The thickness of the extruded text.
*   **Text Size:** The font size of the text.
*   **Label Height:** The height of the rectangular base of the label.
*   **Font:** The font used for the text.

Additionally, I want the design to extrude the text on top of the label base. The user should be able to change colors in the customizer for the label and the text.

I think that's all the parameters for now. This should cover basic label generation. I don't think I'll need any special libraries for this.

[Assistant]
Label.scad:
```
// Label text
label = "Sockets";

//Label length
label_length = 87;

// Label thickness
label_thickness = 1.5;

// Text thickness
text_thickness = 1.5;

// Text size
font_size = 16;

// Label height
label_height = 20;

// Font
font = "REGISTRATION PLATE UK:style=Bold";

// Make the label
// Make the base
color("red") cube([label_length,label_height,label_thickness]);

// Create the text
color("white") translate([2,2,label_thickness])
linear_extrude(height = text_thickness) {
        text(text = str(label), font = font, size = font_size);
}

```


[User]
I'd like to create a parametric token holder for tabletop games, and I need a bit of help with the OpenSCAD code.

Essentially, I want to be able to define the following:

*   **Token Shape:** I need to support triangular, square, pentagonal, hexagonal, and circular tokens.
*   **Token Diameter:** I need to specify the diameter of my tokens.
*   **Holder Height:** The overall height of the token holder.
*   **Base Thickness:** The thickness of the base of the holder.
*   **Number of Organizers:** I want to be able to create multiple token holders that will be printed together.
*   **Optional Cover:**  I'd like an option to generate a matching cover for each token holder.

The token holders should have a base and a wall, with a cutout matching the chosen token shape. I'd also like to have slots on the sides that will help hold the wall and base together. The tokens should fit into the center of each organizer. The covers should sit on top of the holders and have the same cutouts on the bottom so they can sit nicely on top of them.

Could you generate an OpenSCAD file (or multiple if it makes sense), that I can use to generate this? It should be parametric. I don’t expect the library files, but please do tell me if it uses libraries.

[Assistant]
Parametric_multi_shape_token_holder_final.scad:
```
//==================================================
// MultiShape Token Holder by @satanin
//==================================================
// Choose the shape of your tokens
token_sides=60; // [3:Triangle, 4:Square, 5:Pentagon, 6:Hexagon, 60:Circular]
// Diameter of your token
token_diameter=19;
// Height of the token holder
piece_height=10;
// Thickness of the base
base_thickness=2;
// How many?
token_organizers=1;
print_cover="yes";//["yes":Yes, "no":No]

/* Hidden */
// Do not edit beyond this point unless
// you know what you´re doing.
//---------------------------------
// Spacer to give tokens some extra space
token_spacer=1;
token_radius=token_diameter/2+token_spacer/2;
structure_spacer=1;
structure_diameter=token_diameter+structure_spacer;
structure_height=piece_height-base_thickness;

module base(){
	difference(){
		cube([structure_diameter,structure_diameter,base_thickness]);
		translate([token_radius,token_radius,0]){
			cylinder(base_thickness*3,structure_diameter/3,structure_diameter/3, center= true, $fn=60);
		}
	}
}

module body(){
	base();
  difference(){
    difference(){
      translate([0,0,base_thickness]){cube([structure_diameter, structure_diameter, structure_height]);}
      translate([token_radius, token_radius, 0]){cylinder(structure_height*3, token_radius-0.1, token_radius-0.1, center=true, $fn=token_sides);}
    }

    translate([structure_diameter/2-token_diameter/6,-structure_diameter*3,base_thickness]){cube([token_diameter/3,token_diameter*5,structure_height*2]);}
    translate([-structure_diameter*3,structure_diameter/2-token_diameter/6,base_thickness]){cube([token_diameter*5,token_diameter/3,structure_height*2]);}
  }
}

module cover(){
	if(print_cover=="yes"){
		cover_thickness=base_thickness;
		translate([0,-structure_diameter,piece_height]){
			rotate([180,0,0]){
				difference(){
					translate([0,0,piece_height-cover_thickness]){
						color("indigo"){
							cube([structure_diameter,structure_diameter,cover_thickness]);
						}
					}
					body();
				}
			}
		}
	}
}

for(i=[0:1:token_organizers-1]){
	translate([structure_diameter*i, 0, 0]){
		body();
	}
	translate([(structure_diameter+1)*i,0,0]){
		cover();
	}
}

```


[User]
I'd like to create a customizable origami rooster design in OpenSCAD, similar to the one I saw on Thingiverse. I want to be able to control the overall size, model height, and the thickness of both the outer and inner outlines. The inner outlines should have rounded ends. I'd also like the option to flip the model horizontally.

The design is based on specific points which I will provide:

**Outer Points:**

A1 = [250, 811];
A2 = [397, 714];
A3 = [394, 649];
A4 = [605, 570];
A5 = [681, 721];
A6 = [567, 817];
A7 = [932, 1104];
A8 = [1708, 160];
A9 = [1880, 273];
A10 = [1934, 437];
A11 = [1958, 658];
A12 = [1939, 679];
A13 = [1928, 861];
A14 = [1723, 1151];
A15 = [1657, 1419];
A16 = [1489, 1693];
A17 = [665, 1693];
A18 = [347, 1026];
A19 = [388, 787];

**Inner Points:**

B1 = [416, 680];
B2 = [598, 607];
B3 = [910, 1146];
B4 = [1799, 308];
B5 = [1834, 368];
B6 = [1850, 550];

**Polygons:** (these are combinations of the A and B points)

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

The outer outline is formed by all the points A1-A19, and the inner shapes are cut out using the polygons C1-C13.

I'd like all measurements to be in millimeters.

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

[Assistant]
customizable_origami_rooster.scad:
```
/*
 * Customizable Origami - Rooster - https://www.thingiverse.com/thing:2770373
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2018-01-26
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

// preview[view:north, tilt:top]

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.7; //[0.5:0.1:20]

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

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.5; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [250, 811];
A2 = [397, 714];
A3 = [394, 649];
A4 = [605, 570];
A5 = [681, 721];
A6 = [567, 817];
A7 = [932, 1104];
A8 = [1708, 160];
A9 = [1880, 273];
A10 = [1934, 437];
A11 = [1958, 658];
A12 = [1939, 679];
A13 = [1928, 861];
A14 = [1723, 1151];
A15 = [1657, 1419];
A16 = [1489, 1693];
A17 = [665, 1693];
A18 = [347, 1026];
A19 = [388, 787];

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

// Inner Points
B1 = [416, 680];
B2 = [598, 607];
B3 = [910, 1146];
B4 = [1799, 308];
B5 = [1834, 368];
B6 = [1850, 550];

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

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

min_x = A1[0];
min_y = A8[1];
max_x = A11[0];
max_y = A17[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
I'm looking to design a two-part bobbin for a sewing machine, specifically based on the dimensions of an Elna bobbin but with the intention of making it customizable for other machines.

The bobbin should have a main cylindrical body, and then it's split into two pieces: a "top" and a "bottom" that slip together.  The assembled bobbin should be roughly 20.1mm in diameter and 10.8mm tall, with a central hole of 6.35mm. There will be some slight differences between the two pieces, mainly where they connect, and I'd like to have a small 'slop' factor built in to the joining diameter to accommodate tolerances. I'd like a way to specify the 'slop' as a parameter.

Here are more detailed parameters I was thinking of for each section:

**General Parameters:**

*   `diameter`: (default 20.1mm) Overall diameter of the bobbin.
*   `height`: (default 10.8mm) Overall height of the assembled bobbin.
*   `hole_diameter`: (default 6.35mm) Diameter of the central hole.
*   `wall`: (default 0.96mm) Thickness of the wall of the bobbin.
*    `slop`: (default 0.15mm) Extra diameter added to the slip fit for tolerance.
*    `reinforcement_height`: (Calculated as 1.5 * wall) height of the reinforcement ring where the parts are thicker.

**Top Piece:**

*   `top_outer_diameter`: (Calculated as `hole_diameter + 4 * wall`).  The outer diameter of the main part of the top piece.
*   `top_inner_diameter`: (Calculated as `top_outer_diameter - 2 * wall`).  The inner diameter of the main part of the top piece.
*   `top_height`: (Calculated as `height - 2.5 * wall`).  The height of the main part of the top piece.

**Bottom Piece:**

*   `bottom_outer_diameter`: (Calculated as `hole_diameter + 2 * wall`). The outer diameter of the main part of the bottom piece.
*   `bottom_inner_diameter`: (Calculated as `hole_diameter`).  The inner diameter of the main part of the bottom piece.
*   `bottom_height`: (Calculated as `height - 3.5 * wall`). The height of the main part of the bottom piece.

**Features:**

*   The top piece should have a cylindrical base of `1.5 * wall` height and main section of `top_height` with the `top_outer_diameter`, as well as a reinforcement ring with a diameter of `diameter` and a height of `reinforcement_height` at its base.
*   The bottom piece should have a cylindrical base of `1.5 * wall` height and main section of `bottom_height` with the `bottom_outer_diameter`, as well as a reinforcement ring with a diameter of `diameter` and a height of `reinforcement_height` at its base.
*   The top piece should have a set of 7 cutouts (holes) equally spaced around a circle with a radius of `diameter / 3` and a diameter of 4mm each, and should be 3mm tall. They are in the top portion.

I want the design to be parametric so all of these values can be adjusted. I'd also like to specify `$fn` to control the smoothness of the cylinders, but ideally with a default of `64`.

I think I need a `top()` module and a `bottom()` module to create the separate pieces, and then have a main section where both modules are instantiated, making sure that the bottom module is flipped so that it can connect.  I will probably need to add some superglue to make it stay together, but the fit should be very tight, so make sure the diameters are appropriate for a slip fit.

I'm looking to create this in OpenSCAD and would be grateful if you could generate the necessary `.scad` file.

[Assistant]
Elna_Bobbin.scad:
```
$fn = 64;

diameter = 20.1;
height = 10.8;
hole_diameter = 6.35;
wall = 0.96;

reinforcement_height = 1.5 * wall;

// fudge to get slip parts to *stay* together
slop = 0.15;

top_outer_diameter = hole_diameter + 4 * wall;
top_inner_diameter = top_outer_diameter - 2 * wall;
top_height = height - 2.5 * wall;

bottom_outer_diameter = hole_diameter + 2 * wall;
bottom_inner_diameter = hole_diameter;
bottom_height = height - 3.5 * wall;

module holes() {
  count = 7;
  cutout_diameter = 4;
  center_offset = diameter / 3;
  for (i = [1:1:count])
    translate([sin(360 * i / count) * center_offset, cos(360 * i / count) * center_offset, 0])
      rotate([0, 0, atan2(cos(360 * i / count) * center_offset, sin(360 * i / count) * center_offset)])
        cylinder(d=cutout_diameter, h=3, center=true, $fn = 3);
}

module top() {
  difference() {
    group() {
      color("Red")
        cylinder(d=diameter, h=1.5 * wall, center=true);
      color("Magenta")
        cylinder(d=top_outer_diameter + slop, h=top_height);
      color("Pink")
        cylinder(d1=diameter, d2=top_outer_diameter, h=reinforcement_height);
    }
    group() {
      color("Blue")
        holes();
      color("Orange")
        translate([0, 0, -1 * wall])
          cylinder(d=bottom_inner_diameter + 0.5 * wall, h = 3.1);
      color("Turquoise")
        translate([0, 0, 2*wall])
          cylinder(d1=top_outer_diameter - 2 * wall + slop, d2=top_outer_diameter - 2 * wall, h=top_height + 2 * wall);
    }
  }
}

// slips inside of top
module bottom() {
  difference() {
    group() {
      color("Green")
        cylinder(d=diameter, h=1.5 * wall, center=true);
      color("Turquoise")
        cylinder(d1=bottom_outer_diameter, d2=bottom_outer_diameter + slop, h=bottom_height);
      color("LightCyan")
        cylinder(d1=diameter, d2=bottom_outer_diameter + 2 * wall, h=reinforcement_height);
    }
    group() {
      color("Orange")
        translate([0, 0, -1 * wall])
          cylinder(d=bottom_inner_diameter + 0.5 * wall, h=1.75 * wall);
      color("MediumBlue")
        translate([0, 0, 0.5 * wall])
          cylinder(d=bottom_inner_diameter, h=bottom_height + 2 * wall);
    }
  }
}

top();
translate([diameter, diameter])
  scale([1, -1, 1])   // this line can go away but need to test print first to be 100% sure
    bottom();
```


[User]
I need to design a customizable clamp for various cylindrical objects, like pipes or rods. It should be parametric so I can adjust the dimensions easily. Here's what I'm thinking:

The clamp should be a split design, basically a cylinder cut in half, with flat plates on either side for bolting it together. I need to control the following:

*   **Clamp Inner Diameter:** This is the diameter of the rod or pipe that the clamp will grip. I'll need to specify this value.
*   **Clamp Diameter Offset:** The clamp needs to be slightly larger than the inner diameter to actually clamp, so I need to specify this extra amount.
*   **Clamp Length:** The axial length of the clamp.
*   **Wall Thickness:** The thickness of the material forming the cylindrical part of the clamp.
*   **Plate Thickness:** The thickness of the flat plates where the screw holes are.
*   **Plate Border:**  I need to define a border around the screw hole recesses on the flat plates.
*   **Number of Screws:**  I want to specify how many screw holes there are on each side of the clamp.
*   **Screw Diameter:** The diameter of the screw holes.
*   **Screw Opposite Distance:** The distance between the screw holes on opposite plates. If I set this to 0, then the distance should be automatically calculated from the clamp size.
*   **Screw Distance from Edge:** How far the first and last screw are from the edge of the plate. A zero value should mean that the hole is placed automatically according to the plate border.
*   **Screw Recess Diameter:** I want to be able to include recesses for nuts or screw heads. This is the diameter of those recesses. If set to 0, no recess should be generated.
*   **Screw Recess Shape:** Should these recesses be shaped for a nut or should they be round?
*   **Screw Head/Nut Thickness:** How deep the screw head or nut recesses should be. 0 should mean a flat plate with no recesses.

I'd also like it to be designed so that it's easy to use the OpenSCAD customizer, and I want a few example renderings for the previews. Can you provide the OpenSCAD file(s) for me? I don't expect any external libraries for this.

[Assistant]
clamp.scad:
```
// *********************************************
//
// Customizable/parametric clamp script
// Author: indazoo
// Credits :
//   bardiir   https://www.thingiverse.com/thing:2427479
//   Marko22   https://www.thingiverse.com/thing:2484467
//
// *********************************************

/* [Clamp Definitions] */

//Diameter of the rod or pipe to clamp
clamp_inner_diameter = 20; //[1:200]

//Clamps need some space to apply pressure.
clamp_diameter_offset = 1; //[0:200]

//Clamp length
clamp_length = 50; //[1:200]

//Wall thickness
clamp_wall_thickness = 3; //[1:20]

/* [Plate Definitions] */

//Plate thickness where the screw holes are.
wall_plate_thickness = 4; //[1:20]

//Border around the screw recess.
wall_plate_border = 1; //[1:20]

/* [Screw Definitions] */

//Count of screw holes to be places alongside each side.
num_screws = 2; //[0:20]

//Diameter of screw holes.
screw_diameter = 4; //[1:15]

//Distance of opposite screws. Useful for repair parts where the screw/bolt distance must match. Must be at least larger than the clamps inner diameter. Zero disables this and gives automatic distance depending of clamp size.
screw_opposite_distance = 0; //[0:200]

//Distance for the first and the last screw from the edge. Zero disables this so the holes will placed according to plate border value.
screw_distance_from_edge = 0; //[0:100]

//Diameter of nut trap or screw head diameter (set to 0 to disable).
screw_recess_diameter = 8; //[0:20]

//Make a recess as nut or round shape.
screw_recess_shape = "nut"; //[nut,round]

//How deep the recess is. Set to zero to get a flat clamp plate.
screw_head_nut_thickness = 2; //[0:20]

/* [Hidden] */
plate_r = clamp_wall_thickness/2;

// Output for thingiverse customizer//

rotate([0,90,0])
clamp(clamp_inner_diameter = clamp_inner_diameter,
            clamp_diameter_offset = clamp_diameter_offset,
            clamp_length = clamp_length,
            clamp_wall_thickness = clamp_wall_thickness,
            wall_plate_thickness = wall_plate_thickness,
            wall_plate_border = wall_plate_border,
            num_screws = num_screws,
            screw_diameter = screw_diameter,
            screw_opposite_distance = screw_opposite_distance,
            screw_distance_from_edge = screw_distance_from_edge,
            screw_recess_diameter = screw_recess_diameter,
            screw_recess_is_nut = screw_recess_shape == "nut" ? true : false,
            screw_head_nut_thickness= screw_head_nut_thickness);

// ************************************
// Samples / output for STL picture
// ************************************
/*
// narrow one screw clamp
translate([0,0,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 12,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 2,
            num_screws = 1,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 0,
            screw_recess_diameter = 8,
            screw_recess_is_nut = false,
            screw_head_nut_thickness = 2) ;

translate([15,0,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 12,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 2,
            num_screws = 1,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 0,
            screw_recess_diameter = 8,
            screw_recess_is_nut = true,
            screw_head_nut_thickness = 2) ;

// narrow one screw clamp without recess at fixed distance
translate([50,0,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 12,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 8,
            wall_plate_border = 2,
            num_screws = 1,
            screw_diameter = 4,
            screw_opposite_distance = 36,
            screw_distance_from_edge = 0,
            screw_recess_diameter = 8,
            screw_recess_is_nut = false,
            screw_head_nut_thickness = 0) ;

translate([65,0,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 12,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 8,
            wall_plate_border = 2,
            num_screws = 1,
            screw_diameter = 4,
            screw_opposite_distance = 36,
            screw_distance_from_edge = 0,
            screw_recess_diameter = 8,
            screw_recess_is_nut = true,
            screw_head_nut_thickness = 0) ;

// Dual screw clamp
translate([0,45,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 10,
            clamp_diameter_offset = 1,
            clamp_length = 40,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 1,
            num_screws = 2,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 10,
            screw_recess_diameter = 8,
            screw_recess_is_nut = true,
            screw_head_nut_thickness = 2) ;
translate([50,45,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 10,
            clamp_diameter_offset = 1,
            clamp_length = 40,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 1,
            num_screws = 2,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 10,
            screw_recess_diameter = 8,
            screw_recess_is_nut = false,
            screw_head_nut_thickness = 0) ;

// triple screw clamp
translate([0,90,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 40,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 1,
            num_screws = 3,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 0,
            screw_recess_diameter = 8,
            screw_recess_is_nut = true,
            screw_head_nut_thickness = 2) ;
translate([50,90,0])
rotate([0,90,0])
clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 50,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 1,
            num_screws = 3,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 10,
            screw_recess_diameter = 8,
            screw_recess_is_nut = false,
            screw_head_nut_thickness = 0) ;
*/
// *****************************************************
// Code
// *****************************************************

module clamp(clamp_inner_diameter = 20,
            clamp_diameter_offset = 1,
            clamp_length = 50,
            clamp_wall_thickness = 3,
            wall_plate_thickness = 4,
            wall_plate_border = 1,
            num_screws = 2,
            screw_diameter = 4,
            screw_opposite_distance = 0,
            screw_distance_from_edge = 10,
            screw_recess_diameter = 8,
            screw_recess_is_nut = true,
            screw_head_nut_thickness = 2)
{
    plate_length_p = plate_length(
                        screw_opposite_distance = screw_opposite_distance,
                        wall_plate_border = wall_plate_border,
                        clamp_wall_thickness = clamp_wall_thickness,
                        clamp_inner_diameter = clamp_inner_diameter,
                        screw_recess_is_nut = screw_recess_is_nut,
                        screw_recess_diameter = screw_recess_diameter);
    screwhole_distance_from_edge_p = screwhole_distance_from_edge(
                                        num_screws = num_screws,
                                        clamp_length = clamp_length,
                                        screw_distance_from_edge = screw_distance_from_edge,
                                        wall_plate_border = wall_plate_border,
                                        screw_recess_diameter = screw_recess_diameter
                                        );
    screwhole_distance_p = screwhole_distance(num_screws = num_screws,
                            clamp_length = clamp_length,
                            screwhole_distance_from_edge = screwhole_distance_from_edge_p
                            );
    difference()
    {
        //create clamp structure
        union()
        {
            translate([clamp_diameter_offset,0,0])
            difference()
            {
                cylinder(d=clamp_inner_diameter+clamp_wall_thickness*2,h=clamp_length,$fn=100);
                translate([0,0,-1])
                //remove inner cylinder
                cylinder(d=clamp_inner_diameter,h=clamp_length+2,$fn=100);
                //cut half of clamp
                translate([-clamp_diameter_offset,
                            -(clamp_inner_diameter+clamp_wall_thickness*16)/2,
                            -clamp_length/2])
                    cube([(clamp_inner_diameter+clamp_wall_thickness)*2+1,
                        clamp_inner_diameter+clamp_wall_thickness*16,
                        clamp_length*2]);
            }
            //add plates on the left/right
            translate([0,
                        plate_center_x(clamp_inner_diameter = clamp_inner_diameter,
                                        plate_length = plate_length_p),
                        clamp_length/2])
            rotate([180,0,0])
            plate(plate_length = plate_length_p,
                    wall_plate_thickness = wall_plate_thickness,
                    clamp_length = clamp_length);
            translate([0,
                        -plate_center_x(clamp_inner_diameter = clamp_inner_diameter,
                                        plate_length = plate_length_p),
                        clamp_length/2])
            plate(plate_length = plate_length_p,
                    wall_plate_thickness = wall_plate_thickness,
                    clamp_length = clamp_length);
        }
        //remove screw holes
        if(num_screws > 0)
        {
            translate([0,-screw_center_x(screw_opposite_distance = screw_opposite_distance,
                            clamp_inner_diameter = clamp_inner_diameter,
                            wall_plate_border = wall_plate_border,
                            screw_recess_is_nut = screw_recess_is_nut,
                            screw_recess_diameter = screw_recess_diameter,
                            plate_length = plate_length_p),
                        0])
               recess(num_screws = num_screws,
                        screw_diameter = screw_diameter,
                        wall_plate_thickness = wall_plate_thickness,
                        screw_head_nut_thickness = screw_head_nut_thickness,
                        screw_recess_is_nut = screw_recess_is_nut,
                        screw_recess_diameter = screw_recess_diameter,
                        recess_height = screw_head_nut_thickness,
                        screwhole_distance_from_edge = screwhole_distance_from_edge_p,
                        screwhole_distance = screwhole_distance_p);
            translate([0,+screw_center_x(screw_opposite_distance = screw_opposite_distance,
                            clamp_inner_diameter = clamp_inner_diameter,
                            wall_plate_border = wall_plate_border,
                            screw_recess_is_nut = screw_recess_is_nut,
                            screw_recess_diameter = screw_recess_diameter,
                            plate_length = plate_length_p),
                        0])
                recess(num_screws = num_screws,
                        screw_diameter = screw_diameter,
                        wall_plate_thickness = wall_plate_thickness,
                        screw_head_nut_thickness = screw_head_nut_thickness,
                        screw_recess_is_nut = screw_recess_is_nut,
                        screw_recess_diameter = screw_recess_diameter,
                        recess_height = screw_head_nut_thickness,
                        screwhole_distance_from_edge = screwhole_distance_from_edge_p,
                        screwhole_distance = screwhole_distance_p);
        }
    }
}

//this function would minimize the width of the clamp but then the counterpart may not have the same width
function screw_recess_virtual_diameter(screw_recess_is_nut = true,
                                        screw_recess_diameter = 8)
            //0.88 is relation between diameter of nut versus width of flat sides
            //= (screw_recess_is_nut ? screw_recess_diameter*0.88 : screw_recess_diameter);
            = screw_recess_diameter;

function plate_length(screw_opposite_distance = 0,
                    wall_plate_border = 2,
                    clamp_wall_thickness = 3,
                    clamp_inner_diameter = 20,
                    screw_recess_is_nut = true,
                    screw_recess_diameter = 8
                    )
            = screw_opposite_distance == 0 ?
                screw_recess_virtual_diameter(screw_recess_is_nut = screw_recess_is_nut,
                                        screw_recess_diameter = screw_recess_diameter)
                + wall_plate_border
                + clamp_wall_thickness
            : (screw_opposite_distance - clamp_inner_diameter)/2
                + screw_recess_virtual_diameter(screw_recess_is_nut = screw_recess_is_nut,
                                        screw_recess_diameter = screw_recess_diameter)/2
                + wall_plate_border ;

function plate_center_x(clamp_inner_diameter=20,
                        plate_length = 10)
            = clamp_inner_diameter/2 + plate_length/2;

function screw_center_x(screw_opposite_distance = 0,
                        clamp_inner_diameter = 20,
                        wall_plate_border = 2,
                        screw_recess_is_nut = true,
                        screw_recess_diameter = 8,
                        plate_length = 10
                        )
            = screw_opposite_distance > 0 ?
            screw_opposite_distance/2
            :clamp_inner_diameter/2
                + plate_length
                - wall_plate_border
                - screw_recess_virtual_diameter(screw_recess_is_nut = screw_recess_is_nut,
                                                screw_recess_diameter = screw_recess_diameter)/2
                +0.05 ; //correction factor because screw_recess_virtual_diameter() is not exact to prevent ultra thin wall with border = 0

function screwhole_distance_from_edge(num_screws = 2,
                                    clamp_length = 50,
                                    screw_distance_from_edge = 0,
                                    wall_plate_border = 2,
                                    screw_recess_diameter = 8
                                    )
            =
   num_screws == 1 ? clamp_length/2
   : screw_distance_from_edge == 0 || 2*screw_distance_from_edge > clamp_length ? wall_plate_border + screw_recess_diameter/2
   : screw_distance_from_edge;

function screwhole_distance(num_screws = 2,
                            clamp_length = 50,
                            screwhole_distance_from_edge = 10
                            )
           = num_screws == 1 ? 0 : (clamp_length - 2*screwhole_distance_from_edge) / (num_screws-1) ;

/*
echo("clamp_length",clamp_length);
echo("screwhole_distance_from_edge()",screwhole_distance_from_edge());
echo("screwhole_distance()",screwhole_distance());
echo(clamp_length-screwhole_distance_from_edge()-(screwhole_distance()*1));
*/

module plate(plate_length = 10, wall_plate_thickness = 4, clamp_length = 50)
{
    translate([-wall_plate_thickness,0,0])
    rotate([0,90,0])
    roundedRect([clamp_length,plate_length,wall_plate_thickness],plate_r , $fn=30);
}

module recess(num_screws = 2,
                screw_diameter = 4,
                wall_plate_thickness = 4,
                screw_head_nut_thickness = 3,
                screw_recess_is_nut = true,
                screw_recess_diameter = true,
                recess_height = 3,
                screwhole_distance_from_edge = 10,
                screwhole_distance = 0
             )
{
    if(num_screws>0)
    {
        for(i=[0:num_screws-1])
        {
            translate([0,0,screwhole_distance_from_edge+screwhole_distance*i])
                screwhole(screw_diameter = screw_diameter,
                        wall_plate_thickness = wall_plate_thickness,
                        screw_head_nut_thickness = screw_head_nut_thickness,
                        screw_recess_is_nut = screw_recess_is_nut,
                        screw_recess_diameter = screw_recess_diameter,
                        recess_height = recess_height
                        );
        }
    }
}

module screwhole(screw_diameter = 4,
                wall_plate_thickness = 4,
                screw_head_nut_thickness = 3,
                screw_recess_is_nut = true,
                screw_recess_diameter = true,
                recess_height = 3
                )
{
    rotate([0,90,0])
    union() {
        cylinder(d=screw_diameter, h=wall_plate_thickness+20, $fn=30, center=true);
        if(screw_head_nut_thickness > 0)
        {
            translate([0,0,(-(20+recess_height)/2)- (recess_height == 0 ? wall_plate_thickness +0.01: wall_plate_thickness-recess_height) ])
            if(screw_recess_is_nut)
                cylinder(d=screw_recess_diameter, h=recess_height+20, $fn=6, center=true);
            else
                cylinder(d=screw_recess_diameter, h=recess_height+20, $fn=30, center=true);
        }
    }
}

// size - [x,y,z]
// radius - radius of corners
module roundedRect(size, radius)
{
	x = size[0]-radius;
	y = size[1]-radius;
	z = size[2];

	linear_extrude(height=z)
	hull()
	{
		// place 4 circles in the corners, with the given radius
		translate([(-x/2)+(radius/2), (-y/2)+(radius/2), 0])
		circle(r=radius);

		translate([(x/2)-(radius/2), (-y/2)+(radius/2), 0])
		circle(r=radius);

		translate([(-x/2)+(radius/2), (y/2)-(radius/2), 0])
        square(size = [radius*2, radius*2], center = true);

		translate([(x/2)-(radius/2), (y/2)-(radius/2), 0])
		square(size = [radius*2, radius*2], center = true);
	}
}
```