[User]
I need a parametric knob designed in OpenSCAD. The design should be based on the included example, but I want it to be completely new code and not modifications of existing code.

The knob needs to have a main cylindrical body with a length that can be set as a parameter. This length will determine the height of the straight cylinder part. On top of the cylinder, it should transition to a more rounded, almost spherical shape. The transition should be a bit complex, involving scaled spheres and some differences to achieve the final look. I need to be able to adjust the overall length of the knob and there should be a slight narrowing near the base.

There also needs to be a hexagonal nut recess in the top part of the knob, and a cylindrical through-hole for a bolt, positioned so that the bolt will go all the way through the knob. The nut recess should be sized for an M5 nut, and the bolt hole should be for an M5 bolt. Please include tolerances, but I would like to adjust these parameters.

Finally, there should be six small, decorative spheres arranged around the circumference where the cylindrical section meets the complex rounded top part. These should be equally spaced and slightly protruding from the surface. They should also be able to be toggled off as a parameter.

I'm looking for a well-structured, easily modifiable design that uses appropriate modules for each component. Please use the `MCAD` library, specifically `boxes.scad` and `nuts_and_bolts.scad`.

[Assistant]
knob.scad:
```
// Designed by Glen Chung, 2014
// License: http://creativecommons.org/licenses/by-nc/3.0/

include <MCAD/boxes.scad>
include <MCAD/nuts_and_bolts.scad>

/* [Global] */

//knob length
length = 36; //[14:43]

//tolerance
tolerance = 0.4;

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

knob(length);

module knob(total_length=14) {
	r=12.0;
	s1=0.95;
	s2=1.9;
	nut_r=4.5;
	length=total_length-9.8;

	difference() {
		union() {
			translate([0,0,length-3.2])
			intersection() {
				difference() {
					translate([0,0,r*s2-1.2])
					intersection() {
						scale([s1,s1,s2])
						sphere(r=r);

						scale([s1*0.93,s1*0.93,s2*1.25])
						sphere(r=r);

					}

					translate([-25,-25,13])
					cube([50,50,50]);

					for(a=[0,90,180,270])
					{
						rotate([0, 1.5, a])
						translate([r+0.35, 0, 0]) scale([1,1.4,1])
						cylinder(r=r/2, r*2);

						rotate([0, 0, a])
						translate([r, 0, 1.31*r]) scale([1,1.6,1])
						rotate([0,-45,0])
						cylinder(r=r/2, r*2);

					}
				}

				translate([0,0,r/3])
				scale([1.2,1.2,1])
				sphere(r=r);
			}

			cylinder(r1=6, r2=6.4, h=length);

		}

		translate([0,0, 20+4])
		rotate([0,0,45])
		cylinder(r1=(nut_r+tolerance/2), r2=r/2, h=40, $fn=6, center=true);

		translate([0,0,-1])
		boltHole(size=5, length=35, tolerance=0.2);
	}

	for(ang=[0, 60, 120, 180, 240, 300])
	rotate([0,0,ang+45-60/2])
	translate([nut_r-0.15,0,2+4+4])
	rotate([0,2.5,0])
	scale([0.4,0.4,2])
	sphere(r=2, h=1);

}

```


[User]
I'm looking to create a solid, non-flexible replacement band for a Fitbit Flex. I've seen some designs online, but I want to be able to fully customize it for my wife's wrist.  I'm picturing a simple, arced band with a cutout to hold the Fitbit module snugly.

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

*   **Wrist Circumference:** I need to be able to specify this in millimeters or inches.
*   **Band Stretch:** This would control the shape of the arc, allowing it to be more oval or circular, like the code I included shows.
*   **Band Open Ratio:**  A parameter to adjust how much of the wrist is left uncovered, affecting how tight or loose the band is.
*   **Band Thickness:**  The overall thickness of the band material, in millimeters.
*   **Band Wall Thickness:**  The thickness of the material surrounding the edges, in millimeters - this may be the same as the band thickness, but I want the option to make it bigger.
*   **Flex Tweak (Radial & Axial):**  Adjustments in millimeters for the position of the Fitbit cutout, to move it in and out or forward and back on the wrist, as in the code I included.
*   **Clearance:** A small value to control the tolerance around the Fitbit module to compensate for printing variations, in millimeters.
*   **Support:** An on/off parameter for generating print supports in the model, like in the code I included, but I think this can be excluded if we do a print-in-place method.
*   **Band Width:** An overall control for the width of the band.

I'd like the design to be parametric so that I can adjust all of those values and easily generate a new band. I'm okay with doing this as a single part, not assembled from multiple links like some designs. I don't need support, so please just a single OpenSCAD file.

[Assistant]
FitbitBandSolid.scad:
```
// Replacement band for Fitbit Flex.
//
// http://www.thingiverse.com/thing:205148
//
// (c) 2013,2014 Laird Popkin.

/* [Settings] */

// Measurement around wrist (mm).
wristLenMM = 185;
// and in inches
wristLenIn = 0;
// Part to view
part = 5; //[5: Preview, 4:Band]

// . 0:Assembled Flex (don't print), 1:Flex Band, 2:Flex Box Bottom, 3:Flex Box Top]

/* [Solid Band] */

// Ratio of wrist width to height. 1.0 = circular, 1.25 is normal.
stretch = 1.25;
// Fraction of wrist size to leave open. 1.0 is very loose, 0.8 is tight.
bandOpenRatio = 0.8;
// Band thickness (mm)
bandThick=7;
// Band 'wall' thickness (mm)
bandWall = 10;
// Generate support in model
support=0; //[0:Don't include support, 1:Include support]
// Flex adjust in/out. Positive moves towards the outside, negative moves to inside. Adjust if needed to have the Flex intersect the band as you like.
flexTweakR = 1.5;
// Flex adjust up/down. Positive moves towards the end with the lights, negative moves the other way.
flexTweakX = 0;
// Clearance around Fitbit in band, adjust for your printer. 0=none, .25=loose
clearance=.25;
clearanceFactor=clearance/10;

/* [Hidden] */

wristLength = wristLenMM + wristLenIn*24.5;
// Length of links
linkLen = 13; // [11:Tight, 12:Tight-ish, 13:Loose-ish, 14:Loose]

/* [Hidden] */
$fn=16;
linkHeight=7;
pi=3.14159; // I could go on...
wristLen = wristLength + linkHeight*3.14159; // diameter of outside of band to allow for thickness
in=24.5;
len = 1.4*in;
width=8.5/16*in;
height=3/8*in;
echo(len,width,height);
r=2;
xoff=width/2-r;
yoff=height/2-r;
thick=.5;

flexScale=1.3;
flexLScale=1.105;

blockH=10;
angle=30; // angle of face
zoff = sin(30)*5;

outerWidth=width+4.6*thick;
outerLen = len-3;
outerHeight = height+thick;

hinge_dia = outerHeight * 1000;

hingeXscale = .8;
hingeXoff=0.7;

echo("wrist band length ",wristLen);

flexAngle = 88.7; //89.2;

numLinks = floor((wristLen-outerLen-outerWidth/2)/(linkLen*2));
linksLen = numLinks*linkLen;
echo("links ",numLinks," length ",linksLen);

gap = 0.8;

echo("size ",outerWidth,outerLen,outerHeight);

module flex() {
	translate([0,0,-1]) difference() {
		translate([0,0,-zoff]) linear_extrude(scale=0.85,height=len) {
			square([width-2*r,height],center=true);
			square([width,height-2*r],center=true);

			translate([-xoff,-yoff,0]) circle(r=r);
			translate([-xoff,yoff,0]) circle(r=r);
			translate([xoff,-yoff,0]) circle(r=r);
			translate([xoff,yoff,0]) circle(r=r);
			}
		translate([0,0,-zoff]) rotate([30,0,0]) cube([2*width,2*height,5],center=true);
		}
	}

module male() {
	scale([1,1/2,1]) {
		translate([-outerWidth/8,0,0])
			cube([outerWidth/4,outerWidth/2,linkHeight]);
		translate([0,-gap,0]) cylinder(r=outerWidth/4, h=linkHeight);
		}
	}

module female() {
	scale([1,1/2,1]) difference() {
		translate([-outerWidth/2,-outerWidth/2-gap,0])
			cube([outerWidth,outerWidth,linkHeight]);
		translate([-outerWidth/8-gap,0,-1])
			cube([outerWidth/4+2*gap,outerWidth/2,linkHeight+2]);
		translate([0,0,-1]) cylinder(r=outerWidth/4+2*gap, h=linkHeight+2);
		}
	}

module FitBitBand(band=1) {
	//#translate([	outerWidth,0,0]) cube([1,wristLen,1],center=true);

	difference() {
		union() {
			// hull around Flex
			translate([0,len/2-zoff,height/2])
				rotate([flexAngle,0,0])
					scale([flexScale,flexScale,flexLScale]) flex();
			// Make 'head' thicker
			translate([0,outerLen*.43,height/2+thick/2]) cube([outerWidth,outerLen*.25,outerHeight],center=true); // around flex
			//block in middle of 'face'
			translate([0,-4,height/2+thick/2+outerHeight/4]) cube([outerWidth,outerLen*.2,outerHeight/2],center=true); // around flex
			//Make sides thicker
			translate([0,-4,height/2+thick/2])
				cube([outerWidth,outerLen,height-2*r],center=true); // around flex
			// links on both sides
			if (band) translate([0,0,outerHeight-linkHeight]) {
				for (link = [0:numLinks-1]) {
					assign (y=link*linkLen) {
//				for (y=[0:linkLen:wristLen/4+outerWidth/4]) {
					translate([hingeXoff,outerLen/2+y+linkLen/2,0]) scale([hingeXscale,1,1]) demo(linkHeight,gap/hingeXscale);
					translate([hingeXoff,-(outerLen/2+y+linkLen/2)-2,0]) scale([hingeXscale,1,1]) demo(linkHeight,gap/hingeXscale);
					}
				translate([0,-wristLen/2,0]) male();
				translate([0,wristLen/2,0]) female();
				}
				}
			}
		// carve out space for Flex
		translate([0,len/2-zoff-1,height/2]) rotate([flexAngle,0,0]) flex();
		// carve out hole on top to put Flex in
		translate([0,1,0]) cube([width,len-7,2*(r)],center=true);
		// carve out gap for pulling Flex out
		translate([0,len/2,.2]) cube([width*.75,6,2*(r+thick)], center=true);
		}

//	translate([hingeXoff,outerLen+1,0]) scale([hingeXscale,1,1]) demo(outerHeight,0.4/hingeXscale);
//	translate([hingeXoff,-outerLen-1,0]) scale([hingeXscale,1,1]) demo(outerHeight,0.4/hingeXscale);
//	translate([hingeXoff,1.75*outerLen+1,0]) scale([hingeXscale,1,1]) demo(outerHeight,0.4/hingeXscale);
//	translate([hingeXoff,-1.75*outerLen-1,0]) scale([hingeXscale,1,1]) demo(outerHeight,0.4/hingeXscale);
	//translate([hingeXoff,2.5*outerLen+1,0]) scale([hingeXscale,1,1]) demo(outerHeight,0.4/hingeXscale);
	//translate([hingeXoff,-2.5*outerLen-1,0]) scale([hingeXscale,1,1]) demo(outerHeight,0.4/hingeXscale);

	// fill gaps between ends and links
	if (band) translate([0,0,linkHeight*.9]) difference() {
		cube([outerWidth,wristLen-outerWidth/2,linkHeight],center=true);
		cube([outerWidth/.9,outerLen+2*linksLen,linkHeight+2],center=true);
		echo("gap len ",((wristLen-outerWidth/2) - (outerLen+2*linksLen))/2);
		}
	}

//flex();

module band() {
fitBitBand(0);
difference() {
	translate([0,0,outerHeight]) rotate([180,0,90]) FitBitBand();
	translate([0,0,-1]) cube([wristLen+10,outerWidth,2],center=true);
	if (part==0) rotate([90,0,0]) translate([0,0,4]) cube([wristLen+10,2*outerWidth,10],center=true);
	}
}

bandH = width+2*bandWall;

module solidBand(preview=0) {
	wristR = wristLen/pi/2/stretch;
	wristW = wristR+bandThick;
	echo ("wrist len ",wristLen," wrist R ",wristR);
	color("red") {
		difference() {
			scale([stretch,1,1]) difference() {
				translate([0,-bandThick/2,0])
					cylinder(r=wristR+bandThick/2, h=bandH, $fn=64);
				translate([0,-1,-1])
					cylinder(r=wristR, h=bandH+2, $fn=64);
				}
			difference() {
				translate([-len/2-flexTweakX,-wristR-flexTweakR,width/2+bandWall])
					rotate([0,-90,180])
						scale([1+2*clearanceFactor,
							1+clearanceFactor,
							1+0*clearanceFactor])
						flex();
				if (support) //for (xo=[-len/5:len/2.5:len/5]) {
					translate([0,-wristR-bandThick,0])
						cube([0.4,bandThick+2,width+2*r]); // loop
					//}
				}
			translate([-wristR*bandOpenRatio,0,-1])
				cube([2*wristR*bandOpenRatio, (wristR+bandThick),width+2*bandWall+2]);
			}
		}
		if (preview)
			translate([-len/2-flexTweakX,-wristR-flexTweakR,width/2+bandWall])
				rotate([0,-90,180])
					color("black") flex();

	}

module boxBottom() {
	margin = 3;
	bw = outerWidth + 2*margin;
	bl = wristLen+10 + 2*margin;
	wall = 1;

	difference() {
		translate([0,0,outerHeight/2-wall-margin]) cube([bl,bw,outerHeight],center=true);
		translate([0,0,outerHeight/2-margin]) cube([bl-2*wall,bw-2*wall,outerHeight-wall],center=true);
		if (part==0) rotate([90,0,0]) translate([0,0,9]) cube([wristLen+20,3*outerWidth,20],center=true);
		}
	}

module boxTop() {
	margin = 3;
	wall = 1;
	bw = outerWidth + 2*margin + 3*wall;
	bl = wristLen+10 + 2*margin + 3*wall;

	difference() {
		translate([0,0,outerHeight/2+wall+margin]) cube([bl,bw,outerHeight],center=true);
		translate([0,0,outerHeight/2+margin]) cube([bl-2*wall,bw-2*wall,outerHeight-wall],center=true);
		if (part==0) rotate([90,0,0]) translate([0,0,9]) cube([wristLen+20,3*outerWidth,20],center=true);
		}
	}

if ((part==0)||(part==1)) band();
if ((part==0)||(part==2)) boxBottom();
if ((part==0)||(part==3)) boxTop();
if (part==4) solidBand(0);
if (part==5) rotate([-90,0,0]) solidBand(1);

//male();
//female();

/// HINGE

// What diameter or thickness should the hinge have (in 0.01 mm units)?
//hinge_dia = 500; // [1:5000]

// How much gap should be left between separate parts (in 0.01 mm units)?
//hinge_gap = 40; // [1:2000]

module hingepair() {
	union() {
		cylinder(h=0.25, r=0.5);
		translate([0,0,0.25]) cylinder(h=0.25, r1=0.5, r2=0.25);
		translate([0,0,1]) cylinder(h=0.25, r1=0.25, r2=0.5);
		translate([0,0,1.25]) cylinder(h=0.25, r=0.5);
	}
}

module hingecore(gap) {
	union() {
		difference() {
			union() {
				cylinder(h=1.5, r=0.5);
				translate([-0.5,0,0.25+gap])
					cube(size=[1,1,1-gap-gap]);
				//translate([0,-0.5,0.25+gap])
				//	cube(size=[0.5,0.5,1-gap-gap]);
			}
			translate([0,0,0.25+gap-0.5]) cylinder(h=0.75, r1=1, r2=0.25);
			translate([0,0,1-gap]) cylinder(h=0.75, r1=0.25, r2=1);
		}
		translate([-0.5,0.5+gap,0])
			cube(size=[1,0.5-gap,1.5]);
	}
}

module hingeedge(gap) {
	union() {
		hingepair();
		translate([-0.5,-1,0])
			cube(size=[1,0.5-gap,1.5]);
		translate([-0.5,-1,0])
			cube(size=[1,1,0.25]);
		translate([-0.5,-1,1.25])
			cube(size=[1,1,0.25]);
		//translate([0,0,1.25])
		//	cube(size=[0.5,0.5,0.25]);
		//translate([0,0,0])
			//cube(size=[0.5,0.5,0.25]);
	}
}

module hinge(thick, realgap) {
	hingeedge(realgap / thick);
	hingecore(realgap / thick);
}

module demo(t, rg) { // modified to make only two hinges
	scale([t,t,t])
	translate([-2.75,0,0.5])
	rotate(a=[0,90,0])
	union() {
		//hinge(t, rg);
		translate([0,0,1.25]) hinge(t, rg);
		translate([0,0,2.5]) hinge(t, rg);
		//translate([0,0,3.75]) hinge(t, rg);
		//translate([-.5,1,1.25]) cube(size=[1,1,5.25/2+.1]);
		//translate([-0.5,-2,1.25]) cube(size=[1,1,5.25/2+.1]);
	}
}
```


