[User]
Alright, I've been playing around with the blaster design, and I've got some ideas for an awesome ray gun. I really want to dial up the "space weapon" look, so I'm thinking we can go heavy on the barrel decorations.

First off, let's get more rings on that barrel. Instead of just 8, can we push it up to 12? And how about we make those rings a bit more varied in size? I'm envisioning a sort of stepped effect. Could you set `ring_scale` so that it scales from 1.0 to 1.4 in increments of 0.04, starting with 1.0, so `ring_scale` would be `[1.0, 1.04, 1.08, 1.12, 1.16, 1.20, 1.24, 1.28, 1.32, 1.36, 1.40, 1.40]`?

Also, let's increase the radiator discs to 7. For their scaling, how about we make `radiator_scale` something like `[1.5, 1.8, 2.0, 2.1, 2.0, 1.8, 1.5]`? I want them to have a bit more of a subtle curve than they have right now.

On the main body, could we make the sight a bit longer, say `sight_length` of 5 instead of 3? Also, let's keep the barrel caliber `barrel_caliber` at 1.5, and the barrel thickness `barrel_thickness` at 0.3. The barrel should be lengthened to `barrel_length` = 20. The grip is good at `grip_width` = 2.5, but let's increase `grip_length` to 14.

Okay, for the fins, let's tone them down. Instead of 0, set `fin_count` to 2. Let's keep the width at `fin_width`=0.2, and the size at `fin_size` = 0.8. It's important to offset them a bit: set `fin_offset_angle` to 20 degrees.

Now for the "wibbly bits," the capacitor rings, let's crank `capacitor_count` to 8! For their angle, let's put them at a slight forward slant, so `capacitor_angle` would be at 20.

Finally, the barrel bell is good to go - let's keep `barrel_bell_present` at 1.

I think that should be about it. I'm not attached to any particular library, but whatever works best for this would be amazing! I'm looking forward to seeing this design come to life.

[Assistant]
blaster.scad:
```
/* [Barrel Decorations] */

// number of rings on barrel
ring_count = 0; // [0:8]

// size of each ring (1=default)
ring_scale=[1,1.2,1,1,1,1,1];

// number of radiator discs
radiator_count = 5; // [0:8]

// radius of each radiator disc
radiator_scale=[1.8,2.1,2.2,2.1,1.8,1.2,1,1,1,1,1];

/* [Main Body and Barrel] */

// Length of the sight
sight_length = 3;

// barrel_caliber
barrel_caliber=1.5; //

// thickness of the sides of the barrel
barrel_thickness=0.3;

// Lenght of barrel
barrel_length = 17;

// Width of the grip
grip_width=2.5; //

// length of the grip
grip_length=10; // [4:20]

/* [Fins and Wibbly Bits] */

// Number of fins
fin_count = 0;

// Width of fins
fin_width = 0.2;

// size of fins (best between 0.7 and 1.3)
fin_size = 1.0;

// angle to start the fins
fin_offset_angle = 45; // [0:360]

// number of capacitor ring elements
capacitor_count = 6; // [0:8]

// angle to display the capacitor  (negative to put these at the back of the gun)
capacitor_angle = 55; // [-80:80]

// Bell on end of barrel? (0=no)
barrel_bell_present = 1; // [0:1]

/* [Hidden] */

radiator_offset=6;

$fn =60;

/************************************************************************************************
****   Library functions for torii, beziers
**************************************************************************************************/

// define a torus
module torus(girth, radius)
{
	rotate_extrude(convexity = 10)
	translate([girth, 0, 0])
	circle(r = radius);
}

// Linear Bezier (linear interpolation)
function lb(t, p0, p1) = p0 + (t * (p1 - p0));
// Quadratic Bezier (1 control point)
function qb(t, p0, p1, p2) = lb(t,
		lb(t, p0, p1),
		lb(t, p1, p2));
// Cubic Bezier (2 control points)
function cb(t, p0, p1, p2, p3) = lb(t,
		qb(t, p0, p1, p2),
		qb(t, p1, p2, p3));
// Fourth-order Bezier (3 control points)
function b4(t, p0, p1, p2, p3, p4) = lb(t,
		cb(t, p0, p1, p2, p3),
		cb(t, p1, p2, p3, p4));
// Vertex at position t on Bezier curve
// Use curve appropriate to number of available control points
function b(t, points) =
		(len(points) == 2 ? lb(t, points[0], points[1]) :
		(len(points) == 3 ? qb(t, points[0], points[1], points[2]) :
		(len(points) == 4 ? cb(t, points[0], points[1], points[2], points[3]) :
		(len(points) == 5 ? b4(t, points[0], points[1], points[2], points[3], points[4]) : [0, 0]))));

// control_points: an array of 5 pairs of 2d coordinates. first and last
//    points are endpoints, rest are control.
// slices: how many slices to take.
module bezier_solid(control_points, slices)
{
	rotate_extrude($fn=70)
	translate([0.5, 0, 0])
	union() {
		// Each slice of the profile is a strip that runs from the lathe axis (x = -0.5) to
		// a segment of the Bezier curve. p and q are bottom and top points of the segment.
		for (i = [1 : slices]) {
			assign(p = b((i-1)/slices,control_points), q = b(i/slices,control_points)) {
				polygon(points=[
						[-0.5, p[1]], // bottom left (on axis; x = -0.5)
						[-0.5, q[1]], // top left (on axis; x = -0.5)
						[q[0], q[1]], // top right (on curve; x = q[0])
						[p[0], p[1]]  // bottom right (on curve; x = p[1])
				]);
}	}	}	}

/************************************************************************************************
****   Library functions for gun parts
**************************************************************************************************/

// draw the bell on the end of the barrel
module barrel_bell(inner_caliber, mouth_caliber)
{
	translate([barrel_length-0.2,0,0])
	rotate([0,90,0])
	difference()
	{
		bezier_solid([[inner_caliber,0],[1,1],[1,2],[5,3],[mouth_caliber,4]],40);
		translate([0,0,-0.05])
		scale([0.9,0.9,1.1])
		bezier_solid([[inner_caliber-0.4,0],[1,1],[1,2],[5,3],[mouth_caliber,4]],40);
	}
}

module ring(barrel_offset, ringwidth)
{

	translate([barrel_offset,0,0])
		rotate([0,90,0])
		torus(3,ringwidth);

	translate([barrel_offset-2.1,0,0.9])
		rotate([0,40,0])
		cylinder(h=3,r=0.2);

	translate([barrel_offset-2.1,-.65,-0.65])
		rotate([120,0,0])
		rotate([0,40,0])
		cylinder(h=3,r=0.2);

	translate([barrel_offset-2.1,0.65,-0.65])
		rotate([240,0,0])
		rotate([0,40,0])
		cylinder(h=3,r=0.2);
}

module fin(rot_angle)
{
rotate([rot_angle,0,0])
translate([-7,-2.5,0])
scale([1.5*fin_size,0.3*fin_size,1*fin_size])
difference()
{
	cylinder(h=fin_width,r=6);
	translate([0,0,-0.5])
		cube([6,6,2]);

	rotate([0,0,60])
		translate([-6,0,-0.5])
		cube([14,9,2]);

}

}

		// barrel rings
		if(ring_count > 0)
		{
			for(k = [1: ring_count])
			{
				scale([1,ring_scale[k-1],ring_scale[k-1]])
					ring(barrel_length+1-2.5*k,0.4);
			}
		}

		if(radiator_count > 0)
		{
			for(m = [1: radiator_count])
			{
				translate([radiator_offset+1*m,0,0])
					rotate([0,90,0])
					difference()
					{
						cylinder(h=0.4, r=1.5*radiator_scale[m-1]);

						translate([0,0,-0.1])
							cylinder(h=0.6, r=barrel_caliber/2-0.04);

					}
			}
		}

		// capacitors
		if(capacitor_count > 0)
		{
			for(ca = [1: capacitor_count])
			{
				translate([-3,0,0])
				rotate([360/capacitor_count*ca,0,0])
				rotate([0,capacitor_angle,0])
				union()
				{
					cylinder(h=5.5+4*abs(cos(90-capacitor_angle)), r=0.2);
					translate([0,0,5.5+4*abs(cos(90-capacitor_angle))])
						sphere(r=0.55, center=true);
				}
			}
		}

// barrel
rotate([0,90,0])
difference()
{
	union()
	{

		cylinder(h=barrel_length, r=barrel_caliber/2+barrel_thickness);
	}
	translate([0,0,-0.5])
		cylinder(h=barrel_length+1, r=barrel_caliber/2);
}

if(barrel_bell_present==1)
{
	barrel_bell(0.5,4);
}

// body
translate([-3,0,0])
scale([3,1,1.4])
sphere(r=3);

torus(4,0.4);

// grip

translate([-12,-grip_width/2,0-grip_length])
rotate([0,30,0])
scale([1,grip_width,1])
union()
{
	translate([0,0.5,0])
		scale([1,1.25,1])
		cylinder(h=grip_length, r=0.5);
	translate([3,0.5,0])
		scale([1,1.25,1])
		cylinder(h=grip_length, r=0.5);
   cube([3,1,grip_length]);

	// grippy bits
	translate([1.5,0.5,3])
		scale([1.6,0.6,0.5])
		sphere(r=1);
	translate([1.5,0.5,5])
		scale([1.6,0.6,0.5])
		sphere(r=1);
	translate([1.5,0.5,7])
		scale([1.6,0.6,0.5])
		sphere(r=1);
	translate([1.5,0.5,1])
		scale([1.6,0.6,0.5])
		sphere(r=1);
}

// trigger guard
translate([-4,0.5,-5])
rotate([90,0,0])
difference()
{
	cylinder(h=1,r=2);
	translate([0,0,-0.1])
		cylinder(h=1.2,r=1.6);
}
// trigger
translate([-3,0.5,-4.6])
rotate([90,0,0])
difference()
{
	cylinder(h=0.7,r=2);
	translate([0,0,-0.1])
		cylinder(h=1.2,r=1.6);
	translate([-1,-2.5,-0.1])
		cube([3,5,1]);

}

// sight
translate([-8,0,0])
scale([sight_length*5,1,1])
{
translate([0,0,5])
	rotate([0,90,0])
	torus(1,0.1);
translate([0,1,5])
	rotate([90,0,0])
	cylinder(h=2,r=0.1);
translate([0,0,4])
	cylinder(h=2,r=0.1);
}
translate([-8,0,2])
	cylinder(h=2,r=0.4);

// fins
if(fin_count > 0)
{
	for(j = [1: fin_count])
	{
		fin(fin_offset_angle+360/fin_count*j);
	}
}
// preview[view:south east, tilt:top diagonal]
```


[User]
I'd like to create a DNA-like ring structure in OpenSCAD, similar to the one described in the provided code, but I'd like to start from scratch with a fully parametric design.

The design should feature a ring of spheres connected by optional links. Here are the key parameters I'd like to control:

*   **`numOfEl`:** The total number of sphere pairs around the ring.
*   **`radius`:** The radius of the main ring (the distance from the center to the sphere pairs).
*   **`sphere_radius_linked`:** The radius of the spheres that are linked together.
*   **`sphere_radius_unlinked`:** The radius of the spheres that are not linked.
*  **`link_length`**: The length of the links between linked spheres.
*  **`link_radius`**: The radius of the links between linked spheres.
*   **`link_every`:** The frequency at which sphere pairs are linked. For example, `link_every = 5` would mean every fifth pair of spheres has a link.
*   **`twist`:**  An amount that each linked sphere is rotated around the ring's axis to create a helical effect.
*   **`flatten`:** A scaling factor on the z-axis to flatten the whole structure.
*   **`base_cylinder`**: A boolean value to enable or disable drawing a flat cylinder at the bottom of the structure, which serves as a visual base.
    *  If enabled, the cylinder should have a thickness of 2 and a radius of `radius` + `sphere_radius_linked`
*  **`center_sphere`**: A boolean value to enable or disable drawing a sphere in the center of the structure.
    *  If enabled, the center sphere should have a radius of 12 and be translated -4 units in the z-axis.

The basic unit should consist of two spheres, separated by a `link_length`. The linked spheres also have a cylinder connecting them. The unlinked sphere pairs do not have a cylinder connecting them. All sphere pairs are rotated around the central axis according to their position in the sequence. The linked spheres should also be rotated around the ring axis by an amount given by the `twist` parameter to give the DNA helix look. I'd like all the parts to be unioned together.

I don't require any external libraries for this design. Can you generate a `.scad` file with this parametric design?

[Assistant]
DNA_Ring.scad:
```
$fn=18;

numOfEl=120;  // number of elements
radius=50;   // main radius
radius1=6;   // radius of linked spheres
radius2=5;   // radius of unlinked spheres
link_length=20;
link_radius=2;
link_every=5;
twist=3;
flatten=0.8; // normal = 1

scale([1,1,flatten])
color("SteelBlue")
union(){

//// sphere in center
// translate([0,0,-4])
 //   sphere(12);

//// base
// translate([0,0,-link_length/2-radius1])
 //  cylinder(h=2,r=radius+radius1, center=0);

 for (i = [0:1:numOfEl-1]) {
   rotate( [0, 0, i*(360/numOfEl)])
    translate([radius,0,0])
      if((i/link_every-round(i/link_every))==0) {
        //color("red")
         DNA_mod(roty= i*twist*(360/numOfEl), radius=radius1, link_radius=link_radius, link_length=link_length, link=true);
      } else {
        // color("blue")
         DNA_mod(roty= i*twist*(360/numOfEl), radius=radius2, link_radius=link_radius, link_length=link_length, link=false);
      }
 }

}

//=================================

module DNA_mod(radius=10, link_radius=3, link_length=50, rotx=0, roty=0, rotz=0, link=true){

 rotate( [rotx, roty, rotz])
  union() {

    translate([-1*link_length/2, 0, 0])
     sphere(radius);

    translate([link_length/2, 0, 0])
     sphere(radius);

    if (link) {
       translate([-link_length/2, 0, 0]) rotate([0,90,0])
        cylinder(h=link_length,r=link_radius, center=0);
    }
  }
}

```


