[User]
I'd like to create a custom parametric fastener generator in OpenSCAD, similar to the provided code, but with some key differences and expansions. I need to be able to create both bolts and nuts with different thread types, not just ISO metric, and I'd like the dimensions to be more flexible and defined by tables. I'd like to use some kind of library for the core functionality, but if that doesn't fit my needs I can write some of the core functions myself.

Here's a breakdown of what I'm looking for:

**Core Functionality:**

*   **Parametric Thread Generation:**  I need to generate external and internal threads, and not just ISO metric. I want to support at least:
    *   ISO Metric (coarse and fine)
    *   Unified National (UNC, UNF, UNEF)
    *   British Standard Whitworth (BSW)
    *   Possibly some Acme or trapezoidal thread support if it can be implemented
*   **Thread Parameter Control:** Each thread type should allow for specification of:
    *   Nominal diameter
    *   Pitch
    *   Thread depth (derived from standard if possible, but also customisable)
    *   Thread length
    *   Thread quality/resolution ($fn) - similar to current functionality

*   **Hex Head/Nut Generation:** I need to generate hex heads for bolts and hex bodies for nuts. The hex dimensions should also be table-driven and configurable per thread standard. I want to be able to pick my standards (e.g. DIN, ANSI, etc), or provide custom values.
 *   **Bolt Head Parameters:**
      *   Head diameter
      *   Head height
  * **Nut Body Parameters:**
      * Nut diameter
      * Nut height
*   **Chamfers:** Allow for chamfers on the top/bottom of both the bolt head and nut body

**High-Level Features:**

*   **Arrays:** Ability to easily generate arrays of bolts or nuts, as in the provided code. The spacing and arrangement of these arrays should be configurable.
*   **Multiple instances:** Allow multiple instances of bolts and nuts with different parameters to be placed in the same design.
*   **Material definitions:** A material definition system for easy specification of colour, transparency and other settings.

**Library Usage:**

*   I'd prefer to build this on top of an existing library if possible. I see in the provided code that there isn't one being used, but I am hoping you might have a recommendation. For example, perhaps BOLTS could be suitable for this, or some other library for generating the basic thread profile?
*   If an appropriate library can't be used for the threads, I think I would prefer the thread generation code to be custom-built rather than use a library for that functionality.
*   I'd like to avoid using more than one library for the primary functionality. I can write some code myself if necessary, I'm comfortable with that.

**Output:**
* I'm hoping to get a single .scad file that encapsulates all of the above functionality in modules.

Let me know what you think, and if you have any questions!

[Assistant]
ISOThreadCust.scad:
```
// ISO Metric Thread Implementation
// Trevor Moseley
// 26/04/2014

// For thread dimensions see
//   http://en.wikipedia.org/wiki/File:ISO_and_UTS_Thread_Dimensions.svg

/* [Global] */

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

// What Wrench (Spanner) sizes?
WrenchSizes = 0;	// [0:Rolson sizes,1:Fairbury sizes]

// Nuts or Bolts?
Type = 0;	// [0:Nuts,1:Bolts]

// What size of metric thread?
Thread = 8;	//[5:100]

// What length of thread (mm)?
Length = 16;	//[5:100]

// How many accross (y)?
Accros = 1;	// [1:20]

// How many down (x)?
Down = 1;	// [1:20]

// Spacing between centres?
Space = 17;	// [5:200]

do_it();

module do_it()
{
	for (ac=[1:Accros])
	{
		for (dn=[1:Down])
		{
			translate([
				-(((Accros-1)*Space)/2)+((ac-1)*Space),
				-(((Down-1)*Space)/2)+((dn-1)*Space),
				0])
			{
				if (Type==0)
					hex_nut(Thread);
				else
					hex_bolt(Thread,Length);
			}
		}
	}
}

//--demo functions--------------------------------------------------------------

//hex_bolt(10,16);						// make an M10 x 16 ISO bolt
//hex_nut(10);							// make an M10 ISO nut
//hex_bolt(8,16);						// make an M8 x 16 ISO bolt
//hex_nut(8);							// make an M8 ISO nut
//hex_bolt(6,12);						// make an M6 x 12 ISO bolt
//hex_nut(6);							// make an M6 ISO nut
//thread_out(8,16);					// make an M8 x 16 ISO thread
//thread_out_centre(8,16);				// make a centre for an M8 x 16 ISO thread
//thread_out_pitch(8,16,1.0);			// make an M8 x 16 thread with 1 mm pitch
//thread_out_centre_pitch(8,16,0.5);	// make the centre for an M8 x 16 thread with 1 mm pitch
//thread_in(8,10);						// make an M8 x 10 ISO thread
//thread_in_ring(8,10,2);				// make a ring to enclose an M8 x 10 ISO thread with thickness 2 mm
//thread_in_pitch(8,10,1.0);			// make an M8 x 10 thread with 1mm pitch

//--pitch-----------------------------------------------------------------------
// function for ISO coarse thread pitch (these are specified by ISO)
function get_coarse_pitch(dia) = lookup(dia, [
[1,0.25],[1.2,0.25],[1.4,0.3],[1.6,0.35],[1.8,0.35],[2,0.4],[2.5,0.45],[3,0.5],[3.5,0.6],[4,0.7],[5,0.8],[6,1],[7,1],[8,1.25],[10,1.5],[12,1.75],[14,2],[16,2],[18,2.5],[20,2.5],[22,2.5],[24,3],[27,3],[30,3.5],[33,3.5],[36,4],[39,4],[42,4.5],[45,4.5],[48,5],[52,5],[56,5.5],[60,5.5],[64,6],[78,5]]);

//--nut dims--------------------------------------------------------------------
// these are NOT specified by ISO
// support is provided for Rolson or Fairbury sizes, see WrenchSizes above

// function for Rolson hex nut diameter from thread size
function rolson_hex_nut_dia(dia) = lookup(dia, [
[3,6.4],[4,8.1],[5,9.2],[6,11.5],[8,16.0],[10,19.6],[12,22.1],[16,27.7],[20,34.6],[24,41.6],[30,53.1],[36,63.5]]);
// function for Rolson hex nut height from thread size
function rolson_hex_nut_hi(dia) = lookup(dia, [
[3,2.4],[4,3.2],[5,4],[6,3],[8,5],[10,5],[12,10],[16,13],[20,16],[24,19],[30,24],[36,29]]);

// function for Fairbury hex nut diameter from thread size
function fairbury_hex_nut_dia(dia) = lookup(dia, [
[3,6.0],[4,7.7],[5,8.8],[6,11.0],[8,14.4],[10,17.8],[12,20.0],[16,26.8],[20,33.0],[24,40.0],[30,50.9],[36,60.8]]);
// function for Fairbury hex nut height from thread size
function fairbury_hex_nut_hi(dia) = lookup(dia, [
[3,2.2],[4,3.0],[5,4.5],[6,5.0],[8,6.5],[10,8.1],[12,10.4],[16,14.2],[20,17],[24,20.3],[30,24.4],[36,29.5]]);

//--bolt dims-------------------------------------------------------------------
// these are NOT specified by ISO
// support is provided for Rolson or Fairbury sizes, see WrenchSizes above

// function for Rolson hex bolt head diameter from thread size
function rolson_hex_bolt_dia(dia) = lookup(dia, [
[3,6.4],[4,8.1],[5,9.2],[6,11.5],[8,14.0],[10,16],[12,22.1],[16,27.7],[20,34.6],[24,41.6],[30,53.1],[36,63.5]]);
// function for Rolson hex bolt head height from thread size
function rolson_hex_bolt_hi(dia) = lookup(dia, [
[3,2.4],[4,3.2],[5,4],[6,3.5],[8,4.5],[10,5],[12,10],[16,13],[20,16],[24,19],[30,24],[36,29]]);

// function for Fairbury hex bolt head diameter from thread size
function fairbury_hex_bolt_dia(dia) = lookup(dia, [
[3,6.4],[4,8.1],[5,8.8],[6,11.1],[8,14.4],[10,17.8],[12,20.1],[16,26.8],[20,33.0],[24,39.6],[30,50.9],[36,60.8]]);
// function for Fairbury hex bolt head height from thread size
function fairbury_hex_bolt_hi(dia) = lookup(dia, [
[3,2.4],[4,3.2],[5,3.4],[6,3.9],[8,5.1],[10,6.2],[12,7.3],[16,9.7],[20,12.2],[24,14.6],[30,17.9],[36,21.7]]);

//--top level modules-----------------------------------------------------------

module hex_bolt(dia,hi)
// make an ISO bolt
//  dia=diameter, 6=M6 etc.
//  hi=length of threaded part of bolt
{
	if (WrenchSizes==0)	rolson_hex_bolt(dia,hi);
	else					fairbury_hex_bolt(dia,hi);
}

module hex_nut(dia,hi)
// make an ISO nut
//  dia=diameter, 6=M6 etc.
{
	if (WrenchSizes==0)	rolson_hex_nut(dia);
	else					fairbury_hex_nut(dia);
}

module thread_out(dia,hi,thr=$fn)
// make an outside ISO thread (as used on a bolt)
//  dia=diameter, 6=M6 etc
//  hi=height, 10=make a 10mm long thread
//  thr=thread quality, 10=make a thread with 10 segments per turn
{
	p = get_coarse_pitch(dia);
	thread_out_pitch(dia,hi,p,thr);
}

module thread_in(dia,hi,thr=$fn)
// make an inside thread (as used on a nut)
//  dia = diameter, 6=M6 etc
//  hi = height, 10=make a 10mm long thread
//  thr = thread quality, 10=make a thread with 10 segments per turn
{
	p = get_coarse_pitch(dia);
	thread_in_pitch(dia,hi,p,thr);
}

module thread_out_pitch(dia,hi,p,thr=$fn)
// make an outside thread (as used on a bolt) with supplied pitch
//  dia=diameter, 6=M6 etc
//  hi=height, 10=make a 10mm long thread
//  p=pitch
//  thr=thread quality, 10=make a thread with 10 segments per turn
{
	h=(cos(30)*p)/8;
	Rmin=(dia/2)-(5*h);	// as wiki Dmin
	s=360/thr;				// length of segment in degrees
	t1=(hi-p)/p;			// number of full turns
	r=t1%1.0;				// length remaining (not full turn)
	t=t1-r;					// integer number of full turns
	n=r/(p/thr);			// number of segments for remainder
	// do full turns
	for(tn=[0:t-1])
		translate([0,0,tn*p])	th_out_turn(dia,p,thr);
	// do remainder
	for(sg=[0:n])
		th_out_pt(Rmin+0.1,p,s,sg+(t*thr),thr,h,p/thr);
}

module thread_in_pitch(dia,hi,p,thr=$fn)
// make an inside thread (as used on a nut)
//  dia = diameter, 6=M6 etc
//  hi = height, 10=make a 10mm long thread
//  p=pitch
//  thr = thread quality, 10=make a thread with 10 segments per turn
{
	h=(cos(30)*p)/8;
	Rmin=(dia/2)-(5*h);	// as wiki Dmin
	s=360/thr;				// length of segment in degrees
	t1=(hi-p)/p;			// number of full turns
	r=t1%1.0;				// length remaining (not full turn)
	t=t1-r;					// integer number of turns
	n=r/(p/thr);			// number of segments for remainder
	for(tn=[0:t-1])
		translate([0,0,tn*p])	th_in_turn(dia,p,thr);
	for(sg=[0:n])
		th_in_pt(Rmin+0.1,p,s,sg+(t*thr),thr,h,p/thr);
}

module thread_out_centre(dia,hi)
{
	p = get_coarse_pitch(dia);
	thread_out_centre_pitch(dia,hi,p);
}

module thread_out_centre_pitch(dia,hi,p)
{
	h = (cos(30)*p)/8;
	Rmin = (dia/2) - (5*h);	// as wiki Dmin
	cylinder(r = Rmin, h = hi);
}

module thread_in_ring(dia,hi,thk)
{
	difference()
	{
		cylinder(r = (dia/2)+0.5,h = hi);
		translate([0,0,-1]) cylinder(r = (dia/2)+0.1, h = hi+thk);
	}
}

//--low level modules-----------------------------------------------------------

module rolson_hex_bolt(dia,hi)
// make an ISO bolt with Rolson wrench sizes
//  dia=diameter, 6=M6 etc.
//  hi=length of threaded part of bolt
{
	hhi = rolson_hex_bolt_hi(dia);
	cylinder(r = rolson_hex_bolt_dia(dia)/2,h = hhi, $fn=6);
	translate([0,0,hhi-0.1])	thread_out(dia,hi+0.1);
	translate([0,0,hhi-0.1])	thread_out_centre(dia,hi+0.1);
}

module fairbury_hex_bolt(dia,hi)
// make an ISO bolt with Fairbury wrench sizes
//  dia=diameter, 6=M6 etc.
//  hi=length of threaded part of bolt
{
	hhi = fairbury_hex_bolt_hi(dia);
	cylinder(r = fairbury_hex_bolt_dia(dia)/2,h = hhi, $fn=6);
	translate([0,0,hhi-0.1])	thread_out(dia,hi+0.1);
	translate([0,0,hhi-0.1])	thread_out_centre(dia,hi+0.1);
}

module rolson_hex_nut(dia)
// make an ISO nut with Rolson wrench sizes
//  dia=diameter, 6=M6 etc.
{
	hi = rolson_hex_nut_hi(dia);
	difference()
	{
		cylinder(r = rolson_hex_nut_dia(dia)/2,h = hi, $fn=6);
		translate([0,0,-0.1])	cylinder(r = dia/2, h =hi + 0.2);
	}
	translate([0,0,0.1])	thread_in(dia,hi-0.2);
}

module fairbury_hex_nut(dia)
// make an ISO nut with Fairbury wrench sizes
//  dia=diameter, 6=M6 etc.
{
	hi = fairbury_hex_nut_hi(dia);
	difference()
	{
		cylinder(r = fairbury_hex_nut_dia(dia)/2,h = hi, $fn=6);
		translate([0,0,-0.1])	cylinder(r = dia/2, h =hi + 0.2);
	}
	translate([0,0,0.1])	thread_in(dia,hi-0.2);
}

module th_out_turn(dia,p,thr=$fn)
// make a single turn of an outside thread
//  dia=diameter, 6=M6 etc
//  p=pitch
//  thr=thread quality, 10=make a thread with 10 segments per turn
{
	h = (cos(30)*p)/8;
	Rmin = (dia/2) - (5*h);	// as wiki Dmin
	s = 360/thr;
	for(sg=[0:thr-1])
		th_out_pt(Rmin+0.1,p,s,sg,thr,h,p/thr);
}

module th_out_pt(rt,p,s,sg,thr,h,sh)
// make a part of an outside thread (single segment)
//  rt = radius of thread (nearest centre)
//  p = pitch
//  s = segment length (degrees)
//  sg = segment number
//  thr = segments in circumference
//  h = ISO h of thread / 8
//  sh = segment height (z)
{
	as = (sg % thr) * s;			// angle to start of seg
	ae = as + s  - (s/100);		// angle to end of seg (with overlap)
	z = sh*sg;
	//pp = p/2;
	//   1,4
	//   |\
	//   | \  2,5
 	//   | /
	//   |/
	//   0,3
	//  view from front (x & z) extruded in y by sg
	//
	//echo(str("as=",as,", ae=",ae," z=",z));
	polyhedron(
		points = [
			[cos(as)*rt,sin(as)*rt,z],								// 0
			[cos(as)*rt,sin(as)*rt,z+(3/4*p)],						// 1
			[cos(as)*(rt+(5*h)),sin(as)*(rt+(5*h)),z+(3/8*p)],		// 2
			[cos(ae)*rt,sin(ae)*rt,z+sh],							// 3
			[cos(ae)*rt,sin(ae)*rt,z+(3/4*p)+sh],					// 4
			[cos(ae)*(rt+(5*h)),sin(ae)*(rt+(5*h)),z+sh+(3/8*p)]],	// 5
		triangles = [
			[0,1,2],			// near face
			[3,5,4],			// far face
			[0,3,4],[0,4,1],	// left face
			[0,5,3],[0,2,5],	// bottom face
			[1,4,5],[1,5,2]]);	// top face
}

module th_in_turn(dia,p,thr=$fn)
// make an single turn of an inside thread
//  dia = diameter, 6=M6 etc
//  p=pitch
//  thr = thread quality, 10=make a thread with 10 segments per turn
{
	h = (cos(30)*p)/8;
	Rmin = (dia/2) - (5*h);	// as wiki Dmin
	s = 360/thr;
	for(sg=[0:thr-1])
		th_in_pt(Rmin+0.1,p,s,sg,thr,h,p/thr);
}

module th_in_pt(rt,p,s,sg,thr,h,sh)
// make a part of an inside thread (single segment)
//  rt = radius of thread (nearest centre)
//  p = pitch
//  s = segment length (degrees)
//  sg = segment number
//  thr = segments in circumference
//  h = ISO h of thread / 8
//  sh = segment height (z)
{
	as = ((sg % thr) * s - 180);	// angle to start of seg
	ae = as + s -(s/100);		// angle to end of seg (with overlap)
	z = sh*sg;
	pp = p/2;
	//         2,5
	//          /|
	//     1,4 / |
 	//         \ |
	//          \|
	//         0,3
	//  view from front (x & z) extruded in y by sg
	//
	polyhedron(
		points = [
			[cos(as)*(rt+(5*h)),sin(as)*(rt+(5*h)),z],				//0
			[cos(as)*rt,sin(as)*rt,z+(3/8*p)],						//1
			[cos(as)*(rt+(5*h)),sin(as)*(rt+(5*h)),z+(3/4*p)],		//2
			[cos(ae)*(rt+(5*h)),sin(ae)*(rt+(5*h)),z+sh],			//3
			[cos(ae)*rt,sin(ae)*rt,z+(3/8*p)+sh],					//4
			[cos(ae)*(rt+(5*h)),sin(ae)*(rt+(5*h)),z+(3/4*p)+sh]],	//5
		triangles = [
			[0,1,2],			// near face
			[3,5,4],			// far face
			[0,3,4],[0,4,1],	// left face
			[0,5,3],[0,2,5],	// bottom face
			[1,4,5],[1,5,2]]);	// top face
}

```


