[User]
I'm looking for an OpenSCAD design for a customizable cable holder, and I need it to have an integrated spade connector. The design should be parametric so I can easily adjust the dimensions to fit various cable sizes and mounting needs.

Here are the key features I'm thinking about:

*   **Cable Holder:**
    *   The holder should be essentially a ring, with adjustable inner and outer diameters, and ring thickness.
    *   I need to be able to specify the width of the gap in the ring – the split.
    *   The holder's center point should be offset from the base of the holder, with that offset being adjustable.
    *   The holder can be rotated to be on top, middle or bottom.
    *   It should have a thickness, which is also adjustable.

*   **Spade Connector:**
    *   The spade connector should be integrated with the cable holder.
    *   It should have its own inner diameter and edge width, all adjustable.
    *   The thickness of the spade should also be a configurable parameter.
    *   Its center point should also have an adjustable offset from the back of the holder.

*   **General:**
    *   I'd like to set the `$fn` value for the circle resolution.
    *   I'll need to specify a tolerance value for the design.

I need the following parameters to be configurable:
*   `$fn` (number of fragments for circles)
*   `tol` (tolerance for fitting)
*   `h_in_dia` (holder inner diameter)
*   `h_ring_wid` (holder ring width)
*    `h_ring_thi` (holder ring thickness)
*   `cus_h_thi` (holder thickness)
*   `cus_h_offset` (holder center offset from base)
*   `h_rot` (holder rotation: 0=middle, 1=top, 2=bottom)
*   `cus_h_split_wid` (holder split width)
*   `s_in_dia` (spade inner diameter)
*   `s_edge_wid` (spade edge width)
*   `s_thi` (spade thickness)
*   `cus_s_offset` (spade center offset from back of holder)

Please provide a parametric OpenSCAD file, or set of files if needed, that allows for these adjustments. I don't need any external libraries; keep it simple and self-contained.

[Assistant]
CableHolder.scad:
```
////CableHolder+spade.scad
////OpenSCAD 2015.03-2
////Kijja Chaovanakij
////2019.10.27

/*[var]*/
//number of fragments[40=low,60=medium,90=high]
$fn=90;
//tolerance[0.2]
tol=0.2;

/*[cable holder var]*/
//holder inner diameter[10]
h_in_dia=10; //[5:0.2:50]
//holder ring width[2.4]
h_ring_wid=2.4; //[1.8:0.2:8]
//holder ring thickness[2.4]
h_ring_thi=6.4;
//holder thickness[2.4]
cus_h_thi=10.4; //[2:0.5:50]
//holder center offset from base[24]
cus_h_offset=15;
//holder rotatation
h_rot=1; //[0:middle,1:top,2:bottom]
//holder split width[2.4]
cus_h_split_wid=7.4;

/*[spade var]*/
//spade inner diameter[4]
s_in_dia=4;
//spade edge width[3.2]
s_edge_wid=3.2;
//spade thickness[1.8]
s_thi=3.8;
//spade center offset from back of holder[12]
cus_s_offset=13;

////translate var
h_out_dia=h_in_dia+h_ring_wid*2;
  echo("h_out_dia=",h_out_dia);
s_out_dia=s_in_dia+s_edge_wid*2;
  echo("s_out_dia=",s_out_dia);
h_offset=max(cus_h_offset,h_out_dia/2+s_thi);
  echo("h_offset=",h_offset);
s_offset=max(cus_s_offset,s_out_dia/2+h_in_dia/2+h_ring_wid);
  echo("s_offset=",s_offset);
min_h_thi=max(cus_h_thi,h_ring_thi/2);
h_thi=min(min_h_thi,s_out_dia);
  echo("h_thi=",h_thi);
h_split_wid=min(h_in_dia,cus_h_split_wid);
  echo("h_split_wid=",h_split_wid);
cham_size=(h_out_dia-s_out_dia)/2;
  echo("cham_size=",cham_size);

////main
if (h_rot==0){
  spade();
  holder();
  linear_extrude(s_thi){
    translate([-h_thi,s_out_dia/2,0])
      rotate([0,0,90])
        chamfer();
    translate([-h_thi,-s_out_dia/2,0])
      rotate([0,0,180])
        chamfer();
  }//l
}//i
if (h_rot==1){
  spade();
  translate([0,s_out_dia/2,0])
    rotate(90)
      holder();
  linear_extrude(s_thi){
    difference(){
      square([h_out_dia,s_out_dia],true);
      translate([h_out_dia/2,-s_out_dia/2,0])
        rotate([0,0,90])
          chamfer();
    }//d
  }//l
}//i
if (h_rot==2){
  spade();
  translate([0,-s_out_dia/2,0])
    rotate(-90)
      holder();
  linear_extrude(s_thi){
    difference(){
      square([h_out_dia,s_out_dia],true);
      translate([h_out_dia/2,s_out_dia/2,0])
        rotate([0,0,180])
          chamfer();
    }//d
  }//l
}//i
//

module spade(){
linear_extrude(s_thi)
difference(){
  hull(){
    translate([-s_offset/2,0,0])
      square([s_offset,s_out_dia],true);
    translate([-s_offset,0,0])
      circle(d=s_out_dia);
  }//h
  translate([-s_offset,0,0])
    circle(d=s_in_dia+tol);
  translate([-(s_offset+s_out_dia/4),0,0])
    square([s_out_dia/2,s_in_dia+tol],true);
}//d
}//m
//

module holder(){
rotate([0,-90,0]){
  color("yellow")
  difference(){
    linear_extrude(h_ring_thi)
      union(){
        translate([h_offset,0,0])
          circle(d=h_out_dia);
        translate([h_offset-h_out_dia/4,0,0])
          square([h_out_dia/2,h_out_dia],true);
      }//u
    translate([h_offset,0,-0.05])
      linear_extrude(h_ring_thi+0.1)
        circle(d=h_in_dia+tol);
    translate([h_offset+h_out_dia/2,0,-0.05])
      linear_extrude(h_ring_thi+0.1)
        square([h_out_dia,h_split_wid],true);
  }//d

  if (h_offset-h_out_dia/2-h_thi<=0){
    color("pink")
    hull(){
      translate([h_offset-h_out_dia/2,0,0])
        linear_extrude(h_ring_thi)
          square([0.01,h_out_dia],true);
      translate([s_thi,0,0])
        linear_extrude(h_thi)
          square([0.01,h_out_dia],true);
    }//h
    translate([s_thi/2,0,0])
      linear_extrude(h_thi)
        square([s_thi,h_out_dia],true);
  }//i

  if (h_offset-h_out_dia/2-h_thi>0){
    color("pink")
    hull(){
      translate([h_offset-h_out_dia/2,0,0])
        linear_extrude(h_ring_thi)
          square([0.01,h_out_dia],true);
      translate([h_offset-h_out_dia/2-h_thi,0,0])
        linear_extrude(h_thi)
          square([0.01,h_out_dia],true);
    }//h
    translate([(h_offset-h_out_dia/2-h_thi)/2,0,0])
      linear_extrude(h_thi)
        square([h_offset-h_out_dia/2-h_thi,h_out_dia],true);
  }//i
}//r
}//m
//

module chamfer(){
difference(){
square([cham_size,cham_size]);
translate([cham_size,cham_size,0])
  circle(d=cham_size*2);
}//d
}//m
```


[User]
I'm looking to design some handwheels for T8 threaded rods, similar to what you'd find on a lathe or milling machine. The key feature I need is for them to automatically disengage when not being actively turned, providing that "clicky" feedback. I've got a basic idea of the components, but I'd like a parametric OpenSCAD design that allows me to easily adjust the key dimensions.

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

*   **Overall Structure:**  The handwheel will consist of several interconnected parts: a fixed side, a mobile (rotating) side, a handle, a locking mechanism, and an end stop. There should also be some sort of spring element to push the two sides together, and create the desired resistance/feedback.
*   **Fixed Side:** This will be a relatively simple cylinder, with a locking mechanism integrated on one end and screw holes for mounting it to something. I'd like to control the overall diameter, cylinder height, locking mechanism depth and inner diameter as parameters. The inner diameter must be able to pass a T8 rod.
*   **Mobile Side:** This part will have a central hole for the T8 rod as well as an offset location for the handle and a locking mechanism which fits with the fixed side, as well as holes for the screws. I need to be able to control the main body diameter, the offset distance for the handle, and the diameter and height of the central hole.
*   **Locking Mechanism:** This will be a key feature, allowing the mobile side to rotate until the engagement is broken. It should be a series of wedges that mesh together, and have a configurable outer and inner diameter. I need to parameterize the number of wedges, and their angle (to control the feel of the click).
*  **End Stop**: I need a piece that can fit against the rotating part with a hole to secure it with screws. I need to control the overall diameter, height, and hole diameter.
*   **Spring:**  This element needs to be flexible and strong enough to push the rotating and fixed parts together, but also allow for disengagement with some small force. The spring should be adjustable in diameter, wire thickness and stiffness.
*   **Handle:** This will attach to the mobile side and act as the interface for turning the wheel. I'd like a simple cylindrical handle with a rounded end. The handle should be adjustable in length and diameter.
*   **Screws**: All screw holes should accept an M4 screw.

I'd like the design to be parametric using OpenSCAD, so I can modify:

*   All the diameters, heights, and offset distances I mentioned above
*   Number and angle of the wedges in the locking mechanism
*   Length and diameter of the handle
*   Spring properties: inner/outer diameter, wire thickness, length, number of coils
*   Screw hole sizes (for example, M3, M4, or M5, etc)

I'm not worried about having the screw holes pre-threaded, but I need to easily be able to force thread the holes for an M4. The whole thing should be fairly easy to assemble once 3D printed.

I'm not sure what libraries to use here, but I'd be grateful if you could include anything you think would be useful in your response.

[Assistant]
hand_wheels.scad:
```
handle_l = 30;
handle_d = 40;
screw_d = 3.5;

module handle(){
  $fn = 40;
  difference(){
	hull(){
	  cylinder(d = 8, h = 1);
	  translate([0,0,handle_l])sphere(d = 15);
	}
	cylinder(d = screw_d, h = 10);
  }
}
module pie_slice(r=3.0,a=30) {
  intersection() {
    circle(r=r);
    square(r);
    rotate(a-90)square(r);
  }
}

module lock(OD, ID){
  $fn = 40;
  difference(){
	for(a = [0:360/5:360]){
	  rotate([0,0,a-360/20])linear_extrude(height = 5)pie_slice(r = OD/2, a=360/10 - 2);
	}
	translate([0,0,4.6])for(a = [0:360/5:360]){
	  rotate([0,0,a-360/10-2])hull(){
		translate([0,0,0])rotate([45,0,0])cube([1,2,2]);
		translate([10,0,-3.8])rotate([45,0,0])cube([1,12,12]);
	  }
	}
	cylinder(d = ID, h = 6);
  }

}
module end_stop(){
  $fn = 40;
  difference(){
	union(){
	  cylinder(d2 = 20, d1 = 18, h = 2);
	  translate([0,0,2])cylinder(d = 20, h = 6);
	  translate([0,0,8])cylinder(d1 = 20, d2 = 18, h = 2);

	}
	cylinder(d = 8, h = 20);
	translate([0,0,5]){
	  rotate([0,90,0])cylinder(d = screw_d, h = 20);
	  rotate([0,-90,0])cylinder(d = screw_d, h = 20);
	}
  }

}

module fixed_side(){
  $fn = 40;
  difference(){
	union(){
	  cylinder(d = 20, h = 10);
	  translate([0,0,10])lock(16, 8.4);
	}
	cylinder(d = 8, h = 20);
	translate([0,0,5]){
	  rotate([0,90,0])cylinder(d = screw_d, h = 20);
	  rotate([0,-90,0])cylinder(d = screw_d, h = 20);
	}
  }

}
module mobile_side(){
  $fn = 40;
  difference(){
	union(){
	  hull(){
		cylinder(d = 20, h = 10);
		translate([0,handle_d, 0])cylinder(d = 8, h = 10);
	  }
	  translate([0,0,10])lock(16, 8.5);
	}
	cylinder(d = 8.5, h = 20);
	translate([0,handle_d, 0])cylinder(d = screw_d, h = 10);

  }

}
module spring(){
  $fn=80;
  difference(){
	union(){
	  translate([-13,0,6])rotate([0,90,0])difference(){
		linear_extrude(height = 26)scale([1, 4])circle(r = 6);
		linear_extrude(height = 27)scale([1, 4.4])circle(r = 5.2);
	  }
	  translate([-13,-10,0])cube([26,20,1]);
	  translate([-13,-10,11])cube([26,20,1]);

	}
	cylinder(d = 17, h = 50);
  }
}

fixed_side();
translate([0,0,10.5])spring();
translate([0,0,33])rotate([0,180,0])mobile_side();
translate([0,handle_d,33.5])handle();
translate([0,0,33.5])end_stop();

```


