[User]
I'd like a parametric test print model generator in OpenSCAD. It should be able to create a base with multiple sloped blocks on top, and let me choose whether the blocks are solid or hollow. I also need to be able to label the model with dimensions and the slope angles, or disable the labels completely.

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

*   **`shells`**: This should be an option to make the sloped blocks solid or hollow. I'd like a simple switch between "Solid" (1) and "Shell" (2).
*   **`labels`**: This will control the labels: 0 for no labels, 1 for just the plane labels (XY, XZ, YZ), 2 for just the numeric dimensions and slope angles, and 3 for all the labels.
*   **`cube_x`**: The width of the entire model along the X axis.
*   **`cube_y`**: The depth of the model along the Y axis, and the depth of each sloped block.
*   **`cube_z`**: The height of the whole model, including the base and the blocks.
*   **`base_th`**: The thickness of the base wall.
*   **`block_gap`**: The gap between sloped blocks when there are multiple blocks.
*   **`angles`**: A list of angles for the sloped blocks. If I only provide `[0]`, it should make a plain box. Negative angles or angles greater than 90 should be recalculated to fall between 0 and 90 degrees. An angle of 90 should create a "bridge" instead of a slope.
*   **`shell_th`**: The thickness of the shell when the blocks are hollow.
*   **`font_size`**: The size of the text labels.
*  **`detail`**: The level of detail for the STL mesh, mainly used for text.

I'd like the generated model to have three reinforced outer walls (for XY, XZ and YZ planes).

The text labels for the planes (XY, XZ, and YZ) should be centered on the corresponding faces, using a font called "Roboto", if possible. I'd also like to have numeric dimensions on the XY plane in millimeters. The slope angles should be shown on the XZ plane.

I understand that text adjustment might be required, and I need to visually check the model before exporting. I also know there is some risk involved and I shouldn't leave the printer unattended.

I don't need any external libraries for this.

[Assistant]
PTPM_V1.03.scad:
```
/////////////////////////////////////////////////////////////////
// Parametric Test Print Model
// Version: V1.03
// Author: thorgal (2019-05-11)
// Program: OpenSCAD Version 2019.01 RC4
// Licensed: Creative Commons - Attribution - Non-Commercial - Share Alike (by-nc-sa)
// Source: https://www.thingiverse.com/thing:3610548
//
// Usefull for slopes, outer dimensions, moire and other issues
//
// You can make the model solid or hollow to save filament
// or resin. You can insert as many sloped blocks as you like.
// Just keep the list in square brackets separated with commas
// If you will use just one angle of 0 degrees (angles = [0]),
// than the result will be plain box.
// Negative angles and angle sizes above 90 degrees are
// recalculated to fit between 0 and 90 degrees.
// Type angle 90degrees to make a bridge instead of slope.
// Manual text adjustment is required and model have to be
// checked visualy prior to exporting as my programming skill
// in OpenSCAD is not good enough to check all the dependences.
// Sorry for inconvenience.
//
// You are using this model at your own risk. Whenever you are
// experimenting with print quality, do not keep the printer
// unattended. Keep in mind that model created with this
// parametric tool may not be printable.
//
// Enjoy
/////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////////////////

// Mass of sloped blocks
shells = 1; // [1:Solid,2:Shell]

// Display labels
labels = 3; // [0:None,1:Plains,2:Numbers,3:All]

// Width (X axis size of the whole model, will be divided by number of blocks)
cube_x = 60; // [5:1:100]

// Depth (Y axis size of the whole model and each sloped block)
cube_y = 33; // [5:1:100]

// Height (Z axis size of the whole model, block and base together )
cube_z = 10; // [5:1:100]

// Base wall thickness for XY, XZ and YZ plane
base_th = 2.0; //[0.1:0.1:5.0]

// Gap between sloped blocks (if more than one block required)
block_gap = 1.0; // [0.0:0.1:5.0]

// List of slopes and number of block (0 is vertical, 90 means bridge; separate numbers with comma; at the begining and end have to be a square bracket, atleast one value have to be specified, [0] makes a box)
angles = [0,15,30,45,60,75,90]; //

// Block shell thickness
shell_th = 1.5; //[0.1:0.1:5.0]

// Font size (change it according to size of the model so all texts will be visible)
font_size = 3; //[1.5:0.5:10.0]

// Level of detail for the STL mesh (mostly for texts)
detail = 8; // [8:Draft, 16:Coarse, 32:Medium, 64:High, 128:Ultra]

/* [Hidden] */
block_count = len(angles); // Number of blocks
block_width = (cube_x - (block_gap*(block_count-1)))/block_count; //Width of each block
switch_angle = atan((cube_y-base_th)/(cube_z-base_th)); // Maximal angle that can be made from front to bottom making front sharp edge. Above this angle the slope is made from bottom to front making flat surface in front of the block.
a = 0.1*1; // Add for substraction. Required for OpenSCAD to do the substraction correctly.
font = "Roboto"; // Font used for dimensions and descriptions
font_extr = base_th/3; // Font extrusion depth
font_spacing = 1; // Space between lines of text
spacing = 1*1; // Font spacing
$fn = detail; // Number of faces per circle

/////////////////////////////////////////////////////////////////
// Main 3D model
/////////////////////////////////////////////////////////////////

draw ();

module draw () {
    difference () {
        union () {
            if (shells == 1) draw_solids ();
            if (shells == 2) draw_shells ();
            draw_corner ();
        }
        if (labels == 1) draw_labels ();
        if (labels == 2) draw_numbers ();
        if (labels == 3) draw_labels_and_numbers ();
    }
}

/////////////////////////////////////////////////////////////////
// This will create solid blocks with slopes
/////////////////////////////////////////////////////////////////
module draw_solids (){
    for (i = [0:1:block_count-1]) { // draw slopes according to the list
        angle = (360+angles[i]) % 90; // make the angle positive and less or equal to right angle
        if (angles[i]!=0 && angle==0) { // if there was right angle => draw a bridge instead of slope
            difference () {
                translate([(i*(block_width+block_gap)),base_th,base_th]) cube([block_width,cube_y-base_th,cube_z-base_th], center = false);
                translate([(i*(block_width+block_gap))-a,base_th-a,base_th-a]) cube([block_width+(2*a),cube_y-base_th-base_th+a,cube_z-(base_th*2)+a], center = false);
            }
        }
        else { // if angle is less than horizontal draw a slope
            if (angle <= switch_angle) { // draw a slope from front
                intersection () { // draw a block_width slope from front
                    translate([(i*(block_width+block_gap)),base_th,base_th]) cube([block_width,cube_y-base_th,cube_z-base_th], center = false);
                    translate([(i*(block_width+block_gap)),cube_y,cube_z]) rotate([180-angle,0,0]) cube([block_width,cube_y+cube_z,cube_y+cube_z], center = false);
                }
            }
            else { // otherwise draw a slope from back
                intersection () { // draw a block_width slope from bottom
                    translate([(i*(block_width+block_gap)),base_th,base_th]) cube([block_width,cube_y-base_th,cube_z-base_th], center = false);
                    translate([(i*(block_width+block_gap)),base_th,base_th]) rotate([90-angle,0,0]) cube([block_width,cube_y+cube_z,cube_y+cube_z], center = false);
                }
            }
        }
    }
}

/////////////////////////////////////////////////////////////////
// This will create shells with slopes
/////////////////////////////////////////////////////////////////
module draw_shells (){
    for (i = [0:1:block_count-1]) { // draw slopes according to the list
        angle = (360+angles[i]) % 90; // make the angle positive and less or equal to right angle
        if (angles[i]!=0 && angle==0) { // if there was right angle => draw a bridge instead of slope
            difference () {
                translate([(i*(block_width+block_gap)),base_th,base_th]) cube([block_width,cube_y-base_th,cube_z-base_th], center = false);
                translate([(i*(block_width+block_gap))-a,base_th-a,base_th-a]) cube([block_width+(2*a),cube_y-base_th-base_th+a,cube_z-(base_th*2)+a], center = false);
            }
        }
        else { // if angle is less than horizontal draw a slope
            if (angle <= switch_angle) { // draw a slope from front
                difference () {
                    intersection () { // draw a block_width slope from front
                        translate([(i*(block_width+block_gap)),base_th,base_th]) cube([block_width,cube_y-base_th,cube_z-base_th], center = false);
                        translate([(i*(block_width+block_gap)),cube_y,cube_z]) rotate([180-angle,0,0]) cube([block_width,cube_y+cube_z,cube_y+cube_z], center = false);
                    }
                    intersection () { // substract infill
                        translate([(i*(block_width+block_gap))+shell_th,base_th-a,base_th-a]) cube([block_width-(2*shell_th),cube_y-base_th+(2*a),cube_z-base_th+(2*a)], center = false);
                        translate([(i*(block_width+block_gap))+shell_th,cube_y-(cos(angle)*shell_th)+(sin(angle)*a),cube_z+(sin(angle)*shell_th)+(cos(angle)*a)]) rotate([180-angle,0,0]) cube([block_width-(2*shell_th),cube_y+cube_z,cube_y+cube_z], center = false);
                    }
                }
            }
            else { // otherwise draw a slope from back
                difference () {
                    intersection () { // draw a block_width slope from bottom
                        translate([(i*(block_width+block_gap)),base_th,base_th]) cube([block_width,cube_y-base_th,cube_z-base_th], center = false);
                        translate([(i*(block_width+block_gap)),base_th,base_th]) rotate([90-angle,0,0]) cube([block_width,cube_y+cube_z,cube_y+cube_z], center = false);
                    }
                    intersection () { // substract infill
                        translate([(i*(block_width+block_gap))+shell_th,base_th-a,base_th-a]) cube([block_width-(2*shell_th),cube_y-base_th-shell_th+a,cube_z-base_th+(2*a)], center = false);
                        translate([(i*(block_width+block_gap))+shell_th,base_th-(cos(angle)*shell_th)-(sin(angle)*a),base_th+(sin(angle)*shell_th)-(cos(angle)*a)]) rotate([90-angle,0,0]) cube([block_width-(2*shell_th),cube_y+cube_z,cube_y+cube_z], center = false);
                    }
                }
            }
        }
    }
}

/////////////////////////////////////////////////////////////////
// Three main plains reinforced to measure outer dimensions
/////////////////////////////////////////////////////////////////
module draw_corner (){
    difference() {
            cube([cube_x,cube_y,cube_z], center = false);
            translate([base_th,base_th,base_th]) cube([cube_x-base_th+a,cube_y-base_th+a,cube_z-base_th+a], center = false);
        }
}

/////////////////////////////////////////////////////////////////
// Draw only centered cartesian plains description
/////////////////////////////////////////////////////////////////
module draw_labels (){
    // YZ plane
    translate([font_extr,cube_y/2,cube_z/2]) rotate([90,0,-90]) linear_extrude(height=font_extr+a) text(text = "YZ", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    // XY plane
    translate([cube_x/2,cube_y/2,font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = "XY", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    // XZ plane
    translate([cube_x/2,font_extr,cube_z/2]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = "XZ", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
}

/////////////////////////////////////////////////////////////////
// Draw just centered dimensions and slopes
/////////////////////////////////////////////////////////////////
module draw_numbers (){
    echo ("numbers", labels);
    // XY plane
    if (shells == 1 && block_count == 1) { // if possible ommit line with thickness
        translate([cube_x/2,cube_y/2,font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = str(cube_x,"x",cube_y,"x",cube_z,"mm"), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    }
    else { // otherwise print all dimensions
        translate([cube_x/2,cube_y/2-((font_size+font_spacing)/2),font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = str(cube_x,"x",cube_y,"x",cube_z,"mm"), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        translate([cube_x/2,cube_y/2+((font_size+font_spacing)/2),font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = str(base_th,"/",shell_th,"/",block_gap,"mm"), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    }
    // XZ plane
    for (i = [0:1:block_count-1]) { // draw slope size according to the list
        angle = (360+angles[i]) % 90;
        if (angles[i]!=0 && angle==0) { // if bridge make it 90 degrees
            angle = 90;
            translate([cube_x-((block_count-i-1)*(block_width+block_gap))-(block_width/2),font_extr,cube_z/2]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = str(angle), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        }
        else { // otherwise print the corrected angle number
            translate([cube_x-((block_count-i-1)*(block_width+block_gap))-(block_width/2),font_extr,cube_z/2]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = str(angle), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        }
    }
}

/////////////////////////////////////////////////////////////////
// Draw cartesian plains description, dimensions and slopes
/////////////////////////////////////////////////////////////////
module draw_labels_and_numbers(){
    // YZ plane
    translate([font_extr,cube_y/2,cube_z/2]) rotate([90,0,-90]) linear_extrude(height=font_extr+a) text(text = "YZ", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    // XY plane
    if (shells == 1 && block_count == 1) { // if possible ommit line with thickness
        translate([cube_x/2,cube_y/2-((font_size+font_spacing)/2),font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = "XY", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        translate([cube_x/2,cube_y/2+((font_size+font_spacing)/2),font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = str(cube_x,"x",cube_y,"x",cube_z,"mm"), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    }
    else { // otherwise print all dimensions
        translate([cube_x/2,cube_y/2-(font_size+font_spacing),font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = "XY", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        translate([cube_x/2,cube_y/2,font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = str(cube_x,"x",cube_y,"x",cube_z,"mm"), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        translate([cube_x/2,cube_y/2+(font_size+font_spacing),font_extr]) rotate([0,180,180]) linear_extrude(height=font_extr+a) text(text = str(base_th,"/",shell_th,"/",block_gap,"mm"), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
    }
    // XZ plane
    if (block_count == 1) { // if possible ommit the line with slopes
        angle = (360+angles[0]) % 90;
        if (angles[0]!=0 && angle==0) { // if bridge make it 90 degrees
            angle = 90;
        }
        if (angle == 0) { // if the angle is O draw just XZ label
            translate([cube_x/2,font_extr,cube_z/2]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = "XZ", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        }
        else { // otherwise draw XZ label with one slope
            translate([cube_x/2,font_extr,(cube_z/2)+((font_size+font_spacing)/2)]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = "XZ", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
            translate([cube_x/2,font_extr,(cube_z/2)-((font_size+font_spacing)/2)]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = str(angle), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        }
    }
    else { // otherwise print XZ label with list of slopes
        translate([cube_x/2,font_extr,(cube_z/2)+((font_size+font_spacing)/2)]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = "XZ", font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
        for (i = [0:1:block_count-1]) { // draw slope size according to the list
            angle = (360+angles[i]) % 90;
            if (angles[i]!=0 && angle==0) { // if bridge make it 90 degrees
                angle = 90;
                translate([cube_x-((block_count-i-1)*(block_width+block_gap))-(block_width/2),font_extr,(cube_z/2)-((font_size+font_spacing)/2)]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = str(angle), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
            }
            else { // otherwise print the corrected angle number
                translate([cube_x-((block_count-i-1)*(block_width+block_gap))-(block_width/2),font_extr,(cube_z/2)-((font_size+font_spacing)/2)]) rotate([90,0,0]) linear_extrude(height=font_extr+a) text(text = str(angle), font = font, size = font_size, spacing = spacing, valign = "center", halign= "center");
            }
        }
     }
}
/////////////////////////////////////////////////////////////////
// End of the script
/////////////////////////////////////////////////////////////////
```