[User]
Hi there, I'm looking to design a fully parametric hob knob for a range/stove, and I've seen some examples that I really like. I need it to be adaptable to different shaft sizes, knob diameters, and with some optional features, so I was hoping you could generate the OpenSCAD code for me.

Essentially, I need a knob with the following basic features:

*   **Overall shape:** A cylindrical knob with an optional top chamfer and a recessed area at the top to make it more ergonomic to grip.
*   **Internal shaft connection:** The knob needs a D-shaped hole to fit onto a rotary shaft. Both the shaft diameter and the width of the flat side of the D need to be configurable. The depth of this hole should also be a parameter, along with an optional additional plunge depth on the top of the knob (recess depth). I need to be able to set a clearance value as well for both the shaft diameter and D flat width.
*   **Inner structure:** I need to be able to define a wall thickness, an inner diameter that creates a space/gap between the outer and inner cylinder. I also need some internal support structures (like internal cross-ribs) to strengthen it without adding much bulk. It would also be handy to be able to set a clearance height at the bottom of the internal area as well.
*   **Cosmetic features:** I'd like to set the number of sides on the outer cylinder (which, when sufficiently high, will approximate a true cylinder), and the size of the top chamfer.
*   **Zero pointer:** I want an optional pointer feature that indicates the current position of the knob. I should be able to set whether to use the pointer, as well as the pointer's size and the rotation angle with respect to the D-flat on the shaft.

Beyond the base shape, I'd like to have some optional extra features:

*   **Scollops:** Option to add decorative scoops or cutouts around the circumference of the knob.  I need to be able to set the number of these and an offset angle.
*  **Taps:** Option to add small, raised bumps around the circumference of the knob to improve grip.  I need to set the number of bumps and an offset angle.
*   **Cutaway:** A simple cutaway option (which would be used for printing tests), which would produce a slice of the knob removed as a printing/testing feature.

I want to make sure that the code is well-parameterized, so I can adjust these settings to fit the particular hob/stove I'm working with. The units should be in millimeters. I don't have any libraries in particular that I'm already using, so I'm fine with however you would like to implement this. I'm looking for a clean, well-commented OpenSCAD file. I'm mostly looking for it to be efficient with the code generation.

[Assistant]
hob_knob.scad:
```
/* [Design Variables] */
//in mm
height = 20;
//in mm (set to measured value, clearance is added)
shaft_diameter =  6.1;
//in mm (set to measured value, clearance is added)
D_width = 4.7;
//in mm
outer_diameter = 36;
//in mm
wall_thickness = 3;
//in mm
inner_diameter = 14;
//in mm
shaft_length = 11;
//in mm
plunge_depth = 3;
//in mm
clearance_height = 8;

/* [Cosmetic Settings] */
no_sides =9;
//in mm (0 for no chamfer)
top_chamfer=1.5;

/* [Zero Pointer] */
with_pointer = "yes"; // [yes,no]
//in mm
point_size = 5;
//degrees clockwise from the flat side
point_angle = 90;

/* [Additional Features] */
extra_feature="scollops"; // [none,scollops,taps,cutaway]
number_of_features=3;
//degrees
offset_angle=-30;

tap_height=3*1;
clearance = 0.1*1;
stiffener_thickness = 2*1; // mm
$fn = 	100*1;

module knob() {
	difference() {
		difference(){
			union() {
				difference() {
					overall_knob();
					hollow_torus();
				}
				internal_supports();
			}
			D_shaft_hole();
		}
		internal_clearance();
	}
}

module overall_knob() {
	union() {
		translate([0,0,top_chamfer]) cylinder(h=height-top_chamfer, r=outer_diameter/2, $fn=no_sides);
		cylinder(h=top_chamfer, r1=-top_chamfer+outer_diameter/2, r2=outer_diameter/2, $fn=no_sides);
		translate([0,0,height]) cylinder(h=(plunge_depth), r=(inner_diameter/2));
	}
}

module hollow_torus() {
	translate([0,0,(wall_thickness)]) difference() {
		cylinder(h=height, r=(outer_diameter/2)-wall_thickness);
		translate([0,0,-1]) cylinder(h=height+2, r=inner_diameter/2);
	}
}

module internal_supports() {
	translate([0,0,(top_chamfer+height)/2]) cube(size=[outer_diameter-wall_thickness, stiffener_thickness, height-top_chamfer], center=true);
	translate([0,0,(top_chamfer+height)/2]) cube(size=[stiffener_thickness, outer_diameter-wall_thickness, height-top_chamfer], center=true);
}

module D_shaft_hole() {
	rotate([0,0,-90-point_angle]) {
		translate([0,0,(height-shaft_length)]) difference() {
			cylinder(h=(shaft_length+plunge_depth+2), r=(shaft_diameter+clearance)/2);
			translate([-shaft_diameter/2,((D_width+clearance)-shaft_diameter/2),-1]) cube(size=[shaft_diameter+clearance,shaft_diameter+clearance,shaft_length+plunge_depth+4]);
		}
	}
}

module internal_clearance() {
	translate([0,0,height-clearance_height]) difference() {
		cylinder(h=height, r=(outer_diameter/2)-wall_thickness);
		translate([0,0,-1]) cylinder(h=height+2, r=inner_diameter/2);
	}
}

module scollop() {
	rotate([0,0,offset_angle]) {
		for (i=[0:number_of_features]) {
				rotate([0,0,(360/number_of_features)*i]) translate([-outer_diameter/2,(outer_diameter/2)+(height/8)-(wall_thickness),height/3]) rotate([0,90,0]) cylinder(h=outer_diameter, r=height/8);
		}
	}
}

module scollop_wall() {
	intersection() {
		translate([0,0,top_chamfer]) cylinder(h=height-top_chamfer, r=outer_diameter/2, $fn=no_sides);
		rotate([0,0,offset_angle]) {
			for (i=[0:number_of_features]) {
				rotate([0,0,(360/number_of_features)*i]) translate([-outer_diameter/2,(outer_diameter/2)+(height/8)-(wall_thickness),height/3]) rotate([0,90,0]) cylinder(h=outer_diameter, r=(height/8)+wall_thickness);
			}
		}
	};
}

module taps() {
	difference() {
		for (i=[0:number_of_features]) {
			rotate([0,0,(360/number_of_features)*i+offset_angle]) {
				minkowski() {
					hull() {
						translate([0,0,0]) cylinder(h=tap_height*2, r=1);
						translate([-outer_diameter/1.25,0,0]) cylinder(h=tap_height, r=outer_diameter/10);
					}
					translate([0,0,tap_height]) sphere(r=tap_height/2, $fn=5);
				}
			}
		}
		cylinder(h=height, r=(outer_diameter/2)-wall_thickness);
	}
}

if(extra_feature=="scollops") {
	difference() {
		scollop_wall();
		scollop();
	}
	difference() {
		knob();
		scollop();
	}
} else if(extra_feature=="taps") {
	knob();
	taps();
} else if(extra_feature=="cutaway") {
	difference() {
		knob();
		translate([0,0,-1]) cube([1000,1000,1000]);
	}
}else {
	knob();
}

if(with_pointer=="yes") {
	// zero marker
	translate([outer_diameter/2,0,0]) {
		polyhedron(
			points=[
				[point_size,0,height],[-wall_thickness/3,-point_size/2,height],[-wall_thickness/3,point_size/2,height],
				[0,0,top_chamfer]
			],
			triangles=[
				[0,1,2],
				[0,3,1],
				[0,2,3],
				[2,1,3]
			]
		);
	}
}

```


[User]
Hey, I'm trying to design a sort of locking mechanism for use in tight spaces, and I think I need some help with the OpenSCAD design. Basically, I want to create a trapezoidal "key" that slides into a matching trapezoidal slot in a block. I've got a rough idea and some dimensions, but I need to make it parametric and cleaner.

Here's what I'm thinking:

*   **Basic Shape:** A rectangular block with a trapezoidal slot cut into one side. The trapezoidal slot needs to be mirrored on the opposite side.
*   **Key:** A trapezoidal piece that matches the slot, and slides in to lock against the block's base.
*   **Parameters:** I want to control a few things with parameters:
    *   `block_height`: The overall height of the rectangular block.
    *   `block_length`: The length of the rectangular block.
    *   `block_width`: The width of the rectangular block.
    *   `trap_height`: The height of the trapezoidal slot at its highest point.
    *   `trap_length`: The length of the trapezoid base.
     *   `trap_diff`: the difference in length between the top and base of the trapezoid.
    *    `key_tolerance`: The clearance between the key and slot.
    *   `screw_r`: radius of screw holes
    *   `screw_h`: height of the screw recess for the countersunk screw

*  **Locking Mechanism**: The slot needs two screw holes. One at the begining of the slot and one at the end of the slot at the top face. These are used to secure the block to another surface. The key also needs a screw hole on the top face to secure the key to whatever it needs to lock against the block.

*   **Placement:** The trapezoidal slot should be centered along the width and length of the block and start from the bottom face.
*  **Libraries:** I'm fine using any reasonable libraries, but I'm hoping you can make use of BOSL and BOSL2 to keep things modular and organized.

Could you generate the SCAD files for me? I think I'll need a primary file that sets the parameters and calls in the key and slot parts.

[Assistant]
trap_lock.scad:
```
h = 30;
off = 15;
folga = 1;

trap_dif = 3;
trap_h = 10;
trap_l = 30;

paraf_r= 2;
paraf_h= 5;

translate([off, off*.8, 0]){

difference(){
translate([-off, -off,0])cube([trap_l + 2*off,trap_h + off,h]);
translate([0,0,5]
)linear_extrude(height = h + 5, center = false, convexity = 10) polygon(points=[[0,0],[trap_dif,trap_h + 1],[trap_l-trap_dif,trap_h + 1],[trap_l,0]]);

translate([-off/2,50,h/2]) rotate([90,0,0]) cylinder(r=paraf_r, h=200, $fn=30);
translate([trap_l + off/2,50,h/2]) rotate([90,0,0]) cylinder(r=paraf_r, h=200, $fn=30);

translate([-off/2,trap_h + 1,h/2]) rotate([90,0,0]) cylinder(r=paraf_r*2, h=paraf_h, $fn=30);
translate([trap_l + off/2,trap_h + 1,h/2]) rotate([90,0,0]) cylinder(r=paraf_r*2, h=paraf_h, $fn=30);

}
/*

difference(){
union(){
translate([-off, trap_h + folga,0])cube([trap_l + 2*off,trap_h + off*.5,h]);
translate([0,0,5]
)linear_extrude(height = h - 5, center = false, convexity = 10) polygon(points=[[folga,folga],[trap_dif + folga,trap_h + 1],[trap_l-trap_dif - folga,trap_h + 1],[trap_l - folga, + folga]]);
}

translate([-off/2,50,h/2]) rotate([90,0,0]) cylinder(r=paraf_r, h=200, $fn=30);
translate([trap_l + off/2,50,h/2]) rotate([90,0,0]) cylinder(r=paraf_r, h=200, $fn=30);

translate([-off/2, trap_h + folga + paraf_h-1,h/2]) rotate([90,0,0]) cylinder(r=paraf_r*2,  h=paraf_h, $fn=30);
translate([trap_l + off/2,trap_h + folga + paraf_h-1,h/2]) rotate([90,0,0]) cylinder(r=paraf_r*2, h=paraf_h, $fn=30);

}
*/
}

```


[User]
I need an OpenSCAD design for a test print, and it should be configurable through the customizer. I want to be able to choose whether it tests wall thickness or gap spacing. For either, it will create a series of progressively thicker walls or gaps.

Specifically, the design should include:

*   A base platform, with a configurable height.
*   A series of walls or gaps, with a configurable start thickness, end thickness, and thickness increment.
*   Configurable spacing between the individual walls/gaps.
*   A configurable wall height when testing walls (this is ignored when testing gaps).
*   A configurable length for each wall or gap.
*   Labels below each wall/gap indicating its specific thickness, with a configurable text emboss depth, font height, and font. (Please use the "orbitron.dxf" font included with the `write/Write.scad` library and assume it is available).
*   A title at the top of the design, with configurable text emboss, height, and the same font.
*   Configurable space between the text and the samples, and whitespace margin around the outside for corner rounding.
*   The whole thing needs to be parametrically designed, with variables for all of the above settings and default values where it makes sense.
*   It should use `write/Write.scad` to generate text.
*   Round corners using a `rrect` module

Could you generate the necessary OpenSCAD file(s) for this? I think it needs at least two files: one for the `rrect` module and the main file.