[User]
Hey, I need a little help creating a customizable cap for the end of a tube. I'm mounting a luggage rack and the manufacturer shorted me one of the protective caps they ship to avoid scratching the bike during install. I figured I could just make one. I have an idea of the basic shape but I'd like to make it parametric so it's more reusable.

Essentially, it's a cylinder with a cylindrical cutout to create the cap. I need to specify the outer diameter of the cap, the wall thickness, the total height of the cap, and the height of the inner cutout.

Could you generate an OpenSCAD file for this? I'd like to be able to tweak the dimensions through variables at the top of the file. I don't need any special features, just a simple, clean cap with those parameters. Make sure to define `$fn` for the cylinder.

[Assistant]
luggagerackcap.scad:
```
// cap diameter in mm (not radius!)
cap_diameter=14.75;
// wall thickenss in mm
wall_thickness=0.825;
// Total height in mm
outer_height=16;
// Height of interior cut out in mm
inner_height=12;

$fn=100+0;
difference() {
cylinder(r=cap_diameter/2,h=outer_height,center=true);
translate([0,0,(outer_height-inner_height)/2+.1])
cylinder(r=cap_diameter/2-wall_thickness,h=inner_height+.05,center=true);
}

```


[User]
Hey, I'm looking to create a parametric vibration dampener for my 3D printer, and I need help generating the OpenSCAD code.

Here's the basic idea: It's going to be a dampener that sits between the printer and the surface it's on, aiming to reduce noise by absorbing vibrations. I've already got some basic dimensions in mind, but I'd like these to be customizable, of course.

There should be two possible mount types: square and round. For square, I need a simple extruded shape with a base and an angled arm going up from it, and then a solid, fairly thick, connection to the main dampening body. The round type would be a cylinder with a base, which then connects to the main dampening body.

The main body of the dampener is something I'd like to be able to adjust - it's the oval-ish part that actually absorbs the vibrations. I'm envisioning a somewhat flattened oval shape created using a cylinder that's then resized to make it oval.

Finally, I'd like to include the option for a bolt hole through the dampener for secure mounting if needed.

Here are the parameters I need to be able to control:

*   `mountType`: Select between square (1) or round (2) mounts.
*   `dampenerLength`: The length of the main dampening body.
*   `dampenerHeight`: The height of the main dampening body.
*   `dampenerWidth`: The width of the main dampening body and also mount thickness.
*   `dampenerStrength`: The thickness of the dampener material. Think of this as the amount of material we remove to make it softer.
*   `mountHeight`: The height of the mount itself.
*  `mountLength`: The length of the mount that connects to the dampener base.
*   `holeSize`: The diameter of the bolt hole, if needed.

I think I have a pretty good idea of what I need this to look like, I just need help with the scad code! I'm not particularly picky on the implementation, but it'd be nice if it were reasonably efficient.

[Assistant]
dampener-customizable.scad:
```
//Dampeners for printer
//By Jkk79

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

//
mountType=2;  //[1:square, 2:round]

//Has to be quite large to absorb vibrations. 100mm works well.
dampenerLength=100;//[60:150]

//30mm works well.
dampenerHeight=30; //[15:50]

//19mm for prusa i3 (with two extra dampeners under the frame), 46mm for k8200 (with 4 dampeners)
dampenerWidth=46; //[10:60]

//(Thickness). 2.6mm seems flexible enough, and 3 too stiff already.
dampenerStrength=2.6;//[1.6:0.1:4.0]

//~10mm is good for prusa i3, 12mm for k8200, at least...
mountHeight=12;//[0:0.5:20]

//22.4 for prusa i3 legs, 6mm for prusa i3's aluminium frame, 40mm for k8200's round legs.
mountLength=40;//[0:0.2:60]

//For possible bolt-type fastening.
holeSize=6;//[0:0.5:20]

module squareMount(){
linear_extrude(dampenerWidth)polygon(points=[[0,mountHeight],[0,0],[mountLength,0],[mountLength,mountHeight],[mountLength+3,mountHeight],[mountLength+3,-dampenerHeight/2],[-3,-dampenerHeight/2],[-3,mountHeight]]);
}

module roundMount(){
	rotate([90,0,0])translate([mountLength/2,dampenerWidth/2,-mountHeight+1]){
		difference(){
			difference(){
				cylinder(mountHeight+2,(mountLength/2)+3,(mountLength/2)+3,$fn=128);
				translate([0,0,-1])cylinder(mountHeight+0.5,(mountLength/2),(mountLength/2),$fn=128);
			}
			translate([0-dampenerLength/2,dampenerWidth/2,-dampenerHeight+mountHeight])cube([100,mountLength/2,dampenerHeight+mountHeight]);
			translate([0-dampenerLength/2,-(mountLength/2)-dampenerWidth/2,-dampenerHeight+mountHeight])cube([100,mountLength/2,dampenerHeight+mountHeight]);
		}
	}

}

module dampener(){

	difference(){
        union(){
            if(mountType==1){

                squareMount();

            }else{

                roundMount();
            }
              translate([(mountLength)/2,((0-dampenerHeight/2)+10)-11,0])  resize([dampenerLength,dampenerHeight])cylinder(dampenerWidth,10,10,$fn=128);
            }
      translate([(mountLength)/2,((0-dampenerHeight/2)+10)-11,-1])resize([(dampenerLength-dampenerStrength*2),dampenerHeight-dampenerStrength*2])cylinder(dampenerWidth+2,1,1,$fn=128);
      rotate([90,0,0])translate([mountLength/2,dampenerWidth/2,-4])cylinder(10,holeSize/2,holeSize/2,$fn=128);
	}
}

dampener();
```


[User]
Hi, I'm looking to create a parametric drain cover/hair catcher for both a bathtub and a bathroom sink. I have some specific dimensions in mind, and I'd like the design to be flexible so I can easily change the size for different drains.

Essentially, I need a cylindrical base with a slightly raised rim and a domed top. The cylinder should have a series of angled slots or channels around its base for water to pass through. There also needs to be a central hole going all the way through the center.

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

*   **`drain_diameter`**: The diameter of the drain opening. I need to be able to easily set this, and the entire cover needs to scale based on this parameter. Examples would be 38mm for a typical bathtub drain and 28.5mm for a typical bathroom sink drain.
*   **`base_height`**: The height of the main cylindrical base of the cover.
*   **`rim_height`**: The height of the raised rim.
*   **`rim_thickness`**: The thickness of the raised rim.
*   **`dome_height`**: The height of the domed top.
*   **`slot_width`**: The width of the water slots/channels.
*   **`slot_depth`**: The depth of the water slots/channels.
*   **`slot_angle`**: The angle of the slots in relation to the z axis.
*   **`slot_count`**: Number of water slots/channels around the perimeter.
*   **`central_hole_diameter`**: The diameter of the central hole.

The design should start with a base cylinder. Then, a slightly larger cylinder or ring for the rim on top of the base. Finally, a dome on top of that. Then we'll add the slots which should be angled, to direct water flow to the center. The slots should be created via subtraction from the base cylinder. Then, subtract a central cylinder to create the center hole.

I'd prefer it if you could use the `rotate_extrude` feature for the dome, if possible. This will allow to create a smooth curve for the dome.

Can you generate an OpenSCAD file (or files, if that makes the most sense) that achieves this? Please include comments to help me understand how the code works and be sure to clearly label all of the parametric values. It's ok to include `module`s for various components, but try to avoid using any external libraries like `MCAD` or `BOSL`, etc.