[User]
I'm looking for an OpenSCAD design for a highly customizable L-bracket, similar to the one I've seen described in a few places, but I need it to be completely parametric. I want to be able to easily change things like screw hole size, placement, spacing, as well as fillet sizes, wall thickness, and if it has gussets.

Specifically, I'd like these parameters:

*   **Screw Hole Diameter:** For the main clearance holes.
*   **Screw Hole Counterbore Diameter:** The diameter of the counterbore.
*   **Screw Hole Counterbore Depth:** How deep the counterbore is.
*   **Side 1 Holes:** The number of screw holes along the length of the first side.
*   **Side 1 Hole Spacing:** The spacing between screw holes on the first side.
*   **Side 1 Hole Offset:** Distance from the corner to the first hole on the first side.
*   **Side 2 Holes:** The number of screw holes along the length of the second side.
*   **Side 2 Hole Spacing:** The spacing between screw holes on the second side.
*   **Side 2 Hole Offset:** Distance from the corner to the first hole on the second side.
*   **Width Holes:** Number of screw holes going along the 'width' direction, essentially extending the bracket along the corner axis.
*   **Width Hole Spacing:** The spacing between those holes.
*   **Hole Margin:** The space between the holes and the edges of the bracket on the length and width directions
*   **Thickness:** The overall thickness of the bracket material.
*   **Fillet Radius:** The radius of the fillets on the outer edges of the bracket sides.
*   **Fillet Corner Axis:** A boolean (0 or 1) to enable/disable a fillet on the inside corner, along the bracket's axis.
*   **Fillet Corner Axis Radius:** The radius of the fillet on the corner axis.
*   **Gusset Left:** A boolean to enable/disable a gusset on the left side.
*   **Gusset Right:** A boolean to enable/disable a gusset on the right side.
*   **Gusset Size:** The size of the gussets.
*   **Gusset Thickness:** The thickness of the gussets.
*   **Circle Resolution:** Number of segments for circles.

I'd like a single file that uses these parameters to generate the complete bracket. I don't need any special libraries for this, just basic OpenSCAD.

[Assistant]
Parametric_L_Bracket.scad:
```
// Copyright 2019 jackw01.
// https://jackw01.github.io
// Released under the Creative Commons - Attribution license.

// Screw clearance hole diameter (mm)
screwHoleDiameter = 3.4;
// Screw clearance hole counterbore diameter (mm)
screwHoleCounterboreDiameter = 6.5;
// Screw clearance hole counterbore depth (mm)
screwHoleCounterboreDepth = 3;
// Number of screw holes on side 1 (length dimension)
side1Holes = 2;
// Spacing of screw holes on side 1 (mm)
side1HoleSpacing = 10;
// Spacing between corner axis and first screw hole on side 1 (mm)
side1HoleOffset = 12;
// Number of screw holes on side 2 (length dimension)
side2Holes = 2;
// Spacing of screw holes on side 2 (mm)
side2HoleSpacing = 10;
// Spacing between corner axis and first screw hole on side 2 (mm)
side2HoleOffset = 12;
// Number of screw holes in width direction (essentially extends the bracket along the corner axis)
widthHoles = 2;
// Width of bracket (per hole on width axis) (mm)
widthHoleSpacing = 10;
// Margin around holes on width and length axes (mm)
holeMargin = 6;
// Thickness of the bracket (mm)
thickness = 5;
// Fillet radius (mm)
filletRadius = 5;
// Fillet the corner axis?
filletCornerAxis = 1; // [0:no, 1:yes]
// Fillet radius for corner axis (mm)
filletCornerAxisRadius = 5;
// Gusset on left side?
gussetLeft = 1; // [0:no, 1:yes]
// Gusset on right side?
gussetRight = 1; // [0:no, 1:yes]
// Gusset size (in both dimensions) (mm)
gussetSize = 18;
// Gusset thickness (mm)
gussetThickness = 2;
// Number of segments used to make circular shapes
circleRes = 20;

length = (side1Holes - 1) * side1HoleSpacing + side1HoleOffset + holeMargin;
width = holeMargin * 2 + widthHoleSpacing * (widthHoles - 1);

module hole() {
    union() {
        linear_extrude(height=thickness + length) {
            circle(d=screwHoleDiameter, $fn=circleRes);
        }
        translate([0, 0, thickness - screwHoleCounterboreDepth]) linear_extrude(height=screwHoleCounterboreDepth + length) {
            circle(d=screwHoleCounterboreDiameter, $fn=circleRes);
        }
    }
}

module bracketSide() {
    difference() {
        union() {
            linear_extrude(height=thickness) {
                square([length, width], center=false);
            }
            if (gussetLeft == 1) {
                rotate([-90, 0, 0]) linear_extrude(height=gussetThickness) {
                    polygon(points=[[thickness - 0.2, -thickness + 0.2], [gussetSize + thickness, -thickness + 0.2], [gussetSize / 2 + thickness - 1, -gussetSize / 2 - thickness - 1]]);
                }
            }
            if (gussetRight == 1) {
                translate([0, width - gussetThickness, 0]) rotate([-90, 0, 0]) linear_extrude(height=gussetThickness) {
                    polygon(points=[[thickness - 0.2, -thickness + 0.2], [gussetSize + thickness, -thickness + 0.2], [gussetSize / 2 + thickness - 1, -gussetSize / 2 - thickness - 1]]);
                }
            }
        }
        translate([length - filletRadius, filletRadius, 0]) rotate([0, 0, -90]) linear_extrude(height=length) {
            difference() {
                square([filletRadius * 2, filletRadius * 2], center=false);
                circle(r=filletRadius, $fn=circleRes);
            }
        }
        translate([length - filletRadius, holeMargin * 2 + widthHoleSpacing * (widthHoles - 1) - filletRadius, 0]) linear_extrude(height=length) {
            difference() {
                square([filletRadius * 2, filletRadius * 2], center=false);
                circle(r=filletRadius, $fn=circleRes);
            }
        }
    }
}

module bracketSideHoles() {
    for (x=[0:widthHoles - 1]) {
        for (y=[0:side1Holes - 1]) {
            translate([side1HoleOffset + y * side1HoleSpacing, holeMargin + x * widthHoleSpacing]) hole();
        }
    }
}

difference() {
    union() {
        bracketSide();
        rotate([0, 90, 0]) mirror([1, 0, 0]) bracketSide();
        if (filletCornerAxis == 1) {
            translate([filletCornerAxisRadius * 2, 0, filletCornerAxisRadius * 2]) rotate([0, 90, 90]) linear_extrude(height=width) {
                difference() {
                    square([filletCornerAxisRadius + 0.2, filletCornerAxisRadius + 0.2], center=false);
                    circle(r=filletCornerAxisRadius, $fn=circleRes);
                }
            }
        }
    }
    union() {
        bracketSideHoles();
        rotate([0, 90, 0]) mirror([1, 0, 0]) bracketSideHoles();
    }
}

```


[User]
I need an OpenSCAD design for a guitar nut compensator. It's a small piece that sits at the nut of a guitar, under the strings, and it needs to be customized to achieve perfect intonation.

The design should consist of a base with individual "fingers" or "tabs" extending from it. Each finger will sit under a guitar string, and their heights will be adjustable via parameters. I'm planning to 3D print this, so it needs to be designed for that.

Here are the critical dimensions:

*   **`neck_width`**: The overall width of the nut, which is 41mm.
*   **`strings_gap`**: The spacing between the center of each string, set to 6.8mm.
*   **`base_height`**: The height of the main base of the nut, which will be 0.5mm.
*   **`action`**: The initial height of the string at the nut, which I'll start with 1.3mm (but will need to tweak it).
*   **`compensation`**: This is an array of values – one for each string – that represent the height offset needed for intonation. This will be where I need to make adjustments to fine-tune my nut. The initial values are [0.6, 1.8, 1, 1.6, 2.3, 3].
*   **`extrusion_width`**: The width of a small "lip" added at the top of each finger, which is 0.5mm. This keeps the strings located well on the fingers.
*   **`layer`**: The layer height when printing, this is 0.2mm, and I'd like to be able to generate a few versions of the nut with different heights based on this layer height to test.

The design should be parametric such that:

1.  It uses `neck_width`, `strings_gap`, `base_height`, `action`, `compensation`, `extrusion_width`, and `layer` as parameters.
2.  It creates a base cube that’s `neck_width` wide and `base_height` thick.
3.  It creates six fingers (cubes) extending from this base, each with a width of `strings_gap`. These fingers should be positioned at the correct offsets based on `strings_gap`, and the length of each finger will be determined by the `compensation` value at that string’s position.
4.  Each finger also should have a small rectangular extension on top of the length determined by the `compensation` value. The height of this extension should be the `action` value and its width should be `extrusion_width`.
5.  I would like the design to render three total compensation models, one with the action set to 1.3mm, one with action set to 1.3mm + `layer` (1.5mm), and one set to 1.3mm - `layer` (1.1mm).
6. The code must not use the `polygon()` or the `linear_extrude()` commands, as my printer can have issues with those.

