[User]
I need an OpenSCAD design for a Zanker Flow Conditioner Plate, which is essentially a circular plate with a specific pattern of holes. The plate's diameter should be a variable I can set, and the hole pattern needs to follow certain rules outlined in ASME MFC-3M-2004 standards.

Specifically, the plate will have 5 concentric arrays of holes. The diameter of each hole array is dependent on the plate diameter (D) in the following manner, where "Diam" refers to the diameter of the holes, and "Pitch" refers to the pitch circle diameter of the array:

*   **Array 1 (innermost):** Diam1 = 0.141 * D, Pitch1 = 0.25 * D; 4 holes, equally spaced, plus a rotation of 45 degrees
*   **Array 2:** Diam2 = 0.139 * D, Pitch2 = 0.56 * D; 8 holes (4 pairs), each pair equally spaced relative to the main points but with a rotation of 18.5 degrees and -18.5 degrees, respectively
*   **Array 3:** Diam3 = 0.1365 * D, Pitch3 = 0.75 * D; 4 holes, equally spaced, plus a rotation of 45 degrees
*   **Array 4:** Diam4 = 0.110 * D, Pitch4 = 0.85 * D; 8 holes (4 pairs), each pair equally spaced relative to the main points but with a rotation of 11.66667 degrees and -11.66667 degrees, respectively
*   **Array 5 (outermost):** Diam5 = 0.077 * D, Pitch5 = 0.90 * D; 8 holes (4 pairs), each pair equally spaced relative to the main points but with a rotation of 29 degrees and -29 degrees, respectively

The thickness of the plate should be D / 8. The holes should go completely through the plate, so extend them slightly beyond the plate's thickness.

I’d like the design to be parametric, so I can easily change the diameter D. I'm hoping this will all be done in a single `.scad` file.

[Assistant]
ZankerFlowConditionerPlate.scad:
```
//Variables

//Diameter of Plate in mm
D = 127 ;

Thickness = D/8; ; // Thickness of plate

//Diameter 1-5 for hole arrays from inner to outer
Diam1 = 0.141*D;//
Diam2 = 0.139*D;
Diam3 = 0.1365*D;
Diam4 = 0.110*D;
Diam5 = 0.077*D;

//Corresponding Pitch circle diameters
Pitch1 = 0.25*D;
Pitch2 = 0.56*D;
Pitch3 = 0.75*D;
Pitch4 = 0.85*D;
Pitch5 = 0.90*D;

//Build hole array
module HoleArray(){

//Inner Hole Array (1)
for (i=[1:4])  {
	translate([Pitch1/2*cos(i*(360/4)+45),Pitch1/2*sin(i*(360/4)+45),0]) cylinder(r=Diam1/2,h=Thickness+1, $fn=500);
    }

//Second Hole Array (2)
for (i=[1:4])  {
	translate([Pitch2/2*cos(i*(360/4)+18.5),Pitch2/2*sin(i*(360/4)+18.5),0]) cylinder(r=Diam2/2,h=Thickness+1, $fn=500);
    translate([Pitch2/2*cos(i*(360/4)-18.5),Pitch2/2*sin(i*(360/4)-18.5),0]) cylinder(r=Diam2/2,h=Thickness+1, $fn=500);
    }

//Third Hole Array (3)
for (i=[1:4])  {
	translate([Pitch3/2*cos(i*(360/4)+45),Pitch3/2*sin(i*(360/4)+45),0]) cylinder(r=Diam3/2,h=Thickness+1, $fn=500);
    }

//Fourth Hole Array (4)
for (i=[1:4])  {
	translate([Pitch4/2*cos(i*(90)+11.66667),Pitch4/2*sin(i*(90)+11.66667),0]) cylinder(r=Diam4/2,h=Thickness+1, $fn=500);
    translate([Pitch4/2*cos(i*(90)-11.66667),Pitch4/2*sin(i*(90)-11.66667),0]) cylinder(r=Diam4/2,h=Thickness+1, $fn=500);
    }

//Fifth / Outer hole array (5)
for (i=[1:4])  {
	translate([Pitch5/2*cos(i*90+29),Pitch4/2*sin(i*90+29),0]) cylinder(r=Diam5/2,h=Thickness+1, $fn=500);
    translate([Pitch5/2*cos(i*90-29),Pitch5/2*sin(i*90-29),0]) cylinder(r=Diam5/2,h=Thickness+1, $fn=500);
    }
}

module Plate() {
    cylinder (r=D/2, h=Thickness, $fn=500);
}

difference()    {
Plate(center=true);
translate([0,0,-.5], center = false) HoleArray(center=true);
}

//Subtract modules from one anotherv
```


[User]
I'd like to design a customizable smartphone stand in OpenSCAD. I have a basic idea based on some code I found, but I need it to be more flexible and parametric.

Here's what I'm thinking:

**Core Structure:**

*   The stand should be cylindrical, with an adjustable outer radius and height.
*   The wall thickness should also be a parameter, allowing for adjustments to the stand's sturdiness.
*   It should have a cutout to hold the phone, angled backward at a customizable angle. The depth of this cutout should also be adjustable.
*   I'd like to have a small lip or ridge at the bottom of the cutout to prevent the phone from sliding. This should also have parameters for its size and position.

**Hex Grid Pattern:**

*   The stand should have a hexagonal grid pattern on its surface.
*   I need parameters for the starting position (x and y), the radius of the hexagons, and the width of the grid lines. I'd like the pattern to extend over the entire cylindrical surface of the stand.
*   I'm thinking of having a boolean parameter for whether to invert the hex pattern, that way I can have either the hexagons or the hexagon outlines as the surface detail.

**Parameters:**

I need to be able to control all these things with parameters at the start of the file:

*   `outer_radius` (of the cylinder)
*   `height` (of the cylinder)
*   `wall_thickness`
*   `angle` (of the phone cutout)
*   `smartphone_depth` (depth of phone cutout)
*   `start_x` (for hex grid)
*   `start_y` (for hex grid)
*   `radius` (of hexagons)
*   `width` (of hex grid lines)
* `invert_hex_pattern` (boolean)

Could you generate the OpenSCAD code for this? I don't need any special libraries; I'd rather keep it as simple as possible.

[Assistant]
Smartphone-HalterungV4.scad:
```
// -----------------------------------------------------
// Smartphone-HalterungV4
//
//  Detlev Ahlgrimm, 11.2018
// -----------------------------------------------------

/* [Main parameters] */
outer_radius=40;        // [20:60]
height=100;             // [50:150]
wall_thickness=1;       // [0.5:0.1:4]
angle=26;               // [0:40]
smartphone_deepth=20;   // [5:40]

/* [Hex-Grid parameters] */
start_x=20;             // [0:0.1:40]
start_y=12;             // [0:0.1:40]
radius=10;              // [3:30]
width=1;                // [0.2:0.05:2]

/* [Hidden] */
$fn=100;
c=smartphone_deepth;
a=c*cos(angle);
b=sqrt(c*c-a*a);

// -----------------------------------------------------
//    v : Abmessungs-Vektor
//    r : Radius der Aussparungen
//    w : Wandstaerke zwischen den Aussparungen
//    i : invertieren (true:Sechseck-Umrandungen, false:Sechsecke)
//    a : anschraegen 45 Grad (bei true)
// -----------------------------------------------------
module HexPatternV2(v, r=10, w=1, i=true, a=false) {
  dx=r*1.5;
  dy=r*0.866025;      // 0.866025=sqrt(3)/2
  sy=(i) ? -0.1 : 0;
  az=(i) ? 0.2 : 0;
  r1=(a) ? r-w/2-(v.z+0.2) : r-w/2;

  intersection() {
    difference() {
      if(i) cube(v);
      for(yi=[0:1:v.y/dy+1]) {
        for(xi=[0:1:v.x/(2*dx)+1]) {
          if((yi%2)==1) {
            translate([xi*2*dx+dx, yi*dy, sy]) cylinder(r1=r1, r2=r-w/2, h=v.z+az, $fn=6);
          } else {
            translate([xi*2*dx, yi*dy, sy]) cylinder(r1=r1, r2=r-w/2, h=v.z+az, $fn=6);
          }
        }
      }
    }
    if(!i) cube(v);
  }
}

union() {
  difference() {
    union() {
      difference() {        // aeussere Wand
        cylinder(r=outer_radius, height, $fn=6);
        translate([0, 0, -0.1]) cylinder(r=outer_radius-wall_thickness, height+0.2, $fn=6);
      }
      intersection() {      // Hex-Pattern
        translate([-outer_radius-start_x, -outer_radius-start_y, 0]) HexPatternV2([200, 200, height], radius, width);
        cylinder(r=outer_radius, height, $fn=6);
      }
    }
    // Platz fuer Smartphone schaffen
    translate([-outer_radius-1, -outer_radius*0.866025+2+a, 5]) rotate([-angle, 0, 0]) translate([0, -2*outer_radius, 0]) cube([2*outer_radius+2, 2*outer_radius, 2*height]);
  }
  // Anti-Wegrutsch-Steg
  translate([-outer_radius*0.5, -outer_radius*0.866025+2, 5+b]) rotate([90, 0, 0]) hull() {
    linear_extrude(2) polygon([[0,0], [outer_radius,0], [outer_radius-5,5], [5,5]]);
    translate([0, -2, 1.99]) cube([outer_radius, 2, 0.01]);
  }
}

// Smartphone-Muster draufsetzen
//%translate([-outer_radius-1, -outer_radius*0.866025+2+a, 5]) rotate([-angle, 0, 0]) translate([0, -smartphone_deepth, 0]) cube([2*outer_radius+2, smartphone_deepth, height*1.5]);

```


[User]
I'm looking to design a mount for an SMA antenna on a drone, specifically something that attaches to the standoffs of the drone frame. I've got a pretty good idea of what I need, and I'd like to make it fully parametric so I can adjust it for different frames later. I want to be able to adjust the standoff separation, radius, and height, as well as the SMA adapter's position and angle.

Here's the breakdown:

*   **Standoffs:** The mount should slide over the drone's standoffs. I need to define parameters for the separation between standoffs, their radius, and their height. I also need to be able to set a thickness around the standoffs, as the mount itself adds material to the standoff's radius.
*   **SMA Adapter:** The mount should include a section to hold an SMA adapter. I want to define the adapter's outer radius, the angle it sits at, and its offset (how far it sticks out from the standoffs). Also, I'll need to set the height offset of the mount point for the adapter relative to the base of the mount, as well as the connection's thickness and height where it connects to the standoff mount. I will also need the depth for the recessed hex part in the adapter and the depth for the sma hole in the adapter, as well as the radius of the hex and the connector itself.
*  **Tie-wrap holes:** The mount should also incorporate tie-wrap holes. These holes must have a specified width and height. They should be located on either side of the standoff. There should also be holders for these tie-wraps. I need to be able to set the tie-wrap holder's width, height, and depth.
*   **Flat surfaces:** I'd like options to flatten the top of the connection to the adapter and also flatten the top of the whole adapter so that everything is flush with the build plate. I would like these to be set by variables called `flat_connection_top` and `flat_adapter_top`, which can be 0 or 1.
*  **Rotation:** I also need an option to rotate the entire model to make it easier to print. This should be a boolean variable called `rotate_model`.
*   **Overall:** I'll need to define a `$fn` variable to make all curves more round.

I'd like to see this in OpenSCAD, and I would appreciate it if you used a modular design, so I can easily reuse parts later. I'm not expecting any specialized libraries, just pure OpenSCAD. Let me know if you need more clarification.