[Assistant]
Drain.scad:
```
//Drain Diameter (bathtub 38, bathroom sink 28.5)
diameter=38; //
// //Bathtub (mine was 38mm)
// //Sink    (mine was 28.5mm)
scale(diameter/36.25,[1,1,1]) //bathtub 38

//_______________________________________
//original design=36.25mm
// To calculate the scale..
// NewScale=DiameterRequired/36.25
//_______________________________________

difference(){
	union(){
		intersection(){
		cylinder(r1=35/2,r2=37/2,h=10,$fn=50);
		translate([0,0,12])
		sphere(19,$fn=50);
		}
		translate([0,0,10])
		cylinder(r1=37/2,r2=39/2,h=1.5,$fn=50);
	}
	translate([0,0,20])
	sphere(35.5/2,$fn=100);
	//translate([0,0,3])
	//cylinder(r=34.5/2,h=11,$fn=25);
	for (r=[0:40:359]){
		rotate(r)
	difference(){
	hull(){
			translate([5,0,-8])
			rotate([0,90,0])
			cylinder(r1=.9,r2=3.75,h=28/2,$fn=16);
			translate([5,0,5])
			rotate([0,90,0])
			cylinder(r1=.9,r2=6.75,h=28/2,$fn=16);
		}
		translate([0,0,10])
		cylinder(r1=37/2,r2=39/2,h=1.5,$fn=50);
	}
	}

	cylinder(r=3.5,h=10,center=true,$fn=16);

}

```


[User]
I'd like to create a cellphone microscope attachment using OpenSCAD. I want it to be parametric so I can easily adjust it to fit different phones and lenses.

The basic idea is to have a clip that attaches to the side of the phone, and an arm that extends out with a holder for the laser pointer lens. I've seen a similar design on instructables.

Here's what I'm thinking for the main parameters:

*   **Phone dimensions:** `phoneWidth`, `phoneDepth`.
*   **Lens dimensions:** `lensDiameter`, `lensDepth`.
*   **Lens offset:** `lensOffset` which is the distance from the right edge of the phone to the center of the lens.
*   **Arm dimensions:** `armThick`, `armWidth`.
*   **Clip length:** `clipLength`, which I would like to define as a percentage of the phone's width.
*   **Build plate selection:** for preview purposes, I'd like to be able to select from a predefined list of build plate sizes, such as Replicator 2, Replicator, Thingomatic, or manual. When manual is selected, I'd like to set `build_plate_manual_x` and `build_plate_manual_y`.

I'd like the design to use a `build_plate` module from an external library to display the build plate size. The `build_plate` module can use the `build_plate_selector` variable (an integer) to determine which build plate to use. If `build_plate_selector` is 3 (manual), then the `build_plate` module can instead use the dimensions provided in `build_plate_manual_x` and `build_plate_manual_y`. Let's use the `utils/build_plate.scad` library for that.

The main structure should have an arm with a hole to hold the lens, and two clasp-like extensions with "clipLength" that wrap around the sides of the phone.  The arm and clasp-like extensions should be created using the `arm()`, `sideClasp()` and `lensHole()` modules.  The lens should also have its own module called `lens()` and be centered over the hole, the lens module should also add a little lip to assist with holding in the lens.
I think that the design should be composed of a number of modules such as arm, sideClasp, lensHole and lens to make it easier to read.

I'm hoping this is enough information to get started. Let me know if you need more details.

[Assistant]
Cellphone_Microscope.scad:
```
use <utils/build_plate.scad>
/* [Phone & lens dimensions] */

phoneWidth = 65.3;
phoneDepth = 13.7;

lensDiameter = 6.5;
lensDepth = 3;
// Distance from the right hand edge of the phone to the centre of the lens
lensOffset = 32.65;

/* [holder dimensions] */
armThick = 2;
armWidth = 10;
//Percentage of the camera width
clipLength = 10; //[0:50]

/* [Build plate] */

//for display only, doesn't contribute to final object
build_plate_selector = 0; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

/* [Hidden] */
// All done. Customizer doesn't need to see all this
$fn = 20;

lensR = lensDiameter/2;

lensTranslate = [phoneWidth/2-lensOffset,(armWidth/2-(lensR+armThick)),0];
translate([0,0,armWidth/2])rotate([-90,0,0]){
difference(){
arm();
translate(lensTranslate)
lensHole();
}
translate(lensTranslate)
lens();
}
module lens(){
lipDepth = lensR/10;
holderH = lensDepth+2;
translate([0,0,-holderH+armThick])
difference(){
cylinder(r=lensR+armThick, h = holderH);
translate([0,0,1])cylinder(r=lensR, h = holderH);
cylinder(r=lensR-lipDepth, h = holderH*4, center = true);
//}
}
}
module lensHole(){
cylinder(r=lensR+armThick, h = lensDepth*8, center = true);
}

module arm(){
translate([0,-armWidth/2,0]){
translate([-phoneWidth/2,0,0])cube([phoneWidth,armWidth, armThick]);
sideClasp();
mirror([1,0,0]){
sideClasp();
}
}
}
module sideClasp(){
claspLength = phoneWidth * clipLength/100;
translate([phoneWidth/2,0,0])cube([armThick, armWidth, phoneDepth+2*armThick]);
translate([-claspLength+phoneWidth/2,0,phoneDepth+armThick])cube([claspLength, armWidth, armThick]);
}
```


[User]
I'm looking to design a knob, similar to a four-pronged rotary knob you might see on some older equipment. I want it to be parametric so I can easily change its dimensions.

Here’s a basic rundown of what I need:

**General Shape:** The knob should have a central hub with a square hole to fit onto a shaft, and then four knob arms extending outwards.

**Specific Dimensions I’d like to control:**

*   `thickness`: The overall height/thickness of the knob.
*   `outer_r`: The radius of the circle that the outside edges of the knob arms sit on. This will help determine the overall size.
*   `knob_r`: The radius of each individual arm, before the wall thickness is added
*   `bolt_r`: The radius of the central shaft hole
*   `wall_thickness`: The thickness of the material around the shaft hole, and the space between the arm and the main body.
*   `square_ratio`: The ratio controlling the 'rectangularity' of the shaft hole. A value of 1 would make it perfectly square.

**Hole:** The hole for the shaft needs to be square with rounded corners.

**Arms:** The four arms should extend out from the central part of the knob. I envision them being cylindrical, but I could be convinced otherwise if it's visually better!

**Wall Thickness:** I need to be able to set a wall thickness for the material around the shaft hole and the thickness for the material separating the arms and the center.

I'm hoping that the code will also allow me to easily adjust all of these parameters. I'd prefer the code to be as clean and easy to understand as possible. I would like for the code to not use any libraries if that is possible.

Can you generate an OpenSCAD file for me based on these specifications?

[Assistant]
four_side_knob.scad:
```
thickness=20;
outer_r=45;
knob_r=35;
bolt_r=4.6;
wall_thickness=6;
square_ratio=1.5;

union(){
	difference(){
		cylinder(r=bolt_r+wall_thickness,h=thickness);
		intersection(){
			translate([0,0,wall_thickness])cylinder(r=bolt_r,h=thickness);
			translate([-square_ratio*.5*bolt_r,-bolt_r*2,wall_thickness])cube([square_ratio*bolt_r,bolt_r*4,thickness]);
		}
	}
	intersection(){
		difference(){
			union(){
				difference(){
					cylinder(r=outer_r,h=thickness);
					translate([0,0,wall_thickness])cylinder(r=outer_r-wall_thickness,h=thickness);
					}
				translate([(outer_r+bolt_r+wall_thickness)*sin(90),(outer_r+bolt_r+wall_thickness)*cos(90),0])cylinder(r=knob_r+wall_thickness,h=thickness);
				translate([(outer_r+bolt_r+wall_thickness)*sin(180),(outer_r+bolt_r+wall_thickness)*cos(180),0])cylinder(r=knob_r+wall_thickness,h=thickness);
				translate([(outer_r+bolt_r+wall_thickness)*sin(270),(outer_r+bolt_r+wall_thickness)*cos(270),0])cylinder(r=knob_r+wall_thickness,h=thickness);
				translate([(outer_r+bolt_r+wall_thickness)*sin(360),(outer_r+bolt_r+wall_thickness)*cos(360),0])cylinder(r=knob_r+wall_thickness,h=thickness);
			}

			translate([(outer_r+bolt_r+wall_thickness)*sin(90),(outer_r+bolt_r+wall_thickness)*cos(90),-wall_thickness])cylinder(r=knob_r,h=thickness+wall_thickness*2);
			translate([(outer_r+bolt_r+wall_thickness)*sin(180),(outer_r+bolt_r+wall_thickness)*cos(180),-wall_thickness])cylinder(r=knob_r,h=thickness+wall_thickness*2);
			translate([(outer_r+bolt_r+wall_thickness)*sin(270),(outer_r+bolt_r+wall_thickness)*cos(270),-wall_thickness])cylinder(r=knob_r,h=thickness+wall_thickness*2);
			translate([(outer_r+bolt_r+wall_thickness)*sin(360),(outer_r+bolt_r+wall_thickness)*cos(360),-wall_thickness])cylinder(r=knob_r,h=thickness+wall_thickness*2);
		}
	cylinder(r=outer_r,h=thickness);
	}
}

```


[User]
Okay, I'm looking to design a parametric propeller, something similar to the one described in the SCAD file I've attached (mid-prop.scad). It's based on an ellipse for the fin shape, twisted by an angle, and I want to maintain that basic concept.

Here's what I need in my design:

**Core Structure:**

*   **Ring:** There should be a central ring with adjustable outer radius (`trad`) and thickness (`outw`). I'd also like an adjustable bevel height (`bevh`) on the top edge of this ring.
*   **Hub:** The hub needs to be a central cylinder with a radius (`rins`) and a depth that matches the prop depth (`tdepth`). I want an option (`hubstyle`) to add a spherical "hubcap" on top of the cylinder, and a shaft hole that goes through to near the other end. The shaft hole radius (`chrad`) needs to be adjustable.
*   **Fin Attachment:** The fins should attach directly to the cylinder.

**Fins:**

*   **Number:** The number of fins (`nfins`) should be adjustable.
*   **Depth:** The overall depth of the propeller (and thus how far the fins extend from the hub) will be controlled by `tdepth`.
*   **Angle:** The twist angle of each fin (`fangle`) needs to be adjustable.
*   **Thickness:** The fin thickness (`tfin`) should also be adjustable.
*   **Shape:** The fins should have an elliptical shape that is achieved through an extrusion of a circle with the scaling such that a circle appears like an ellipse.

**Rendering/Parametric Control:**

*   **Facet Size/Angle:** I need parametric control over the facet size (`fs`), facet angle (`fa`), and number of facets (`fn`) for smoother rendering.
*   **Slices:** Control over the number of slices (`nslices`) for the twisting of the fin would be useful.

I'm aiming for something that's easy to customize.  So, make sure everything's parametric.

I don't need any specific libraries but I am familiar with the basics of how OpenSCAD works.