[User]
Okay, I'm looking to create a customizable pegboard system using OpenSCAD. I'd like to be able to generate both the pegboard panels themselves and also various types of connecting braces, all from the same script or set of scripts.

Here's what I'm envisioning for the pegboard panels:

*   **Panel Size:** I need to be able to specify the overall size of the panel (square for now, let's say), like 200mm, but adjustable.
*   **Panel Thickness:** The thickness of the panel should be adjustable too; I want it to be a solid piece, for instance 5mm.
*   **Hole Size:** The diameter of the peg holes should be adjustable, say 6mm by default.
*   **Hole Spacing:** I want to set the distance between hole centers, like 25mm by default.
*   **Mounting Options:** I need mounting tabs that will allow screw holes to secure to a wall, maybe with mounting tabs on both sides and top and bottom to screw to the wall. I need to be able to toggle these tabs on and off, control how many I want per side and adjust their dimensions (width, length, and height). And I'd like the screw hole size to be adjustable.
*   **Brace Toggle:** if mounting tabs are not used, then we need a way of connecting the panels to each other.

For the Braces, I need to generate the following:
    *   **Dual Brace:** Two mounting points, one on each side of the brace.
    *   **Quad Brace:** Two pairs of mounting points for connecting four pegboards together on one corner.
    *   **Diagonal Brace:** Diagonal brace to connect opposite corners.
*   **Brace Thickness:** I should be able to control the thickness of the brace.
*   **Brace Offset:** I want to be able to set how far the brace extends outwards from the peg hole edges, to make it a bit beefier.
*   **Snap Thickness:** the snap thickness for all braces for better grip.
*   **Screw Size:** I need to use the same screw size setting for mounting and braces.
*   **Tolerance:** An adjustable tolerance parameter to account for printer tolerances is needed.

The code should generate either the panels *or* the braces based on a parameter, I'm thinking a variable called `Render` (0 for panels, 1 for braces). The braces should be designed to slot into the peg holes and also allow screws to secure them together.

I don't need any special libraries here, just base OpenSCAD. Let me know if I need to clarify anything.

[Assistant]
Pegboard_Panels.scad:
```
//What to Render
Render = 0; //[0:Panel,1:Brace]
//panel base Size
PanelSize = 200;
//Thickness of the Panel
PanelThick = 5;

//Hole Size in mm
HoleSize = 6;
//Hole Spacing center to center
Spacing = 25;
HoleCount = PanelSize/Spacing;

//Mounting related

//Turn off if you want to use braces to connect your panels. You can turn this on but may interfere with mounting the brace. Turn MountCount down to ensure clearance
Mounting = 0; //[1:Yes,0:No]
MountWidth = 10;
MountLength = 3;
MountHeight = 10;
MountCount = 4;
//Set to what screws that you're using. Tolerance not accounted in this. Shared with Braces Parameter.
ScrewSize = 3;

//Brace related if mounting pegs not used
//Dual or Quad screw mounting
BraceType = 1; //[0:Dual,1:Quad,2:Diagonal]
//Thickness of brace bars
BraceThick = 2;
//Offset of the bar aka chamfers
BraceOffset = 2;
SnapThick = PanelThick/2;

//Change according to your printer's spec
Tolerance = 0.2;

module PegHole(){
color("green")
    for(i = [0:(HoleCount-1)],j = [0:(HoleCount-1)])
    {
        translate([-(i*Spacing),-(j*Spacing),0])translate([(PanelSize/2)-(Spacing/2),(PanelSize/2)-(Spacing/2),0]) cylinder(PanelThick+2,d=HoleSize, center = true,$fn = 50);
    }
}

module Mounting(){

    for(k = [1:(MountCount)])
    {
        translate([(k*((PanelSize/1)/(MountCount/1))-(PanelSize/2)+(Tolerance/2))-(PanelSize/MountCount/2),-(MountLength/2)+(PanelSize/2)-(Tolerance/2),(PanelThick/2)+(MountHeight/2)])
    {
        difference(){
            cube([MountWidth,MountLength,MountHeight],true);
            rotate([90,0,0]) color ("gold")cylinder(h=10, d= ScrewSize, center = true, $fn= 50);
        }
    }
    //echo (k*((PanelSize/1)/MountCount));

        translate([(MountLength/2)-(PanelSize/2)+(Tolerance/2),-(k*((PanelSize/1)/(MountCount/1))-(PanelSize/2)+(Tolerance/2))+(PanelSize/MountCount/2),(PanelThick/2)+(MountHeight/2)])
        {
        difference(){
                rotate([0,0,90])cube([MountWidth,MountLength,MountHeight],true);
                rotate([0,90,0]) color ("gold")cylinder(h=10, d= ScrewSize, center = true, $fn= 50);
            }
        }
    }
}

module DualBrace(){
    difference()
    {
        union()
        {
//			echo(-(SnapThick+(BraceThick/2)-SnapThick/2));
            translate([0,0,-(SnapThick+BraceThick/2-SnapThick/2)])

                hull(){

                translate([Spacing/2,0,0])cylinder(h=BraceThick,d1 = HoleSize,d2 = (HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
                translate([-Spacing/2,0,0])cylinder(h=BraceThick,d1 = HoleSize,d2=(HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
                }
                translate([Spacing/2,0,0])cylinder(h=SnapThick,d=HoleSize-Tolerance, center = true, $fn = 50);
                translate([-Spacing/2,0,0])cylinder(h=SnapThick,d=HoleSize-Tolerance, center = true, $fn = 50);
        }
            translate([Spacing/2,0,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
            translate([-Spacing/2,0,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);

    }
}

module QuadBrace(){
    translate([0,Spacing/2,0])DualBrace();
	translate([0,-Spacing/2,0])DualBrace();

	rotate([0,0,90])
	{
		translate([0,Spacing/2,0])DualBrace();
	translate([0,-Spacing/2,0])DualBrace();
	}

	translate([0,0,-(SnapThick+BraceThick/2-SnapThick/2)])
	difference(){
		hull(){

					translate([Spacing/2,Spacing/2,0])cylinder(h=BraceThick,d1 = HoleSize-Tolerance,d2 = (HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
					translate([-Spacing/2,-Spacing/2,0])cylinder(h=BraceThick,d1 = HoleSize-Tolerance,d2=(HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
					}

		translate([Spacing/2,Spacing/2,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
		translate([-Spacing/2,-Spacing/2,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
				}

	translate([0,0,-(SnapThick+BraceThick/2-SnapThick/2)])
	rotate([0,0,90])
				difference(){
		hull(){

					translate([Spacing/2,Spacing/2,0])cylinder(h=BraceThick,d1 = HoleSize-Tolerance,d2 = (HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
					translate([-Spacing/2,-Spacing/2,0])cylinder(h=BraceThick,d1 = HoleSize-Tolerance,d2=(HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
					}

		translate([Spacing/2,Spacing/2,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
		translate([-Spacing/2,-Spacing/2,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
				}
}

module DiaBrace()
{
	difference(){
		union(){
			translate([0,0,-(SnapThick+BraceThick/2-SnapThick/2)])
			hull(){

					translate([Spacing/2,Spacing/2,0])cylinder(h=BraceThick,d1 = HoleSize-Tolerance,d2 = (HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
					translate([-Spacing/2,-Spacing/2,0])cylinder(h=BraceThick,d1 = HoleSize-Tolerance,d2=(HoleSize+BraceOffset)-Tolerance, center = true, $fn = 50);
				}
				translate([Spacing/2,Spacing/2,0])cylinder(h=SnapThick,d=HoleSize-Tolerance, center = true, $fn = 50);
                translate([-Spacing/2,-Spacing/2,0])cylinder(h=SnapThick,d=HoleSize-Tolerance, center = true, $fn = 50);
			}
		translate([Spacing/2,Spacing/2,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
		translate([-Spacing/2,-Spacing/2,-(PanelThick/2+BraceThick/2)])cylinder(h=PanelThick*4,d=ScrewSize, center = true, $fn = 50);
				}
}

if(Render == 0){
    difference()
	{
        color ("skyblue",0.50)cube([PanelSize-Tolerance,PanelSize-Tolerance,PanelThick], true);
        PegHole();
    }
    if(Mounting){
    Mounting();
    rotate([0,0,180])Mounting();
    }
}else
{
    if(BraceType == 0 )
    DualBrace();
    else if(BraceType == 1)
        QuadBrace();
	else if(BraceType == 2)
		DiaBrace();
}
```


[User]
I'm looking for an OpenSCAD design for a case for my Odroid-H2 (or H2+, H3, or H3+ - they all have the same board dimensions), and I'd like it to be parametric so I can customize it.

Here's what I need:

*   The case should be in two parts, a top and a bottom.
*   I want the option to include space for a 2.5" disk drive inside, below the mainboard. The height of the drive space should be adjustable, ranging from 0mm up to 15mm, with common sizes like 7mm, 9.5mm, 12.5mm being easy to select.
*   There should be mounting holes for the Odroid mainboard using M3 screws; I'd like to be able to set the screw hole diameter.
*   I also want screw holes for securing the top and bottom parts of the case together. Those screw diameters should be separately configurable, as I'll probably be using self-tapping screws.
*   It needs ventilation holes, and I like the look of honeycomb patterns.
*   I would like optional wall-mounting holes on the bottom.
*   A power button hole on the back panel of the case is required.
*   Optionally, a front cutout for the Odroid's status LEDs would be good.
*   Finally, the case should have the ports on the back easily accessible, such as the power, ethernet, USB, DP, HDMI, and audio jacks.

I'd like this to be easy to customize, so please make sure everything is configurable. I'm not super familiar with OpenSCAD, so I'd be grateful if you could keep the code relatively simple and well commented. I've seen some use of the `honeycomb.scad` library, which would be useful to include if possible.

[Assistant]
h2-case.scad:
```
/*
 * Configurable case for the Odroid-H2 and one 2.5" disk drive
 *
 * (c) 2019 Johannes Heimansberg
 * Licensed under the Creative Commons - Attribution license.
 * https://creativecommons.org/licenses/by/3.0/
 *
 * Version: 1.1
 *
 * Features:
 * - Configurable (Choose settings with the OpenSCAD Customizer)
 * - Two piece construction
 * - Optional space for one 2.5" drive below the mainboard (up to 15 mm thick)
 * - Lots of ventilation holes
 * - Two optional wall mounting holes on the bottom side
 * - Hole for mounting a power button
 * - Optional front cutout for the Odroid's status LEDs
 * - Attach rubber feet to the bottom side of the case
 */

// Configuration:
// Render top part of the case
enable_top = true;
// Render bottom part of the case
enable_bottom = true;

// Maximum disk height in mm
disk_height = 9.5; // [0, 7, 9.5, 12.5, 15]

// Wall mounting holes
enable_wall_mounts = true;

// Mainboard screw hole diameter (mm)
mb_screw_diameter = 3.5; // M3x30 screws fit nicely in 3.5 mm holes

// Case screw hole diameter (mm)
case_screw_diameter = 2.5; // Use self-tapping screws and adjust this if you use thicker or thinner screws

// Cutout for status LEDs
status_led_cutout = true;

// Position of 2.5" disk mounting holes (you probably don't want to change this)
disk_mount_x = 39.5;
disk_mount_y = 23;

// Dummy mainboard component for testing only (do not print)
enable_mainboard = false;
// Dummy disk component for testing only (do not print)
enable_disk = false;

include <honeycomb.scad>

$fn = 25;

module standoff(x, y, height, screw_diameter = 2.6)
{
    translate([x, y, 0]) {
        difference() {
            cylinder(h = height, r1 = 3.5, r2 = 3.5, center = true);
            cylinder(h = height+0.1, d1 = screw_diameter, d2 = screw_diameter, center = true);
        }
    }
}

module fillet(r, h)
{
    translate([r / 2, r / 2, 0]) difference() {
        cube([r + 0.01, r + 0.01, h], center = true);
        translate([r/2, r/2, 0])
            cylinder(r = r, h = h + 1, center = true);
    }
}

module mainboard()
{
    difference() {
        cube([110, 112, 2]);
        union() {
            translate([4, 6, 0])
                cylinder(d = 2, h = 2);
            translate([106, 6, 0])
                cylinder(d = 2, h = 2);
            translate([4, 87.3, 0])
                cylinder(d = 2, h = 2);
            translate([106, 94.5, 0])
                cylinder(d = 2, h = 2);
        }
    }
    translate([2, 112-20, 1]) cube([106, 20, 35]);   // Ports (USB, Eth., etc.)
    translate([10, 110-30, -10]) cube([73, 30, 10]); // RAM slots, etc.
}

module harddisk25()
{
    if (disk_height > 0)
        cube([100, 70, disk_height]);
}

module case_bottom()
{
    difference() {
        union() {
            difference() {
                cube([130, 120, 2.5]); // W x D x H
                union() {
                    translate([0, 0, 1.25])
                        fillet(2, 2.5);
                    translate([130, 0, 1.25]) rotate([0, 0, 90])
                        fillet(2, 2.5);
                    translate([130, 120, 1.25]) rotate([0, 0, 180])
                        fillet(2, 2.5);
                    translate([0, 120, 1.25]) rotate([0, 0, 270])
                        fillet(2, 2.5);
                }
            }
            translate([10, 0, 0]) // Front panel
                cube([110, 2.5, 15.5+disk_height]);
            difference() { // Back panel
                translate([10, 120-2.5, 0])
                    cube([110, 2.5, 15.5+disk_height]);
                // Power button (back)
                translate([106, 120+0.5, 8.25+disk_height/2])
                    rotate([90, 0, 0])
                        cylinder(d = 8, h = 5);
            }
        }

        union() {
            // Wall mounts
            if (enable_wall_mounts) {
                translate([65, 13, -0.1]) wall_mount();
                translate([65, 110, -0.1]) wall_mount();
            }

            translate([17.9, 23, 0.9]) honeycomb(11, 10);
            // 2.5" disk mounts (4 screw holes) (part a)
            if (disk_height > 0) {
                translate([disk_mount_x, disk_mount_y, 0]) {
                    translate([0, 0, 1.25]) {
                        translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
                    }
                    translate([77, 0, 1.25]) {
                        translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
                    }
                    translate([0, 62, 1.25]) {
                        translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
                    }
                    translate([77, 62, 1.25]) {
                        translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
                    }
                }
            }
            // 4 mainboard standoffs
            translate([121, 6.5, 12-4.75+(disk_height/2)]) rotate([0, 0, 90]) {
                translate([4.2, 5, -2])
                    cylinder(h = disk_height+14.5, d = mb_screw_diameter, center = true);
                translate([5+88.41, 5, -2])
                    cylinder(h = disk_height+14.5, d = mb_screw_diameter, center = true);
                translate([4.2, 5+102.23, -2])
                    cylinder(h = disk_height+14.5, d = mb_screw_diameter, center = true);
                translate([5+81.43, 5+102.23, -2])
                    cylinder(h = disk_height+14.5, d = mb_screw_diameter, center = true);
            }
        }
    }

    // 4 mainboard standoffs
    translate([121, 6.5, 12-4.75+(disk_height/2)]) rotate([0, 0, 90]) {
        standoff(4.2,  5,        disk_height+12.5, mb_screw_diameter); // TL
        standoff(5+88, 5,        disk_height+12.5, mb_screw_diameter); // BL
        standoff(4.2,  5+102.23, disk_height+12.5, mb_screw_diameter); // TR
        standoff(5+81, 5+102.23, disk_height+12.5, mb_screw_diameter); // BR
    }
    // 4 blocks with screw holes for attaching the top cover
    translate([3, 5, 0])     block_with_hole();
    translate([3, 100, 0])   block_with_hole();
    translate([119, 5, 0])   block_with_hole();
    translate([119, 100, 0]) block_with_hole();
    // 2.5" disk mounts (4 screw holes) (part b)
    if (disk_height > 0) {
        translate([disk_mount_x, disk_mount_y, 0]) {
            translate([0, 0, 1.25]) difference() {
                cube([10, 10, 2.5], center = true);
                translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
            }
            translate([77, 0, 1.25]) difference() {
                cube([10, 10, 2.5], center = true);
                translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
            }
            translate([0, 62, 1.25]) difference() {
                cube([10, 10, 2.5], center = true);
                translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
            }
            translate([77, 62, 1.25]) difference() {
                cube([10, 10, 2.5], center = true);
                translate([0, 0, -2]) cylinder(d = 3.5, h = 5);
            }
        }
    }
}

module block_with_hole()
{
    difference() {
        cube([8, 10, 12]);
        translate([-0.1, 5, 8]) rotate([0, 90, 0]) cylinder(d = case_screw_diameter, h = 10);
    }
}

module wall_mount()
{
    cylinder(d = 8, h = 3);
    translate([-1.5, -10, 0]) cube([3, 10, 3]);
}

module case_top()
{
    difference() {
        difference() {
            cube([130, 120, 50.5+disk_height]);
            union() {
                translate([0, 0, 25.25+disk_height/2])
                    fillet(2, 50.5+disk_height+0.1);
                translate([130, 0, 25.25+disk_height/2]) rotate([0, 0, 90])
                    fillet(2, 50.5+disk_height+0.1);
                translate([130, 120, 25.25+disk_height/2]) rotate([0, 0, 180])
                    fillet(2, 50.5+disk_height+0.1);
                translate([0, 120, 25.25+disk_height/2]) rotate([0, 0, 270])
                    fillet(2, 50.5+disk_height+0.1);
            }
        }
        union() {
            translate([2, 2, -0.1]) cube([130-4, 120-4, 50.5-2+0.2+disk_height]);

            translate([9.5, -0.1, 0]) cube([111, 3, 13+disk_height]);   // Front
            if (status_led_cutout)
                translate([9.5+7, -0.1, 13+disk_height-0.1]) cube([20, 3, 2]);  // LEDs
            translate([9.5, 117.1, -0.1]) cube([111, 3, 13+disk_height+0.1]); // Back

            translate([10, 10, 49.5+disk_height]) honeycomb(13, 14);

            // Side screw holes
            translate([-0.1, 10, 5.1]) rotate([0, 90, 0]) cylinder(d = case_screw_diameter+0.5, h = 10);
            translate([-0.1, 105, 5.1]) rotate([0, 90, 0]) cylinder(d = case_screw_diameter+0.5, h = 10);
            translate([130-4, 10, 5.1]) rotate([0, 90, 0]) cylinder(d = case_screw_diameter+0.5, h = 10);
            translate([130-4, 105, 5.1]) rotate([0, 90, 0]) cylinder(d = case_screw_diameter+0.5, h = 10);

            // Ventilation slot on the sides
            length = 110;
            width = 40.5+disk_height;
            translate([130, 60, 24+disk_height]) for (i = [1 : (length / 5) - 1]) {
                rotate([0, 90, 0])
                    translate([0, i * 5 - length / 2, -0.1]) cube([width/4*3, 1, 4], center = true);
            }
            translate([1, 60, 24+disk_height]) for (i = [1 : (length / 5) - 1]) {
                rotate([0, 90, 0])
                    translate([0, i * 5 - length / 2, 0]) cube([width/4*3, 1, 4], center = true);
            }

            // Odroid-H2 I/O cutouts
            // Back
            translate([107.6, 117.1, 12.5+disk_height])
                cube([11, 3, 11]); // DC-IN
            translate([55.8, 117.1, 12.5+disk_height])
                cube([44, 3, 32]); // 2xEthernet+4xUSB
            translate([33, 117.1, 12.5+disk_height])
                cube([25, 3, 19]); // DP+HDMI
            translate([12, 117.1, 12.5+disk_height])
                cube([13, 3, 36]); // Audio
        }
    }
    // Reinforcements for thinner pieces between backside cutouts
    translate([27.5, 116, 15+disk_height])
        cube([3, 2, 34]);
    translate([102.5, 116, 15+disk_height])
        cube([3, 2, 34]);
}

if (enable_bottom) case_bottom();
if (enable_top) translate([0, 0, 2.7]) case_top();

if (enable_mainboard) translate([10, 5, 13.5+disk_height]) mainboard();
if (enable_disk) translate([20, 20, 3]) harddisk25();

```
honeycomb.scad:
```
// Based on a design by EvanCarlsen: https://www.thingiverse.com/thing:1652822
// License: CC-BY
radius = 4;
inscribedOrCircumscribed = 0;//	[0:Use inscribed (corner to corner) radius, 1:Use circumscribed (edge to edge) radius]
//(inscribed radius)*cos(30)=circumscribed radius
combRadius = radius*cos(30)*(1-inscribedOrCircumscribed)+radius*inscribedOrCircumscribed;
combWidth = 2*combRadius;
//distance between edges of honeycomb holes
combSeperation = 2;
//Thickness/extrusion in the z direction
thickness = 1;
l=1/cos(30);
y=l*sin(30);
//radius*cos(30) = combWidth/2
//radius=(combWidth/2)/cos(3);

module hexagon(h=1,w=1)
{
    //l*cos(30)=1,
    hexPoints=[[1,y],[0,l],[-1,y],[-1,-y],[0,-l],[1,-y]];
    linear_extrude(h){
        polygon((w/2)*hexPoints);
    }
}

module honeycomb(xCount, yCount)
{
    yShift=sin(60)*(combWidth+combSeperation);
    for (j =[0:yCount-1]) {
        translate([0,yShift*j,0]) {
            for (i = [0:xCount-1]) {
               translate([(combWidth*.5+combSeperation*.5)*(j%2),0,0]) {
                   translate([i*(combWidth+combSeperation),0,0]) {
                      translate([0,0,-1]) {
                         hexagon(thickness+2,combWidth);
                      }
                   }
               }
            }
        }
    }
}

```


[User]
Hey, I'm looking to create a parametric bearing puller in OpenSCAD. I have a basic idea, but I need help building it.

The puller should consist of a main body with a hole for a bolt and a space for a nut to be held securely. The main body will have chamfered edges, kind of like the linked library I used in my previous attempt.

Here's the breakdown of what I need and the parameters I'd like to control:

**Overall Dimensions**

*   `width`:  The overall width of the main body.
*   `depth`:  The depth of the main body.
*   `height`: The overall height of the main body.

**Main Body Details**

*   `thickness`: The thickness of the main body's walls.
*   `chamfer`: The size of the chamfer.
*   `chamfer_edges`: The list of edges that need to be chamfered.
    *    Use a list of length 3, where index 0 refers to the X axis edges, 1 to the Y axis edges, 2 to the Z axis edges.
    *   Each element of the list should be a list of 4 values, each corresponding to one of the 4 corners of the axis
    *   Where a corner should be chamfered, the corresponding value in the list will be true (1), otherwise it should be false (0).

**Bolt and Nut Details**

*   `bolt_diameter`: The diameter of the bolt that goes through the centre hole.
*   `nut_width`: The width of the nut that will fit into the nut slot.

**Mounting Tabs (optional)**
*   `tab_width`: The width of the optional mounting tabs on each side
*   `tab_thickness`: The thickness of the optional mounting tabs
*   `tab_chamfer`: The size of the chamfer of the tab
*   `tab_chamfer_edges`: The list of edges to be chamfered in the tabs

**Functionality**
I want to be able to control all of these parameters. I want the script to create a solid object with a central hole for the bolt, a recess for the nut, and optionally tabs on the sides. It needs to have chamfered edges on both the main body and the tabs. I need the nut to be held firmly within the body - it doesn't need to be a press fit, but it shouldn't be loose.

I'd also like to avoid relying on any external library for the chamfering, I'd like the code to be included directly in the design if at all possible.

It would be fantastic if you could generate the OpenSCAD files based on these requirements.

[Assistant]
bearing_puller.scad:
```
width = 32;
depth = 15;
height = 20;

thickness = 4;
screw_d = 6.2;
nut_width = 10;

difference(){
  union(){
	chamferCube([width+2*thickness, height+2*thickness, depth]);
  }
  translate([thickness,-3,-2])chamferCube([width, height+thickness+3, depth+4], ch = 2);

  #translate([width/2+thickness,0,depth/2])rotate([-90,0,0])cylinder(d = screw_d, h = depth+3*thickness+2, $fn = 40);
}

chamferCube([thickness*2,thickness,depth],[[1,1,1,1],[1,1,1,1],[1,1,0]]);
translate([width,0,0])chamferCube([thickness*2,thickness,depth],[[1,1,1,1],[1,1,1,1],[1,1,1]]);

translate([width/2+thickness+nut_width/2,height,0])cube([thickness,thickness, depth]);
translate([width/2-nut_width/2,height,0])cube([thickness,thickness, depth]);

module chamferCube(size, chamfers = [undef, undef, undef], ch = 1, ph1 = 1, ph2 = undef, ph3 = undef, ph4 = undef, sizeX = undef, sizeY = undef, sizeZ = undef, chamferHeight = undef, chamferX = undef, chamferY = undef, chamferZ = undef) {
    if(size[0]) {
        chamferCubeImpl(size[0], size[1], size[2], ch, chamfers[0], chamfers[1], chamfers[2]);
    } else {
        // keep backwards compatibility
        size     = (sizeX == undef) ? size : sizeX;
        chamfers = (sizeY == undef) ? chamfers : sizeY;
        ch       = (sizeZ == undef) ? ch : sizeZ;
        ph1      = (chamferHeight == undef) ? ph1 : chamferHeight;
        ph2      = (chamferX == undef) ? ph2 : chamferX;
        ph3      = (chamferY == undef) ? ph3 : chamferY;
        ph4      = (chamferZ == undef) ? ph4 : chamferZ;

        chamferCubeImpl(size, chamfers, ch, ph1, ph2, ph3, ph4);
    }
}

module chamferCubeImpl(sizeX, sizeY, sizeZ, chamferHeight, chamferX, chamferY, chamferZ) {
    chamferX = (chamferX == undef) ? [1, 1, 1, 1] : chamferX;
    chamferY = (chamferY == undef) ? [1, 1, 1, 1] : chamferY;
    chamferZ = (chamferZ == undef) ? [1, 1, 1, 1] : chamferZ;
    chamferCLength = sqrt(chamferHeight * chamferHeight * 2);

    difference() {
        cube([sizeX, sizeY, sizeZ]);
        for(x = [0 : 3]) {
            chamferSide1 = min(x, 1) - floor(x / 3); // 0 1 1 0
            chamferSide2 = floor(x / 2); // 0 0 1 1
            if(chamferX[x]) {
                translate([-0.1, chamferSide1 * sizeY, -chamferHeight + chamferSide2 * sizeZ])
                rotate([45, 0, 0])
                cube([sizeX + 0.2, chamferCLength, chamferCLength]);
            }
            if(chamferY[x]) {
                translate([-chamferHeight + chamferSide2 * sizeX, -0.1, chamferSide1 * sizeZ])
                rotate([0, 45, 0])
                cube([chamferCLength, sizeY + 0.2, chamferCLength]);
            }
            if(chamferZ[x]) {
                translate([chamferSide1 * sizeX, -chamferHeight + chamferSide2 * sizeY, -0.1])
                rotate([0, 0, 45])
                cube([chamferCLength, chamferCLength, sizeZ + 0.2]);
            }
        }
    }
}
```


[User]
I need a parametric OpenSCAD design for a funnel. It should be constructed from three cylindrical sections. The first section is a short cylinder with a larger diameter that forms the entrance of the funnel. The second section is a frustum that tapers down from the entrance diameter to a smaller output diameter, and the third section is another cylinder with that smaller output diameter and a longer length, which forms the neck.

I want to control several parameters:

*   `d_ext`: The diameter of the funnel entrance (the larger diameter).
*   `d_small`: The diameter of the funnel output (the smaller diameter).
*   `h_fun_1`: The height of the entrance cylinder.
*   `h_fun_2`: The height of the frustum section.
*   `h_fun_3`: The height of the output cylinder (the neck).
*   `th_alu`: The thickness of the funnel walls, which should default to 1. If empty = `true`, the funnel should be hollowed out; if empty=`false`, the funnel is solid.

The design should be a single module called `funnel` that takes these parameters as inputs. This module should return a solid funnel or a hollowed one depending on the empty parameter. I'm not expecting you to use any libraries.

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

// Just a simple parametric funnel
// modify child modules regardless of how the child geometry
// is created.

$fn = 90;

// funnel entrance diameter
d_ext=20.0;

// funnel output diameter
d_small = 6.7;

// heigt of the nail
h_fun_1=6.0;

// height of the cylinder
h_fun_2=6.0;

// height of border
h_fun_3=20.0;

// thickness (used for empty funnel)
th_alu=1.0;

// empty funnel
empty = true;

module funnel(d1, d2,h1,h2,h3,th,empty=true){
    union(){
        difference(){
            cylinder(h=h1, d=d1);
            if (empty) translate([0,0,-1])
                cylinder(h=h1+2,d=d1-2*th);
        }
        difference(){
            translate([0,0,h1])
                cylinder(h=h2,d1=d1, d2=d2);
            if (empty) translate([0,0,h1-1])
                cylinder(h=h2+2,d1=d1-2*th, d2=d2-2*th);
        };
        difference(){
            translate([0,0,h1+h2])
                cylinder(h=h3,d=d2);
            if (empty) translate([0,0,h1+h2-1])
                cylinder(h=h3+2,d=d2-2*th);
        };
    }
}

funnel(d_ext,d_small,h_fun_1,h_fun_2,h_fun_3,th_alu,empty);
/*
translate([1.5*d_ext,0,0])funnel(d_ext-2*th_alu,d_small-2*th_alu,
        h_fun_1/2,h_fun_2,1.5*h_fun_3,th_alu);

*/

```


[User]
I'd like to have a parametric design for a clock based on a golden spiral, similar to what's described in the provided text. I need a few different parts that should all be adjustable using parameters.

The main components should be:

1.  **A clock dial:** This should be a rectangular base with a hole in the center for a clock mechanism. It needs to have markings for the hours, using cutouts in the dial itself, based on the spiral's path. This part will have a parameter for the dial's overall height, width, thickness, and the diameter of the center hole. I'd like two versions of the dial, actually: one with just hour markings and another with both hour and minute markings.

2.  **An hour pointer:**  This will follow a golden spiral path. It should have parameters for the thickness of the pointer, a hole diameter at the base where it attaches to the clock mechanism, and a diameter for the ring around that hole. The width of the spiral line itself should be adjustable too.

3.  **A minute pointer:** I'd like to have a couple options for the minute pointer, one that is a more traditional straight pointer and another that is a spiral. The straight pointer should have parameters for its thickness, a hole diameter for attachment, and a ring diameter around the hole, similar to the hour pointer. The spiral pointer should have parameters for the thickness of the spiral and a way to control the line width of the spiral. I'll want to be able to select which style of minute hand I want to use.

I need all parts to be able to be generated separately, or all together. I'm going to want to be able to easily rotate and translate the parts to see the full assembled view.

The golden spiral itself should be based on Fibonacci numbers and have parameters for a starting and ending Fibonacci number and a scaling factor. I think that should cover it all for now. I plan to 3d print these parts, so those parameters should be in millimeters. Also, can you please use the "Stencilia-A:style=Regular" font for the numbers on the dials?

[Assistant]
GoldenSpiralClock_V1.4.scad:
```

/* Golden Spiral Clock by Thomas Heiser
 *
 * 2019-10-28
 *
 * Thingiverse: thomasheiser https://www.thingiverse.com/thomasheiser/about
 *
 * V1.4
 *
 * Licensing: This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
 * Further information is available here - https://creativecommons.org/licenses/by-nc-sa/3.0/
*/

/* [General] */

// Part [dial,hour,minute,all]
part= "dial"; //[dial,dial2,hour,minute,minute_spiral,all]

// Diameter hour pointer hole [mm]
diameter_hour_pointer_hole = 5.5;

// thickness hour pointer [mm]
thickness_hour_pointer = 2;

// width hour pointer [mm]
width_hour_pointer = 2;

// Diameter hour pointer ring [mm]
diameter_hour_pointer_ring = 18;

// Diameter minute pointer hole [mm]
diameter_minute_pointer_hole = 3.7;

// Diameter minute pointer ring [mm]
diameter_minute_pointer_ring = 7;

// thickness minute pointer ring [mm]
thickness_minute_pointer_ring = 3;

// thickness minute pointer [mm]
thickness_minute_pointer = 2;

// width minute pointer (spiral only) [mm]
width_minute_pointer = 2;

// Dial height [mm]
dial_height = 190;

// Dial width [mm]
dial_width = 70;

// Dial hole [mm]
dial_hole = 7.7;

// Dial thickness [mm]
dial_thickness=2;

text_font= "Stencilia\\-A:style=Regular";

/* [hidden] */

from = 5; // from n-th fibonacci number
to = 10;  // to n-th fibonacci number
spirals = 1;
spiral_scale=1.4;

// Minute_Pointer
if(part=="all" || part=="minute")
{
    rotate_minute= part=="minute"? 180:0;

    color("white")
    rotate([0,rotate_minute,0])
    translate([0,0,thickness_hour_pointer])
    union()
    {
        difference()
        {
            cylinder(thickness_minute_pointer_ring,diameter_minute_pointer_ring/2,diameter_minute_pointer_ring/2,$fn=50,false);

            cylinder(thickness_minute_pointer_ring,diameter_minute_pointer_hole/2,diameter_minute_pointer_hole/2,$fn=50,false);
        }
        translate([diameter_minute_pointer_ring/2-1,-thickness_minute_pointer/2,thickness_minute_pointer_ring-thickness_minute_pointer])cube([50,thickness_minute_pointer,thickness_minute_pointer],false);
    }
}

// Hour_Pointer
if(part=="all" || part=="hour" || part=="minuute_spiral")
{
color("black")
hour_spiral();
}

// Minute_Pointer_Spiral
if(part=="all" || part=="minute_spiral")
{
color("red")
translate([0,0,thickness_hour_pointer])minute_spiral();
}

// Dial
if(part=="all" || part=="dial")
{
color("gray")
    difference() {
        translate([-dial_height/2,-dial_width/2,-dial_thickness])cube([dial_height,dial_width,dial_thickness],false);
        {
            translate([0,0,-dial_thickness])cylinder(dial_thickness,dial_hole/2,dial_hole/2,$fn=50,false);
            dial_hours_bottom(12);
            dial_hours_bottom(11);
            dial_hours_bottom(10);
            dial_hours_bottom(9);
            dial_hours_bottom(8);
            dial_hours_bottom(7);
            dial_hours_top(6);
            dial_hours_top(5);
            dial_hours_top(4);
            dial_hours_top(3);
            dial_hours_top(2);
            dial_hours_top(1);

            dial_number(12,-85.5,0);
            dial_number(11,-72,0);
            dial_number(10,-61,0);
            dial_number(9,-54,0);
            dial_number(8,-47.5,0);
            dial_number(7,-41,0);
            dial_number(6,85.5,0);
            dial_number(5,72,0);
            dial_number(4,61,0);
            dial_number(3,54,0);
            dial_number(2,47.5,0);
            dial_number(1,41,0);

        }
    }
}

// Dial2
if(part=="all" || part=="dial2")
{
color("gray")
    difference() {
        translate([-dial_height/2,-dial_width/2,-dial_thickness])cube([dial_height,dial_width,dial_thickness],false);
        {
            translate([0,0,-dial_thickness])cylinder(dial_thickness,dial_hole/2,dial_hole/2,$fn=50,false);

            dial_hours_minutes_bottom(12);

            dial_hours_minutes_bottom(11);
            dial_hours_minutes_bottom(10);
            dial_hours_minutes_bottom(9);
            dial_hours_minutes_bottom(8);
            dial_hours_minutes_bottom(7);
            dial_hours_minutes_top(6);
            dial_hours_minutes_top(5);
            dial_hours_minutes_top(4);
            dial_hours_minutes_top(3);
            dial_hours_minutes_top(2);
            dial_hours_minutes_top(1);

            dial_number(1,38,-8);
            dial_number(2,44.5,-8);
            dial_number(3,51,-8);
            dial_number(4,58,-8);
            dial_number(5,69,-8);
            dial_number(6,83,-8);
            dial_number(7,-42.5,-8);
            dial_number(8,-49.5,-8);
            dial_number(9,-56,-8);
            dial_number(10,-63.5,-8);
            dial_number(11,-75,-8);
            dial_number(12,-87.5,-8);

            dial_number(5,42.5,8);
            dial_number(10,49.5,8);
            dial_number(15,56,8);
            dial_number(20,63.5,8);
            dial_number(25,75,8);
            dial_number(30,87.5,8);
            dial_number(35,-38,8);
            dial_number(40,-44.5,8);
            dial_number(50,-58,8);
            dial_number(45,-51,8);
            dial_number(55,-69,8);
            dial_number(0,-83,8);

        }
    }
}

module dial_number(hours,pos,posy)
{
translate([pos,posy,-5])linear_extrude(10)rotate(-90)text(str(hours),halign="center",valign="center",size=5, font=text_font);
}

module dial_hours_bottom(hours)
{
    translate([0,0,-dial_thickness])intersection()
    {
        rotate(hours*-30)hour_spiral();
        difference()
        {
            translate([-60,0,0])cube([70,20,20],true);
            translate([-60,0,0])cube([70,8,8],true);
        }
    }
}

module dial_hours_top(hours)
{
    translate([0,0,-dial_thickness])intersection()
    {
        rotate(hours*-30)hour_spiral();
        difference()
        {
            translate([60,0,0])cube([70,20,20],true);
            translate([60,0,0])cube([70,8,8],true);
        }
    }
}

module dial_hours_minutes_bottom(hours)
{
    translate([0,0,-dial_thickness])intersection()
    {
        rotate(hours*-30)hour_spiral();
        difference()
        {
            translate([-60,0,0])cube([70,35,35],true);
            translate([-60,0,0])union()
            {
                translate([0,8,0])cube([70,9,8],true);
                translate([0,-8,0])cube([70,8,8],true);
            }
        }
    }
}

module dial_hours_minutes_top(hours)
{
    translate([0,0,-dial_thickness])intersection()
    {
        rotate(hours*-30)hour_spiral();
        difference()
        {
            translate([60,0,0])cube([70,35,35],true);
            translate([60,0,0])union()
            {
                translate([0,8,0])cube([70,9,8],true);
                translate([0,-8,0])cube([70,8,8],true);
            }
        }
    }
}

module hour_spiral()
{
    union()
    {
        scale([spiral_scale,spiral_scale,1])rotate(0)linear_extrude(thickness_hour_pointer)golden_spiral(from, to, true, width_hour_pointer/spiral_scale);
        difference() {
            cylinder(thickness_minute_pointer,diameter_hour_pointer_ring/2,diameter_hour_pointer_ring/2,$fn=50,false);
            cylinder(thickness_hour_pointer,diameter_hour_pointer_hole/2,diameter_hour_pointer_hole/2,$fn=50,false);
        }
    }
}

module minute_spiral()
{
    difference()
    {
        union()
        {
            scale([spiral_scale,spiral_scale,1])rotate(0)linear_extrude(thickness_minute_pointer)golden_spiral(from, to, true, width_minute_pointer/spiral_scale);
            cylinder(thickness_minute_pointer,diameter_hour_pointer_ring/2,diameter_hour_pointer_ring/2,$fn=50,false);
        }
        cylinder(thickness_minute_pointer,diameter_minute_pointer_hole/2,diameter_minute_pointer_hole/2,$fn=50,false);
    }
}

// remix from: https://www.thingiverse.com/thing:1759124

function PI() = 3.14159;

function fibonacci(nth) =
    nth == 0 || nth == 1 ? nth : (
	    fibonacci(nth - 1) + fibonacci(nth - 2)
	);

// Given a `radius` and `angle`, draw an arc from zero degree to `angle` degree. The `angle` ranges from 0 to 90.
// Parameters:
//     radius - the arc radius
//     angle - the arc angle
//     width - the arc width
module a_quarter_arc(radius, angle, width = 1) {
    outer = radius + width;
    intersection() {
        difference() {
            offset(r = width) circle(radius, $fn=48);
            circle(radius, $fn=48);
        }
        polygon([[0, 0], [outer, 0], [outer, outer * sin(angle)], [outer * cos(angle), outer * sin(angle)]]);
    }
}

module golden_spiral(from, to, count_clockwise = false, width = 1) {
    if(from <= to) {
		f1 = fibonacci(from);
		f2 = fibonacci(from + 1);

		offset = f1 - f2;

		a_quarter_arc(f1, 90, width);

		translate([count_clockwise ? 0 : offset, count_clockwise ? offset : 0, 0]) rotate(count_clockwise ? 90 : -90)
			golden_spiral(from + 1, to, count_clockwise, width);

	}
}

```


[User]
Hey there, I'm looking to create a parametric OpenSCAD design for a geometric earring. I really like the style of a minimal hexagon earring I saw online, and I'd like to build my own version with some customization options.

The basic idea is to have a hexagonal base, and then a triangle design layered on top of that. Here are the specifics:

*   **Hexagon Base:** This should be a flat cylinder with 6 sides. The size of the hexagon will be defined as point-to-point diameter. It will also have its own thickness.
*   **Triangle Layer:** On top of the base, I want to have three triangles positioned in a pattern. Each triangle should have its own thickness. The triangle positions are defined as the coordinates from the center, plus rotation about the z axis.
*   **Overlapping:** I'd like the triangle layer to slightly overlap the base layer. I think I'll want a small tolerance value to control the overlap.

Here's what I'd like to be able to customize:

*   **`size`:** The point-to-point diameter of the hexagon.
*   **`bot_thick`:** The thickness of the hexagon base.
*   **`top_thick`:** The thickness of the triangles.
*   **`triangles`:** The location and rotation of each triangle. I would like this parameter to be an array of vectors, where each vector has the form `[x, y, z, rotation]`

I'm hoping to use the design to do some multi-color printing, so it would be great if the two layers are separate objects which I can re-position relative to each other or export separately as needed.

I'm not sure if it would be better to generate one or more `.scad` files for this, but I would like to request the entire design be generated from scratch without including any code from other projects. I don't think I'll need any external libraries for this, but if you see any utility in using a library let me know.

[Assistant]
my-hexagon-earring.scad:
```
/*
    My remade version of the minimal hexagon earring by Isi8Bit.
    With CUSTOMIZER support!
*/

// size is point to point (not flat to flat)
size=24;
// bot thick is thickness of the hexagon base
bot_thick=2;
// top thick is thickness of the triangle design
top_thick=1.5;

/* [Hidden] */
// slightly overlap the two layers
tol=.01;
// triangles are defined by x,y,z,rotation
triangles = [ [-size/4,-size/7,bot_thick-tol, 30], [size/4,-size/7,bot_thick-tol, 30], [0,size/7,bot_thick-tol, 90] ];

// make the hexagon base
cylinder(r=size/2,h=bot_thick,$fn=6);
// add the trianges for the top layer
for (p = triangles)
    translate([p[0],p[1],p[2]]) rotate([0,0,p[3]]) cylinder(r=size/3.475,h=top_thick,$fn=3);

```


[User]
Hey, I need a custom cable box designed for 3D printing that can be mounted under a shelf. I've got some specific dimensions and features in mind, and I'd like it to be fully parametric so I can adjust it later if needed.

Here are the main parameters I need:

*   **Inner Dimensions:** I'd like to control the inner width (x), depth (y), and height (z) of the box. These should all be independently adjustable.
*   **Wall Thickness:** I need to be able to set the wall thickness (ws) of the box.
*   **Hexagonal Pattern:** I'd like a hexagonal pattern on the top of the box, where I can control the radius (hexr) of the hexagons.
*   **Cable Feed Diameter:** There should be a hole on the side for cables to pass through, and I need to be able to set the diameter (cfd) of this hole.
*   **Mounting:** I need mounting tabs with screw holes that extend from the sides of the box.

I envision the box itself to have rounded edges on the outer shell. The hexagonal pattern should be a *negative* pattern – i.e., it should be cut out of the box, not raised. I also want a separate module for the hexagonal pattern so that it could be reused for other projects. I need screw holes through the mounting tabs on either side of the box to be used for mounting, and I want to control the distance of the tabs to be parametric.

The overall design should be printable without supports. I'm hoping you can generate a well-commented OpenSCAD file that will allow me to adjust all of these parameters. I'm not super familiar with complex OpenSCAD techniques, so I would appreciate if the code was relatively straightforward. I'm fine with a single .scad file for all of this. I'd like to be able to adjust these parameters from the Customizer as well, so they should be noted appropriately.

Also, for future projects, could you make a note of any libraries I need, if you end up using any in the final code?

[Assistant]
Kabelbox_fuer_Gerd.scad:
```
// -----------------------------------------------------
// Kabelbox fuer Gerd
//
//  Detlev Ahlgrimm, 26.10.2019
// -----------------------------------------------------

// inner width
x=150;    // [50:200]

// inner depth
y=100;    // [50:200]

// inner height
z=50;     // [20:150]

// wall thickness
ws=1.2;   // [1.0:0.05:4]

// radius hex
hexr=12;  // [5:20]

// diameter cable feed
cfd=30;   // [10:40]

/* [Hidden] */
$fn=100;
//s=[150, 100, 50];
s=[x, y, z];

// -----------------------------------------------------
//  wie cube() - nur abgerundet gemaess "r"
// -----------------------------------------------------
module cubeR(v, r=1) {
  assert(r<=v.x/2 && r<=v.y/2 && r<=v.z/2);   // Requires version "nightly build"
  hull() {
    translate([    r,     r,     r]) sphere(r=r);
    translate([v.x-r,     r,     r]) sphere(r=r);
    translate([    r, v.y-r,     r]) sphere(r=r);
    translate([v.x-r, v.y-r,     r]) sphere(r=r);

    translate([    r,     r, v.z-r]) sphere(r=r);
    translate([v.x-r,     r, v.z-r]) sphere(r=r);
    translate([    r, v.y-r, v.z-r]) sphere(r=r);
    translate([v.x-r, v.y-r, v.z-r]) sphere(r=r);
  }
}

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

module theThing() {
  difference() {
    union() {
      difference() {
          cubeR([s.x+2*ws, s.y+ws+3, s.z+ws+3], 3);
          translate([-0.1, -0.1, s.z+ws]) cube([s.x+2*ws+1, s.y+2*ws+3, 10]);
          translate([ws, ws, ws]) cube([s.x, s.y+ws+3.1, s.z+0.1]);
          translate([5, 5, -0.1]) HexPatternV2([s.x+2*ws-2*5, s.y+ws-2*5, ws+0.2], r=hexr, w=3, i=false);
      }
      translate([s.x/2+ws, s.y, 0]) cylinder(d=cfd+10, 2*ws);
    }
    translate([s.x/2+ws, s.y, -0.2]) cylinder(d=cfd, 2*ws+0.4);
    translate([-0.1, s.y+ws, -0.2]) cube([s.x+2*ws+0.2, cfd, s.z+ws+0.3]);
  }
  for (i = [0, 1]) {
      translate([i*(s.x+2*ws), 0, ws]) mirror([i, 0, 0])
      difference() {
          translate([0, s.y/2-5, s.z]) rotate([0, 90, 90]) linear_extrude(10) polygon([ [0,0], [0,15], [15,0] ]);
          translate([-20, s.y/2-5+ws, s.z-20]) cube([20-ws, 10-2*ws, 20-2*ws]);
          translate([-7, s.y/2, s.z-2*ws+0.25]) cylinder(d=4, 20);
      }
  }
  translate([s.x/2+ws-10/2, ws, 0]) rotate([0, 0, -90]) translate([0, -(s.y/2-5), ws]) difference() {
      translate([0, s.y/2-5, s.z]) rotate([0, 90, 90]) linear_extrude(10) polygon([ [0,0], [0,15], [15,0] ]);
      translate([-20, s.y/2-5+ws, s.z-20]) cube([20-ws, 10-2*ws, 20-2*ws]);
      translate([-7, s.y/2, s.z-2*ws+0.25]) cylinder(d=4, 20);
  }
  intersection() {
    union() {
      translate([3, 3, ws]) cylinder(r=3, h=s.z);
      translate([s.x+2*ws-3, 3, ws]) cylinder(r=3, h=s.z);
      translate([ws, s.y+ws-3, ws]) cube([3, 3, s.z]);
      translate([s.x+ws-3, s.y+ws-3, ws]) cube([3, 3, s.z]);

      translate([0, s.y+ws-3, 0]) cube([s.x/2-cfd/2, 3, 2*ws]);
      translate([s.x/2+ws+cfd/2, s.y+ws-3, 0]) cube([s.x/2-cfd/2, 3, 2*ws]);

      translate([ws, s.y/2, ws]) cylinder(r=3, h=s.z);
      translate([s.x+ws, s.y/2, ws]) cylinder(r=3, h=s.z);
    }
    cubeR([s.x+2*ws, s.y+ws+3, s.z+ws+3], 3);
  }
}

rotate([0, 0, 180]) // drehen fuer die Thingiverse-Preview
theThing();

```


[User]
Hi there, I'm looking to generate some customizable text-based models using OpenSCAD. I know that the Makerbot Customizer is really outdated, and I saw a simple script that can tell you which version of OpenSCAD is being used. It just extrudes the version number. I'd like to make something a little more useful.

Specifically, I want to be able to generate a small 3D printed tag with customizable text and the OpenSCAD version number printed on it. It should have a thin rectangular base, maybe 2mm thick, and the text should be raised from the base. The text for the main tag should be a user input and the version number should be a smaller, fixed size. Maybe have the main text centered on the rectangle, and the version number text in a corner, like the bottom right?

I'm hoping you can give me an OpenSCAD file to start with that uses parameters for the text, base width and length, text extrusion height, etc.. It would also be great if the file had comments that explain all the parameters. I'm new to this and want to understand how it all works. Let me know if this is doable!

[Assistant]
what_version_is_customizer_using.scad:
```
linear_extrude(height=0.5) {
  text(str(version_num()/10000));
}
```


[User]
Hey there! I'm looking for some help designing a customizable funnel in OpenSCAD. I've got some ideas, but I'm not great with the code, and I want to make sure it's parametric so I can tweak it easily.

Basically, I need a funnel that has three main sections: a mouth, a middle section (a throat, I guess?), and a spout. I need to control the height and diameter of each of these sections independently, as well as the wall thickness of the entire funnel.

Specifically, I need to specify:

*   **Mouth:** Height and internal diameter.
*   **Throat:** Height, top internal diameter (where it connects to the mouth), and bottom internal diameter (where it connects to the spout).
*   **Spout:** Height and internal diameter.
*   **Wall Thickness:** This should apply to all parts of the funnel.

Also, I'd like an optional hanging tab. If enabled, this tab should stick out from the side of the mouth and have a hole for hanging the funnel.  For this I'd like to be able to control the width of the tab, how far it sticks out from the main funnel body (it's length), the diameter of the hole, the height of an optional lip at the end of the tab, and the resolution of the circle used for the hole.

Finally, I need to be able to control the overall resolution for the curves of the funnel. I'm guessing that means controlling `$fn` in the cylinder objects.

I'm thinking that's probably a few cylinders and some `difference()` operations. I'm not sure about the best way to handle the tab. I definitely want to keep the ability to disable the tab. Is there anything specific I should be thinking about in order to ensure I can produce good .stl files from the script? I know some details of some designs can come out weirdly in exported .stl files from the preview, but I'm not sure what specifically I should be watching out for other than low polygon counts.

I'm hoping you can generate the code for this. Thanks!

[Assistant]
parametric_funnel_ver0.5.scad:
```

//          **PARAMETRIC FUNNEL VER:0.5***
//
// *NOTE: all all units are in 'mm'
// *WARNING: any parameters relating to resolution are intensive, keep the values under ~100 to keep render times low on a slow computers. I suggest increasing the resolution as a final step.

//______________________________________
// Edit the values below to customize your funnel, then click 'preview' (f5) to view the funnel

// Mouth parameters
hm=10; //funnel mouth height
dm=50; //funnel mouth internal diameter

// Middle parameters
ht=20; //middle height
dtt=48; //middle entrance internal diameter
dtb=10; //middle exitinternal diameter

// Spout parameters
hs=20; //funnel spout height
ds=5; //funnel spout internal diameter

// Hang tab parameters
tab=1; // do you want a hang tab? 1=yes 0=no
tw=15; // tab width
tl=20; // tab length (from funnel wall)
thd=5; // tab hole diameter
tlh=10; // tab lip height
thq=100; // tab hole resolution

// Other parameters and options
t=1.5; //funnel wall thickness
q=100; //resolution of funnel body

//Once you make a funnel you want to print, click 'render'(f6).
//When it's done rendering click 'export to STL'(f7)
//When printing, I'd advise using a brim.

//______________________________________
//beyond this point is the actual script

irm=dm/2; //internal raduis of mouth entrance
irtt=dtt/2; //internal radius of throat top
irtb=dtb/2; //internal radius of throat bottom
irs=ds/2; //internal radius of stem exit

erm=irm+t; //external raduis of mouth entrance
ertt=irtt+t; //external radius of throat top
ertb=irtb+t; //external radius of throat bottom
ers=irs+t; //external radius of stem exit

thr=thd/2; //converting tab hole radius to diameter

difference(){

    union(){ //translate and place outside cylinders
        translate([0,0,hm/2])cylinder(h=hm,r1=erm,r2=ertt,center=true,$fn=q);//mouth cylinder
        translate([0,0,hm+ht/2])cylinder(h=ht+0.001,r1=ertt,r2=ertb,center=true,$fn=q);//middle cylinder
        translate([0,0,hm+ht+hs/2])cylinder(h=hs,r1=ertb,r2=ers,center=true,$fn=q);//spout cylinder
        if (tab==1) { //statement to add tab
            difference(){ //to cut hole from tab
                union(){ //combine tab and tab lip
                    translate([0,-tw/2,0]) cube([erm+tl+0.001,tw,t]); //tab
                    translate([erm+tl,-tw/2,0]) cube([t,tw,tlh]); //tab lip
                }
                translate([erm+tl/2,0,0]) cylinder(t+0.01,thr,thr,$fn=thq); //tab hole
            }
        }
    }

    union(){
        translate([0,0,hm/2])cylinder(h=hm+0.001,r1=irm,r2=irtt,center=true,$fn=q);//mouth cylinder
        translate([0,0,hm+ht/2])cylinder(h=ht+0.01,r1=irtt,r2=irtb,center=true,$fn=q);//middle cylinder
        translate([0,0,hm+ht+hs/2])cylinder(h=hs+0.01,r1=irtb,r2=irs,center=true,$fn=q);//spout cylinder
    }
}
```


[User]
I'm looking to design a customizable motor base for a marble run, specifically for the Tulio marble run. I'd like the design to be parametric so I can easily adjust various dimensions. The base needs to house a GA12-N20 motor (3mm shaft), two AAA batteries, and a small power switch. It also needs to be able to connect to a modified version of the marble run's spiral screw and the top cap.

Here's a breakdown of the features and parameters I'd like to be able to control:

**Overall Base:**

*   **Base Diameter:** The main diameter of the circular base.
*   **Base Height:** The overall height of the base.
*   **Bottom Base Height:**  The height of the main base before any cutouts or upper inserts.
*   **Hole Side Count:** An integer that controls the number of sides on the decorative holes that go through the base, allowing for circle, triangle, square, pentagon, hexagon, heptagon, or octagon holes.
*   **Upper Insert Height:** A raised lip around the top of the base that is smaller in diameter
*  **Battery Clip Height:** The height of the battery clips.

**Motor Housing:**

*   **Core Diameter:**  The diameter of the motor body itself.
*   **Core Height:** The height of the motor's main body.
*   **Gearbox Height:** The height of the motor's gearbox.
*   **Gearbox Width:**  The width of the motor's gearbox.
*   **Motor Mounting Offset:**  The offset from the base center of where to position the motor.
*  **Shaft Diameter:** The diameter of the motor shaft.

**Battery Compartment:**

*   **Battery Opening Diameter:** The diameter of the openings for the two AAA batteries.
*   **Battery Spacing:** The horizontal space between the two battery compartments.
*   **Battery Clip Offset:** The distance of the battery clips from the edge of the battery compartment.

**Switch Mount:**

*   **Switch Spacing:**  The distance from the center of the base to the switch location.

**Couplers:**

*   The bottom motor coupler should have a D-shaped hole to match the motor shaft.
*  The top coupler should have a hexagonal insert to attach the screw.

**Spiral Screw:**

* The screw will be imported as an STL file, with the option to translate it vertically.
* I'd like to have an option to add a cylindrical section at the top of the spiral screw.

**Top Cap:**
* The top cap should be imported as an STL file, with the option to translate it vertically.
* The top cap should have a lip that interlocks with the motor housing.

**Track:**
* The main track body will be imported as an STL file, with the option to translate it vertically, and with a hole added to the center.

**Files:**
I'd need a minimum of four different SCAD files. One for the main motor base, one for the spiral screw, one for the top cap, and another for the track. I'd also like a small file for the motor coupler.

I'd like to use the `import()` function to import the track, screw, and top cap STL files. I'd prefer to design everything else in OpenSCAD rather than relying on libraries, but I'm not opposed if it makes things easier.

Could you generate the OpenSCAD code for these parts? Please make sure to include comments so I can understand how it's all put together.

[Assistant]
MotorMount.scad:
```
//Base holes sides
HoleSideCount = 30; // [3:30]
// Model part to generate
ModelToDisplay = 0; // [0:Motor base, 1:Updated ball screw, 2:Updated top cap, 3:Motor-screw coupler, 4:Updated track]

$fn = 100;
$BodyLength = 65.98;
$CoreHeight = 15;
$CoreDiameter = 12.6;
$GearboxHeight = 9.2;
$GearboxWidth = 10.5;
$CapInsertHeight = 2;
$BatteryOpening = 15.1;
$SwitchSpacing = 21;
$BottomBaseHeight = 28;

if (ModelToDisplay == 0)
  BottomSideMotor();
else if (ModelToDisplay == 1)
  UpdatedScrew();
else if (ModelToDisplay == 2)
  UpdatedCap();
else if (ModelToDisplay == 3)
  BottomCoupler();
else if (ModelToDisplay == 4)
  UpdatedTrack();

//TopSideMotorSet(); // Terrible idea!!! Bottom motor is much better

module UpdatedTrack()
{
  difference()
  {
    import("Track.stl");
    cylinder(d = 22, h = 40, center = true);
  }
}

module UpdatedCap()
{
  translate([0, 0, -95.74])
    import("Turncap.stl");
  difference()
  {
    cylinder(d = 43, h = 7);
    cylinder(d = 38, h = 4.1);
    translate([0, 0, 4])
      cylinder(d = 41, h = 4.1);
  }
}

module UpdatedScrew()
{
  difference()
  {
    union()
    {
      import("Spiral.stl");
      translate([0, 0, 100])
        cylinder(d = 8.5, h = 9.8);
    }
    translate([0, 0, 98])
#      cylinder(d = 10, h = 12, $fn = 3);
  }
}

module BottomSideMotor()
{
  difference()
  {
    //Main base
    cylinder(d = 143, h = $BottomBaseHeight + 2);
    //Upper insert
    translate([0, 0, $BottomBaseHeight])
      cylinder(d = 140, h = 2.1);
    //Motor
    translate([0, 0, -($CoreHeight / 2) + $BottomBaseHeight - $GearboxHeight + 0.02])
      MotorOutline();
    //Batteries
    translate([8, 6.5, $BottomBaseHeight - ($BatteryOpening / 2)])
      LowerBatteryOpening();
    mirror([1, 0, 0])
      translate([8, 6.5, $BottomBaseHeight - ($BatteryOpening / 2)])
        LowerBatteryOpening();
    //Switch
    translate([0, 70, $BottomBaseHeight - 2.2])
      rotate(90, [0, 0, 1])
        Switch();
    translate([-3.5, 68, $BottomBaseHeight - 6])
      cube([7, 10, 10]);
    translate([-3.5, 58, $BottomBaseHeight - 2])
      cube([7, 10, 10]);
    //Wire openings
    translate([0, 0, ($BottomBaseHeight / 2) + 2])
    {
      cube([30, 3, $BottomBaseHeight], center = true);
      translate([14, 3.5, 0])
        cube([3, 10, $BottomBaseHeight], center = true);
      translate([-14, 3.5, 0])
        cube([3, 10, $BottomBaseHeight], center = true);
    }
    //Battery clips
    translate([8, 6.9, 12])
      cube([$BatteryOpening, .8, 20], center = true);
    translate([-8, 6.9, 12])
      cube([$BatteryOpening, .8, 20], center = true);
    translate([8, 6.9 + 55.2, 12])
      cube([$BatteryOpening, .8, 20], center = true);
    translate([-8, 6.9 + 55.2, 12])
      cube([$BatteryOpening, .8, 20], center = true);
    //Cutouts
    for (x =[0:7])
    {
      rotate((x * 40) + 130, [0, 0, 1])
        translate([52, 0, -0.1])
          cylinder(d = 33, h = $BottomBaseHeight + 2, $fn = HoleSideCount);
    }
    for (x =[0:6])
    {
      rotate((x * 40) + 150, [0, 0, 1])
        translate([29, 0, -0.1])
          cylinder(d = 16, h = $BottomBaseHeight + 2, $fn = HoleSideCount);
    }
    for (x =[0:3])
    {
      rotate((x * 40) + 210, [0, 0, 1])
        translate([16, 0, -0.1])
          cylinder(d = 10, h = $BottomBaseHeight + 2, $fn = HoleSideCount);
    }
    for (x =[0:8])
    {
      rotate((x * 40) + 150, [0, 0, 1])
        translate([64, 0, -0.1])
          cylinder(d = 10, h = $BottomBaseHeight + 2, $fn = HoleSideCount);
    }
  }
}

module LowerBatteryOpening()
{
  rotate(-90, [1, 0, 0])
    hull()
    {
      cylinder(d = $BatteryOpening, h = 56);
      translate([0, -10, 0])
        cylinder(d = $BatteryOpening, h = 56);
    }
}

module TopSideMotorSet()
{
  MotorHousing();
  translate([50, 0, 0])
    MotorMount();
  translate([28, 17, 0])
    TopCoupler();
  translate([28, -40, 7])
    rotate(180, [1, 0, 0])
      MotorCap();
}

module MotorCap()
{
  difference()
  {
    MotorCapInsert();
    translate([0, 13.5, 0])
      cylinder(d = 11, h = 5);
    translate([0, -13.5, 0])
      cylinder(d = 11, h = 5);
  }

  //Switch mount
  SwitchMount();
  translate([0, 0, 1])
    difference()
    {
      translate([0,0, 0.01])
        cylinder(d = 44 + 4, h = 6);
      cylinder(d = 44 + .8, h = 4);
      //Switch opening
      translate([$SwitchSpacing, 0, 1.79])
      {
        Switch();
      }
    }
}

module SwitchMount()
{
  difference()
  {
    translate([13, -8, 1])
      cube([9, 16, 4]);
    translate([$SwitchSpacing, 0, 2.8])
    {
      Switch();
    }
  }
}

module MotorCapInsert()
{
  $Clearance = .7;
  translate([0, 0, 5.0 - $CapInsertHeight])
  {
//    translate([0, 0, 59])
//      cylinder(d = 30 - $Clearance, h = $CapInsertHeight);
    //Alignment notch
    translate([-16, 0, $CapInsertHeight / 2])
      cube([6 - $Clearance, 6 - $Clearance, $CapInsertHeight], center = true);
    //Battery openings
//    translate([13.5, 0, 0])
//      BatteryOpening($Height = $CapInsertHeight);
    rotate(90, [0, 0, 1])
      translate([13.5, 0, 0])
        BatteryOpening($Height = $CapInsertHeight);
    rotate(-90, [0, 0, 1])
      translate([13.5, 0, 0])
        BatteryOpening($Height = $CapInsertHeight);
  }
}

module MotorHousing()
{
  difference()
  {
    //Main body
    translate([0, 0, 0.01])
      cylinder(d = 44, h = $BodyLength);
    //Lockcap mount
    cylinder(d = 40, h = 8);
    //Motor mount opening
    translate([0, 0, ($CoreHeight / 2) + $GearboxHeight])
      rotate(180, [1, 0, 0])
        MotorOutline();
    //Motor wire openings
    translate([4, 0, 0])
      cylinder(d = 3.5, h = 70);
    translate([-4, 0, 0])
      cylinder(d = 3.5, h = 70);
    $Clearance = 0;
    //Battery openings
//#    translate([13.5, 0, 0])
//      BatteryOpening($Height = 54);
    rotate(90, [0, 0, 1])
      translate([13.5, 0, 10])
        BatteryOpening($Height = 56);
    rotate(-90, [0, 0, 1])
      translate([13.5, 0, 10])
        BatteryOpening($Height = 56);
    //Wiring access opening
    translate([0, 0, 59])
      cylinder(d = 30, h = 7);
    //Alignment notch
    translate([-16, 0, 63])
      cube([6, 6, 8], center = true);
    //Switch opening
    translate([$SwitchSpacing - 3.5, 0, $BodyLength - 2.2])
    {
//      Switch();
//      cube([13, 7, 5], center = true);
      cube([11, 17, 5], center = true);

    }
  }
}

module Switch()
{
  translate([0, 0, -.49])
  {
    cube([13, 7, 4.4], center = true);
    translate([-3.15, 0, -1.05 + .5])
      cube([6.7, 11.2, 6.5], center = true);
  }
  cube([13, 7, 4.4], center = true);
}

module BatteryOpening()
{
  translate([0, 0, $Height / 2])
  {
    cylinder(d = $BatteryOpening - $Clearance, h = $Height, center = true);
    cube([3, 20 - $Clearance, $Height], center = true);
  }
}

module MotorMount()
{
  //Use the original cap, align and flip
  rotate(180, [1, 0, 0])
    translate([0, 0, -110.75 - 9])
      import("Lockcap.stl");
  //Fill in the center with a motor aligner
  difference()
  {
    cylinder(d = 16, h = 9);
    translate([0, 0, 5.5])
      cube([$CoreDiameter, $GearboxWidth, 10], center = true);

    cylinder(d = 4.2, h = 2);
  }
}

module MotorOutline()
{
  //Motor
  intersection()
  {
    cylinder(d = $CoreDiameter, h = $CoreHeight, center = true);
    cube([$CoreDiameter, $GearboxWidth, $CoreHeight], center = true);
  }
  //Gearbox
  translate([0, 0, -0.01 + (($CoreHeight + $GearboxHeight) / 2)])
    cube([$CoreDiameter, $GearboxWidth, $GearboxHeight], center = true);
  //Upper bearing
  translate([0, 0, ($CoreHeight / 2) + $GearboxHeight])
    cylinder(d = 4, h = 1);
  //Shaft
  translate([0, 0, ($CoreHeight / 2) + $GearboxHeight])
    cylinder(d = 3, h = 10);
  //Lower bearing
  translate([0, 0, -($CoreHeight / 2) - 1.2])
    cylinder(d = 5.2, h = 1.2);
  //Connectors
  translate([0, 0, -($CoreHeight / 2) - 1])
    cube([$CoreDiameter, 3, 2], center = true);
}

module TopCoupler()
{
  difference()
  {
    union()
    {
      cylinder(d = 8.2, h = 10);
      cylinder(d = 13, h = 5.5, $fn = 3);
    }
    difference()
    {
      cylinder(d = 3.2, h = 10.1);
      translate([-3, 1.2, 0])
        cube([6, 6, 10.1]);
    }
  }
}

module BottomCoupler()
{
  difference()
  {
    cylinder(d = 9, h = 6, $fn = 3);
    difference()
    {
      cylinder(d = 3.2, h = 10.1);
      translate([-3, 1.2, 0])
        cube([6, 6, 10.1]);
    }
  }
}
```


[User]
Hey, I'm looking to create a customizable city generator in OpenSCAD, something like what I've seen others do with procedurally generated buildings and roads.

I'd like to be able to control a few key things:

*   The number of avenues (think of them like north-south roads) and streets (east-west).
*   The width of the streets and sidewalks.
*   The size of the city blocks.
*   The maximum length of cars (for scaling purposes)
*   Building wall thickness
*   The overall building heights should be somewhat random.
*   And the design should be easily printable with hollow buildings that I can add lights to.

I'm thinking the city should be on a grid layout with streets and avenues intersecting and city blocks in between. I want some variety in the building designs, and perhaps different cladding styles like mullions, floors and windows, also procedurally generated. I'd also like to include some cars moving around on the roads. I'm not looking for any specific design aesthetic beyond making it look like a small city, if that makes sense.

Can you generate an OpenSCAD file (or files if it makes sense) that would do that?

[Assistant]
City.scad:
```
// City Builder
// Copyright (c) 2019-2020 Michael S. Scherotter
// synergist@outlook.com
// Version 0.3

// Number of avenues (x)
numAvenues = 5; // [2:10]

// Number of streets (y)
numStreets = 4; // [2:10]

// Street width in meters
streetWidth = 16; // [7:20]

// Sidewalk width in meters
sidewalkWidth = 3; // [1:4]

// Block width in meters (x)
blockWidth = 20; // [12:60]

// Block height in meters (y)
blockHeight = 40; // [12:60]

// Maximum car length in meters
maxCarLength = 4; // [3:6]

// Wall thickness for buildings
wallThickness = 2; //[4:8]

// Random number seed
//seed = 1; //[1:9999]

city();

module city(){
    buildingHeights = rands(0,100,(numStreets - 1) * (numAvenues-1));
    //echo(buildingHeights, " heights");
    union()
    {
        difference() {
            union(){
                ground();
                buildings(buildingHeights);
            //buildingHollows(buildingHeights);
            }
            streets();
            avenues();
            buildingHollows(buildingHeights);
        }
        cars();

    }
}

module cars(){

    blocks = 10 * (numStreets) * (numAvenues);
    carCount = rands(blocks, blocks, 1)[0];

    //echo(Cars = carCount);

    for (i=[0:carCount])
    {
        onAvenue = round(rands(0,1,1)[0]);

        lane = round(rands(0,3,1)[0]);

        laneSize = (streetWidth - (sidewalkWidth * 2) - 0.5) / 4;

        if (onAvenue == 0){
            avenue = round(rands(0, numAvenues-1, 1)[0]);
			  //echo(avenue= avenue);
            streetDim = rands(0, streetWidth + (numStreets-1) * (blockHeight + streetWidth) - maxCarLength, 1)[0];
            translate([1.5 + avenue * (blockWidth + streetWidth) - streetWidth / 2, streetDim, 1.9])
            translate([-laneSize * lane, -streetWidth, 0])
                car();
        } else {
            street = round(rands(0, numStreets-1, 1)[0]);
				//echo (street = street);

            avenueDim = rands(0, streetWidth + (numAvenues-1) * (blockWidth + streetWidth) - maxCarLength, 1)[0];
            translate([avenueDim, street *(blockHeight + streetWidth) - streetWidth / laneSize*2, 1.9])
                translate([-streetWidth + maxCarLength,laneSize * lane, 0])
                    rotate(a=90, v=[0,0,1])
                car();
        }
    }
}

module car(){
    scale([2, rands(2,maxCarLength,1)[0], rands(1,2.5, 1)[0]])
        cube ();
}

module streets(){
    c=0;
    translate([-streetWidth-1,-streetWidth-1,2])
    for (r=[0:numStreets])
        //for (c=[0:numAvenues])
            translate([c*(blockWidth + streetWidth),
                       r *(blockHeight + streetWidth) + sidewalkWidth,
                        0])
            scale([(numAvenues) * (streetWidth + blockWidth) + streetWidth + 2,
                   streetWidth - (sidewalkWidth * 2), 3])
            cube();
}

module avenues(){
    r=0;
    translate([-streetWidth-1,-streetWidth-1,2])
        for (c=[0:numAvenues + 1])
            translate([c*(blockWidth + streetWidth) + sidewalkWidth,
                       0,
                        0])
            scale([streetWidth - (sidewalkWidth * 2), (numStreets + 1) * (streetWidth + blockHeight) + streetWidth + 2,
                   , 3])
            cube();
}

module ground(){
    translate([-streetWidth, -streetWidth, 0])
        scale([(numAvenues-1) * (streetWidth + blockWidth) + streetWidth,
            (numStreets-1) * (streetWidth + blockHeight) + streetWidth, 3])
            cube();
}

module buildings(buildingHeights){

    for (r=[0:numStreets-2])
        for (c=[0:numAvenues-2])
            translate([c*(blockWidth + streetWidth),
                        r*(blockHeight + streetWidth),
                        1])
        {
            index = r*(numStreets-2) + c;
            //echo ("row ", r, " col ", c, " index", index);
                building(buildingHeights[index]);
        }
}

module building(height){
    //height = rands(0, 100, 1)[0];

    if (height > 40) {
        difference()
        {
            buildingMass(height);
            selectCladding(height);

        }
    } else {
        buildingMass(height);
    }
}

module buildingMass(height){
    scale([blockWidth, blockHeight, height])
        cube();
}

module buildingHollow(height){
    //echo("Building height: ", height);
    innerWidth = blockWidth - (wallThickness * 2);
    innerHeight = blockHeight - (wallThickness * 2);
    innerCubeHeight = height - wallThickness - innerHeight / 2;

    translate([wallThickness, wallThickness, -2])
        scale([innerWidth, innerHeight, 1+ innerCubeHeight])
        cube();
    translate([ wallThickness+innerWidth/2,wallThickness+innerHeight/2,innerCubeHeight])
        rotate(a=90, v=[0,1,0])
            cylinder(h=innerWidth, r1 = innerHeight / 2, r2 = innerHeight/2, center=true);
}

module buildingHollows(buildingHeights){
    for (r=[0:numStreets-2])
        for (c=[0:numAvenues-2])
            translate([c*(blockWidth + streetWidth),
                        r*(blockHeight + streetWidth),
                        1])
            {
                index = r*(numStreets-2) + c;

                buildingHollow(buildingHeights[index]);
            }
}

module addCladding(cladding, height, blockWidth, windowWidth, floorHeight, floorYTranslate) {
    if (cladding == 0) {
        mullion(height, blockWidth, windowWidth);
	}else if (cladding == 1) {
        translate([0,floorYTranslate,0])
        floors(height, blockWidth, floorHeight);
	} else if (cladding == 2){
		windows(height, blockWidth, floorHeight);
	}
}

module selectCladding(height){
    cladding =  round(rands(0,2,1)[0]);
	//echo(cladding=cladding);
    windowWidth = rands(2,5,1)[0];
    floorHeight = rands(2,5,1)[0];

	addCladding(cladding, height, blockWidth, windowWidth, floorHeight, 0);

    rotate(a=270, v=[0,0,1])
        translate([-blockHeight,0,0])
			addCladding(cladding, height, blockHeight, windowWidth, floorHeight, 0.0);

	rotate(a=180, v=[0,0,1])
   translate([-blockWidth, -blockHeight,0])
		addCladding(cladding, height, blockWidth, windowWidth, floorHeight, 0);

	rotate(a=90, v=[0,0,1])
   		translate([0, -blockWidth,0])
			addCladding(cladding, height, blockHeight, windowWidth, floorHeight, 0);

}

module windows(height, width, windowHeight, floorY	){
   goldenRatio = 1.61803399;

    mullionWidth = 0.25;
    numFloors = floor(height/(windowHeight + mullionWidth));
    	windowWidth = windowHeight / goldenRatio;
    numWindows = floor((width - mullionWidth) / (windowWidth + mullionWidth));
    windowArea = numWindows * windowWidth;
    diff = width - windowArea;
    modifiedMullionWidth = diff / (numWindows + 1);
	//echo(numFloors=numFloors);
   floorSpan = windowHeight + mullionWidth;
   //echo(floorSpan=floorSpan);
	for (floor2 = [1 : numFloors - 1])
{
   		for(window=[0: numWindows - 1])
        translate([modifiedMullionWidth +( windowWidth + modifiedMullionWidth) * window, -1.7 , floorSpan *0.5 + floor2 * floorSpan])
        scale([windowWidth, 2 , windowHeight])
        cube();
}
}

module mullion(height, width, windowWidth){
    mullionWidth = 0.25;
    numWindows = floor((width - mullionWidth) / (windowWidth + mullionWidth));
    windowArea = numWindows * windowWidth;
    diff = width - windowArea;
    modifiedMullionWidth = diff / (numWindows + 1);

    for (r=[0: numWindows-1])
        translate([modifiedMullionWidth +( windowWidth + modifiedMullionWidth) * r, -1.3, 0])
        scale([windowWidth, 1.5, height + 1])
        cube();
}

module floors(height, width, floorHeight){
    floorThickness = 1;
    numFloors = floor(height/(floorHeight + floorThickness));
    floorArea = numFloors * floorHeight;
    diff = height - floorArea;
    modifiedFloorThickness = diff / (numFloors + 1);
    for (h=[0:numFloors - 1])
        translate([0,-1.5,
            modifiedFloorThickness + (floorHeight + modifiedFloorThickness) * h])
            scale([width, 1.7, floorHeight])
            cube();
}
```


[User]
Okay, I'm looking to create a customizable header cover, specifically for things like Raspberry Pi GPIO headers but I'd like it to be more generic, so it's not limited to just those. The main idea is to have a cover that protects the pins but also allows for selective access to certain pins for things like jumper wires.

Here's what I need it to do:

1.  **Pin Configuration:**
    *   The design should handle headers with different numbers of pins and rows. For example, the Raspberry Pi has 40 pins in 2 rows, but I might use this for other boards.
    *   I need to be able to specify the number of pins in a single row, and the number of rows.
    *   The pin pitch (distance between pins) needs to be customizable, likely in millimeters (e.g., 2.54mm for standard headers).

2.  **Jumper Cut-outs:**
    *   I need to be able to define which specific pins should have cut-outs to allow for jumpers. I'd prefer specifying this as a list of pin numbers (where the pins are numbered sequentially by row from 1).
    *   The cut-out size around each jumper pin should be customizable.  I'd like to be able to specify an X and Y tolerance around the pin pitch for the cut-out.
    *   The cut-outs should go all the way through the cover and be rectangular.

3. **Pin Sockets:**
    * The pin sockets should fit snugly around the pin, and I should be able to specify a tolerance to ensure a good fit.
    * The holes should be customizable for shape (square or round)
    * The pin socket depth should be automatically based on the total pin length to be covered, as well as an extra bit of recess to make sure it is fully inserted.
    * The first pin should have a slight recessed top so it can be easily identified.

4.  **Overall Dimensions:**
    *   I need to be able to set the overall height of the cover.
    *   The thickness of the perimeter walls should be customizable.
    *   There should be a ridge around the base of the cover, with pin 1 indicated by a chamfer.

5.  **Customization & Advanced Options:**
   *   I'd like to have a scaling factor, so I can slightly adjust the size to compensate for printer shrinkage if needed.

6.  **Libraries:**
    *   Please avoid any external dependencies other than the standard OpenSCAD libraries.

Could you generate OpenSCAD code that accomplishes all of this? I'd expect to see a main file with modules for generating a single pin, for creating a grid of them, creating the perimeter, etc. It sounds like a lot, but I think it can be broken into manageable parts. The main thing is that it is fully parameterized for all the values I listed above.

[Assistant]
HeaderCoverWithCutouts.scad:
```

/*
   Customizable pin header cover with jumper cut-outs.
   https://www.thingiverse.com/thing:3962634
   2019 Todd Lowe
   https://www.thingiverse.com/ltlowe/about
*/

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

/*
// Pi3B+ GPIO pins
pin=[
       [1,1],  //      3v   1|2   5v
       [1,1],  //   GPIO2   3|4   5V
       [1,1],  //   GPIO3   5|6   Ground
       [1,1],  //   GPIO4   7|8   GPIO14
       [0,1],  //  Ground   9|10  GPIO15
       [0,0],  //  GPIO17  11|12  GPIO15
       [1,1],  //  GPIO27  13|14  Ground
       [0,1],  //  GPIO22  15|16  GPIO23
       [1,1],  //      3v  17|18  GPIO24
       [1,1],  //  GPIO10  19|20  Ground
       [1,1],  //   GPIO9  21|22  GPIO25
       [1,1],  //  GPIO11  23|24  GPIO8
       [1,1],  //  Ground  25|26  GPIO7
       [1,1],  //   ID_SD  27|28  ID_SC
       [0,1],  //   GPIO5  29|30  Ground
       [0,0],  //   GPIO6  31|32  GPIO12
       [1,1],  //  GPIO13  33|34  Ground
       [0,1],  //  GPIO19  35|36  GPIO16
       [1,1],  //  GPIO26  37|38  GPIO20
       [0,1]   //  Ground  39|40  GPIO21
   ];
*/

// List (as an array) of pins to leave out for jumpers.  Use PI header numbers, not GPIO numbers.  These will show as red boxes in the preview, but are removed when rendered. Pin 1 is upper left in preview.
exclude_pins=[1,7,6,35,39]; //exclude_pins

// How tall are the pins in mm. Raspberry Pi 3B GPIO header is 7mm. Hat's with passthrough pins may have different lengths.
pin_length=7;

// How many in the a header.  Raspberry Pi GPIO is 26 for v1B and 1A or 40 other models through 4B.
pins=40;

// How many rows of pins. Raspberry Pi GPIO is 2
rows=2;

// The pin pitch in mm. Raspberry Pi GPIO header is 0.1" or 2.54mm
pitch=2.54;

/* [advanced] */

// Perimeter wall thickness in mm.
wall=1.2;

// The Pi GPIO header uses square pins.
hole_style="square"; //[square,round]

// Extra to be added to pin hole size. Standard square holes are 0.64mm per side. Standard round holes are 1.02mm. tolerance will be added to each side for square or diameter for round.
hole_tolerance=0.4;

// Jumper tolerances - Extra in mm to be added to pitch size to create the x and y dimensions for jumper holes. If jumpers are not square, define the long side as y and the 1st and last rows will be shifted towards the outside by the difference.
jumper_x_tolerance=0.4;
jumper_y_tolerance=0.6;

// Use this to compensate for filament shrinkage or slight variations in printer dimensional accuaracy. Enter the additional percentage to expand (or shrink) by.  ie 1.7 will cause the entire object to be scaled to 101.7% of original size.  -1.7 will cause it to be 99.983%.  At this size I do not see shrinkange with pla or asa on my Prusa i3 MK3S.  Other materials and printers combinations may require compensation.
scale_compensation=0;

/* [Hidden] */

jumper_x=pitch+jumper_x_tolerance;
jumper_y=pitch+jumper_y_tolerance;

pin_height=pin_length+0.8; //extra space to ensure room for recessed pin 1
pin_edge=0.64+hole_tolerance;
hole_dia=1.02+hole_tolerance;
cover_height=pin_height+1.6;
pins_per_row=pins/rows;

scale(1+(scale_compensation/100))
  difference(){
    // build the header
    union(){
      header(pins_per_row,rows);
      color( "grey") perim(pins_per_row,rows);
    }
    // blocks to be subtracted for jumpers
    header(pins_per_row,rows,blank=1);
  }

/* ---------------------------------------------------------------- */

/*
 * Create a full header or pin sockets or jumper cut-outs
 */
module header(pins_per_row, rows, blank=0)
{
   translate([ -pitch*pins_per_row/2+pitch/2,-pitch*rows/2+pitch/2,0])
      {
          for(col=[0:pins_per_row-1],row=[0:rows-1]){
              // when using full array
              //v=pin[col][row]==undef?0:pin[col][row]?0:1;

              // when using a list of pin numbers
              v=search((col*rows+row)+1,exclude_pins)[0]+1?1:0;

              echo(str("[",col,"][",row,"]=",(col*rows+row)+1,"  ",v?"exclude":""));
              if (v==blank) one_block(col,row,blank=v);
          }
      }
}

/*
 * Create the perimeter and grab ridge with pin one indicated
 * by a 45% cut off the corner of the ridge.
 */
module perim(pins_per_row, rows, height=cover_height, wall=wall)
{
    translate([0,0,height/2])
      difference(){
        union()
           {
              // main border
              cube([pitch*pins_per_row+wall*2,pitch*rows+wall*2,height], center=true);
              // ridge
              translate([0,0,-(height)/2]) difference()
              {
                  linear_extrude(height=2) offset(r=wall, $fn=64)
                  square([pitch*pins_per_row+wall*2,pitch*rows+wall*2], center=true);
              }
          }
          // center cut out
          cube([pitch*pins_per_row,pitch*rows,height+.01], center=true);
          // pin 1 corner
          translate([(-pitch*pins_per_row/2)-(wall*1.5),(pitch*rows/2)+(wall*1.5),0])
              rotate(-45)cube([2,8,height*2],center=true);
        }
}

/*
 * create a single pin header block.
 * Either a female header with pin hole (blank=0), or
 * a block for removal sized for a jumper lead (blank=1)
 * If pin one is visible, the topsize of the header
 * is recessed by .08mm as an identifier.
 */
module one_block(col,row,p=pitch,h=cover_height,blank=0)
{
    // mark pin 1 by recessing it .8mm
    recess =((row==0 && col==0) &&!blank ? .8:0);
    h=h-recess;

    // reverse rows since we're rendering upside down
    row=((rows-1)-row);

    translate( [ p*col, p*row , h/2+recess] )
    {
       // '#' causes removal blocks to be visible as red in preview mode
       if(blank) #union() // create block to remove
       {
           y_translate=(jumper_y>jumper_x)?(jumper_y-jumper_x)*((row==0)?-1:(row==rows-1)?1:0):0;
           translate([0,y_translate,0])
           {
               // define the shape to be removed for a jumper
               cube([jumper_x,jumper_y,h+2],center=true);

               // chamfer
               translate([0,0,(-h/2)+2]) rotate([0,180.0])
                 linear_extrude(height=2,scale=(jumper_x+1.6)/jumper_x)
                   square ([jumper_x,jumper_y],center=true);
           }
       }
       else difference() // create a block with one pin hole
       {
           // block
           cube([p,p+0.1,h-.01], center=true );

           // hole
           if (hole_style=="round")
             translate ([0,0,cover_height-pin_height])
               cylinder(h=h,r=hole_dia/2,$fn=24,center=true);
           else
             // square
             translate ([0,0,cover_height-pin_height])
               cube([pin_edge,pin_edge,h],center=true);

           // chamfer
           rotate([0,0,45])
             translate ([0,0,h/2-hole_dia/2])
               cylinder(h=hole_dia,d1=hole_dia,d2=(pitch*1.414)-0.4,$fn=4,center=true);
        }
    }
 }
```