I'm also planning on iterating on these values to fine-tune them for my guitar. Therefore, having a clear structure where I can easily adjust the `compensation` array and `action` is very important.

[Assistant]
kompenzace.scad:
```
neck_width = 41;
strings_gap = 6.8;
base_height = 0.5;
action = 1.3;
compensation = [0.6, 1.8, 1, 1.6, 2.3, 3];
extrusion_width = 0.5;
layer = 0.2;

for (i=[-1:1]) {
  translate ([0, i*20, 0]) {
    compensation(compensation, action+(i*layer));
  }
}

module compensation (compensations, action) {
compensator_width = max(compensations);
union() {
translate([-neck_width/2, 0, 0])
    cube([neck_width, compensator_width, base_height]);
for (i=[0:5]) {
  translate([(i-3)*strings_gap,0,0])
      cube ([strings_gap, compensation[i], action-layer]);
  translate([(i-3)*strings_gap,compensation[i]-extrusion_width, 0])
      cube ([strings_gap, extrusion_width, action]);
}
}
}
```


[User]
Hey, I'm looking to design a parametric RC car trailer wheel mount system in OpenSCAD. I want to use the standard 12mm hex mount for the wheels, because that's what all RC car wheels use, and I want individual ball bearings for each wheel. Also, I'd like to incorporate a bend in the axle for extra ground clearance, and be able to adjust the wheel offset height to accommodate different wheel sizes and trailer heights.

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

*   **Bearing Dimensions:**
    *   `Bearing_Diameter`: The outer diameter of the bearing (e.g., 12mm for a common MR128-2RS bearing).
    *   `Bearing_Inner_Diameter`: The inner diameter of the bearing (e.g., 8mm).
    *   `Bearing_Height`: The height/thickness of the bearing (e.g., 3.5mm).
*   **Wheel Screw Type:**
    *   `Wheel_screw_type`:  Either "M4" or "M3", to specify the size of the screw that holds the wheel to the hex adapter.
*   **Axle Screw Type:**
    *   `Screw_type`:  Either "M3" or "M2", to specify the size of screws used for mounting the axle to the trailer chassis/leaf springs.
*   **Overall Width:**
    *   `Width`:  The total width of the assembly from bearing to bearing - I'd like the code to automatically add an extra 12mm to this to get the hex to hex width, since that's easier to think about when sizing.
*   **Wheel Offset Height:**
    *   `Wheel_offset_height`: A value that moves the wheel mount up (+) or down (-), in millimeters.
*   **Ground Clearance:**
    *    `Ground_clear`: How much the middle of the axle is lifted to increase ground clearance.
*   **Axle Mount Distance:**
    *   `S_AXLE_MOUNT_X`: The distance between the center of the screw holes for mounting the axle to the leaf springs.
*   **Leaf Spring Dimensions**
    *   `S_SPRING_W`: Width of the leaf springs.
    *   `S_SPRING_SCREW_DIST`: Distance between the screw holes on each leaf spring mount.
    *   `S_SPRING_SCREW_OFFSET`: Offset from the center of the spring mount to the mounting holes.
    *   `S_SPRING_MOUNT_THIN`: Thickness of the mounting section for the springs

I'd like to be able to generate the following parts individually, or all together:

*   **Hub:** The part that holds the bearings and provides mounting points.
*   **Wheelhex:** The hex adapter that mounts to the wheels.
*   **Wheelhex_cap:** The cap that secures the wheel to the hex adapter.
*   **Axle:** The bent axle that connects the two hubs and mounts to the leaf springs.
*   **Visual:** An assembly of all parts, for a visual check.
*  **All:** Generate all the parts individually

For libraries, I'd like to use the following:

*   **MCAD:** To be able to do standard screw threads
*   **BOSL2:** It would be great if you can leverage any tools from this library

Could you provide the OpenSCAD code for this? Let me know if you need any clarification.

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

// Parameters in Customizer

// Recomended is the 8x12x3.5 also known as MR128-2RS
Bearing_Diameter = 12;
Bearing_Inner_Diameter = 8;
Bearing_Height = 3.5;

// Wheel screw type
Wheel_screw_type = "M4"; //[M4,M3]

// Screw type
Screw_type = "M3"; //[M3,M2]

// Total width from bearing to bearing, Add 12mm to get Hex to Hex.
Width = 155;

// What part to generate. Select visual to see in assembled view.
What_To_Print = "Visual"; // [All,Hub,Wheelhex,Wheelhex_cap,Axle,Visual]

// How much in height the wheel mount should move up+ or down-
Wheel_offset_height = -10;

// How much the middle part is moved up to avoid hitting stuff offroad.
Ground_clear = 10;

/* [Hidden] */

//a = Bearing_Diameter+Bearing_Inner_Diameter; // just a code to stop customizer from showing more variables
// ############# Settings ################

$fs = 0.5;
$fa = 5.1;

S_HEIGHT_OFFSET = Wheel_offset_height; // How much in height the wheel mount should move up+ or down-

S_GROUND_CLEAR = Ground_clear; // How much the middle part is moved up to avoid hitting stuff offroad.

S_TOTAL_WIDTH = Width;

S_AXLE_X = 150;
S_AXLE_Y = 8;

S_WIDTH_EXTRA_HEX = 6;

S_AXLE_MOUNT_X = 93; // Distance between center holes for axle mount on leaf springs

S_SPRING_W = 8; // Width of the leaf springs
S_SPRING_SCREW_DIST = 11;
S_SPRING_SCREW_OFFSET = 1;
S_SPRING_MOUNT_THIN = 4;
// ############# Constants ################
C_M2_DIAMETER = 2.3; // size of a hole that a M3 screw will slide through
C_M2_DIAMETER_THREAD = 2; // size of a hole that a M3 screw will create own threads in

C_M2_NUT = 6;
C_M2_NUT_H = 2.5;

C_M3_DIAMETER = 3.3; // size of a hole that a M3 screw will slide through
C_M3_DIAMETER_THREAD = 2.8; // size of a hole that a M3 screw will create own threads in

C_M3_NUT = 7;
C_M3_NUT_H = 3;

C_M4_NUT = 8.4;
C_M4_NUT_H = 4;

C_M4_DIAMETER = 4.1; // size of a hole that a M4 screw will slide through
C_M4_DIAMETER_THREAD = 3.8; // size of a hole that a M4 screw will create own threads in

    b_12mm_tol = 0.3; // tolerance for bearing with 12mm diameter
C_12MM_BEARING_D = 12+b_12mm_tol; // Size of a hole that hold a 12mm bearing
C_12MM_BEARING_H = 3.5;

    b_tol = 0.6; // tolerance for bearing

//MR128-2RS bearing
C_BEARING_D = Bearing_Diameter+b_tol; // Size of a hole that hold a bearing
C_BEARING_H = Bearing_Height;
C_BEARING_INSIDE = Bearing_Inner_Diameter; // Inside diameter of bearing

//C_SCREW = (Screw_type == "M3") ? C_M3_DIAMETER : C_M2_DIAMETER; // if not M3 its M2
//C_SCREW_THREAD = (Screw_type == "M3") ? C_M3_DIAMETER_THREAD : C_M2_DIAMETER_THREAD; // if not M3 its M2

//C_WHEEL_SCREW = (Wheel_screw_type == "M4") ? C_M4_DIAMETER : C_M3_DIAMETER; // if not M4 its M3
//C_WHEEL_SCREW_THREAD = (Wheel_screw_type == "M4") ? C_M4_DIAMETER_THREAD : C_M3_DIAMETER_THREAD; // if not M4 its M3

//C_WHEEL_SCREW_NUT = (Wheel_screw_type == "M4") ? C_M4_NUT : C_M3_NUT; // if not M4 its M3
//C_WHEEL_SCREW_NUT_H = (Wheel_screw_type == "M4") ? C_M4_NUT_H : C_M3_NUT_H; // if not M4 its M3

C_WHEEL_HEX = 13.9; // The hex that the rims mount to

C_WHEEL_AXLE = C_BEARING_INSIDE - 0.3; // Axle that goes through the 5mm hole in the bearings

// ############# Code ################

//Assembly();
PrintAll();
module wheelhex(Wheel_screw_type2 = Wheel_screw_type) {
    C_WHEEL_SCREW_NUT = (Wheel_screw_type2 == "M4") ? C_M4_NUT : C_M3_NUT; // if not M4 its M3
    C_WHEEL_SCREW_NUT_H = (Wheel_screw_type2 == "M4") ? C_M4_NUT_H : C_M3_NUT_H; // if not M4 its M3
    C_WHEEL_SCREW = (Wheel_screw_type2 == "M4") ? C_M4_DIAMETER : C_M3_DIAMETER; // if not M4 its M3
    C_WHEEL_SCREW_THREAD = (Wheel_screw_type2 == "M4") ? C_M4_DIAMETER_THREAD : C_M3_DIAMETER_THREAD; // if not M4 its M3
    difference() {
        union() {
            translate([0,0,-S_WIDTH_EXTRA_HEX]) cylinder($fn=6, d=C_WHEEL_HEX, h=S_WIDTH_EXTRA_HEX);
            cylinder(d=C_WHEEL_AXLE, h=hub_h+0.3);
        }
        wheelhex_screws(Wheel_screw_type2 = Wheel_screw_type2);
        translate([0,0,-S_WIDTH_EXTRA_HEX-0.8]) cylinder(d=C_WHEEL_SCREW_NUT, h=C_WHEEL_SCREW_NUT_H+1, $fn=6);
    }

}
module wheelhex_cap(Wheel_screw_type2 = Wheel_screw_type) {
    C_WHEEL_SCREW_NUT = (Wheel_screw_type2 == "M4") ? C_M4_NUT : C_M3_NUT; // if not M4 its M3
    C_WHEEL_SCREW_NUT_H = (Wheel_screw_type2 == "M4") ? C_M4_NUT_H : C_M3_NUT_H; // if not M4 its M3
    C_WHEEL_SCREW = (Wheel_screw_type2 == "M4") ? C_M4_DIAMETER : C_M3_DIAMETER; // if not M4 its M3
    C_WHEEL_SCREW_THREAD = (Wheel_screw_type2 == "M4") ? C_M4_DIAMETER_THREAD : C_M3_DIAMETER_THREAD; // if not M4 its M3
    difference() {
        translate([0,0,hub_h+0.3]) cylinder(d1=C_WHEEL_AXLE, d2=C_WHEEL_AXLE+3, h=3);
        //translate([0,0,hub_h+0.3]) cylinder(d=C_WHEEL_SCREW, h=20);
        wheelhex_screws(Wheel_screw_type2 = Wheel_screw_type2);
        %wheelhex_screws(Wheel_screw_type2 = Wheel_screw_type2);
    }
}
module wheelhex_screws(Wheel_screw_type2 = Wheel_screw_type) {
    C_WHEEL_SCREW = (Wheel_screw_type2 == "M4") ? C_M4_DIAMETER : C_M3_DIAMETER; // if not M4 its M3
    C_WHEEL_SCREW_THREAD = (Wheel_screw_type2 == "M4") ? C_M4_DIAMETER_THREAD : C_M3_DIAMETER_THREAD; // if not M4 its M3
    translate([0,0,hub_h+0.3+4]) rotate([0,180,0]) common_flat_screw_tap(l = 35, l2 = 10, dd1=C_WHEEL_SCREW_THREAD, dd2=C_WHEEL_SCREW);
    //translate([0,0,-S_WIDTH_EXTRA_HEX]) cylinder(d=C_WHEEL_SCREW_THREAD, h=20*10);
}

hub_middle_gap = 5;
hub_h = (C_BEARING_H*2+hub_middle_gap);
hub_mount_y = (C_BEARING_D>S_AXLE_Y) ? C_BEARING_D+0.2 : S_AXLE_Y+0.2;

hub_mount_d = 8; // diameter of mounting pin
hub_mount_h = 10; // distance to first mounting hole from bearings back
hub_mount_dist = 10; // distance between mounting holes
hub_mount_w = 4; // thickness of mount
module hub() {