[Assistant]
mid-prop.scad:
```
//Parametric propeller using an ellipse for the fin shape, twisted by an angle.
// Derived from http://www.thingiverse.com/thing:116974 by Robotbeat
// Updated by Kevin Osborn (http://baldwisdom.com) to improve variable documentation
// 	changed fin attachment to a cylinder, with an optional spherical "hubcap"
//Creative Commons license.

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

// ring radius
trad=32; //outerradius not counting outw. 23.5 good
// ring thickness
outw=1.5; //outerwidth. 1.5 is good
// outer ring bevel height
bevh = 2;

//hub radius
rins= 5; //radius of coupling thing, 5 is good
// shaft radius including tolerance. 1.2 works well for 2mm motor shafts
chrad = 1.2;
//hub style -- 0 is none, 1 is sphere hubcap
hubstyle = 1; //[0,1]
// fin parameters
// number of fins
nfins=5; //number of fins. Min # is 2, but 3 is better
// prop depth, reduce if nfins is big
tdepth = 5;
// fin angle > 60 may have too much overhang for printing
fangle = 60;
// fin thickness
tfin = 1;

/* [rendering resolution */
//facet size
fs=.2;   //.2 is good, 2 is for viewing, facet size
//facet angle
fa=4;	 //4 is decent, 12 is for viewing, deg per facet
//number of facets
fn=40;  //40 is good, 10 is for viewing
//slices for twist in fin
nslices=15; //15 is good, 5 is for viewing

module total(fs,fa,fn,nslices,trad,outw,nfins,rins,tdepth,fangle,bevh,tfin,hubstyle)
{  //.5, 4, 40, 12
$fs=fs;$fa=fa;$fn=fn;  //default $fs,$fa,$fn is 2,12,10,min facet size,deg.per facet,etc

union(){
	difference(){
		union(){
			// make the hub
			cylinder(r=rins, h=tdepth);
			if (hubstyle == 1){
				translate([0,0,tdepth])hubcap();
			}
			translate([0,0,-119]) cylinder(h=119,r=rins);
			difference(){
				translate([0,0,-14]) cylinder(h=15,r=trad+outw);
				translate([0,0,-15]) cylinder(h=17,r=trad);}
		}
		translate([0,0,-119-tdepth]) cylinder(h=119,r=trad+outw+119);
	}
	translate([0,0,1])
	difference(){
		translate([0,0,0]) cylinder(h=bevh, r1=trad+outw, r2=trad); //bevel
		translate([0,0,-10]) cylinder(h=119, r=trad);}
	intersection(){
		union(){for (i = [0:(nfins-1)]){rotate([0,0,360*i/nfins]) betterfin();}	}
		translate([0,0,-.5*119]) cylinder(h=119,r=trad);}
}
}
$fn=50;

difference(){ //This difference is to add a centering hole
	difference(){total(fs,fa,fn,nslices,trad,outw,nfins,rins,tdepth,fangle,bevh,tfin,hubstyle);
		//Difference so that it will print nice. Otherwise it wouldn't.
		translate([0,0,-119-3]) cylinder(h=119,r=119);} //This is to trim it flat
		// axle hole, almost all the way through (1mm from top
		translate([0,0,-4]) cylinder(h=(tdepth+rins+3),r=chrad);
}

module hubcap(){
	difference(){
		sphere(r=rins);
		// chop off the bottom
		translate([-(rins/2),-(rins/2),-rins])cube([rins,rins,rins]);
	}
}
module fin()
{union(){rotate([-fangle,0,0]){union() {
			cube([119, 119, tfin]);
				translate( [119,0,.5*tfin]){
rotate([0,-90,0]) cylinder (h=119,r=.5*tfin);}
}}};
}
module betterfin()
{
	rotate([90,0,90])
	linear_extrude(height=trad, center=false, convexity=10, twist=fangle, slices=nslices)
	scale([tfin/tdepth,1,1]) circle(r = tdepth);
}

```


[User]
Hey! I'm working on a project in OpenSCAD and I need some help with colors. I found this cool script online (hsvtorgb.scad) that converts HSV color values to RGB, which is exactly what I need since I'm trying to create some designs with specific hues, saturations, and values. It would make my work so much easier if I didn't have to calculate RGB by hand!

I was hoping you could help me design a parametric OpenSCAD file that makes use of this HSV to RGB conversion. Specifically, I'd like to create a function that I can call to easily create a cylinder with a specified HSV color and another function to create a cube with a specified HSV color. Ideally, these functions should take height/depth, radius/size, and hsv color parameters as input. I want to be able to pass in values between 0 and 1 for hue, saturation, and value, same as the provided script. For transparency (alpha), I'll just use the same alpha value across all parts, so you don't need to include it as a parameter.

Also, could you include an example of how to use both functions to create a simple scene showing a few colorful cylinders and cubes? That would be really helpful to see it in action. I'd like to keep the design flexible and parametric, so everything should be configurable, such as sizes and the color of the shapes.

So, to summarize, please generate the following:

1.  **hsvtorgb.scad:** A file that contains the existing hsv to rgb color conversion functions given to you.
2.  **color_shapes.scad:** A file with a function `hsvCylinder(height, radius, h, s, v)` that will create a cylinder with the specified color and dimensions and a function `hsvCube(size, h, s, v)` to do the same with a cube.
3.  **example.scad:** A file demonstrating how to use `hsvCylinder` and `hsvCube` to create a sample design with some colorful cylinders and cubes at different locations on the plane.

I'm excited to see what you come up with!

[Assistant]
hsvtorgb.scad:
```
//use this to convert hue-saturation-value colors to red-green-blue colors for use with OpenSCAD's color() module
//Rainbows are much easier to  make now!

/****************************************************/
/*						How to Use					*/
/****************************************************/

//use the hsvToRGB function to convert hsv colors to rgb colors
//it takes 4 parameters:
//	h is a value from 0.0 to 1.0 and represents hue which is the type of color (red, green, blue, orange, yellow, etc)
//		0.0 is red
//		0.33 is green
//		0.66 is blue
//	s is a value from 0.0 to 1.0 and controls saturation which is how 'rich' the color is
//	v is a value from 0.0 to 1.0 and controls the value of the color which is how bright the color is
//	a is a value from 0.0 to 1.0 and controls how transparent the color is

//parameters will default to 1.0 if they are not set

/****************************************************/
/*						Example						*/
/****************************************************/

//changing hue
for(i = [0:10])
{
	color(hsvToRGB(1 / 10 * i, 1, 1, 1))
		translate([0,0,1 * i])
			cube([11 - i,11 - i,1], center = true);
}

//changing saturation
translate([0,15,0])
for(i = [0:10])
{
	color(hsvToRGB(1, 1 / 10 * i, 1, 1))
		translate([0,0,1 * i])
			cube([11 - i,11 - i,1], center = true);
}

//changing value
translate([15,0,0])
for(i = [0:10])
{
	color(hsvToRGB(1, 1, 1 / 10 * i, 1))
		translate([0,0,1 * i])
			cube([11 - i,11 - i,1], center = true);
}

//changing alpha
translate([15,15,0])
for(i = [0:10])
{
	color(hsvToRGB(1, 1, 1, 1 / 10 * i))
		translate([0,0,1 * i])
			cube([11 - i,11 - i,1], center = true);
}

/****************************************************/
/*				Modules and Functions				*/
/****************************************************/

function hsvToRGB(h = 1, s = 1, v = 1, a = 1) =	[
													hsvToPreRGB(h, s, v, a)[0] + hsvToMin(h, s, v, a),
													hsvToPreRGB(h, s, v, a)[1] + hsvToMin(h, s, v, a),
													hsvToPreRGB(h, s, v, a)[2] + hsvToMin(h, s, v, a),
													a
												];

function hsvToChroma(h, s, v, a) = s * v;

function hsvToHdash(h, s, v, a) = h * 360 / 60;

function hsvToX(h, s, v, a) = hsvToChroma(h, s, v, a) * (1.0 - abs((hsvToHdash(h, s, v, a) % 2.0) - 1.0));

function hsvToMin(h, s, v, a) = v - hsvToChroma(h, s, v, a);

function hsvToPreRGB(h, s, v, a) = 	hsvToHdash(h, s, v, a) < 1.0 ? [hsvToChroma(h, s, v, a), hsvToX(h, s, v, a), 0, a] :
									hsvToHdash(h, s, v, a) < 2.0 ? [hsvToX(h, s, v, a), hsvToChroma(h, s, v, a), 0, a] :
									hsvToHdash(h, s, v, a) < 3.0 ? [0, hsvToChroma(h, s, v, a), hsvToX(h, s, v, a), a] :
									hsvToHdash(h, s, v, a) < 4.0 ? [0, hsvToX(h, s, v, a), hsvToChroma(h, s, v, a), a] :
									hsvToHdash(h, s, v, a) < 5.0 ? [hsvToX(h, s, v, a), 0, hsvToChroma(h, s, v, a), a] :
									[hsvToChroma(h, s, v, a), 0, hsvToX(h, s, v, a), a];

```


[User]
Hi! I'm looking to create a parametric phone microscope attachment, similar to the "Phonescope" described, but I need it to be adaptable to a wider range of phones and have a few more features.  I'm thinking of using OpenSCAD to make this happen.

Here's what I'm envisioning:

**Core Functionality:**

*   **Phone Compatibility:**  I need a design that is truly parametric, where I can easily specify the phone's dimensions (X, Y, and Z as in the original file), and the design will adapt accordingly. This means the base structure, camera and flash cutouts, and the power button cutout should all adjust. I want to be able to add custom holes on the top.
*   **Lens Mount:** The design should include a mount for a lens of a specified radius. I want to be able to specify the X and Y offsets for both the lens and a flash cutout.
*   **Focus Mechanism:** A thumbscrew-based focus mechanism, like in the original, is required, but I want to be able to specify the radius of the thumbscrew and the thread, as well as the depth of the screw into the mount.

**Improvements/Additions:**

*   **Interchangeable Lens Mounts:** It would be fantastic if I could generate different lens mounts that could be swapped out easily, perhaps using a dovetail or press-fit type connection. This would let me use different lenses more easily.
*   **Adjustable height:** I need to be able to specify how high the "bottom" section extends, so the microscope can be set higher off the table. This should probably be a parametric height, which I can control. I need to be able to change the length of the main part as well, while maintaining the relative location of all the parts.
*   **Sturdier Bottom:** The bottom section needs to be a bit sturdier with thicker standoffs. I want to specify the thickness of these standoffs as well, and have it affect the height of the overall microscope.
*   **Attachment points:** I'm going to want some kind of customisable attachment points for things like a light source, so I need to be able to specify several connection points that are all fully parametric, including the shape, size, and position of these.
*   **OpenSCAD Libraries:** I'd like the final design to use the BOSL2 library for the features such as the dovetail and threads.

**Parametric Parameters:**

I would like to have these, at least:

*   `phone_x`:  Phone's width (short edge)
*   `phone_y`:  Phone's length (long edge)
*   `phone_z`: Phone's thickness
*   `wall_thickness`:  Thickness of the walls
*   `rim_width`:  Width of the rim around the phone
*   `tolerance`: General wiggle room for clearances
*   `lens_radius`: Radius of the lens
*   `lens_x_offset`: X-offset of the lens from the phone's edge
*   `lens_y_offset`: Y-offset of the lens from the phone's edge
*   `flash_radius`: Radius of the flash hole
*   `flash_x_offset`: X-offset of the flash from the phone's edge
*   `flash_y_offset`: Y-offset of the flash from the phone's edge
*  `power_button_x_offset` : X-offset of the power button
*   `power_button_x_length`: Length of the power button cutout
*   `power_button_z_height` : Height of the power button cutout
*   `lens_thickness` : Thickness of the lens
*  `top_stand_y` : Height of the top stand
*  `bottom_stand_wall`: Thickness of the bottom stand walls
*  `bottom_stand_z` : Height of the bottom stand
*   `screw_x_offset`: X-offset of the thumbscrew
*   `screw_y_offset` Y-offset of the thumbscrew
* `screw_small_radius`: Radius of the screw hole
*   `screw_head_radius`: Radius of the screw head slot
*   `screw_hex_width` Width of the "boat" shaped screw head slot
*   `screw_hex_thickness` : Thickness of the screw boat
* `thumbscrew_radius` : radius of the thumbscrew head
* `thumbscrew_inner_radius` : Inner radius of the thumbscrew thread
* `thumbscrew_z` : height of the thumbscrew above case
* `thumbscrew_inner_z` : Depth the thumbscrew engages
* `thumbscrew_end_radius` : radius of the bottom of the thumbscrew
*  `main_y_length` : Length of the main body.
* `attachment_points` : A list of attachment points, with each item having a location, size, and shape (cube, sphere or cylinder).

Could you generate an OpenSCAD file (or files) that implements this? I'm particularly interested in ensuring the design is easily modifiable for various phone sizes, as well as the inclusion of the different lens mount system, so please let me know if there's anything else you'd need to make this happen.