[Assistant]
wall-gap_test_print_v2-0.scad:
```
use <write/Write.scad>

// wall/gap test print (vertical)

/*[Setup]*/

// wall height or gap test
_style = 2; //[1:Wall,2:Gap]

// start thickness
_start = 0.2;

// end thickness
_end = 2.0;

// thickness difference between samples
_increment = 0.2;

// space between samples
_gap = 3.6;

// wall height (ignored for gaps)
_height = 3; // [1:16]

// wall or gap length
_length = 16; // [1:64]

// thickness of the base
_baseHeight = 1.0;

/*[Text]*/

// title for the test print
_title = "GAP TEST PRINT";

// depth of text emboss
_textEmboss = 0.25;

// height of title text
_titleHeight = 4; // [1:16]

// height of numerical text
_fontHeight = 3; // [1:16]

/*[Whitespace]*/

// space between the test and samples
_textGap = 3; // [1:8]

// whitespace margin around the outside, affects corner radius
_edgePadding = 5; // [1:8]

/*[Ignore]*/
eps = 0.1 * 1; // ignore
$fn=48 * 1; // ignore

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

module rrect(h, w, l, r) {
	r = min(r, min(w/2, l/2));
	w = max(w, eps);
	l = max(l, eps);
	h = max(h, eps);
	if (r <= 0) {
		translate([-w/2, -l/2,0]) {
			cube([w,l,h]);
		}
	} else {
		hull() {
			for (y = [-l/2+r, l/2-r]) {
				for (x = [-w/2+r, w/2-r]) {
					translate([x,y,0]) {
						cylinder(h=h, r=r, center=false);
					}
				}
			}
		}
	}
}

module thinWallTest() {

	module addWallGrid(count, wallHeight) {
		module addWall(thickness, xspacing, xpos, h) {
			//echo (xpos, thickness);
			translate([xspacing * xpos, 0, 0]) {
				cube([thickness, _length, h]);
			}
		}

		xspacing = _gap + _end;
		for (index = [0:count-1]) {
			assign(thickness = _start + _increment * index) {
				translate([-thickness/2, 0, 0]) {
					addWall(thickness, xspacing, index, wallHeight);
				}
			}
		}
	}

	module addTextGrid(count, wallHeight) {

		module addText(thickness, xspacing, xpos) {
			//!@# get font length
			translate([xspacing * xpos + _fontHeight/2, _length + _textGap, 0]) {
				rotate(90,00,0) {
					write(str(thickness), t=_textEmboss+eps, h=_fontHeight, font="write/orbitron.dxf", space=1);
				}
			}
		}

		xspacing = _gap + _end;
		for (index = [0:count-1]) {
			assign(thickness = _start + _increment * index) {
					addText(thickness, xspacing, index);
			}
		}
	}

	function maxFast(a,b) = (a >= b) ? a : b; // using the builtin max will be really slow O(2^n) vs O(n) : https://github.com/openscad/openscad/issues/738

	// count the max number of characters in the display strings
	function maxChars(start, increment, end, chars) =
		start >= end ? chars : maxFast(chars, maxChars(start+increment, increment, end, len(str(start)) ) );

	fontLength = maxChars(_start, _increment, _end, 0);
	count = round((_end-_start)/_increment)+1;
	xspacing = _gap + _end;
	xdim = xspacing * (count-1) + _fontHeight;
	xdim = xspacing * (count-1) + _fontHeight + _end;
	ydim = _length + _titleHeight + _textGap*2 + _fontHeight * fontLength * (2/3);
	difference() {
		if (_style == 1) {
			// walls
			union () {
				translate([xdim/2-xspacing/2, ydim/2 - _titleHeight - _textGap,-_baseHeight]) {
					rrect(_baseHeight, xdim + _edgePadding*2, ydim + _edgePadding*2, _edgePadding);
				}
				addWallGrid(count, _height);
			}
		} else {
			// gaps
			difference () {
				translate([xdim/2-xspacing/2, ydim/2 - _titleHeight - _textGap,-_baseHeight]) {
					rrect(_baseHeight, xdim + _edgePadding*2, ydim + _edgePadding*2, _edgePadding);
				}
				translate([0, 0, -_baseHeight-eps]) {
					addWallGrid(count, _baseHeight+eps*2);
				}
			}
		}

		// labels
		translate([0, 0, -_textEmboss]) {
			addTextGrid(count, _textEmboss + eps);
		}

		// title
		translate([xdim/2 - xspacing/2, -_textGap - _titleHeight/2, -_textEmboss/2+eps/2]) {
			rotate([0,0,180])
			write(_title, t=_textEmboss+eps, h=_titleHeight, font="write/orbitron.dxf", space=1.2, center=true);
		}
	}
}

thinWallTest();

```


[User]
I'm looking to create a parametric knob that can hold a hex nut. I've seen a few designs but want to have one that's really flexible and configurable.

Specifically, I'd like these parameters:

*   **`diameter`**: The overall diameter of the knob (in millimeters).
*   **`thickness`**: The total thickness of the knob (in millimeters).
*   **`hexNutWidth`**: The point-to-point width of the hex nut that the knob will hold (in millimeters).
*   **`holeDiameter`**: The diameter of the through-hole, in millimeters.
*   **`hexHoleDepth`**: The depth of the hex nut recess in the knob, in millimeters.

The knob should have a main cylindrical body, and it should have cutouts on the sides to make it easier to grip. These cutouts should be made by taking three cylinders and rotating them by 60 and -60 degrees respectively, then subtracting those cylinders from the main cylindrical body. The center of each of these cylinders should be at 75% of the knob diameter, and their diameter should be the same as the knob diameter. The hex nut cutout should be centered in the knob, should be a hexagon, and should be only as deep as specified with the `hexHoleDepth` parameter, and there should be a smaller cylindrical through-hole through the rest of the knob.

I'd like the code to be written in OpenSCAD and to be fully parametric.

I'm not too familiar with OpenSCAD, so please don't use any non-standard libraries - just the basic functionality is fine. I'd like it to be a single `.scad` file.

[Assistant]
parametric_hex_nut_knob.scad:
```
// stuff for Thingiverse Customizer
//---------------------------------------------
// (mm)
	diameter=30;
// (mm)
	thickness=4;
// (mm) - measured point-to-point
	hexNutWidth=7;
// (mm)
	holeDiameter=4;

// ensure base is at least 1mm thick
	hexHoleDepth=thickness-1;

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

// this geometry works nicely - don't adjust!!!
//---------------------------------------------
	distFromCentre=0.75*diameter;
//---------------------------------------------

// construction
//---------------------------------------------
render(){ // some wrapping to work with Sublime and OpenSCAD
difference(){
//main body
	cylinder(h=thickness, r=diameter/2, center=true, $fn=50);

//cut outs
	rotate([0, 0, 60])
	translate([distFromCentre, 0, 0])
		cylinder(h=thickness+2, r=diameter/2, center=true, $fn=50);
	translate([-distFromCentre, 0, 0])
		cylinder(h=thickness+2, r=diameter/2, center=true, $fn=50);
	rotate([0, 0, -60])
	translate([distFromCentre, 0, 0])
		cylinder(h=thickness+2, r=diameter/2, center=true, $fn=50);

//hex hole
	rotate([0, 0, 0])
	translate([0, 0, thickness-hexHoleDepth])
		cylinder(h=thickness, r=hexNutWidth/2, center=true, $fn=6);
		cylinder(h=thickness+2, r=holeDiameter/2, center=true, $fn=50);
}
}
//---------------------------------------------
```


[User]
Hey, I'm looking to get some OpenSCAD code for a customizable set of drawers. I've seen a few examples out there, but I want one that's very flexible with a specific aesthetic.

First, I need the design to be modular. I want to be able to choose how many drawers the final unit has, and the individual dimensions of each drawer, as well as the overall box housing them. I need parameters for the drawer's height, depth, and width, along with the number of drawers. I'd also like to be able to set the wall thickness, the floor thickness, and a clearance value between the drawers and the box. There should also be a radius parameter for rounded corners and fillets.

A key element I want is a hexagonal pattern on the sides of the drawer box (not the drawers themselves). It should be customizable, allowing me to set the hex size and spacing between them. It'd be great if the pattern could automatically adjust to fit the box dimensions so it's consistent.

I'd also like a simple handle on each drawer and the ability to add a text label on the front. I need control over the handle size and the text height.

Finally, I'd like a feature that helps the drawers "lock" when in the closed position, so they don't fall out when opened. I think a small bump on the inside of the drawer box and corresponding dimples on the bottom of the drawers would do the trick. I need a way to set the size of these bumps and dimples.

The design should utilize the `write.scad` library for the text labels. I'd also like to use the `roundedBox` module from a standard boxes.scad library, if you can handle that.

Could you generate the necessary OpenSCAD files for this?