    translate([0,0,0]) difference() {
        union() {
            translate([0,0,0]) cylinder(d=C_BEARING_D+4, h=C_BEARING_H*2+hub_middle_gap);
            //cylinder(d=C_WHEEL_AXLE, h=20);

            // Mountings
            hull() {
                translate([0,hub_mount_y/2,(C_BEARING_H*2+hub_middle_gap)-hub_mount_d/2]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
                translate([+hub_mount_dist/2,hub_mount_y/2,(C_BEARING_H*2+hub_middle_gap)+hub_mount_h]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
                translate([-hub_mount_dist/2,hub_mount_y/2,(C_BEARING_H*2+hub_middle_gap)+hub_mount_h]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
            }
            hull() {
                translate([0,-hub_mount_y/2 - hub_mount_w,(C_BEARING_H*2+hub_middle_gap)-hub_mount_d/2]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
                translate([+hub_mount_dist/2,-hub_mount_y/2 - hub_mount_w,(C_BEARING_H*2+hub_middle_gap)+hub_mount_h]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
                translate([-hub_mount_dist/2,-hub_mount_y/2 - hub_mount_w,(C_BEARING_H*2+hub_middle_gap)+hub_mount_h]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
            }
        }

        // Bearing holes
        translate([0,0,-1]) cylinder(d=C_BEARING_D, h=C_BEARING_H+1);
        translate([0,0,C_BEARING_H + hub_middle_gap]) cylinder(d=C_BEARING_D, h=C_BEARING_H+1);
        translate([0,0,0]) cylinder(d=C_BEARING_D-1, h=C_BEARING_H*2+hub_middle_gap+1);
        //Elephant foot
        translate([0,0,0]) cylinder(d1=C_BEARING_D+1,d2=C_BEARING_D, h=C_BEARING_H/3);

        // Holes for mounting
        hub_screws();
        %hub_screws();
    }
}
module hub_screws(Screw_type2 = Screw_type) {
    C_SCREW = (Screw_type2 == "M3") ? C_M3_DIAMETER : C_M2_DIAMETER; // if not M3 its M2
    C_SCREW_THREAD = (Screw_type2 == "M3") ? C_M3_DIAMETER_THREAD : C_M2_DIAMETER_THREAD; // if not M3 its M2
    translate([+hub_mount_dist/2,hub_mount_y/2+hub_mount_w,(C_BEARING_H*2+hub_middle_gap)+hub_mount_h]) rotate([90,0,0]) common_button_screw_tap(l = 25, l2 = 1+hub_mount_w, dd1=C_SCREW_THREAD, dd2=C_SCREW);
    translate([-hub_mount_dist/2,hub_mount_y/2+hub_mount_w,(C_BEARING_H*2+hub_middle_gap)+hub_mount_h]) rotate([90,0,0]) common_button_screw_tap(l = 25, l2 = 1+hub_mount_w, dd1=C_SCREW_THREAD, dd2=C_SCREW);
    //translate([0,-hub_mount_y/2 - hub_mount_w,hub_mount_h+hub_mount_dist]) rotate([-90,0,0]) cylinder(d=hub_mount_d, h= hub_mount_w);
}
module axle(Screw_type2 = Screw_type) {
    union() {
        axle_mirror(Screw_type2 = Screw_type2);
        mirror([1,0,0]) axle_mirror(Screw_type2 = Screw_type2);
    }
}
module axle_mirror(Screw_type2 = Screw_type) {

    C_SCREW = (Screw_type2 == "M3") ? C_M3_DIAMETER : C_M2_DIAMETER; // if not M3 its M2
    C_SCREW_THREAD = (Screw_type2 == "M3") ? C_M3_DIAMETER_THREAD : C_M2_DIAMETER_THREAD; // if not M3 its M2

    //translate([-S_AXLE_X/2,-S_AXLE_Y/2,-S_AXLE_Y/2]) cube([S_AXLE_X, S_AXLE_Y,S_AXLE_Y]);
    difference() {
        union() {
            hull() {
                translate([0,-S_AXLE_Y/2,0 + S_GROUND_CLEAR]) rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=S_AXLE_Y);
                translate([S_AXLE_MOUNT_X/2-S_SPRING_W/2-S_AXLE_Y/2,  -S_AXLE_Y/2,  0 + S_GROUND_CLEAR]) rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=S_AXLE_Y);
            }
            hull() {
                translate([S_AXLE_MOUNT_X/2-S_AXLE_Y/2-S_SPRING_W/2,  -S_AXLE_Y/2,  0 + S_GROUND_CLEAR]) rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=S_AXLE_Y);
                translate([S_AXLE_MOUNT_X/2-S_AXLE_Y/2-S_SPRING_W/2,  -S_AXLE_Y/2,  0+S_SPRING_MOUNT_THIN/2]) rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=S_AXLE_Y);
            }

            hull() { // Spring mount part
                translate([S_AXLE_MOUNT_X/2-S_AXLE_Y-S_SPRING_W/2++S_AXLE_Y/2 , -S_AXLE_Y/2,  0])  rotate([-90,0,0]) cylinder(d=S_AXLE_Y-S_SPRING_MOUNT_THIN, h=S_AXLE_Y);
                translate([S_AXLE_MOUNT_X/2-S_AXLE_Y-S_SPRING_W/2 +S_SPRING_W+S_AXLE_Y+S_AXLE_Y/2 ,  -S_AXLE_Y/2,  0])  rotate([-90,0,0]) cylinder(d=S_AXLE_Y-S_SPRING_MOUNT_THIN, h=S_AXLE_Y);
                // Screw mounts
                translate([S_AXLE_MOUNT_X/2, -S_SPRING_SCREW_OFFSET, -S_AXLE_Y/2+S_SPRING_MOUNT_THIN/2]) rotate([0,0,0])cylinder(d=C_SCREW_THREAD+2, h=S_AXLE_Y-S_SPRING_MOUNT_THIN);
                translate([S_AXLE_MOUNT_X/2, -S_SPRING_SCREW_OFFSET+S_SPRING_SCREW_DIST, -S_AXLE_Y/2+S_SPRING_MOUNT_THIN/2]) rotate([0,0,0]) cylinder(d=C_SCREW_THREAD+4, h=S_AXLE_Y-S_SPRING_MOUNT_THIN);
            }
            //translate([S_AXLE_MOUNT_X/2-S_AXLE_Y-S_SPRING_W/2 ,-S_AXLE_Y/2,-S_AXLE_Y/2]) cube([S_SPRING_W+S_AXLE_Y+S_AXLE_Y, S_AXLE_Y,S_AXLE_Y]);

            hull() { // hub mount part
                //translate([S_AXLE_MOUNT_X/2+S_SPRING_W/2,-S_AXLE_Y/2,-S_AXLE_Y/2 + S_HEIGHT_OFFSET]) cube([S_AXLE_Y, S_AXLE_Y, S_AXLE_Y]);
                translate([S_AXLE_MOUNT_X/2-S_AXLE_Y-S_SPRING_W/2 +S_SPRING_W+S_AXLE_Y+S_AXLE_Y/2 ,  -S_AXLE_Y/2,  -S_SPRING_MOUNT_THIN/2])  rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=S_AXLE_Y);
                translate([S_TOTAL_WIDTH/2-(C_BEARING_H*2+hub_middle_gap)-hub_mount_h, -S_AXLE_Y/2, +hub_mount_dist/2+ S_HEIGHT_OFFSET]) rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=hub_mount_y-0.6);
                translate([S_TOTAL_WIDTH/2-(C_BEARING_H*2+hub_middle_gap)-hub_mount_h, -S_AXLE_Y/2, -hub_mount_dist/2+ S_HEIGHT_OFFSET]) rotate([-90,0,0]) cylinder(d=S_AXLE_Y, h=hub_mount_y-0.6);
            }
            //translate([S_AXLE_MOUNT_X/2+S_SPRING_W/2,-S_AXLE_Y/2,-S_AXLE_Y/2 + S_HEIGHT_OFFSET]) cube([S_AXLE_MOUNT_X/2-S_SPRING_W/2,S_AXLE_Y, S_AXLE_Y]);

        }

        axle_screws(Screw_type2 = Screw_type2);
        %axle_screws(Screw_type2 = Screw_type2);
        translate([S_TOTAL_WIDTH/2,0,+ S_HEIGHT_OFFSET]) rotate([0,-90,0]) hub_screws(Screw_type2 = Screw_type2);
        //translate([S_TOTAL_WIDTH/2,0,0]) rotate([0,-90,0]) %hub_screws();
    }
}
module axle_screws(Screw_type2 = Screw_type) {
    C_SCREW = (Screw_type2 == "M3") ? C_M3_DIAMETER : C_M2_DIAMETER; // if not M3 its M2
    C_SCREW_THREAD = (Screw_type2 == "M3") ? C_M3_DIAMETER_THREAD : C_M2_DIAMETER_THREAD; // if not M3 its M2
    translate([S_AXLE_MOUNT_X/2, -S_SPRING_SCREW_OFFSET, -S_AXLE_Y/2]) rotate([0,0,0]) common_button_screw_tap(l = 25, l2 = 0, dd1=C_SCREW_THREAD, dd2=C_SCREW);
    translate([S_AXLE_MOUNT_X/2, -S_SPRING_SCREW_OFFSET+S_SPRING_SCREW_DIST, -S_AXLE_Y/2]) rotate([0,0,0]) common_button_screw_tap(l = 25, l2 = 0, dd1=C_SCREW_THREAD, dd2=C_SCREW);
}

module Assembly() {
    // For visual assembly only
    y_diff = -(S_AXLE_Y - hub_mount_y)/2;
    axle();
    translate([S_TOTAL_WIDTH/2, y_diff ,+ S_HEIGHT_OFFSET-15]) rotate([0,-90,0]) wheelhex();
    translate([S_TOTAL_WIDTH/2, y_diff ,+ S_HEIGHT_OFFSET-15]) rotate([0,-90,0]) wheelhex_cap();
    translate([S_TOTAL_WIDTH/2, y_diff ,+ S_HEIGHT_OFFSET]) rotate([0,-90,0]) hub();

    rotate([0,0,180]) translate([S_TOTAL_WIDTH/2,-y_diff,+ S_HEIGHT_OFFSET-15]) rotate([0,-90,0]) wheelhex();
    rotate([0,0,180]) translate([S_TOTAL_WIDTH/2,-y_diff,+ S_HEIGHT_OFFSET-15]) rotate([0,-90,0]) wheelhex_cap();
    rotate([0,0,180]) translate([S_TOTAL_WIDTH/2,-y_diff,+ S_HEIGHT_OFFSET]) rotate([0,-90,0]) hub();
}

module PrintAll() {
    //What_To_Print = "All"; // [All,Hub,Wheelhex,Wheelhex_cap,Axle,Visual]
    if (What_To_Print == "All") {
        translate([0,0,S_AXLE_Y/2]) rotate([90,0,180]) axle();
        translate([-8,-20,S_WIDTH_EXTRA_HEX]) wheelhex();
        translate([8,-20,S_WIDTH_EXTRA_HEX]) wheelhex();
        translate([-25,-20,-hub_h-0.3]) wheelhex_cap();
        translate([25,-20,-hub_h-0.3]) wheelhex_cap();
        translate([10,-38,0])hub();
        translate([-10,-38,0])hub();
    }
    if (What_To_Print == "Hub") {
        hub();
    }
    if (What_To_Print == "Wheelhex") {
        wheelhex();
    }
    if (What_To_Print == "Wheelhex_cap") {
        wheelhex_cap();
    }
    if (What_To_Print == "Axle") {
        rotate([90,0,0]) axle();
    }
    if (What_To_Print == "Visual") {
        Assembly();
    }
}

module common_flat_screw_tap(l = 10, l2 = 0, dd1=1, dd2=1) {

    // l2 is amount of the screw that are bigger for sliding through the hole
    tap_z = 1.9;
    union() {
        echo(dd1);
        cylinder(d = dd1, h= l);
        cylinder(d = dd2, h= l2);
        translate([0,0,-0.1+0.1]) cylinder(d1 = dd2 + 3.5, d2= dd1, h= tap_z);
        translate([0,0,-0.1]) cylinder(d = dd2 + 3.5, h= 0.3);
    }
}