[Assistant]
Phonescope_v6_-_iPhone5_-_annotated.scad:
```
/////////////////////////////////////////////////////////////////////////////////
/// ///
/// Phonescope v6; 2014 03 24 ///
/// by Tom Baden (thingyverse ID: tbaden) ///
/// thomas.baden@uni-tuebingen.de ///
/// tombaden.wordpress.com ///
/// ///
/////////////////////////////////////////////////////////////////////////////////

// CUSTOMIZABLE VARIABLES

// X Dimension of phone (short edge)
X = 58.57;

// Y Dimension each part
Y = 16;

// Z Dimension of phone (thickness)
Z = 7.13;

// Thickness of walls
Wall = 2;

// Width of the rim
rim = 4;

// Jiggle room for things that should move
tol = 0.9;

// Jiggle room for push-fit parts
tol_S = 0.1;

// Lens radius
Lens_R = 4.4;

// X Lens distance from edge
Lens_Xoffset = 9.23;

// Y Lens distance from edge
Lens_Yoffset = 7.35;

// Flash hole radius
Flash_R = 2;

// X Flash distance from edge
Flash_Xoffset = 18.73;

// Y Flash distance from edge
Flash_Yoffset = 7.35;

// Power button distance from edge
Power_Xoffset = 17;

// Power button length
Power_X = 11;

// Power button height
Power_Z = 4;

///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
/// CUSTOMIZER CUTOFF: MODIFY ANYTHING BELOW HERE AT YOUR OWN RISK! ///////////////////
/// ( Yes, I know the code is messy - it grew organically and I havent cleaned it..) //
module customizer_cutoff(){};//////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

Lens_thickness = 3;

Topstand_Y = 7; // 8

Bottomstand_wall = 3;
Bottomstand_Z = 9.5;

marker_length = 30;

Screw_X_offset = 0;
Screw_Y_offset = 2;
Screw_R_small = 1.8; // screw needs to fit snug but not engage
Screw_R_head = 2.9;; // head of screw slot for part B
Screw_X_hex = 6.05; //7.4; // how wide is the boat
Screw_Z_hex = 2.6; //3.2; // how thick is the boat

Thumbscrew_R = 3;
Thumbscrew_inner_R = 1.5;//1.5 is for screw to screw in;
Thumbscrew_Z = 5; // how much "taller" than case is the foot when fully retracted
Thumbscrew_inner_Z = 4; // how deep into foot can screw go
Thumbscrew_depth = Z+1*Wall+Lens_thickness+tol - 2* Wall - Screw_Z_hex - tol/2; // 7
Thumbscrew_Z_real = Thumbscrew_Z + Thumbscrew_depth;
Thumbscrew_R_end = 6;

Screw_R_big = Thumbscrew_R+tol/4;
Screw_Z_big = Thumbscrew_depth; // how deep does knob go in?

sep = 30; // 123.83/2;

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

module top(){
	translate([0,Wall/2+sep,(Lens_thickness-Wall)/2]){cube([X+2*Wall+tol,Y+1*Wall+tol,Z+1*Wall+Lens_thickness+tol], center = true);} // main top

	translate([0,Wall/2+sep+(Y+1*Wall+tol)/2+Topstand_Y/2,(Lens_thickness-Wall)/2]){cube([X+2*Wall+tol,Topstand_Y,Z+1*Wall+Lens_thickness+tol], center = true);} // Top_extra

}
module top_sub(){
	translate([0,+sep,0]){cube([X+tol,Y+tol,Z+tol], center = true);} // mainhole_top

	translate([0,+sep-rim/2-tol_S,-Wall]){cube([X+tol-2*rim,Y+tol-rim,Z+tol], center = true);} // mainhole_top_wallcut

	translate([-(X+tol)/2+Lens_Xoffset,Wall/2+sep+(Y+1*Wall+tol)/2+Topstand_Y/2-Screw_Y_offset,(Lens_thickness-Wall)/2-(Z+1*Wall+Lens_thickness+tol)/2]){cube([1,marker_length,1], center = true);} // cam marker 1

	translate([-(X+tol)/2,(Y+tol)/2-Lens_Yoffset+sep,(Lens_thickness-Wall)/2-(Z+1*Wall+Lens_thickness+tol)/2]){cube([marker_length,1,1], center = true);} // cam marker 2

	translate([-(X+tol)/2+Lens_Xoffset,(Y+tol)/2-Lens_Yoffset+sep,Z/2+Lens_thickness/2+tol/2]){
		cylinder($fn = 50, r = Lens_R+tol_S, h = Lens_thickness, center = true);} // camerahole
	translate([-(X+tol)/2+Flash_Xoffset,(Y+tol)/2-Flash_Yoffset+sep,Z/2+Lens_thickness/2+tol/2]){
		cylinder($fn = 50, r = Flash_R+tol_S, h = Lens_thickness, center = true);} // flashhole

	translate([Power_Xoffset-(X+2*Wall+tol)/2,Wall/2+sep+(Y+1*Wall+tol)/2,0]){cube([Power_X,10,Power_Z], center = true);} // power button hole

	translate([Screw_X_offset,Wall/2+sep+(Y+1*Wall+tol)/2+Topstand_Y/2-Screw_Y_offset,(Lens_thickness-Wall)/2]){
		cylinder($fn = 50, r = Screw_R_small, h = Z+1*Wall+Lens_thickness+tol, center = true);} // screwhole1 - small
	translate([Screw_X_offset,Wall/2+sep+(Y+1*Wall+tol)/2+Topstand_Y/2-Screw_Y_offset,(Lens_thickness-Wall)/2-(Z+1*Wall+Lens_thickness+tol)/2+Screw_Z_big/2]){
		cylinder($fn = 50, r = Screw_R_big, h = Screw_Z_big, center = true);} // screwhole1 - big

	translate([Screw_X_offset,Wall/2+sep+(Y+1*Wall+tol)/2+Topstand_Y/2-Wall/2,(Lens_thickness-Wall)/2+(Z+1*Wall+Lens_thickness+tol)/2-Screw_Z_hex/2-Wall]){cube([Screw_X_hex,Topstand_Y+Wall+0.01,Screw_Z_hex], center = true);}

}

difference(){top();top_sub();}

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

module bottom(){
	translate([0,-Wall/2-sep,(Lens_thickness-Wall)/2+Bottomstand_Z/2]){cube([X+2*Wall+tol+2*Bottomstand_wall,Y+1*Wall+tol+Topstand_Y,Z+1*Wall+Lens_thickness+tol+Bottomstand_Z], center = true);} // main bottom

}
module bottom_sub(){
	translate([0,-sep,0]){cube([X+tol,Y+tol+Topstand_Y,Z+tol], center = true);} // mainhole_bottom
	translate([0,-sep+rim/2+tol_S,-Wall]){cube([X+tol-2*rim,Y+tol-rim+Topstand_Y,Z+tol], center = true);} // mainhole_bottom_wallcut

	translate([-Screw_X_offset,-Wall/2-sep+(Y+1*Wall+tol)/2-Screw_Y_offset,(Lens_thickness-Wall)/2]){
		cylinder($fn = 50, r = Screw_R_head, h = Z+1*Wall+Lens_thickness+tol+0.01, center = true);} // screwhole_fit

	translate([+(X+tol)/2-Lens_Xoffset,-(Y+tol)/2+Lens_Yoffset-sep-Topstand_Y/2,Z/2+Lens_thickness/2+tol/2]){
		cylinder($fn = 50, r = Lens_R+tol, h = Lens_thickness+0.01, center = true);} // camerahole_fit

	translate([0,-Wall/2-sep,(Lens_thickness-Wall)/2+(Z+1*Wall+Lens_thickness+tol)/2+Bottomstand_Z/2]){cube([X+2*Wall+tol+tol_S,Y+1*Wall+tol+Topstand_Y,Bottomstand_Z], center = true);} // sidestands

}

difference(){bottom();bottom_sub();}

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

module Thumbscrew(){
	translate([(X+2*Wall+tol)/2,0,0]){
		cylinder($fn = 50, r = Thumbscrew_R, h = Thumbscrew_Z_real-tol, center = true);} // shaft1
	translate([(X+2*Wall+tol)/2,0,-Thumbscrew_Z_real/2+(Thumbscrew_Z-tol)/2]){
		cylinder($fn = 12, r = Thumbscrew_R_end, h = Thumbscrew_Z-tol, center = true);} // foot1

}

module Thumbscrew_hole(){

	translate([(X+2*Wall+tol)/2,0,Thumbscrew_Z_real/2-Thumbscrew_inner_Z/2]){
		cylinder($fn = 50, r = Thumbscrew_inner_R, h = Thumbscrew_inner_Z+0.1, center = true);} // hole

}

difference (){Thumbscrew();Thumbscrew_hole();}

```


[User]
I'd like a parametric OpenSCAD design for creating containers, like bowls or vases, using a lathe-like process. The main feature will be a customizable profile created using a Bezier curve. I want to be able to draw control points in a polygon widget, and those control points will define the Bezier curve's shape. The design should take that curve, essentially treat it as a cross-section, and then rotate it around a central axis to create a 3D object.

Specifically, I need the following parameters:

*   `bezier_points`: This will be a list of coordinates and indices. A user will draw a polygon and its shape will be expressed as coordinates in this array. The polygon will determine the control points for the Bezier curve. The first and last points will be the endpoints, and any points in between will pull the line into a curve.
*   `radius`: The overall radius of the final object, basically how wide it will be.
*   `height`: The overall height of the final object.
*   `slices`: This will control the number of layers or segments used to approximate the Bezier curve. A high number will make the surface very smooth, while a low number will show facets.

I want the design to automatically adjust the final profile based on the number of control points provided in the `bezier_points` variable and use the appropriate Bezier curve function (linear, quadratic, cubic, or fourth-order). If the user doesn't provide at least two control points, it should just display a cylinder to avoid any errors.

The final model should be solid, meant to be printed with zero infill and top layers (or stopped early to avoid top layers). Also, the code should make sure the lathe axis is at x=0.

No external libraries are needed, I think. Can you generate that for me, please?

