[User]
I need a custom fan support for my 3D printer, a Sethi3D AiP. I've seen some designs out there, but I want something a little more flexible. I need it to have a few key features.

First, it should replace the existing triangular support for the extruder carriage, basically like the original design but with some modifications, as described below. It needs to have a sort of slanted plate or slate where the fan will attach. The main purpose is to direct airflow onto the printed part. I'm not only printing with PLA so I need to think about both part cooling and nozzle cooling.

The triangle part will need some cutouts for screws and other parts that attach to the carriage, similar to the existing design but customizable. I want the design to be less dependent on specific printer dimensions, giving me some wiggle room, and it also needs to be smaller overall and further from the heated bed to avoid hitting prints that warp.

The fan mount itself is crucial. I want to be able to adjust the angle of the fan relative to the support triangle, which I think could be useful to get the airflow perfect. I also need control over the angle and size of the air nozzle or duct which is why I'll need a parametric nozzle. The nozzle should end with an opening of variable diameter.

I'd like this to be fully parametric so I can adjust things like:

*   Level of detail (for rendering)
*   Diameter of the nozzle opening
*   Angle of the nozzle opening relative to the fan opening
*   Angle of the fan relative to the support triangle
*   Length of the nozzle

I'd like the design to use the BOSL2 library for some of the advanced features.

Can you generate the OpenSCAD files for me?

[Assistant]
triangle-with-fan-support.scad:
```
// Copyright (c) Claudio Luis Marques Sampaio <patola@gmail.com>
// All rights ignored.
//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 University 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 AUTHOR ``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 AUTHOR 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.

// Level of detail
detail=200; // [20:draft, 50:moderate, 200:final]
// Diameter of nozzle opening in mm
opening=8; // [4:14]
// Angle of nozzle opening relative to the fan opening
angle=40; // [0:60]
// Angle of fan relative to support triangle
fanangle=30; // [0:90]
// Nozzle length (keep it short lest it will touch the heated bed)
nozzlelength=30; // [20:40]

$fn=detail;
rotate([180,0,0]) union() {
difference() {
	// support triangle
	linear_extrude(height=5.6) difference() {
		union() {
			polygon(points=[[0,0],[50.8,0],[50.8,5],[5,35],[0,35]]);
			polygon(points=[[50.8,0],[48.3,-2.5],[48.3,0]]);
			polygon(points=[[0,2.6],[-6,2.6],[-6,7.1],[0,7.1]]);
			polygon(points=[[0,18.7],[-6,18.7],[-6,23.2],[0,23.2]]);
		}
		polygon(points=[[0,11.2],[3,11.2],[3,8.9],[5.4,8.9],[5.4,11.2],[7.3,11.2],[7.3,14.6],[5.4,14.6],[5.4,16.9],[3,16.9],[3,14.6],[0,14.6]]);
		polygon(points=[[30.9,0],[30.9,3],[28.6,3],[28.6,5.4],[30.9,5.4],[30.9,7.3],[34.3,7.3],[34.3,5.4],[36.6,5.4],[36.6,3],[34.3,3],[34.3,0]]);
		translate([32.6,11.95,0]) circle(r=1.65);
		translate([42.2,6.75,0]) circle(r=1.65);
		translate([7.7,2.6,0]) square([4.6,3.4]);
		translate([7.7,4.3,0]) circle(r=1.7);
		translate([12.3,4.3,0]) circle(r=1.7);
	}
	// slanted opening for wires
	translate([2,0,10]) rotate([0,45,0]) cube([20,4,3]);
}

// Polygon linking the triangle to the fan mount part
linear_extrude(height=5.6) polygon(points=[[5,35],[61,6],[63,0],[50,0],[50,5]]);

// cylinder linking the polygon to the rest of the fan mount part
translate([60,2,5.6]) rotate([0,-180,0]) cylinder(r=4,h=47.6);

translate([58,-48,18]) rotate([0,90,0]) difference() {
	translate([20,50,0]) rotate([fanangle,0,0]) union() {
		difference () {
			cube([40,50,5.6]);
			translate([20,28,-.2]) cylinder(r=18,h=6);
			translate([4,12,-.2]) cylinder(r=1.2,h=6);
			translate([36,12,-.2]) cylinder(r=1.2,h=6);
			translate([36,44,-.2]) cylinder(r=1.2,h=6);
			translate([4,44,-.2]) cylinder(r=1.2,h=6);
		}
		rotate([180,0,90]) union() {
			for (loc=[9:5.8:49.6]) {
				translate([loc,-7.6,-5.6]) linear_extrude(height=5.6) polygon(points=[[-1.5,0],[1.5,0],[0,8.6]]);
			}
			translate([9,-4,-5.6]) cube([40,1,5.6]);
		}
		// cone for restricting air flow
		translate([20,28,0]) mirror([0,0,-1]) difference() {
			// I am using hull() here to slant the cone if
			// needed. For that, just change the "y" value
			// in the second term of hull, e.g.
			// translate([0,8,20]) will shift the center
			// 8 mm downward.
			hull() {
				cylinder(r=20,h=0.01);
				translate([0,7,nozzlelength]) rotate([-angle,0,0]) cylinder(r=opening+2,h=0.01);
			}
			translate([0,0,-0.1]) hull() {
				cylinder(r=18,h=0.01);
				translate([0,7,nozzlelength+0.2]) rotate([-angle,0,0]) cylinder(r=opening,h=0.01);
			}
		}
	}
	translate([100,100,-10]) cube([100,100,10]);
}
}
```


[User]
I need a parametric OpenSCAD design for a business card holder that clips onto a 6mm thick surface. The basic design is a box with a cutout for business cards and a hook on the back that allows it to clip onto the 6mm surface.

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

*   `card_width`: The width of the business card slot.
*   `card_depth`: The depth of the business card slot (how many cards it should hold).
*   `wall_thickness`: The thickness of the box walls.
*  `clip_thickness`: The thickness of the clip itself.
*   `clip_height`: The height of the clip's "hook" part that grabs the 6mm surface.
*  `clip_depth`: The depth of the clip - that is, how far it projects out from the back of the box.
*  `total_height`: The total height of the box.
* `mounting_thickness`: The thickness of the surface that the holder will be clipped to - should default to 6mm, but I need to be able to adjust it.

The box should have a rectangular cutout for the cards, leaving a wall of `wall_thickness` on all sides. The clip should be attached to the back and consist of two main parts - a horizontal piece that extends backward and a vertical "hook" that grabs onto the mounting surface. The `clip_thickness` should apply to both parts. The vertical "hook" should stick downwards a distance of `clip_height` from the horizontal portion. The horizontal portion should have length equal to `mounting_thickness + clip_depth`.

I think that should cover all the dimensions. I'm not doing anything fancy, just the basic box and clip design.

[Assistant]
vcard_holder.scad:
```
tol=0.05;
th=1.2; // box wall thickness

ply_th= 6; // plywood thickness
hook_th= 3;
hook_sz= 4; // clamp height
hook_top_len= ply_th + hook_th;

vc_w= 55+1; // width of hole for vcard
vc_th_int= 10; // hole thickness (ie. how many card can be packed into the holder)
vc_th_ext= th + vc_th_int + th;

hook_width_ext=th+vc_w+th;
total_h= 30;

module ccube(size)
{
	translate([-size[0]/2, -size[1]/2, 0])
		cube(size);
}

difference()
{
translate([-hook_width_ext/2,0,0])
	union()
	{
		cube([hook_width_ext, vc_th_ext, total_h]);
		translate([0,vc_th_ext-tol,total_h-hook_th-tol])
		{
			cube([hook_width_ext, hook_top_len, hook_th]);
			translate([0,ply_th,-hook_sz])
				cube([hook_width_ext, hook_sz, hook_sz+hook_th]);
		}
	}

	// Main hole
	translate([-hook_width_ext/2,0,0])
		translate([th,th,th])
			cube([vc_w, vc_th_int, total_h]);
/*
	translate([-hook_width_ext/2+4,0,-10])
		translate([th,th,th])
			cube([vc_w-8, vc_th_int, total_h]);

	translate([0,0,total_h/2])
		carve_hole();

	for(dx=[-1,+1])
		for(dz=[-1,+1])
			translate([dx*subhole_dist, 0, dz*subhole_dist+total_h/2])
				scale([0.3,1,0.3])
					carve_hole();
*/
}
subhole_dist=18;

module carve_hole()
{
	translate([0,-1,0])
	{
		rotate([-90,0,0])
		{
			hull()
			{
				scale([1,0.6,1]) cylinder(r=16,h=vc_th_ext+2);
				scale([0.1,1,1]) cylinder(r=23,h=vc_th_ext+2);
			}
		}
	}

}
```


[User]
Hi! I'd like to design a set of modular stone wall components, kinda like what's described in that wall2.0.scad file I saw. I'm thinking of a system where I can build walls of arbitrary length, height, and thickness, and also some end pieces for aesthetic purposes. I really like the idea of those randomly shaped, 'chipped granite' looking stones. Here are some requirements for this system, which you can consider as modular units (in separate files or as separate modules within the same file):

**Core Stone Module (`stone.scad`)**

*   **Randomized Shape:** Each stone should be composed of intersecting, rotated cubes like in that wall2.0.scad example.
*   **Parameters:**
    *   `unit_dimension`: (real number) The base size of the cubes that make up the stone, used for sizing.
    *   `max_rotation`: (angle in degrees) The maximum rotation angle allowed for the cubes that make up the stone, controls how "chipped" the stone looks.
    *   `seed`: (integer) A seed value for the random number generator to control the shape, so the same seed creates the same stone.
    *   `n`: (integer) The number of cubes used to make up the block, for adding facets
    *   `power`: (real number) A way to reduce the ability of higher `n` to chop up a block, should be -2 to 0

**Wall Module (`wall.scad`)**

*   **Running Bond:** The wall should be constructed using a running bond pattern, where each layer is offset by half a stone length from the layer below it.
*   **Parameters:**
    *   `stone_length` (real number): the 'U' dimension - length of a stone
    *   `wall_thickness`: (real number) the 'V' dimension - thickness of the wall
    *    `stone_height`:(real number) the 'W' dimension - height of a stone
    *   `num_stones_x`: (integer) Number of stones along the wall.
    *   `num_stones_z`: (integer) Number of stone layers in the wall (height).
    *   `master_seed`: (integer) A seed to control the arrangement of the stones. This should affect each individual stone's `seed`, not just the whole wall.
     * `z_compression`: (real number): A way to reduce the apparent height of stones.
*  **Mortar:** Optional mortar between stones.
     *   `mortar`: (boolean) Whether to include mortar.
     *   `mortar_u_adjust`: (real number) How much the mortar protrudes into the running direction of the stones.
     *   `mortar_v_ratio`: (real number) the thickness of the mortar compared to the wall thickness.
*  **Base:** Optional base for the wall
    *   `base` (boolean): whether to include a base
    *  `base_x_adjust`: (real number): the percentage of a brick you want the base to extend from the wall in the running direction.
     *   `base_y_adjust`: (real number): the percentage of a brick you want the base to extend in the front and back of the wall.
     *  `base_z`: (real number): what percentage of a brick you want the base's height to be.

**End Cap Module (`endcap.scad`)**

*   **Rounded Ends:** The end pieces should use a rounded, column-like shape. I'm thinking maybe a partial cylinder for each end, attached to the last stone in the wall.
*   **Parameters:**
    *   `wall_thickness`: (real number) The thickness of the wall, should match the main wall.
    * `stone_length`: (real number): the 'U' dimension - length of a stone
    *   `stone_height`: (real number): the 'W' dimension - height of a stone.
    *   `endcap_radius`: (real number) The radius of the cylinder.
    *   `num_stones_z`: (integer) number of stones in the height of the wall, to match the main wall height.
    * `z_compression`: (real number):  A way to reduce the apparent height of stones.
*    **Placement:** The end caps should align vertically with each layer of the stone wall.

**General Requirements:**

*   **Parametric:** All of the dimensions and parameters should be easily adjustable using variables.
*   **Modular:** The stone, wall, and end cap should work together well and be easy to use as separate pieces or as a whole.
*   **Preview:** I'd like each module to be previewable with a reasonable view, say south east and tilted sideways, like in the example file.
*   **No dependencies:** I would prefer if there are no external dependencies (e.g. external .scad files, libraries). If you absolutely need an external library, use the BOSL2 library, but let me know first.

I'm hoping to use this to create a variety of walls and structures. Thanks!