module common_button_screw_tap(l = 10, l2 = 0, dd1=1, dd2=1) {

    union() {
        cylinder(d = dd1, h= l);
        cylinder(d = dd2, h= l2);
        translate([0,0,-4]) cylinder(d = dd1+3, h=4);
    }
}
```


[User]
Okay, I've got an idea for a really useful tool I'd like to design in OpenSCAD, and I'm hoping you can help me create the necessary parametric files. It's essentially a sliding attachment for a standard ruler or rule, that can be used for a bunch of things like transferring measurements, marking hole positions, and acting as a sort of L-square for drawing.

Here’s the breakdown of what I'm envisioning:

**Core Functionality:**

*   **Sliding Grip:** The main part of the design needs to firmly grip a standard rule. It should be an interference fit so that it holds the rule securely, but can still slide along its length with some resistance.  I imagine it being a U-shaped channel that clamps onto the rule.
*   **Pointer/Reference Edge:**  On one side of the grip there needs to be a pointer or reference edge that projects outwards. This will be used for taking measurements and transferring distances.
*  **Hole Markers:** It should have a set of equally spaced holes that can be used to mark the positions to drill when transferring measurements. These should all be aligned with the main pointer.

**Customization Parameters I Need:**

*   `length_1`:  The overall length of the main body of the grip
*   `length_2`: The width of the gripping channel. This needs to be a little bit larger than the thickness of the rule.
*   `Thickness`: The thickness of the plastic parts.
*   `height`: How deep is the grip channel
*   `fillet`: A radius for filleting edges of the grip.
*  `hole_diameter`: The diameter of the marker holes.
*   `num_holes`:  The number of holes for marking.
*   `hole_pitch`: The spacing between the centers of the holes.
*   `length_of_pointer`: How long the pointer protrudes.
*   `Arrow_head_angle`: The angle of the pointer’s head.
*   `point_rad`: radius of the end of pointer
* `depth`: The extrude depth of the pointer

**Specific Features:**

*   **Mirrored Option:** Ideally, I’d like to be able to create mirrored versions of the design, so I can have one on each side of the rule, or both pointing in the same direction for comparison.
* **Vertical Print Orientation:** The object should print best in a vertical orientation.
*  **Interference Fit:** The gripping channel should have an interference fit with the rule (adjustable with length_2 and thickness params). This can require trial and error testing

**Possible Uses:**

*   Measure between 2 points, and transfer the mark to a drill point.
*   Height gauge
*  L square

**OpenSCAD Setup:**
I am not requesting specific files, but the design might require a single file with conditional logic, or multiple linked files to generate the design, and a separate file for a test piece.

For this, I am assuming we're not using any additional external libraries like MCAD or BOSL. So I’m expecting pure OpenSCAD code.

I think that’s it. Let me know if you need any more information. Thanks for your help!

[Assistant]
rule_slide_Ken_applications.scad:
```

length_1=13.1;
length_2=0.8;
Thickness=2.0;
height=15;
fillet=0.39;

hole_diameter=5;
num_holes=3;
hole_pitch=10;
show_part=3;  // 1 = left hand  2= right hand  3=both

length_of_pointer=50;//pointer parameters ******************
Arrow_head_angle=20;
point_rad=5;
depth=3;

//#translate([0,-length_2/2,0]) square([length_1-0.4,length_2],true);

width=height;

if(show_part==1)rule_slide ();
if(show_part==2) mirror([0,1,0]) translate([0,50,0]) rule_slide ();

if(show_part==3)rule_slide ();
if(show_part==3) mirror([0,1,0]) translate([0,50,0]) rule_slide ();

module rule_slide (){
    difference(){
    union(){
rotate([90,0,0]) translate([length_1/2,0,-Thickness]) linear_extrude(height = depth, center = false, convexity = 10) pointer();
clip();
    }

 for (a =[1:1:num_holes])
 rotate([90,0,0]) translate([(length_1/2)+a*hole_pitch,height/2,-length_2*6]) cylinder(  20,d1=hole_diameter, d2=hole_diameter, center=false,$fn=60);
    }
}

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

$fn=100;
module clip(){
linear_extrude(height=height){

round2d(OR=fillet,IR=fillet){
translate([-length_1/2-Thickness,0,0]) square([length_1+Thickness+Thickness,Thickness],false);
translate([length_1/2,-length_2,0]) square([Thickness,length_2],false);
translate([-length_1/2-Thickness,-length_2,0]) square([Thickness,length_2],false);
translate([-length_1/2-Thickness,-length_2-Thickness,0]) square([Thickness*1.5,Thickness],false);
translate([+length_1/2-Thickness/2,-length_2-Thickness,0]) square([Thickness*1.5,Thickness],false);
}
}
}

module pointer(){
len_minus_point=point_rad/tan(Arrow_head_angle/2);
mirror([1,0,0]) translate([-length_of_pointer,0,0]){
difference(){
$fn=60;
round2d(OR=point_rad,IR=0   ){
radius = 500;
angles = [0, Arrow_head_angle];
points = [
    for(a = [angles[0]:1:angles[1]]) [radius * cos(a), radius * sin(a)]
];

translate([-len_minus_point+point_rad,0,0]) polygon(concat([[0, 0]], points));
}

translate([length_of_pointer,-0.1,0]) square(1000);
translate([0,width,0]) square(1000);
}
}
}

```


[User]
Hi, I'm looking for a parametric design for a headphone holder that mounts onto the top of a computer monitor. I've seen some designs out there, and I'd like something customizable in OpenSCAD.

The basic idea is that it should have a hook that hangs down in the front to hold the headphones, a part that rests on top of the monitor, and a support that extends down the back of the monitor.

Here are the parameters I'd like to be able to adjust:

*   `monitor_len`: The length of the monitor's top edge (from the front to the back of the monitor).
*   `h_front`: The height of the hook part on the front edge of the monitor. Basically, how far down it hangs from the top of the monitor.
*   `a_sup`: The angle of the support that sits on the back of the monitor, relative to the vertical. 0 would be straight down.
*   `l_hook`: The length of the headphone hook itself, where the headphones sit.
*   `d_hook`: The depth of the curved indentation on the headphone hook. I want to make sure the headphones don't slip off.
*   `l_sup`: The length of the monitor support section. This is the part that's angled on the back of the monitor.
*   `w_hook`: The width of the headphone hook.
*   `th`: The thickness of the material.

I'd like it to be fairly simple, and the design I'm envisioning is largely 2D shapes extruded, so I think it should be relatively straightforward. I don't need any fancy libraries or anything. Just standard OpenSCAD functionality, please. Thanks!

[Assistant]
Parametric_Headphone_Holder_for_Monitor.scad.scad:
```
// Parametric Headphone Holder for Monitor
// May 08, 2019
// https://www.thingiverse.com/thing:3617042
// by Bikecyclist
// https://www.thingiverse.com/Bikecyclist
//
// Remix of
//
// Headphonestand for Monitor
// https://www.thingiverse.com/thing:3483155
// by
// https://www.thingiverse.com/ZibbiDasZebra

/* [Main Parameters] */

// Length of monitor top (front to back)
monitor_len = 30;

// Height of hook on monitor front edge (bottom to top)
h_front = 20;

// Angle of support on monitor backside (0 = vertical)
a_sup = 35;

// Number of facets
$fn = 32;

/* [Secondary Parameters] */

// Length of hook for headphone
l_hook = 60;

// Depth of curved indentation in hook (don't go too deep - remember Moria!)
d_hook = 10;

// Length of monitor support (can usually remain unchanged)
l_sup = 35;

// Width of the hook (left to right)
w_hook = 10;

// Thickness of hook material
th = 2.25;

/* [Hidden] */

// Small distance to ensure proper meshing
eps = 0.01;

/* Now unused code for important ZibbiDasZebra's original design for reference
color ("red")
mirror ([0, 1, 0])
translate ([44.25 + 2.25/2, -1.8, -11])
import ("headphonestand_for_monitor.stl");
*/

hook (w_hook);

module hook (h)
{
    linear_extrude (h)
    {
        offset (-th/2 * 0.9)
        offset (th/2 * 0.9)
        difference ()
        {
            offset (th/2 * 0.9)
            offset (-th/2 * 0.9)
            hook_xsection ();

            offset (-th)
            hook_xsection ();
        }
    }
}

module hook_xsection ()
{
    translate ([0, -th])
    square ([th, monitor_len + 2 * th]);

    translate ([-h_front, monitor_len])
    square ([h_front + th, th]);

    difference ()
    {
        hull ()
        {
            rotate ([0, 0, a_sup])
            translate ([-l_sup/2, -th/2])
            square ([l_sup, th], center = true);

            translate ([th/2, -l_hook + th])
            square ([th, th], center = true);

            translate ([th/2, -th/2])
            square ([th, th], center = true);
        }

        translate ([th + th, -(l_hook - th)/2])
        resize ([2 * d_hook, l_hook - 2 * th])
        circle (d = l_hook);
    }
}
```


[User]
I'm looking to create a customizable planetary gear bearing with some specific features and tolerances. It needs to have a ring gear, a sun gear, and planetary gears.

Here's what I need:

*   **Overall Structure:** A planetary gear system where the planetary gears revolve around a central sun gear within an outer ring gear.
*   **Diameters and Thickness:** The outer diameter of the ring gear (`D`) should be a parameter, as well as the overall thickness (`T`).
*   **Tolerances:** I need two types of clearance:
    *   `tol`: A general overall clearance for gear spacing, probably around 0.15mm.
    *   `tol2`:  A specific anti-stick clearance, around 0.20mm, applied to nearly-touching points between gears during printing. This should help prevent the gears from fusing together.
*   **Number of Gears:**
    *   The number of planetary gears (`number_of_planets`).
    *   The number of teeth on each planetary gear (`number_of_teeth_on_planets`).
    *   An approximate number of teeth on the sun gear (`approximate_number_of_teeth_on_sun`). The design should calculate the actual number based on the other gear counts to make the system work. The actual sun gear and ring gear numbers of teeth should be integers and calculated from those numbers and the number of planets in a way that makes a working planetary gear.
*   **Gear Parameters:**
    *   A pressure angle (`P`) for the gear teeth, adjustable between 30 and 60 degrees.
    *   A number of teeth to twist across (`nTwist`) for a helical or herringbone cut. This will control the angle of the helical gear.
    *   The depth ratio of teeth (`DR`).
*   **Center Hole:** The sun gear needs a hexagonal hole in the center (`w`) for a tool to fit through.
*   **Surface Finish:**  I'd like an option to toggle between a smooth cylindrical outer surface and a faceted one, driven by a boolean `faceted`.
*   **Planetary Gear Decorations:** I want to be able to add different decorations on the planetary gears. It should be a string (`decorations`) where each character corresponds to a planet, and can be:
    *   `0`: No decoration.
    *   `1`: A large dome.
    *   `2`: A conical bump.
    *   `3`: A conical hole.
    *   `4`: An off-center bump.
    *   `5`: A circle of small bumps.
	*	`6`: A low dome
	*	`7`: A ring on top of the gear.

The planetary gears should have a small centered conical hole in their bottom surfaces. If the planet decorations include conical holes (3), then those should be on the tops of the planetary gears. If the decoration is (4), an off center conical hole is needed on the bottom, and an off-center sphere is needed on the top. The actual position of these decorations is not critical.

I'd like it if the design makes use of the `gear()` module for drawing the gears. Please include the `rack`, `monogram`, `herringbone`, `gear`, `flat_extrude` and `gear2D` modules within the design, as well as all the involute functions and math that is used within those modules. Make sure that the involute functions and all the dependent code work correctly - the existing code had some errors. I'm not interested in using any external libraries - it's fine if you include helper functions as needed.

It's important that the calculations for the gears result in a working planetary gear setup, and that the `tol` and `tol2` clearances work as expected. The tolerance `tol` should apply to the gears that go inside the ring gear and the sun gear. The `tol2` clearance should apply to only the planetary gears, and only in the places where they touch the sun or ring gears. Also, the existing design has an issue with the rotation of the sun gear - it needs to be rotated to mesh with the planetary gears properly. The planetary gears should be placed at the correct angular position as well to mesh correctly.

[Assistant]
bearing-mod3.scad:
```
// Planetary gear bearing (customizable)