[Assistant]
bezier-lathe.scad:
```
//Customizable Bezier Bowl
//preview[tilt:side]

// Bezier curve control points. Draw two to five blobs; the center of each blob is used as the actual point. The first and last points are the endpoints of the curve. Any intermediate control points pull the line towards them into a curve. Object is formed by connecting curve endpoints to left edge with horizontal lines, then rotating that shape around the left edge as if it is the axis of a lathe or potter's wheel.
bezier_points = [[[-0.1273972602739726,-0.46164383561643835],[-0.12465753424657534,-0.47534246575342465],[-0.12465753424657534,-0.47534246575342465],[-0.13013698630136986,-0.48904109589041095],[-0.1410958904109589,-0.5],[-0.1547945205479452,-0.5027397260273972],[-0.17123287671232876,-0.49726027397260275],[-0.17397260273972603,-0.48356164383561645],[-0.1684931506849315,-0.46986301369863015],[-0.15205479452054796,-0.46164383561643835],[0.06712328767123288,-0.25068493150684934],[0.06164383561643835,-0.26438356164383564],[0.06164383561643835,-0.27808219178082194],[0.06986301369863014,-0.29178082191780824],[0.08356164383561644,-0.29726027397260274],[0.09726027397260274,-0.29178082191780824],[0.1,-0.27808219178082194],[0.10547945205479452,-0.26438356164383564],[0.10547945205479452,-0.25068493150684934],[0.1,-0.236986301369863],[0.09178082191780822,-0.22602739726027396],[0.0013698630136986301,0.04246575342465753],[-0.012328767123287671,0.03972602739726028],[-0.026027397260273973,0.031506849315068496],[-0.036986301369863014,0.023287671232876714],[-0.036986301369863014,0.009589041095890411],[-0.028767123287671233,-0.0013698630136986301],[-0.015068493150684932,-0.0013698630136986301],[0.0013698630136986301,-0.0013698630136986301],[0.015068493150684932,0.00410958904109589],[0.023287671232876714,0.015068493150684932],[0.026027397260273973,0.031506849315068496],[0.026027397260273973,0.045205479452054796],[-0.42054794520547945,0.19041095890410958],[-0.4315068493150685,0.17945205479452056],[-0.4315068493150685,0.16575342465753426],[-0.42054794520547945,0.15753424657534246],[-0.40684931506849314,0.1547945205479452],[-0.39315068493150684,0.15205479452054796],[-0.37945205479452054,0.15753424657534246],[-0.37945205479452054,0.17123287671232876],[-0.37945205479452054,0.18493150684931506],[-0.37945205479452054,0.18493150684931506],[-0.3821917808219178,0.19863013698630136],[-0.2534246575342466,0.4452054794520548],[-0.26164383561643834,0.43424657534246575],[-0.2589041095890411,0.42054794520547945],[-0.2452054794520548,0.41506849315068495],[-0.23150684931506849,0.41506849315068495],[-0.21780821917808219,0.42054794520547945],[-0.21506849315068494,0.43424657534246575],[-0.21506849315068494,0.44794520547945205]],[[0,1,2,3,4,5,6,7,8,9],[10,11,12,13,14,15,16,17,18,19,20],[21,22,23,24,25,26,27,28,29,30,31,32],[33,34,35,36,37,38,39,40,41,42,43],[44,45,46,47,48,49,50,51]]]; // [draw_polygon]

// Stretch result to this radius. (Technically, width of the Bezier Points sketch box; object radius may differ.)
radius = 30;

// Stretch result to this height. (Technically, height of the Bezier Points sketch box; object height may differ.)
height = 30;

// Approximate curve with this many layers. High values (like 100) yield smooth surfaces; low values (like 10) yield a faceted appearance.
slices = 100;

/* [Hidden] */

// When the polygon drawing is cleared, bezier_points[] is borked;
// however, as long as we draw *something* (ie the stock cylinder),
// error messages aren't shown. OK since they're expected & temporary.

// Number of control points. We need two to four.
vn = len(bezier_points[1]);

// v_mean defaults control points to [0, 0] until drawn
v0 = v_mean(bezier_points[0], bezier_points[1][0]);
v1 = v_mean(bezier_points[0], bezier_points[1][1]);
v2 = v_mean(bezier_points[0], bezier_points[1][2]);
v3 = v_mean(bezier_points[0], bezier_points[1][3]);
v4 = v_mean(bezier_points[0], bezier_points[1][4]);

// v is a list of vertex vectors
// p is a list of indices
// (i is used to terminate recursion at end of p)
// return the sum of the vertex vectors in v identified by p
function v_sum(v, p, i = 0) = (i == len(p) ? [0, 0] : v[p[i]] + v_sum(v, p, i + 1));

// v is a list of vertex vectors
// p is a list of indices
// return the mean of the vertex vectors in v identified by p (ie, the centroid of selected vertices)
// returns [0, 0] if p is empty
function v_mean(v, p) = (len(p) > 0 ? v_sum(v, p) / len(p) : [0, 0]);

// Linear Bezier (linear interpolation)
function lb(t, p0, p1) = p0 + (t * (p1 - p0));

// Quadratic Bezier (one control point)
function qb(t, p0, p1, p2) = lb(t,
		lb(t, p0, p1),
		lb(t, p1, p2));

// Cubic Bezier (two control points)
function cb(t, p0, p1, p2, p3) = lb(t,
		qb(t, p0, p1, p2),
		qb(t, p1, p2, p3));

// Fourth-order Bezier (three 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) =
		(vn == 2 ? lb(t, v0, v1) :
		(vn == 3 ? qb(t, v0, v1, v2) :
		(vn == 4 ? cb(t, v0, v1, v2, v3) :
		(vn == 5 ? b4(t, v0, v1, v2, v3, v4) : [0, 0]))));

if (vn < 2 || vn == undef) {

	// Just show a dummy object if there aren't enough control points;
	// suppresses confusing Customizer error messages while drawing.
	cylinder(r=radius, h=height, $fn=180);

} else {

	// 4. Bring result to requested size and position above floor
	translate([0, 0, height/2]) scale([radius, radius, height])

	// 3. Spin the profile on the lathe/potter's wheel/whatever
	rotate_extrude($fn=180)

	// 2. Move the profile so the lathe axis (left edge of drawing) is on the origin
	translate([0.5, 0, 0])

	// 1. Assemble approximated profile from the requested number of slices.
	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), q = b(i/slices)) {
				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])
				]);
			}
		}
	}
}

```


[User]
I'm looking to design a converging-diverging rocket nozzle in OpenSCAD, and I'd like to be able to adjust a number of parameters to optimize it. I've seen some designs before, and the best ones seem to use a combination of cones, arcs, and a parabolic bell section.

Specifically, I need to control the following:

*   **Wall Thickness:**  The approximate thickness of the nozzle walls.
*   **Inlet Radius (Rinlet):** The radius of the nozzle's opening where the flow enters.
*   **Converging Angle (Ain):**  The angle of the converging cone section.
*   **Throat Radius (Rthroat):** The radius of the narrowest point of the nozzle.
*   **Exit Radius (Rexit):** The radius of the nozzle's exhaust opening.
*   **Diverging Transition Angle (Aout):** The angle where the diverging arc transitions into a parabolic bell.
*   **Nozzle Length Percentage (pct):**  A factor to determine the length of the nozzle relative to a 15-degree cone design.  This seems to be a way to compress the length.
*   **Minimum External Radius (minRadius):**  This would set a minimum external size of the nozzle.

The nozzle should have four sections: a converging cone, a converging radial inlet, a diverging radial outlet, and a parabolic bell at the end. It's also important that the transitions between these sections are smooth.

Can you generate the OpenSCAD code for a parametric model of this? I'm not sure exactly what libraries this would need, but I'm familiar with the basics.

[Assistant]
ConvergingDiverging_v1.1.scad:
```
// Copyright (c) 2014-2016, William Waters
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list
//    of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//    of conditions and the following disclaimer in the documentation and/or other materials
//    provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used
//    to endorse or promote products derived from this software without specific prior
//    written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//
// This script builds a converging-diverging nozzle of initial radius Rinlet with
// four sections:
//
// A converging cone with half-angle Ain
// A converging radial inlet smoothly tangent to Ain
// A diverging radial outlet smoothly tangent to a Aout
// A diverging parabolic bell expanding to radius Rexit
//
// Documentation: http://www.waters.to/blog/rocket-nozzles-part-1-the-math/
//
// Author: Bill Waters www.waters.to
//
// Credits:
// Nozzle equations: http://www.scribd.com/doc/58809639/13/Bell%C2%A0nozzle
// Bezier equations: Thingiverse user donb - http://www.thingiverse.com/thing:8931
//
// Thanks to reprap user buback who pointed out the utility of donb's algorithm in this thread:
// http://forums.reprap.org/read.php?88,319401 . Although his project at
// http://www.thingiverse.com/thing:8931 bears a superficial resemblance to this one, there
// are many important differences.
//
// In particular, this program models the solid interior of the nozzle and only
// in post-processing does it compute an outer shell.  In modeling that interior space, I
// attempt to be as rigorous as possible in my math in order to avoid lumps, bumps, and
// discontinuities.  Finally, I attempt to document my work to improve understanding of
// both the math and the model.
//

//CUSTOMIZER VARIABLES

// Wall Thickness of the Nozzle (approximate)
wallThickness = 1.5;

// Radius of the nozzle inlet
Rinlet = 8;

// Converging Angle
Ain = 35;

// Radius of the nozzle throat
Rthroat = 1.5;

// Radius of the nozzle exit.
// This plus Rthroat define the nozzle's expansion ratio
Rexit = 16;

// Angle at which the throat transitions
// from an arc to a parabola
Aout = 30; // [20, 25, 30, 35, 45]

// How long should the nozzle be relative to a 15% cone
pct = .7; // [.60, .65, .70, .75, .80, .85, .90, .95, 1]

// Experimental: minimum external radius
minRadius = 3;

//CUSTOMIZER VARIABLES END

// Important for rendering circles and arcs smoothly
$fn = 200 /* don't customize */ + 0;

if (wallThickness > Rthroat) {
   echo("WARNING: wallThickness should be less than Rthroat");
}

// Lead-in to the converging cone
leadInCylinderLen = Rinlet;

finalize(3d="true")
  makeShell(thickness = wallThickness, minRadius = minRadius)
    full2dNozzle(leadInCylinderLen = leadInCylinderLen,
                 Rinlet = Rinlet, Ain = Ain, Rthroat = Rthroat,
                 Rexit = Rexit, Aout = Aout, pct = pct);

module full2dNozzle(Rinlet, Ain, Rthroat, Rexit, Aout, pct,
                    leadInCylinderLen = 0)
{

  // convergent section is just a conic nozzle mirrored about the y axis
  mirror()
    conicNozzle2d(Rthroat = Rthroat,
                  Rexit = Rinlet,
                  Rarc = 1.5 * Rthroat,
                  a = Ain,
                  extraLen = leadInCylinderLen);

  bellNozzle2d(Rthroat = Rthroat,
               Rexit = Rexit,
               Rarc = .382 * Rthroat,
               a = Aout,
               pct = pct);
}

// Returns the point P where the exit arc is tangent to the given angle
//
//        _     /
//      -   -  / a=angle
//     /     \P_____________ y = Rthroat + Rarc - Rarc * cos(a)
//     \     /
//      - _ - ______________ y = Rthroat
//        |
//        |
//        __________________ y = 0
//
//
function findTransition(Rthroat, Rarc, angle) =
  [ Rarc * sin(angle),
    Rthroat + Rarc - (Rarc * cos(angle))
  ];

// Builds the 2D profile of a nozzle with radius Rthroat
// expanding along an arc of radius Rarc into a cone with
// half-angle a, terminating at exit radius Rexit
//
// Recommended values converging nozzles:
// Rarc: 1.5 * Rthroat
// a: 20 < a < 35
module conicNozzle2d(Rthroat, Rarc, Rexit, a, extraLen = 0)
{

  // The transition point from arc to cone
  Ptrans = findTransition(Rthroat, Rarc, a); //[x, Rthroat + Rarc - y];

  // Compute h, the rise from Ptrans to Rout
  z = Rexit - Ptrans[1];

  // Compute q, the run from Ptrans to the exit plane
  q = z / tan(a);
  len = Ptrans[0] + q;

  throatSegment(Rthroat = Rthroat,
				   Rarc = Rarc,
                Ptrans = Ptrans);

  coneSegment2d(Ptrans,
                [len, Rexit]);

  totalLen = len + extraLen;
  if (extraLen) {
    polygon([[len, 0], [totalLen, 0],
             [totalLen, Rexit], [len, Rexit]]);
  }
}

// Builds the 2d profile of a nozzle with radius Rthroat
// expanding along an arc of radius Rarc transitioning at
// angle a into a parabolic bell of final radius Rexit.
//
// The length of the nozzle is specified as a percentage
// relative to the length of a 15 degree cone nozzle.
//
//
// Recommended value for Rarc: 0.382 * Rthroat (diverging nozzles)
// Recommended values for a: 20 < a < 35
// Recommended values for pct: 0.6 < pct < 0.8
//
module bellNozzle2d(Rthroat, Rarc, Rexit, a, pct)
{
  Ptrans = findTransition(Rthroat, Rarc, a);

  // Calculate length of a full 15 degree cone
  cone15Len = Rexit / tan(15);

  bellLen = pct * cone15Len;

  bellSegment2d(Ptrans = Ptrans,
	             Pexit = [bellLen, Rexit],
                a = a);

  throatSegment(Rthroat = Rthroat,
					Rarc = Rarc,
					Ptrans = Ptrans);

}

// Builds a bell nozzle from Ptrans to Pexit that is:
// - tangent to angle a at Ptrans
// - horizontal at Pexit
module bellSegment2d(Ptrans, Pexit, a)
{
   // Compute P1, the intersection of lines
   // [P1, Px] (horizontal line)
   // [Ptrans, P1] (rising to the right with a slope of a)

   // h is the rise from Ptrans to P1.  This is easy since
   // we assume a horizontal exit
   h = Pexit[1] - Ptrans[1];

	// x is the run from Ptrans to P1
   x = h / tan(a);

   p1 = Ptrans + [x, h];

   bezierApprox(Ptrans, p1, Pexit, steps=20 );
}

// Make a trapezoidal segment of a cone like this:
//
//            Pexit
//          /|
//         / |
// Ptrans /  |
//        |  |
//        |  |
//        |  |
//        |  |
//        ----
module coneSegment2d(Ptrans, Pexit) {
   p2 = [Pexit[0], 0];
   p3 = [Ptrans[0], 0];
   polygon([Ptrans, Pexit, p2, p3]);
}

// Make a segment that is a rectangle
// with a circular arc nicked out of
// corner.
//        _
//      -   -
//     /     \                Ptrans
//     \     /|             /|
//      - _ - |  Rthroat _ - |
//        |   |          |   |
//        |   |          |   |
//        -----          -----
//
module throatSegment(Rthroat, Rarc, PTrans) {
  difference() {
    polygon([[0, 0],
	          [0, Rthroat],
             Ptrans,
             [Ptrans[0], 0]]);

    translate([0, Rthroat + Rarc, 0])
      circle(r=Rarc);
  }
}

// Builds a quadratic bezier curve from P0 to P2 using P1 as the 3rd
// control point.
//
// Based on algorithm by donb - http://www.thingiverse.com/thing:8931
// Adapted from a variant by buback - http://www.thingiverse.com/thing:8931
//
// I modified the algorithm to create a trapezoidal approximation (buback used triangles to
// create the inverse of what we build here)
//
// The idea of bezier curve is to build an arc from p0 to p2 that is
// tangent to the line from p0 -> p1 as well as the line from p1 -> p2.
//
// We approximate that curve via a series of trapezoids
//
// In the drawing, X is P0, Y is P1 and Z is P2
//
//      Y   . . Z
//        . | | |
//      . | | | |
//      | | | | |
//    X | | | | |
//    | | | | | |
//    | | | | | |
//    | | | | | |
//    -----------
module bezierApprox(p0,p1,p2,steps=25)
{
	stepsize1 = (p1-p0)/steps;
	stepsize2 = (p2-p1)/steps;
	for (i=[0:steps-1]) {
		point1 = p0+stepsize1*i;
		point2 = p1+stepsize2*i;
        point3 = p0+stepsize1*(i+1);
        point4 = p1+stepsize2*(i+1);
		bpoint1 = point1+(point2-point1)*(i/steps);
        bpoint2 = point3+(point4-point3)*((i+1)/steps);
        x0 = bpoint1[0];
        x1 = bpoint2[0];
		polygon(points=[bpoint1,bpoint2,
                        [x1, 0],
                        [x0, 0]]);
	}
}

// Turns a 2-d profile in X-Y space into a 3D solid
module finalize(3d) {
    // work around floating point rounding bug in rotate_extrude
    epsilon = [1e-5, 0, 0];
  if (3d == "true") {
    rotate_extrude()
      translate(epsilon) rotate([0, 0, -90]) children(0);
  } else {
    children();
  }
}

// Takes a 2D profile, shifts it vertically
// and subtracts the original.
//
// A more precise approach would use a minkowski sum, but
// that seems to be inordinately expensive computationally
// as of OpenScad 2014.3
//
// If thickness is zero, leaves the profile alone
module makeShell(thickness, minRadius) {
  if (thickness) {
    difference() {
      union() {
        polygon([[-minRadius, Rthroat], [-minRadius, minRadius],
                   [minRadius, minRadius], [minRadius, Rthroat]]);
        translate([0, thickness, 0])
          children(0);
      }
     children(0);
   }
  } else {
    children(0);
  }
}

```