[Assistant]
wall2.0.scad:
```
//Customizable Stone Wall
//Created by Ari M. Diacou, January 2014 (updated February, 2014)
//Shared under Creative Commons License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
//see http://creativecommons.org/licenses/by-sa/3.0/

// preview[view:south east, tilt:side]
/*[Wall]*/
//Length of a stone
U=3;
//Thickness of wall
V=2;
//Height of a stone
W=1;
//Number of stones along wall
num_x=4;
//The wall height in number of stones
num_z=6;
//A way to save the arrangement of stones
master_seed=14;
//Higher angles make more wedge-shaped stones, lower angles produce blocks. Reccomend 5-30 (zero crashes).
maximum_rotation_angle=12;
//Higher rotation angles might need more compression
z_compression=0.9;
//Number of cubes that make up a block
n=8;
//A way to reduce the abilty of higher n to chop up a block (should be -2 to 0)
power=0;

/*[Mortar]*/
//Do you want mortar between the stones?
mortar=1; //[1,0]
//What percentage of a brick do you want the mortar in the running direction?
u_adjust=-0.15;
//How much of the wall's thickness do you want the mortar to take up?
v_ratio=0.5;

/*[Base]*/
//Do you want a base for the wall
base=1; //[1,0]
//What percentage of a brick do you want the base to extend from the wall in the running direction?
bx_adjust=0.1;
//What percentage of a brick do you want the base to extend in the front and back of the wall?
by_adjust=0.1;
//What percentage of a brick do you want the base's height to be?
bz=.5;

/*[Hidden]*/
dimensions=[U,V,W];
half_dimensions=[U/2,V,W];
wall();

module rock(unit_dimension, max_rotation, seed){
	random=rands(-1,1,n*3,seed);
		intersection(){
			intersection_for(i=[0:n-1]){
				rotate([	max_rotation*random[3*i+0]*pow(i,power),
							max_rotation*random[3*i+1]*pow(i,power),
							max_rotation*random[3*i+2]*pow(i,power)])
					cube(unit_dimension, center=true);
					}
			}
	}

module wall(){
	union(){
		difference(){
			for(z=[0:num_z-1]){
				for(x=[0:num_x-1]){
					if(half_condtion(x, z, num_x)){
						translate([U*(x+0.5-0.25), 0,z*W*z_compression])
							color("SlateGray")
								rock(half_dimensions,maximum_rotation_angle,num_x*z+x+master_seed);
						} else {
						translate([U*(x+0.5-0.25*(1+pow(-1,z))), 0,z*W*z_compression])
							color("SlateGray")
								rock(dimensions,maximum_rotation_angle,num_x*z+x+master_seed);
						}
					}
				}
			translate([-0.25*U,-V/1.3,-W])
				cube([U*num_x,V*1.5,W]);
			}
		if(mortar==1){
			translate([(-u_adjust)*U,-V*v_ratio/2,0])
				color("silver")
					cube([(num_x-0.5+2*u_adjust)*U,V*v_ratio,W*(num_z-1)*z_compression]);
			}
		if(base==1){
			translate([-bx_adjust*U,-(.5+by_adjust)*V,-W*(bz-0.01)])
				color("green")
					cube([U*(num_x-0.5+2*bx_adjust),V*(1+2*by_adjust),W*bz]);
			}
		}
	}

function half_condtion(i, j, num_i)=((i==0 && j%2==0) || (i==num_i-1 && j%2==1));

```


[User]
I'd like a parametric design for a horned starfish, something similar to the one I have here but I need it to be completely re-written. I'm looking for a design that lets me specify:

*   The number of legs the starfish has (between 3 and 12).
*   The number of segments each leg has (between 0 and 5).
*   The length of each leg segment (between 13mm and 23mm).
*   The gap between the leg segments (which should default to 0.1mm but can be overridden).
*   A shell thickness, radius, slope and scale for the segments.
*   A radius ratio `r_ratio` for segment calculations, and a segment angle `s_angle`.
*   I'll need some way to render the complete starfish, or just the center section, or individual leg segments using a `part` parameter. 1 would be "All," 2 is "Plate", 3 would be "Center," and then 4 through 8 would be "Seg1" through "Seg5", or some way to achieve the same result.

I'm not really committed to the exact shapes from my example, so you can be creative. The main thing is that each segment has a ball joint where it connects to the next segment, it has horns, and that it looks like a stylised horned starfish. I think it might be best if the basic shape of each segment is based on a sphere with some extrusions, but you can use whatever primitives or transformations you think are suitable. I think the segment calculations should use a for loop to handle the multiple legs.

I'd like all the parameters to have reasonable defaults, and be easily configurable in OpenSCAD's customizer. I’d also appreciate if the code included clearly labeled `MAKE_TARGET` modules as in my example. Also, include the `$fn` parameter for rendering quality, and set it to 48.

I'm looking to generate STL files for various parts, so it's important that the code is structured for easy use with a build system. It would be great if you could do the whole thing in a single OpenSCAD file, if possible. No libraries required.

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

/* [Starfish Parameters] */

// Select which part of the starfish would like to render.
part=1; //[1:All, 2:Plate, 3:Center, 4:Seg1, 5:Seg2, 6:Seg3, 7:Seg4, 8:Seg5]

// How many legs should the starfish have?
legs = 5; // [3:12]

// How many segments should each leg have?
segments = 4; // [0:5]

// How long should the leg segment be (mm)?
length = 16; // [13:23]

// How large should the gap be between segments (mm)?
gap = 0.1;

/* [Hidden] */

slope = -99;
radius = 10;
shell = 0.8;
scale = 0.7;
r_ratio = 0.45;
s_angle = 10;
$fn=48;

// IMPORTANT!!! - Comment out starfish before running make

starfish(part);

// -------------- BUILD TARGETS FOR MAKEFILE

module star_segment_1() { // MAKE_TARGET
	segment(radius - shell, shell, length, segments - 1);
}

module star_segment_2() { // MAKE_TARGET
	segment(radius - (shell * 2), shell, length, segments - 2);
}

module star_segment_3() { // MAKE_TARGET
	segment(radius - (shell * 3), shell, length, segments - 3);
}

module star_segment_4() { // MAKE_TARGET
	segment(radius - (shell * 4), shell, length, segments - 4);
}

module star_segment_5() { // MAKE_TARGET
	segment(radius - (shell * 5), shell, length, segments - 5);
}

module star_center() { // MAKE_TARGET
	all(legs, 0);
}

module star_plate() { // MAKE_TARGET
	x_offset = radius * 2 + 5;
	y_offset = radius + length + 5;
	rotate([0,0,90])
	translate([-x_offset * (legs-1) / 2, -y_offset * segments / 2, 0])
	for(leg = [0: legs - 1])
	for(seg = [0: segments - 1]) {
		translate([x_offset * leg, y_offset * seg, 0])
		segment(radius - (shell * seg), shell, length, segments - seg);
	}
	// cube([280,150,1], center=true);
}

// -------------- STARFISH

module starfish(part) {
	if(part == 1) {
		all(legs, 1);
	}
	else if (part == 2) {
		star_plate();
	}
	else if (part == 3) {
		star_center();
	}
	else if (part == 4) {
		star_segment_1();
	}
	else if (part == 5) {
		star_segment_2();
	}
	else if (part == 6) {
		star_segment_3();
	}
	else if (part == 7) {
		star_segment_4();
	}
	else if (part == 8) {
		star_segment_5();
	}
}

module horn(r, n) {
	o = n * 0.3;
	translate([0,0,r + o]) sphere(r * 0.35);
	translate([0,0,(r/2) + o]) cylinder(r / 2, r * 0.55, r * 0.35);
}

module trim(r, d, l) {
	// socket hole
	sphere(r - d + gap);
	// socket back
	translate([-r * 3/2,-r -r/2, -r]) cube([r * 3, r, r * 2]);
	// ball edges
	translate([0,-r/2,0]) cube([r*1.1, r, r*2], center=true);
	// top
	translate([-r,-r,r*scale]) cube([r*2, r*2+l, r]);
	// bottom
	translate([-r,-r,-r-r*scale]) cube([r*2, r*2+l, r]);
}

module ball(r, r2, d, l) {
	rotate([slope, 0, 0]) cylinder(l, r, r2);
	translate([0,l,-d*scale]) sphere(r-(d*2));
}

module tip(r, r2, d, l) {
	rotate([slope+1, 0, 0]) cylinder(l, r, r2);
	translate([0,l,-r*0.25]) sphere((r-(d*2)) * 3/4);
}

module segment(r, d, l, n) {
	r2 = (r-(d*2)) * r_ratio;
	if(n >= 0) {
		translate([0,0,r*scale]) {
			if(n) translate([0,l,0]) horn(r - d, n - 1);
			difference() {
				union() {
					sphere(r+d);
					if(n) {
						ball(r, r2, d, l);
					}
					else {
						tip(r, r2, d, l);
					}
				}
				trim(r, d, l);
			}
		}
	}
	else {
		rotate([0,0,45]) cube([10,30,10], center=true);
		rotate([0,0,-45]) cube([10,30,10], center=true);
	}
}

module segment5(r, d, l, n) {
	r2 = (r-(d*2)) * r_ratio;
	translate([0,0,r*scale]) {
		horn(r, n);
		difference() {
			union() {
				sphere(r+d);
				tip(r, r2, d, l);
			}
			trim(r, d, l);
		}
	}
}

module segment4(r, d, l, n, a) {
	r2 = (r-(d*2)) * r_ratio;
	if(n) translate([0, l, 0]) rotate([0,0,a]) segment5(r - d, d, l, n - 1);
	translate([0,0,r*scale]) {
		horn(r, n);
		difference() {
			union() {
				sphere(r+d);
				if(n) {
					ball(r, r2, d, l);
				}
				else {
					tip(r, r2, d, l);
				}
			}
			trim(r, d, l);
		}
	}
}

module segment3(r, d, l, n, a) {
	r2 = (r-(d*2)) * r_ratio;
	if(n) translate([0, l, 0]) rotate([0,0,a]) segment4(r - d, d, l, n - 1, a, 1);
	translate([0,0,r*scale]) {
		horn(r, n);
		difference() {
			union() {
				sphere(r+d);
				if(n) {
					ball(r, r2, d, l);
				}
				else {
					tip(r, r2, d, l);
				}
			}
			trim(r, d, l);
		}
	}
}

module segment2(r, d, l, n, a) {
	r2 = (r-(d*2)) * r_ratio;
	if(n) translate([0, l, 0]) rotate([0,0,a]) segment3(r - d, d, l, n - 1, a, 1);
	translate([0,0,r*scale]) {
		horn(r, n);
		difference() {
			union() {
				sphere(r+d);
				if(n) {
					ball(r, r2, d, l);
				}
				else {
					tip(r, r2, d, l);
				}
			}
			trim(r, d, l);
		}
	}
}

module segment1(r, d, l, n, a) {
	r2 = (r-(d*2)) * r_ratio;
	if(n) translate([0, l, 0]) rotate([0,0,a]) segment2(r - d, d, l, n - 1, a, 1);
	translate([0,0,r*scale]) {
		horn(r, n);
		difference() {
			union() {
				sphere(r+d);
				if(n) {
					ball(r, r2, d, l);
				}
				else {
					tip(r, r2, d, l);
				}
			}
			trim(r, d, l);
		}
	}
}

module segment0(r, d, l, n, a, s) {
	r2 = (r-(d*2)) * r_ratio;
	if(n && s) translate([0, l, 0]) rotate([0,0,a]) segment1(r - d, d, l, n - 1, a);
	translate([0,0,r*scale]) {
		horn(r, n);
		if(n && s==0) translate([0,l,0]) horn(r - d, (n - 1) * 0.4);
		difference() {
			union() {
				rotate([slope, 0, 0]) cylinder(l * 2, r * 1.4, r2, center=true);
				if(n) {
					translate([0,l,-d*scale]) sphere(r-(d*2));
				}
				else {
					translate([0,l,-r*0.25]) sphere((r-(d*2)) * 3/4);
				}
			}
			translate([-r*2,-r-l,r*scale]) cube([r*4, (r+l)*2, r]);
			translate([-r*2,-r-l,-r-r*scale]) cube([r*4, (r+l)*2, r]);
		}
	}
}

module all(n, s) {
	a = 360 / n;
	r = n  * length / 6.7;
	r2 = n * length / 4.5;
	o = (radius * scale) + (segments * 0.4);
	rotate([0,0,a/2]) {
		translate([0, r2, 0])
			segment0(radius, shell, length, segments, s_angle, s);
		for(i = [1: n - 2]) {
			rotate([0, 0, i * a])
			translate([0, r2, 0])
				segment0(radius, shell, length, segments, i > 1 && i < n - 2 ? (i < n /2 ? -s_angle : s_angle) : 0, s);
		}
		rotate([0, 0, (n - 1) * a])
		translate([0, r2, 0])
			segment0(radius, shell, length, segments, -s_angle, s);
	}
	cylinder(radius*2*scale, r, r, s);
	if(legs > 4) {
		translate([0,0,radius + o]) sphere(radius * 0.35);
		translate([0,0,(radius/2) + o]) cylinder(radius / 2, radius * 0.55, radius * 0.35);
		if(legs > 7) {
			for(i = [0: n - 1]) {
				rotate([0, 0, i * a])
				translate([0, r*0.9, 0])
				union() {
					translate([0,0,radius + o]) sphere(radius * 0.3);
					translate([0,0,(radius/2) + o]) cylinder(radius / 2, radius * 0.5, radius * 0.3);
				}
			}
		}
	}
}