[User]
I need an OpenSCAD design for a customizable can lid, specifically for dog food cans. I'd like the design to be parametric so I can easily adjust it for different can sizes.

Here are the key features and parameters I have in mind:

*   **Can Diameter:** The design should accommodate different can diameters, including the top rim. This needs to be a customizable parameter I can easily adjust.
*   **Rim Height:** The height of the can's rim also needs to be adjustable.
*   **Rim Thickness:** The thickness of the rim needs to be a parameter as well.
*   **Lid Wall Thickness:** I need to be able to control the thickness of the main lid wall itself.
*   **Smoothness:** The design should have a smoothness parameter to control the number of facets used in the curves.

I'm envisioning a lid that fits snugly over the top of the can, with a lip that hooks onto the rim. I'd like a fairly clean and simple design.

I'm not sure if you need more information; let me know if you do. I'm excited to see what you can do! I don't have any existing code, so I need you to generate the whole thing for me. I'd prefer it if you didn't use any external libraries or dependencies for this. Let's keep it vanilla OpenSCAD for now.

[Assistant]
Customizable_Can_Lid.scad:
```
/* [Global] */
// can diameter including top rim
Diameter_Including_Top_Rim = 75; // [10:200]
// rim height
Rim_Height = 3; //[1:5]
//rim thickness
Rim_Thickness_x_10 = 7; //[0:10]
// lid wall thickness
Lid_Wall_Thickness_x_10 = 15; //[1:50]
Smoothness = 60; //[1:100]

/* [Hidden] */
smooth=Smoothness;
wt=Lid_Wall_Thickness_x_10/10.0;
rimd = Rim_Thickness_x_10/10.0;
rimh = Rim_Height;
d = Diameter_Including_Top_Rim;
pad = 0.1;  // Padding to maintain manifold
r = d/2+wt+rimd;
h = rimh + wt*2; // overall lid height

union () {
  difference() {
    cylinder(h,r,r,center=false,$fn=smooth);
    translate([0,0,wt]) cylinder(h,r-wt,r-wt,center=false,$fn=smooth);
  }

  rotate_extrude(convexity=10, $fn = smooth)
    translate([r-wt,h-rimd,0])
    circle(rimd,$fn=smooth);

}

```


[User]
Hey there, I'm looking to get a custom funnel designed for my Storz & Bickel Volcano vaporizer, specifically for the herb chamber. I've got a bit of a problem with herb bits getting stuck around the lip and then getting sucked into the bag – not ideal!

I need a two-stage funnel design, basically two truncated cones stacked on top of each other. The first stage needs to have a larger radius at the bottom, transitioning to a smaller radius at the top. The second stage picks up from where the first stage leaves off, continuing to a yet smaller radius at its own top. I need each cone to be hollow, with a wall thickness that can be adjusted.

Here are the key dimensions that I’d like to be able to control in the file:
*   `r1`: Radius of the bottom of the first cone
*   `r2`: Radius of the top of the first cone / bottom of the second cone
*   `r3`: Radius of the top of the second cone
*   `h1`: Height of the first cone
*   `h2`: Height of the second cone
*   `thickness`: The wall thickness of the funnel

I would also like there to be a minor vertical offset used in the difference() operation of both cones - I'll refer to this as `minor_h_offset`.

I'd like the final design to have a smooth surface, so I think we can set `$fn` to 200 or something similar to accomplish that.

Could you please generate an OpenSCAD file for me that allows me to customize all of these parameters? It should be one file that defines the parameters and renders the funnel. Let me know if you have any questions.

[Assistant]
VolcanoFunnel.scad:
```
r1 = 26;
r2 = 16;
r3 = 11;
h1 = 10;
h2 = 10;
extruder_thickness = .4;
thickness = 2*extruder_thickness;
minor_h_offset = 0.1;
$fn=200;

difference()
{
	cylinder(r1=r1, r2=r2, h=h1);
	translate([0, 0, -minor_h_offset])
		cylinder(r1=r1-thickness, r2=r2-thickness-.15, h=h1+2*minor_h_offset);
}

translate([0, 0, h1]) difference()
{
	cylinder(r1=r2, r2=r3, h=h2);
	translate([0, 0, -minor_h_offset])
		cylinder(r1=r2-thickness, r2=r3-thickness, h=h2+2*minor_h_offset);
}

```


[User]
Hi! I'm looking to create a parametric ring sizer generator in OpenSCAD. I've seen a few out there, but I'd like something that's a bit more flexible. I'm primarily interested in creating three different types of sizers.

First, I'd like to be able to generate individual rings that I can print separately. I need to be able to specify the starting ring size, the number of rings I want, and the increment between the sizes (e.g., 0.5 for half sizes, 1 for consecutive sizes, or 2 for even/odd). The ring's width (along the finger) and the ring's thickness (the radius of the ring) should be customizable too.

Second, I'd like a version that creates all of the rings as a single, solid piece for easier handling. Again, I need all of the same parameters - start size, number of rings, size increment, ring width, and ring thickness.

Third and most importantly, I also need a version that creates a ring sizer, but split it into two halves, like a clamshell. This is essential so people can't get stuck if the sizer is too small. The idea is that you print two halves and then tie them together for use. This version would also need the start size, number of rings, size increment, ring width, and ring thickness parameters.

It's important that the sizing is accurate. I know there's a lookup table for ring sizes (diameters) and some scaling factors that are important for printing, so I'd need to use those. The code I'm starting from defines ring sizes using the lookup table below and scales the result based on a different table. This would have to be included:

```
RING_SIZES =
[
[0,	11.63],
[1,	12.45],
[2,	13.26],
[3,	14.07],
[4,	14.88],
[5,	15.70],
[6,	16.51],
[7,	17.32],
[8,	18.14],
[9,	18.95],
[10,	19.76],
[11,	20.57],
[12,	21.39],
[13,	22.20],
[14,	23.01],
[15,	23.83],
[16,	24.64]
];

RING_SCALING =
[
[6, get_actual_size(6) / get_actual_size(5)],
[15, get_actual_size(15) / get_actual_size(13.75)],
];
```

The code uses functions to perform these lookups:

```
function get_actual_size(s) = lookup(s, RING_SIZES);
function get_scaling(s) = lookup(s, RING_SCALING);
function get_size(s) = get_actual_size(s) * get_scaling(s);
```

I would also like each of the split pieces to have a small post on each side of the sizer so that they can be tied together with twist ties or rubber bands.

I don't have any specific library requirements.  I'm hoping you can generate the necessary code for all of this. Let me know if you have questions!

[Assistant]
ringsizer.scad:
```
// This tool allows you to create jewelry-makers' ring sizers in:
//	1) Individual rings
//	2) A single solid set of rings.
//	3) A set of rings split down the middle so people don't get stuck.
//
// This file resides on thingiverse at:
//    ...
//
// Released under BSD(cc) licence:
//    http://opensource.org/licenses/bsd-license.php
//
// Based on OpenSCAD ring sizing script.
// by, Christopher "ScribbleJ" Jansen
// Available from:
//    http://www.thingiverse.com/thing:7210

//CUSTOMIZER VARIABLES

/* [Main] */

// What to create
generate=2; // [0:separate sizing rings,1:combinded ring tool,2:split-apart ring tool that so you don't get stuck]

// The size of the first ring to create
first_ring_size=4;

// How many rings to create
num_rings=5;

// Spacing between ring sizes (eg 0.5 for half sizes, 2 for odd or even sizes only)
ring_size_incriment=2;

/* [Ring Feel] */

// set ring_w to width of ring.
ring_w = 8;

// ring_thick = radius of ring
ring_thick = 2;

/* [Hidden] */

use<write/Write.scad>

// Stolen from Wikipedia.
RING_SIZES =
[
[0,	11.63],
[1,	12.45],
[2,	13.26],
[3,	14.07],
[4,	14.88],
[5,	15.70],
[6,	16.51],
[7,	17.32],
[8,	18.14],
[9,	18.95],
[10,	19.76],
[11,	20.57],
[12,	21.39],
[13,	22.20],
[14,	23.01],
[15,	23.83],
[16,	24.64]
];
function get_actual_size(s) = lookup(s, RING_SIZES);

// Ring scaling.  Two data points provided by Worksofman.
// 6 = 1 size too small.
// 15 = 1.25 too small.
// Openscad will interpolate
RING_SCALING =
[
[6, get_actual_size(6) / get_actual_size(5)],
[15, get_actual_size(15) / get_actual_size(13.75)],
];
function get_scaling(s) = lookup(s, RING_SCALING);
function get_size(s) = get_actual_size(s) * get_scaling(s);

if (generate==0)
{
	separate_rings();
}else{
	if(generate==1){
		ring_guage();
	}else{
		ring_gauge_split();
	}
}

module post(){
	translate([0,-2,-ring_w/2]) union() {
		cube([5,2,ring_w]);
		translate([4,-2,0]) cube([2,4,ring_w]);
	}
}

module ring_gauge_split()
{
	max_ring_dia=get_size(first_ring_size+(num_rings*ring_size_incriment));
	difference() {
		ring_guage(posts=true);
		translate([-max_ring_dia,0,-ring_w/2]) cube([max_ring_dia*(num_rings+2),max_ring_dia+ring_thick,ring_w+2]);
}
}

// recursively-generated ring guage
module ring_guage(posts=false,i=0,pos=0) {
	size=first_ring_size+(i*ring_size_incriment);
	if(i==0&&posts){
		translate([-get_size(first_ring_size)/2,0,0]) rotate([0,180,0]) post();
	}
	if(i<num_rings){
		union() {
			translate([pos, 0, 0]) ring(size);
			ring_guage(posts,i+1,pos+get_size(size)+(ring_thick*1.5));
		}
	}else{
		if(posts){
			translate([pos-(get_size(size)/2)-ring_thick,0,0]) post();
		}
	}
}

module separate_rings() {
	rings_per_row=sqrt(num_rings);
	max_ring_dia=get_size(first_ring_size+(num_rings*ring_size_incriment));
	ring_space=max_ring_dia+2;
	row=0;
	col=0;
	for(i = [0:num_rings - 1])
	{
		assign(row = floor(i / rings_per_row)) {
			assign(col  = i % rings_per_row) {
				assign(size=first_ring_size+(i*ring_size_incriment)){
				echo(str("Ring: ", i,
					" Row: ", row,
					" Col: ", col,
					" Size: ", size,
					" ID(ref): ", get_actual_size(size),
					" ID(actual): ", get_size(size)
				));
				translate([ring_space * row, ring_space * col, 0]) ring(size);
}
			}
		}
	}
}

module ring(size = 0)
{
	difference()
	{
		cylinder(h=ring_w, r=(get_size(size)/2) + ring_thick, center=true);
		ringhole(size);
	}

}

module ringhole(size = 0)
{
	polyhole(h=ring_w * 2, d=get_size(size), center=true);
}

// polyhole code from http://hydraraptor.blogspot.com/2011/02/polyholes.html
module polyhole(h, d, center=false) {
    n = max(round(2 * d),3);
    rotate([0,0,180])
        cylinder(h = h, r = (d / 2) / cos (180 / n), center=center, $fn = n);
}

```