[Assistant]
drawer_box_v5_-_hex_pattern.scad:
```
/*

Customizable drawer box
Gian Pablo Villamil
August 4, 2014

v1 first iteration
v2 added drawer handle
v3 added full fillets, tweaked wall thickness and corner handling
v4 added text label
v5 added hex patterning on the sides

*/

use<write.scad>;

/* [Global] */

// Which one would you like to see?
part = "drawerbox"; // [drawer1:1 section drawer,drawer2:2 section drawer,drawer3:3 section drawer, drawer4:4 section drawer, drawerbox:drawer housing]

/* [Basic] */

// How many drawers?
NUM_DRAWERS = 5;

// How high?
DRAWER_HEIGHT = 15;

// How deep?
DRAWER_DEPTH = 59;

// How wide?
DRAWER_WIDTH = 80;

// Label on the drawer
MESSAGE = " ";

// Text height
TEXT_HEIGHT = 6;

/* [Pattern] */

india = 6 ;
spacing = 1;
dia = india + (spacing * 2);

hoff = india+spacing;
voff = sqrt(pow(hoff,2)-pow(hoff/2,2));

/* [Advanced] */

// Handle size?
HANDLE_SIZE = 10;

// Corner radius?
DRAWER_CORNER_RAD = 2;

// Clearance
CLEARANCE = 0.5;

// Wall thickness
WALL_THICK = 1.6;

// Floor thickness
FLOOR_THICK = 1.2;

// Rounded fillets?
FILLETS = true;

/* [Hidden] */

$fn = 32;
NOFILLETS = !FILLETS;
WALL_WIDTH = WALL_THICK + 0.001; // Hack to trick Makerware into making the right number of filament widths
INNER_FILLET = DRAWER_CORNER_RAD-(WALL_WIDTH/1.25);

BOX_HEIGHT = NUM_DRAWERS*(DRAWER_HEIGHT+CLEARANCE*2+WALL_WIDTH)+WALL_WIDTH;
BOX_WIDTH = DRAWER_WIDTH+CLEARANCE*2+WALL_WIDTH*2;
BOX_DEPTH = DRAWER_DEPTH+CLEARANCE+WALL_WIDTH;

thick = WALL_THICK + 0.2;

//
print_part();

module print_part() {
	if (part == "drawer1") {
		drawer1();
	} else if (part == "drawer2") {
		drawer2();
	} else if (part == "drawer3") {
		drawer3();
	} else if (part == "drawer4") {
		drawer4();
	} else {
		drawerbox();
	}
}

module drawerbox() {
	translate([-BOX_WIDTH/2,-BOX_DEPTH/2,0])
	difference () {
		cube([BOX_WIDTH,BOX_DEPTH,BOX_HEIGHT]);
		for (i=[0:NUM_DRAWERS-1]) {
			translate([WALL_WIDTH,-1,i*(DRAWER_HEIGHT+CLEARANCE*2+WALL_WIDTH)+WALL_WIDTH])
			cube([DRAWER_WIDTH+CLEARANCE*2,DRAWER_DEPTH+CLEARANCE+1,DRAWER_HEIGHT+CLEARANCE*2]);
		}
	translate([0,BOX_DEPTH+0.1,0])
	holes(BOX_WIDTH,BOX_HEIGHT);
	rotate([0,0,90]) translate([hoff/2,0.1,0]) holes(BOX_DEPTH,BOX_HEIGHT);
	rotate([0,0,90]) translate([hoff/2,-BOX_WIDTH+WALL_WIDTH+0.1,0]) holes(BOX_DEPTH,BOX_HEIGHT);
	}
};

module drawer1() {
	difference() {
		drawerbase();
		 translate([0,0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH-(WALL_WIDTH*2),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
	}
};

module drawer2() {
	difference() {
		drawerbase();
		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
}
};

module drawer3() {
	difference() {
		drawerbase();
		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,DRAWER_DEPTH/4-WALL_WIDTH/4,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,-(DRAWER_DEPTH/4-WALL_WIDTH/4),FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
}

};

module drawer4() {
	difference() {
		drawerbase();
		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),DRAWER_DEPTH/4-WALL_WIDTH/4,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),-(DRAWER_DEPTH/4-WALL_WIDTH/4),FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,DRAWER_DEPTH/4-WALL_WIDTH/4,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,-(DRAWER_DEPTH/4-WALL_WIDTH/4),FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
}};

module drawer6() {};

module drawerbase() {
	union() {
	difference() {
	translate([0,0,DRAWER_CORNER_RAD/2]) roundedBox([DRAWER_WIDTH,DRAWER_DEPTH,DRAWER_HEIGHT+DRAWER_CORNER_RAD],DRAWER_CORNER_RAD,NOFILLETS);
	translate([0,0,DRAWER_HEIGHT]) cube([DRAWER_WIDTH+1, DRAWER_DEPTH+1,DRAWER_HEIGHT],center=true);}
translate([0,-DRAWER_DEPTH/2,-DRAWER_HEIGHT/2+FLOOR_THICK]) handle();

translate([-DRAWER_WIDTH/2+DRAWER_CORNER_RAD,-DRAWER_DEPTH/2+0.5,-DRAWER_HEIGHT/4+DRAWER_CORNER_RAD/2]) rotate([90,0,0]) write(MESSAGE,h=TEXT_HEIGHT,font="Orbitron.dxf");
};
};

module handle() {

	difference() {
		roundedBox([DRAWER_WIDTH/4,HANDLE_SIZE*2,FLOOR_THICK*2],2,true);
		translate([0,HANDLE_SIZE,0]) cube([DRAWER_WIDTH/4+1,HANDLE_SIZE*2,FLOOR_THICK*2+1],center=true);
	};

	difference() {
		translate([0,-DRAWER_CORNER_RAD/2,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			cube([DRAWER_WIDTH/4,DRAWER_CORNER_RAD,DRAWER_CORNER_RAD],center=true);
		translate([-DRAWER_WIDTH/8-1,-DRAWER_CORNER_RAD,FLOOR_THICK+DRAWER_CORNER_RAD]) rotate([0,90,0])
			cylinder(h=DRAWER_WIDTH/4+2,r=DRAWER_CORNER_RAD);
		};

	difference() {
		translate([-DRAWER_WIDTH/8,0,-FLOOR_THICK])
			cube([DRAWER_WIDTH/4,DRAWER_CORNER_RAD,DRAWER_CORNER_RAD],center=false);
		translate([-DRAWER_WIDTH/8-1,DRAWER_CORNER_RAD,-FLOOR_THICK+DRAWER_CORNER_RAD]) rotate([0,90,0])
			cylinder(h=DRAWER_WIDTH/4+2,r=DRAWER_CORNER_RAD);
		};
};

module holes(width,height) {
	cols = width / hoff - DRAWER_CORNER_RAD;
	rows = height / voff - DRAWER_CORNER_RAD;

	translate([hoff*1.3,0,voff*2])
	for (i=[0:rows-1]) {
		for (j=[0:cols-1]){
			translate([j*hoff+i%2*(hoff/2),0,i*voff])
			rotate([90,90,0]) rotate([0,0,0]) cylinder(h=thick,r=india/2,$fn=6);
		}
	}
}

// translate([DRAWER_WIDTH/2+WALL_WIDTH+CLEARANCE,DRAWER_DEPTH/2,DRAWER_HEIGHT/2+FLOOR_THICK+CLEARANCE])
// drawerbase();
// handle();
// drawer1();
// drawer2();
// drawer3();
// drawer4();
// translate([-BOX_WIDTH/2,-BOX_DEPTH-thick,BOX_HEIGHT/2])
// drawerbox();
// holes(BOX_WIDTH,BOX_HEIGHT);
%cube([200,200,1],center=true);

// Library: boxes.scad
// Version: 1.0
// Author: Marius Kintel
// Copyright: 2010
// License: BSD

// roundedBox([width, height, depth], float radius, bool sidesonly);

// EXAMPLE USAGE:
// roundedBox([20, 30, 40], 5, true);

// size is a vector [w, h, d]
module roundedBox(size, radius, sidesonly)
{
  rot = [ [0,0,0], [90,0,90], [90,90,0] ];
  if (sidesonly) {
    cube(size - [2*radius,0,0], true);
    cube(size - [0,2*radius,0], true);
    for (x = [radius-size[0]/2, -radius+size[0]/2],
           y = [radius-size[1]/2, -radius+size[1]/2]) {
      translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
    }
  }
  else {
    cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
    cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
    cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);

    for (axis = [0:2]) {
      for (x = [radius-size[axis]/2, -radius+size[axis]/2],
             y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
        rotate(rot[axis])
          translate([x,y,0])
          cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
      }
    }
    for (x = [radius-size[0]/2, -radius+size[0]/2],
           y = [radius-size[1]/2, -radius+size[1]/2],
           z = [radius-size[2]/2, -radius+size[2]/2]) {
      translate([x,y,z]) sphere(radius);
    }
  }
}

```
drawer_box_v6_-_hex_pattern.scad:
```
/*

Customizable drawer box
Gian Pablo Villamil
August 4, 2014

v1 first iteration
v2 added drawer handle
v3 added full fillets, tweaked wall thickness and corner handling
v4 added text label
v5 added hex patterning on the sides
v6 added dimple stop to drawers and box

*/

use<write.scad>;

/* [Global] */

// Which one would you like to see?
part = "drawerbox"; // [drawer1:1 section drawer,drawer2:2 section drawer,drawer3:3 section drawer, drawer4:4 section drawer, drawerbox:drawer housing]

/* [Basic] */

// How many drawers?
NUM_DRAWERS = 5;

// How high?
DRAWER_HEIGHT = 15;

// How deep?
DRAWER_DEPTH = 59;

// How wide?
DRAWER_WIDTH = 80;

// Label on the drawer
MESSAGE = " ";

// Text height
TEXT_HEIGHT = 6;

/* [Pattern] */

india = 6 ;
spacing = 1.2;
dia = india + (spacing * 2);

hoff = india+spacing;
voff = sqrt(pow(hoff,2)-pow(hoff/2,2));

/* [Advanced] */

// Handle size?
HANDLE_SIZE = 10;

// Corner radius?
DRAWER_CORNER_RAD = 2;

// Clearance
CLEARANCE = 0.25;

// Wall thickness
WALL_THICK = 1.6;

// Floor thickness
FLOOR_THICK = 1.2;

// Rounded fillets?
FILLETS = true;

/* [Hidden] */

$fn = 32;
NOFILLETS = !FILLETS;
WALL_WIDTH = WALL_THICK + 0.001; // Hack to trick Makerware into making the right number of filament widths
INNER_FILLET = DRAWER_CORNER_RAD-(WALL_WIDTH/1.25);

BOX_HEIGHT = NUM_DRAWERS*(DRAWER_HEIGHT+CLEARANCE*2+WALL_WIDTH)+WALL_WIDTH;
BOX_WIDTH = DRAWER_WIDTH+CLEARANCE*2+WALL_WIDTH*2;
BOX_DEPTH = DRAWER_DEPTH+CLEARANCE+WALL_WIDTH;

thick = WALL_THICK + 0.2;
bumprad = 1;

earthick = 0.6;
earrad = 10 ;

//
print_part();

module print_part() {
	if (part == "drawer1") {
		drawer1();
	} else if (part == "drawer2") {
		drawer2();
	} else if (part == "drawer3") {
		drawer3();
	} else if (part == "drawer4") {
		drawer4();
	} else {
		drawerbox();
	}
}

module drawerbox() {
	translate([-BOX_WIDTH/2,-BOX_DEPTH/2,0])
	union () {
		difference () {
			cube([BOX_WIDTH,BOX_DEPTH,BOX_HEIGHT]);
			for (i=[0:NUM_DRAWERS-1]) {
				translate([WALL_WIDTH,-1,i*(DRAWER_HEIGHT+CLEARANCE*2+WALL_WIDTH)+WALL_WIDTH])
				cube([DRAWER_WIDTH+CLEARANCE*2,DRAWER_DEPTH+CLEARANCE+1,DRAWER_HEIGHT+CLEARANCE*2]);
			}
		translate([0,BOX_DEPTH+0.1,0])
		holes(BOX_WIDTH,BOX_HEIGHT);
		rotate([0,0,90]) translate([hoff/2,0.1,0]) holes(BOX_DEPTH,BOX_HEIGHT);
		rotate([0,0,90]) translate([hoff/2,-BOX_WIDTH+WALL_WIDTH+0.1,0]) holes(BOX_DEPTH,BOX_HEIGHT);
		}
		for (i=[0:NUM_DRAWERS-1]) {
			translate([BOX_WIDTH/2,DRAWER_CORNER_RAD*2,i*(DRAWER_HEIGHT+CLEARANCE*2+WALL_WIDTH)+WALL_WIDTH-0.1])
			{
				scale([1,1,0.9]) half_sphere(bumprad);
				translate([0,0,DRAWER_HEIGHT+CLEARANCE*2+0.2]) rotate([180,0,0])
				scale([1,1,0.9]) half_sphere(bumprad);
			}
		}

// mouse ears
translate([-earrad/2,BOX_DEPTH,-earrad/2]) rotate([90,0,0]) cylinder(r=earrad,h=earthick);
translate([BOX_WIDTH+earrad/2,BOX_DEPTH,-earrad/2]) rotate([90,0,0]) cylinder(r=earrad,h=earthick);
translate([-earrad/2,BOX_DEPTH,BOX_HEIGHT+earrad/2]) rotate([90,0,0]) cylinder(r=earrad,h=earthick);
translate([BOX_WIDTH+earrad/2,BOX_DEPTH,BOX_HEIGHT+earrad/2]) rotate([90,0,0]) cylinder(r=earrad,earthick);

	}
};

module drawer1() {
	difference() {
		drawerbase();
		 translate([0,0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH-(WALL_WIDTH*2),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
	}
};

module drawer2() {
	difference() {
		drawerbase();
		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
}
};

module drawer3() {
	difference() {
		drawerbase();
		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),0,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH-(WALL_WIDTH*2),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,DRAWER_DEPTH/4-WALL_WIDTH/4,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,-(DRAWER_DEPTH/4-WALL_WIDTH/4),FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
}

};

module drawer4() {
	difference() {
		drawerbase();
		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),DRAWER_DEPTH/4-WALL_WIDTH/4,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([-(DRAWER_WIDTH/4-WALL_WIDTH/4),-(DRAWER_DEPTH/4-WALL_WIDTH/4),FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,DRAWER_DEPTH/4-WALL_WIDTH/4,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);

		translate([DRAWER_WIDTH/4-WALL_WIDTH/4,-(DRAWER_DEPTH/4-WALL_WIDTH/4),FLOOR_THICK+DRAWER_CORNER_RAD/2])
			roundedBox([DRAWER_WIDTH/2-(WALL_WIDTH*1.5),DRAWER_DEPTH/2-(WALL_WIDTH*1.5),DRAWER_HEIGHT+DRAWER_CORNER_RAD],INNER_FILLET,NOFILLETS);
}};

module drawer6() {};

module drawerbase() {
	union() {
		difference() {
			translate([0,0,DRAWER_CORNER_RAD/2]) roundedBox([DRAWER_WIDTH,DRAWER_DEPTH,DRAWER_HEIGHT+DRAWER_CORNER_RAD],DRAWER_CORNER_RAD,NOFILLETS);
			translate([0,0,DRAWER_HEIGHT]) cube([DRAWER_WIDTH+1, DRAWER_DEPTH+1,DRAWER_HEIGHT],center=true);
			translate([0,-DRAWER_DEPTH/2+DRAWER_CORNER_RAD*2,-DRAWER_HEIGHT/2]) scale([1.2,1.2,1.]) sphere(bumprad);
			translate([0,DRAWER_DEPTH/2-DRAWER_CORNER_RAD*2,-DRAWER_HEIGHT/2]) scale([1.2,1.2,1.]) sphere(bumprad);
		}
	translate([0,-DRAWER_DEPTH/2,-DRAWER_HEIGHT/2+FLOOR_THICK])
	handle();

	translate([-DRAWER_WIDTH/2+DRAWER_CORNER_RAD,-DRAWER_DEPTH/2+0.5,-DRAWER_HEIGHT/4+DRAWER_CORNER_RAD/2]) rotate([90,0,0])
	write(MESSAGE,h=TEXT_HEIGHT,font="Orbitron.dxf");
	};
};

module handle() {

	difference() {
		roundedBox([DRAWER_WIDTH/4,HANDLE_SIZE*2,FLOOR_THICK*2],2,true);
		translate([0,HANDLE_SIZE,0]) cube([DRAWER_WIDTH/4+1,HANDLE_SIZE*2,FLOOR_THICK*2+1],center=true);
	};

	difference() {
		translate([0,-DRAWER_CORNER_RAD/2,FLOOR_THICK+DRAWER_CORNER_RAD/2])
			cube([DRAWER_WIDTH/4,DRAWER_CORNER_RAD,DRAWER_CORNER_RAD],center=true);
		translate([-DRAWER_WIDTH/8-1,-DRAWER_CORNER_RAD,FLOOR_THICK+DRAWER_CORNER_RAD]) rotate([0,90,0])
			cylinder(h=DRAWER_WIDTH/4+2,r=DRAWER_CORNER_RAD);
		};

	difference() {
		translate([-DRAWER_WIDTH/8,0,-FLOOR_THICK])
			cube([DRAWER_WIDTH/4,DRAWER_CORNER_RAD,DRAWER_CORNER_RAD],center=false);
		translate([-DRAWER_WIDTH/8-1,DRAWER_CORNER_RAD,-FLOOR_THICK+DRAWER_CORNER_RAD]) rotate([0,90,0])
			cylinder(h=DRAWER_WIDTH/4+2,r=DRAWER_CORNER_RAD);
		};
};

module holes(width,height) {
	cols = width / hoff - DRAWER_CORNER_RAD;
	rows = height / voff - DRAWER_CORNER_RAD;

	translate([hoff*1.3,0,voff*2])
	for (i=[0:rows-1]) {
		for (j=[0:cols-1]){
			translate([j*hoff+i%2*(hoff/2),0,i*voff])
			rotate([90,90,0]) rotate([0,0,0]) cylinder(h=thick,r=india/2,$fn=6);
		}
	}
}

module half_sphere(rad) {
	difference() {
		sphere(rad);
		translate([-rad,-rad,-rad])
		cube([rad*2,rad*2,rad]);
	}
}

// translate([DRAWER_WIDTH/2+WALL_WIDTH+CLEARANCE,DRAWER_DEPTH/2,DRAWER_HEIGHT/2+FLOOR_THICK+CLEARANCE])
// drawerbase();
// handle();
// drawer1();
// drawer2();
// drawer3();
// drawer4();
// translate([-BOX_WIDTH/2,-BOX_DEPTH-thick,BOX_HEIGHT/2])
// drawerbox();
// holes(BOX_WIDTH,BOX_HEIGHT);
// %cube([200,200,1],center=true);

// Library: boxes.scad
// Version: 1.0
// Author: Marius Kintel
// Copyright: 2010
// License: BSD

// roundedBox([width, height, depth], float radius, bool sidesonly);

// EXAMPLE USAGE:
// roundedBox([20, 30, 40], 5, true);

// size is a vector [w, h, d]
module roundedBox(size, radius, sidesonly)
{
  rot = [ [0,0,0], [90,0,90], [90,90,0] ];
  if (sidesonly) {
    cube(size - [2*radius,0,0], true);
    cube(size - [0,2*radius,0], true);
    for (x = [radius-size[0]/2, -radius+size[0]/2],
           y = [radius-size[1]/2, -radius+size[1]/2]) {
      translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
    }
  }
  else {
    cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
    cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
    cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);

    for (axis = [0:2]) {
      for (x = [radius-size[axis]/2, -radius+size[axis]/2],
             y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
        rotate(rot[axis])
          translate([x,y,0])
          cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
      }
    }
    for (x = [radius-size[0]/2, -radius+size[0]/2],
           y = [radius-size[1]/2, -radius+size[1]/2],
           z = [radius-size[2]/2, -radius+size[2]/2]) {
      translate([x,y,z]) sphere(radius);
    }
  }
}

```