[User]
I'd like to create a parametric smartphone holder that can be printed. I need it to support the phone in three different angles – approximately 45 degrees, 30 degrees, and 90 degrees.

Here's what I'm looking for in terms of parameters:

*   **`gap_thickness`**: This will be the space where the phone sits, so I need to be able to adjust it for different phone sizes, in millimeters. I'd like a range from about 5mm to 15mm.
*   **`width`**: The width of the holder, also in millimeters.
*   **`length`**: The length of the holder, in millimeters.
*   **`height`**: The overall height of the holder, in millimeters. Let's say a range of 10mm to 25mm.
*   **`text`**: I'd like to be able to add some text on the holder. It can also be empty.
*   **`textSize`**: The size of the text in millimeters. Allow a range of about 4mm to 20mm.
*   **`corner_radius`**: The radius of the corners of the holder in millimeters. I want to be able to have sharp corners or rounded ones, so let's make this go from 0 (no rounding) up to 20mm.

The holder should have a main body with rounded corners and the three angled supports, using cube shapes rotated on one axis and at different lengths/positions, all attached to the main body. I'd like the text to be on the front of the holder near the bottom.

I'd like you to generate OpenSCAD code for this, please. I'm also using the `write/Write.scad` library for the text.

[Assistant]
smartphoneholder_parametric.scad:
```
// Original von Hardest
// TODO: Copyright Infos

use <write/Write.scad>

// Gap in mm. Adjust to your phone size.
gap_thickness = 11; // [5:15]

// Width in mm.
width = 40;

// Length in mm.
length = 125;

// Height in mm.
height = 15; // [10:25]

// The text. Can also be empty.
text = "Text";

// Text height in mm.
textSize = 11; // [4:20]

// Radius of the corners. 0 = no corners.
corner_radius = 13; // [0:20]

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

module roundedCube(dim,r,sidesOnly) {
	translate([dim[0]/2,dim[1]/2,dim[2]/2]) roundedBox(dim,r,sidesOnly);
}

module smartphoneholder() {
	$fn=100;
	rotate([0,0,180]) translate([-width/2+1,(-length/3)*2,height]) color("red") {
		write(text, h=textSize,t=2.5,font="write/orbitron.dxf",center=true);
	}

	difference () {
		roundedCube ([width,length,height],corner_radius,true);
		union () {
			translate ([-1,15,height/4]) rotate (a = 40, v=[1,0,0]) cube (size = [width+2,height*2,gap_thickness]);
			translate ([-1,(length/2+gap_thickness/2),height/2]) rotate (a = 90, v=[1,0,0]) cube (size = [width+2,height*2,gap_thickness]);
			translate ([-1,length-10,height/2]) rotate (a = 120, v=[1,0,0]) cube (size = [width+2,height*2,gap_thickness]);
		}
	}
}

translate([width/2,length/2,0]) rotate([0,0,180]) smartphoneholder();
```


[User]
I'd like to design a new X-axis leveling tool for my Prusa i3, and I'd like your help creating the OpenSCAD files. I've been using a design that rests on the Y-axis smooth rod and you manually adjust the Z-axis until the X-axis rod touches the top of the tool, but I think a better design would hang from the X-axis rod. This way, I could hang a tool on each side of the X-axis and adjust them simultaneously.

Here are the requirements for the design:

*   **Hanging Mechanism:** The tool should have a "hook" or similar mechanism that allows it to hang securely from the X-axis smooth rod. This hook should be designed to minimize any wobble or slipping.
*   **Reference Surface:** The tool should have a flat, precisely defined reference surface that will rest on the Y-axis smooth rod. This surface should be designed so that the Y-axis rod sits securely. When the tool is hanging correctly from the X axis, this reference surface will be at a known distance from the hook on the X-axis.
*   **Parametric Design:** The design should be parametric, allowing me to easily adjust the following:
    *   `x_rod_diameter`: Diameter of the X-axis smooth rod.
    *   `y_rod_diameter`: Diameter of the Y-axis smooth rod.
    *   `hook_depth`: Depth of the hook from the center of the X-axis rod.
    *   `reference_height`: Vertical distance from the hook to the reference surface that will rest on the Y-axis rod.
    *   `tool_width`: Overall width of the tool.
    *   `tool_thickness`: Overall thickness of the tool.
    *   `wall_thickness`: Thickness of the walls of the tool.
*   **Material Considerations:** I'll be 3D printing this tool, so please keep that in mind when designing for strength and printability.  It should be strong enough to not break under its own weight, and the hook should be able to reliably support it.
*   **OpenSCAD Libraries:** I'd like to use the BOSL2 library if possible.

I think that covers everything. Let me know if you have any questions. I'm looking forward to seeing your design!

[Assistant]
X_Leveler.scad:
```
// Customizable X-axis leveling tool designed for Prusa i3 Berlin.  Used to
// make sure that each side of the X-axis is at the same height.  Necessary
// since there's a stepper motor on each side and they can get out of step.
//
// To use:
// Place "forked" end of tool on Y smooth rod and use Z control to bring the X axis
// just above the flat part of the top of the tool.  Manually rotate the Z rod
// for that side so the X smooth rod just touches the bottom of the "L" at the top
// of the tool.  Adjust the other side the same way.  Go back and forth to each
// side a few times to get the X-axis rod level.
//
// IMPORTANT: Don't squish the tool between the rods by using the Z motor control -
// this could put pressure on the smooth rods and possibly bend them.  Doing the
// final adjustment by hand works best.
//
// Successfully printed using 0.2mm layer height, 1.0mm shell width and 30% infill
// density.  Square or triangular shapes might be more accurate than the curves
// that touch the smooth rods.  Happy to see a remix!

// Michael Ang
// http://michaelang.com
// 25.03.2014

// Copyright (C) 2014 Michael Ang
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Additionally:
// This work by Michael Ang is licensed under a Creative Commons
// Attribution-ShareAlike 4.0 International License.

// Distance between centers of claws
z_distance = 60;

// Diameter of smooth rods, plus a little extra so the claw sits flat
rod_diameter = 8.2;

// How deep to make claws
claw_depth = 25;

// How tall to make claws
claw_height = 15;

// Thickness of walls
wall_thickness = 3;

// Width of T-beam
beam_width = 10;

// Height of T-beam
beam_height = 10;

module claw(inner_radius, height, depth, wall_thickness, with_entry = false) {
	total_width = (inner_radius + wall_thickness) * 2;

	difference() {
		// outer part
		union() {
			cylinder(r = inner_radius + wall_thickness, h = depth, center = true);
			translate([-total_width/2, -(height - inner_radius - wall_thickness), -depth/2]) cube([(inner_radius + wall_thickness) * 2, height - inner_radius - wall_thickness, depth]);
			if (with_entry) {
				translate([0,0,-depth/2]) cube([inner_radius + wall_thickness, inner_radius + wall_thickness, depth]);
			}
		}

		claw_inner(inner_radius, height, depth, wall_thickness, with_entry);
	}
}

module claw_inner(inner_radius, height, depth, wall_thickness, with_entry) {
	cut_overlap = 1;

	cube_cutout_height = height - inner_radius - wall_thickness + cut_overlap;
	entry_cutout_height = height - wall_thickness + cut_overlap;

	// inner part
	union() {
		cylinder(r = inner_radius, h = depth + cut_overlap, center = true);
		translate([-inner_radius, -cube_cutout_height, -(depth + cut_overlap)/2]) cube([inner_radius * 2, cube_cutout_height, depth + cut_overlap]);
		if (with_entry) {
			// Chop off part of claw so rod can enter from side
			translate([-(inner_radius+wall_thickness+cut_overlap/2), -entry_cutout_height + inner_radius, -(depth + cut_overlap)/2]) cube([inner_radius * 2, entry_cutout_height, depth + cut_overlap]);
		}
	}
}

module t_beam(length, width, height, thickness) {
	translate([-width/2, 0, 0]) cube([width, length, thickness]);
	translate([-thickness/2, 0, 0]) cube([thickness, length, height]);
}

module x_leveler(z_distance, rod_radius, claw_depth, claw_height, wall_thickness, beam_width, beam_height) {
	translate([0, 0, claw_depth/2]) claw(rod_radius, claw_height, claw_depth, wall_thickness);
	translate([0, z_distance, rod_radius + wall_thickness]) rotate([180,90,0]) claw(rod_radius, claw_height, claw_depth, wall_thickness, with_entry = true);

	difference() {
		t_beam(z_distance, beam_width, beam_height, wall_thickness);
		translate([0, 0, claw_depth/2]) claw_inner(rod_radius, claw_height, claw_depth, wall_thickness);
		translate([0, z_distance, rod_radius + wall_thickness]) rotate([180,90,0]) claw_inner(rod_radius, claw_height, claw_depth, wall_thickness, with_entry = true);
	}
}

x_leveler(z_distance, rod_diameter / 2, claw_depth, claw_height, wall_thickness, beam_width, beam_height);
```


[User]
I'm looking to create a parametric OpenSCAD design for a compressed air rocket, similar to the one I've been playing with. I've included my existing code as a starting point, but I'd like the design to be more robust and flexible. The basic idea is a hollow cylinder for the body, a cone for the nose, and a number of fins, all configurable.

Here's a breakdown of what I need:

*   **Rocket Body:**
    *   The main body should be a hollow cylinder with a user-defined inner diameter and height.
    *   The wall thickness should be set as a parameter as well, and should be used everywhere (including the cone and fins) as 'perimeter_width'.
    *   The design should have a clear way to ensure the cylinder and cone wall thickness is correct for 3D printing (a crucial setting).
*   **Nose Cone:**
    *   The nose cone should be a truncated cone, attached to the top of the cylinder.
    *   It should also have user-defined height and a consistent wall thickness as well. It should blend smoothly into the cylindrical body.
    *   The very tip of the nose should be a small cylindrical cap, also with the same perimeter wall thickness.