```


[User]
I want to create a customizable stone wall, similar to the one I found on Thingiverse (thing:219574). I need an OpenSCAD design that allows me to adjust several parameters to control the wall's appearance.

First, I want to control the basic dimensions of the stones. I need parameters for:

*   `U`: the length of a stone
*   `V`: the thickness of the wall
*   `W`: the height of a stone

I also need to set the number of stones along the wall's length (`num_x`) and the total height of the wall in terms of the number of stones (`num_z`).

A very important feature is the random variation of the stones. I want a `master_seed` parameter that controls the overall random pattern of the wall. Each stone should be slightly rotated to give a more irregular, "rock-like" appearance. The maximum rotation angle, `maximum_rotation_angle`, should be adjustable as well. I’ll also need `z_compression` to squish the wall height if required.

I also want to optionally include mortar between the stones. There should be a `mortar` parameter that is either 1 (for yes) or 0 (for no). If mortar is enabled, I want to be able to control the thickness and extent of the mortar using `u_adjust` (mortar percentage of a stone's length) and `v_ratio` (mortar percentage of the wall's thickness).

Finally, I would also like an optional base for the wall. A `base` parameter of 1 enables it, and 0 disables it. I need to control the base's extension using `bx_adjust` (base length in x direction), `by_adjust` (base length in y direction), and the height with `bz` (base percentage of a stone's height).

Could you generate OpenSCAD code that implements all of this? I don't want to have to manually adjust the parameters in the code itself, so I need to be able to set these values through the customizer.

[Assistant]
uploads_c7_fe_4d_61_b2_wall1.2.scad:
```
//Customizable Stone Wall
//Created by Ari M. Diacou, January 2014
//Shared under Creative Commons License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
//see http://creativecommons.org/licenses/by-sa/3.0/
//(Tweaks to accomodate Thingiverse Customizer by Jim DeVona)

// preview[view:south east, tilt:side]
/*[Wall]*/
//Length of a stone
U=3;
//Thickness of wall
V=2;
//Height of a stone
W=1;
//Number of stones along wall
num_x=4;
//The wall height in number of stones
num_z=6;
//A way to save the arrangement of stones
master_seed=15;
//Higher angles make more wedge-shaped stones, lower angles produce blocks. Reccomend 5-30 (zero crashes).
maximum_rotation_angle=12;
//Higher rotation angles might need more compression
z_compression=1.0;

/*[Mortar]*/
//Do you want mortar between the stones?
mortar=1; //[1:yes,0:no]
//What percentage of a brick do you want the mortar in the running direction?
u_adjust=-0.15;
//How much of the wall's thickness do you want the mortar to take up?
v_ratio=.5;

/*[Base]*/
//Do you want a base for the wall
base=1; //[1:yes,0:no]
//What percentage of a brick do you want the base to extend from the wall in the running direction?
bx_adjust=0.1;
//What percentage of a brick do you want the base to extend in the front and back of the wall?
by_adjust=0.2;
//What percentage of a brick do you want the base's height to be?
bz=0.5;

/*[Hidden]*/
dimensions=[U,V,W];
half_dimensions=[U/2,V,W];
union(){
	difference(){
		for(z=[0:num_z-1]){
			for(x=[0:num_x-1]){
				//echo(x, z, half_condtion(x, z, num_x));
				if(half_condtion(x, z, num_x)){
					translate([U*(x+.5-.25), 0,z*W*z_compression])
						color("grey")
							rock(half_dimensions,maximum_rotation_angle,num_x*z+x);
					} else {
					translate([U*(x+.5-.25*(1+pow(-1,z))), 0,z*W*z_compression])
						color("grey")
							rock(dimensions,maximum_rotation_angle,num_x*z+x);
					}
				}
			}
		translate([-.25*U,-V/1.3,-W])
			cube([U*num_x,V*1.5,W]);
		}
	if(mortar==1){
		translate([(-u_adjust)*U,-V*v_ratio/2,0])
			color("gainsboro")
				cube([(num_x-.5+2*u_adjust)*U,V*v_ratio,W*(num_z-1)*z_compression]);
		}
	if(base==1){
		translate([-bx_adjust*U,-(.5+by_adjust)*V,-W*(bz-.01)])
			color("green")
				cube([U*(num_x-.5+2*bx_adjust),V*(1+2*by_adjust),W*bz]);
		}
	}

function half_condtion(i, j, num_i)=((i==0 && j%2==0) || (i==num_i-1 && j%2==1));

module rock(unit_dimension, max_rotation, seed){
	rotation_vector=rands(-max_rotation,max_rotation,3*3,seed*1000*master_seed);
	//echo( "rotation_vector: ",rotation_vector);
	intersection(){
		rotate([rotation_vector[1],rotation_vector[1+1],rotation_vector[1+2]])
			cube(unit_dimension,center=true);
		rotate([rotation_vector[2],rotation_vector[2+1],rotation_vector[2+2]])
			cube(unit_dimension,center=true);
		rotate([rotation_vector[3],rotation_vector[3+1],rotation_vector[3+2]])
			cube(unit_dimension,center=true);
		}
	}

```


[User]
Hey, I'm looking to get some OpenSCAD code for a gimbal design. I've got a basic idea of what I want, and it's inspired by something I've already got, but I want it to be more parametric and flexible.

Basically, it's a series of nested hoops, each rotating within the previous one. The outermost hoop should be fixed, and the innermost one should be the innermost, free-rotating hoop.

Here are the parameters I'd like to control:

*   **Number of Hoops:** I want to be able to specify how many hoops are in the gimbal.
*   **Outer Radius:** The radius of the outermost hoop.
*   **Hoop Height:** The height/thickness of each hoop.
*   **Hoop Thickness:** The radial thickness of each hoop.
*   **Gap between Hoops:** The radial space between the hoops.

Each hoop should be a hollow ring, formed by the difference of two spheres, and then some boolean subtractions to make them hoop-like. I also want "posts" on each hoop that the next hoop can use for support. The outer hoop, of course, will not need any outer posts, and the inner hoop won't need any inner posts.

For the posts, the outer posts on each hoop should be small cylinders placed at diametrically opposed positions (180 degrees apart) at the outer edge of each hoop, and the inner posts should be the same, but positioned at the inner edge. These posts should be oriented so that they stick up along the Z-axis. The inner posts on each hoop will rest inside of the outer posts of the inner hoop.

I'm picturing the code being relatively straightforward. I'd prefer it not to use any external libraries, but I can consider them if that would be much easier. All of the calculations should be done using variables so that if I wanted to, I could easily change a single parameter and have it re-render the whole model.

Can you help me with this?

[Assistant]
hoops.scad:
```
$fn = 100 + 0;

// height of the hoops
hoop_height = 8;
// thickness of each hoop
hoop_thinkness = 3;
// space between hoops
hoop_gap = 1;
// number of hoops
num_hoops = 3;
// radius of outer loop
outer_r = 30;

module hoop(ro, wh, inner, outer){
	if (wh % 2){
		rotate([0,0,90])
			hoop2(ro, inner, outer);
	}
	else {
		hoop2(ro, inner, outer);

	}
}

module hoop2(ro, inner, outer){
	ri = ro - hoop_thinkness;
	difference(){
		sphere(r=ro);
		sphere(r=ri);
		translate([0,0,ro / 2 + hoop_height / 2])
			cube([ro*2, ro * 2, ro], center=true);

		translate([0,0,-(ro / 2 + hoop_height / 2)])
			cube([ro*2, ro * 2, ro], center=true);

		if (!outer){
			translate([0, ro, 0])
				rotate([90, 0, 0])
				cylinder(r1 = 4, r2 = 0, h=3);

			translate([0, -(ro), 0])
				rotate([-90, 0, 0])
				cylinder(r1 = 4, r2 = 0, h=3);
		}
	}

	if (!inner){

		translate([ri, 0, 0])
			rotate([0, -90, 0])
			cylinder(r1 = 4, r2 = 0, h=3.5);

		translate([-(ri), 0, 0])
			rotate([0, 90, 0])
			cylinder(r1 = 4, r2 = 0, h=3.5);

	}
}

module hoop_non_rec(){
	for (i = [1:num_hoops]){
		hoop(outer_r - (hoop_thinkness + hoop_gap) * (num_hoops - i), i, i == 1, i == num_hoops);
	}
}

module hoop_rec(r, num, outer){
//	echo (r);
	hoop(r, num, num == 1, outer);
	if (num > 1){
		hoop_rec(r - hoop_thinkness - hoop_gap, num - 1, false);

	}
}

//hoop_rec(30, num_hoops, true);
hoop_non_rec();

```


[User]
I'd like a parametric design for a harmonic drive gearbox, similar to the one described in the provided text and video, but I'd like it to be more flexible in terms of the gear ratios. The core idea is to have a flexible outer ring that deforms to engage with the output gear, as well as planetary gears before that, all enclosed in a fixed outer ring.

Specifically, I need the following parameters to be easily adjustable:

*   **Outer Diameter (D):** The overall diameter of the fixed outer ring.
*   **Gear Thickness (T):** The thickness of all the gears.
*   **Clearance (tol):** The spacing between the gears, which should have the option to be a positive or negative value.
*   **Extrusion Thread Width (wt):** The width of the "thread" for the flexible section. This may be more of a design feature rather than a hard parameter, but being able to control the width of the flexible sections would be helpful.
*   **Number of Teeth on Planets (np):** The number of teeth on each of the planetary gears.
*   **Number of Teeth on Sun (ns):** The number of teeth on the central sun gear.
*   **Pressure Angle (P):** The pressure angle for all gears, and I need to be able to adjust that.
*   **Number of Teeth to Twist Across (nTwist):** This relates to how much the flex ring twists across the gear.
*   **Width of Hexagonal Hole (w):** The width of the hexagonal hole in the center of the sun gear.
*   **Maximum depth ratio of teeth (DR):** This parameter allows to control teeth depth.
*   **Number of Planets (m):** The number of planets.

The design should include the following key components:

1.  **Fixed Outer Ring:** This ring will have an internal herringbone gear cut into it. It should also have an option for adding some text (either a ratio or other designator) to its exterior.
2.  **Flexible Output Ring:** This is the key part. It should have a crinkled shape with involute teeth on both the inside and the outside. The edges of the teeth should taper down. I understand this part of the design uses a calculated "nf" number of teeth, but I'm not sure how that is used.
3.  **Sun Gear:** This gear will have a hexagonal hole in its center and will mesh with the planetary gears.
4.  **Planetary Gears:** There should be *m* of these gears, meshing with the sun gear and the flexible output ring.

I'd like the whole thing to be pre-assembled, similar to the original design, so that it prints in one piece without any need for supports. I want all the gears to have herringbone teeth so that they are constrained. Also, could the design use the `Write.scad` library from the original design for the text on the outer ring?

Could you generate the parametric OpenSCAD code for this? I'm looking for a set of .scad files that I can use to generate the model. I'm not too concerned with the exact code, but I'd need to be able to tweak all of the parameters mentioned above to try out different gear ratios and design options.

[Assistant]
harmonic.scad:
```
// Preassembled Harmonic Drive by Emmett Lalish
// License: CC-BY-SA, January 5th, 2014

use <../write/Write.scad>

// outer diameter of ring
D=70;
// gear thickness
T=15;
// clearance
tol=0.15;
// width of extrusion thread
wt=0.4;
number_of_teeth_on_planets=15;
number_of_teeth_on_sun=12;
// pressure angle
P=45;//[30:60]
// number of teeth to twist across
nTwist=1.4;
// width of hexagonal hole
w=6.7;

m=2*1;
DR=0.7*1;// maximum depth ratio of teeth

np=round(number_of_teeth_on_planets);
ns=round(number_of_teeth_on_sun);
nr=ns+2*np;
delta=2*1;
nf=nr-delta;
pitchD=0.8*D/(1+min(PI/(2*nr*tan(P)),PI*DR/nr));
pitch=pitchD*PI/nr;
echo(pitch);
helix_angle=atan(2*nTwist*pitch/T);
echo(helix_angle);

phi=$t*360/m;
R1=(ns+np)*2/ns;
R2=nr/delta;
R=R1*R2;
echo(R);

//flex();
assembly();
//herringbone(ns,pitch,P,DR,tol,helix_angle,T);

module assembly()
translate([0,0,T/2]){
	difference(){// fixed ring
		cylinder(r=D/2,h=T,center=true,$fn=100);
		herringbone(nr,pitch,P,DR,-5*tol-2*wt,helix_angle,T+0.02);
		difference(){
			union(){
				rotate([0,0,180])translate([0,-D/2,0])rotate([90,0,0])monogram(h=10);
				writecylinder(text=str(R),radius=D/2,h=5,t=2,
					font="../write/Letters.dxf");
			}
			cylinder(r=D/2-0.25,h=T+2,center=true,$fn=100);
		}
	}

	flex();// flexible output

	rotate([0,0,(np+1)*180/ns+phi*R1])// sun gear
	difference(){
		mirror([0,1,0])
			herringbone(ns,pitch,P,DR,0,helix_angle,T);
		cylinder(r=w/sqrt(3),h=T+1,center=true,$fn=6);
	}

	for(i=[1:m])rotate([0,0,i*360/m+phi])translate([pitchD/2*(ns+np)/nr,0,0])// planets
		rotate([0,0,i*ns/m*360/np-phi*(ns+np)/np-phi])
			herringbone(np,pitch,P,DR,tol,helix_angle,T);
}

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