[User]
I'm looking to create a phone mount for my 3D printer, specifically a Makerbot Replicator 2. I'd like it to be customizable so I can adjust it for different phones. The idea is a simple bracket that attaches to the printer's frame and holds the phone.

Here's the basic setup:

*   **Makerbot Frame:** I need to account for the frame's depth (53mm from front to interior), height (45mm from top to interior) and thickness (8mm panel thickness).
*   **Bracket:** The bracket itself will have a width of 7.5mm and wall thickness of 5mm.
*   **Phone Specs:** I need to be able to specify the phone's width and depth. Also, I'd like a small overhang parameter to adjust how far the bracket extends beyond the phone's edge.
*   **Mounting Options:** It would be great to have the option of mounting the phone either over the screen or over the back of the phone. This is just to account for how people use their phone.

Could you design an OpenSCAD file (or files if that makes sense) that does all this, using parameters for the different dimensions and the mounting option? I'm not tied to any specific libraries, so whatever you think is best would be fine. I am planning to use it to film time lapses, so the ability to hold the phone securely is important.

[Assistant]
phone_bracket.scad:
```
//Width of the bracket itself
bracket_width = 7.5;
//Thickness of the walls of the bracket
bracket_wall = 5;

//Makerbot frame depth (measured from the front to the interior)
depth = 53;
//Makerbot frame height (measured from the top to the interior)
height = 45;
//Makerbot frame thickness (the thickness of the panels)
thickness = 8;

//Width of your phone
phone_width = 80;
//Thickness of your phone
phone_depth = 9;
//Phone overhang
phone_overhang = 5;

//Does the phone mount go over the screen or the back?
_back_mount = 1; // [0:Front, 1:Back]
back_mount = _back_mount == 1;

/* [Hidden] */

linear_extrude(bracket_width) {
	square([bracket_wall, depth + bracket_wall * 2]);
	translate([bracket_wall, 0])
		square([height + bracket_wall, bracket_wall]);
	translate([height + bracket_wall, bracket_wall])
		square([bracket_wall, phone_depth + bracket_wall]);
	translate([bracket_wall, depth + bracket_wall])
		square([thickness, bracket_wall]);
	translate([bracket_wall * 2 + height + phone_width, 0])
		square([bracket_wall, phone_depth + bracket_wall * 2]);

	if(back_mount) {
		translate([bracket_wall + height, bracket_wall + phone_depth/*0*/])
			square([phone_width + bracket_wall * 2, bracket_wall]);
		translate([bracket_wall * 2 + height + phone_width - phone_overhang, 0/*bracket_wall + phone_depth*/])
			square([phone_overhang, bracket_wall]);
		translate([height + bracket_wall * 2, 0/*bracket_wall + phone_depth*/])
			square([phone_overhang, bracket_wall]);
	} else {
		translate([bracket_wall + height, 0])
			square([phone_width + bracket_wall * 2, bracket_wall]);
		translate([bracket_wall * 2 + height + phone_width - phone_overhang, bracket_wall + phone_depth])
			square([phone_overhang, bracket_wall]);
		translate([height + bracket_wall * 2, bracket_wall + phone_depth])
			square([phone_overhang, bracket_wall]);
	}
}
```


[User]
Okay, so I'm trying to design some customizable cable spools for 3D printing, and I'd like to have the design be parametric. I've got a basic idea of what I want, and I've even started on a basic OpenSCAD design to give you an idea of what I had in mind.

Essentially, I want a spool that consists of two main parts: an inner spool and an outer ring. The inner spool will have a central core where you wind the cable, and the outer ring will act as the flange that keeps the cable from falling off. I'd like to control the following dimensions:

**Spool Parameters:**

*   **Number of Sides (`ns`):** The spool should be a polygon, not a circle, and I'd like to be able to set the number of sides. Let's say from 6 to 16.
*   **Holder Frequency (`hn`):**  I want holders on the inner spool to secure cable ends. They should appear every *n* sides (like every third side), with *n* being adjustable between 2 and 4.
*   **Outer Diameter (`do`):** I'd need to be able to specify the total diameter of the spool. Let's start with a range from 50 to 250 mm.
*   **Inner Diameter (`di`):** This is the diameter of the inner core where cables are wound, and it needs to be less than half of the outer diameter. Let's say a range of 25 to 150 mm.
*   **Roll Diameter (`rs`):** This is the diameter of any center roll inside the inner core.  If set to 0, there's no center roll and the core diameter matches the `di`. I'd say range from 0 to 140 mm.

**Printing Parameters:**

*   **Wall Height (`wh`):**  The thickness of the spool "walls", for both the inner and outer parts, with a range of 1 to 10 mm.
*   **Wall Width (`ww`):** The width of the walls (thickness of the plastic in the horizontal plane), let's say range from 2 to 10 mm.
*   **Spool Height (`sh`):** The height of the inner spool section where the cable goes. This should be range of 20 to 100 mm.
*   **Fit (`fit`):** A small amount of space for parts to fit together, let's stick with 0.15 mm for now.

**Global Parameter:**

*   **Show (`show`):** I need to be able to select which parts to render, and it should be one of three options: `"i"` (inner spool only), `"o"` (outer ring only), or `"b"` (both parts).

So, my requirements for the OpenSCAD code are that:

1.  It should create the inner and outer spool parts based on these parameters.
2.  The inner spool should have holders on its perimeter, based on the `hn` value.
3.  The outer ring should have tabs to fit in the inner spool, if needed.
4.  All dimensions should be calculated correctly to ensure the parts fit together and are easily printed.
5. The code should be parametric to use in the customizer.

It would also be awesome if you could add comments in the code so I understand how everything works. I don't think you'd need any external libraries, but if you do, please let me know what they are and why.

Could you generate the OpenSCAD file(s) for this?

[Assistant]
CableSpool2.scad:
```
/////////////////Parameters
/* [Sizes] */
// number of sides
ns = 9; // [6:16]
// holder every n sizes
hn = 3; // [2:4]
// outer diameter
do	= 180; // [50:250]
// inner diameter should be smaller than half of outer diameter
di = 90; // [25:150]
// roll diameter inside, if 0 then no isnide roll and inner diameter =roll
rs = 45; // [0:140]
/* [Printer_Opts] */
// height of walls and spool
wh = 3; // [1:10]
// width of walls - outer and inside
ww = 5; // [2:10]
// height of spool inside
sh = 50; // [20:100]
// spacing to fit parts
fit= 0.15;
/* [Global] */
// which spool parts to show
show = "b"; // [i:Inner spool,o:Outer spool,b:Both spools]
/* [Hidden] */

//////////////////Calculations

$fn=120;
ms = 0.05;

or = do/2;
ir = di/2;

irs = (rs!=0)? rs/2 : ir;

aw = 360/ns;
aw2 = aw/2;
bw = (180-aw)/2;
bw2 = (180-aw2)/2;

//echo("aw:",aw," bw:",bw," aw2",aw2);

g = irs+ww+wh+ww+fit;
a = sqrt(2*g * g - 2 * g * g * cos(aw2));
x = g*(ww-2*a)/(2*(a-g));
//echo("g:",g," a:",a," x:",x);

go = or-ww-ww/2;

ao = a*go/g - ww;
as = sin(bw2)*ao;
ac = cos(bw2)*ao;

gi = ir+wh/2;
ai = sqrt(2*gi*gi - 2*gi*gi*cos(aw));
//echo("gi:",gi," ai:",ai," x:",x);

module ring() {

	difference() {
		cylinder(h=wh,r=or,center=true);
		cylinder(h=wh+ms,r=irs,center=true);

		intersection() {
			for(i = [aw:aw:360+ms]) {
				rotate([0,0,i]) translate([g+x,0,0])
					hull() {
						cylinder(h=wh+ms,r=x,center=true);
						translate([go-g-x+ww,0,0])
							cylinder(h=wh+ms,r=ww/2,center=true);
						translate([go-g-x-ac,-as,0])
							cylinder(h=wh+ms,r=ww/2,center=true);
						translate([go-g-x-ac,as,0])
							cylinder(h=wh+ms,r=ww/2,center=true);
					}
			}
			cylinder(h=wh+ms+ms,r=or-ww,center=true);
		}
	}
}

module inner_ring() {

	ring();
	translate([0,0,sh/2]) {
		difference() {
			cylinder(h=sh+wh,r=ir+wh,center=true);
			cylinder(h=sh+wh+ms,r=ir,center=true);
			for(i = [aw:aw:360+ms]) {
				rotate([0,0,i])
					translate([gi,0,-wh/2]) difference() {
						cube([4*wh+ms, ai-ww-wh/2,sh+wh-ww-ww],center=true);
						if (i/aw/hn == floor(i/aw/hn)) {
							translate([0,0,-wh/2])
								cube([4*wh, ai-ww-wh,sh-ww-ww+ms],center=true);
						}
					}
			}
		}
		intersection() {
			rotate_extrude($fn=200)
				polygon( points=[[ir,sh/2-4*wh],[ir+2*wh-fit,sh/2-3*wh],[ir,sh/2-wh]] );
			for(i = [aw:aw:360+ms]) {
				rotate([0,0,i])
					translate([gi,0,wh/2]) {
//						echo(i,aw,hn,i/aw/hn,floor(i/aw/hn));
						if (i/aw/hn == floor(i/aw/hn))
							translate([0,0,-wh/2])
								cube([wh*4, ai-ww-wh,sh-ww-ww-wh+ms],center=true);

				}
			}
		}
		if (rs!=0) translate([0,0,-sh/2])
			difference() {
				translate([0,0,sh/2])
					cylinder(h=sh+wh,r=rs/2+wh,center=true);
				translate([0,0,sh/2])
					cylinder(h=sh+wh+ms+ms,r=irs,center=true);
		}
	}
}

module outer_ring() {
	ring();

	translate([0,0,3*wh-ms]) {
		difference() {
			cylinder(h=7*wh,r=ir+wh+wh+fit,center=true);
			cylinder(h=7*wh+ms,r=ir+wh+fit,center=true);
			for(i = [aw:aw:360+ms]) {
				rotate([0,0,i])
					translate([ir+wh,0,-wh/2])
						cube([sin(aw)*gi+ms, ai-ww,4*wh],center=true);

			}
		}
	}
}

if(show=="i" || show=="b")
	inner_ring();

if (show=="o")
	outer_ring();

if (show=="b")
	translate([0,0,sh+wh+fit]) rotate([180,0,0]) #outer_ring();

```


[User]
I'd like a parametric OpenSCAD design for a net pot, which is basically a tapered cup with vent holes. I want to be able to specify a few key parameters.

First, I need to control the overall shape of the pot. I want to define a `diameter` for the top of the pot, and a `height`. It should taper from the top diameter down to a smaller diameter at the base using a `ratio` parameter that expresses the base diameter as a fraction of the top diameter. I'll also need to specify a `wall` thickness for the pot's material.

The pot needs vent holes all around the main body. The holes can be either square or cylindrical, controlled by a `shape` parameter set to either "cube" for square or "cylinder" for round. Their size should be controlled by a `size` parameter, defining the side length of the square or the diameter of the circle. The holes should be arranged in vertical columns spaced evenly around the circumference of the pot. The vertical spacing of the holes should also be controlled by the `size` parameter, and there should be a slight vertical stagger as they go down due to the taper. I guess a good spacing calculation would be to leave a gap equal to half the size of the hole.

Finally, I want a separate brim that can be added or omitted. It should be a ring that sits flush on top of the main pot body with an outer and inner ring, sort of like a flange. The brim should be controlled by two parameters, `girth` defining the width of the brim beyond the pot's edge, and `thickness` of the brim's material. I need to be able to select either to create the main pot body (without brim), just the brim, or both parts at once.

I'd like the design to be relatively smooth, so a `$fn` setting of 24 would be good. I think this captures all the parameters. Thanks!