[Assistant]
sma-mount.scad:
```
// 1 to stretch the connection upwards and flatten it, 0 to keep connection height
flat_connection_top = 1;

// 1 to flatten the adapter top to make everything flush (with the build plate) for easier printing
flat_adapter_top = 1;

// Standoff seperation
so_sep = 31;
// Standoff radius is 2.5mm, I added 0.2mm on each side to make it a nice slide-on with PETG
so_r = 2.7;
// Model thickness around standoff
so_t = 1.2;
// Standoff height. The Hawk 5 has a 25mm standoff but the bottom ~0.5mm is covered
so_h = 24.5;

// The sma adapter outer radius
sma_r = 6;
// Angle at which the adapter sits
angle = 25;
// Distance the adapter sticks out
a_offset = 15;
// Offset from the bottom to the adapter-to-standoff mount
a_hoffset = 12;
// Adapter to standoff connection thickness
connection_thickness = 4.5;
// Adapter to standoff connection height
connection_height = 8;

// Tiewrap hole width & height
tw_w = 3.1;
tw_h = 1.2;

// Tiewrap holder width & height
tw_holder_h = 5;
tw_holder_w = (so_r + so_t) * 2;
tw_holder_d = so_r + so_t + tw_w + 2;

// Depth of the recessed hex part in the adapter
hex_h = 3;
// Depth of the sma hole in the adapter
shaft_h = 3;

// Hex and connector radi
hex_r = 4.1;
con_r = 3.4;

// Total 'height' for the adapter
con_h = hex_h + shaft_h;

// 1 to rotate, 0 to have it upright
rotate_model = 0;

$fn = 64;

module arc( height, depth, radius, degrees ) {
    // This dies a horible death if it's not rendered here
    // -- sucks up all memory and spins out of control
    render() {
        difference() {
            // Outer ring
            rotate_extrude($fn = 100)
                translate([radius - height, 0, 0])
                    square([height,depth]);

            // Cut half off
            translate([0,-(radius+1),-.5])
                cube ([radius+1,(radius+1)*2,depth+1]);

            // Cover the other half as necessary
            rotate([0,0,180-degrees])
            translate([0,-(radius+1),-.5])
                cube ([radius+1,(radius+1)*2,depth+1]);

        }
    }
}

// Block for the tiewraps
module AntennaHolder() {
    // The tiewrap
    translate([so_sep / 2, 0, so_h - (tw_holder_h / 2)]) {
        rotate([0, 0, 45]) {
            difference() {
                translate([tw_holder_d / -2, 0, 0]) {
                    cube([tw_holder_d, tw_holder_w, tw_holder_h], center = true);
                }
                translate([-(so_r + so_t) - (tw_w / 2), 0, 0.5]) {
                    # cube([tw_w, 40, tw_h], center = true);
                    translate([0, 0, tw_h / -2]) {
                        # cube([1.5, 40, 2], center = true);
                    }
                    # cube([tw_w, 40, tw_h], center = true);
                }
            }
        }
    }
}

module StandOffs() {
    translate([so_sep / 2, 0, 0]) {
        cylinder(r = so_r, h = so_h * 2);
    }
    translate([-so_sep / 2, 0, 0]) {
        cylinder(r = so_r, h = so_h * 2);
    }
}

module StandoffsHolder() {
    translate([so_sep / 2, 0, 0]) {
        cylinder(r = so_r + so_t, h = so_h);
    }
    translate([-so_sep / 2, 0, 0]) {
        cylinder(r = so_r + so_t, h = so_h);
    }
}

// size is the XY plane size, height in Z
module hexagon(size, height) {
    boxWidth = size/1.75;
    for (r = [-60, 0, 60]) rotate([0,0,r]) cube([boxWidth, size, height], true);
}

module AdapterCylinder(os = 0) {
    cylinder(r = sma_r - os, h = con_h, center = true);
}

module Adapter() {
    difference() {
        AdapterCylinder();
        translate([0, 0, -(con_h / 2) + (hex_h / 2)]) {
            hexagon(hex_r * 2, hex_h);
        }
        translate([0, 0, (con_h / 2) - (shaft_h / 2)]) {
            cylinder(r = con_r, h = shaft_h, center = true);
        }
    }
}

module RoundBar() {
    difference() {
        scale([1,a_offset / (so_sep / 2),1]) {
            rotate([0,0,-90]) {
                arc(connection_thickness, connection_height + (flat_connection_top * 10), so_sep / 2 + (connection_thickness / 2), 180);
            }
        }
    }
}

module Holder() {
    difference() {
        translate([0, 0, a_hoffset]) {
            rotate([angle, 0, 0]) {
                translate([0, a_offset, 0]) {
                    rotate([-90, 30, 0]) {
                        Adapter();
                    }
                }
            }
        }
    }
}

module HolderArm() {
    AntennaHolder();
    mirror([1,0,0]) {
        AntennaHolder();
    }
    intersection() {
        translate([-20, 0, 0]) {
            cube([40, 40, 40]);
        }
        difference() {
            translate([0, 0, a_hoffset]) {
                rotate([angle, 0, 0]) {
                    translate([0, a_offset, 0]) {
                        difference() {
                            translate([0,-a_offset,-connection_height / 2]) {
                                RoundBar();
                            }
                            rotate([-90, 0, 0]) {
                                AdapterCylinder(0.01);
                            }
                        }
                    }
                }
            }
            translate([0, 0, so_h + 10]) {
                cube([50, 50, 20], center = true);
            }
        }
    }
}

module Model() {
    difference() {
        StandoffsHolder();
        StandOffs();
    }

    difference() {
        union() {
            Holder();
            HolderArm();
        }
        StandOffs();
        translate([-50,0,-100 + so_h + (flat_adapter_top * 100)]) {
            cube([100,100,20]);
        }
    }
}

// Rotate everything to make it print-ready
if (rotate_model == 1) {
    rotate([180 - angle, 0, 0]) {
        Model();
    }
} else {
    Model();
}
```


[User]
Hi, I'm looking to create a parametric life counter for a tabletop game, and I need some help with the design in OpenSCAD. I've seen some examples online, but I'd really like to be able to customize all the dimensions.

Here's what I'm envisioning:

The counter will be composed of multiple rotating dials stacked on top of each other. Each dial will have a set of numbers and/or letters engraved on its outer surface. The whole assembly will have endcaps at the top and bottom that hold everything together, and also a central shaft that the dials will rotate around. I'd like to be able to control all of the sizes of each of the following parts:

*   **Dials:**
    *   The number of sides (and thus the number of numbers/letters) on each dial.
    *   The depth of the engraved numbers/letters.
    *   The larger radius and smaller radius of each dial.
    *   The height (or width) of each dial.
    *   The number of dials on the assembled counter.
*   **Endcaps:**
    *   The radius of the base of the endcaps should be slightly larger than the dial radius.
    *   The height of the endcaps.
*   **Shaft:**
    *   The shaft will pass through all the dials and both endcaps and be slightly longer than total height of all dials and endcaps to ensure the dials are held in place.
    *   I want the shaft to be based on a star shape.

It would also be great if the design has a small indicator built into the endcaps to show which number is currently selected. And, I want to be able to choose between having a hole for the shaft to pass through the endcaps or having the shaft be a solid part of the endcaps.

I'm using the `star.scad` file from Thingiverse (the parametric star library by Gaellafond) as part of this design, so I'll need to make sure that the design takes that into account as a dependency.

I would like to specify these parameters via variables at the beginning of the file, so they're easily changed. I'm imagining something like: `sides`, `Engrave_Depth`, `Large_Radius`, `Small_Radius`, `Cylinder_Height`, `Number_of_Dials`, `Base_Radius`, `overhang`, and `Endcap_Height`, among others. Also a variable like `part` which will let me preview only specific parts of the model and the assembly.