[User]
I need a parametric OpenSCAD design for a phone holder that clips onto something, like the handle of a treadmill. It's going to print on its side, and I'd like the clip part to have a bit of a curve, so it doesn't need supports. Think of it as a long, thin cup with a hooked part at the back.

Here's what I'm thinking for parameters:

*   `hook_gap`: The space between the back of the "cup" and the start of the hook.
*   `hook_height`: How tall the hook part of the clip is.
*   `overall_length`: The total length of the holder. This should be at least 18.

The "cup" part should have rounded corners. It should be able to hold a phone securely. The base of the cup should be solid, and the hook should be integrated into the structure for strength. I'd also like to make sure that the edges of the hole in the cup are curved, so it prints nicely without supports.

[Assistant]
HolderCup.scad:
```

//CUSTOMIZER VARIABLES

// space between back of cup and beginning of hook
hook_gap=15;

// height of hook clip
hook_height=3;

// total length of part (minimum 18)
overall_length=78;

//CUSTOMIZER VARIABLES END

translate([0,-23+hook_gap,0])
rotate([0,-90,0])
union() {
 difference() {
  translate([0,23-hook_gap,0]) cube([overall_length,7+hook_gap,50]);
  translate([-0.1,22.9-hook_gap,-0.1]) cube([overall_length+0.2,3.2,46-hook_height]);
  translate([-0.1,26-hook_gap,-0.1]) cube([overall_length+0.2,hook_gap,46]);
 }
 difference() {
  translate([0,30,0]) cube([overall_length,18,50]);
  translate([9,31,1]) cube([overall_length-18,16,49.1]);
  translate([9,39,1]) cylinder(r=8, h=49.1, $fn=50);
  translate([overall_length-9,39,1]) cylinder(r=8, h=49.1, $fn=50);
 }
}

//44.27
```


[User]
Hey, I'm looking for an OpenSCAD model for a coaster. I have a bunch of small, square stone tiles that I want to use as the inset. The coaster should be a rounded rectangle with an inset area that's also a rounded rectangle. I'd also like an option to put small circular holes on the bottom for little rubber feet.

Here are the parameters I'd like to be able to adjust through the customizer:

*   `coaster_size_x`: Overall width of the coaster.
*   `coaster_size_y`: Overall length of the coaster.
*   `coaster_height`: Overall height of the coaster.
*   `coaster_corner_r`: Radius of the rounded corners of the coaster.
*   `inset_size_x`: Width of the inset for the tile.
*   `inset_size_y`: Length of the inset for the tile.
*   `inset_height`: Height of the inset (or how deep the tile sits in the coaster).
*   `do_feet`: A boolean option (0 for no, 1 for yes) to enable/disable the foot holes.
*   `feet_height_div2`: Half the height of the foot holes.
*    `feet_radius`: The radius of the foot holes.

I'd like the overall coaster to be a rounded rectangle and the inset cutout to also be a rounded rectangle (so the corners in the inset mirror the corners of the coaster.)

If `do_feet` is enabled, I want four circular holes at the corners on the bottom, suitable for inserting small rubber or cork feet.

Could you help me create this in OpenSCAD? I don't have any of the supporting libraries, so any necessary ones you use would need to be included in your response. I'm not particular about any specific libraries, but if you have a good recommendation I'm open to it!

[Assistant]
coasterInset.scad:
```

//CUSTOMIZER VARIABLES

// width of coaster
coaster_size_x=90;

// length of coaster
coaster_size_y=90;

// height of coaster
coaster_height=15;

// radius of coaster corner
coaster_corner_r=6;

// widith of hole
inset_size_x=74.5;

// length of hole
inset_size_y=75.5;

// height of hole
inset_height=3.8;

// make little holes in bottom for inserting rubber feet or cork circles
do_feet = 0; // [0:no, 1:yes]

// height of foot hole divided by two
feet_height_div2=3.2;

// radius of foot hole
feet_radius=3.5;

//CUSTOMIZER VARIABLES END

module roundedRect(size, radius)
{
x = size[0];
y = size[1];
z = size[2];

linear_extrude(height=z)
//union()
hull()
{
// place 4 circles in the corners, with the given radius
translate([(-x/2)+(radius), (-y/2)+(radius), 0])
circle(r=radius,$fn=50);

translate([(x/2)-(radius), (-y/2)+(radius), 0])
circle(r=radius,$fn=50);

translate([(-x/2)+(radius), (y/2)-(radius), 0])
circle(r=radius,$fn=50);

translate([(x/2)-(radius), (y/2)-(radius), 0])
circle(r=radius,$fn=50);
}
}

difference() {
roundedRect([coaster_size_x,coaster_size_y,coaster_height],coaster_corner_r);
translate([-inset_size_x/2,-inset_size_y/2,inset_height]) cube(size=[inset_size_x,inset_size_y,coaster_height]);

if (do_feet) {
translate([coaster_size_x*3.4/8,coaster_size_y*3.4/8,-0.1]) cylinder(r=feet_radius,h=feet_height_div2,$fn=50);
translate([-coaster_size_x*3.4/8,coaster_size_y*3.4/8,-0.1]) cylinder(r=feet_radius,h=feet_height_div2,$fn=50);
translate([coaster_size_x*3.4/8,-coaster_size_y*3.4/8,-0.1]) cylinder(r=feet_radius,h=feet_height_div2,$fn=50);
translate([-coaster_size_x*3.4/8,-coaster_size_y*3.4/8,-0.1]) cylinder(r=feet_radius,h=feet_height_div2,$fn=50);
}
}

```


[User]
Okay, so I'm looking to create a tool for leveling coffee grounds in an espresso portafilter, and I want it to be parametric so I can easily adjust it for different portafilter sizes and depths. I've seen some designs using a yin-yang shaped wiper, and I really like that idea, where rotating one way pushes the grounds towards the center, and the other way pushes them outwards.

Here’s the basic concept:

It'll be a cylindrical base that sits on top of the portafilter rim. Then, there will be a central column attached to the base. From this base, two yin-yang shaped wipers will extend down into the portafilter. These wipers should reach some specified distance into the portafilter. The wipers need a specific thickness so they can actually move the grounds.

I need the design to be fully parametric, so I can adjust:

*   **Portafilter Outside Diameter:** This sets the size of the outer cylinder that rests on the portafilter rim.
*   **Portafilter Inside Diameter:** This will determine the diameter for the inner cylinders and wipers.
*   **Reach Into Portafilter:** This sets how far down the wipers extend into the portafilter.
*   **Outside Wall Height:** This sets the height of the top cylinder that sits on the portafilter.
*   **Wiper Thickness:** This sets how thick the wiping part is.
*   **Clearance:** An overall clearance value.

I would like to generate the scad files from scratch, and will need code that includes these parameters. Can you do that for me? I don't need code for a GUI, but I would like to see a preview. I think the only libraries I need are built in to OpenSCAD, but please let me know if I'm wrong.

[Assistant]
Yin_Yang_v6.scad:
```
/* [Global] */
Porta_Filter_Outside_Diameter = 71; // [10:150]
Porta_Filter_Inside_Diameter = 60; //[10:150]
Reach_Into_Porta_Filter_x_10 = 24; //[0:100]
Outside_Wall_Height_x_10 = 36; //[0:100]
/* [Hidden] */
Clearance = 0.5;
Smoothness=40;
pf_r = Porta_Filter_Outside_Diameter/2;
circle_thickness = 3;
support_height=6;
tab_height=Outside_Wall_Height_x_10/10;
central_column_h = 5;
central_column_r = 1.5;

wiper_height = support_height+Reach_Into_Porta_Filter_x_10/10;
wiper_thickness = 1.8;

union(){

difference(){
	cylinder(h=support_height+tab_height,r=pf_r+circle_thickness+Clearance,$fn=Smoothness);//outer
	cylinder(h=support_height+tab_height,r=pf_r+Clearance,$fn=Smoothness);//inner
}
difference(){
	cylinder(h=support_height,r=pf_r+Clearance+0.1,$fn=Smoothness);//inner
	cylinder(h=support_height,r=pf_r-circle_thickness,$fn=Smoothness);//outer
}

intersection(){
union(){
cylinder(h=wiper_height,r=Porta_Filter_Inside_Diameter/2-Clearance,$fn=Smoothness);//inner
cylinder(h=support_height,r=pf_r-circle_thickness+0.01,$fn=Smoothness);//inner

}
union(){
translate([-Porta_Filter_Inside_Diameter/2+wiper_thickness/2,0,0])difference(){
	cylinder(h=wiper_height,r=Porta_Filter_Inside_Diameter/2,$fn=Smoothness);//inner
	cylinder(h=wiper_height,r=Porta_Filter_Inside_Diameter/2-wiper_thickness,$fn=Smoothness);//outer
	//translate([Porta_Filter_Outside_Diameter*2,0,0])cube([Porta_Filter_Outside_Diameter*4,Porta_Filter_Outside_Diameter*4,support_height*4],center=true);
	translate([0,-Porta_Filter_Outside_Diameter*2+0.01,0])cube([Porta_Filter_Outside_Diameter*4,Porta_Filter_Outside_Diameter*4,wiper_height*4],center=true);
}
translate([Porta_Filter_Inside_Diameter/2-wiper_thickness/2,0,0])difference(){
	cylinder(h=wiper_height,r=Porta_Filter_Inside_Diameter/2,$fn=Smoothness);//inner
	cylinder(h=wiper_height,r=Porta_Filter_Inside_Diameter/2-wiper_thickness,$fn=Smoothness);//outer
	//translate([Porta_Filter_Outside_Diameter*2,0,0])cube([Porta_Filter_Outside_Diameter*4,Porta_Filter_Outside_Diameter*4,support_height*4],center=true);
	translate([0,Porta_Filter_Outside_Diameter*2-0.01,0])cube([Porta_Filter_Outside_Diameter*4,Porta_Filter_Outside_Diameter*4,wiper_height*4],center=true);
}
}
}
}

```


[User]
I'm looking to design a customizable coat hook, and I want it to be parametric so I can easily adjust the size and shape. I'd like to be able to control the following:

*   **Overall Knob Dimensions:**
    *   The diameter of the main knob part, with a minimum of 30mm and a maximum of 150mm.
    *   The thickness of the knob, ranging from 5mm to 25mm.
    *   A "roundness percentage" that affects how rounded the knob is - I'd like it to range from 0% (not rounded at all) to 400% (very rounded, almost a sphere). I want this to change the curvature of the knob's outer face, not simply a filleting operation.

*   **Base Dimensions:**
    *   The diameter of the base where it attaches to the wall, from 20mm to 100mm.
    *   The thickness of the base, from 0mm to 25mm.

*   **Screw Mounting:**
    *   I need a recessed screw hole that will hide the screw head when mounted.
    *   The screw head should be about 8.5mm wide, with a small margin to make it fit easily, and should be 3.5mm in diameter for the screw stem.
    *   The hole depth needs to be a variable so I can adjust how deep to recess the screw head but I expect it to be more than the base depth.

*   **Accuracy:**
    *   I'd like a way to control the accuracy/smoothness of curves, perhaps with a multiplier. Something like 1x for less detail and 3x for higher detail would be great.

I'm not particularly concerned with code organization but I will need to maintain it and am happy to get as many modules as appropriate. Ideally, the design should be created in such a way that I can easily change these parameters and the coat hook will update accordingly. The mounting should be strong enough and the screw hole a tight fit, and I want to hide the screw head.

I'd also like it if there was a way to generate the STL files. I'm hoping you can create an OpenSCAD file for me that will do all this. I'm not using any libraries at the moment, but I'm happy to start if needed.

[Assistant]
Customizable_Knob.scad:
```
/* [Basic] */
// Diameter of the knob
knobDia = 50;  // [30:150]
// Thickness of the knob
knobDepth = 12; // [5:25]

// Diameter of the base
baseDia = 36;  // [20:100]
// Thickness of the base
baseDepth = 10; // [0:25]
// How rounded should the knob be?
roundnessPercentage = 65; // [0:400]

/* [Screw] */
// Width of the head (+ a little margin so you can get it in)
screwHead = 8.5;
// Thickness of the stem of the screw
screwDia = 3.5;
// How deep should the screw hole be? (should be > baseDepth)
screwDepth = 8; //

/* [Advanced] */
// Accuracy multiplier, higher = slower = more accuracy
acc = 2; // [1:3]

/* [Hidden] */
roundness = roundnessPercentage / 100;
xTranslate = (knobDia/2)-(knobDepth*roundness/2);
screwDisplacement = baseDia/2 - (1.5*screwHead + 1.5);

// Accuracy multiplier
fnScrew = acc * 16;
fnBase = acc * 60;
fnCircle = acc * 70;
fnExtrude = acc * 100;

module knob() {
	rotate_extrude($fn = fnExtrude) {
		union() {
			translate([xTranslate, knobDepth/2, 0]) scale([roundness, 1,1])
				circle(r = knobDepth/2, $fn= fnCircle);
		}
		square([xTranslate,knobDepth]);
	}
}

module base() {
	difference() {
		cylinder(r = baseDia/2, h = baseDepth + knobDepth/2,$fn = fnBase);
	}
}

module screwHole() {
	cylinder(r = screwHead/2, h = screwDepth,$fn = fnScrew);
	translate([screwHead,0,0]) cylinder(r = screwDia/2, h = screwDepth/2,$fn = fnScrew);
	translate([0,-screwDia/2,0]) cube([screwHead,screwDia,screwDepth/2]);
	intersection() {
		translate([0,0,0]) rotate([45,-5,0]) cube([screwHead*1.6,screwHead*1.5,screwHead*1.5]);
		union() {
			translate([screwHead,0,0]) cylinder(r = screwHead/2, h = screwDepth,$fn = fnScrew);
			translate([0,-screwHead/2,0]) cube([screwHead,screwHead,screwDepth]);
		}
	}
}

module render() {
	translate([0,0,baseDepth+knobDepth]) rotate([180,0,0]){
		difference() {
			union() {
				translate([0,0,baseDepth]) knob();
				base();
			}
			translate([screwDisplacement,0, -0.02]) screwHole();
		}
	}
}

//screwHole();

render();
```