module flex(){
difference(){
	union(){
		flexbase(w=2*wt);
		translate([0,0,2.5*T-0.01])cylinder(r=pitch*nf/(2*PI)+tol/2+wt,h=T/2,$fn=2*nf);
	}
	translate([0,0,-0.01])scale([1,1,(3*T+0.02)/(3*T)])flexbase(w=0);
	translate([0,0,2.5*T-0.02])cylinder(r1=pitch*nf/(2*PI)+tol/2,r2=pitch*nf/(2*PI)+tol/2-1,h=1);
	translate([0,0,3*T])cylinder(r=w/sqrt(3),h=T-4,center=true,$fn=6);
}}

module flexbase(w)
union(){
	scale([nr/nf,nf/nr,1])herringbone(nf,pitch,P,DR,-tol-w,helix_angle,T);
	translate([0,0,2.5*T])rotate([180,0,0])linear_extrude(height=2*T+0.01,scale=[nr/nf,nf/nr])
		circle(r=pitch*nf/(2*PI)+(tol+w)/2,$fn=2*nf);
}

module herringbone(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=20,
	depth_ratio=2/PI,
	clearance=0,
	helix_angle=0,
	gear_thickness=5){
union(){
	half(number_of_teeth,
		circular_pitch,
		pressure_angle,
		depth_ratio,
		clearance,
		helix_angle,
		gear_thickness/2);
	mirror([0,0,1])
		half(number_of_teeth,
			circular_pitch,
			pressure_angle,
			depth_ratio,
			clearance,
			helix_angle,
			gear_thickness/2);

}}

module half(
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=20,
	depth_ratio=2/PI,
	clearance=0,
	helix_angle=0,
	gear_thickness=5){
radius=circular_pitch*number_of_teeth/(2*PI)-clearance/2;
intersection(){
	union(){
		gear(number_of_teeth,
			circular_pitch,
			pressure_angle,
			depth_ratio,
			clearance,
			helix_angle,
			gear_thickness);
		cylinder(r1=radius-gear_thickness/2,r2=radius,h=gear_thickness,$fn=2*number_of_teeth);
	}
	cylinder(r1=radius+gear_thickness/2,r2=radius,h=gear_thickness,$fn=2*number_of_teeth);
}}

module gear (
	number_of_teeth=15,
	circular_pitch=10,
	pressure_angle=20,
	depth_ratio=2/PI,
	clearance=0,
	helix_angle=0,
	gear_thickness=5,
	flat=false){
twist=turn(number_of_teeth,circular_pitch,helix_angle,gear_thickness);

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

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

module gear2D (
	number_of_teeth,
	circular_pitch,
	pressure_angle,
	depth_ratio,
	clearance){
pitch_radius = pitchR(number_of_teeth,circular_pitch);
base_radius = pitch_radius*cos(pressure_angle);
depth = rackDepth(circular_pitch,pressure_angle);
max_radius = pitch_radius+depth/2+max(-clearance,0);
outer_radius = outerR(number_of_teeth, circular_pitch, pressure_angle, clearance, depth_ratio);
inner_radius = innerR(number_of_teeth, circular_pitch, pressure_angle, clearance, depth_ratio);
min_radius = max(base_radius,inner_radius);
backlash_angle = clearance/(pitch_radius*cos(pressure_angle)) * 180 / PI;
pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
tip_angle = atan2(pitch_point[1], pitch_point[0]) + 90/number_of_teeth - backlash_angle/2;

intersection(){
	circle($fn=number_of_teeth*2,r=outer_radius);
	union(){
		rotate(90/number_of_teeth)
			circle($fn=number_of_teeth*2,r=inner_radius);
		for (i = [1:number_of_teeth])rotate(i*360/number_of_teeth){
			halftooth (
				base_radius,
				min_radius,
				max_radius,
				tip_angle);
			mirror([0,1])halftooth (
				base_radius,
				min_radius,
				max_radius,
				tip_angle);
		}
	}
}}

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

difference(){
	rotate(-tip_angle)polygon(points=p);
	square(2*max_radius);
}}

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

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

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

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

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

function pitchR(Nteeth=15, pitch=10) = Nteeth*pitch/(2*PI);

function turn(Nteeth=15, pitch=10, helix_angle=0, h=5) = tan(helix_angle)*h/pitchR(Nteeth, pitch)*180/PI;

function rackDepth(pitch=10, pressure_angle=20) = pitch/(2*tan(pressure_angle));

function baseR(Nteeth=15, pitch=10, pressure_angle=20) = pitchR(Nteeth, pitch)*cos(pressure_angle);

function innerR(Nteeth=15, pitch=10, pressure_angle=20, clearance=0, depth_ratio=2/PI) =
	max(max(pitchR(Nteeth, pitch)-rackDepth(pitch, pressure_angle)/2-clearance/2,
		baseR(Nteeth, pitch, pressure_angle)*sign(-clearance)),
		pitchR(Nteeth, pitch)-depth_ratio*pitch/2-clearance/2);

function outerR(Nteeth=15, pitch=10, pressure_angle=20, clearance=0, depth_ratio=2/PI) =
	pitchR(Nteeth, pitch) + min(depth_ratio*pitch/2-clearance/2,
		rackDepth(pitch, pressure_angle)/2+max(-clearance,0));

function depth_diameter(Nteeth=15, pressure_angle=20, depth_ratio=2/PI) =
	min(PI/(2*Nteeth*tan(pressure_angle)),PI*depth_ratio/Nteeth);
```


[User]
Hey, I need an OpenSCAD design for a bearing guard. I've got this 3D printer, a QU-BD OneUp, and it uses these little washers stacked together as guards for the bearings. They keep breaking, and I want to print replacements. I was hoping you could help me design a parametric version of what I've already got so I can adjust it for different bearing sizes if needed.

Basically, the design is a cylinder with a hole in the middle, with a lip extending out around the edge on one side. I've included the .scad file I used as a starting point which has all the dimensions as they're used on the printer for a standard 608 bearing. I'm thinking that I'd like parameters for the inside radius of the bearing (the main hole in the center of the model), the race depth (the thickness of the bearing in the axial direction), the guard radius, the overall thickness of the guard, and the thickness of the race portion. It would be nice if the thickness of the race and the overall thickness are controlled independently to allow for overprinting or adjustments for fit. Can you generate the OpenSCAD file for me? I'm not picky about which libraries you use, but I'd like to be able to just drop the files into my OpenSCAD folder and have them work.

[Assistant]
BearingGuard.scad:
```
// Bearing guard printer

// Radius of inside of bearing
ir=4.6875;
// Race depth
race=2;
rr=ir+race;
// Guard radius (could be bearing size, or more if you like.
or=12.5;
// Thickness of guard
h=1;
// Thickness of race
raceH = 0.5;
h2=h+raceH;

difference() {
	union() {
		cylinder(r=rr, h=h2);
		cylinder(r=or, h=h);
		}
	cylinder(r=ir+.5, h=h2);
	}
```


[User]
I'd like to create a 3D printable broken heart pendant using OpenSCAD, and I'd like it to be parametric so I can easily adjust the size and some other details. I'm aiming for something similar to the "mathgrrl broken heart" design, which uses a mathematical formula for the heart shape. I'm particularly interested in using a parametric curve to define the shape, and then extruding that into a 3D form.

Here's what I'm hoping for:

*   **Heart Shape:** The basic heart shape should be generated by the following parametric equations:
    *   `x(t) = scalefactor * 16 * pow(sin(t), 3)`
    *   `y(t) = scalefactor * (13*cos(t) - 5*cos(2*t) - 2*cos(3*t) - cos(4*t))`
    *   Where `t` will vary between 0 and just under 360 degrees, with the value slightly less than 360 being crucial for a broken heart (to create the break at the top). `scalefactor` is a variable that is used to adjust the size. I will pass in this variable as `heart_diameter` which will be scaled.
*   **Parameters:** I need to be able to control:
    *   `heart_diameter`:  This should control the overall size of the heart, in millimeters.
    *   `line_thickness`: This should control the thickness of the line that forms the heart outline, in millimeters.
    *   `line_height`: This is the extrusion height of the heart, in millimeters.
    *   `number_of_steps`: This should control the resolution of the curve (more steps, smoother; fewer steps, more jagged).
*   **Functionality:**  The design should extrude the 2D heart curve into a 3D shape. It needs to use a custom module that will draw a polygon between each point in the curve.
*   **Libraries:** I'm aware that I will need some type of library similar to the `2dgraph.scad` library, which is not a standard OpenSCAD library, so please include the necessary code for this to function.

Could you generate the necessary OpenSCAD code to achieve this? I want a single .scad file that includes the heart generation logic and the necessary library code.

[Assistant]
mathgrrl_brokenheart.scad:
```
// mathgrrl broken heart - OpenSCAD parametric graph example

/////////////////////////////////////////////////////////////
// EXTENSIONS ///////////////////////////////////////////////

// curriculum.makerbot.com/daily_tutorial/openscad/openscad_05.html
// include <EXTENSIONS/2dgraph.scad>

/////////////////////////////////////////////////////////////
// PARAMETERS ///////////////////////////////////////////////

// Set the diameter of the heart, in mm
heart_diameter = 20;

// Set the thickness of the line, in mm
line_thickness = 1;

// Set the height of the model, in mm
line_height = 3;

// Choose low numbers for jagged, high for smooth
number_of_steps = 48;

scalefactor = heart_diameter*1.15/20;

/////////////////////////////////////////////////////////////
// RENDERS //////////////////////////////////////////////////

// broken heart parametric curve
// equation from http://mathworld.wolfram.com/HeartCurve.html
function x(t) = scalefactor*16*pow(sin(t),3);
function y(t) = scalefactor*(13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t));

// make the graph and extrude it
linear_extrude(height=line_height)
	2dgraph(	[0, 350], 				// stop before 360 to make broken
				line_thickness, 		// set line thickness
				steps=number_of_steps,// choose low/high poly look
				parametric=true);		// use parametric grapher

/////////////////////////////////////////////////////////////
// MODULES //////////////////////////////////////////////////

// in Customizer we need to include these to use 2dgraph?
// curriculum.makerbot.com/daily_tutorial/openscad/openscad_05.html

// These functions are here to help get the slope of each segment, and use that to find points for a correctly oriented polygon
function diffx(x1, y1, x2, y2, th) = cos(atan((y2-y1)/(x2-x1)) + 90)*(th/2);
function diffy(x1, y1, x2, y2, th) = sin(atan((y2-y1)/(x2-x1)) + 90)*(th/2);
function point1(x1, y1, x2, y2, th) = [x1-diffx(x1, y1, x2, y2, th), y1-diffy(x1, y1, x2, y2, th)];
function point2(x1, y1, x2, y2, th) = [x2-diffx(x1, y1, x2, y2, th), y2-diffy(x1, y1, x2, y2, th)];
function point3(x1, y1, x2, y2, th) = [x2+diffx(x1, y1, x2, y2, th), y2+diffy(x1, y1, x2, y2, th)];
function point4(x1, y1, x2, y2, th) = [x1+diffx(x1, y1, x2, y2, th), y1+diffy(x1, y1, x2, y2, th)];
function polarX(theta) = cos(theta)*r(theta);
function polarY(theta) = sin(theta)*r(theta);

module nextPolygon(x1, y1, x2, y2, x3, y3, th) {
    if((x2 > x1 && x2-diffx(x2, y2, x3, y3, th) < x2-diffx(x1, y1, x2, y2, th) || (x2 <= x1 && x2-diffx(x2, y2, x3, y3, th) > x2-diffx(x1, y1, x2, y2, th)))) {
        polygon(
            points = [
                point1(x1, y1, x2, y2, th),
                point2(x1, y1, x2, y2, th),
                // This point connects this segment to the next
                point4(x2, y2, x3, y3, th),
                point3(x1, y1, x2, y2, th),
                point4(x1, y1, x2, y2, th)
            ],
            paths = [[0,1,2,3,4]]
        );
    }
    else if((x2 > x1 && x2-diffx(x2, y2, x3, y3, th) > x2-diffx(x1, y1, x2, y2, th) || (x2 <= x1 && x2-diffx(x2, y2, x3, y3, th) < x2-diffx(x1, y1, x2, y2, th)))) {
        polygon(
            points = [
                point1(x1, y1, x2, y2, th),
                point2(x1, y1, x2, y2, th),
                // This point connects this segment to the next
                point1(x2, y2, x3, y3, th),
                point3(x1, y1, x2, y2, th),
                point4(x1, y1, x2, y2, th)
            ],
            paths = [[0,1,2,3,4]]
        );
    }
    else {
        polygon(
            points = [
                point1(x1, y1, x2, y2, th),
                point2(x1, y1, x2, y2, th),
                point3(x1, y1, x2, y2, th),
                point4(x1, y1, x2, y2, th)
            ],
            paths = [[0,1,2,3]]
        );
    }
}