// outer diameter of ring
D=50;
// thickness
T=8;
// clearance overall for gear spacing
tol=0.15;
// anti-stick clearance at nearly touching points
tol2=0.20;
number_of_planets=5;
number_of_teeth_on_planets=7;
approximate_number_of_teeth_on_sun=9;
// pressure angle
P=45;//[30:60]
// number of teeth to twist across
nTwist=1;
// width of hexagonal hole
w=6.7;
// if true, use faceted outside surface instead of smooth cylinder
faceted=true;
// Planet gear greebles, one character per planet. 0:None, 1:large dome, 2:conical bump, 3:conical hole, 4:off center bump, 5:bumps in circle, 6: low dome, 7: ring
decorations = "12345";

DR=0.5*1;// maximum depth ratio of teeth

m=round(number_of_planets);
np=round(number_of_teeth_on_planets);
ns1=approximate_number_of_teeth_on_sun;
k1=round(2/m*(ns1+np));
k= k1*m%2!=0 ? k1+1 : k1;
ns=k*m/2-np;
nr=ns+2*np;
pitchD=0.9*D/(1+min(PI/(2*nr*tan(P)),PI*DR/nr));
pitch=pitchD*PI/nr;
helix_angle=atan(2*nTwist*pitch/T);

phi=$t*360/m;
// Generally, tolerances are effectively doubled since all gears
// are shrunk by that amount. For antistick, we're only subtracting
// the planetary gears, so we need to double it to get a similar
// effect.
antistick = 2 * tol2;

translate([0,0,T/2]){
  // outer gear ring
	difference(){
		cylinder(r=D/2,h=T,center=true,$fn=faceted ? nr : 100);
		herringbone(nr,pitch,P,DR,-tol,helix_angle,T+0.2);
		difference(){
			translate([0,-D/2,0])rotate([90,0,0])monogram(h=10);
			cylinder(r=D/2-0.25,h=T+2,center=true,$fn=faceted ? nr : 100);
		}

    // Subtract slightly enlarged versions of the planetary
    // gears using the anti-stick tolerance.
	  for(i=[1:m])rotate([0,0,i*360/m+phi])translate([pitchD/2*(ns+np)/nr,0,0])
		  rotate([0,0,i*ns/m*360/np-phi*(ns+np)/np-phi]) {
			  herringbone(np,pitch,P,DR,-antistick,helix_angle,T);
      }
	}

  // inner sun gear
	rotate([0,0,(np+1)*180/ns+phi*(ns+np)*2/ns])
	difference(){
		mirror([0,1,0])
			herringbone(ns,pitch,P,DR,tol,helix_angle,T);

    // hexagonal hole in center of sun gear
		cylinder(r=w/sqrt(3),h=T+1,center=true,$fn=6);

    // Subtract slightly enlarged versions of the planetary
    // gears using the anti-stick tolerance, need to reverse
    // the sun gear rotation.
	  rotate([0,0,-((np+1)*180/ns+phi*(ns+np)*2/ns)])
    for(i=[1:m])rotate([0,0,i*360/m+phi])translate([pitchD/2*(ns+np)/nr,0,0])
		  rotate([0,0,i*ns/m*360/np-phi*(ns+np)/np-phi]) {
			  herringbone(np,pitch,P,DR,-antistick,helix_angle,T);
      }
	}

  // planetary gears
	for(i=[1:m])rotate([0,0,i*360/m+phi])translate([pitchD/2*(ns+np)/nr,0,0])
		rotate([0,0,i*ns/m*360/np-phi*(ns+np)/np-phi]) {
      pr = np*pitch/(2*PI);
      base_radius = pr*cos(P);
      depth=pitch/(2*tan(P));
      difference() {
			  herringbone(np,pitch,P,DR,tol,helix_angle,T);

        if (decorations[i-1] == "4") {
          // off-center bottom conical hole, slightly shrunk
          rotate([0,0,(0.25)*360/np])
          translate([0, base_radius - depth/2, -T / 2 - 0.05])
          cylinder(pr / 4, 0.9*depth * 3 / 4, 0.9*depth * 3 / 8);
        } else {
          // centered bottom conical hole
          translate([0, 0, -T / 2 - 0.05])
          cylinder(pr / 4, pr / 2, pr / 4);
        }

        if (decorations[i-1] == "3") {
          // conical hole on top
          translate([0, 0, T / 2 + 0.05])
          rotate([180, 0, 0])
          cylinder(pr / 4, pr / 2, pr / 4);
        }
      }

      $fs=0.5;
      if (decorations[i-1]=="1") {
        // protuding half sphere
        translate([0, 0, T * 0.5])
        sphere(base_radius * 0.8);
      } else if (decorations[i-1]=="2") {
        // cone slice
        translate([0, 0, T / 2])
        cylinder(pr / 4, pr / 2, pr / 4);
      } else if (decorations[i-1]=="3") {
        // Nothing to do here, ConicalHole is handled above
      } else if (decorations[i-1]=="4") {
        // off-center small half sphere
        rotate([0,0,(0.25)*360/np])
        translate([0, base_radius - depth/2, T * 0.5])
        sphere(depth * 3/4);
      } else if (decorations[i-1]=="5") {
        // small sphere ring
        for(i2=[1:np])
          rotate([0,0,(i2+0.25)*360/np])
          translate([0, base_radius, T * 0.5])
          sphere(depth/2);
      } else if (decorations[i-1]=="6") {
        // low sphere segment
        intersection() {
          sphere(sqrt(base_radius*base_radius+T*T/4));

          translate([0, 0, T])
          cylinder(T, base_radius, base_radius, center=true);
        }
      } else if (decorations[i-1]=="7") {
        // torus
        translate([0, 0, T / 2])
        rotate_extrude(convexity=2)
        translate([base_radius * 0.8, 0, 0])
        circle(base_radius * 0.2);
      }
    }
}

module rack(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	helix_angle=0,
	clearance=0,
	gear_thickness=5,
	flat=false){
addendum=circular_pitch/(4*tan(pressure_angle));

flat_extrude(h=gear_thickness,flat=flat)translate([0,-clearance*cos(pressure_angle)/2])
	union(){
		translate([0,-0.5-addendum])square([number_of_teeth*circular_pitch,1],center=true);
		for(i=[1:number_of_teeth])
			translate([circular_pitch*(i-number_of_teeth/2-0.5),0])
			polygon(points=[[-circular_pitch/2,-addendum],[circular_pitch/2,-addendum],[0,addendum]]);
	}
}

module monogram(h=1)
linear_extrude(height=h,center=true)
translate(-[3,2.5])union(){
	difference(){
		square([4,5]);
		translate([1,1])square([2,3]);
	}
	square([6,1]);
	translate([0,2])square([2,1]);
}

module herringbone(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5){

union(){
	gear(number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance,
		helix_angle,
		gear_thickness/2);
	mirror([0,0,1])
		gear(number_of_teeth,
			circular_pitch,
			pressure_angle,
			depth_ratio,
			clearance,
			helix_angle,
			gear_thickness/2);
}}

module gear (
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=28,
	depth_ratio=1,
	clearance=0,
	helix_angle=0,
	gear_thickness=5,
	flat=false){
pitch_radius = number_of_teeth*circular_pitch/(2*PI);
twist=tan(helix_angle)*gear_thickness/pitch_radius*180/PI;

flat_extrude(h=gear_thickness,twist=twist,flat=flat)
	gear2D (
		number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance);
}

module flat_extrude_with_bevel_unused(h,twist,flat){
  h_body=0.9;
  h_bevel=1-h_body;
  w_bevel=h_body;
	if(flat==false) {
		linear_extrude(height=h*h_body,twist=twist*h_body,slices=twist/6*h_bevel)
    children(0);

    translate([0,0,h*h_body])
    rotate([0,0,-twist*h_body])
		linear_extrude(height=h*h_bevel,twist=twist*h_bevel,slices=twist/6*h_bevel,scale=w_bevel)
    children(0);
	} else {
		children(0);
  }
}

module flat_extrude(h,twist,flat){
	if(flat==false) {
		linear_extrude(height=h,twist=twist,slices=twist/6)
    children(0);
	} else {
		children(0);
  }
}

module gear2D (
	number_of_teeth,
	circular_pitch,
	pressure_angle,
	depth_ratio,
	clearance){
pitch_radius = number_of_teeth*circular_pitch/(2*PI);
base_radius = pitch_radius*cos(pressure_angle);
depth=circular_pitch/(2*tan(pressure_angle));
outer_radius = clearance<0 ? pitch_radius+depth/2-clearance : pitch_radius+depth/2;
root_radius1 = pitch_radius-depth/2-clearance/2;
root_radius = (clearance<0 && root_radius1<base_radius) ? base_radius : root_radius1;
backlash_angle = clearance/(pitch_radius*cos(pressure_angle)) * 180 / PI;
half_thick_angle = 90/number_of_teeth - backlash_angle/2;
pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
min_radius = max (base_radius,root_radius);

intersection(){
	rotate(90/number_of_teeth)
		circle($fn=number_of_teeth*3,r=pitch_radius+depth_ratio*circular_pitch/2-clearance/2);
	union(){
		rotate(90/number_of_teeth)
			circle($fn=number_of_teeth*2,r=max(root_radius,pitch_radius-depth_ratio*circular_pitch/2-clearance/2));
		for (i = [1:number_of_teeth])rotate(i*360/number_of_teeth){
			halftooth (
				pitch_angle,
				base_radius,
				min_radius,
				outer_radius,
				half_thick_angle);
			mirror([0,1])halftooth (
				pitch_angle,
				base_radius,
				min_radius,
				outer_radius,
				half_thick_angle);
		}
	}
}}

module halftooth (
	pitch_angle,
	base_radius,
	min_radius,
	outer_radius,
	half_thick_angle){
index=[0,1,2,3,4,5];
start_angle = max(involute_intersect_angle (base_radius, min_radius)-5,0);
stop_angle = involute_intersect_angle (base_radius, outer_radius);
angle=index*(stop_angle-start_angle)/index[len(index)-1];
p=[[0,0],
	involute(base_radius,angle[0]+start_angle),
	involute(base_radius,angle[1]+start_angle),
	involute(base_radius,angle[2]+start_angle),
	involute(base_radius,angle[3]+start_angle),
	involute(base_radius,angle[4]+start_angle),
	involute(base_radius,angle[5]+start_angle)];

difference(){
	rotate(-pitch_angle-half_thick_angle)polygon(points=p);
	square(2*outer_radius);
}}

// Mathematical Functions
//===============

// Finds the angle of the involute about the base radius at the given distance (radius) from it's center.
//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html

function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / PI;

// Calculate the involute position for a given base radius and involute angle.

function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*PI/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*PI/180*cos (involute_angle))
];