[User]
Okay, I'm looking to design a simple, two-part pencil case that can be assembled without glue. It will have a base and a top part, connected by a rotating rod. I'm planning to 3D print this, and I want to make it parametric so that I can easily adjust the size later.

Here are the core parameters I want to be able to control:

*   `hcoffre`: The overall height of the pencil case. The base will have a different height than the top.
*   `lcoffrex`: The length of the pencil case.
*   `lcoffrey`: The width of the pencil case.
*   `llamey`: The thickness of the material/walls of the pencil case. It's important to keep this consistent for assembly.

Here's how I envision the base and top should look like:

**Base:**

*   A rectangular base with dimensions `lcoffrex` x `lcoffrey` x `llamey`.
*   Side walls of height `hcoffre` (for the base), and `llamey` thickness running along the length on both sides (so two walls).
*   Two cylindrical "supports" for the rotation rod, located at each end and partially embedded in the base with a radius that is half the `lcoffrey`. The support will go along the `llamey` height.
*   Three small supports that also go along the `llamey` height, to support the pencil case standing.
*   A semi-cylindrical opening at both ends, on top of the walls, for the rotation rod.
*   Circular indentations at the top of the walls to act as a guide for the top piece.

**Top:**

*   A rectangular top with dimensions `lcoffrex` x `lcoffrey` x `llamey`. The top should align with the base.
*   Side walls of height `hcoffre` (for the top), and `llamey` thickness running along the length on both sides (so two walls). the `hcoffre` variable is half of the base.
*    Three small supports that also go along the `llamey` height, on the opposite face as the base.
*   A semi-cylindrical opening at both ends of the walls, for the rotation rod.
*   Two spherical features on the side walls that should align with the indentations on the base.
*  A small feature on the front face of the top.

**Rotating Rod (Key):**

*   A simple cylinder that fits inside the semi-cylindrical openings of both the base and top, and which passes through the two sides of the case.

I need the design as separate modules for the base, top and the rotating rod, so that they can be assembled into a complete pencil case. Please provide the code as parametric OpenSCAD files, I would like to be able to change every value. I'm not very experienced with OpenSCAD, so a clear code would be very helpful.

[Assistant]
base.scad:
```
$fn=30;

hcoffre= 50;
lcoffrex= 130;
llamey= 5;
lcoffrey=70;

module base(){

cube([lcoffrex,lcoffrey,llamey]) ;

translate([0,lcoffrey/2+5,0])cylinder(h=llamey,r=lcoffrey/2+5) ;

translate([lcoffrex,lcoffrey/2+5,0])cylinder(h=llamey,r=lcoffrey/2+5) ;

cube([lcoffrex,llamey,hcoffre]) ;

translate([0,lcoffrey,0])cube([lcoffrex,llamey,hcoffre]) ;

difference(){translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2);
translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([0,llamey,0])cube([lcoffrex/2,lcoffrey,hcoffre]); }

difference(){translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2) ;
translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([lcoffrex/2,llamey,0])cube([lcoffrex/2,lcoffrey,hcoffre]); }

union() {translate([0,0,hcoffre])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,hcoffre+5,0])cylinder(h=10,r=llamey/2) ;}

translate([lcoffrex/2-10,0,0])union() {translate([0,0,hcoffre])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,hcoffre+5,0])cylinder(h=10,r=llamey/2) ;}

translate([lcoffrex-10,0,0])union() {translate([0,0,hcoffre])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,hcoffre+5,0])cylinder(h=10,r=llamey/2) ;}

translate([0,lcoffrey/2+llamey/2,0])cylinder(h=llamey,r=lcoffrey/2+10);

translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=llamey,r=lcoffrey/2+10);

difference(){translate([0,lcoffrey/2+llamey/2,hcoffre-llamey])cylinder(h=llamey,r=lcoffrey/2+llamey);
translate([0,lcoffrey/2+5,hcoffre-10])cylinder(h=hcoffre,r=lcoffrey/2) ;translate([0,llamey,hcoffre-10])cube([lcoffrex/2,lcoffrey,hcoffre]); }

difference(){translate([lcoffrex,lcoffrey/2+llamey/2,hcoffre-llamey])cylinder(h=llamey,r=lcoffrey/2+llamey);
translate([lcoffrex,lcoffrey/2+5,hcoffre-10])cylinder(h=hcoffre,r=lcoffrey/2) ;translate([lcoffrex/2,llamey,hcoffre-10])cube([lcoffrex/2,lcoffrey,hcoffre]); }

}
base();

module llave(){
translate([0,llamey/2,hcoffre+5])rotate([90,0,90])cylinder(h=lcoffrex,r=llamey/4);
}
llave();
```
head.scad:
```
$fn=18.5;
hcoffre= 25;
lcoffrex= 130;
llamey= 5;
lcoffrey=70;

module head(coffrex,coffrey,coffrez){

	difference(){union(){difference(){cube([coffrex,llamey,coffrez]) ;
union(){union() {translate([0,0,0])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=12,r=llamey/2) ;}

translate([lcoffrex/2-10,0,0])union() {translate([0,0,0])cube([12,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=12,r=llamey/2) ;}

translate([lcoffrex-10,0,0])union() {translate([0,0,0])cube([12,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=12,r=llamey/2) ;}}}}translate([0,llamey/2,4])rotate([90,0,90])cylinder(h=lcoffrex,r=llamey/4+0.5);translate([0,1.5,0])cube([lcoffrex,2.5,3]);}

translate([0,lcoffrey,0])cube([coffrex,llamey,coffrez]) ;

difference(){	union(){difference(){translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2);
translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([0,llamey,0])cube([lcoffrex/2-15,lcoffrey-llamey,hcoffre]); }}union() {translate([0,0,0])cube([12,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=12,r=llamey/2) ;}}

difference(){	union(){difference(){translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2) ;
translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([lcoffrex/2,llamey,0])cube([lcoffrex/2,lcoffrey-llamey,hcoffre]); }}union(){translate([lcoffrex-10,0,0])union() {translate([0,0,0])cube([12,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=12,r=llamey/2) ;}}}

translate([0,lcoffrey/2+llamey/2,hcoffre])rotate([0,90,0])difference(){cylinder(h=lcoffrex,r=lcoffrey/2+llamey/2);cylinder(h=lcoffrex,r=lcoffrey/2-llamey/2);translate([0,-lcoffrey/2+llamey/2,0])cube([lcoffrey/2+5,lcoffrey-llamey,lcoffrex]);}

translate([llamey/2,0,hcoffre])translate([0,lcoffrey+llamey])rotate([0,0,180])translate([-lcoffrey/2,0,-lcoffrey])difference(){translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey+llamey);cube([lcoffrey+llamey,lcoffrey+llamey,lcoffrey]);cube([lcoffrey/2,lcoffrey+llamey,lcoffrey+lcoffrey/2+llamey]);translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey-llamey);}

translate([lcoffrex-llamey/2,0,hcoffre])translate([-lcoffrey/2,0,-lcoffrey])difference(){translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey+llamey);cube([lcoffrey+llamey,lcoffrey+llamey,lcoffrey]);cube([lcoffrey/2,lcoffrey+llamey,lcoffrey+lcoffrey/2+llamey]);translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey-llamey);}

intersection(){translate([lcoffrex/2-hcoffre/4,lcoffrey+llamey,0])cube([hcoffre/2,llamey,hcoffre]);
translate([lcoffrex/2,lcoffrey+llamey+llamey,hcoffre/2])rotate([90,0,0])cylinder(h=llamey,r=hcoffre/2);}
}

translate([0,0,0])head(lcoffrex,lcoffrey,hcoffre);

```
base+instructions.scad:
```
$fn=30;

//The variables hcoffre, lcoffrex,lcoffrey and llamey represent in the same order: 1) the height of the object 2) the lenght of the object 3) the width of the object 4) the thickness of the object. All values can be changed but it is recommended not to change the "llamey" value for the fonctionnality of the object.

hcoffre= 50;
lcoffrex= 130;
llamey= 5;
lcoffrey=70;

module base(){

//the first part represent the base of the object

cube([lcoffrex,lcoffrey,llamey]) ;

translate([0,lcoffrey/2+5,0])cylinder(h=llamey,r=lcoffrey/2+5) ;

translate([lcoffrex,lcoffrey/2+5,0])cylinder(h=llamey,r=lcoffrey/2+5) ;

//the second part represents the sides of the object

cube([lcoffrex,llamey,hcoffre]) ;

translate([0,lcoffrey,0])cube([lcoffrex,llamey,hcoffre]) ;

difference(){translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2);
translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([0,llamey,0])cube([lcoffrex/2,lcoffrey,hcoffre]); }

difference(){translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2) ;
translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([lcoffrex/2,llamey,0])cube([lcoffrex/2,lcoffrey,hcoffre]); }

//the next part represents the support of the pencil case

union() {translate([0,0,hcoffre])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,hcoffre+5,0])cylinder(h=10,r=llamey/2) ;}

translate([lcoffrex/2-10,0,0])union() {translate([0,0,hcoffre])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,hcoffre+5,0])cylinder(h=10,r=llamey/2) ;}

translate([lcoffrex-10,0,0])union() {translate([0,0,hcoffre])cube([10,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,hcoffre+5,0])cylinder(h=10,r=llamey/2) ;}

translate([0,lcoffrey/2+llamey/2,0])cylinder(h=llamey,r=lcoffrey/2+10);

translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=llamey,r=lcoffrey/2+10);

//the last part of the object represent the support for the rotation rod who will put together both parts of the pencil case

difference(){translate([0,lcoffrey/2+llamey/2,hcoffre-llamey])cylinder(h=llamey,r=lcoffrey/2+llamey);
translate([0,lcoffrey/2+5,hcoffre-10])cylinder(h=hcoffre,r=lcoffrey/2) ;translate([0,llamey,hcoffre-10])cube([lcoffrex/2,lcoffrey,hcoffre]); }

difference(){translate([lcoffrex,lcoffrey/2+llamey/2,hcoffre-llamey])cylinder(h=llamey,r=lcoffrey/2+llamey);
translate([lcoffrex,lcoffrey/2+5,hcoffre-10])cylinder(h=hcoffre,r=lcoffrey/2) ;translate([lcoffrex/2,llamey,hcoffre-10])cube([lcoffrex/2,lcoffrey,hcoffre]); }

}
base();

//the module key represent the rotation rod who will put together both parts of the pencil

module key(){
translate([0,llamey/2,hcoffre+5])rotate([90,0,90])cylinder(h=lcoffrex,r=llamey/4);
}
key();
```
head+instructions.scad:
```
$fn=15;

//The variables hcoffre, lcoffrex,lcoffrey and llamey represent in the same order: 1) the height of the object 2) the lenght of the object 3) the width of the object 4) the thickness of the object. All values can be changed but it is recommended not to change the "llamey" value for the fonctionnality of the object. For this part, it is recommended to use 1/2 of the "hcoffre" value than the one used for the base.

hcoffre= 25;
lcoffrex= 130;
llamey= 5;
lcoffrey=70;

module head(coffrex,coffrey,coffrez){

//the first part of text represents the head's sides (base) of the pencil case

	difference(){union(){difference(){cube([coffrex,llamey,coffrez]) ;
union(){union() {translate([0,0,0])cube([llamey+llamey+2,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=llamey+llamey+2,r=llamey/2) ;}

translate([lcoffrex/2-10,0,0])union() {translate([0,0,0])cube([llamey+llamey+2,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=llamey+llamey+2,r=llamey/2) ;}

translate([lcoffrex-10,0,0])union() {translate([0,0,0])cube([llamey+llamey+2,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=12,r=llamey/2) ;}}}}translate([0,llamey/2,4])rotate([90,0,90])cylinder(h=lcoffrex,r=llamey/4+0.5);translate([0,1.5,0])cube([lcoffrex,2.5,3]);}

translate([0,lcoffrey,0])cube([coffrex,llamey,coffrez]) ;

//the second part of the codes represents the cover of the pencil case

difference(){	union(){difference(){translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2);
translate([0,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([0,llamey,0])cube([lcoffrex/2,lcoffrey-llamey,hcoffre]); }}union() {translate([0,0,0])cube([llamey+llamey+2,llamey,5]) ;

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=llamey+llamey+2,r=llamey/2) ;}}

difference(){	union(){difference(){translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2+llamey/2) ;
translate([lcoffrex,lcoffrey/2+llamey/2,0])cylinder(h=hcoffre,r=lcoffrey/2-llamey/2) ;translate([lcoffrex/2,llamey,0])cube([lcoffrex/2,lcoffrey-llamey,hcoffre]); }}union(){translate([lcoffrex-10,0,0])union() {translate([0,0,0])cube([llamey+llamey+2,llamey,5]);

rotate([90,0,90])translate([llamey/2,llamey,0])cylinder(h=llamey+llamey+2,r=llamey/2) ;}}}

translate([0,lcoffrey/2+llamey/2,hcoffre])rotate([0,90,0])difference(){cylinder(h=lcoffrex,r=lcoffrey/2+llamey/2);cylinder(h=lcoffrex,r=lcoffrey/2-llamey/2);translate([0,-lcoffrey/2+llamey/2,0])cube([lcoffrey/2+5,lcoffrey-llamey,lcoffrex]);}

translate([llamey/2,0,hcoffre])translate([0,lcoffrey+llamey])rotate([0,0,180])translate([-lcoffrey/2,0,-lcoffrey])difference(){translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey+llamey);cube([lcoffrey+llamey,lcoffrey+llamey,lcoffrey]);cube([lcoffrey/2,lcoffrey+llamey,lcoffrey+lcoffrey/2+llamey]);translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey-llamey);}

translate([lcoffrex-llamey/2,0,hcoffre])translate([-lcoffrey/2,0,-lcoffrey])difference(){translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey+llamey);cube([lcoffrey+llamey,lcoffrey+llamey,lcoffrey]);cube([lcoffrey/2,lcoffrey+llamey,lcoffrey+lcoffrey/2+llamey]);translate([lcoffrey/2+llamey/2,lcoffrey/2+llamey/2,lcoffrey])sphere(d=lcoffrey-llamey);}

//the last part of the code represent the badge in front of the pencil case for the chest aesthetics

intersection(){translate([lcoffrex/2-hcoffre/4,lcoffrey+llamey,0])cube([hcoffre/2,llamey,hcoffre]);
translate([lcoffrex/2,lcoffrey+llamey+llamey,hcoffre/2])rotate([90,0,0])cylinder(h=llamey,r=hcoffre/2);}
}

translate([0,0,0])head(lcoffrex,lcoffrey,hcoffre);

```