[Assistant]
netpot.scad:
```
// configured
// part
which = "both"; // [pot:pot,brim:brim,both:both]
// top
diameter = 50;
// height
height = 25;
// taper
ratio = .75;
// thickness
wall = 2;
// mesh hole
size = 6.5;
// hole
shape = "cube"; // [cube:Square,cylinder:Circle]
// smoothing
$fn = 24;
// brim
girth=3;
// brim
thickness=2;
// derived
radius = diameter / 2;
circumference = PI * diameter;
// function
function space() = shape=="cube" ? size / 1.4142 : size;
// procedures
main();
module main() {
	both = which == "both";
	if (both || which == "pot") {
		difference() {
			pot();
			mesh();
		}
	}
	if (both || which == "brim") {
		brim();
	}
}
module brim() {
	position = diameter + radius;
	translate([0,0,thickness])
	difference() {
		translate([position, 0, -thickness])
			cylinder(r = radius + wall + girth, h = thickness);
		translate([position, 0, -height + wall])
			cup(radius);
	}
}
module mesh() {
	// perforate vessel
	// fit as many as can be around in a row, the smallest row
	count = circumference * ratio / (space() + space() / 2);
	step = 360 / count;
	for (i = [0 : step : 360 - step]) {
		rotate([0, 0, i]) {
			holes();
		}
	}
}
module holes() {
	// single column of holes
	// fit as many as can be top to bottom in a column
	steps = (height - wall) / (space() + space() / 2);
	stepsize = space() + space() / 2;
	// do not overlap these and create many unions or gcal will choke (#350)
	// stagger inward based on taper
	offset = (diameter - (diameter * ratio)) / steps / 2;
	function stagger(_i) = (steps - _i) * offset;
	for(i = [1 : 1 : steps]) {
		translate([0, stagger(i), stepsize * i - space() / 2])
			shaft();
	}
}
module shaft() {
	// single hole
	rotate([90, 45, 0]) {
		if (shape == "cube") {
			translate([0, 0, radius])
			cube([space(), space(), radius / 2], center = true);
		}
		else {
			translate([0, 0, radius])
			cylinder(r = space()/2, h = radius / 2, center = true );
		}
	}
}
module pot() {
	// create vessel and hollow it
	difference() {
		cup(radius);
		translate([0, 0, wall])
			cup(radius - wall);
		translate([0,0,height])
			cylinder(r = radius + wall, h=wall);
	}
}
module cup(_radius) {
	// create tapered shape
	hull() {
		cylinder(r = _radius * ratio);
		translate([0, 0, height]) cylinder(r = _radius);
	}
}

```


[User]
Okay, I'd like to design a customizable loom for making those rubber band bracelets, you know, like a Rainbow Loom. I'd like it to be parametric so I can change the size easily.

Here's what I'm thinking:

The loom should have a rectangular base with pins sticking up. I need to be able to control:
*   The number of pins along the length and width of the loom.
*   The spacing between the pins. I want to control the spacing along the length and across the width separately.
*   Whether the pins are staggered or in a grid.
*   The thickness of the base.
*   The diameter of the narrow part of the pin, as well as the top and bottom wider parts.
*   The height of the pins, and the heights of the wider top and bottom sections of each pin.
*   The diameter of the hole up through the center of the pin.
*  A tolerance variable for between mating parts.

I'd also like to add connectors to the ends and sides of the base so I can connect multiple looms together. These connectors should have both male and female parts, and I should be able to control the diameter of the connectors and the amount that the connector overlaps the base of the loom.

Finally, I want a set of arrows on one side of the loom to indicate the direction to weave.

Can you make an OpenSCAD file that has all of these parameters?

[Assistant]
LoomCust.scad:
```
// Customizeable Loom Band Loom
// TrevM 10/08/2014

/* [Global] */

// What quality?
$fn = 30;	// [20,30,40,50,60,70,80,90,100]

// Pin spacing accross loom (x)
Pin_Space_Acc = 16.5;

// Pin spacing along loom (y)
Pin_Space_Alo = 25;

// Number of pins along length
NumPinsL = 7;	// [2:10]

// Number of pins accross
NumPinsW = 4;	// [2:10]

// Pins Staggered?
Staggered = 1;	// [0:No,1:Yes]

// End connects?
End_Connects = 1;	// [0:No,1:Yes]

// Side connects?
Side_Connects = 1;	// [0:No,1:Yes]

// Tolerance (space between mating surfaces)
Tol = 0.5;

// Base Thickness?
Base_Th = 7;	// [2:30]

// Pin Diameter (centre part)
Pin_Narrow = 8;	// [1:20]

// Pin Hole Diameter (hole up centre of pin)
Pin_Hole = 4;	// [1:20]

// Pin Diameter (top and bottom)
Pin_Wide = 10;	// [1:20]

// Pin Height (total, base to top)
Pin_Hi = 15;	// [1:50]

// Pin Base Height (wide bit at bottom of pin)
Pin_Base = 4;	// [1:50]

// Pin Top Height (wide bit at top of pin)
Pin_Top = 3;	// [1:50]

// Connector Diameter (male & female)
Conn = 9;		// [1:20]

// Connector Offset (overlap with base)
Conn_Off = 2;	// [0:20]

/* [Hidden] */

// spacing
spw=Pin_Space_Acc;	// spacing width
spl=Pin_Space_Alo/2;	// spacing length

// base dims
bll=(NumPinsL*2*spl)+(Staggered*spl);
blw=NumPinsW*spw;

// pin dims
PinN=Pin_Narrow/2;
PinW=Pin_Wide/2;
PinD=PinW-PinN;
PinH=Pin_Hole/2;

ConR=Conn/2;
TolH=Tol/2;

loom();

module loom()
{
	base();
	for(x=[1:NumPinsW])
	{
		for(y=[1:NumPinsL])
			eachPeg(x,y);
	}
	for(a=[1:NumPinsW])
		eachArrow(a);
}

module base()
{
	translate([-blw/2,-bll/2,0])
	{
		difference()
		{
			union()
			{
				// shamfered base block
				polyhedron(
					points=[
						// base
						[1+TolH,		1+TolH,		0],		//lb
						[blw-1-TolH,	1+TolH,		0],		//rb
						[blw-1-TolH,	bll-1-TolH,	0],		//rt
						[1+TolH,		bll-1-TolH,	0],		//lt
						// top
						[TolH,			TolH,		1.1],	//lb
						[blw-TolH,		TolH,		1.1],	//rb
						[blw-TolH,		bll-TolH,	1.1],	//rt
						[TolH,			bll-TolH,	1.1]],	//lt
					faces=[
						[0,1,2,3],					//bot
						[7,6,5,4],					//top
						[4,5,1,0],					//near
						[5,6,2,1],					//left
						[3,2,6,7],					//far
						[7,4,0,3]]);				//right
				// main base block
				translate([TolH,TolH,1])
					cube([blw-Tol,bll-Tol,Base_Th-1]);
			}
			if (End_Connects==1)
			{
				for(c=[1:NumPinsW-1])
					doEndFem(c,c*spw,+ConR-Conn_Off);
			}
			if (Side_Connects==1)
			{
				for(c=[1:NumPinsL-1])
					doSideFem(c,ConR-Conn_Off,c*spl*2);
			}
		}
		if (End_Connects==1)
		{
			for(c=[1:NumPinsW-1])
				doEndMale(c,c*spw,bll+ConR-Conn_Off);
		}
		if (Side_Connects==1)
		{
			for(c=[1:NumPinsL-1])
				doSideMale(c,blw+ConR-Conn_Off,c*spl*2);
		}
	}
}

module doSideFem(n,x,y)
{
	e=floor(n/2);
	even=n-(e*2);
	//echo("n=",n," even=",even);
	if (even==0)
		Fem(x,y);
}

module doEndFem(n,x,y)
{
	e=floor(n/2);
	even=n-(e*2);
	//echo("n=",n," even=",even);
	if (even==1)
		Fem(x,y);
}

module Fem(x,y)
{
	translate([x,y,-0.1])
	{
		//cylinder(r=ConR,h=Base_Th+0.2);
		cylinder(r1=ConR+1+TolH,r2=ConR+TolH,h=1.2);
		translate([0,0,1.1])
			cylinder(r=ConR+TolH,h=Base_Th-0.9);
	}
}

module doSideMale(n,x,y)
{
	e=floor(n/2);
	even=n-(e*2);
	//echo("n=",n," even=",even);
	if (even==0)
		Male(x,y);
}

module doEndMale(n,x,y)
{
	e=floor(n/2);
	even=n-(e*2);
	//echo("n=",n," even=",even);
	if (even==1)
		Male(x,y);
}

module Male(x,y)
{
	translate([x,y,0])
	{
		cylinder(r1=ConR-1-TolH,r2=ConR-TolH,h=1.1);
		translate([0,0,1])
			cylinder(r=ConR-TolH,h=Base_Th-1);
	}
}

module eachPeg(x,y)
{
	even = floor((x-1)/2);
	exy = x-1-(even * 2);
	posx = ((x-1)*spw)+(spw/2);
	posy = ((y-1)*spl*2)+spl;
	//echo("x=",x," y=",y," even=",even," exy=",exy," posx=",posx," posy=",posy);
	if (Staggered == 0)
		peg(posx,posy);
	else
		peg(posx,posy+(exy*spl));
}

module peg(posx,posy)
{
	translate([posx-(blw/2),posy-(bll/2),Base_Th-0.1])
	{
		difference()
		{
			union()
			{
				cylinder(r=PinN,h=Pin_Hi+0.1);		// narrow
				cylinder(r=PinW,h=Pin_Base+0.1);		// base
				// base shamfer
				if (PinD > 0)
				{
					translate([0,0,Pin_Base])
						cylinder(r1=PinW,r2=PinN,h=PinD);
				}
				translate([0,0,Pin_Hi-Pin_Top+0.1])
					cylinder(r=PinW,h=Pin_Top);		// top
				// top shamfer
				if (PinD > 0)
				{
					translate([0,0,Pin_Hi-Pin_Top+0.1-PinD])
						cylinder(r1=PinN,r2=PinW,h=PinD+0.1);
				}
			}
			translate([0,0,-0.1])
			{
				cylinder(r=PinH,h=Pin_Hi+0.3);			// hole
				translate([-PinH,0,0])
					cube([PinH*2,PinW,Pin_Hi+0.3]);		// slot
				translate([-PinW-0.1,PinH,0])
					cube([(PinW+0.1)*2,PinW,Pin_Hi+0.3]);	// slice
			}
		}
	}
}

module eachArrow(x)
{
	even = floor((x-1)/2);
	exy = x-1-(even * 2);
	posx = ((x-1)*spw)+(spw/2);
	posy = spl;
	if (Staggered == 0)
		arrow(posx,posy);
	else
		arrow(posx,posy+(exy*spl));
}

module arrow(x,y)
{
	thk=2;
	translate([x-(blw/2),y-(bll/2),Base_Th-1])
	{
		// shaft
		translate([-PinH,PinW,0])
			cube([PinH*2,spl-PinW,thk]);
		// head
		polyhedron(
			points=[
				// base
				[-PinW,spl-0.1, 0],	//lb
				[ PinW,spl-0.1, 0],	//rb
				[ 0   ,spl+PinW,0],	//tip
				// top
				[-PinW,spl-0.1, thk],	//lb
				[ PinW,spl-0.1, thk],	//rb
				[ 0   ,spl+PinW,thk]],	//tip
			faces=[
				[1,0,2],						//bot
				[3,4,5],						//top
				[0,1,4,3],						//base
				[1,2,5,4],						//left
				[0,3,5,2]]);					//right
	}
}

```


[User]
Okay, I'm looking to create a parametric spool holder for my Makerbot Replicator 5th Generation, similar to the one described in the Thingiverse link. The key is that it needs to clip onto the printer's frame and hold a spool using a separate tube-like support. I want to be able to customize the spool holder for different spool sizes.

Specifically, I need two main parts:

1.  A **wall support clip** that attaches to the top of the printer's side wall. This part should have a clip that hooks onto the frame, and a section where the spool support tube will slide into. I would like two versions of this clip, one which is straight and one which is angled at 45 degrees from the wall.

2.  A **spool support** consisting of a base plate, a tube which the spool fits onto, and a collar at the top to keep the spool in place. The tube's diameter and depth should be parametric. I'll need a support triangle to strengthen where the tube joins the base plate. The design should allow for re-use of the wall clips.

The design needs to be fully parametric, allowing me to change:

*   **`SpoolHoleDiameter`**: The diameter of the hole in the center of the spool.
*   **`SpoolDepth`**: The width of the spool.
*   **`angled`**: A boolean value determining if the wall clip should be angled or straight.
*   **`part`**: To print either `Both` parts, only the `Wall` support, or only the `Spool` support.

I'd also like these parameters to be available, though with default values specified:

*   **`SideTrackWidth`**: Width of the side track. (Default: `3.0`)
*   **`SideTrackHeight`**: Height of the side track. (Default: `5.0`)
*   **`SideTopHeight`**: Height of the side top. (Default: `6.0`)
*  **`TubeThickness`**: Thickness of the tube walls. (Default: `4.0`)
*   **`TubeCollarWidth`**: Width of the tube collar. (Default: `5.0`)
*   **`TubeCollarHeight`**: Height of the tube collar. (Default: `2.0`)
*  **`TubeBaseClearance`**: Space between the tube base and baseplate edges. (Default:`3.0`)
*   **`TubeBaseSlippage`**: Allowance for slippage between tube base and side rail. (Default: `0.5`)
*   **`SpoolPrintOffset`**:  Offset of the spool from the wall support. (Default: `30`)