module 2dgraph(bounds=[-10,10], th=2, steps=10, polar=false, parametric=false) {

    step = (bounds[1]-bounds[0])/steps;
    union() {
        for(i = [bounds[0]:step:bounds[1]-step]) {
            if(polar) {
                nextPolygon(polarX(i), polarY(i), polarX(i+step), polarY(i+step), polarX(i+2*step), polarY(i+2*step), th);
            }
            else if(parametric) {
                nextPolygon(x(i), y(i), x(i+step), y(i+step), x(i+2*step), y(i+2*step), th);
            }
            else {
                nextPolygon(i, f(i), i+step, f(i+step), i+2*step, f(i+2*step), th);
            }
        }
    }
}
```


[User]
I need a parametric adapter to mount VGA fans to standard 40mm and 50mm fan mounts. I've got a few different ideas for hole configurations, so I'd like to be able to choose between them. I'm also thinking about wire routing.

Here's the specific design I'm envisioning:

*   **Fan Size:** The adapter needs to work with both 40mm and 50mm fans as the mounting target.
*   **VGA Fan Mounting:** The adapter will have mounting holes for a standard VGA fan. The distance between holes is about 35mm, and the mounting holes are approximately 2.5mm diameter. The VGA fan will mount flush to the top of the adapter.
*   **Target Fan Mounting:** The adapter should have standard mounting holes and recessed nut pockets for 40mm or 50mm fans depending on selection. Those are approximately 3.5mm diameter with a 6.2mm nut recess that is about 3mm deep, though this should be parametrically adjustable.
*   **Hole Configuration:** The user should be able to choose between the following mounting hole configurations:
    *   **"fan"**: Only the standard 40/50mm fan mounting holes are present.
    *   **"vga"**: Only the VGA fan mounting holes are present.
    *   **"both"**: Both VGA and standard fan mounting holes are present.
    *    **"cross"**: Both sets of mounting holes are present and in a mirrored configuration about the center of the adapter, so that they form a cross shape
    *   **"side"**: All mounting holes are present on one side of the adapter.
*   **Adapter Body:** The main body of the adapter should be a rounded rectangular box shape. The size should be driven by the fan width, but the VGA fan should be centered and contained by the design even when using a larger 50mm fan. The adapter should be roughly 10mm tall.
*    **Inner Support:** The inner mounting area for the VGA fan should also be a rounded box shape, but slightly shorter than the full height. This provides some structural support for the VGA fan. The VGA fan should have a 1mm wall surrounding it at this interior section.
*   **Wire Routing:** There should be a small channel to run the VGA fan wire down and out to the side of the adapter. This channel should be roughly 3mm wide and 1.7mm high, recessed into the base of the adapter.

I'd like to use the `MCAD/boxes.scad` library for the rounded box function. Can you generate the OpenSCAD code for this? It should be fully parametric so that I can adjust the dimensions and hole configurations.

[Assistant]
vga_to_fan_adapter.scad:
```
use <MCAD/boxes.scad>;

/* [Global] */
// What is the fan size?
fan_w=40;//[40,50]

// What is the position of the holes?
holes = "side";// [fan:Regular fan only, vga:VGA fan only, both:Both fans, cross:Cross position, side:On one side]

/* [Hidden] */
$fs=1;
$fa=1.5;

wall_w = 1.2;
vga_w = 41.5;
vga_h = 10;
vga_int_h = vga_h - 2.4;
vga_hole = 35;
fan_hole = fan_w * 0.8;
vga_hole_d = 2.5;
fan_hole_d = 3.5;
fan_nut_d = 6.2;
fan_nut_h = 3;
wire_w = 3;
wire_h = 1.7;

difference()
{
	if(vga_w > fan_w)
	{
		roundedBox([vga_w + wall_w, vga_w + wall_w, vga_h],1,true);
	}
	else
	{
		roundedBox([fan_w + wall_w, fan_w + wall_w, vga_h],1,true);
	}
	union()
	{
		translate([0,0, vga_int_h/2+1]) roundedBox([vga_w, vga_w, vga_h - vga_int_h + 2],1,true);
		cylinder(r = (vga_w-wall_w)/2, h = vga_h+2, center = true);
		if( holes == "vga" || holes == "cross" || holes == "both"  || holes == "side")
		{
			translate([ -vga_hole/2, -vga_hole/2, 0])
				cylinder(r = vga_hole_d/2, h = vga_h+2, center = true);
		}
		if( holes == "vga" || holes == "cross" || holes == "both" )
		{
			translate([  vga_hole/2,  vga_hole/2, 0])
				cylinder(r = vga_hole_d/2, h = vga_h+2, center = true);
		}
		if( holes == "vga" || holes == "both" )
		{
			translate([  vga_hole/2, -vga_hole/2, 0])
				cylinder(r = vga_hole_d/2, h = vga_h+2, center = true);
		}
		if( holes == "vga" || holes == "both"  || holes == "side" )
		{
			translate([ -vga_hole/2,  vga_hole/2, 0])
				cylinder(r = vga_hole_d/2, h = vga_h+2, center = true);
		}

		if( holes == "fan" || holes == "cross" || holes == "both" )
		{
			translate([ -fan_hole/2,  fan_hole/2, 0])
			{
				cylinder(r = fan_hole_d/2, h = vga_h+2, center = true);
				translate([ 0, 0, vga_int_h/2-(vga_h-vga_int_h)+2])
					cylinder(r = fan_nut_d/2, h = fan_nut_h+4, center = true);
			}
		}
		if( holes == "fan" || holes == "cross" || holes == "both" || holes == "side" )
		{
			translate([  fan_hole/2,  -fan_hole/2, 0])
			{
				cylinder(r = fan_hole_d/2, h = vga_h+2, center = true);
				translate([ 0, 0, vga_int_h/2-(vga_h-vga_int_h)+2])
					cylinder(r = fan_nut_d/2, h = fan_nut_h+4, center = true);
			}
		}
		if( holes == "fan" || holes == "both"  || holes == "side" )
		{
			translate([  fan_hole/2,  fan_hole/2, 0])
			{
				cylinder(r = fan_hole_d/2, h = vga_h+2, center = true);
				translate([ 0, 0, vga_int_h/2-(vga_h-vga_int_h)+2])
					cylinder(r = fan_nut_d/2, h = fan_nut_h+4, center = true);
			}
		}
		if( holes == "fan" || holes == "both" )
		{
			translate([ -fan_hole/2,  -fan_hole/2, 0])
			{
				cylinder(r = fan_hole_d/2, h = vga_h+2, center = true);
				translate([ 0, 0, vga_int_h/2-(vga_h-vga_int_h)+2])
					cylinder(r = fan_nut_d/2, h = fan_nut_h+4, center = true);
			}
		}
		translate([-wire_w/2, 0, - vga_h/2 - 1])
			cube([wire_w,	vga_w + fan_w, wire_h + 1]);
	}
}

```


[User]
I'd like to design a customizable hamster wheel, something similar to what's described in the provided text, but I need it to be a completely new design.  It needs to be parametric so I can easily adjust the size and features.

The main parts are the wheel itself, a snap-on axel that attaches to the cage, and a center post that the wheel rotates around. I envision the wheel as having a rounded back, a running track with optional treads, and a center post with a flared base for stability.  I want the wheel's back to have a pattern of cutouts to make it print easier. The axel needs to snap securely onto standard cage bars and hold the wheel a set distance away from the cage to allow free rotation. I would like to be able to specify the diameter of the wheel, the depth of the running track, the thickness of both the back and track, the axel diameter, the center post dimensions, the amount of rounding on the corners, the cutout pattern details, and the tread bumps on the running path. I also need to specify the cage bar dimensions and spacing, plus the overhang for the snap-on axel.

I'd like the design to have the following parameters that can be easily changed:

*   **Wheel Parameters:**
    *   `wheel_diam`: Diameter of the wheel (measured to the outside).
    *   `wheel_depth`: Depth of the wheel (width of the running track).
    *   `back_thick`: Thickness of the back of the wheel.
    *   `wheel_thick`: Thickness of the wheel running track.
    *   `o_corner_r`: Radius of the rounded back outside edge of the wheel.
    *   `i_corner_r`: Radius of the rounded back inside edge of the wheel.
    *   `hole_coverage`: Percentage of material to cut out of the back for easier printing.
    *   `hole_sections`: Number of sections to cut out of the back.
	*   `tread_sections`: Number of tread bumps along the running path.
*   **Axel Parameters:**
    *   `axel_diam`: Diameter of the axel.
    *   `center_post_diam`: Outside diameter of the center post.
    *   `center_post_h`: Height of the center post (and length of the axel).
    *   `post_base_corner_r`: Radius of the rounded base of the center post.
*   **Cage Attachment Parameters:**
    *   `bar_d`: Diameter of the cage bars.
    *   `bar_space`: Space between cage bars (measured from center to center).
    *    `bar_snap`: Overhang distance for the axel snap to the cage bars.
	*   `wheel_cage_clearance`: Space between the back of the wheel and the cage bars.

I'd like the OpenSCAD code to have modules for:

*   `hamster_wheel()`: Creates the full wheel assembly.
*   `axel()`: Creates the snap-on axel with cage attachment.
*   `center_post()`: Creates the center post.
*   `hollow_wheel()`: Creates the main wheel shape (bowl).
*   `back_holes()`: Creates the cutout pattern on the back.
*   `tread()`: Creates the treads on the running path.
*    `bars()`: for visualzation of cage bars.
*   `cylinder_rounded_top()`: Helper function for making cylinders with a rounded edge on top.
*   `fil_polar_i()`: Helper for creating inside fillets (rounded edges).
*   `fil_polar_o()`: Helper for creating outside fillets (rounded edges).
*  `fil_2d_i()`: Helper for 2D inside fillets.
*  `fil_2d_o()`: Helper for 2D outside fillets.

It would be great if the OpenSCAD file would include a way to select which part to render using a `part` variable. Possible values for the `part` variable are "Wheel", "SnapOnAxel", and "AxelWithPost". Also, if the user selects "All", it should display all parts, including cage bars for visualization (though the cage bars don't need to be printable).

I don't need any additional libraries. Just the core OpenSCAD functions.

Thanks!

[Assistant]
HamsterWheelCustomizedv6.scad:
```
// A better Hamster Wheel  Jan 3, 2014
//
//  Goal was to learn OpenScad and create something valuable
//  for my daughters little friend Pippi the hamster.
//
//  You will find a very customizable wheel along with a
//  custom axel made to snap onto the back of the cage.
//
//  The wheel itself is a big print, so I suggest first printing
// the axel along with the center post.   While the center post is
// a throw-away once you print the wheel this gives you the chance
// to verify that it will fit onto the cage properly and that the
// post spins freely.  You may need to try the axel a few times
// to get the parameters right for a snap on fit for the cage.
//
// Pippi the hamster loves his new 150cm wheel.
//
// The measurements below all worked well for me and resulted in
// a sturdy fast wheel.
//

//CUSTOMIZER VARIABLES

/* [Global] */
// Which view do you want to use?
part = "Wheel"; // [Wheel:Print Wheel,SnapOnAxel:Snap on Axel,AxelWithPost:Print Snap-on Axel and Center Post)]

// This section displays the wheel options
// Diameter(mm) of wheel (measured to the outside)
wheel_diam=150;  // [90:200]

// Depth(mm) of wheel determines width of the running track
wheel_depth=65;  // [20:120]

// Thickness of back of wheel
back_thick=1.8;  // [1.0,1.2,1.4,1.6,1.8,2.0,2.2,2.4,2.6,2.8]

// Thickness of wheel running track
wheel_thick=1.6; // [1.0,1.2,1.4,1.6,1.8,2.0,2.2,2.4,2.6,2.8]

// Diameter of your axel.  Must hold the wheel and fit through bars
axel_diam=8; // [2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12]

// Center post outside diameter.  At least +4 over axel diameter.
center_post_diam=12; // [4,4.5,6,6.5,7,7.5,8,8.5,9,10,11,12,13,14,15,16]

// Center post height (also the axel length).  Over half of wheel depth.
center_post_h=46;  // [10:120]

// Post base radius.  Adds stiffness to center post
post_base_corner_r=14;  // [4:20]

// Radius of rounded back outside edge of wheel (small to avoid overhang)
o_corner_r=1.5;  // [0,0.5,1,1.2,1.5,1.8,2,2.2,2.5,2.8,3,3.2,3.5,3.8,4]

// Radius of rounded back inside edge of wheel (make at least 0.5 > than outside radius corner
i_corner_r=8;    // [1,2,3,4,5,6,7,8,9,10]

// Pct of material to cut out of back (makes printing easier).
hole_coverage=50; // [0:75]

// Number of sections to cut out of back (size depends on prior parameter)
hole_sections=12; // [4:16]

// Number of treads on running path (creates bumps for grip)
tread_sections=40; // [10:80]

//echo("tread bump distance=",(3.14159*wheel_diam)/tread_sections);

   axel_hole_diam=axel_diam+1; // how much wiggle room for axel

// Diameter of cage bar
bar_d=2.2; // [1,1.2,1.4,1.6,1.8,2,2.2,2.4,2.6,2.8,3,3.2,3.4.3.6,3.8,4]

// Space between bars (measured on center).
bar_space=10;  // [7,7.5,8,8.5,9,9.5,10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5]

// Overhang to make the axel snap to cage.  Smaller is looser.
bar_snap=0.4;  // [0.1,0.2,0.3,0.4,0.5,0.6]

// Space back wheel needs to be held way from cage for spin clearance.
wheel_cage_clearance=11;

/* [Hidden] */

   i_cage_offset=bar_d+wheel_cage_clearance;

   o_base_d=3.6+0;
   o_base_w=20+0;
   o_base_h=bar_space*9;
   axel_overlap_d=axel_hole_diam+1.1;// enough to keep wheel in place
   axel_l=center_post_h+1;
   axel_corner_r=axel_overlap_d/4;
   axel_cap_h=axel_corner_r+1; // assume half round
   bend_gap_w=axel_overlap_d-axel_hole_diam+1.2;  // must be able to
									//squeeze the overlap into the axel hole
									// the 1 should provide that space
   bend_gap_h=axel_l*3/5;