[User]
I'm looking for an OpenSCAD design that creates a rounded rectangular prism, also known as a rounded rectangular parallelepiped. I'd like to be able to control the overall dimensions (length, width, height), the number of facets used for the rounded corners/edges, and the radius of those rounded edges.

I'd prefer a single module that takes these parameters as input. I want to be able to easily call this module with different values to create different shapes. I'm thinking something like `rounded_cube(size_x, size_y, size_z, facets, rounding_radius)`. Can you generate the code for that, please? I don't need any special external libraries for this, just the standard OpenSCAD language features.

[Assistant]
Rounded_Rectangular_Parallelepiped.scad:
```
// Rounded Rectangular Parallelepiped module - faster than minkowski!
// variables with "customizer" in them are only for the Thingiverse customizer and are not essential.

customizer_x=2;
customizer_y=10;
customizer_z=5;

customizer_facets=16;
customizer_rounding_radius=1;

module rounded_cube(size_x,size_y,size_z,facets,rounding_radius)
{
	hull()
	{
		translate([rounding_radius,        rounding_radius,        rounding_radius]) sphere (r=rounding_radius, $fn=facets);
		translate([size_x-rounding_radius, rounding_radius,        rounding_radius]) sphere (r=rounding_radius, $fn=facets);
		translate([rounding_radius,        size_y-rounding_radius, rounding_radius]) sphere (r=rounding_radius, $fn=facets);
		translate([size_x-rounding_radius, size_y-rounding_radius, rounding_radius]) sphere (r=rounding_radius, $fn=facets);

		translate([rounding_radius,        rounding_radius,        size_z-rounding_radius]) sphere (r=rounding_radius, $fn=facets);
		translate([size_x-rounding_radius, rounding_radius,        size_z-rounding_radius]) sphere (r=rounding_radius, $fn=facets);
		translate([rounding_radius,        size_y-rounding_radius, size_z-rounding_radius]) sphere (r=rounding_radius, $fn=facets);
		translate([size_x-rounding_radius, size_y-rounding_radius, size_z-rounding_radius]) sphere (r=rounding_radius, $fn=facets);
	}
}

rounded_cube(customizer_x, customizer_y, customizer_z, customizer_facets, customizer_rounding_radius);

```


[User]
Hey, I'm looking to design a custom Raspberry Pi case, and I'd like to use OpenSCAD for it. I have some basic ideas, but I need help creating a fully parametric design. I'm hoping to be able to customize things like the case size, wall thickness, and cutouts for various ports. I'd like it to be a snap-together design. I'd also like to be able to add a custom text and a logo to the top of the case.

Here's what I have in mind:

*   **Overall Structure:** The case should consist of two main parts - a top and a base that snap together. I'd like to control the overall dimensions using a parameter.
*   **Wall Thickness:** I'd like to be able to set the wall thickness using a variable. This should apply to all walls of the case. I'd also need a lip on the bottom piece to allow the top piece to snap on.
*   **Port Cutouts:** The case should include cutouts for all the standard Raspberry Pi ports - USB, Ethernet, HDMI, mini USB, audio jack, and composite video. The size and placement of these cutouts should be based on the standard Raspberry Pi board layout.
*   **Text and Logo:** I want to add a custom name and a logo to the top of the case. This logo should be a combination of two leaves and a raspberry shape. These should be able to be raised or engraved into the surface, using a given thickness.
*   **PCB Retainers:** The design should include some cylinder-shaped pegs on the walls of the case that would hold the Pi board in place. These should have a diameter and height parameters. They should also have smaller "base retainer" pegs that are shorter and smaller.

I'd prefer to use the `write` module from the `Write.scad` library for adding text.

Could you generate the necessary OpenSCAD files for me?

[Assistant]
PiCaseCust.scad:
```
// Raspberry Pi Case Design
// TrevM 28 April 2014

use <write/Write.scad>

/* [Global] */

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

// What quality?
$fn = 40;

// What name?
Name = "Trev";

// What Size?
NSize = 12;	// [1:30]

/* [Hidden] */

Trans = 1.0;
thk = 2.5;
logoDeep = thk-1;

translate([-56-4,-85/2,0])	top();
translate([4,-85/2,0])		base();

module top()
{
	wide = 56+((thk+0.1)*2);
	long = 85+((thk+0.1)*2);
	translate([-thk-0.1, -thk-0.1,0])	{
		difference()	{															// base
			cube([wide,long,thk]);
			translate([thk,thk+1,-0.1])			cube([10,12,thk+0.2]);	// clear LEDs
			translate([thk+2,thk+51.5,-0.1])		cube([4,32,thk+0.2]);	// clear GPIO cable
			//translate([10,30,-0.1]) linear_extrude(height=logoDeep) import("logo1.dxf",scale=0.2);
			translate([10,30,-0.1]) logo(logoDeep);
			translate([30,27.5,0])	rotate([0,180,0])	write(Name,t=logoDeep,h=NSize,center=true);
		}

		translate([wide-(16+(thk*2))-23.5,-7.5+thk,0])	cube([16+(thk*2),7.6,thk]);	// USB base
		translate([wide-(16+(thk*2))-23.5,-7.5+thk,0])	cube([thk+0.5,7.5,19.4]);		// USB R
		translate([wide-23.5-thk,-7.5+thk,0])				cube([thk,7.5,19.4]);			// USB L

		translate([wide-(18+(thk*2))-1,0,thk-0.1])		cube([18+(thk*2)+1,thk,3]);	// ethernet
		translate([wide-(18+(thk*2))-1,0,thk-0.1])		cube([3,thk,19.5-thk]);		// ethernet R
		translate([wide-thk-1.5,0,thk-0.1])				cube([4,thk,19.5-thk]);		// ethernet R

		translate([wide-thk,32.5,thk-0.1])				cube([1,16+(thk*2),10.1]);		// hdmi (thin)
		translate([wide-thk,32.5,thk-0.1])				cube([thk,16+(thk*2),7]);		// hdmi (thick)
		translate([wide-thk,32.5,thk-0.1])				cube([1,thk,19.4-thk]);		// hdmi R
		translate([wide-thk,33+15.5+thk,thk-0.1])			cube([1,thk,19.4-thk]);		// hdmi L

		translate([wide-2.5-(8.5+(thk*3)),85.2+thk,thk-0.1])		cube([8.5+(thk*4),1,13.5]);		// mini usb (thin)
		translate([wide-2.5-(8.5+(thk*3)),85.2+thk+0.2,thk-0.1])	cube([8.5+(thk*4),thk-0.2,10]);	// mini usb (thick)
		translate([wide-2.5-(8.5+(thk*3)),85.2+thk,thk-0.1])		cube([(thk*2)-0.5,1,19.4-thk]);	// mini usb L
		translate([wide-(thk*2),85.2+thk,thk-0.1])				cube([(thk*2),1,19.4-thk]);		// mini usb R

		translate([wide-16-(28+(thk*2)),85+thk+0.2,thk-0.1])		cube([28+(thk*2),thk,18]);		// card holder

		translate([wide-thk,0,thk-0.1])							cube([thk,33-0.1,18.5]);		// near L wall (thick)
		translate([wide-thk+1.1,0,thk+18.5-0.1])					cube([thk-1.1,33-0.1,3.5]);	// near L wall (thin)
		translate([wide-thk,thk,thk+15.5])		rotate([-90,0,0])	cylinder(r=1,h=33-thk-0.1);	// near L wall PCB retainer
		translate([wide-thk+1.1,0,thk+20.6-0.1])	rotate([-90,0,0])	cylinder(r=0.6,h=33-0.1);		// near L wall base retainer

		translate([wide-thk,48.1+(thk*2),thk-0.1])				cube([thk,35.6,18.5]);				// far L wall (thick)
		translate([wide-thk+1.1,48.1+(thk*2),thk+18.5-0.1])		cube([thk-1.1,35.6,3.5]);			// far L wall (thin)
		translate([wide-thk,48.1+(thk*2),thk+15.5])			rotate([-90,0,0])	cylinder(r=1,h=35.5-0.1);	// far L wall PCB retainer
		translate([wide-thk+1.1,48.1+(thk*2),thk+20.6-0.1])	rotate([-90,0,0])	cylinder(r=0.6,h=35.5-0.1);	// far L wall base retainer

		translate([0,0,thk-0.1])								cube([thk,14.4+thk,18.5]);			// near R wall (thick)
		translate([0,0,thk+18.5-0.1])							cube([thk-1.1,14.4+thk,3.5]);		// near R wall (thin)
		translate([thk,thk,thk+15.5])			rotate([-90,0,0])	cylinder(r=1,h=14.4);				// near R wall PCB retainer
		translate([thk-1.3,0,thk+20.6-0.1])	rotate([-90,0,0])	cylinder(r=0.6,h=14.4+thk);		// near R wall base retainer

		translate([0,26.6+thk,thk-0.1])						cube([thk,7.3,18.5]);			// centre R wall (thick)
		translate([0,26.6+thk,thk+18.5-0.1])					cube([thk-1.1,7.3,3.5]);		// centre R wall (thin)

		translate([0,44.6+thk,thk-0.1])						cube([thk,40+thk,18.5]);			// far R wall (thick)
		translate([0,44.6+thk,thk+18.5-0.1])					cube([thk-1.1,40+thk,3.5]);		// far R wall (thin)
		translate([thk,44.6+thk,thk+15.5])			rotate([-90,0,0])	cylinder(r=1,h=40+thk);		// far R wall PCB retainer
		translate([thk-1.3,44.6+thk,thk+20.6-0.1])	rotate([-90,0,0])	cylinder(r=0.6,h=40+thk);		// far R wall base retainer

		translate([0,long-thk,thk-0.1])						cube([12.6,thk,18.5]);			// back wall (thick)
		translate([0,long-thk+1,thk+18.5-0.1])				cube([12.6,thk-1,3.5]);		// back wall (thin)

		translate([0,0,thk-0.1])								cube([16.5,thk,18.6]);			// front wall (thick)
		translate([0,0,thk-0.1])								cube([16.8,thk,17]);			// front wall (thick)
		translate([0,0,thk+18.5-0.1])							cube([16.5,thk-1,3.5]);		// front wall (thin)

		translate([0,14+thk,thk-0.1])	{											// ear jack
			difference()	{
				cube([thk,13,10.1]);
				translate([-0.1,6.5,10.1])	rotate([0,90,0])	cylinder(r=4,h=thk+0.2);
			}
		}
		translate([0,33.5+thk,thk-0.1])	{												// comp vid
			difference()	{
				cube([thk,11.5,7]);
				translate([-0.1,5.75,8.5])	rotate([0,90,0])	cylinder(r=5,h=thk+0.2);
			}
		}
	}
}

module base()
{
	translate([-thk-0.1, -thk-0.1,0])	{
		cube([56+((thk+0.1)*2),85+((thk+0.1)*2),thk]);						// base
		translate([43.6+thk,5.1+thk,thk-0.1])		cylinder(r=3.5,h=3.5);
		translate([18.1+thk,60.1+thk,thk-0.1])	cylinder(r=3.5,h=3.5);

		translate([16,85.5+thk,0])	{										// card holder base
			difference()	{
				cube([27.5+(thk*2),17,thk+1]);
				translate([(27.5/2)+thk,17+3,-0.1])	cylinder(r=10,h=thk+2);
			}
		}
		translate([16,85.5+thk,thk+0.9])			cube([thk+1.5,17,3.1]);		// card holder R side
		translate([17.5+25+thk,85.5+thk,thk+0.9])	cube([thk+1,17,3.1]);			// card holder L side

		translate([23.5,-7.5+thk,0])					cube([16+(thk*2),7.6,thk]);		// USB base
		translate([23.5,-7.5+thk,thk-0.1])			cube([16+(thk*2),thk,thk+2.6]);	// USB front
		translate([23.5,-7.5+thk,thk-0.1])			cube([thk,7,thk+2.6]);				// USB L side
		translate([23.5+16+thk,-7.5+thk,thk-0.1])		cube([thk,7,thk+2.6]);				// USB R side

		difference()	{
			union()	{
				translate([thk-1,thk-1,thk-0.1])		cube([56+2,2,3.5]);				// front lip
				translate([thk-1,0,thk-0.1])			cube([2,85+2,3.5]);				// left lip
				translate([56+2,thk-1,thk-0.1])		cube([2,85+2,3.5]);				// right lip
				translate([thk-1,85.5+1,thk-0.1])		cube([15.1,2,3.5]);				// back L lip
				translate([18+27+thk,85.5+1,thk-0.1])	cube([12.5,2,3.5]);				// back L lip

				translate([thk+0.1,0,thk-0.1])		cube([18+(thk*2),thk,thk+2.6]);	// ethernet
				translate([thk-1,33,thk-0.1])			cube([1,15+(thk*2),thk+2.6]);		// hdmi
				translate([2.5,85+thk,thk-0.1])		cube([8.5+(thk*2),1,thk+2.6]);	// mini usb
			}
			translate([thk-1,-0.1,thk+1.5])	rotate([-90,0,0])	cylinder(r=0.7,h=85+(thk*2));
			translate([56+(thk*2)-1,-0.1,thk+1.5])	rotate([-90,0,0])	cylinder(r=0.7,h=85+(thk*2));
		}
		translate([0,33,thk-0.1])				cube([thk,15+(thk*2),2.6]);		// hdmi
		translate([56.5+thk,14.5+thk,thk-0.1])	{								// ear jack
			difference()	{
				cube([thk-0.3,12,1.4+10.5]);
				translate([-0.1,6,1.4+10.5])	rotate([0,90,0])	cylinder(r=4,h=thk+0.2);
			}
		}
		translate([56.5+thk,34+thk,thk-0.1])	{									// comp vid
			difference()	{
				cube([thk-0.3,10.5,1+8.1+3.5]);
				translate([-0.1,5.25,1.9+8.1+3.5])	rotate([0,90,0])	cylinder(r=5,h=thk+0.2);
			}
		}
	}
}

module logo()
{
	//off=-50;
	//off=0;
	//translate([off,0,0])	linear_extrude(height=logoDeep) import("logo1.dxf",scale=0.2);

	translate([13.5,42.5,0])	leaf(logoDeep);
	translate([27,42.5,0])		mirror([1,0,0])	leaf(logoDeep);
	difference()
	{
		RaspOut(logoDeep);
		RaspIn(logoDeep+0.2);
	}
}

module leaf(hi)
{
	difference()
	{
		leafOut(hi);
		translate([-0.8,-0.4,-0.1])	leafIn(hi+0.2);
	}
}

module leafOut(hi)
{
	rotate([0,0,-34])	hull()	// bottom half
	{
		rotate([0,0,3])		squash(15.5,5,4,hi);
		translate([1.8,0,0])	cylinder(r=5.5,h=hi);
		translate([-1,-0.5,0])	cylinder(r=5.4,h=hi);
	}
}

module leafIn(hi)
{
	rotate([0,0,-35])	hull()	// bottom half
	{
		squash(11,1.5,6,hi);
		translate([2.2,-1.8,0])	cylinder(r=1.8,h=hi);
		translate([-1,-2.2,0])		cylinder(r=1.6,h=hi);
	}
	translate([1,1,0])	rotate([0,0,156])	//hull()	// bottom half
	{
		squash(12,1,6,hi);
		//translate([2.2,-1.8,0])	cylinder(r=1.8,h=hi);
		//translate([-1,-2.2,0])		cylinder(r=1.6,h=hi);
	}
}

module RaspOut(hi)
{
	hull()
	{
		translate([20.5,12.5,0])	cylinder(r=5,h=hi);	// bottom lobe
		translate([20.9,34.5,0])	cylinder(r=5,h=hi);	// top lobe
		translate([11,24.9,0])		cylinder(r=6,h=hi);	// left lobe
		translate([30,24.9,0])		cylinder(r=6,h=hi);	// right lobe
		translate([14,18,0])		cylinder(r=6.5,h=hi);	// bl lobe
		translate([27,18,0])		cylinder(r=6.5,h=hi);	// br lobe
	}
	translate([14.2,30.6,0])		cylinder(r=6.5,h=hi);	// tl lobe
	translate([27,30.6,0])			cylinder(r=6.5,h=hi);	// tr lobe
}

module RaspIn(hi)
{
	translate([0,0,-0.1])
	{
		// 3 centre shapes
		translate([20.75,18.75,0])	linear_extrude(height=hi) scale([1.1,1,1])	circle(4.25);
		translate([25.8,26.75,0])	rotate([0,0,-66])	linear_extrude(height=hi) scale([1.15,1,1])	circle(4.25);
		translate([15.4,26.75,0])	rotate([0,0,66])	linear_extrude(height=hi) scale([1.15,1,1])	circle(4.25);
		translate([20.7,11.5,0])	squash(9,3.5,5,hi);							// bottom shape
		translate([20.5,33.7,0])	rotate([0,0,180])	squash(9,3.7,6,hi);		// top shape
		translate([12.2,17,0])		rotate([0,0,-53])	squash(9.1,4.5,6.2,hi);	// bl shape
		translate([29,17,0])		rotate([0,0,53])	squash(9.1,4.5,6.2,hi);	// br shape
		translate([8.6,25,0])		rotate([0,0,-98])	squash(8,2,5,hi);			// l shape
		translate([32.3,25,0])		rotate([0,0,98])	squash(8,2,5,hi);			// r shape
		translate([12.6,33,0])		rotate([0,0,-142])	squash(8,2,5,hi);			// tl shape
		translate([28.5,33,0])		rotate([0,0,142])	squash(8,2,5,hi);			// tr shape
	}
}

module squash(w,t,b,hi)
{
	// top arf
	resize(newsize=[w,t,hi])	cylinder(r=4,h=hi);
	// bottom arf
	difference()
	{
		resize(newsize=[w,b,hi]) 		cylinder(r=4,h=hi);
		translate([-(w+1)/2,0,-0.1])	cube([w+1,b,0.2+hi]);
	}
}

```