I'd like to use the `cube()`, `cylinder()`, `translate()`, `rotate()`, and `difference()` primitives. I also would like to use a custom `tube()` module which constructs a hollow cylinder, and a custom `box()` module to generate cubes with the center of the box at the origin. Finally, I'd like a `rightTriangle()` module that takes three parameters: adjacent, opposite and depth. I don't anticipate needing any external libraries for this project.

Could you provide me with the OpenSCAD code for this?

[Assistant]
gen5_parametric_spindle_clip.scad:
```
/* Uses OpenSCAD 2012.04.04

Parametric Replicator Spool Holder
==================================

Based on http://www.thingiverse.com/thing:20710

Modified for the Makerbot Replicator 5th Generation.
Updated to allow re-use of the clip.

This program renders 2 parts which allow for the mounting of non-standard spools on the Makerbot Replicator 5th Generation.

Part 1 is a right hand side wall support panel which clips around the top support wall.

Part 2 is a mounting tube and base which slides into the wall support panel and allows for the mounting of
the spool.

Both Part 1 and 2 can be customised for spools by changing the value of variables below.

The main variables which need to be customised are:

	SpoolHoleDiameter
	SpoolDepth

The "Layout" variable can be set to "Both", "Wall" or "Spool" to render the parts required for printing.

The Part 1 wall support panel can be Mirrored in ReplicatorG or Makerware to print for the right hand side spool.

*/

/* [Global] */

// What do you want to print?
part = "Both";	  //  [Both:Both, Wall:Wall, Spool:Spool]

// Do you want an angled spool?
angled = "yes";  //  [yes, no]

// Diameter of Hole in Center of Spool (52.0 for Makerbot)?
SpoolHoleDiameter = 52.0;  // Settings for Makerbot Spools.

// Width of Spool (80.0 for Makerbot)?
SpoolDepth = 80.0;

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

print_part();

module print_part() {
	if (part == "Both") {
       if (angled == "yes") {
         AngledWallSupport();
       } else {
		  WallSupport();
       }
		SpoolSupport();
	} else if (part == "Wall") {
		if (angled == true) {
         AngledWallSupport();
       } else {
		  WallSupport();
       }
	} else {
		SpoolSupport();
	}
}

/*
===========  OpenSCAD Shapes Library (www.openscad.at)
===========  Copyright (C) 2009  Catarina Mota <clifford@clifford.at>
*/

module tube(height, radius, wall) {
	difference(){
		cylinder(height, radius, radius,$fa=1);
		cylinder(height, radius-wall, radius-wall);
	}
}

module box(w,h,d) {
	scale ([w,h,d]) cube(1, true);
}

//-----------------------
//MOVES THE ROTATION AXIS OF A BOX FROM ITS CENTER TO THE BOTTOM LEFT CORNER
module dislocateBox(w,h,d){
	translate([w/2,h,0]){
		difference(){
			box(w, h*2, d+1);
			translate([-w,0,0]) box(w, h*2, d+1);
		}
	}
}

module rightTriangle(adjacent, opposite, depth) {
	difference(){
		translate([-adjacent/2,opposite/2,0]) box(adjacent, opposite, depth);
		translate([-adjacent,0,0]){
			rotate([0,0,atan(opposite/adjacent)]) dislocateBox(adjacent*2, opposite, depth);
		}
	}
}
/*
  ==============================================================================
   MAIN CODE
  ==============================================================================
*/

//--  Standard Build Variables.
SideTrackWidth = 3.0 * 1;
SideTrackHeight = 5.0 * 1;
SideTopHeight = 6.0 * 1;
TubeThickness = 4.0 * 1;
TubeCollarWidth = 5.0 * 1;
TubeCollarHeight = 2.0 * 1;
TubeBaseClearance = 3.0 * 1;									// Space between edge of baseplate and tube.
TubeBaseSlippage = 0.5 * 1;									// Slippage between tube base plate and side rail.

//--  Calculated Dimensions

SpoolPrintOffset = 30 * 1;									// Offset of Spool from Wall Support for print layout

SpoolBaseplateDepth = SideTrackHeight - 0.4;
SpoolBaseplateXorY = 52.0 + (TubeBaseClearance * 2);

//-- Wall Support Panel.

module WallSupport() {
  overhang_x = 48.1;
  overhang_z = 36;
  clip_x = 4;
  clip_y = 60;
  clip_z = 4;

  wall_thickness = 4;

  support_slider_gap = 5;
  support_slider_edge_thickness = 6;
  support_slider_edge_z = 3;
  support_slider_z = 59;
  support_z = support_slider_z + (wall_thickness * 2);

  translate([24,-3,0]) {
  rotate([90, 0, 0]) {
    cube([overhang_x + wall_thickness, clip_y, wall_thickness]);

    translate([0,0,wall_thickness])
      cube([wall_thickness, clip_y, overhang_z + wall_thickness]);

    translate([0,0,overhang_z + wall_thickness])
      cube([clip_x + wall_thickness, clip_y, wall_thickness]);

    translate([clip_x + wall_thickness, 0, overhang_z])
      cube([2, clip_y, clip_z + wall_thickness]);

    translate([overhang_x + wall_thickness, 0, 0])
      cube([wall_thickness, clip_y, support_z]);

    translate([overhang_x + (wall_thickness * 2), 0, 0])
      cube([support_slider_gap, clip_y, wall_thickness]);

    translate([overhang_x + (wall_thickness * 2) + support_slider_gap, 0, 0])
      cube([support_slider_edge_thickness, clip_y, support_slider_edge_z + wall_thickness]);

    translate([overhang_x + (wall_thickness * 2), 0, support_z - wall_thickness])
      cube([support_slider_gap, clip_y, wall_thickness]);

    translate([overhang_x + (wall_thickness * 2) + support_slider_gap, 0, support_z - (support_slider_edge_z + wall_thickness)])
      cube([support_slider_edge_thickness, clip_y, support_slider_edge_z + wall_thickness]);
  }}
}

module AngledWallSupport() {
  overhang_x = 48.1;
  overhang_z = 36;
  clip_x = 4;
  clip_y = 60;
  clip_z = 4;

  wall_thickness = 4;

  support_slider_gap = 5;
  support_slider_edge_thickness = 6;
  support_slider_edge_z = 3;
  support_slider_z = 59;
  support_z = support_slider_z + (wall_thickness * 2);

  rotate([90, 0, 0]) {
    cube([20 + wall_thickness, clip_y, wall_thickness]);

    translate([0,0,wall_thickness])
      cube([wall_thickness, clip_y, overhang_z + wall_thickness]);

    translate([0,0,overhang_z + wall_thickness])
      cube([clip_x + wall_thickness, clip_y, wall_thickness]);

    translate([clip_x + wall_thickness, 0, overhang_z])
      cube([2, clip_y, clip_z + wall_thickness]);

    translate([overhang_x + wall_thickness, 0, 33.5])
      cube([wall_thickness, clip_y, 20]);

    translate([-28.3, 0, 27]) {
      rotate([0,45,0]){
        translate([overhang_x + wall_thickness, 0, 0])
          cube([wall_thickness, clip_y, support_z]);

        translate([overhang_x + (wall_thickness * 2), 0, 0])
          cube([support_slider_gap, clip_y, wall_thickness]);

        translate([overhang_x + (wall_thickness * 2) + support_slider_gap, 0, 0])
          cube([support_slider_edge_thickness, clip_y, support_slider_edge_z + wall_thickness]);

        translate([overhang_x + (wall_thickness * 2), 0, support_z - wall_thickness])
          cube([support_slider_gap, clip_y, wall_thickness]);

        translate([overhang_x + (wall_thickness * 2) + support_slider_gap, 0, support_z - (support_slider_edge_z + wall_thickness)])
          cube([support_slider_edge_thickness, clip_y, support_slider_edge_z + wall_thickness]);
      }
    }
  }
}

module BasePlate() {

	color("red") translate([SpoolPrintOffset, SideTrackWidth, 0])
	cube([SpoolBaseplateXorY,SpoolBaseplateXorY,SpoolBaseplateDepth]);

}

module MainTube() {

 	difference(){

    	color("Yellow")
		translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SideTrackWidth + (SpoolBaseplateXorY / 2.0),SpoolBaseplateDepth-0.01])
		tube(SpoolDepth + SideTopHeight + 1.0,SpoolHoleDiameter/2.0,TubeThickness);

		color("Orange")
		//  Leave 15mm lower collar to strengthen printing.
    	translate([SpoolPrintOffset,0,15])
		cube([SpoolBaseplateXorY,(SpoolBaseplateXorY  + TubeBaseClearance)/2,SpoolDepth  + SideTopHeight + 1.0 + TubeCollarWidth ]);
  }
}

module UpperCollar() {

	difference(){
    	color("SkyBlue")
 		translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SideTrackWidth + (SpoolBaseplateXorY / 2.0),SpoolDepth  + SideTopHeight + 1.0])
		tube(TubeCollarWidth,(SpoolHoleDiameter + TubeCollarHeight)/2.0,TubeCollarHeight);

    	translate([SpoolPrintOffset,0,0])
		cube([SpoolBaseplateXorY,(SpoolBaseplateXorY  + TubeBaseClearance)/2,SpoolDepth + SideTopHeight + 1.0 +TubeCollarWidth]);
  }
}

module SupportTriangle() {

	color("pink");
    y_offset = (SpoolBaseplateXorY - SpoolHoleDiameter) / 2.0;
	translate([SpoolPrintOffset + (SpoolBaseplateXorY /2.0),SpoolBaseplateXorY - y_offset,SpoolBaseplateDepth-0.01]) rotate ([0,90,180])
	rightTriangle(SpoolDepth,SpoolHoleDiameter - TubeBaseClearance,TubeThickness);

}

//--	Spool Tube and support base.

module SpoolSupport() {

	BasePlate();
	MainTube();
	UpperCollar();
	SupportTriangle();
}

```


[User]
I'd like to design a parametric PowerPole distribution box for my amateur radio gear. I want to be able to specify how many PowerPole connectors are on the top of the box, with one always on the side. I'd also like to control the thickness of the case.

The design should use the standard Anderson PowerPole dimensions. I've found some code online (I'm including the full code in this prompt for reference, but assume you're designing this from scratch) that includes a pretty good model of the PowerPole connector itself (a "twoPole" module in the attached code). That has to be accurate. The PowerPole connectors on the top should be equally spaced. I'd like to specify the spacing between the connectors on top. There should be enough space within the box for a secure fit, but not too much empty volume - basically like the "internalCavity" from the provided code.

The box needs to be designed in two halves, with pins on one half and matching holes in the other half for easy assembly. The "pins/pins.scad" library from the provided code is where the code for the pins and holes is located - I assume it's ok to use that as well. I want a little bit of slop for the pins and holes, as shown in that code.

So, to summarize, I'd like to be able to specify:

*   The number of PowerPole pairs on the top (e.g., 2, 3, 4, etc.).
*   The thickness of the case.
*   The spacing between the PowerPole pairs on top.

I need the design to include the following features:
*   One PowerPole pair on the side of the box.
*   The specified number of PowerPole pairs on the top of the box.
*   The correct spacing between PowerPole connectors, as well as the internal spacing so the connectors will fit and the pins will make proper contact.
*   A case designed in two halves with integrated pins on one half and pin holes on the other.
*   The case should be reasonably minimal. I don't need a big chunky box, but there should be enough material to make it structurally sound.

Also, could you make sure that both halves of the box are oriented for easy 3D printing? This means that the open part of the box should face upwards for each half.