//CUSTOMIZER VARIABLES END

// [Wheel:Print Wheel,SnapOnAxel:Print Axel,AxelWithPost:Print Snap-on Axel and Center Post,All:Show all parts with cage bars(not for print)]
print_part();

module print_part() {
  if (part=="Wheel") {
    print_wheel();
  } else if (part=="SnapOnAxel"){
    print_axel();
  } else if (part=="AxelWithPost") {
    print_axel_w_post();
  } else if (part=="All") {
    show_all();
  } else {
    show_all();
  }
}

// -- Time to Render //
module print_wheel() {
	translate([0,0,wheel_depth]) rotate([0,180,0])
		hamster_wheel(wheel_diam=wheel_diam,
						wheel_depth=wheel_depth,
						back_thick=back_thick,
						center_post_diam=center_post_diam,
						center_post_h=center_post_h,
						axel_hole_diam=axel_hole_diam,
						o_corner_r=o_corner_r,
						i_corner_r=i_corner_r,
						post_base_corner_r=post_base_corner_r,
						hole_coverage=hole_coverage,
						hole_sections=hole_sections,
						tread_sections=tread_sections);
}

module print_axel() {
	translate([0,0,o_base_d])
		axel(post_h=center_post_h,
				  axel_diam=axel_diam,
				  axel_hole_diam=axel_hole_diam);
}

module print_axel_w_post() {
  print_axel();
  translate([50,0,0])
			difference() {
				translate([0,0,0])
					center_post(post_h=center_post_h,
						 post_diam=center_post_diam,
						 base_corner_r=post_base_corner_r,
						 corner_r=1);
				translate([0,0,0])
        			cylinder(h=wheel_depth+2,r=axel_hole_diam/2,$fn=32);
  			};
}

module show_all() {
  // axel
  translate([0,0,0-(i_cage_offset)])
		union() {
			 axel(post_h=center_post_h,
				 	axel_diam=axel_diam,
				  	axel_hole_diam=axel_hole_diam);
			 color("black") bars(bar_space=bar_space,bar_d=bar_d);
		}
  print_wheel();
}

// ------------------------------------------------------
// For the rounded corners I used the fillet
// modules from "Airtripper's Bowden 3D Printer Extruder"
// thingiverse project.
// The modules were slightly modifed for my needs for proper
// overlap and height consistency.
//

// 2d primitive for inside fillets.
module fil_2d_i(r, angle=90) {
  difference() {
    polygon([
      [0, 0],
      [0, -r],
      [-r * tan(angle/2), -r],
      [-r * sin(angle), -r * cos(angle)]
    ]);
    circle(r=r);
  }
}

// 3d polar inside fillet.
module fil_polar_i(R, r, angle=90) {
  rotate_extrude(convexity=10) {
    translate([R, 0, 0]) {
      fil_2d_i(r, angle);
    }
  }
}

// 2d primitive for outside fillets.
module fil_2d_o(r, angle=90) {
   $fn=100;
   intersection() {
    circle(r=r);
    polygon([
      [0, 0],
      [0, r],
      [r * tan(angle/2), r],
      [r * sin(angle), r * cos(angle)]
    ]);
  }
}

// 3d polar outside fillet.
module fil_polar_o(R, r, h, angle=90) {
  $fn=100;
  union(){
	  translate([0,0,h-r]) {
		rotate_extrude(convexity=10) {
		    translate([R-r, 0, 0]) {
		      fil_2d_o(r, angle);
		    }
		  }
	      cylinder(r=R-r+0.1, h=r+0.1);
      }
      cylinder(r=R, h=(h-r)+0.1);
  }
}

// --------------------------------------------
// -----------------------------------------
// Main modules for building the Hamster Wheel
// along with axel and cage attachment.
//
// Main 2 modules are:
//    hamster_wheel() and axel()
//

// cylinder_rounded_top() is used to create a
// vertical cylinder with the top edge rounded
// off a a given corner r.
// This module is called often for creating rounded
// edges.
module cylinder_rounded_top(diam,corner_r,depth) {
 fil_polar_o(R=diam/2,r=corner_r,h=depth, angle=90);
}

// hollow_wheel() creates the main fram of the wheel
// essentially by creating a bowl. (actually it creates
// a dome which will be flipped later)
module hollow_wheel(wheel_diam,
						  i_corner_r,
						  o_corner_r,
						  wheel_depth,
						  back_thick) {
	inner_diam=wheel_diam-(wheel_thick*2);
	difference() {
     	cylinder_rounded_top(diam=wheel_diam,
										corner_r=o_corner_r,
										depth=wheel_depth);
		translate([0,0,-1])
			cylinder_rounded_top(diam=inner_diam,
											corner_r=i_corner_r,
											depth=(wheel_depth-back_thick)+1);
	 }
}

// bars() draws the bars representing the cage bars.
// This is used for visualization and also for removing
// grooves needed by the snap-on axel.
// The bars are only shown when drawing the Axel while
// in display="together" mode.
module bars(bar_space,bar_d) {
  for (i=[1:8]) {
	  	translate([0,bar_space*i-bar_space/2,bar_d/2])
   	   rotate([0,90,0]) cylinder(h=200,r=bar_d/2,$fn=16,center=true);
		translate([0,0 - (bar_space*i-bar_space/2),bar_d/2])
   	   rotate([0,90,0]) cylinder(h=200,r=bar_d/2,$fn=16,center=true);
  }
}

// axel() creates the axel around which the wheel will spin
// The axel is also attached to the snap-on cage
// attachement.
module axel(post_h,
				axel_diam,
				axel_hole_diam) {

   axel_over=0.6;  // make the axel a bit longer
                   // which is used to overlap the
						 // parts and avoid face gaps.

   rotate([1,0,0])  // angles the axel ever so slightly upward
						  // which I found compensates for the bend
						  // of the cage with the wheel attached.
						  // decided to leave this off the parameter list
   translate([0,0,i_cage_offset-axel_over])
   difference () {
		difference() { // post with mushroom cap
 			cylinder_rounded_top(diam=axel_overlap_d,
											depth=axel_l+axel_cap_h+axel_over,
											corner_r=axel_corner_r);
			difference() { // sleeve to subtract
				cylinder(h=axel_l+axel_over,
											r=(axel_overlap_d/2)+1,
											$fn=64);
            cylinder(h=axel_l+axel_over,
											   r=axel_diam/2,
									  			$fn=64);
			}
		} // gap to substract
      union () { // remove sqeezable gap (which is squeezed to fit the
                // axel cap thru the smaller axel hole in the post.
      	//squeeze gap
			translate([0-bend_gap_w/2,
				     0-axel_overlap_d/2,
					  axel_l+axel_cap_h-bend_gap_h])
				cube([bend_gap_w,axel_overlap_d,bend_gap_h+1]);
			// The bar only squeezes in one direction so the cap
		   // must be shaved off in the other direction in order
		   // to fit thru the post axel hole.
         // shave right cap (+y)
			translate([axel_overlap_d/2,
				     ((axel_diam)/2),
					  axel_l+axel_cap_h-bend_gap_h])
				rotate([0,0,90])
					cube([bend_gap_w,axel_overlap_d,bend_gap_h+1]);
         //shave left cap(-y)
			translate([axel_overlap_d/2,
				     0-((axel_diam)/2+bend_gap_w),
					  axel_l+axel_cap_h-bend_gap_h])
				rotate([0,0,90])
					cube([bend_gap_w,axel_overlap_d,bend_gap_h+1]);
	 	}
	}
   // Now build the snap on plate that the axel is attached to
   // it snaps onto the outside of the cage bars.
   difference() {
    union() {
   // block sticking up between bar for axel to attach to
   // This block sticks up far enough to give the wheel
   // freedom to spin without hitting the cage wall.
   // adjust using the cage_clearance parameter.
   	translate([0,0,i_cage_offset/2])
			cube([axel_overlap_d+2,axel_diam,i_cage_offset],center=true);
   // block are created with just enough room for the cage
   // bars to squeeze tight between.
   // blocks between bars below axel
   	translate([0,bar_space,bar_d])
			cube([o_base_w,bar_snap+bar_space-bar_d,bar_d*2],center=true);
   	translate([0,bar_space*2,bar_d])
			cube([o_base_w,bar_snap+bar_space-bar_d,bar_d*2],center=true);
   // block between bars above axel
   	translate([0,0-bar_space,bar_d])
			cube([o_base_w, bar_snap+bar_space-bar_d,bar_d*2],center=true);
   // block between 3 bars above axel with raised base
   	translate([0,0-bar_space*4,bar_d])
			cube([o_base_w,bar_snap+bar_space-bar_d,bar_d*2],center=true);
   // block between 4 bars above axel with raised base
   	translate([0,0-bar_space*5,bar_d])
			cube([o_base_w,bar_snap+bar_space-bar_d,bar_d*2],center=true);
   // the stiff strip attaches vertically on outside of cage
		translate([0,0-o_base_h/2+bar_space*3,0-o_base_d/2])
      union() {
 		  cube([o_base_w,o_base_h,o_base_d],center=true);
      }
	 } // now by removing the space where the bars should
      // be, we provide a small rounded edge to the bars to
      // snap into.
    union () {  // remove the following
		bars(bar_space=bar_space,bar_d=bar_d);
		translate([0,0,bar_d+0.4])
			bars(bar_space=bar_space,bar_d=bar_d);
    }
   }

}

// ---------------------------------------------------
// center_post() build the post which rotates around the
// axel.  It is a cylinder with a hole just big enough
// for the axel.  It has a rounded top and the base is
// flared out with gives is a very rigid attachment to
// the back of the wheel.
module center_post(post_h,
						 post_diam,
						 base_corner_r,
						 corner_r) {
   cylinder_rounded_top(diam=center_post_diam,
									depth=post_h,
									corner_r=1);
	translate([0,0,base_corner_r])
		fil_polar_i(R=center_post_diam/2+base_corner_r,
						r=base_corner_r,angle=90);
}

// back_holes() creates a 2D pattern to be used to
// remove this pattern from the back of the wheel.
// I had issues trying to get the very large area
// solid back to stick to the build plate while printing
// the first 2 layers.
// I found that by removing material it printed better
// and so this also helps make an attractive pattern
// that is customizable.  Need to leave enough material
// to keep the wheel stiff.
module back_holes(o_rad,i_rad,sections,coverage)
{  a=(360*coverage/100)/sections;
   o_y=2*sin(a/2)*o_rad;
   i_y=2*sin(a/2)*i_rad;
   len=(o_rad-i_rad)-o_y/2-i_y/2;
   for (i=[1:sections]) {
				rotate([0,0,i*360/sections])
               intersection() {
                 hull(convexity=10) {translate([i_rad+i_y/2,0,0]) circle(i_y/2);
                         translate([o_rad-o_y/2,0,0]) circle(o_y/2);
			               }
                 polygon(points=[[0,0],
											[o_rad,0-o_y/2],
											[o_rad,0+o_y/2]],
								 convexity=10);
                              }
       }
}

// ----------------------------------------
// tread() produces the little bumps along the
// running path of the wheel.   I found the hamster
// really likes them to be less than 2cm apart.
// Use the parameter tread_sections to adjust.
// The bumps are the edges of cylinders embedded
// in the wheel.
module tread(wheel_diam,
				 wheel_depth,
			    wheel_thick,
				 o_corner_r,
				 sections)
{  a=360/sections;
   R=wheel_diam/2-wheel_thick;
   r=wheel_thick/2-.1;
   h=wheel_depth-o_corner_r;
   for (i=[1:sections]) {
				rotate([0,0,i*a])
			  		translate([R,0,0])
						cylinder(h=h,r=r,$fn=16);
   }
}

//------------------------------------
// hamster_wheel() puts the wheel together and
// finishes it off with a rounded bezel around the
// open edge.
module hamster_wheel(wheel_diam,
							wheel_depth,
							back_thick,
							center_post_diam,
							center_post_h,
							axel_hole_diam,
							o_corner_r,
							i_corner_r,
							post_base_corner_r,
							hole_coverage,
							hole_sections,
							tread_sections) {
  difference() {
  	 union() { // full shell
          hollow_wheel(wheel_diam=wheel_diam,
                       i_corner_r=i_corner_r,
							  o_corner_r=o_corner_r,
                       wheel_depth=wheel_depth,
                       back_thick=back_thick);
  	       translate([0,0,wheel_depth]) rotate([0,180,0])
               center_post(post_h=center_post_h,
                           post_diam=center_post_diam,
                           base_corner_r=post_base_corner_r,
								   axel_diam=axel_hole_diam,
                           corner_r=o_corner_r/2);
			 tread(wheel_diam=wheel_diam,
					 wheel_depth=wheel_depth,
			   	 wheel_thick=wheel_thick,
					 o_corner_r=o_corner_r,
					 sections=tread_sections);
			 translate ([0,0,0])
				rotate_extrude(convexity=10,$fn=64) {
		    		translate([wheel_diam/2, 0, 0]) {
		      		circle(wheel_thick/2+.2,$fn=32);
		     }
		  }
    }

	 union() // parts to remove
      {
        translate([0,0,0])
        		cylinder(h=wheel_depth+2,r=axel_hole_diam/2,$fn=32);
        translate([0,0,wheel_depth-back_thick*2])
            linear_extrude(height=back_thick*4,convexity=10)
               {back_holes(o_rad=wheel_diam/2-wheel_thick-i_corner_r-2,
                           i_rad=center_post_diam/2+post_base_corner_r,
                           sections=hole_sections,
                           coverage=hole_coverage);
               }
      }
	}
}