[User]
I'd like to design a customizable piggy bank, kind of like a stylized pig. I've got some initial ideas laid out in two separate files, but I'd like the design to be more parametric and flexible. I'll need the main body of the pig, including the slot at the bottom, and I'd also like to have separate pieces for the legs, the snout, nostrils, eyes, and ears. I also need the slot on top for putting the money in. I'd like the sizes of all these elements to scale appropriately with the overall dimensions of the pig.

Here are some details and constraints:

*   **Overall Dimensions:** I'll need to be able to easily specify the width, depth, and height of the main pig body as parameters.
*   **Legs:** The pig should have four legs, positioned near the corners. They should be simple cuboids, and their size should scale relative to the main body.
*   **Snout:** The snout should be a rectangular prism, also scaled to the body.
*   **Nostrils:** I want two small nostrils on the snout, also scaled to the overall pig.
*   **Eyes:** The eyes should be small cylinders, kind of like pegs, placed on the sides of the head.
*   **Ears:** The ears should be somewhat curved, sticking out from the side, like half-cylinders intersecting rectangular prisms.
*   **Top Slot:** The slot on the top needs to be large enough for coins, and needs to also scale with the main body.
*   **Bottom Access:** I need a rectangular slot on the bottom, that's also scaled with the rest, for getting the money out. This should be a separate piece that fits into the slot.
*   **Parametric Design:** Everything should be defined parametrically in terms of the main width, depth, and height, so that when I change those, the rest of the model scales reasonably.

I want the whole design to be generated in OpenSCAD and I would appreciate it if you can make the code easy to understand and modify later on. I would also like to be able to use all the variables in the top level module.

[Assistant]
piggy_bank_square.scad:
```
$fn=30;
width=30;
depth=35;
height=30;
diameter=8;
//
//jambe
//
translate([width/3,depth/3.04,-height/1.7])cube([width/6,depth/5.83,height/10]);
translate([-width/2,depth/3.04,-height/1.7])cube([width/6,depth/5.83,height/10]);
translate([width/3,-depth/2,-height/1.7])cube([width/6,depth/5.83,height/10]);
translate([-width/2,-depth/2,-height/1.7])cube([width/6,depth/5.83,height/10]);
//
//nez
//
translate([0,depth/1.92,height/6-6])cube([width/3.75,depth/23.33,height/3.75],center=true);
//
//narine
//
translate([width/18,depth/1.81,height/6-6])cube([width/30,depth/50,height/10],center=true);
translate([-width/18,depth/1.81,height/6-6])cube([width/30,depth/50,height/10],center=true);
//
//yeux
//
translate([width/4,depth/2.1,height/4])rotate([270,0,0])cylinder(h=diameter/4,r=diameter/5.33);
translate([-width/4,depth/2.1,height/4])rotate([270,0,0])cylinder(h=diameter/4,r=diameter/5.33);
//
//oreille
//
translate([width/1.63,depth/2.5,height/2.7])cube([width/21,depth/9.9,height/12]);
intersection()
{
difference()
{
translate([width/1.8,depth/2.5,height/2.3])rotate([270,0,0])cylinder(h=diameter/2.3,r=diameter/2.5);
translate([width/1.8,depth/2.5,height/2.3])rotate([270,0,0])cylinder(h=diameter/2.3,r=diameter/4.3);
}
translate([width/2.5,depth/2.7,height/2.3])cube([width/3,depth/7,height/2.5]);
}
//
//oreille 2
//
translate([-width/1.51,depth/2.5,height/2.7])cube([width/21,depth/9.9,height/12]);
intersection()
{
difference()
{
translate([-width/1.8,depth/2.5,height/2.3])rotate([270,0,0])cylinder(h=diameter/2.3,r=diameter/2.5);
translate([-width/1.8,depth/2.5,height/2.3])rotate([270,0,0])cylinder(h=diameter/2.3,r=diameter/4.3);
}
translate([-width/1.4,depth/2.7,height/2.3])cube([width/3,depth/7,height/2.5]);
}
//
//trous pour argent
//
difference()
{
cube([width,depth,height],center=true);
union() {
translate([0,0,height/1.5])cube([width/6,depth/1.25,height],center=true);
cube([width/1.1,depth/1.4,height/1.1],center=true);
}
translate([0,-depth/8-2,-height/2.3])cube([width/1.2,depth/0.744,height/15],center=true);
translate([0,0,-height/2])cube([width/2,depth/1.522,height/1.25],center=true);
}
```
sarahbankpiece.scad:
```
width=30;

depth=35;

height=30;

cube([width/1.3,depth/1.06,height/18.5],center=true);

translate([0,depth/2,0])cube([width/9,depth/6,height/18.5],center=true);
```


[User]
Hi, I'm looking to design a parametric laptop cooler in OpenSCAD, and I'd really appreciate some help with it. I've already got some basic pieces designed, but I need help putting them together and making them configurable.

The cooler should be composed of a middle frame, two end pieces, and then two types of sticks that fit into the overall structure.

Let me describe the pieces I'm thinking of:

**Middle Piece:**
This will be the core of the structure, composed of four rectangular "legs," two running along the length of the laptop (left and right) and two across the width (front and back). Each leg is 2mm thick and 13mm wide for the long sides and 2mm thick and 10mm wide for the short sides and 2mm high. Each of these has a cylindrical connector extending from the top with a radius of 0.5mm and a height of 2.6mm and rotated by 120 degrees around the [1,1,1] axis. The long sides are positioned at x= +/-4.  The short sides are at y= +/-6.5. In addition, there are 4 legs that extend below the structure, with diameter of 10mm and a height of 3mm.  These are positioned below the long sides and the short sides

**End Piece:**
This piece will connect to the ends of the middle piece, with matching holes to accept the connectors from the middle piece. The end pieces have the same basic rectangular leg structure (two long and two short), with dimensions identical to the middle piece, but also have the matching holes to connect to the middle section. The holes are positioned at x=4 and x=-4 on the long sides. In addition, each end piece has three additional cubes arranged vertically on one of the long sides; these are 2mm cubes with holes through them (top and bottom). Each of these cubes should have two smaller holes suitable for 0.3mm radius cylinders with a height of 3mm, positioned at 1mm and 2 mm on the x axis relative to the cube center. Each also has a small cube extending out horizontally from the side to form a slot for the sticks, measuring 0.3mm x 3.5mm and 0.3mm x 3.1 mm, positioned at y=-1.5mm and y=-0.5mm respectively, relative to the cube center and with a height of 1.0mm. These cubes should be rotated 450 deg around the Z axis and translated to sit outside the end piece. The first cube is at x=2.5, y=20, the second cube at x=-9, y=22, and the third cube at x=-2.5, y=-10 (all relative to the origin). As with the middle piece, the end piece has 4 legs with diameter of 10mm and a height of 3mm.  These are positioned below the long sides and the short sides

**Stick with Duck Bill End:**
This will be a long, rectangular prism (25mm long) with a half-cylinder along one side (0.16mm radius, 25mm height, rotated by 120 degrees along the [1,1,1] axis), for a snug fit in the slots in the cubes of the end pieces. The stick also features a "duck bill" on one end, constructed from a combination of cubes and cylinders. There's a main "bill" shape (5mm x 2.5mm x 1.1mm cube with a 5mm x 1.6mm x 1.5mm cube cut out of it) and a head shape (2.5mm radius cylinder, 1.1mm high, with 2mm radius cylinder cut out and a 3mm x 10mm x 1.5mm cube that acts as a connector between head and bill). Finally, there is a small neck shape, 2 x 1.1 x 1.5 mm. This stick should be rotated 120 degrees along the [1,1,1] axis and translated to start at x=-12, y=1.3, z=1.4.

**Stick with Flat End:**
This stick will be a simpler design, also featuring the same long rectangular prism (25mm long) with the half-cylinder, but with a flat end on one side instead of a duck bill. The flat end is 0.25mm thick and 2.4mm wide, and 0.9mm high with a cylinder at the top of it (radius 0.45, height 0.2, rotated by 120 around [1,1,1]). The flat end is positioned at the end of the stick.

I'd like the following parameters:
*   **`middle_length`**: The length of the middle section legs.
*   **`middle_width`**: The width of the middle section legs.
*  **`leg_height`**: The height of the legs on all pieces
*  **`leg_diameter`**: The diameter of the legs on all pieces
*   **`connector_radius`**: The radius of the cylindrical connectors.
*   **`connector_height`**: The height of the cylindrical connectors.
*  **`stick_length`**: The length of the sticks
*   **`stick_radius`**: The radius of the half-cylinder on the sticks.
*   **`cube_size`**: The size of the end-piece cubes that hold the sticks.
*   **`cube_hole_radius`**: The radius of the holes in the end-piece cubes.

I'm envisioning this in separate files: one for the middle piece, one for the end piece, and one each for the two different sticks. I'd like all files to be parametric.

For libraries, please use the `MCAD` library, as I'm comfortable with that.

Could you help me generate this? Thanks!