Is this something you can do? Let me know if I need to clarify anything.

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

 * =====================================
 *  Parametric life counter
 *  https://www.thingiverse.com/thing:3194819
 *  This code is available under a  Creative Commons - Attribution - Non-Commercial
 *  see https://creativecommons.org/licenses/by-nc/3.0/ for details.
 *  Contributed by: TappedOut
 *  https://www.thingiverse.com/TappedOut/about

 * design theory for the ratcheting mechanism is inspired by Ratcheting Spin-Down Life Counter by Intentional3D: https://www.thingiverse.com/thing:1008518
 *
 *
 * Requires Parametric star library by Gaellafond (https://www.thingiverse.com/thing:3194819) as a dependency. place star.scad
 * in the same directory as this file to run.

 * =====================================

*/

include <star.scad>;

/* [Configuration] */
// Which part would you like to preview.
part = 0; // [0:Middle Dial,1:Left Dial,2:Right Dial,3:Endcap with Hole,4:Endcap with shaft]
// How many sides are on the dial? (Letters appear after 9!)
sides = 10;
// how many digits are there?
Number_of_Dials = 2;

/* [Dials] */
// How deep are the numbers engraved on the dials?
Engrave_Depth = 2;
// what is the larger radius of dials?
Large_Radius = 16.6;
// what is the smaller radius of dials?
Small_Radius = 14.4;
// how wide are the dials?
Cylinder_Height = 12.5;

/*[Base_and_Endcaps]*/
// how much larger is the base compared to the dials?
Base_Radius = 3;
// how much taller should the shaft be?
overhang = 0;
// how tall are the endcaps

Endcap_Height = 5;
/* [Hidden] */
// how deep should the shaft go into the endcap (when not solid)
Overlap_Area = 2.5;

module center(){
    // top of circle with point.
    intersection(){
       translate([0,0,200/-2]) star3D(n=sides, ri=7,ro=8, h=400, center=true);
        rotate([0,0,360/sides/2]) translate([0,8,0]) cylinder(r=8/1.25, h=200, center=true);
    }

   // circle without the top
   difference(){
        cylinder(r=8, h=200, center=true);
        rotate([0,0,360/sides/2]) translate([0,8+1,0]) cube(size=[8*4,5,50], center=true);
    }

    difference(){
        rotate([0,0,360/sides/2]) translate([0,8,0]) cylinder(r=2.5, h=200, center=true);
        rotate([0,0,360/sides/2]) translate([0,8,0]) cylinder(r=8*5/8, h=200, center=true);
    }

    // remove an area from the center and the partial ring.
    rotate([0,0,360/sides/2-360/sides]) translate([0,8,0]) cube(size=[1,8,200], center=true);

    // create the partial ring
    intersection(){
        // constrain the ring to a segment based on this cube.
        rotate([0,0,360/sides/2-360/sides]) translate([0,8,0]) translate([8*1.35/-2,0,0]) cube(size=[8*2,20,200], center=true);
        // create a ring
        difference(){
            cylinder(r=8+8/2, h=200, center=true);
            cylinder(r=8+8/2-2.3, h=200, center=true);
        }
     }
}

// inner portion of a dial (does not have engraved numbers)
module innerShell(cylinderRadius, cylinderRadius2){
    difference(){
        cylinder(r=cylinderRadius-Engrave_Depth, r2=cylinderRadius2-Engrave_Depth, h=Cylinder_Height, $fn=sides);
        center();
    }
}

// outer portion of a dial (DOES not have engraved numbers)
module outerShell(cylinderRadius, cylinderRadius2, includeNumbers=true){
 difference(){
        cylinder(r=cylinderRadius, r2=cylinderRadius2, h=Cylinder_Height, $fn=sides);
        center();
        numbers();
    }
}

// create the numbers in a for loop
module numbers(){
    for (i = [0:sides-1]){
        rotate([0,0,360/sides/2-360*i/sides]) translate([0,0,Cylinder_Height/2])
        rotate([90,90,90])
        linear_extrude(max(Large_Radius,Small_Radius)) scale(.7) text(
        // if the number is greater than 9 start making letters
        str (i < 10 ? i : chr(65+i-10)),        str(i),
        valign="center", halign="center");
    }
}

module bottom(star=1, offsetValue=0, h2=5){
    translate([0,0,5-h2]) difference(){
        // complete shape
        hull(){
            // cylinder base
            cylinder(r2=max(Large_Radius,Small_Radius)+Base_Radius/2, r1=max(Large_Radius,Small_Radius,Base_Radius)+Base_Radius, h=h2, $fn=sides);
            // bottom edge
            difference(){
                // bottom edge base
                translate([0,(max(Large_Radius,Small_Radius)+Base_Radius)*-1,0]) translate([0,h2/2,h2/2]) cube(size=[(max(Large_Radius
,Small_Radius)+Base_Radius)*2,h2,h2],center=true);
                // top part removed from bottom to make it half its normal height
                translate([0,0,h2/4]) translate([0,(max(Large_Radius,Small_Radius)+Base_Radius)*-1,0]) translate([0,h2/2,h2/2]) cube(size=[(max(Large_Radius,Small_Radius)+Base_Radius)*2,h2,h2],center=true);
            }
        }

        // star (this has NO height if the module value 'star' is zero)
        translate([0,0,h2-offsetValue]) translate([0,0,h2/2]) centerstar3D(h2*star);
        // indicator cylinder
        translate([0,(max(Large_Radius,Small_Radius)+3),h2]) rotate([90,0,0]) scale([2,1.1  ,1]) cylinder(r=5/2, h=5, $fn=100);
    }
}

module preview(){
    makePart(4);
    translate([0,0,Endcap_Height]) makePart(2);
    for (i = [0:Number_of_Dials-3]){
        translate([0,0,Cylinder_Height*(i+1)+Endcap_Height]) makePart(0);
    }

    translate([0,0,Endcap_Height+Cylinder_Height*(Number_of_Dials-1)]) makePart(1);
    translate([0,0,Endcap_Height*2+Cylinder_Height*Number_of_Dials]) rotate([0,180,0]) makePart(3);
}

// remove the functions from center before running this preview.
// only useful for making a preview of the thing.
// rotate([90,0,0]) preview();

makePart(part);

// make different versions of the parts.
module makePart(mode){
    if (mode == 0){
        // middle dial
        // portion of the dial out to a certain radius before engraving happens
        outerShell(Small_Radius, Small_Radius);
        // portion of the dial from where the engraving begins to the edge
        innerShell(Small_Radius, Small_Radius);
    } else if (mode == 1){
        // left dial
        // portion of the dial out to a certain radius before engraving happens
        innerShell(Small_Radius, Large_Radius);
        // portion of the dial from where the engraving begins to the edge
        outerShell(Small_Radius, Large_Radius);
    } else if (mode == 2){
        // right dial
        // portion of the dial out to a certain radius before engraving happens
        innerShell(Large_Radius, Small_Radius);
        // portion of the dial from where the engraving begins to the edge
        outerShell(Large_Radius, Small_Radius);
    } else if (mode == 3){
        // endcap with hole
        bottom(1, Endcap_Height, Endcap_Height);
    } else if (mode == 4){
        // make a shaft equal to the number of dial's height, and a fudge factor (overhang)
//        translate([0,0,Cylinder_Height*Number_of_Dials-Endcap_Height+overhang/2]) centerstar3D(Cylinder_Height*Number_of_Dials+Endcap_Height+overhang);
//        translate([0,0,Cylinder_Height*Number_of_Dials-Endcap_Height+overhang/2]) star3D(Cylinder_Height*Number_of_Dials+Endcap_Height+overhang);
    translate([0,0,Endcap_Height]) star3D(n=sides, ri=7,ro=8, h=Cylinder_Height*Number_of_Dials+Endcap_Height+overhang);

        // make a solid endcap
        bottom(0, -1);
    } else if (mode == 5){
        // encaps with holes that do not go all the way through.
        // overlap is the how deep the hole is that does not go all the way through.
        bottom(1, Overlap_Area);
    } else if (mode == 6){
        // encaps with holes that do not go all the way through.
        // overlap is the how deep the hole is that does not go all the way through.
        centerstar3D(Cylinder_Height*Number_of_Dials+Overlap_Area*2+overhang);
    } else if (mode == 7){
        // shaft for 2 endcaps with holes
        centerstar3D(Cylinder_Height*Number_of_Dials+Endcap_Height*2+overhang);
    }
}

// convert a 2d star to 3d with height (h)
module star3D(n=5, ri=15, ro=30, h=0) {
    linear_extrude(h) star(n, ri, ro);
}

// create a 3d star and center it vertically
module centerstar3D(heightInput=200){
   translate([0,0,heightInput/-2]) star3D(n=sides, ri=7,ro=8, h=heightInput);
}

```


[User]
I need a design for a pipe collar that can be 3D printed. It should be in two halves that bolt together, allowing it to be clamped around a pipe.

Here are the parameters I want to control:

*   **`pod`**: The outside diameter of the pipe the collar will fit around (e.g., 75mm).
*   **`sd`**: The diameter of the mounting screw used to attach the collar to the wall (e.g., 5mm for an M5 screw).
*   **`shp`**: The profile of the mounting screw head. This will be a selector, with `0` for a cylinder head, `1` for a hex head, and `2` for a flat head.
*   **`shd`**: The diameter of the screw head (or the widest part of the head for hex or flat heads), for example, 9mm.
*   **`shh`**: The height of the screw head, for example, 3.75mm.
*   **`wd`**: The minimum wall distance - the distance from the edge of the pipe to the edge of the collar where it can be mounted, say 9mm.
*   **`tol`**: Tolerance, 0.2mm
*   **`fn`**: Resolution for circular parts. For instance, 90 would give a nice smooth circle.
*   **`part`**: Which part to render, where 0 will render both, 1 will render part A, and 2 will render part B.

The collar will be basically two semi-circular pieces. Each piece should have two "arms" extending out from the pipe circle part. These arms should then have mounting holes for the screws. I need a way to mount it to the wall using screws that go perpendicular to the pipe.

I need a few features for the arms:
   * Each arm should start with a narrow section attached to the pipe half, with a small hull or similar shape extending out about 1.5mm from the main body.
   * That narrow section should widen to create an arm. The end of the arm should then extend out vertically before attaching to a flat section that runs horizontally out to the mounting hole.
    * The mounting hole section should be thick and have some kind of support or ribs. This should be for mounting it to a wall. I think a hexagonal shape would be neat.
*   The mounting holes themselves should have a counterbore for the screws that fits the `shp` variable.

I'm thinking something along these lines:
   * A main cylinder cut with a slightly larger diameter to allow for pipe tolerance.
   * Cut the main cylinder in half.
   * Add the arms and mounting hole features to each half.
   *  Create the cutouts for the mounting screws and also the counterbore.

The mounting holes will require M3 bolts for assembly so we should also account for bolt head and bolt clearance. I would also like to be able to select the screw head type.

I don't need a library at the moment, but using the $fn variable for part resolution would be great. I'd expect to be able to use a customizer to set up these values when rendering. Could you provide a single `.scad` file that handles all of this for me?

[Assistant]
PipeCollar_001.scad:
```
//pipe outside diameter
pod=75;
//mounting screw diameter
sd=5;
//mounting screw head profil
shp=0; //[0:cylinder, 1:hex head A, 2:flat head]
//mounting screw head diameter (widest diameter for hex or flat head screw)
shd=9;
//mounting screw head height
shh=3.75;
//wall distance (6mm min)
wd=9;

//tolerance
tol=0.2;
//definition
$fn=90;
//Part to render
part=0; //[0:All, 1:Part A, 2:Part B]

/////////////

module All() {
    difference() {
        union() {
            cylinder(d=pod+12,h=15,center=true);
            hull() {for(i=[-pod/2-wd+1.5,-pod/2],j=[-1,1]) translate([i,j*(pod/4),0]) cylinder(d=3,h=15,center=true);}
            hull() {for(i=[-1,1],j=[-1,1]) translate([i*7+0.25*pod/2,j*(pod/2+16),0]) cylinder(d=3,h=15,$fn=32,center=true);}
        }

        cylinder(d=pod+1+2*tol,h=17,center=true);
        translate([0.25*pod/2,0,0]) cube([0.75,pod+40,17],center=true);
        rotate([0,-90,0]) {cylinder(d=sd+2*tol,h=pod);}
        if (shp==0) {rotate([0,-90,0]) cylinder(d=shd+2*tol,h=pod/2+shh);}
        else if (shp==1) {rotate([90,0,-90]) cylinder(d=shd+2*tol,h=pod/2+shh,$fn=6);}
        else if (shp==2) {
            rotate([0,-90,0]) {
                cylinder(d=shd+2*tol,h=pod/2+0.51+2*tol);
                translate([0,0,pod/2+0.5+2*tol]) cylinder(d1=shd+2*tol,d2=sd+2*tol,h=shh);
            }
        }
        for(i=[-1,1]) translate([0.25*pod/2,i*(pod/2+10),0]) rotate([0,-90,0]) {
            cylinder(d=3.6,h=20,center=true);
            translate([0,0,-9.5]) cylinder(d=6.5,h=4);
            translate([0,0,5]) rotate([0,0,30]) cylinder(d=7,h=4,$fn=6);
        }
    }
}
module PartA() {
    difference() {
        All();
        translate([1.25*pod/2,0,0]) cube([pod,2*pod,17],center=true);
    }
}

module PartB() {
    difference() {
        All();
        translate([-0.75*pod/2,0,0]) cube([pod,2*pod,17],center=true);
    }
}

module Render(a) {
    if(a==0) {
        PartA();
        translate([6,0,0]) PartB();
    }
    else if(a==1) {PartA();}
    else if(a==2) {PartB();}
}
Render(part);

```


[User]
Hey, I'm trying to design some screws, and I've found this pretty neat OpenSCAD module called `revolve.scad`. It lets you define a 2D profile and then extrude it rotationally along a helix, which is exactly what I need. I'd like to create a parametric design around it, but I'm not exactly sure how to get started.

Here's what I'm envisioning:

1.  I'd like to keep the core functionality from `revolve.scad`, but I don't want to include the function itself as it will be incorporated into my own module. It uses a `linspace` helper function, as well, which I will need.
2.  I'd like to be able to specify several parameters:
    *   `pitch`: This is the distance between threads, like in the `period` example of the code.
    *   `length`: This is the overall length of the screw.
    *   `n_threads`: This is the number of threads. It can be positive for right-handed screws or negative for left-handed ones, just like the original module.
    *   `profile_type`: This will be a string that allows me to select a predefined profile, such as "square", "trapezoidal", "triangular", or "sinusoidal".
    *   `profile_params`: This will be an array of parameters that depend on the selected profile type. For example, if `profile_type` is "square", this might be `[thread_width, thread_height]` but could also take on other meaning for other shapes, and may not even be used.
    *   `angular_segments`: this is the number of segments in the circular direction, like the `f` parameter in the code. It defaults to `undef`, at which point it will compute automatically as in the code.
3.  The different `profile_type`s should be defined as functions, each of which takes the `profile_params` and a `z` value, and outputs `[z, f(z)]`, just like the example profile function.
4.  I would also like the module to have `render(convexity=10)` applied automatically, as in the original example.
5.  The profile should always be defined over a closed interval (including the extremes) representing one period of the thread.

I want all of this to be in a single file, called something like `parametric_screw.scad`. Could you help me create this parametric screw module?

Also, please don't include any code that would try to *call* the module - I just want the module itself.

[Assistant]
revolve.scad:
```
/***************************
*** Introduction

This OpenSCAD module allows for rotational extrusion of generic user-defined profiles,
introducing a pitch in the longitudinal direction, the most common application being
the creation of screws.
The solid is built as a single polyhedron by transforming the 2D points found in the
profile array. No boolean operation is necessary, aiming at obtaining the ultimate
performance by producing the simplest possible object for the desired level of detail.

*** Arguments

* profile: array of 2D points defined as [[z1, f(z1)], [z2, f(z2)], ... [zn,f(zn)]].
  The function f(z) describes the shape of the thread (trapezoidal, square, triangular,
  sinusoidal, ...).
  The shape of the profile can be refined by adding more points, however this will
  also make it heavier to handle.
  The profile should should be defined over a closed interval (including the extremes)
  representing one period of the thread.
  The linspace helper function might be used to create the profile from a mathematical
  function (see example below).
* length: how far to go in the longitudinal direction, note that the mesh size increases
  linearly with this parameter.
* nthreads: allows the creation of multiple threads, it should be an integer.
  Negative number are also accepted, generating left threads.
  Zero results in no pitch, similar to rotate_extrude.
* f: the number of subdivisions in the angular direction, similar to $fn for a cylinder.
  Note that if this parameter is too small, the resulting mesh could be completely wrong.
  A sufficient condition to satisfy correctness should be: f>period*nthreads/dz;
  where dz is the minimum sum of two consecutive z increments as defined in the profile.
  In the longitudinal direction the number of subdivisions is controlled directly by
  the number of points in the profile.

*** Example

***************************/
period = 6; // choose the pitch
length = 30;  // the tallness
nthreads = 7; // the number of threads (<0 for left threads)
f = undef; // angular finesse, undef for autocompute

// A sinusoidal profile function...
function prof_sin(z) = [z, 10+sin(z*360/period)];
// ...which becomes a profile array with the help of linspace
prof = [for (z=linspace(start=0, stop=period, n=16)) prof_sin(z)];

// Otherwise define a square profile array defined manually
//prof = [[0, 11], [0.01, 9], [period/2, 9], [period/2+0.01, 11], [period, 11]];

// now the screw
render(convexity=10) revolve( prof, length=length, nthreads=nthreads, f=f);
/***************************

*** Licence

This OpenSCAD module was written by Dario Pellegrini <pellegrini dot dario at gmail dot com>
It is released under the Creative Commons Attribution (CC BY) licence v4.0 or later.
https://creativecommons.org/licenses/by/4.0/

*** Changelog

2018/11/09 Released v1.0

***************************/

function linspace(start,stop, n) = let (step=(stop-start)/(n)) concat( [ for (i = [0:1:n-step/2]) start+i*step], stop);

function xor(a,b) = (a && !b) || (!a && b);
function ceil_mult(n,m) = ceil(n/m)*m;
function rotate_2D(p, a=0) = [cos(a)*p[0]-sin(a)*p[1], sin(a)*p[0]+cos(a)*p[1], p[2]];

function front(v) = v[0];
function back(v) = v[len(v)-1];
function pop_front(v) = [for (i=[1:1:len(v)-1]) v[i] ];
function reverse(v) = [for (i=[len(v)-1:-1:0]) v[i]];
function reverse_if(v, cond) = cond ? reverse(v) : v;

function lookup_2D(pts, z) =
  let(x=[for (p=pts) [p[2],p[0]]], y=[for (p=pts) [p[2],p[1]]])
    [lookup(z,x), lookup(z,y), z];

function trim_duplicates(v) = let(N=len(v)-1)
    concat([for (i=[0:1:N-1]) if (v[i] != v[i+1]) v[i]],
           (v[N-1] == v[N]) ? [] : [v[N]]); //adjusts the last one

function trim_bottom(pts, val) =
  concat([ for (i=[0:1:len(pts)-2])
    if ( pts[i+1][2]>val )
      (pts[i][2]<val) ? lookup_2D([pts[i],pts[i+1]], val) : pts[i]
  ], [back(pts)]);

function trim_top(pts, val) =
  concat([ for (i=[len(pts)-1:-1:1])
    if ( pts[i-1][2]<val )
      (pts[i][2]>val) ? lookup_2D([pts[i-1],pts[i]], val) : pts[i]
  ], [front(pts)]);

function trim(pts, b, t) =
  reverse(trim_top(trim_bottom(trim_duplicates(pts), b), t));

function flatten(l) = [ for (a = l) for (b = a) b ] ;

function make_indx(pts, res=[], i=0) = (len(pts)==0) ? res :
  make_indx(pop_front(pts), concat(res,
    [[for (j=[0:1:len(front(pts))-1]) j+i]]), i+len(front(pts)));

function make_circular(v) = concat(v, [front(v)]);

function sort3(a,b,c) =
  (a<b) ? (b<c) ? [a,b,c] : (a<c) ? [a,c,b] : [c,a,b] :
 /*a>b*/  (b>c) ? [c,b,a] : (a>c) ? [b,c,a] : [b,a,c] ;

function make_triplet(v1,v2,last) = let( s=sort3(v1[0],v2[0],v2[1]) )
  xor(s[1]+1==s[2], last) ? [s[0],s[2],s[1]] : s;

function final_triplets(v1,v2,last) =
  (len(v1)==3) ? [make_triplet(v2,v1,last), make_triplet(v2,pop_front(v1),last)] :
  (len(v1)==2) ? [make_triplet(v2,v1,last)] : [];

function make_triplets(v1, v2, last, res=[]) =
  (len(v1)<len(v2)) ? make_triplets(pop_front(v2), v1, last, concat(res, [make_triplet(v1,v2,last)] ) ) :
  (len(v2)==1) ? concat(res, final_triplets(v1,v2,last)) :
  make_triplets(pop_front(v2), v1, last, concat(res, [make_triplet(v1,v2, last)] ) );

function Na_euristic(dz, pthreads, Na) =
  (Na > pthreads/dz) ? Na : Na_euristic(dz, pthreads, Na+1);

function compute_Na(dz, period, nthreads, Na) = let(nt=max(abs(nthreads),1))
   ceil_mult(min(200,(Na==undef ? Na_euristic(dz, period*nt, 3) : Na)), 2*nt);

module revolve(profile = [[]], length, nthreads=1, f=undef) {
  // Prepare some variables
  period = back(profile)[0]-front(profile)[0];
  profile_ext = [for (zp = [-period*abs(nthreads):period:length*(abs(nthreads)+1)]) for ( p=profile ) [ p[0]+zp, p[1]]];
  maxR = max([for (p=profile) p[1]]);
  dz = min([for (i=[2:1:len(profile)-1]) abs(profile[i][0]-profile[i-2][0]) ]);
  Na = compute_Na(dz, period, nthreads, f);
  if (f==undef && Na>200) echo("WARNING (revolve): the internal computation of \"f\" resulted in a value larger than 200, therefore it has been trimmed down. If the mesh is inconsistent please spefify manually a larger value.");
  echo(str("Na=", Na));
  stepa = 360/Na;

  // Compute the array of points
  pts = [for (an=[0:1:Na-1]) let(ai=an*stepa) trim(
        [for (pn=profile_ext) let(zi=pn[0]+an*period*nthreads/Na, ri=pn[1] )
        rotate_2D([ri, 0, zi], ai)],
      profile[0][0], profile[0][0]+length )];
  // Compute the array of indexes: same structure as pts, but contains a progressive numbering
  indx = reverse_if(make_circular(make_indx(pts)), nthreads<0);

  // Compute the faces, this is the trickiest part...
  fcs = concat( [ for(i=[0:1:Na-1]) make_triplets(indx[i],indx[i+1], last=(nthreads>=0)?(i==Na-1):(i==0))],
                [[reverse_if([ for(i=[0:1:Na-1]) front(indx[i])], nthreads< 0),  //bottom
                  reverse_if([ for(i=[0:1:Na-1])  back(indx[i])], nthreads>=0)]] //top
    );

  // Finally build the polyhedron
  polyhedron( points = flatten(pts), faces = flatten(fcs));

  //debugging
//  print_spheres(pts);
//  print_indx(indx, pts, stepa*sign(nthreads));
//  echo_pts(indx,pts);
//  echo_fcs(fcs);
}

//debugging modules
//module echo_pts(indx, pts)
//  for (col=[0:1:len(indx)-2]) for (row = [0:1:len(indx[col])-1])
//    echo(str(indx[col][row],"=", flatten(pts)[indx[col][row]]));
//
//module echo_fcs(fcs)
//  for (f=fcs) echo(f);
//
//module print_spheres(pts)
//  for (p=flatten(pts)) translate(p) color("red") sphere(r=0.2);
//
//module print_indx(indx, pts, stepa)
//  for (an=[0:1:len(indx)-2]) for(zn=[0:1:len(indx[an])-1])
//  let(pt=flatten(pts)[indx[an][zn]])
//  translate(pt) rotate([90,0,90+an*stepa])
//  color("red") linear_extrude(0.02) scale(0.05)
//  text(str(indx[an][zn]), valign="center", halign="center", $fn=4);
```


[User]
I'm trying to create a parametric OpenSCAD design for generating servo spline test plates and individual splines, but I'm having a bit of trouble getting it just right. I'd like the design to function similarly to the existing `servo_spline_maker.scad` file I've included, but I'd like to make sure it's well organized and easily adaptable. The key is to generate either a test plate with incrementally sized splines or just a single spline, depending on user selection.

Here's a breakdown of what I need:

1.  **User-Selectable Part Type:** The design should have a parameter `part` that allows the user to choose between generating a "plate" (test plate with multiple splines) or "spline" (single spline).

2.  **Spline Geometry:**
    *   The number of teeth on the spline (`spline_count`) should be a user-adjustable parameter.
    *   An approximate diameter of the spline (`approximate_diameter`) should be adjustable as well. This is just an initial guess, the generated splines in the test plate will vary around this size.
    *   The difference in diameter between adjacent splines on the test plate (`step_size`) should be adjustable.
    *   The geometry should create a circular hole with splines.  The splines should be somewhat pointy, but not excessively so.  There should be some reasonable amount of solid material between the tips of the splines and the outside edge of the hole.  I think a good algorithm for generating the alternating inside and outside spline points is given in the `servo_spline_maker.scad` file.

3.  **Test Plate Generation:**
    *   If the user selects "plate", the design should generate multiple splines, each with a slightly different diameter. The diameter should vary based on the `approximate_diameter` and the `step_size`.
    *   Each spline should be labeled with a text indication of its offset from the nominal diameter (e.g., "-2", "-1", "0", "1", "2").
    *   Each label should be located directly above the center of the spline.
    *   The splines should be evenly spaced along the x axis, with the nominal diameter in the center.
    *   The labels should be extruded with a height of 1mm, as in the attached file.
    *   There should be a base plate behind the splines, to allow the text labels to be printed on a solid surface.  This should have some margin.
    *   A single line of text should be located on the top edge, saying the approximate diameter and step size for all the splines.

4.  **Single Spline Generation:**
    *   If the user selects "spline", the design should generate just one spline with the diameter specified by `approximate_diameter`.
    *   The shape of the spline should match those generated for the plate.

5.  **Parameters and Customization:**
    *   All the parameters (part, spline\_count, approximate\_diameter, step\_size) should be exposed to the OpenSCAD customizer.

For this task, I don't need to worry about including any external libraries.  Can you generate the OpenSCAD code for this?

[Assistant]
servo_spline_maker.scad:
```
// Generate test plate for determining proper size, or spline alone for integrating into larger design
part = "plate"; // [ plate:Test Plate, spline:Spline Only ]

// How many points are on the spline (it's important that this is correct)
spline_count = 21;

// Estimated diameter of spline will be fine-tuned for a good fit
approximate_diameter = 4.5;

// First attempt, recommend 0.2 or greater, finer tuning recommend 0.1
step_size = 0.2;

module dummy() { }  // no more parameters

approx_od = approximate_diameter;
disc_size = approx_od+10;  // for purposes of plate generation...

stepmin = -4;
stepmax = 4;
xmid = (stepmin+stepmax)/2*(approx_od+8);

if (part == "plate") {
  for (i=[stepmin:stepmax]) {
    translate([i*(approx_od+8), 0, 0]) {
      spline_hole(approx_od + i*step_size);
      spline_plate(i);
    }
  }

  translate([xmid, 17, 0])
  linear_extrude(height=1)
  text(str("Nominal: ", approx_od, "  Step: ", step_size), 5, halign="center");
}
else {  // spline or anything else, just make the spline
  spline_hole(approx_od);
}

module spline_hole(inside_points_diameter = approx_od, label) {
  r1 = inside_points_diameter/2;
  // approximate distance along circumference from one bump to the next
  space = r1*sin(360/spline_count);
  r2 = r1 + space*0.75;  // pointy but not *too* pointy
  // about 4mm solid between outer points and outside disc, should be large enough to prevent
  // slicers from being goofy about the space betewen the splines and the outside.
  disc_d = 2*r2 + 8;

  linear_extrude(height=2.6)
  difference() {
    circle(d=disc_d, $fn=36);
    polygon([
      for (i=[1:2*spline_count])
        (i % 2 == 0) ?
          [ r1*cos(i*360/(2*spline_count)), r1*sin(i*360/(2*spline_count)) ] :
          [ r2*cos(i*360/(2*spline_count)), r2*sin(i*360/(2*spline_count)) ]
        ]);
  }
}

module spline_plate(label) {
  // text showing which value
  translate([0, disc_size/2+1, 0])
  linear_extrude(height=1)
  text(str(label), 5, halign="center");

  // flat plate on which to put text
  translate([-disc_size/2-2, -disc_size/2, -2])
  cube([disc_size+4, disc_size+18, 2]);
}
```


[User]
Hey, I'm looking to design a custom enclosure for a vactrol, which is basically an LED and a photoresistor that are housed together to act like a variable resistor controlled by current. I've seen some designs online, and I really like the "Chez Vactrol" model by Stellar Innovation. It's on Thingiverse, if that helps. What I need is a parametric OpenSCAD design that allows me to adjust all the component dimensions, as well as the enclosure thickness and tolerances for a good fit.

Specifically, I need to be able to specify:

*   The diameter and height of the LED, plus a small tolerance.
*   The diameter and height of the LED's "ring", again with tolerance.
*   The spacing and diameter of the LED leads, and how far out they extend from the LED body.
*   The width, height, and thickness of the photoresistor cell, with tolerance.
*   The spacing and diameter of the photoresistor leads, and how far out they extend.

The enclosure itself needs to have adjustable wall thickness and a "tight fit" tolerance that is applied to both the upper and lower parts of the enclosure. I also need to ensure that the design accounts for the minimum vertical and horizontal spacing of the leads as well as that the external leads come out on a 0.1" pitch, since this is a standard spacing.

I want the enclosure to have a rounded rectangular shape using the BoxWithRoundCorners function, and the design should also incorporate a small pin 1 marker on the upper enclosure part, and include internal supports for the leads on the lower part of the enclosure that keep them apart. I was hoping to be able to use `linear_extrude` and `polygon` for the pin 1 marker, and `cube` for box and support shapes. `cylinder` and `sphere` should do for the LED and its leads, and `circle` and `square` for the rounded box corners.
I'm not really sure where to begin with this one, so if you could generate the full set of .scad files that I would need, that would be great.

[Assistant]
chezvactrol.scad:
```
// "Chez Vactrol" provided by Stellar Innovation
// http://www.thingiverse.com/stellarinnovation/about
// under Creative Commons License, Attribution (BY)

// Thickness of shell
shell = 1.2;      // [1.0:0.1:3.0]

// Tolerance used for upper/lower part
tightFit = 0.15;  // [0.10:0.01:0.30]

// Diameter of LED +tolerance
LED_Diameter = 5.3; // [3.0:0.1:9.9]

// Height of LED +tolerance
LED_Height = 9.0;        // [3.0:0.1:15.0]

// Diameter of LED "ring" + tolerance
LED_RingDiameter = 6.1; // [3.0:0.1:12.0]

// Height of LED "ring" + tolerance
LED_RingHeight = 1.4;   // [0.5:0.1:3.0]

// Spacing of LED leads
LED_LeadSpacing = 2.5; // [1.0:0.1:5.0]

// Diameter of LED leads + tolerance
LED_LeadDiameter = 1.2;  // [0.5:0.1:1.9]

// Distance, LED to holes for leads
LED_LeadLength = 4.0; // [1.0:0.5:6.0]

// Width of LDR photo cell + tolerance
PhotoCellWidth = 5.5; // [3.0:0.1:9.9]

// Height of LDR photo cell + tolerance
PhotoCellHeight = 4.8; // [3.0:0.1:9.9]

// Thickness of LDR photo cell + tolerance
PhotoCellThickness = 2.2; // [0.5:0.1:5.0]

// Spaceing of LDR photo-cell leads
PhotoCellLeadSpacing = 2.5; // [1.0:0.1:5.0]

// Diameter of LDR photo-cell leads + tolerance
PhotoCellLeadDiameter = 1.2; // [0.5:0.1:1.9]

// Distance, LDR photo cell to holes for leads
PhotoCellLeadLength = 5;  // [1.0:0.5:6.0]

// Minimum vertical spacing between leads of the enclosure (round upwards to 0.1" pitch)
minVerticalLeadSpacing = max(PhotoCellLeadSpacing, PhotoCellWidth - PhotoCellLeadDiameter,
                                LED_LeadSpacing, LED_Diameter - LED_LeadDiameter);
verticalLeadSpacing = 2.54*ceil(minVerticalLeadSpacing/2.54);

// Minimum horizontal spacing between leads of the enclosure (round upwards to 0.1" pitch)
minLEDLength = LED_Height + LED_LeadLength;
minPhotoCellLength = PhotoCellThickness + PhotoCellLeadLength;
horizontalLeadSpacing = 2.54*ceil((minLEDLength + minPhotoCellLength)/2.54);

width = verticalLeadSpacing + max(PhotoCellLeadDiameter, LED_LeadDiameter) + 4*shell + 2*tightFit;
height = max(PhotoCellHeight, LED_Diameter, LED_RingDiameter) + 2*shell + 2*tightFit;
length = horizontalLeadSpacing + 0.5*(PhotoCellLeadDiameter + LED_LeadDiameter) + 4*shell + 2*tightFit;

translate([0, 0.5*width+1])
  VactrolCasePart(isUpperPart=true);
translate([0, -0.5*width-1])
  VactrolCasePart(isUpperPart=false);

module VactrolCasePart(isUpperPart) {
   h0 = 0.5*height;
   h1 = h0 - 0.5*shell;
   h2 = h0 + 0.5*shell;
   w1 = 2*shell;
   w2 = w1 + 2*tightFit;
   w3 = w2 + 2*shell;
   extraLength = horizontalLeadSpacing - minLEDLength - minPhotoCellLength;

   difference() {
     // Enclosing box
     BoxWithRoundCorners(length, width, h2, shell);

     // Ledgers around the edge
     translate([0, 0, h1])
       if (isUpperPart)
         Box(length-w1, width-w1, shell);
       else
         difference() {
           Box(length, width, shell+1);
           Box(length-w2, width-w2, shell+2);
         }

     // Inner space of box
     translate([0, 0, h1])
       Box(length-w3, width-w3, h0);

     // cut-out for LED
     translate([0.5*horizontalLeadSpacing, 0, h0])
       LED(LED_LeadLength + 0.5*extraLength);

     // cut-out for photocell
     translate([-0.5*horizontalLeadSpacing, 0, h0])
       PhotoCell(PhotoCellLeadLength + 0.5*extraLength);

     // External holes for leads
     if (!isUpperPart)
       for (y=[-0.5*verticalLeadSpacing, +0.5*verticalLeadSpacing]) {
         translate([-0.5*horizontalLeadSpacing, y])
           cylinder(d=PhotoCellLeadDiameter, h=h0, $fn=24);
         translate([+0.5*horizontalLeadSpacing, y])
           cylinder(d=LED_LeadDiameter, h=h0, $fn=24);
       }

     // Pin1 marker
     if (isUpperPart)
       translate([0.5*horizontalLeadSpacing, -0.5*width + shell])
         Pin1Marker();
   }

   // isolator that keeps the leads apart
   w4 = PhotoCellLeadSpacing - PhotoCellLeadDiameter - 2*tightFit;
   l4 = minPhotoCellLength - PhotoCellThickness + 0.5*extraLength + 0.5*PhotoCellLeadDiameter;
   if (!isUpperPart && w4 > 0)
     translate([-0.5*(horizontalLeadSpacing+PhotoCellLeadDiameter) - shell, -0.5*w4])
       cube([l4 + shell, w4, h2]);

   w5 = LED_LeadSpacing - LED_LeadDiameter - 2*tightFit;
   l5 = LED_LeadLength + 0.5*extraLength + 0.5*LED_LeadDiameter;
   if (!isUpperPart && w5 > 0)
     translate([0.5*(horizontalLeadSpacing+LED_LeadDiameter)-l5, -0.5*w5])
       cube([l5+shell, w5, h2]);

}

module LED(leadLength) {
    r = 0.5*LED_Diameter;
    translate([-leadLength-LED_Height+r, 0]) {
      sphere(d=LED_Diameter, $fn=60);
      rotate([0, 90])
        cylinder(d=LED_Diameter, h=LED_Height-r, $fn=60);
    }
    // Ring
    translate([-leadLength-LED_RingHeight, 0])
      rotate([0,90])
        cylinder(d=LED_RingDiameter, h=LED_RingHeight, $fn=60);

    // Leads
    for (k=[-0.5, +0.5])
      translate([-leadLength, k*LED_LeadSpacing]) {
        rotate([0, 90])
          cylinder(d=LED_LeadDiameter, h=leadLength, $fn=12);
        rLead = 0.5*LED_LeadDiameter;
        translate([0, -rLead])
          cube([leadLength, 2*rLead, shell]);
      }
}

module PhotoCell(leadLength) {
  translate([leadLength, -0.5*PhotoCellWidth, -0.5*PhotoCellHeight])
    cube([PhotoCellThickness, PhotoCellWidth, PhotoCellHeight]);

  // Hole between LED and photo cell
  wayTooMuch = 0.5*LED_Diameter;
  w = min(PhotoCellWidth, LED_Diameter);
  translate([leadLength, -0.5*w, -0.5*PhotoCellHeight])
    cube([PhotoCellThickness+wayTooMuch, w, PhotoCellHeight]);

  // Leads
  for (k=[-0.5, +0.5])
    translate([0, k*PhotoCellLeadSpacing])
      rotate([0, 90])
        cylinder(d=PhotoCellLeadDiameter, h=leadLength, $fn=12);
}

module Pin1Marker() {
  y1 = 2.5;
  x1 = y1/1.73;

  linear_extrude(height = 0.8)
    polygon([[0,0], [x1,y1], [-x1,y1]]);
}

module Box(l, w, h) {
  translate([-0.5*l, -0.5*w])
    cube([l, w, h]);
}

module BoxWithRoundCorners(l, w, h, r) {
  x1 = 0.5*l-r;
  y1 = 0.5*w-r;
  linear_extrude(height=h) {
    for (x=[-x1, +x1], y=[-y1, +y1])
      translate([x, y])
        circle(r=r, $fn=16);

    translate([-0.5*l, -y1]) square([l, 2*y1]);
    translate([-x1, -0.5*w]) square([2*x1, w]);
  }
}

```


[User]
I'd like to design a mushroom anchor for use in a plant pot. It'll have a mushroom-shaped cap on top and a stem with a hole for attaching a line. I'm envisioning a design similar to the one I use now, but I'd like the flexibility to easily change all the dimensions.

Here's a breakdown of the design I need:

**Mushroom Cap:**
*   It should have a generally mushroom-like shape, where a circular base flares out to a slightly larger radius, like a truncated cone.
*   I want to control the *base radius*, the *top radius*, and the *height of the cap*. I also need to control a small shelf thickness around the base of the cap for stability.

**Stem:**
*   The stem is a kind of flat bar that extends down from the center of the cap.
*   The stem should have a rounded hole near the bottom of the stem for attaching a string or line.
*   I need to control the *overall length of the stem*, the *width of the stem*, and the *diameter of the hole*. The stem should also have a rounded profile at the end to make it easier to insert into soil.

**Parameters I need to control:**

*   `cap_base_radius`: Radius of the base of the mushroom cap.
*   `cap_top_radius`: Radius of the top of the mushroom cap.
*   `cap_height`: Height of the mushroom cap.
*   `cap_shelf_thickness`: Thickness of the shelf around the cap base.
*   `stem_length`: Length of the stem
*   `stem_width`: Width of the stem.
*   `hole_diameter`: Diameter of the hole for the line.

It would also be great if we could control how smooth the circular objects are, for preview and rendering purposes, using `$fa` and `$fs` variables. Please try to include that. I don't need any extra libraries. I would like two modules: `mushroom_anchor()` to produce the whole thing, and `rounded_cube()` as a helper module to make the stem's flat bar. Thanks!

[Assistant]
mushroom_anchor.scad:
```
// -*- mode: SCAD ; c-file-style: "ellemtel" ; coding: utf-8 -*-
//
// simple, functional small mushroom anchor
//
// Copyright 2018 Roland Sieker <ospalh@gmail.com>
// Licence: CC-BY-SA 4.0

// Radius of the cap in millimetres
r = 20;  // [5:1:50]

// size of the "chain" hole
hl = 4;  // [1:0.5:10]

// Set this to "render" and click on "Create Thing" when done with the setup.
preview = 1; // [0:render, 1:preview]

/* [Hidden] */

// Done with the customizer

// *******************************************************
// Extra parameters. These can be changed reasonably safely.

l_to_r = 2.5;  // Length of the stem in rs
r_to_h = 0.35;

w = 2.4;  // Wall width
p = 1.8; // cap width
c = 0.4;  // Clearance
angle = 60; // Overhangs much below 60 degrees are a problem for me

// *******************************************************
// Some shortcuts. These shouldn't be changed

tau = 2 * PI;  // pi is still wrong

xy_factor = 1/tan(angle);
// To get from a height to a horizontal width inclined correctly
z_factor = tan(angle);  // The other way around

h = r * r_to_h;
r_i = r - h * xy_factor;
l = r * l_to_r;

some_distance = 50;
ms = 0.01;  // Muggeseggele.

// fn for differently sized objects and fs, fa; all for preview or rendering.
pna = 40;
pnb = 15;
pa = 5;
ps = 1;
rna = 180;
rnb = 30;
ra = 1;
rs = 0.1;
function na() = (preview) ? pna : rna;
function nb() = (preview) ? pnb : rnb;
$fs = (preview) ? ps : rs;
$fa = (preview) ? pa : ra;

// *******************************************************
// End setup

// *******************************************************
// Generate the part

mushroom_anchor();

// *******************************************************
// Code for the parts themselves

module mushroom_anchor()
{
   anchor_cap();
   anchor_stem();
}

module anchor_cap()
{
   difference()
   {
      cylinder(r1=r_i, r2=r, h=h);
      translate([0, 0, -ms])
      {
         cylinder(r1=r_i-p, r2=r-p, h=h+2*ms);
      }
   }
   cylinder(r=r_i, h=p);
}

module anchor_stem()
{
   le = l - w  - hl/2;
   difference()
   {
      union()
      {
         translate([0,0,le/2])
         {
            cube([w,2*w+hl,le], center=true);
         }

         translate([0, 0, le])
         {
            rotate([0, 90, 0])
            {
               cylinder(r=w+hl/2, h=w, center=true);
            }
         }
      }
      translate([0, 0, le])
      {
         rotate([0, 90, 0])
         {
            cylinder(r=hl/2, h=w+2*ms, center=true);
         }
      }
   }
}

```


[User]
I'd like to create a parametric Christmas countdown calendar, similar to the perpetual flip calendar design by Dsk001 but adapted for a countdown.  I've got a pretty good idea of what I want it to look like but need some help with the OpenSCAD code, I'm hoping you can help me generate the files.

Here's a breakdown of the design:

**Core Components:**

*   **Tiles:** These are rectangular tiles that display the countdown numbers. They should have a number on both sides. I need tiles that will countdown from 25 to 13, with "25" on one side of the first tile, "12" on the other side of that tile, "23" on one side of the second tile, "10" on the other side of that second tile, and so on. The last tile, with the number "13" on one side, has a custom "Merry Christmas" on the opposite side, but I also need an alternative where the opposite side has the number "0" instead of the text.
*   **Box:** The box will house the tiles and allow them to be flipped. It should have a slot at the top where the top of the tile will rest and it should be slightly wider than the tile. The box should be a rectangular box with a base and an opening at the top.
*   **Lid:** A simple lid that covers the box.
*   **Roller:** A roller that sits within the box and allows the user to rotate the tiles.
*   **Nuts:** Small nuts to hold the roller in place.
*   **Base:** Two different base options: one narrow, and one wider for better stability.
*   **Plaques (Optional):**  Optional decorative plaques that say "Days Till Christmas".

**Specific Requirements:**

*   **Parametric Design:** I need all dimensions to be customizable.  Specifically, I'd like to control:
    *   Tile width, height, and thickness.
    *   Text height and font.
    *   Box width, depth, and height.
    *   Roller diameter and length.
    *   Nut dimensions.
    *   Base width, depth, and height.
    *   Plaque dimensions (if included).
    *   Clearances between parts (e.g., tile clearance in the box).
*   **Text:** The text on the tiles should be centered. I'd also like to be able to choose between different fonts. I'll be needing to use a few different fonts but I do not know what they are and how they would be defined in the code, I'm hoping you can provide a variety of options. I would like to define two variables, one for the main font and one for the special "Merry Christmas" font.
*   **Tile Design:** The tiles should have numbers extruded on both sides. For the final tile, the text "Merry Christmas" should be on one side using a rotated design, and on the other side a "13". And then the second to last tile should have a '13' on one side and '0' on the other.
*   **Base Design:** The wider base needs to have a significantly larger footprint compared to the narrow one for added stability.
*   **Alignment:** It would be useful to add small alignment lines on the box to better align tiles in the box.
*   **Units:** I'm working in millimeters.

**Libraries:**
I am happy to use any needed libraries to make this project as easy to program as possible, feel free to include any libraries you see fit.

Could you generate the OpenSCAD files based on this description? I'm really looking forward to seeing what you come up with!

[Assistant]
Xmas_Countdown_Date_Block2.scad:
```
// preview[view:south, tilt:top]

part = 13; //[1:"01 - 14", 3:"03 - 16", 5:"05 - 18",7:"07 - 20",9:"09 - 22",11:"11 - 24",13:"13 - Xmas",15:"15 - 02", 17:"17 - 04",19:"19 - 06",21:"21 - 08",23:"23 - 10",25:"25 - 12",0:"13 - 0"]

TextH = 20;
TextF = "Monoton"; // [Monoton, Kumar One Outline, Gloria Hallelujah, Pacifico, Courgette, Permanent Marker, Domine, Ultra, Bevan, Corben, Coustard, Roboto, Orbitron, Indie Flower, Baloo Bhai, Raleway, PT Serif, Jua, Lobster, Do Hyeon, Gloria Hellelujah, Righteous, Stalinist One, Manual]
TextFM = "Monoton";

function is_manual() = TextF == "Manual" ? true : false;

print_part();

module print_part() {
	if (part == 1) {
		p("01", "14");
	} else if (part == 3) {
		p("03", "16");
	} else if (part == 5) {
		p("05","18");
    } else if (part == 7) {
		p("07","20");
    } else if (part == 9) {
		p("09","22");
    } else if (part == 11) {
		p("11","24");
    } else if (part == 13) {
		p13();
    } else if (part == 15) {
		p("15","02");
    } else if (part == 17) {
		p("17","04");
    } else if (part == 19) {
		p("19","06");
    } else if (part == 21) {
		p("21","08");
    } else if (part == 23) {
		p("23","10");
    } else if (part == 25) {
		p("25","12");
    } else if (part == 0) {
		p("13","0");
	} else {
		p("01", "14");
	}
}

module p(front, back){
    difference(){
        //Cube
        translate([-22.5,-30,0]) {
          cube([45,60,3]);
        }

        //Front Text
        translate([0,0,2.5])
        linear_extrude(height = 1)
        text(front,
        size = TextH,
        font = is_manual() ? TextFM : TextF,
        valign = "center",
        halign = "center")
        ;

        //Back Text
        rotate(a=[180,0,0])
        translate([0,0,-.5])
        linear_extrude(height = 1)
        text(back,
        size = TextH,
        font = is_manual() ? TextFM : TextF,
        valign = "center",
        halign = "center")
        ;

        //alignment lines
        translate([-17.5,-30,0]) {
          cube([.5,60,.3]);
        }

        translate([17.5,-30,0]) {
          cube([.5,60,.3]);
        }

        translate([-17.5,-30,2.7]) {
          cube([.5,60,.3]);
        }

        translate([17.5,-30,2.7]) {
          cube([.5,60,.3]);
        }
    }
}

module p13(){
    difference(){
        //Cube
        translate([-22.5,-30,0]) {
          cube([45,60,3]);
        }

        //Front Text
        rotate(a=[0,0,65])
        //translate([-5,7,-.5])
        translate([6,8,2.5])
        linear_extrude(height = 1)
        text("Merry",
        size = TextH-12,
        font = is_manual() ? TextFM : TextF,
        valign = "center",
        halign = "center")
        ;

        //Front Text
        rotate(a=[0,0,65])
        //translate([4,-3,-.5])
        translate([0,-1,2.5])
        linear_extrude(height = 1)
        text("Christmas",
        size = TextH-11,
        font = is_manual() ? TextFM : TextF,
        valign = "center",
        halign = "center")
        ;

        //Back Text
        rotate(a=[180,0,0])
        translate([0,0,-.5])
        linear_extrude(height = 1)
        text("13",
        size = TextH,
        font = is_manual() ? TextFM : TextF,
        valign = "center",
        halign = "center")
        ;

        //alignment lines
        translate([-17.5,-30,0]) {
          cube([.5,60,.3]);
        }

        translate([17.5,-30,0]) {
          cube([.5,60,.3]);
        }

        translate([-17.5,-30,3]) {
          cube([.5,60,.3]);
        }

        translate([17.5,-30,3]) {
          cube([.5,60,.3]);
        }
    }
}
```


[User]
I need a parametric OpenSCAD design for a TFT screen mount, designed to be compatible with LEGO Technic building. I've got a few specific requirements, and I'd like it to be flexible enough to handle different TFT screen sizes and mounting options.

Here's what I'm thinking:

**Base Dimensions:**

*   I need to be able to specify the overall width and height of the base. Let's call these `base_width` and `base_height`. These will be the outer dimensions of the mount itself.

**TFT Screen Dimensions:**

*   The actual TFT screen will have its own width and height, which I'll set as `tft_width` and `tft_height`. I also need to specify its thickness with `tft_thickness`.

**Holes:**

*   There should be mounting holes, both for attaching the TFT to the base and for attaching the base to other LEGO structures.
*   The internal holes (for TFT) should have a width separation of `tft_hole_width` and a height separation of `tft_hole_height`.
*   The external LEGO-compatible holes should have a width separation of `lego_hole_width` and a height separation of `lego_hole_height`.
*   The distance from the edges for external LEGO holes should be specified using `lego_hole_edge_distance`.
*   The thickness of the LEGO hole sections should be adjustable with `hole_thickness`.
*   I'll need to define the diameters of both internal mounting holes (`internal_hole_diameter`) and external LEGO mounting holes (`lego_hole_diameter`).

**Pin Holes:**

*   I need to add space for wiring coming from the TFT, with pins extending beyond each edge of the TFT.
*   These pin holes should have a configurable horizontal offset from the TFT edge, specified by `pin_left_offset` and `pin_right_offset`.
*   The vertical size of the wire holes needs to be set by `pin_left_height` and `pin_right_height`.
*   The thickness of these wire holes needs to be controlled by `pin_thickness`.

**Additional Notes:**

*   I would like the design to be as robust as possible to differing TFT sizes
*   The design should ensure that the base dimensions are always large enough to contain the TFT and the holes.
*   I'd also like for all measurements to be in millimeters.
*   I don't need to specify tolerances right now.
*   I'd also like to be able to round the edges of the base for aesthetics. This should be controlled by a `rounding_radius` parameter.

I'm thinking this is going to need a few different modules, like one for the main base, one for the holes, one for the pin areas, and one for the TFT area itself. Does this make sense?

I think I'd prefer that you not use external libraries, and instead write out the modules.

[Assistant]
TFTSupport.scad:
```
/* [ TFT Base Size] */
//Base Width
$display_w = 120;
//Base Height
$display_h = 56;

/* [ TFT Screen Size] */
//TFT Width must be less than Width Hole
$TFT_w = 62;
//TFT Height
$TFT_h = 36;
//Thickness // Min 5
$TFT_thickness = 5;

/* [ Holes Define ] */
//Width distance between Holes
$width_hole = 60;
//Height distance between TFT Holes
$height_hole = 30;
//Height distance between External Holes
$height_outhole = 44;
//Distance from sides
$distance_outhole = 8;
//Thickness holes distance
$hole_thickness = 5;

//Internal Metric Hole diameter
$m = 3;
//External Hole diameter
$extd = 5.4;

/* [ Pin Holes ] */
//Left Pin Holes Distance from TFT
$pinLeft_d = 3.3;
//Right Pin Holes Distance from TFT
$pinRight_d = 5.5;
//Height Left Wire
$pinLeft_h = 13;
//Height Right Wire
$pinRight_h = 40;
//Thickness for Wire Holes
$pin_e = 3.5;

/* [Hidden] */
$m3 = $m;
$fn=20;

//Height distance between TFT Holes
$hole_h = $height_hole;
//$hole_h = (($height_hole > $TFT_h)?($height_hole): ($TFT_h + $hole_extd));
//Height distance between External Holes
$hole_sh = $height_outhole;
//$hole_sh = (($height_outhole > $TFT_h)?($height_outhole): ($TFT_h + $hole_extd));
//Distance from sides
$hole_sd = ( $distance_outhole > ($display_w-$TFT_w)/2)? 4: $distance_outhole;
//Thickness holes distance
$hole_s = $hole_thickness ;
$hole_extd = (($extd > $m)? $extd: $m + 2.4 );

$hole_w = (($width_hole > $TFT_w)?($width_hole): ($TFT_w + $hole_extd));

$base_h = (($display_h < $TFT_h)? ($TFT_h+20): $display_h);
$base_w = (($display_w < $TFT_w)?ceil((($TFT_w+2*$hole_sd+20)/8)*8):(ceil($display_w/8)*8));

$rm = 2;
$hm = 2*$rm;

$TFT_thick = ($TFT_thickness < 5)? 5:$TFT_thickness;
$TFT_e  = $TFT_thick - $hm/2-$rm;
$hole_height = $hole_s+$TFT_e;

//Hole for support
$hole_sw = $base_w-2*$hole_sd;

//TFT Base
tftbase();

module tftbase(){
    difference (){
        pinbase();
    for(i = [ [  $hole_w/2,  $hole_h/2,   0],
           [ $hole_w/2, -$hole_h/2,0],
           [-$hole_w/2, $hole_h/2,  0],
           [ -$hole_w/2, -$hole_h/2,  0],
            [ $hole_sw/2,  $hole_sh/2,   0],
           [ $hole_sw/2, -$hole_sh/2,0],
           [-$hole_sw/2, $hole_sh/2,  0],
           [ -$hole_sw/2, -$hole_sh/2,  0] ])
{
    translate(i){
        translate([0,0,$hole_s/2+$TFT_thick])
        cylinder(h = $hole_height+2*$TFT_thick, d = $m3 , center = true );
    }
}
        }
}

module pinbase(){
    union(){

        tftpins();
        pinholes();
    }
}
module pinholes(){
for(i = [ [  $hole_w/2,  $hole_h/2,   0],
           [ $hole_w/2, -$hole_h/2,0],
           [-$hole_w/2, $hole_h/2,  0],
           [ -$hole_w/2, -$hole_h/2,  0],
            [ $hole_sw/2,  $hole_sh/2,   0],
           [ $hole_sw/2, -$hole_sh/2,0],
           [-$hole_sw/2, $hole_sh/2,  0],
           [ -$hole_sw/2, -$hole_sh/2,  0] ])
{
    translate(i){
        translate([0,0,$hole_s/2+$TFT_thick])
        cylinder(h = $hole_s, d = $hole_extd , center = true );
    }
}
}

//TFT with pins space
module tftpins(){
difference(){
    tftsupport();
    if($pinLeft_d != 0){
        translate([-$TFT_w/2-$pinLeft_d-$pin_e,-$pinLeft_h/2,0])
        cube(size = [$pin_e,$pinLeft_h,$hole_thickness ]);
    }
    if($pinRight_d != 0){
        translate([$TFT_w/2+$pinRight_d,-$pinRight_h/2,0])
        cube(size = [$pin_e,$pinRight_h,$hole_thickness ]);
    }
}
}
module tftsupport(){
difference(){
    translate([0,0,$TFT_e/2])
    cubekowski();
    translate([0,0,$TFT_thick/2])
    cube(size = [$TFT_w,$TFT_h,$TFT_thick], center = true);
}
}
module cubekowski(){
    minkowski()
    {
      cube(size = [$base_w-2*$rm,$base_h-2*$rm,$TFT_e], center = true);
      rcylinder(r=$rm,h=$hm);
    }
}

module rcylinder(r = 4,
                 h = 20,
                 center = false,
                 both = false, $fn = 30)
{

  hc = (both == true) ? h - 2 * r : h - r;
  posc = (center == true) ? 0 : h/2;

  translate([0, 0, posc])

    if (both == true) {
      cylinder(r = r, h = hc, center = true, $fn = $fn);
      for (i = [-1, 1])
        translate([0, 0, i * hc / 2])
          sphere(r = r);

    }
    else
      translate([0, 0, -h/2]) {

        cylinder(r = r, h = hc, $fn = $fn);
          translate([0, 0, hc]) sphere(r = r, $fn = $fn);
      }

}
```


[User]
I'd like a simple OpenSCAD design that demonstrates how to display the OpenSCAD version, preview mode, and a custom number. The design should use the `text()` function to show each of these on separate lines. I need the following:

1.  The first line of text should display "version = " followed by the result of the `version()` function.
2.  The second line should show "$preview = " followed by the boolean value of `$preview`. It should be translated 15 units in the y direction from the first line.
3.  The third line should display "my number = " followed by the value of a parameter named `number`. The default value for this parameter should be 10 and it should have a range from 1 to 100 using the `[1:100]` syntax. This line should be translated 30 units in the y direction from the first line.

I'm not looking for anything fancy, just a way to see those values printed out.

[Assistant]
version.scad:
```
/* test number */
number = 10; // [1:100]

text(str("version = ", version()));
translate([0, 15])
text(str("$preview = ", $preview));
translate([0, 30])
text(str("my number = ", number));
```


[User]
I'm looking to design a hex key holder for my Ikea Skadis pegboard. I'd like it to be customizable, so I can adjust it for different size hex keys.

Here's what I'm envisioning:

*   **Hex Key Sizes:** The holder should be able to accommodate a range of hex key sizes. I'd like to be able to specify these sizes in a list. For example: `sizes = [4, 3, 2.5, 2, 1.5]`.
*   **Hole Spacing:** There should be some extra space around each hex key within its hole. I need to be able to define this spacing with a variable. Let's call it `spacing`. Something like `spacing = 0.5` should be good.
*   **Padding:** I want to control the space between each hex key hole. I'd like a `padding` variable for that, maybe `padding = 7`.
*   **Height:** The main body of the holder should have a defined `height`, for instance, `height = 20`.
*   **Rounded Corners:** The holder should have rounded corners, and I'd like to control that with a `radius` variable (e.g., `radius = 4`).
*   **Skadis Mount:** It needs an integrated Skadis mount on the back so I can attach it to my pegboard. I'd like to be able to adjust the number of hooks that this mount has, but I'd like to be able to specify that I only want the hooks, not any of the extra base plating. I'd like to be able to specify that the base should be excluded from the mounting piece.
*   **Parametric Design:** Everything should be controlled by variables, so I can easily change the sizes and spacing later.
*   **Clearance:** I need the holes to be made with a cylinder subtraction with sufficient depth so that the hex keys can be pushed all the way through without hitting the back face.

Can you generate an OpenSCAD file that will let me do that?

I'd also like to have a second OpenSCAD file that contains the `Right_Angled_Triangle`, `Triangle`, `Isosceles_Triangle`, `Wedge`, `Equilateral_Triangle`, and `Trapezoid` modules that I can then include into other OpenSCAD designs.

I’m not using any external libraries.

[Assistant]
hex_mount.scad:
```
// Hex key sizes (large to small)
sizes = [4, 3, 2.5, 2, 1.5];
// Extra space in hole around hex key
spacing = 0.5;
// Space between hex keys
padding = 7;
// Height of the holder
height = 20;
// Radius of the rounded corners
radius = 4;

function add(v, i = 0, r = 0) = i < len(v) ? add(v, i + 1, r + v[i]) : r;
function addSub(v, count, i = 0, r = 0) = i < count ? addSub(v, count, i + 1, r + v[i]) : r;

module SlopedCube(size, radius = 0) {
	union() {
		cube([size[0], radius, size[3]]);
		translate([radius, radius])
			minkowski() {
				union() {
					cube([size[0] - radius * 2, size[2] - radius * 2, size[3]]);
					translate([0, size[2] - radius * 2])
						Right_Angled_Triangle(size[1] - size[2], size[0] - radius * 2, size[3]);
				}
				cylinder(r = radius, h = 0.01);
			}
	}
}

module Mount() {
	$fn = 50;
	count = len(sizes);
	mountWidth = 45;
	width = (padding + spacing * 2) * count + add(sizes);
	translate([-width / 2, 0, 0])
		rotate([90])
			union() {
				translate([0, 21])
					rotate([90, 0, 0])
						difference() {
							SlopedCube([width, padding + max(sizes), padding + min(sizes), height], radius);
							for(i = [0: len(sizes) - 1]) {
								size = sizes[i];
								union() {
									translate([padding * i + addSub(sizes, i) + padding, padding / 2 + size / 2, -1])
										cylinder(r = size / 2 + spacing, h = 50);
									translate([padding * i + addSub(sizes, i) + padding,  padding + max(sizes) + size * 0.45, 3])
										rotate([90, 0, 0])
											cylinder(r = size / 2 + spacing, h = padding);
									translate([padding * i + addSub(sizes, i) + padding - size / 2 - spacing, padding / 2 + size / 2, -1])
										cube([size + spacing * 2, 20, 4]);
								}
							}
						}
				translate([(width - mountWidth) / 2, 10 - height / 2, 0.5])
					SkadisMount(count = 2, basePlate = false);
			}
}

Mount();

//-------------

function skadisMountWidth(count = 2) = count * 5 + (count - 1) * 35;

module SkadisMount(count = 2, overhang = 10, overhangHeight = 5, height = 1, basePlate = true, grid = true, hookDepth = 6) {
	holeSpacing = 35;
	holeVericalSpacing = 25;
	union() {
		if (basePlate)
			cube(size = [skadisMountWidth(count), overhang + 4 + (holeVericalSpacing * height), overhangHeight]);
		for (i = [0: (grid ? 1 : count - 1) : count - 1]) {
			for (j = [0: (grid ? 1 : height - 1) : height - 1]) {
				translate([i * (holeSpacing + 5), overhang + (holeVericalSpacing + 15) * j, -10])
					SkadisHook(hookDepth);
			}
		}
	}
}

module SkadisHook(hookDepth = 6) {
	rotate([90, 0 ,0])
		translate([0.5, 6 - hookDepth, 0])
			union() {
				translate([0, 0, -4])
					union() {
						RoundBox(size=[4, 10, 4], radius = 1);
						translate([0, hookDepth, 0])
							cube(size=[4,4,4]);
					}
				RoundBox(size=[4,4,5], radius = 1);
			}
}

module RoundBox(size, radius) {
	translate([radius, radius, 0])
		minkowski() {
			cube(size=[size[0] - radius * 2,size[1] - radius * 2, size[2]]);
			cylinder(r=radius, h=0.01);
		}
}

//------------

/*
Triangles.scad
 Author: Tim Koopman
 https://github.com/tkoopman/Delta-Diamond/blob/master/OpenSCAD/Triangles.scad

         angleCA
           /|\
        a / H \ c
         /  |  \
 angleAB ------- angleBC
            b

Standard Parameters
	center: true/false
		If true same as centerXYZ = [true, true, true]

	centerXYZ: Vector of 3 true/false values [CenterX, CenterY, CenterZ]
		center must be left undef

	height: The 3D height of the Triangle. Ignored if heights defined

	heights: Vector of 3 height values heights @ [angleAB, angleBC, angleCA]
		If CenterZ is true each height will be centered individually, this means
		the shape will be different depending on CenterZ. Most times you will want
		CenterZ to be true to get the shape most people want.
*/

/*
Triangle
	a: Length of side a
	b: Length of side b
	angle: angle at point angleAB
*/
module Triangle(
			a, b, angle, height=1, heights=undef,
			center=undef, centerXYZ=[false,false,false])
{
	// Calculate Heights at each point
	heightAB = ((heights==undef) ? height : heights[0])/2;
	heightBC = ((heights==undef) ? height : heights[1])/2;
	heightCA = ((heights==undef) ? height : heights[2])/2;
	centerZ = (center || (center==undef && centerXYZ[2]))?0:max(heightAB,heightBC,heightCA);

	// Calculate Offsets for centering
	offsetX = (center || (center==undef && centerXYZ[0]))?((cos(angle)*a)+b)/3:0;
	offsetY = (center || (center==undef && centerXYZ[1]))?(sin(angle)*a)/3:0;

	pointAB1 = [-offsetX,-offsetY, centerZ-heightAB];
	pointAB2 = [-offsetX,-offsetY, centerZ+heightAB];
	pointBC1 = [b-offsetX,-offsetY, centerZ-heightBC];
	pointBC2 = [b-offsetX,-offsetY, centerZ+heightBC];
	pointCA1 = [(cos(angle)*a)-offsetX,(sin(angle)*a)-offsetY, centerZ-heightCA];
	pointCA2 = [(cos(angle)*a)-offsetX,(sin(angle)*a)-offsetY, centerZ+heightCA];

	polyhedron(
		points=[	pointAB1, pointBC1, pointCA1,
					pointAB2, pointBC2, pointCA2 ],
		triangles=[
			[0, 1, 2],
			[3, 5, 4],
			[0, 3, 1],
			[1, 3, 4],
			[1, 4, 2],
			[2, 4, 5],
			[2, 5, 0],
			[0, 5, 3] ] );
}

/*
Isosceles Triangle
	Exactly 2 of the following paramaters must be defined.
	If all 3 defined H will be ignored.
	b: length of side b
	angle: angle at points angleAB & angleBC.
*/
module Isosceles_Triangle(
			b, angle, H=undef, height=1, heights=undef,
			center=undef, centerXYZ=[true, false, false])
{
	valid = 	(angle!=undef)?((angle < 90) && (b!=undef||H!=undef)) : (b!=undef&&H!=undef);
	ANGLE = (angle!=undef) ? angle : atan(H / (b/2));
	a = (b==undef)?(H/sin((180-(angle*2))/2)) :
		 (b / cos(ANGLE))/2;
	B = (b==undef)? (cos(angle)*a)*2:b;
	if (valid)
	{
		Triangle(a=a, b=B, angle=ANGLE, height=height, heights=heights,
					center=center, centerXYZ=centerXYZ);
	} else {
		echo("Invalid Isosceles_Triangle. Must specify any 2 of b, angle and H, and if angle used angle must be less than 90");
	}
}

/*
Right Angled Triangle
	Create a Right Angled Triangle where the hypotenuse will be calculated.

       |\
      a| \
       |  \
       ----
         b
	a: length of side a
	b: length of side b
*/
module Right_Angled_Triangle(
			a, b, height=1, heights=undef,
			center=undef, centerXYZ=[false, false, false])
{
	Triangle(a=a, b=b, angle=90, height=height, heights=heights,
				center=center, centerXYZ=centerXYZ);
}

/*
Wedge
	Is same as Right Angled Triangle with 2 different heights, and rotated.
	Good for creating support structures.
*/
module Wedge(a, b, w1, w2)
{
	rotate([90,0,0])
		Right_Angled_Triangle(a, b, heights=[w1, w2, w1], centerXYZ=[false, false, true]);
}

/*
Equilateral Triangle
	Create a Equilateral Triangle.

	l: Length of all sides (a, b & c)
	H: Triangle size will be based on the this 2D height
		When using H, l is ignored.
*/
module Equilateral_Triangle(
			l=10, H=undef, height=1, heights=undef,
			center=undef, centerXYZ=[true,false,false])
{
	L = (H==undef)?l:H/sin(60);
	Triangle(a=L,b=L,angle=60,height=height, heights=heights,
				center=center, centerXYZ=centerXYZ);
}

/*
Trapezoid
	Create a Basic Trapezoid (Based on Isosceles_Triangle)

            d
          /----\
         /  |   \
     a  /   H    \ c
       /    |     \
 angle ------------ angle
            b

	b: Length of side b
	angle: Angle at points angleAB & angleBC
	H: The 2D height at which the triangle should be cut to create the trapezoid
	heights: If vector of size 3 (Standard for triangles) both cd & da will be the same height, if vector have 4 values [ab,bc,cd,da] than each point can have different heights.
*/
module Trapezoid(
			b, angle=60, H, height=1, heights=undef,
			center=undef, centerXYZ=[true,false,false])
{
	validAngle = (angle < 90);
	adX = H / tan(angle);

	// Calculate Heights at each point
	heightAB = ((heights==undef) ? height : heights[0])/2;
	heightBC = ((heights==undef) ? height : heights[1])/2;
	heightCD = ((heights==undef) ? height : heights[2])/2;
	heightDA = ((heights==undef) ? height : ((len(heights) > 3)?heights[3]:heights[2]))/2;

	// Centers
	centerX = (center || (center==undef && centerXYZ[0]))?0:b/2;
	centerY = (center || (center==undef && centerXYZ[1]))?0:H/2;
	centerZ = (center || (center==undef && centerXYZ[2]))?0:max(heightAB,heightBC,heightCD,heightDA);

	// Points
	y = H/2;
	bx = b/2;
	dx = (b-(adX*2))/2;

	pointAB1 = [centerX-bx, centerY-y, centerZ-heightAB];
	pointAB2 = [centerX-bx, centerY-y, centerZ+heightAB];
	pointBC1 = [centerX+bx, centerY-y, centerZ-heightBC];
	pointBC2 = [centerX+bx, centerY-y, centerZ+heightBC];
	pointCD1 = [centerX+dx, centerY+y, centerZ-heightCD];
	pointCD2 = [centerX+dx, centerY+y, centerZ+heightCD];
	pointDA1 = [centerX-dx, centerY+y, centerZ-heightDA];
	pointDA2 = [centerX-dx, centerY+y, centerZ+heightDA];

	validH = (adX < b/2);

	if (validAngle && validH)
	{
		polyhedron(
			points=[	pointAB1, pointBC1, pointCD1, pointDA1,
						pointAB2, pointBC2, pointCD2, pointDA2 ],
			triangles=[
				[0, 1, 2],
				[0, 2, 3],
				[4, 6, 5],
				[4, 7, 6],
				[0, 4, 1],
				[1, 4, 5],
				[1, 5, 2],
				[2, 5, 6],
				[2, 6, 3],
				[3, 6, 7],
				[3, 7, 0],
				[0, 7, 4]	] );
	} else {
		if (!validAngle) echo("Trapezoid invalid, angle must be less than 90");
		else echo("Trapezoid invalid, H is larger than triangle");
	}
}

```