```


[User]
I'm looking to design a parametric replacement extruder for my QU-BD One/TwoUp 3D printer, and I'd like to use OpenSCAD for this. I need a design that's both functional and relatively easy to tweak. The extruder needs to securely hold the hot end, facilitate easy filament loading and unloading, and optionally integrate fan cooling. I'm aiming for a modular approach, where I can start with the basic extruder and then add the fan and venting later. I've attached the description of a design I've been working on, along with its OpenSCAD file (UpExtruderv11.scad), as a reference point for some ideas.

Here are the key features I want:

1.  **Body & Lever:**
    *   A main body that replaces the existing MDF parts and mounts to the printer's gantry system.
    *   A lever mechanism that makes it easy to load and unload filament. It should pivot, using a M3 screw, and should apply tension to the bearing. The lever should have an integrated guide to help keep the filament on path to the bearing and hot end.
    *   The body should be designed with mating features to connect the two halves when printed, to ensure proper alignment of the two halves.
    *   The design should securely hold a standard hot end. I'm using the same hot end as the original printer.
    *   The design should use existing screws, springs, and bearings from the original printer.
2.  **Hot End:**
    *   A secure mounting point for the hot end, designed to be quite firm.
    *   It should accommodate the standard hot end, with a diameter around 7.94mm, with a groove radius of 8.25mm, and a groove depth of 2.5mm.
    *   The hot end should be positioned at roughly half the Z height of the body.
3.  **Motor Mount:**
    *   The design must accommodate the printer's stepper motor. The current design uses an NEMA 17 stepper motor, and screws onto the mounting plate with 4 M3 screws.
    *   It should allow for mounting with 4 screws, though the original design uses 3.
4.  **Filament Path:**
    *   The design should ensure the filament path is smooth and direct to the hot end.
    *   It should work well with 1.75mm filament, which goes directly from the bearing to the hot end.
5.  **Bearing:**
    *   The bearing is a standard 625ZZ bearing.
    *   The design must accommodate this bearing and its associated components (spring, lever, etc).
    *   The bearing needs to be offset by 0.5mm, to leave room for filament.
6.  **Venting (Optional):**
    *   I would like an optional vent system that can direct a fan's airflow onto the motor and the print.
    *   This vent should be designed to integrate with a 40mm fan and be printed as a single piece, ideally.
    *   The vents need to be angled so they don't melt due to the hot end, but also so that they clear the left side of the print bed during full X travel.
7. **Spring:**
	*   The current design uses a 16mm spring hole, with a 3mm radius.
	*   The support for this spring should be strong.

8.  **Parametric Design:**
    *   I'd like for all the key dimensions to be easily adjustable through variables.
    *   This includes things like the box dimensions, wall thicknesses, screw hole positions, hot end positioning, bearing diameter, lever length, etc.

I think it'd be best to break this down into a few OpenSCAD modules that can be combined: the body, the lever, and then the optional fan/vent system. The `part` variable would be useful for easily selecting which parts to view or generate.

I am not specifically looking for any libraries to be used for this design, but if it makes sense to use them please let me know. This should be buildable from scratch in OpenSCAD.

[Assistant]
UpExtruderv11.scad:
```
// TwoUp Extruder model

/* todo:

- Add bumps/holes so two halves of parts mate together (done)
- make body more airtight to force more air to vent
- add second vent to fan (done)
- make hot end tighter (done)
- make spring shorter (done)
- move spring out slightly (done, added holder)
- move bearing away 0.5mm (done)

*/

$fn=32;
part = 0; //[0:Preview Assembled, 6:Body plated, 9:Lever plated, 10:Vent, 11:Fan vent]

/* [Spring] */

// Spring hole height (mm)
springH = 16;
// Spring hole radius (mm)
springR = 3;

/* [General] */

// lever length
ll=20;
// Lever back angle (to go around screw and meet bearing hub)
la = 10;
// box x
bx=57;
// box y
by=47.72;
// box z
bz=30.72;
// Wall thickness
wall = 5;
// Clearance
clearance = 0.4;

/* [Hot End] */

// hot end Z
hz=15.36-2;
hz=bz/2;
// Hot end X
hx = 27;
// Hot end y
hy=7;

/* [Motor] */

// motor X
mx = 21;
// motor y
my = 26.72;
// motor size (approx)
ms = by-5;
// middle width
midW = bz-2*wall-2*clearance;
// Screws X Y position
sx1 = 5.5+1;
sx2 = 37.5;
sy1 = 11.22;
sy2 = 42.22;
sr = 1.5; //M3 screws' radius

/* [Bearing] */

// Tension bearing inner diameter
bid = 9.525;
// Tension bearing outer diameter
bod = 15.875;
// Tension bearing width
bw = 3.967;
// Offset (to leave room for filament)
boff = 0.5;

bir=bid/2;
bor=bod/2;

/* [Vents] */

// Vent length
vh = 55;
// Vent into body
vin = 10;
// vent1 angle
va1 = -5;
// Vent Radius
vr = 6;
// Vent straight
vstraight=20;
// Wall thickness
vw = 2;
// Opening at bottom, width
vopenw = 7;
// Height
vopenh = 5;
// vent sphere for clearance
vhr = midW*.4;

// fan size
fs = 40;

module fan() {
	translate([bx+clearance, 5, fs]) rotate([0,90,0]) cube([fs,fs,10]);
	}

module fanScrews() {
	fso = 32/2;

	translate([bx+clearance-4, 5, fs]) rotate([0,90,0]) translate([fs/2,fs/2,0]) {
		for (x=[-fso,fso]) {
			for (y=[-fso,fso]) {
				translate([x,y,-7]) cylinder(r=sr,h=15+7);
				}
			}
		}
	}

// screw holes, enlarged so screw threads slide through
module screws () {
	//echo("screw x ",sx2-sx1);
	// echo("screw y ",sy2-sy1);
	h=bz+2+2;
	translate([0,0,-1]) {
	translate([sx1,sy1,0]) cylinder(r=sr+2*clearance, h=h);
	translate([sx2,sy1,0]) cylinder(r=sr+2*clearance, h=h);
	translate([sx1,sy2,0]) cylinder(r=sr+2*clearance, h=h);
	translate([sx2,sy2,0]) cylinder(r=sr+2*clearance, h=h);
	}
}

						cubeX = bx-2*mx-2*clearance;
						cubeY = fs-2-12;
						cubeZ = 2+fs-bz-clearance-2;

module fanVent() {
	difference() {
		union() {
			difference() {
				translate([ms+clearance,0,bz+clearance])
					translate([2.5,0,0]) difference() {
						union() {
							translate([0,-vstraight,0])
								cube([bx-ms-2*clearance-2,by+vstraight,fs-bz-clearance]);
							translate([-bx+bx-ms-2*clearance-2,0,0]) cube([bx,by,1]);
							}
						translate([1,1+11,-1])
							difference() {
								cube([cubeX,cubeY,cubeZ]);
								for (y=[cubeY/5:cubeY/5:cubeY-1])
									translate([0,y,0]) cube([cubeX,0.5,cubeZ]);
								}
						translate([-2.5-(ms+clearance),0,-(bz+clearance)]) screws();
						}
				ventHole2();
				fanScrews();
				}
			vent2();
			translate([ms+clearance,0,bz+clearance]) translate([-.73+bx-2*mx-2*clearance-1,1+11,2+fs-bz-clearance-3])
				cube([1,fs-2-12,vr*.1]);
			}
			// bisect for design
			//translate([0,-60,35]) cube([100,100,20]);
		}
	}

module fanVentPlated() {
	//rotate([0,180,0])
		translate([-(ms+clearance),0,vr*1.475-(bz+clearance)-(fs-bz-clearance)])
			fanVent();
}

// hole for hot end in body
module hotend() {
	hh=80; // how far to clear outside
	hin=12; // how far to clear inside
	gr=(16.5-2*1.25)/2; // groove radius
	gy = 7; // y position of groove center
	gh=2*1.25;
	hr = 7.94;

	translate([hx,hy+hin,hz]) rotate([90,0,0]) {
		difference() {
			cylinder(r=hr, h=hh+hin);
			translate([0,0,gy+hin-hy]) cylinder(r=hr+1,h=gh-clearance/2,center=true);
		}
		cylinder(r=gr, h=hh);
	}
}

module vent1() {
	difference() {
		rotate([0,0,va1]) translate([1+vr, vin, bz/2])
			difference() {
				vent(vh);
				//translate([vr,vr,0]) sphere(vhr);
				translate([vhr/2,vhr/2,0]) sphere(vhr);
				}
		hotend();
		}
	}

// the actual vent tube

module vent(vh) {
	vLen = 2*vr;
	difference() {
		rotate([90,0,0]) difference() {
			rotate([0,0,360/16]) {
			difference() {
				union() {
					translate([0,0,-3]) cylinder($fn=8, r=vr, h=vh+vin); // 60 mm to reach extruder, 10mm fit into extruder body
					//translate([0,0,vin]) cylinder($fn=8, r=vr+1, h=1); // 60 mm to reach extruder, 10mm fit into extruder body
					rotate([0,0,-360/16]) translate([vr,0,vh+vin-vopenh/2-1])
						rotate([0,-30,0]) cube([vLen,vopenw+2, vopenh+2], center = true);
					}
				translate([0,0,-4]) cylinder($fn=8, r=vr-vw, h=vh+vin); // 60 mm to reach extruder, 10mm fit into extruder body
				rotate([0,0,-360/16]) translate([vr,0,vh+vin-vopenh/2-1])
					rotate([0,-30,0]) cube([vLen+1,vopenw, vopenh], center = true);
				}
			}
			//translate([-(vr+0.04),0,vin]) cube([1,2*vr,3],center=true);
			}
		//hotend();
		}
	}

module vent2() {
	difference() {
		translate([(2*mx+bx)/2, vin/2-vstraight, bz+(fs-bz)/2+2-.7-1])
			difference() {
				rotate([0,0,-30]) rotate([0,360*2/8,0])
					translate([0,2,0]) vent(vh-vstraight+5);
				translate([-vh*.7,-vh,-vr+.46-10+1]) cube([vh,2*vh,10]);
				}
		hotend();
		}
	}

// hole in body to fit vent
module ventHole(){
	rotate([0,0,va1]) translate([1+vr, vin, bz/2]) rotate([90,0,0]) rotate([0,0,360/16]) {
		cylinder($fn=8, r=vr+clearance/2, h=20, center=true);
		translate([vhr/2,0,-vhr/2]) sphere(vhr);
	}
}

// hole in fan vent for vent
module ventHole2(){
	translate([0,-vstraight-3,-1]) translate([(2*mx+bx)/2+clearance, vin/2+1.1, bz+(fs-bz)/2+2+clearance-1.1]) {
		translate([0,2.5,0]) rotate([90,0,0]) rotate([0,-30,0]) rotate([0,0,360/16])
			translate([0,0,3]) cylinder($fn=8, r=vr-vw, h=14, center=true);
		translate([1.5,vstraight-3.3,0]) rotate([90,0,0]) rotate([0,0,0]) rotate([0,0,360/16])
			cylinder($fn=8, r=vr-vw, h=vstraight*1.3, center=true);
		}
	}

module ventPlate(){
	translate([bx+30,by+vin+13,1.54])
		translate([0,0,-bz/2+2*vr+.36]) rotate([0,-90,0])
			rotate([0,0,-va1]) vent1();
	}

module motorHole() {
	mz = bz+1;
	mh = bz+2;

	translate([mx,my,mz]) rotate([180,0,0]) {
		cylinder(r=16, h=mh);
		}
	}

module motor() {
	mz = bz+1;
	mh = bz+2;

	translate([mx,my,0]) {
		//rotate([180,0,0]) {
			translate([0,0,1]) cylinder(r=15, h=2);
			translate([0,0,1]) cylinder(r=6+2, h=bz-5);
			//}

		}
	translate([0,by-ms,-ms]) cube([ms,ms,ms]);
	}

module bearing() {
	echo("bearing", hx, bor, my, hz, bw, bir);
	translate([hx+bor+boff, my, hz])
	difference() {
		cylinder(r=bor,h=bw, center=true);
		cylinder(r=bir, h=bw+1, center=true);
		}
	}

module bearingHole() {
	echo("bearing hole ", hx, bor, my, hz, bw, bir, clearance);
	translate([hx+bor+boff, my, hz])
		difference() {
			cylinder(r=bor+2*clearance,h=bw+4*clearance, center=true);
			cylinder(r=bir-clearance, h=bw+4*clearance+1, center=true);
			}
	}