[Assistant]
Middle_piece__explanations__bilangual.scad:
```
// le cadre du milieu avec avec les connecteurs sur les côté (2 sur chaque)
// Middle piece with connectors on the side (2 each)
// côté droite(longeur)avec un connecteur (extrême droite)
//righ side legth with connector (far right)
union () 					{
rotate(a=120,v=[1,1,1])translate([4,0.1,4])cylinder(r=0.5,h=2.6);
translate([4,0,0]) {
cube(size=[2,13,2],center=true);
		}
// côté gauche (longeur)avec la deuxième connecteur (droite)
//left side legth with seconde connector (right)
rotate(a=120,v=[1,1,1])translate([-4,0.1,4])cylinder(r=0.5,h=2.6);
translate([-4,0,0]){
cube(size=[2,13,2], center=true);
		}
// largeur(vers l'avant)avec la trosième connecteur (gauche)
// Width (front) with third connecteur (left)
rotate(a=120,v=[1,1,1])translate([-4,0.1,-6.6])cylinder(r=0.5,h=2.6);
translate([0,-6.5,0]){
cube(size=[10,2,2],center=true);
		}
// largeur (vers l'arrière) avec quatrième connecteur (extreme gauche)
// Width (back) with fourth connector (far left)
rotate(a=120,v=[1,1,1])translate([4,0.1,-6.6])cylinder(r=0.5,h=2.6);
translate([0,6.5,0]){
cube(size=[10,2,2],center=true);
		}

								}

// Jambe gauche
// left leg
$fn=30;
translate([-4,-6.5,-4]){
cylinder(h=3,l=10);
		}

// Jambe extrême droite
// far right leg
$fn=30;
translate([4,6.5,-4]){
cylinder(h=3,l=10);
		}

// Jambe droite
//right leg
$fn=30;
translate([4,-6.5,-4]){
cylinder(h=3,l=10);
		}

//Jambe extrême gauche
//far left leg
$fn=30;
translate([-4,6.5,-4]){
cylinder(h=3,l=10);
		}
```
End_piece__explanations__Bilangual.scad:
```
//embout pour connecter au cadre du milieu(sur le côté droite) avec trois cube(sur le côté gauche)
//End piece to connect the middle (right side) 3 cubes (left side)
//côté droite longeur avec deux trou extrême droite et droite
//right side with 2 holes far right and right
union () 					{
difference()	{
translate([4,0,0]) {
cube(size=[2,13,2],center=true);
						 }
rotate(a=120,v=[1,1,1])translate([4,0.1,3])cylinder(r=0.5,h=3);

rotate(a=120,v=[1,1,1])translate([-4,0.1,3])cylinder(r=0.5,h=3);
	}
//côté gauche longeur
//left side length
translate([-4,0,0]){
cube(size=[2,13,2], center=true);
		}

//largeur (vers l'avant)
//widht (towards the front)
translate([0,-6.5,0]){
cube(size=[10,2,2],center=true);
		}

// largeur (vers l'arrière)
//widht (back)
translate([0,6.5,0]){
cube(size=[10,2,2],center=true);
		}

								}

// Jambe gauche
// left leg
$fn=30;
translate([-4,-6.5,-4]){
cylinder(h=3,l=10);
		}

//Jambe extrême droite
// far right leg
$fn=30;
translate([4,6.5,-4]){
cylinder(h=3,l=10);
		}

//Jambe droite
//right leg
$fn=30;
translate([4,-6.5,-4]){
cylinder(h=3,l=10);
		}

// Jambe extrême gauche
//far left leg
$fn=30;
translate([-4,6.5,-4]){
cylinder(h=3,l=10);
		}

// Cube (gauche) avec trou(en haut et en bas) pour faire entre les clés
// left cube with hole (top and bottom) to fit in sticks
union()											{
rotate (a=450,v=[0,0,1])translate([2.5,20,0])					{
translate([-10,-15,-1]){
difference () 					{
cube(size=[2,2,2]);
rotate(a=120,v=[1,1,1])translate([1,1.5,-0.5])cylinder(r=0.3,h=3);
rotate(a=120,v=[1,1,1])translate([1,0.5,-0.5])cylinder(r=0.3,h=3);
rotate(a=270,v=[5,0,0])translate([-1.5,-1.5,0.5])cube(size=[3.5,0.3,1.0]);
rotate(a=270,v=[5,0,0])translate([-1,-0.5,0.5])cube(size=[3.1,0.3,1.0]);
						}

									}

															       }

// Cube (gauche milieu) avec trou (en haut et en bas) pour faire entre les clés
// left middle cube with hole (top and bottom) to fit in sticks
rotate (a=450,v=[0,0,1])translate([-9,22,0])					{
translate([8,-17,-1]){
difference () 					   {
cube(size=[2,2,2]);
rotate(a=120,v=[1,1,1])translate([1,1.5,-0.5])cylinder(r=0.3,h=3);
rotate(a=120,v=[1,1,1])translate([1,0.5,-0.5])cylinder(r=0.3,h=3);
rotate(a=270,v=[5,0,0])translate([-1.5,-1.5,0.5])cube(size=[3.5,0.3,1.0]);
rotate(a=270,v=[5,0,0])translate([-1,-0.5,0.5])cube(size=[3.1,0.3,1.0]);
						}

									}
																}

//Cube (gauche extrême) avec un trou (en haut et en bas) pour faire entre les clés
//Cube far left with hole (top and bottom) to fit in sticks
rotate (a=450,v=[0,0,1])translate([-2.5,-10,0])			{
translate([8,15,-1]){
difference () 				       {
cube(size=[2,2,2]);
rotate(a=120,v=[1,1,1])translate([1,1.5,-0.5])cylinder(r=0.3,h=3);
rotate(a=120,v=[1,1,1])translate([1,0.5,-0.5])cylinder(r=0.3,h=3);
rotate(a=270,v=[5,0,0])translate([-1.5,-1.5,0.5])cube(size=[3.5,0.3,1.0]);
rotate(a=270,v=[5,0,0])translate([-1,-0.5,0.5])cube(size=[3.1,0.3,1.0]);
					}

									}	 					 }

												}

```
Stick_with_the_duck_face_The_final_right_one__bilangual_.scad:
```
// bâton avec bec de canard
// Duck bill stick
// Une long prisme rectangulaire avec un long demi cylindre (placer verticalement)
// Long rectangular prisim with half cylinder (vertical)
$fn=30;
translate([-12,1.30,1.4])	{
rotate(a=120,v=[1,1,1])translate([0.8,1.5,0])cylinder(r=0.16,h=25);
rotate(a=270,v=[5,0,0])translate([0,-1.5,0.5])cube(size=[25,0.2,0.6]);
								}
union() 					{
// bec du canard
// Duck bill
translate([0,0.1,1.8])rotate(a=90,v=[1,0,0])	{
difference()		{
translate([-10.5,4.4,-2.5])cube(size=[5,2.5,1.1]);
translate([-10.5,4.8,-2.5])cube(size=[5,1.6,1.5]);
						}
// tête du canard connecter au bec
//Duck head connected to bill
difference()		{
translate([-12,5,-2.5])cylinder(r=2.5,h=1.1);
translate([-12,5,-2.5])cylinder(r=2,h=1.1);
translate([-10.5,4.8,-2.6])cube(size=[3,10,1.5]);
						}
//cou du canard
//Duck neck
translate ([-10,11,-4])rotate(a=120,v=[1,1,1])
translate([-10.4,1.5,-2.8])cube(size=[2,1.1,1.5]);
															}
			}

```
Stick_with_the_flat_end_The_final_right_one__bilangual_.scad:
```
//bâton à bout plat
//Flat end stick
//Une long prisme rectangulaire avec un long demi cylindre (placer verticalement)
// Long rectangular prisim with long half-cylinder (vertical)
$fn=30;
union()	{
translate([0,0,0])				{
rotate(a=120,v=[1,1,1])translate([1,0.1,-0.9])cylinder(r=0.16,h=25);
rotate(a=270,v=[5,0,0])translate([-0.9,-0.1,0.7])cube(size=[25,0.2,0.6]);

// bout plat à la fin du bâton
// Flat end at the end of stick
rotate(a=270,v=[1,0,0]) {
translate([-0.99,-2,1.045]){
translate([0.03,-0.2,-0.05])rotate(a=120,v=[1,1,1])cylinder(r=0.45,h=0.2);
translate([0,-0.25,-0.5])cube(size=[0.25,2.4,0.9]);
					         }

				                  }

											}

			}
```


[User]
I'd like to design a customizable modular building in OpenSCAD. I'm envisioning a basic rectangular structure with parameters for the number of horizontal and vertical windows, as well as options to toggle the display of a door, windows, brickwork, and a roof.

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

*   **`horizontal_windows`**: The number of windows across the width of the building.
*   **`vertical_windows`**: The number of window rows vertically.
*   **`show_door`**: A boolean to enable/disable the display of the door.
*   **`show_windows`**: A boolean to enable/disable the display of all windows.
*   **`show_bricks`**: A boolean to enable/disable the display of brickwork on the facade.
*  **`show_roof`**: A boolean to enable/disable the display of the roof.

I also need to be able to control:

*   **Window Placement:**
    *   `Xinit`: Distance from the left edge of the building to the first window.
    *   `Yinit`: Distance from the bottom of the building to the first window row.
    *   `Xspace`: Horizontal distance between adjacent windows.
    *   `Yspace`: Vertical distance between adjacent window rows.
*   **Wall and Window Dimensions:**
    *   `Zbase`: Thickness of the wall.
    *   `Xwin`: Width of a single window.
    *   `Ywin`: Height of a single window.
    *   `Zwin`: Depth of the window recess.
    *  `Xmuntin`: Height of window muntin
	*  `Ymuntin`: Width of window muntin
	*  `Zmuntin`: Thickness of window muntin
	* `YwinArc`: Parameter for the top of window arc
	* `Xjam`: Width of the door jamb
*   **Roof Dimensions:**
    *   `Yroof`: Height of the roof above the wall.
    *   `Zroof`: Thickness of the roof, additional to wall thickness.
	*  `Droof`: Size of roof crenelation
*  **Brick Dimensions:**
	*  `Xbrick`: Width of a single brick.
	*  `Ybrick`: Height of a single brick.
	*  `Zbrick`: Thickness of the brick grout below the surface (both height and depth).

The building should be constructed using the `cube()` function, and I'd like to use the `ellipticalCylinder()` function from the MCAD library for the arched tops of the windows and the door. The door should be centered horizontally, or a double door with space between the doors if the number of horizontal windows is even.

Can you generate the OpenSCAD code for this?

[Assistant]
customizable_modular_building.scad:
```
//
//
//	Customizable Modular Building
//	Steve Medwin
//	April 21, 2014
//
//
$fn=36*1;
use <MCAD/shapes.scad>
// preview[view:south, tilt:top]

//
// CUSTOMIZING
//
// Number of horizontal windows
horizontal_windows=3; //[1:10]
Ncol=horizontal_windows;
// Number of vertical windows
vertical_windows=2; //[1:5]
Nrow=vertical_windows;

show_door="yes"; //[yes,no]
show_windows="yes"; //[yes,no]
show_bricks="no"; //[yes,no]
show_roof="yes"; //[yes,no]

//
// REMAINING PARAMETERS
//
// windows
Xinit=5*1; // Distance from left edge to first window
Yinit=6*1; //5 Distance from bottom to first window row
Xspace=10*1; // Distance from left edge of window to next left edge of window
Yspace=15.5*1; // Distance from bottom of window row to next row
Zbase=2.0*1; // Thickness of wall
Xwin=6.4*1; // (6.4) Width of window
Ywin=10*1; // Height of window
Zwin=2*1; // Depth of windows
Xmuntin=0.7*1; // Height of window muntin
Ymuntin=Xmuntin;
Zmuntin=0.6*1; // Thickness of window muntin
YwinArc=0.15*1; // Parameter for top of window arc
Xjam=1.0*1; //Width of door jam

Xbase=Xinit*2+Xspace*(Ncol-1)+Xwin; // Width of wall
Ybase=Yinit*2+Yspace*(Nrow-1)+Ywin; // Height of wall without roof
Xdoor=(Xspace+Xwin)/2-Xwin-Xjam/2;

// roof
Xroof=Xbase;
Yroof=4*1; // Height of roof
Zroof=2*1; // Depth of roof in addition to wall thickness
Droof=1*1; // Size of roof crenelation

// bricks
Xbrick=6*1; // Width of bricks
Ybrick=2*1; // Height of bricks (3:1 ratio)
Zbrick=0.205*1; // Height and depth of brick grout below surface (okay at @ .21,.19)

//
//	MODULES
//
// facade
module facade(){
	translate([0,0,-Zbase]) cube([Xbase,Ybase+Yroof,Zbase]);
}

//	bricks
module bricks(){
	for (i=[0:Ybase/Ybrick]){
		translate([0,i*Ybrick-Zbrick,-Zbrick]) cube([Xbase,Zbrick,Zbrick]); // on front
		translate([0,i*Ybrick-Zbrick,-Zbase]) cube([Zbrick,Zbrick,Zbase]); // on left edge
		translate([Xbase-Zbrick,i*Ybrick-Zbrick,-Zbase]) cube([Zbrick,Zbrick,Zbase]); // on right edge
		// add vertical lines for bricks
		for (j=[0:Xbase/Xbrick]){
			if (i/2==floor(i/2)) {
				translate([0,i*Ybrick,-Zbrick]) translate([j*Xbrick,0,0]) cube([Zbrick,Ybrick,Zbrick]);
				}
			else {
				translate([0,i*Ybrick,-Zbrick]) translate([j*Xbrick+Xbrick/2,0,0]) cube([Zbrick,Ybrick,Zbrick]);
				}
		}
	}
}

//	windows
module window(Xpos,Ypos){
	translate ([Xpos,Ypos,-Zwin-2]) cube([Xwin,Ywin,Zwin+2]); // add extra depth to improve Customizer rendering
	translate ([Xpos+Xwin/2,Ypos+Ywin,-Zwin-2]) ellipticalCylinder(Xwin/2,Ywin*YwinArc,Zwin+2);
}

//	muntins
module muntins(Xpos,Ypos){
	translate ([Xpos,Ypos+Ywin/2-Ymuntin/2,-Zwin]) cube([Xwin,Ymuntin,Zmuntin]);
	translate ([Xpos,Ypos+Ywin,-Zwin]) cube([Xwin,Ywin*YwinArc,Zmuntin]);
}

// roof
module roof(){
	Dcount=((Xbase-Xinit*2)/(Droof*2));
	XbaseP=(Dcount+1)*Droof*2-Droof;
	XinitP=(Xbase-XbaseP)/2;
	difference(){
		translate ([0,Ybase,-Zbase]) cube([Xroof,Yroof,Zbase+Zroof]);
		for (i=[0:Dcount+0]){
			translate([XinitP+i*Droof*2,Ybase,0]) cube([Droof,Yroof*0.6,Zroof]);
		}
	}
}

// door
module door(){
	translate ([Xinit+Xspace*(floor(Ncol/2)),Yinit,-Zwin-2]) cube([Xwin,Ywin,Zwin+2]);  // add extra depth to improve Customizer rendering
	translate ([Xinit+Xspace*(floor(Ncol/2))+Xwin/2,Yinit+Ywin,-Zwin-2]) ellipticalCylinder(Xwin/2,Ywin*YwinArc,Zwin+2);
	translate ([Xinit+Xspace*(floor(Ncol/2)),0,-Zwin+Zmuntin]) cube([Xwin,Yinit,Zwin]); // bottom of door
	if (Ncol/2==floor(Ncol/2)) {  // then Ncol is even so make a double door
		translate ([Xinit+Xspace*(Ncol/2-1),Yinit,-Zwin-2]) cube([Xwin,Ywin,Zwin+2]);
 		translate ([Xinit+Xspace*(Ncol/2-1),0,-Zwin+Zmuntin]) cube([Xwin+Xspace,Yinit+Ywin+Ymuntin,Zwin]);
		translate ([Xinit+Xspace*(Ncol/2-1)+Xwin+Xdoor,Yinit,-Zwin]) cube([Xjam,Ywin/2-Ymuntin/2,Zwin]);
		translate ([Xinit+Xspace*(Ncol/2-1)+Xwin+Xdoor,Yinit+Ywin/2+Ymuntin/2,-Zwin]) cube([Xjam,Ywin/2-Ymuntin/2,Zwin]);
		translate ([Xinit+Xspace*(Ncol/2)-Xdoor-Xjam/2,Yinit+Ywin+Ymuntin,-Zwin+Zmuntin]) ellipticalCylinder((Xwin+Xspace)/2,Ywin*YwinArc*1.2,Zwin);
		}
	}

// building
module building(){
	difference(){
		facade();
	//	subtract windows
		for (i=[0:Nrow-1]){
			for (j=[0:Ncol-1]){
				if (show_windows=="yes") {
					window(Xinit+j*Xspace,Yinit+i*Yspace,0);
					}
			}
		}
		if (show_bricks=="yes") {
			bricks();
			}
	}
}

//
// ASSEMBLE BUILDING
//
difference(){
	building();
	if (show_door=="yes") {
		door();
		}
	}

if (show_roof=="yes") {
	roof();
	}

// add muntins
	for (i=[0:Nrow-1]){
		for (j=[0:Ncol-1]){
			muntins(Xinit+j*Xspace,Yinit+i*Yspace,0);
		}
	}
```