```


[User]
Okay, I'm looking to create a customizable measuring cup, similar to the one I saw on Thingiverse by wstein, but I want a completely new version, not a modification of his code. I'd like it to be parametric so I can adjust things like capacity and handle labeling.

Specifically, the cup should have a smoothly curved shape, not just a straight cylinder. I'm thinking a lofted profile starting with a smaller diameter at the base, gradually expanding outwards before curving inwards slightly towards the top. I want a handle that is also curved and blends smoothly with the body of the cup.

Here's what I'd like to control with parameters:

*   **`unit`**: This will determine the unit of volume (e.g. ml, cubic inch, fluid ounces). The default should be ml (1.0), with options to choose from international cubic inches (16.387064), imperial fluid ounces (28.4130625), and US fluid ounces (29.5735295625).

*   **`volume`**: The desired capacity of the cup in the selected unit.

*   **`label1_text` & `label2_text`**: Text strings to be embossed on the handle.

*   **`label_thickness`**: The thickness of the embossed text. Defaults to 1.5.

*   **`label1_height` & `label2_height`**: The height of the embossed text. Defaults to 8.0.

*   **`label1_font` & `label2_font`**: The font for the embossed text. Should include options from some common .dxf fonts (like "orbitron.dxf", "Letters.dxf", "knewave.dxf", "BlackRose.dxf", "braille.dxf"). The default should be "orbitron.dxf".

*   **`adjust`**: A scale factor for volume adjustment if printed results are off. Default to 1.0.

*   **`wall_thickness`**: The thickness of the cup's walls. Default to 1.0.

*   **`build_measure_volume_reference`**: A boolean flag (0 or 1) which will cause the object to generate only the volume of the cup (the inverse mold if you will) which can be used to measure the actual volume of a physical printout. Default to 0.

The design should be based on a lofted polygon profile for the cup and a similar construction for the handle. I think the example code I saw used a `linear_extrude` operation with an intersection to create the cup volume but I'd like to avoid doing things that way. I’d like to see a design that uses `surface` objects with the same lofted profiles. I want the handle to be printed on, not attached. The handle should smoothly come off the side of the cup and also be a lofted shape. The text should be embossed on the handle, not engraved or cut out.

The OpenSCAD file should also use the "write/Write.scad" library for the text embossing. I'm hoping you can handle the complex shapes of the cup and handle with the lofting technique, and use the 'write' library for the text. I'm not sure how to construct the points myself, but I'm hoping that's something you can come up with on your own. I am also hoping you can handle the maths for scaling the object as necessary to arrive at the desired volume for different unit settings.

[Assistant]
measuring_cup.scad:
```
// 'Measuring Cup' Version 1.0 by wstein
// is licensed under the Attribution - Non-Commercial - Share Alike license.
// (c) December 2014
// please refer the complete license here: http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode

//Modified 5/11/2019 to make Customizer work without errors (I hope) by J.P. Cuzzourt
//I renamed 'wall_thickness_' to 'wall_thickness'
//& renamed 'wall_thickness' to 'wall_thickness_adjusted'
//The effect of the word 'thickness' enclosed in underscore characters on the Thingiverse site is to italicize 'thickness'!
//I also edited the code to eliminate the use of the deprecated assign() function calls and replaced them with direct assignments
//While Customizer still times out, it does create the customized item now.

/*Update - later that night (5/11/2019)- JPC
    In further testing I noticed that
    if user entered a number for the label1_text or label2_text in Customizer, it changes the data type from string
    and fails to place the text on handle.
    Since the variable are only used in one place in the code, I just wrapped the assignment with a call to str() as follows:
    labels=[
        [0,str(label1_text),label1_font,label1_height,label_thickness],
        [1,str(label2_text),label2_font,label2_height,label_thickness],
        ];
*/

use <write/Write.scad>

/* [Size] */
// unit of measurement
unit=1.0; // [1.0:ml, 16.387064:cubic inch (international inch), 28.4130625:imperial fluid ounce (Imp.fl.oz.), 29.5735295625: US fluid ounce (US fl.oz.)]

// capacity of the cup
volume=62.5;

label1_text="";
label2_text="";

/* [Font] */

// default: 1.5
label_thickness = 1.5;

//default: 8.0
label1_height = 8.0;

//default: orbitron.dxf
label1_font="orbitron.dxf"; //[orbitron.dxf,Letters.dxf,knewave.dxf,BlackRose.dxf,braille.dxf]

//default: 8.0
label2_height = 8.0;

//default: orbitron.dxf
label2_font="orbitron.dxf"; //[orbitron.dxf,Letters.dxf,knewave.dxf,BlackRose.dxf,braille.dxf]

/* [Advanced] */

// If the printed size does to much differ, you can adjust here. It is easy to calculate: [desired volume] / [printed volume] -> adjust.
adjust=1;

// default: 1.0 (should be enough up to 100ml)
wall_thickness=1.0;

/* [Hidden] */

// set to true, to get a model of the content volume. This can be measure with MeshLab or other tools
build_measure_volume_reference=0; // [1:true, 0:false]

// this is the unscaled cup volume (calculated with MeshLab)
ref_volume=137.2013;

r_fn=12;  // used for $fn

labels=[
[0,str(label1_text),label1_font,label1_height,label_thickness],
[1,str(label2_text),label2_font,label2_height,label_thickness],
];

volume_ml=volume*unit;
echo("capacity in ml:", volume_ml);

// calculate correct scale to get the exact volume
factor=pow(volume_ml/ref_volume*adjust,1/3);
wall_thickness_adjusted=wall_thickness/factor;
echo("factor: ",factor);

r1=1;
r2=r1+wall_thickness_adjusted;

y0=-35;
y1=0;
y3=45;

y4=68;

x0=0;
x1=19;
x2=29;
x3=30;
x5=16;

z0=0;
z1=-45;
z2=-5;

y2=-z1+y0;
y01=y0+(r2-r1);
y31=y4+(y3-y4)*2/3;

x4=(y1-y0)/(y2-y0)*(x3-x5)+x5;
x11=x1+(x2-x1)/2;

z3=-(r2-r1);
z4=y0;

bottom_factor=0.7;
handle_factor=0.9;

// cup points
cup_points=[
[x1,y4,z0],
[x2,y3,z0],
[x3,y2,z0],
[x4,y1,z0],
[-x4,y1,z0],
[-x3,y2,z0],
[-x2,y3,z0],
[-x1,y4,z0],
[x11*bottom_factor,y31,z1],
[x2*bottom_factor,y3-2,z1],
[x3*bottom_factor,y2,z1],
[x4*bottom_factor,y1+3,z4-3],
[-x4*bottom_factor,y1+3,z4-3],
[-x3*bottom_factor,y2,z1],
[-x2*bottom_factor,y3-2,z1],
[-x11*bottom_factor,y31,z1],
];

// handle points
handle_points=[
[x4*handle_factor,y1,z2],
[x4,y1,z0],
[x5,y0,z0],
[x5*handle_factor,y01,z3],
[-x5*handle_factor,y01,z3],
[-x5,y0,z0],
[-x4,y1,z0],
[-x4*handle_factor,y1,z2],
];

//build cup
rotate([45,0,0])
scale([1,1,1]*factor)
build_cup(cup_points);

module build_cup(points)
intersection()
{
	translate([0,0,z1-r2])
	linear_extrude(height=abs(z1)+r2,convexity=10)
	polygon([
	[-x3-r2-.1,y0-r2-.1],
	[x3+r2+.1,y0-r2-.1],
	[x3+r2+.1,y4+r2+.1],
	[-x3-r2-.1,y4+r2+.1],
	]);

	difference()
	{
		if(!build_measure_volume_reference)
		union()
		{
			build_handle(handle_points);

			handle_outline(points, r=r2);
		}

		handle_outline(points, r=r1);
	}
}

module build_handle(points){
a=-atan((z3-z2)/(y1-y01));
difference()
{
	union()
	{
		translate([0,y0,0])
		rotate([-45,0,0])
		translate([-(y1-y0)/2/2,0,-r2])
		cube([(y1-y0)/2,(y1-y0)/3,y1-y0],center=0);

		handle_outline(points, r=r2);
	}

	difference()
	{
		handle_outline(points, r=r1);

		for(label=labels)
		build_label(label[0],label[1],label[2],label[3],label[4]);
	}
}
}

module build_label(idx, text, font, height, thickness){
n=4;
xd=(x4-x5)/(n+1); yd=(y1-y01)/(n+1); zd=(z2-z3)/(n+1);
r=yd/4;
if(len(text)>0)
{
	// write label
	rotate([-atan((z3-z2)/(y1-y01)),0,0])
	translate([0,-11.5-idx*2*yd,z2-r1-.1])
	minkowski()
	{
		write(text, h=height, t=.1, font=font, center=true);

		cylinder(r1=wall_thickness_adjusted/4,r2=0,h=thickness,$fn=4);
	}
}
else
{
	// no labe? Then build riffle
	for(a=[0.7+(1-idx)*2:n-idx*2])
	hull()
	for(m=[0,1])
	mirror([m,0,0])
	translate([x5+xd*a-yd,y01+yd*a,z3+zd*a-r/2])
	sphere(r=r,$fn=r_fn);
}
}

module handle_outline(points, r) {
hull()
for(p=points)
translate(p)
sphere(r=r,$fn=r_fn);
}

```


[User]
I'd like to create a customizable name tag using OpenSCAD. The design should have a larger first letter followed by the rest of the name, all sitting on a rectangular platform with a hole for attaching to something.

Here's a breakdown of what I need:

*   **Text:**
    *   There should be a parameter for the first letter of the name, let's call it `FirstLetter`.
    *   There should be another parameter for the remaining letters, `RemainingLetters`.
    *   The first letter should be larger than the remaining letters.
    *   I need a way to position the first letter using parameters on both the X and Y axes. Let's call those parameters `FirstLetterPositionX` and `FirstLetterPositionY`.
    *   There should be a parameter `CapitalSpacing` to control the horizontal space between the first letter and the remaining letters.
    *  The text should use the "Source Serif Pro:style=Semibold" font. The first letter should be size 20, and the remaining letters should be size 12.

*   **Platform:**
    *   The letters should sit on a platform. The platform should be a rectangular cube.
    *   The platform should have a parameter for its length, let's call it `PlatformLength`. The width should be 1.5 and the height should be 2.
    *  The platform should be slightly below the letters on the Y axis, and it should extend a bit past the text on the X axis.

*   **Hole:**
    *   There should be a hole at one end of the platform.
    *   The hole should be created with a cylinder.
    *   I need parameters for the radius of the cylinder that creates the hole (`HoleRadius`), and for the radius of the outer cylinder that removes the material for the hole (`OuterHoleRadius`).
    *  The hole should be centered on the platform on the X axis and slightly below the platform on the Y axis.

*   **Overall Structure:**
    * The whole thing should be constructed using `difference()` to subtract the hole from the rest of the model.

I'd like all the parameters to be easily adjustable. Could you provide me with an OpenSCAD file or files to achieve this? I would also like the `$fn` value to be set to 128.

[Assistant]
NameTag.scad:
```
FirstLetter = "M";
RemainingLetters = "AYA";
FirstLetterPositionX = 2;
FirstLetterPositionY = 0;
CapitalSpacing = 27;
PlatformLength = 57;

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

createTag(FirstLetter, RemainingLetters, FirstLetterPositionX, FirstLetterPositionY, CapitalSpacing, PlatformLength);

module createTag(firstLetter, remainingLetters, firstLetterPositionX, firstLetterPositionY, capitalSpacing, platformLength) {
    difference() {
        union() {
            translate([firstLetterPositionX, firstLetterPositionY, 0])
            linear_extrude(height=2)
            text(firstLetter, 20, "Source Serif Pro:style=Semibold", spacing=1);

            translate([capitalSpacing,0,0])
            linear_extrude(height=2)
            text(remainingLetters, 12, "Source Serif Pro:style=Semibold", spacing=1);

            translate([0,-1.3,0])
            cube([platformLength,1.5,2]);

            translate([-1,-4.5,0])
            cylinder(2, r=7);
        }

        translate([-1,-4.5,-0.5])
        cylinder(3, r=5.4);
    }
}
```


[User]
I'm looking to create a customizable spring clip holder for tools like screwdrivers. I want to be able to adjust several parameters to fit different tools and mounting situations.

The basic idea is a clip formed by two mirrored, curved arms. These arms should have a notch in the center of each arm, where the screwdriver shaft will be held. The two arms connect at their base. I also want to include mounting holes that can be customized by location and the addition of countersinks.

Specifically, here's what I'd like to be able to adjust:

*   **Number of Mounting Holes:** I need to be able to specify 0, 1, or 2 mounting holes.
*   **Mounting Hole Diameter:**  I need a parameter for the diameter of the mounting holes.
*   **Countersink:** A toggle to enable or disable countersinking of the mounting holes, as well as the angle and depth of the countersink.
*   **Overall Holder Height:** The total height of the clip holder needs to be adjustable.
*   **Spring Distance:** The distance between the two curved arms needs to be adjustable.
*   **Notch Radius:** The radius of the notch that holds the tool.
*   **Notch Type:**  The shape of the notch (e.g. diamond, hexagon, semicircle).
*  **Spring Thickness:** The thickness of the material forming the spring arms.
*   **Spring Width and Height:** The dimensions of the ellipse that defines the spring arm's curvature.

Could you generate the necessary OpenSCAD files to accomplish this? It's important that the whole design is parametric. I expect that the final output will be a single, printable model, but it can be broken into multiple files if needed for clarity.

I'm not using any special libraries at the moment.

[Assistant]
spring_clips_V3.scad:
```
/********* BEST VIEWED IN 80 COLUMNS ** BEST VIEWED IN 80 COLUMNS **************
*
* Spring Clip Screwdriver Holder
* Benjamen Johnson <workshop.electronsmith.com>
* 20190509
* Version 3
* openSCAD Version: 2015.03-2
*******************************************************************************/
// number of mounting holes
mounting_hole_num = 2; // [0,1,2]