module bearingHub() {
	hubGuide = 3.8;
	hgOffset = 2.5;
	translate([hx+bor+boff, my, bz/2])
		cylinder(r=bir-clearance, h=midW-2*clearance, center=true);
	difference() {
		union() {
			translate([hx+bor+boff, my, hz]) {
				translate([0,0,bw/2+(bor-bir)/2]) {
					cylinder(r1=(bir+bor)/2, r2=bir-clearance, h=(bor-bir), center=true);
					translate([0,0,hgOffset])
						cylinder(r1=(bir+bor)/2+hubGuide, r2=bir-clearance, h=(bor-bir)+hubGuide, center=true);
					}
				translate([0,0,-(bw/2+(bor-bir)/2)]) {
					cylinder(r2=(bir+bor)/2, r1=bir-clearance, h=(bor-bir), center=true);
					translate([0,0,-hgOffset])
						cylinder(r2=(bir+bor)/2+hubGuide, r1=bir-clearance, h=(bor-bir)+hubGuide, center=true);
					}
				}
			}
		motor();
		}
	}

module lever(showBearing=0) {
	swing=5;

	difference() {
		union() {
			// slanted/vertical pivot
			translate([hx+bor+2.5, my+by/4, bz/2])
				rotate([0,0,-13]) cube([bor,by/2,midW-2*clearance], center=true);
			//top/lever arm
			translate([-ll,by-2*wall,wall+2*clearance])
				cube([bx*.7+ll, 3*wall, midW-2*clearance]);
			// stick down to cover open area
			translate([wall*2.5+2*clearance,by-2.5*wall,bz/2])
				cube([wall,2*wall,midW-2*clearance],center=true);
			}
		translate([-ll,by-.1+wall,wall+clearance-1])
			cube([bx+ll, 2*wall, midW+2]);
		bearingHole();
		translate([sx1,sy2,-1]) cylinder(r=sr+2*clearance, h=bz+2);
		translate([sx1,sy2+swing,-1]) cylinder(r=sr+2*clearance, h=bz+2);
		translate([sx1-sr-2*clearance,sy2,-1])
			cube([2*(sr+2*clearance),swing,bz+2]);
		filamentHole();
		screws();
		springHole();
		}
	bearingHub();
	//translate([0,by-wall,wall+clearance]) cube([bx*.7, wall, midW]);
	if (showBearing) color("yellow") bearing();
	}

// lever rotated to allow filament to enter
module rotLever(showBearing=0) {
	translate([sx2, sy2, 0]) rotate([0,0,la]) translate([-sx2, -sy2, 0]) lever(showBearing);
	}

// hole into which lever fits
module leverHole() {
	echo("lever hole ", hx, bor, my, hz, bx, by, midW);
	translate([mx, sy1+0.5, wall+clearance])
		cube([bx-15,(by+5)/2,midW]);
	translate([2-ll,by-2*wall-clearance,wall+clearance])
		cube([bx*.7+clearance+2+ll, 2*wall+2*clearance, midW]);
	translate([sx2, sy2, 0]) rotate([0,0,la]) translate([-sx2, -sy2, 0])
		translate([-11,by-2*wall-clearance,wall+clearance])
			cube([bx*.7+clearance+2+11, 2*wall+10, midW]);
	}

module box() {
	cube([bx,by,bz]);
	}

module spring() {
	translate([4, by/2+wall+.5,bz/2]) rotate([-90,0,0])
		cylinder(r=springR-clearance, h=18-2*clearance, center = true);
	}

module springHole() {
	translate([4, by/2+wall+2.5,bz/2]) rotate([-90,0,0])
		cylinder(r=springR, h=springH, center = true);
	}

module springHolder() {
	translate([4, by/2+wall,bz/2]) rotate([-90,0,0])
		cylinder(r=3+wall/2, h=springH+2+2, center = true);
	}

module holes() {
	screws();
	fanScrews();
	hotend();
	difference() {
		motorHole();
		springHolder();
		}
	filamentHole();
	leverHole();
	springHole();
	ventHole();
	ventHole2();
	}

module filament () {
	translate([hx,hy,hz]) rotate([90,0,0]) cylinder(r=1.75/2,h=2*by,center=true);
	}

module filamentHole() {
	translate([hx,hy,hz]) rotate([90,0,0]) cylinder(r=1.75/2+2,h=2*by,center=true);
	}

module assembled(tilt=0) {
	//color("yellow") translate([0,0,clearance]) LBackHanging();
	//color("orange") LFrontHanging();
	//color("green") BFrontHanging();
	//translate([0,0,clearance]) Bback();
	extruderBody();
	//%motor();
	color("red") filament();
	color("grey") screws();
	color("grey") spring();
	//%fan();
	if (tilt==1) rotLever(1);
	if (tilt==0) lever(1);
	vent1();
	//http://www.fabric8r.com/forums/showthread.php?1323-Replacement-extruder/page10
	//color("blue") vent2(); // merged into fanVent
	fanVent();
	color("black") hotend();
	}

module extruderBody() {
	difference() {
		box();
		holes();
		}
	}

module backShape() {
	splitZ = hz;
	translate([-bx/2,-1,-1]) cube([bx*2,by+2,splitZ+1]);
	for (x=[sx1,sx2]) {
		for (y=[sy1,sy2]) {
			//translate([x,y,splitZ]) cylinder(r=3,h=2, center=true);
			}
		}
	translate([(sx1+sx2)/2,sy2,hz]) rotate([0,90,0])
		cylinder(r=1.5, h=1.5*bx, $fn=8, center=true);
	translate([(sx1+sx2)/2,sy1/2,hz]) rotate([0,90,0])
		cylinder(r=1.5, h=1.5*bx, $fn=8, center=true);
	translate([sx2,by/2,hz]) rotate([0,90,90])
		cylinder(r=1.5, h=by+2, $fn=8, center=true);
	translate([bx-wall,sy2,hz]) rotate([0,90,90])
		cylinder(r=1.5, h=2*by, $fn=8, center=true);
	}

module Bback() {
	intersection() {
		extruderBody();
		backShape();
		}
	}

module Bfront() {
	translate([0,by,bz]) rotate([180,0,0]) BFrontHanging();
	}

module BFrontHanging() {
	difference() {
		extruderBody();
		backShape();
		}
	}

module Bplate() {
	Bfront();
	translate([0,by+5,0]) Bback();
	}

module Lback() {
	translate([0,0,-wall-clearance]) LBackHanging();
	}

module LBackHanging() {
	intersection() {
		lever();
		backShape();
		}
	}

module Lfront() {
	translate([0,by,bz-wall-clearance-clearance]) rotate([180,0,0])
		LFrontHanging();
	}

module LFrontHanging() {
	difference() {
		lever();
		backShape();
		}
	}

module Lplate() {
	Lfront();
	translate([0,by+5,-clearance]) Lback();
	}

module allPlated() {
	Bplate();
	translate([bx+30,0,0]) Lplate();
	translate([145,-10,0]) rotate([0,0,90]) ventPlate();
	translate([bx+vr*12-17,by-3,vr-1.6]) rotate([0,0,90]) fanVentPlated();
	}

if (part==0) assembled(0); // no tilt
if (part==1) assembled(1); // tilt
if (part==2) extruderBody();
if (part==3) lever();
if (part==4) Bback();
if (part==5) Bfront();
if (part==6) Bplate();
if (part==7) Lback();
if (part==8) Lfront();
if (part==9) Lplate();
if (part==10) ventPlate();
if (part==11) fanVentPlated();
if (part==12) allPlated();
if (part==13) {
	//extruderBody();
	lever();
	%motor();
	}

```


[User]
Hey! I'm looking to create some parametric Minecraft tools in OpenSCAD, and I'd like your help designing the code.

Basically, I want to be able to generate a pickaxe, sword, axe, or shovel, or all of them at once, based on a single parameter. I'd also like to control the size of the individual "blocks" that make up the tools, and whether the top of the blocks are drawn with a slight bevel or just as plain cubes.

Here's what I'm thinking in terms of parameters:

*   `PART`: A string parameter that specifies which tool to draw. It should accept values like "Pickaxe", "Sword", "Axe", "Shovel", or "All".
*   `BLOCK_SIZE`: A numerical parameter to control the size of the individual blocks (in millimeters).
*   `STYLE`: A string parameter to choose the block style. It should accept "Fancy" for beveled tops and "Plain" for regular cubes.

The tools themselves should be constructed from a combination of cubes and, in some cases, rectangular handles.

Here's a breakdown of each tool's structure:

*   **Pickaxe:** A handle followed by a blade made of blocks. The blade should have a symmetrical shape, extending both horizontally and vertically from the handle.
*   **Sword:** A long handle with a short blade extending vertically with a widening design at the tip of the blade.
*   **Axe:** A handle with a blade that extends horizontally on either side.
*   **Shovel:** A handle with a flat blade made of blocks.

When `PART` is "All", all four tools should be generated, each rotated and translated so that they don't overlap.

For the "Fancy" block style, each block should have a small chamfer or bevel at the top edge. For "Plain" blocks, they should just be basic cubes.

I think it would be best to implement a helper `block()` module, a `handle()` module, and then a `pickaxe_blade()` module for the pickaxe specifically. I'll also need a function `b(x)` to handle the translation of elements by a given number of blocks and a `manifold(x)` function to do very small corrections to object sizes.

I'm not using any external libraries, so everything should be in a single `.scad` file.

Can you generate the necessary OpenSCAD code for me?

[Assistant]
Minecraft_Tools.scad:
```
//
// Minecraft Tools v1.00
// (c) 2014 IronCreek Software
//
// This work is licensed under the Creative Commons
// Attribution-ShareAlike 4.0 International License.
// To view a copy of this license, visit
// http://creativecommons.org/licenses/by-sa/4.0/.
//

/* --- PARAMETERS --------------------------------------------- */

// Which tool do you want to draw?
PART = "All"; // [All, Pickaxe, Sword, Axe, Shovel]

// How big should a single "block" be (in mm)?
BLOCK_SIZE = 2.5;

// How to draw the top of the tool
STYLE = "Fancy"; // [Fancy, Plain]

/* --- IMPLEMENTATION ----------------------------------------- */

tools();

module tools()
{
    if (PART == "Pickaxe") pickaxe();
    else if (PART == "Sword") sword();
    else if (PART == "Axe") axe();
    else if (PART == "Shovel") shovel();
    else all();
}

module all()
{
    translate([b(1), b(1), 0]) pickaxe();
    rotate([0, 0, 90]) translate([b(1), b(1), 0]) sword();
    rotate([0, 0, 180]) translate([b(1), b(1), 0]) axe();
    rotate([0, 0, 270]) translate([b(1), b(1), 0]) shovel();
}

module shovel()
{
    translate([b(1), b(1), 0]) handle(11);
    translate([b(1), b(0), 0]) block();
    translate([b(0), b(1), 0]) block();
    translate([b(2), b(0), 0]) block();
    translate([b(0), b(2), 0]) block();
    translate([b(8), b(7), 0]) handle(5);
    translate([b(7), b(8), 0]) handle(5);
    for (i = [0 : 3])
    {
        translate([b(6+i), b(9+i), 0]) block();
        translate([b(9+i), b(6+i), 0]) block();
    }
}

module axe()
{
    handle(11);
    translate([b(12), b(7), 0]) rotate([0, 0, 90]) handle(6);
    translate([b(11), b(6), 0]) rotate([0, 0, 90]) handle(6);
    translate([b(4), b(9), 0]) handle(5);
    translate([b(5), b(8), 0]) handle(5);
}

module sword()
{
    handle(16);
    translate([b(10), b(2), 0]) rotate([0, 0, 90]) handle(8);
    translate([b(0), b(2), 0]) block();
    translate([b(2), b(0), 0]) block();
    translate([b(3), b(6), 0]) block();
    translate([b(6), b(3), 0]) block();
    for (i = [0 : 7])
    {
        translate([b(8+i), b(6+i), 0]) block();
        translate([b(6+i), b(8+i), 0]) block();
    }
}

module pickaxe()
{
    handle(12);
    translate([b(10), b(3), 0]) pickaxe_blade();
    translate([b(10), b(10), 0]) rotate([0, 0, 90]) pickaxe_blade();
}

module pickaxe_blade()
{
    for (i = [0 : 6])
    {
        translate([b(1), b(i), 0]) block();
        if (i > 0 && i < 6)
        {
            translate([0, b(i), 0]) block();
            translate([b(2), b(i), 0]) block();
        }
    }

}
module handle(length)
{
    for (z = [0 : length-2])
    {
        translate([b(z), b(z), 0]) block();
        translate([b(z+1), b(z), 0]) block();
        translate([b(z), b(z+1), 0]) block();
    }
    translate([b(length-1), b(length-1), 0]) block();
}

module block()
{
    trim = BLOCK_SIZE * 0.1;
    if (STYLE == "Fancy")
    {
        hull()
        {
            cube([manifold(BLOCK_SIZE), manifold(BLOCK_SIZE), BLOCK_SIZE-trim]);
            translate([trim/2, trim/2, 0]) cube([BLOCK_SIZE-trim, BLOCK_SIZE-trim, BLOCK_SIZE]);
        }
    } else {
        cube([manifold(BLOCK_SIZE), manifold(BLOCK_SIZE), BLOCK_SIZE]);
    }
}

function b(x) = x * BLOCK_SIZE;
function manifold(x) = x + 0.02;
```