[User]
I need an OpenSCAD file that can generate a stencil based on a set of 2D coordinates. The design is going to be like the included `QuestionMark.scad` file, but needs to be fully parametric.

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

*   **Input Points:** The 2D coordinates of the stencil shape(s). Instead of the hardcoded array in the example, I need to input this as a variable. This could be a single shape, or multiple shapes (like in the included example with the question mark and dot above it)
*   **Stencil Thickness:** The thickness of the stencil.
*   **Stencil Width:** The overall width of the final stencil, this should automatically calculate the proper scaling factor for the input coordinates.
*   **Margin:** The space around the stencil shapes on all sides. This is in addition to the scale calculation.
*  **Offset:** Ability to offset the final stencil in the x and y directions.
*   **Output Size:** I should be able to specify how many stencils I want to print out in both the x and y directions as well as the offset between them

I'd prefer to have the input coordinates be in the same format as the example in `QuestionMark.scad`-- that is, a list of lists, where each inner list represents a shape. So, something like `points_array = [[1,2],[3,4],[5,6]]` would represent a single shape made of three points, and `points_array = [[[1,2],[3,4]],[[5,6],[7,8]]] would represent two shapes.

The code also uses linear_extrude with a height twice the stencil thickness, I'm not sure why, but that can be preserved. I'm trying to create stencils for a variety of uses and the code should be easily customizable, so please include comments explaining the code.

[Assistant]
QuestionMark.scad:
```
//------------------------------------------------------------
//	Stencil-o-Matic (modified for RossRobotics)
//
//	input comes from:
//	http://chaaawa.com/stencil_factory/
//
//	http://thingiverse.com/Benjamin
//	http://www.thingiverse.com/thing:55821
//------------------------------------------------------------

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

// paste here after "Convert&Copy"
input = "no_input";

stencil_thickness = 1;
stencil_width = 80;
//for margin
margin = 10;

// If you don't want to center
offX = 0;
offY = 0;

module void() {}

cylinder(5,5,5, center=true);

dispo_width = stencil_width - 2*margin;

points_array = (input=="no_input"? [[179,268],[[199.26,15.12],[189.19,15.56],[181.5,16.45],[175.52,17.83],[169.55,19.42],[163.57,21.55],[157.55,24.22],[151.62,27.5],[145.87,31.09],[140.35,35.49],[135,40.71],[130.05,46.71],[125.52,53],[121.87,59.06],[119.06,64.5],[117.12,69.21],[115.55,73.5],[114.31,77.65],[113.16,82],[112.07,87.29],[110.96,93.7],[110.36,99.39],[110.49,102.95],[111.13,105],[136.96,105],[158.46,104.73],[163.39,103.42],[163.83,101.08],[164.04,97.67],[164.46,93.04],[165.44,87.75],[167.04,82.4],[168.96,77.59],[171.9,73.02],[175.98,68.21],[180.98,63.93],[186.13,60.62],[192.15,58.45],[201.05,58],[208.86,58.34],[214.1,59.16],[217.74,60.82],[221.73,63.19],[225.41,66.46],[228.34,70.28],[230.39,74.63],[231.97,79.15],[232.75,85.01],[232.85,92.65],[232.01,100.96],[229.51,107.41],[225.45,113.48],[218.91,119.91],[211.35,126.37],[203.83,132.63],[197.2,138.54],[191.77,144.13],[187.33,150.15],[183.1,157.07],[179.62,164.83],[176.98,172.85],[175.42,181.69],[175.22,192.28],[175.5,203.5],[199,203.5],[222.5,203.5],[222.74,198.5],[223.25,193.21],[224.15,187.5],[225.64,181.94],[227.6,177],[230.92,172.02],[235.69,166.37],[243.47,159.38],[254,151.21],[264.03,143.56],[270.61,137.84],[274.46,133.36],[277.95,128.69],[281.05,123.47],[283.96,117.69],[286.32,111.7],[288.09,106],[289.06,98.48],[289.47,88],[289.05,76.45],[287.17,68],[284.48,60.83],[281.31,54.14],[276.58,47.41],[270.1,40.14],[262.4,33.38],[254.68,28.12],[246.8,24.2],[238.72,20.92],[230.05,18.48],[220.76,16.55],[210.43,15.49],[199.26,15.12]],[[198.05,226.08],[178.93,226.28],[170.25,226.66],[169.27,232.87],[169,254.48],[169.27,277.23],[170.58,282.39],[179.4,282.82],[198.38,283],[218.91,282.73],[225.8,281.8],[226.73,274.94],[227,254.5],[226.73,234.06],[225.8,227.2],[218.87,226.29],[198.05,226.08]]]: input);

input_width = points_array[0][0];
input_height= points_array[0][1];
sTrace = dispo_width/input_width;
stencil_height = input_height*sTrace + 2*margin;

	translate([offX, offY, -stencil_thickness/2])
	scale([sTrace, -sTrace, 1])
	translate([-200, -150, 0]) {
		union() {
			for (i = [1:len(points_array) -1] ) {
				linear_extrude(height=stencil_thickness*2) {polygon(points_array[i]);}
			}
		}
	}

```


[User]
Hey, I'm looking to design a microswitch probe for my 3D printer, similar to the one described in that OpenSCAD file I attached. I want it to be parametric so I can easily adjust it for different printer setups.

Here's what I'm thinking:

**Core Structure:**

*   It needs a triangular main body.
*   There should be a clip mechanism to attach to the printer carriage or effector. The clip should have an adjustable gap for different thicknesses of the part it attaches to.
*   It needs a mounting point for a microswitch. The design should accommodate both small 1/2" microswitches and larger 20mm ones.
*   It should have cutouts for cable routing.
*   It should be mountable with an M3 screw and nut.

**Parametric Requirements:**

I want to be able to control these parameters:

*   `width`: Overall width of the probe.
*   `clip_len`: Length of the clip.
*   `clip_gap`:  Opening of the clip (thickness of the part it attaches to).
*   `base_to_tip`: Distance from the base to the tip of the probe.
*   `microswitch_thread_depth`: Thickness/depth of the microswitch mounting area.
*   `microswitch_height`: Height of the microswitch mounting block.
*   `wall_thickness`: Thickness of the probe's walls
*   `microswitch_width`: Width of the microswitch mounting area, should be at least the width parameter (if width is less than microswitch width).

**Key Design Elements:**

*   The probe should have a semi-automatic design, easy to attach for calibration, then remove for printing so it doesn't add weight.
*   The triangular shape is crucial for rigidity.
*   I'd like it to be designed so it can be mounted either facing forward or backwards (that is, mounted in such a way that the tip of the probe can be on the left side or the right side).
*   I will probably be 3D printing it, so keep that in mind when you are designing it.
*   I need to be able to easily adjust the mounting point for both smaller 1/2" microswitches and larger 20mm microswitches. The mounting holes should be suitable for M1.5 screws for the small microswitches and M2 screws for the larger ones.
*   The M3 screw should be easily accessible for tightening the clip.

**OpenSCAD Specifics:**

*   I would like to use the `hull()` function wherever appropriate for structural purposes.
*   Please use `difference()` and `union()` to create the shape, similar to my original example.
*   I expect to be able to set the `$fn` variable to adjust the smoothness of any cylinders or spheres.

Could you generate an OpenSCAD file that meets these requirements? I don't have a preferred library in mind, so I'm open to suggestions. I will be using the newest version of OpenSCAD. Thanks.

[Assistant]
switch_clip.scad:
```
// Semi-automatic Microswitch Probe
// Design by Marius Gheorghescu, 2014-2017

// width of the probe
width = 15;

// length of the clip
clip_len = 16;

// opening of the clip (thickness of the part the probe attaches to)
clip_gap = 7.0;

// length of the probe
base_to_tip = 50;

/* [Hidden] */

// thickness of the microswitch block (offset of the microswitch)
microswitch_thread_depth = 6;

// height of the microswitch block
microswitch_height = 12;

wall_thickness = 0.405*6;

microswitch_width = max(width, 14);

upper_area = 3*wall_thickness + clip_gap + 2.6 /* Wall + M3 nut + Wall + gap + Wall*/;
probe_len = base_to_tip + upper_area;

echo("clip length:", upper_area);
echo("probe total length:", probe_len);

epsilon = 0.01;

module switch_clip() {

	inner_triangle_height = probe_len - upper_area - 2*wall_thickness - 20;

    difference() {
        union() {

            difference() {
                triangle(probe_len, clip_len, width);

                // save material & increase strength
                rotate([0, 90, 0])
                translate([0,0,-wall_thickness])
                intersection() {
                    hull() {
                        rad = 1;
                        $fn = 50;

                        translate([-rad - wall_thickness, probe_len/2 - rad - upper_area, 0])
                            cylinder(r=rad, h=width, center=true);

                        translate([-rad + wall_thickness - base_to_tip/probe_len*clip_len, probe_len/2 - rad - upper_area, 0])
                            cylinder(r=rad, h=width, center=true);

                        translate([-rad - wall_thickness, -probe_len/2 + rad + microswitch_height, 0])
                            cylinder(r=rad, h=width, center=true);
                    }

                    hull() {
                        rad = 1;
                        $fn = 50;

                        translate([-rad - wall_thickness, probe_len/2 - rad - upper_area, 0])
                            cylinder(r=rad, h=width, center=true);

                        translate([-rad + wall_thickness - base_to_tip/probe_len*clip_len, probe_len/2 - rad - upper_area, 0])
                            cylinder(r=rad, h=width, center=true);

                        translate([-rad, -probe_len/2 + rad + microswitch_height, 0])
                            cylinder(r=rad, h=width, center=true);
                    }
                }

            }

            // microswitch attach
            translate([-microswitch_width/2 + width/2, -probe_len/2 + microswitch_height/2 + epsilon, microswitch_thread_depth/2])
                cube([microswitch_width, microswitch_height, microswitch_thread_depth], center=true);
        }

        // grip / cut-out
        translate([0, probe_len/2 - clip_gap/2 - 2*wall_thickness - 2.6, clip_len/2 + 2*wall_thickness])
            cube([width + epsilon, clip_gap, clip_len], center=true);

        // attach M3 screw
        translate([0, probe_len/2, clip_len/2])
            rotate([90, 0, 0])
            cylinder(r=3.5/2, h=clip_gap + 10, center=true);

        // attach m3 nut
        translate([0, probe_len/2 - 2.6/2 - wall_thickness , clip_len/2])
                cube([width + epsilon, 2.6, 5.65], center=true);

        // cable cutouts
        translate([- wall_thickness, (microswitch_height - upper_area)/2, clip_len/2 + wall_thickness])
        scale([1, base_to_tip/probe_len,1])
        {
            translate([0, -probe_len/4 + 6, 0])
                cube([4, 8, clip_len], center=true);

            translate([0, probe_len/4 - 6, 0])
                cube([4, 8, clip_len], center=true);
        }

        // m1.5 screws for 16mm microswitch
        translate([-microswitch_width/2 + width/2, -probe_len/2 + 6, 3]) {

            translate([-6.5/2, 0, 0])
                cylinder(r=0.75, h=20, center=true, $fn=12);

            translate([6.5/2, 0, 0])
                cylinder(r=0.75, h=20, center=true, $fn=12);
        }

        // m2 screws for 20mm microswitch
        translate([-microswitch_width/2 + width/2, -probe_len/2 + 8, 3]) {

            translate([-9.5/2, 0, 0])
                cylinder(r=1.1, h=20, center=true, $fn=12);

            translate([+9.5/2, 0, 0])
                cylinder(r=1.1, h=20, center=true, $fn=12);
        }

    }
}

module triangle(probe_len, clip_len, width)
{
	bottom = microswitch_thread_depth/2;
	$fn = 36;
	rad = 2;

	rotate([0, 90, 0])
	hull() {

		translate([-rad, probe_len/2 - rad, 0])
			cylinder(r=rad, h=width, center=true);

		translate([-clip_len + rad, probe_len/2 - rad, 0])
			cylinder(r=rad, h=width, center=true);

		translate([-bottom/2, -probe_len/2 + 1/2, 0])
			cube([bottom, 1, width], center=true);
	}

}

rotate([0, 90, 0])
{
	switch_clip();
}

```