*   **Fins:**
    *   The number of fins should be configurable.
    *   Each fin should be a simple triangle with user-defined width and height.
    *   Fins should be placed at the base of the cylinder, and spaced evenly around it, and the wall thickness should be used here as well.

I would like the code to be modular and easy to understand, and if possible, using named modules with comments indicating what they do. If it makes sense, split these into separate modules that are then combined by a main one. I would also like to use the standard functions (difference(), linear_extrude(), etc) and not depend on any custom libraries. Could you help me create that parametric OpenSCAD file?

[Assistant]
compressedAirRocket.scad:
```

/* [Global] */

/* [Rocket] */

inner_diameter = 10.5;

body_height = 40;  //[10:100]
nose_height = 16; //[2:100]
number_of_fins = 3; //[0:4]
fin_width = 10;  //[2:50]
fin_height = 20;  //[2:100]

/* [Extruder] */
// Width of a single wall/perimeter in mm - adjust to ensure model is sliced correctly
perimeter_width = 0.7;

/* [Hidden] */

// other
eta = 0.001;
perim = perimeter_width;
2perim = 2*perim;

// library functions
module donut(or,ir) {
	difference() {
        circle(or);
    	circle(ir);
    }
}

// rocket functions

module rocketBody() {
	$fn=32;

	id=inner_diameter;
	h1=body_height;
	h2=nose_height;

	fins = number_of_fins;
	finW = fin_width;
	finH = fin_height;

	union() {
		// body
		linear_extrude(height = h1)
			donut(id/2 + perim, id/2);

		// cone
		translate([0,0,h1-eta])
			difference() {
				cylinder(r1=id/2 + perim, r2=2perim, h=h2);

				translate([0,0,-eta])
					cylinder(r1=id/2, r2=perim, h=h2);
			}

		// tip
		translate([0,0,h1+h2-2*eta])
			cylinder(r1=2perim, r2=perim, h=2perim);

		// fins
		for(i=[0:fins-1])
			rotate([0,0,i*360/fins])
			translate([id/2,0,0])
			rotate([90,0,0])
			linear_extrude(perim)
			polygon(points=[[0,0],[0,finH],[finW,0]]);

	}
}

rocketBody();

```


[User]
I'm looking to design a Bowden tube attachment for my Printrbot Simple 2014 with an aluminum extruder. I've got some measurements and design ideas from a previous model, but I want to make it fully parametric so I can adjust it for different fittings and hardware. I've also got the hot end dimensions already.

Here's what I need the OpenSCAD design to handle:

1.  **Base Plate:** The base needs to be a rectangular plate, let's say initially 39mm wide, 27mm deep, and 10mm thick, with mounting holes for attaching to the Printrbot's motor plate. These dimensions can be parametric. The mounting holes should be for M3 bolts, and their locations should also be adjustable via parameters, including their X and Y positions as well as a Z-offset for the depth.

2.  **Hot End Mount:** A circular recess needs to be created on top of the base to accommodate the hot end. This should be a stepped cylinder with two diameters. The larger diameter part should be 13.4mm in radius at the base, shrinking to 8.456835mm in radius at a height of 10mm. Then the inner radius of 8.456835 goes down to 1.6 with a height of 3mm. The height of the total mount part needs to start 10mm above the base plate. We should also include a small hole (2.1mm diameter) passing through the middle of the hot-end recess. There will be a cylinder that is 8.456835mm in radius that protrudes from the main cylinder up 11mm

3.  **Bowden Tube Mount:** A cylindrical opening to accept the Bowden tube fitting needs to be created, located on top of the hot end mount. This cylinder should be centered and it's diameter needs to be parametric so that I can specify different sizes, with a default of 10mm. This cylinder should extend out from the hot-end mount an additional 12mm.

4.  **Hotend Securing Bolts:** Two additional M3 bolt holes are needed to secure the hotend within the mount. They should be perpendicular to the Z-axis and be placed 7.59mm to the left and right of the center on the X-axis, and 5mm from the center on the Y-axis. These holes should pass through the side of the hot end mount.

5.  **Mounting Holes:** Four M3 mounting holes should be positioned on the base plate, and they need to be parametric. Initially they'll be located at (-8.5,-8.1,-1), (-8.5,7.88,-1), (21.44,-8.1,-1), and (21.44,7.88,-1) with a depth of 20 and 15 respectively.

6.  **Modularity:** Ideally the different parts of this design should be able to move around using parameters so I can move the entire hotend assembly around, the Bowden tube opening, the base plate, the bolts, etc.

I'm thinking I'll need parameters to control:

*   Base plate dimensions (width, depth, height).
*   Hot end mount radii (upper and lower) and heights.
*   Bowden tube diameter.
*   Bolt hole positions for the base plate, their X,Y positions and their depths.
*   Hotend securing bolt positions.

I'd prefer for this to be well organized and use comments in the OpenSCAD file(s) for each design element.

[Assistant]
Bowden-Attachment.scad:
```
bowdenAttachementDiameter = 10; // [4,10]

difference() {

	union() {
		translate([-13.5,-13.5,0]) {
			cube([39,27,10]);
		}

		translate([0,0,10]) {
			cylinder(r1 = 13.4, r2 = 8.456835, h = 12, $fn = 80);
		}
	}

	union() {
		color([0.1,0.1,0.5]) {

			// hotend opening
			translate([0,0,10]) {
				cylinder(r1 = 8.456835, r2 = 1.6, h = 3, $fn = 80);
			}

			translate([0,0,-1]) {
				cylinder(d = 2.1, h = 19, $fn = 30);
				cylinder(r = 8.456835, h = 11, $fn = 80);
			}

			// Bowden Opening
			translate([0,0,15]) {
				cylinder(d = bowdenAttachementDiameter, h = 12, $fn = 80);
			}

			// Secure the Hotend
			rotate(90, [1,0,0]) {
				translate([7.59,5,-15]) {
					cylinder(r = 1.6, h = 30, $fn = 30);
				}
				translate([-7.59,5,-15]) {
					cylinder(r = 1.6, h = 30, $fn = 30);
				}
			}

			// M3 Mounting Holes
			translate([-8.5,-8.1,-1]) {
				cylinder(r = 1.6, h = 20, $fn = 30);
			}

			translate([-8.5,7.88,-1]) {
				cylinder(r = 1.6, h = 20, $fn = 30);
			}

			translate([21.44,-8.1,-1]) {
				cylinder(r = 1.6, h = 15, $fn = 30);
			}

			translate([21.44,7.88,-1]) {
				cylinder(r = 1.6, h = 15, $fn = 30);
			}
		}
	}
}
```


[User]
Hey, I'm trying to design a mount for a small 60x jeweler's loupe so I can take pictures with my phone through it. I've got an iPhone 5 in a case and I'd like to avoid having to take the case off to use the loupe. I'd like the mount to hold the loupe securely but be easy to put on and take off.

I've taken some measurements and done a little bit of basic math, and I think I have the following important dimensions:

*   The thickness of my phone case wall is `case_wall_thickness`. I've calculated this by subtracting the iPhone width from the case width, and then dividing by two: `case_wall_thickness = (case_width - iphone_width) / 2`.
*   The radius of the tube that holds the loupe is `lens_tube_r`. The cylinder holding the loupe has wall thickness `wall_thickness`.
*   The length of the tube is `lens_tube_length`.
*   The height of my case is `case_height`.
*   The width of my case is `case_width`.
*   The width of the iPhone 5 is `iphone_width`.
*   The X and Y offsets of the iPhone lens from the corner are `iphone_lens_center_offset_x` and `iphone_lens_center_offset_y` respectively.
*   The radius of the phone corners is `iphone_corner_radius`.
*   I'll also need to account for an offset on the X and Y axis for the lens center, which is `lens_offset_fudge_x` and `lens_offset_fudge_y`. These fudge factors may be necessary to account for manufacturing variance of the lens, and for slight differences in phone lens position. I'd like to be able to change them.
*   I need to calculate the case lens center offsets from the phone lens offsets, adding the case wall thickness and fudge factors:
   *   `case_lens_center_offset_x = iphone_lens_center_offset_x + case_wall_thickness + lens_offset_fudge_x`
   *   `case_lens_center_offset_y = iphone_lens_center_offset_y + case_wall_thickness + lens_offset_fudge_y`
*   The case corner radius will be the phone corner radius plus the case wall thickness: `case_corner_radius = iphone_corner_radius + case_wall_thickness`.
*   The height of the full tube, including mounting part is calculated as `full_tube_height = case_height + 2*wall_thickness + lens_tube_length`.

Basically, the design is a tube that holds the loupe, mounted on a base that fits around the corner of the phone case, with a cutout to allow the camera lens to "see" through it. I'd like to be able to adjust all the measurements in the variables at the top of the file, in particular the `lens_offset_fudge_x` and `lens_offset_fudge_y`. I would like the main part of the design to be defined with a module.

Here are the exact measurements I have:
```
wall_thickness = 2;
lens_tube_length = 12;
lens_tube_r = 15.1 / 2;
case_height = 10.4;
case_width = 62.2;
lens_offset_fudge_x = 0;
lens_offset_fudge_y = 0;
iphone_width = 58.57;
iphone_lens_center_offset_x = 9.28;
iphone_lens_center_offset_y = 7.35;
iphone_corner_radius = 9;
```

Could you generate an OpenSCAD file for this? Please include a module for each element and a main module that combines them to create the final design, making sure that the design uses `difference()` to cut out the loupe tube and the area for the phone's corner. The main part should be a difference of two unions and two cutouts. The two unions are a tube and a holder. The two cutouts are for the loupe tube and the phone's corner. I'd also like for the the tube and tube cutout to have an `slop` variable defined to have a small tolerance to help with the fit. Please use `$fn=50` for all circles and cylinders to ensure they have enough sides for printing.

[Assistant]
loupe.scad:
```
wall_thickness = 2;

// Length of the tube holder.
lens_tube_length = 12;

// Radius of tube holder.
lens_tube_r = 15.1 / 2;

// Measured height of phone case, including fudge factor for fit.
case_height = 10.4;

// Measured width of the case, used to determine case thickness.
case_width = 62.2;

// Extra distance in the X axis to offset lens center. Positive moves lens left in image.
lens_offset_fudge_x = 0;

// Extra dystance in the Y axis to offset lens center. Positive moves lens down in image.
lens_offset_fudge_y = 0;

// From dimensional drawings for iPhone 5. You shouldn't have to change these next three, but you can if you need to.
iphone_width = 58.57;
iphone_lens_center_offset_x = 9.28;
iphone_lens_center_offset_y = 7.35;

// Guessed at. No precise numbers available.
iphone_corner_radius = 9;

// [None]
// Calculated dimensions
case_wall_thickness = (case_width - iphone_width) / 2;
case_lens_center_offset_x = iphone_lens_center_offset_x + case_wall_thickness + lens_offset_fudge_x;
case_lens_center_offset_y = iphone_lens_center_offset_y + case_wall_thickness + lens_offset_fudge_y;
case_corner_radius = iphone_corner_radius + case_wall_thickness;
full_tube_height = case_height + 2*wall_thickness + lens_tube_length;

slop = .1;

module tube() {
  translate([-case_lens_center_offset_x, -case_lens_center_offset_y, -lens_tube_length])
  cylinder(h=lens_tube_length, r=lens_tube_r + wall_thickness, $fn=50);
}

module tube_cutout() {
  translate([-case_lens_center_offset_x, -case_lens_center_offset_y, -lens_tube_length - slop])
  cylinder(h=full_tube_height + 2*slop, r=lens_tube_r, $fn=50);
}

module holder() {
  translate([-case_corner_radius, -case_corner_radius])
  linear_extrude(height=2*wall_thickness + case_height)
  circle(case_corner_radius + wall_thickness, $fn=50);
}

module iphone_cutout() {
  translate([-case_corner_radius, -case_corner_radius, wall_thickness]) {
    linear_extrude(height=case_height) {
      circle(case_corner_radius, $fn=50);
      difference() {
        translate([-(50 - case_corner_radius), -(50 - case_corner_radius)]) square(50);
        square(case_corner_radius);
      }
    }
  }
}

difference() {
  union() {
    tube();
    holder();
  }
  tube_cutout();
  iphone_cutout();
}

```