// mounting hole diameter
mount_hole_dia = 4;

// Countersunk mounting hole?
countersink = 1; //[0:false, 1:true]

//Countersink angle
countersink_angle = 82;

//Countersink depth
countersink_depth = 3;

// How high is the entire spring clip holder
holder_height = 20;

// the distance between the springs
spring_distance = 0.2;

// the size of the notch
notch_radius = 3;

// type of notch
notch_type = 4; // [4:Diamond, 5:Hex, 50:Semicircle]

// How thick are the two springs
wall_thickness = 3;

// width of the ellipse that makes the spring
spring_width = 16;

//height of the ellipse that makes the spring
spring_height = 40;

// make holes go all the way through in preview
render_offset = 0.01;

x=tan(countersink_angle/2)*countersink_depth/2;

difference(){

    union(){
        holder();
        mirror([1,0,0])holder();

        //join the two sides
        translate([0,-spring_height/2+wall_thickness/2,0])cube([spring_width+spring_distance,wall_thickness,holder_height],center=true);
    } // end union

    //cut the inside of the spring
    translate([0,-spring_height/2+3*wall_thickness/2,0])cube([spring_width+spring_distance,wall_thickness,2*holder_height],center=true);

    //cut the mounting hole
    if (mounting_hole_num == 1){
        translate([0,-spring_height/2+wall_thickness/2,0])rotate([90,0,0])cylinder(d=mount_hole_dia,h=wall_thickness+render_offset, center=true,$fn=50);
        if (countersink){
            translate([0,-spring_height/2+wall_thickness/2+(wall_thickness-countersink_depth)/2,0])rotate([90,0,0])cylinder(d2=mount_hole_dia, d1=mount_hole_dia+2*x, h=countersink_depth+render_offset,center=true,$fn=50);
        } //end if countersink
    } //end if 1 mounting hole
    else if (mounting_hole_num == 2){
        translate([0,-spring_height/2+wall_thickness/2,-holder_height/4])rotate([90,0,0])cylinder(d=mount_hole_dia,h=wall_thickness+render_offset, center=true,$fn=50);
        translate([0,-spring_height/2+wall_thickness/2,holder_height/4])rotate([90,0,0])cylinder(d=mount_hole_dia,h=wall_thickness+render_offset, center=true,$fn=50);
        if (countersink){
            translate([0,-spring_height/2+wall_thickness/2+(wall_thickness-countersink_depth)/2,-holder_height/4])rotate([90,0,0])cylinder(d2=mount_hole_dia, d1=mount_hole_dia+2*x, h=countersink_depth+render_offset,center=true,$fn=50);
            translate([0,-spring_height/2+wall_thickness/2+(wall_thickness-countersink_depth)/2,holder_height/4])rotate([90,0,0])cylinder(d2=mount_hole_dia, d1=mount_hole_dia+2*x, h=countersink_depth+render_offset,center=true,$fn=50);
        } // end if countersink
    } //end if 2 mounting holes
} //end difference

/*******************************************************************************
* Function to make the spring three dimensional and have thickness
*******************************************************************************/
module holder()
{
    translate([0,0,-holder_height/2])
    linear_extrude(height=holder_height){
        difference(){
            spring();
            offset(r=-wall_thickness)spring();
        }// end difference
    } // end linear_extrude
}

/*******************************************************************************
* Function to make the outline of one side of the spring
*******************************************************************************/
module spring()
{
    difference(){
        translate([-(spring_width/2+spring_distance/2),0,0])ellipse(spring_width/2,spring_height/2,200);
        circle(r=notch_radius,center=true,$fn=notch_type);
        }// end difference
}// end module

/*******************************************************************************
* Simple function to make an ellipse
* a: semi-minor axis
* b: semi-major axis
* res: smoothness -- render with how many sides ($fn)
*******************************************************************************/
module ellipse(a,b,res){
    scale([a,b,1])circle(r=1,$fn=res,center=true);
}// end module
```
spring_clips.scad:
```
/********* BEST VIEWED IN 80 COLUMNS ** BEST VIEWED IN 80 COLUMNS **************
*
* Spring Clip Screwdriver Holder
* Benjamen Johnson <workshop.electronsmith.com>
* 20190509
* Version 1
* openSCAD Version: 2015.03-2
*******************************************************************************/
// number of mounting holes
mounting_hole_num = 2; // [0,1,2]

// mounting hole diameter
mount_hole_dia = 4;

// Countersunk mounting hole?
countersink = 1; //[0:false, 1:true]

//Countersink angle
countersink_angle = 82;

//Countersink depth
countersink_depth = 3;

// How high is the entire spring clip holder
holder_height = 20;

// the distance between the springs
spring_distance = 0.2;

// the size of the notch
notch_radius = 3;

// type of notch
notch_type = 4; // [4:Diamond, 5:Hex, 50:Semicircle]

// How thick are the two springs
wall_thickness = 3;

// width of the ellipse that makes the spring
spring_width = 16;

//height of the ellipse that makes the spring
spring_height = 40;

x=tan(countersink_angle/2)*countersink_depth/2;

difference(){

    union(){
        holder();
        mirror([1,0,0])holder();

        //join the two sides
        translate([0,-spring_height/2+wall_thickness/2,0])cube([spring_width+spring_distance,wall_thickness,holder_height],center=true);
    } // end union

    //cut the inside of the spring
    translate([0,-spring_height/2+3*wall_thickness/2,0])cube([spring_width,wall_thickness,holder_height],center=true);

    //cut the mounting hole
    if (mounting_hole_num == 1){
        translate([0,-spring_height/2+wall_thickness/2,0])rotate([90,0,0])cylinder(d=mount_hole_dia,h=wall_thickness, center=true,$fn=50);
        if (countersink){
            translate([0,-spring_height/2+wall_thickness/2+(wall_thickness-countersink_depth)/2,0])rotate([90,0,0])cylinder(d2=mount_hole_dia, d1=mount_hole_dia+2*x, h=countersink_depth,center=true,$fn=50);
        } //end if countersink
    } //end if 1 mounting hole
    else if (mounting_hole_num == 2){
        translate([0,-spring_height/2+wall_thickness/2,-holder_height/4])rotate([90,0,0])cylinder(d=mount_hole_dia,h=wall_thickness, center=true,$fn=50);
        translate([0,-spring_height/2+wall_thickness/2,holder_height/4])rotate([90,0,0])cylinder(d=mount_hole_dia,h=wall_thickness, center=true,$fn=50);
        if (countersink){
            translate([0,-spring_height/2+wall_thickness/2+(wall_thickness-countersink_depth)/2,-holder_height/4])rotate([90,0,0])cylinder(d2=mount_hole_dia, d1=mount_hole_dia+2*x, h=countersink_depth,center=true,$fn=50);
            translate([0,-spring_height/2+wall_thickness/2+(wall_thickness-countersink_depth)/2,holder_height/4])rotate([90,0,0])cylinder(d2=mount_hole_dia, d1=mount_hole_dia+2*x, h=countersink_depth,center=true,$fn=50);
        } // end if countersink
    } //end if 2 mounting holes
} //end difference

/*******************************************************************************
* Function to make the spring three dimensional and have thickness
*******************************************************************************/
module holder()
{
    translate([0,0,-holder_height/2])
    linear_extrude(height=holder_height){
        difference(){
            spring();
            offset(r=-wall_thickness)spring();
        }// end difference
    } // end linear_extrude
}

/*******************************************************************************
* Function to make the outline of one side of the spring
*******************************************************************************/
module spring()
{
    difference(){
        translate([-(spring_width/2+spring_distance/2),0,0])ellipse(spring_width/2,spring_height/2,200);
        circle(r=notch_radius,center=true,$fn=notch_type);
        }// end difference
}// end module

/*******************************************************************************
* Simple function to make an ellipse
* a: semi-minor axis
* b: semi-major axis
* res: smoothness -- render with how many sides ($fn)
*******************************************************************************/
module ellipse(a,b,res){
    scale([a,b,1])circle(r=1,$fn=res,center=true);
}// end module
```


[User]
I need some help designing LED strip mounting clips for under a windowsill. I'd like to be able to adjust the parameters for the clip to fit different LED strips and mounting situations.

Specifically, I'm looking for two types of clips: one for a permanent, fixed mounting and another where you can easily remove or change the strip.

For the *fixed* clip:

*   It should have a curved base that allows it to be mounted under the window sill, kind of like an upside-down letter "U".
*   The curved base needs a radius that I can adjust.
*   The clip needs to have a space for the LED strip to fit into, with adjustable width and height to suit various LED strip sizes.
*   It should have two mounting holes (countersunk preferred but not strictly required) on either side of where the LED strip goes, for screws.
*   The holes should be a distance apart which is adjustable based on the LED strip width.

For the *changeable* clip:

*   It needs the same curved base with an adjustable radius as the fixed clip.
*   It also needs adjustable width and height for the LED strip.
*   It should only have one mounting hole at one end of the clip.
*   On the opposite side, it should have an extra "wall" that keeps the LED strip in place by friction or a snug fit, so it can be pushed or pulled out easily. This can be like a little block, for example.

For both clip types, I want to be able to control:

*   The radius of the curved base.
*   The width and height of the LED strip space.
*   The diameter of the mounting holes.
*   The thickness of the material.

Could you generate parametric OpenSCAD files for these two clip types? I don't need any particular libraries, just the standard OpenSCAD functions are fine.

[Assistant]
LEDribaKlamber.scad:
```
//Curve quality
$fn=100;//[10:1:300]
/*[LED ribbon parameters]*/
//LED ribbon width
r_laius=10;//[3:1:15]
//LED ribbon height
r_korgus=3;//[2:1:6]
/* [LED ribbon mounting brace parameters] */
//Mounting brace curvature radius
raadius=25;//[20:1:100]
//Mounting brace with one mounting hole
yksik=0;//[0:No,1:Yes]
/* [Hidden] */
korgus=r_korgus*1.5;
kruvi_d=3;
laius=kruvi_d*3;
pikkus=r_laius+4*kruvi_d;
if (yksik!=0) rotate([-90,0,0]) klamber(); else klamber();
module klamber(){
difference(){
translate([0,0,-raadius+korgus])
intersection(){
rotate([90,0,0]) cylinder(laius,r=raadius,center=true);
translate([0,0,raadius-korgus/2]) cube([pikkus,laius,korgus], center=true);
}
cube([r_laius,laius,r_korgus*2], center=true);
translate([r_laius/2+(pikkus/2-r_laius/2)/2,0,0]) cylinder(laius,d=kruvi_d);
translate([-(r_laius/2+(pikkus/2-r_laius/2)/2),0,0]) cylinder(laius,d=kruvi_d);
translate([r_laius/2+(pikkus/2-r_laius/2)/2,0,r_korgus-1]) cylinder(kruvi_d*2,d=kruvi_d+kruvi_d/1.6);
if (yksik==0)
translate([-(r_laius/2+(pikkus/2-r_laius/2)/2),0,r_korgus-1]) cylinder(kruvi_d*2,d=kruvi_d+kruvi_d/1.6);
else{
translate([-(pikkus/2+r_laius/2+1),0,r_korgus]) cube([pikkus,laius,r_korgus*2], center=true);
translate([-r_laius/2,0,0]) cube([r_korgus,laius,r_korgus], center=true);}
}
}
```