I need the model to be in two separate SCAD files. One file (let's call it `powerpole_box_sideA.scad`) should be the half of the box with the pins, and the other (`powerpole_box_sideB.scad`) should be the half with the holes. Thanks so much!

[Assistant]
Parametric_PowerPole_Breakout.scad:
```
// PowerPole Splitter Builder (Vertical)
// Michael Glover, AE5ZC <ae5zc@arrl.net>
//  with additional suggestions from Matt Barlow, W5VO
// August 10, 2014
// Released under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// Creative Commons license: http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
// License summary: http://creativecommons.org/licenses/by-nc-sa/3.0/
//
// Note: Customizer doesn't support the "children" command, so... this will have to be hacked before
//   it works in customizer on Thingiverse.

use<pins/pins.scad> // For the snap pins

/* [Global] */
// There will be one PowerPole pair on the side. How many PowerPole pairs on top?
powerPoleCount = 4;	// [2:8]

// How thick should the outer shell be?
caseThickness = 3; // [2:4]

/* [Hidden] */
$fn=360; // How smooth are circles?
ppLength = 24.5; // Length of a PowerPole connector
ppWidth = 16; // Length of a PowerPole connector (one pair)
ppHeight = 8; // Height of a PowerPole connector
numSides = 360; // How "smooth" is the circular case?
ppSpacing = 3; // Spacing between PowerPoles on top (3 or 4 yields good pin spacing/contact)
internalCavity = 5; // Spacing in cavity between horizontal PowerPole and others; 5=good pin spacing
caseHeight = caseThickness + ppHeight + internalCavity + ppLength;
caseLength = ppLength + (ppHeight+ppSpacing) * powerPoleCount + ppLength + ppHeight/2;
caseWidth = caseThickness*2 + ppWidth;

module powerPoleShell(centerPin=true) {
	myh=8;
	myr=myh/2;
	factor = 3;
	myCube = [myh*factor,myh*factor,myh*factor];

	// Union to make a PowerPole "shell" better suited for subtracting
	union() {
		translate([0,0,-ppHeight/2]) twoPole();
		translate([ppLength/4,-ppHeight,-ppHeight/2]) cube([ppLength/4,ppWidth,ppHeight]);
		translate([-ppLength/2-1,-ppHeight,-ppHeight/2]) cube([ppLength/2+1,ppWidth+.5,ppHeight+.5]);
		if (centerPin == false) {
			translate([0,0,0]) cylinder(h=ppHeight,r=5,center=true);
		}
	}
}

module caseCube() {
	cube([caseLength,caseWidth,caseHeight]);
}

module caseShell() {
	reducePlastic()
	subtractCavity()
		difference() {
			difference() {
				caseCube();
				translate([12,caseWidth/2,ppHeight/2+caseThickness])
					rotate([0,0,180]) powerPoleShell(centerPin=false);

				// Very subtle effect here. @i=0, you get ppLength+ppHeight
				//  but, since the PowerPoles are rendered centered, the resulting shift is only
				//  ppHeight/2 (which is about 4 mm).
				for(i=[0:1:powerPoleCount-1]) {
					translate([ppLength+ppHeight+(ppHeight+ppSpacing)*i,caseWidth/2,ppLength+caseThickness+1])
						rotate([0,-90,180])
							powerPoleShell(centerPin=false);
				}
			}
		}
}

module subtractCavity() {
	difference() {
		children(0);
		translate([ppLength,(caseWidth-ppWidth)/2,caseThickness])
			// The "+1" here provides a bit of "slop" that is needed for a proper fit for the horizontal PP
			cube([caseLength-caseThickness-ppLength, ppWidth, caseHeight-caseThickness-ppLength+1]);
	}
}

module caseSideA() {
	addPins()
	difference() {
		children(0);
		cube([caseLength*2.5,caseWidth,caseHeight*2.5],center=true);
	}
}

module caseSideB() {
	addPinHoles()
	intersection() {
		children(0);
		cube([caseLength*2.5,caseWidth,caseHeight*2.5],center=true);
	}
}

module addPins() {
	union() {
		children(0);
		positionPinOne()
			pintack(h=5,bh=caseWidth/2,br=13/2);

		positionPinTwo()
			pintack(h=5,bh=caseWidth/2,br=13/2);
	}
}

module addPinHoles() {
	difference() {
		union() {
			children(0);
			addOffsetForPinHole() positionPinOne()
			cylinder(d=13,h=caseWidth/2);
			addOffsetForPinHole() positionPinTwo()
			cylinder(d=13,h=caseWidth/2);
		}
		addOffsetForPinHole()
			positionPinOne()
				pinhole(h=5,tight=true);

		addOffsetForPinHole()
			positionPinTwo()
				pinhole(h=5,tight=true);
	}
}

module positionPinOne() {
		translate([13,caseWidth,caseHeight/2])
			rotate([90,0,0])
				children(0);
}

module positionPinTwo() {
	translate([caseLength-13,caseWidth,caseHeight/2])
			rotate([90,0,0])
				children(0);
}

module addOffsetForPinHole() {
	translate([0,-caseWidth/2,0])
		children(0);
}

module reducePlastic() {
	difference() {
		children(0);

		translate([caseThickness,(caseWidth-ppWidth)/2,caseThickness+ppHeight+caseThickness])
			cube([ppLength+ppHeight/2-caseThickness-ppSpacing,ppWidth,caseHeight-caseThickness*2-ppHeight-caseThickness]);

// Should it ever be desired to have two horizontal plugs...
//		#translate([caseLength-(ppLength+ppHeight/2-1-ppSpacing),(caseWidth-ppWidth)/2,caseThickness+ppHeight+caseThickness])
//			cube([ppLength+ppHeight/2-1-ppSpacing-caseThickness, ppWidth, caseHeight-caseThickness*2-ppHeight-caseThickness]);

		translate([caseLength-(ppLength+ppHeight/2-1-ppSpacing),(caseWidth-ppWidth)/2,caseThickness])
			cube([ppLength+ppHeight/2-1-ppSpacing-caseThickness, ppWidth, caseHeight-caseThickness*2]);
	}
}

module prepSideAForPrinting() {
	translate([-caseLength/2,caseWidth/4,caseWidth]) rotate([-90,0,0]) children(0);
}

module prepSideBForPrinting() {
	translate([-caseLength/2,-caseWidth/4,caseWidth]) rotate([90,0,0]) children(0);
}

///////////
/// Main
///
prepSideAForPrinting()
	caseSideA()
		caseShell();

prepSideBForPrinting()
	translate([0,-caseWidth,0])
		caseSideB()
			caseShell();

// End of main

// powerPole.scad
//
// PowerPole code ONLY---->
//  Originally by J. Dunmire under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
//  Originally downloaded from http://rockingdlabs.dunmire.org/exercises-experiments/3d-printing-softrock-enclosure
//  Creative Commons license: http://creativecommons.org/licenses/by-nc-sa/3.0/
//
// Modifications:
//  M. Glover <ae5zc@arrl.net>, 20140408: Changed cylinder radii for pins to 1 from 3/2.
//

module key(){
  translate([0,-1.5,-0.5]) cube([12.5,3,1]);
}

module onePole(){
  difference() {
    union(){
      difference(){
        // body
        union() {
          difference() {
            difference() {
              cube([25,8,8]);
              union(){
                translate([0,(8-5.5)/2,(8-5.5)/2]) cube([5,5.5,5.5]);
                translate([25-6,1,1]) cube([6,6,6]);
              }
            }
                translate([25-6,0,0]) cube([6,8,4]);
          }
          translate([25-6,1,0]) cube([6,6,3.5]);
        }
        // recessed keys
        union(){
          translate([0,4,0]) key();
          translate([0,0,4]) rotate([90,0,0]) key();
          }
      }
      // proud keys
      union(){
        translate([0,4,8]) key();
        translate([0,8,4]) rotate([90,0,0]) key();
      }
    }
    // pin channels
    union() {
      translate([15,0,0]) cylinder(r=1,h=8,$fn=16); // 20140408
      translate([15,8,0]) cylinder(r=1,h=8,$fn=16); // 20140408
    }
  }
}

module twoPole(){
	translate([-25/2,-8,0]) {
		//color([1.0,0,0])
  			onePole();

		//color([0,0,0])
  			translate([0,8,0]) onePole();
	}
}

/// End of PowerPole code

```


[User]
Hey, I'm looking to get a parametric design for a guitar pickup ring, something that I can easily customize. I've seen designs that are just a basic rounded rectangle with screw holes, and that's pretty much what I'm going for, but I need to be able to control all the dimensions, like the overall width and height, the inner cutout dimensions, and the placement of both the mounting screws and the pickup adjustment screws. It also needs to have countersunk screw holes.

I'd like to control the overall thickness of the ring, as well as the thickness of the inner portion if I want to hollow it out. And it should have rounded corners on both the inner and outer rectangles. I also need to control how far the top of the pickup ring extends relative to the bottom so I can make a slightly angled pickup ring if needed, basically shave off some of the top edge.

I've done some OpenSCAD before, but I'm not too familiar with the more advanced features, so if you could provide a well-commented and organized parametric scad file, I'd really appreciate it! It would be great if all the dimensions were controlled with named variables at the top of the file, and the generated shape had both mounting holes and pickup adjustment holes. Also, just to be clear, I do *not* want to rely on any external libraries.

[Assistant]
pickup_ring.scad:
```
//Total pickup ring width in millimeters.
total_width = 90;
//Total pickup ring height in millimeters.
total_height = 46;
//Millimeters to shave off the top edge; useful for neck pickups close to the fretboard.
_top_offset = 0;

// Strandberg pickup rings are 20mm wider than PRS

/* [Hidden] */

$fn = 100;

width_offset = total_width - 90;
height_offset = total_height - 46;

top_offset = -_top_offset;

inner_width = 72 + width_offset;
inner_height = 40 + height_offset;
outer_width = 90 + width_offset;
outer_height = 46 + height_offset;

body_screw_head = 4;
body_screw_shaft = 2;
pickup_screw_head = 5.5;
pickup_screw_shaft = 2.5;
countersink = 1;

body_screw_xdist = 82 + width_offset;
body_screw_ydist = 37;
pickup_screw_dist = 79 + width_offset;

thickness = 4;
inner_thickness = 2;
wall_width = 2;

outer_radius = 4;
inner_radius = 2;

hollow = false;

module rounded_rectangle(size, radius) {
	hull() {
		translate([-(size[0] / 2 - radius), -(size[1] / 2 - radius)])
			circle(radius);
		translate([ (size[0] / 2 - radius), -(size[1] / 2 - radius)])
			circle(radius);
		translate([ (size[0] / 2 - radius),  (size[1] / 2 - radius)])
			circle(radius);
		translate([-(size[0] / 2 - radius),  (size[1] / 2 - radius)])
			circle(radius);
	}
}

module base() {
	difference() {
		linear_extrude(thickness) {
			difference() {
				translate([0, top_offset / 2])
					rounded_rectangle([outer_width, outer_height + top_offset], outer_radius);
				rounded_rectangle([inner_width, inner_height], inner_radius);
			}
		}
		if(hollow)
			translate([0, 0, -(thickness - inner_thickness)])
				linear_extrude((thickness - inner_thickness) * 2)
					rounded_rectangle([outer_width - wall_width, outer_height - wall_width], outer_radius);
	}
}

module screw(head, shaft, x, y) {
	translate([x, y, thickness/2])
		cylinder(thickness*2, shaft / 2, shaft / 2, true);
	translate([x, y, thickness])
		cylinder(countersink*2, head / 2, head / 2, true);
}

module screws() {
	screw(body_screw_head, body_screw_shaft, -(body_screw_xdist / 2), -(body_screw_ydist / 2));
	screw(body_screw_head, body_screw_shaft,  (body_screw_xdist / 2), -(body_screw_ydist / 2));
	screw(body_screw_head, body_screw_shaft,  (body_screw_xdist / 2),  (body_screw_ydist / 2));
	screw(body_screw_head, body_screw_shaft, -(body_screw_xdist / 2),  (body_screw_ydist / 2));
	screw(pickup_screw_head, pickup_screw_shaft, -(pickup_screw_dist / 2),  0);
	screw(pickup_screw_head, pickup_screw_shaft,  (pickup_screw_dist / 2),  0);
}

difference() {
	base();
	screws();
}

```


[User]
I need an OpenSCAD design for a parametric phone case. I've got some specific requirements for the case's shape and features.

The core of the case should be a rounded box, essentially a slightly larger version of the phone itself with rounded corners. I need to define the phone's dimensions – width, height, and thickness – as parameters. I also want a parameter to control the thickness of the case itself. Then, I'd like a parameter to define the curvature of the rounded corners.

Additionally, the case needs "bordini", essentially small rectangular protrusions on the top and bottom, and also on the sides. These act like bumpers to provide some extra protection. The width and height of these protrusions should be a fixed percentage of the phone's width and height, respectively. All the protrusions should have a thickness equal to the case thickness.

Could you design an OpenSCAD file, or files, that define this parametric design? I'm thinking I'd have a main module called `custodia` that calls modules called `corpo`, `bordini`, `bordino_x`, and `bordino_y` , and `roundedBox`. I do *not* want you to use any external libraries.

[Assistant]
phoneCaseRoundedParamThingiverse.scad:
```
// La larghezza del telefono
larghezza_telefono = 58.55

// L'altezza del telefono
altezza_telefono = 115.15

// Lo spessore del telefono
spessore_telefono = 9.4

// Lo spessore della custodia
spessore = 1;

// La curvatura agli angoli del telefono
curvatura = 10

// Le dimensioni del telefono: altezza, larghezza, spessore
dim_tel = [larghezza_telefono, altezza_telefono, spessore_telefono];

module bordino_x (dim_tel, spessore){
	translate([
		0,
		dim_tel[1] / 2 - spessore / 2,
		dim_tel[2] / 2 + spessore / 2])
	cube([dim_tel[0] * 8 / 10, spessore, spessore], center = true);
}

module bordino_y (dim_tel, spessore){
	translate([
		dim_tel[0] / 2 - spessore / 2,
		0,
		dim_tel[2] / 2 + spessore / 2])
	cube([spessore, dim_tel[1] * 8 / 10, spessore], center = true);
}

module bordini(dim_tel, spessore){
	bordino_x(dim_tel, spessore);
	mirror([0, 1, 0])
	bordino_x(dim_tel, spessore);

	bordino_y(dim_tel, spessore);
	mirror([1, 0, 0])
	bordino_y(dim_tel, spessore);
}

module roundedBox(dim_tel, curvatura)
{
	cube(dim_tel - [2 * curvatura, 0, 0], true);
	cube(dim_tel - [0,2 * curvatura, 0], true);
	for (
		x = [curvatura - dim_tel[0]/2, - curvatura + dim_tel[0]/2],
		y = [curvatura - dim_tel[1]/2, - curvatura + dim_tel[1]/2]) {
			translate([x,y,0])
			cylinder(r = curvatura, h = dim_tel[2], center = true);
	}
}

module corpo(dim_tel, spessore, curvatura) {
	difference() {
		roundedBox([
			dim_tel[0] + 2 * spessore,
			dim_tel[1] + 2 * spessore,
			dim_tel[2] + 2 * spessore], 10);
		translate([0, 0, spessore])
		roundedBox(dim_tel, curvatura);
	}
}

module custodia(dim_tel, spessore, curvatura) {
	corpo(dim_tel, spessore, curvatura);
	bordini(dim_tel, spessore);
}

custodia(dim_tel, spessore, curvatura);

```