[User]
Okay, I need help designing a shelving peg that attaches to the tubular verticals of wire shelving units using zip ties. I've got some ideas, and I think it would be best as a parametric design.

Essentially, I want a peg that has a hinged clamp that wraps around the shelving vertical, and then a peg that sticks out for holding things. The clamp part needs to have a cutout for the zip tie. I've attached my current design for reference, but I'd really like something that is a bit cleaner and more parametric.

Here's a breakdown of what I'm thinking for parameters:

*   **`PoleDia`**: Diameter of the shelving vertical (the tube).
*   **`Thick`**: Thickness of the material used for the peg and clamp.
*   **`Height`**: Height of the clamp part.
*   **`PegLength`**: Length of the peg that sticks out.
*    **`PegDia`**: Diameter of the peg
*   **`ZipTieWidth`**: Width of the zip tie being used.
*   **`ZipTieHeight`**: Height of the zip tie cutout from the base of the clamp.
*   **`SpoolThick`**: This is the length of the peg extending out from the clamp.
*   **`nubdia`**: Diameter of the nubs on the inside of the clamp for grip

For the clamp part, I envision it as a two-piece hinged clamp that wraps around the pole. I would like there to be small 'nubs' on the inside of the clamp to help with grip, as in my design.  The hinge should be printable in place, so I'd need that to be designed with appropriate tolerances.  The peg should be an extrusion out from the center of the clamp (or maybe off to the side? Maybe that could be an option in the future). The peg needs to be a half-circle in cross section. I also need a way to connect the clamp after it is installed onto the shelf. I would like a small 'catch' to help prevent the hinged piece from swinging open.

Ideally, I'd like it if you could generate an OpenSCAD design that uses parameters so I can customize it as needed.  I think it would be good to use a library to help with the hinge portion of the design - I believe there are a few good hinge designs in the [BOSL library](https://github.com/BOSL-Lib/BOSL). Specifically, the `HalfHinge` module in the BOSL library looks like it could be very useful.  I think I would also like to use the `HollowRoof` module from my own code.

I'm envisioning two primary files: one for the main peg design (using the BOSL hinge and a modified version of my hollow roof module) and a second file containing the `HollowRoof` module. It's also really important that the files have comments throughout to make it clear what each part of the design is and what the parameters are doing.

Could you help me generate that code?

[Assistant]
Shelving_mount_v5.scad:
```
/*************************************
George Miller
Trying to design a peg that will bolt onto my shelving.
6-17-17
all dimensions in MM unless specified
v1 - I tried to do it with bolts and canceled when decided I wanted a 1 piece part.
v2 - designed for two zip ties top and bot.
v3 - designed for a single zip tie
v4 - cleaning up and adding more variables.
v5 - better hinge
*************************************/

/* variables */
PoleDia = 26;
Thick = 4;
Height = 30;
nubdia = .8;
SpoolThick = 80;
PegLength = 80;
PegDia = 25;
ZipTieHeight = 23;
ZipTieWidth = 8;

/* Hidden */
PoleRad = PoleDia/2;
OuterRad = PoleRad+Thick;

/* Part */
union(){
    //mount
    difference(){
        rotate([0,90,0])
        translate([0,0,-(OuterRad)])
        rotate([0,0,90])
        render(convexity = 2){
        HalfHinge(L=Height,Dia=Thick,Tol=0.3,Segments=6,centerLen=Height,Pin=1,Snap=0,Rev=0,$fn=180)
        rotate([0,0,-90])
        translate([0,0,(OuterRad)])
        rotate([0,-90,0])
        union(){
            //shell around the pole
            HollowRoof(length=Height,OuterDiameter = (OuterRad*2),WallThick=Thick);
            //nub ring to grip pole
            nubRing();
        }}
        CutoutForZipTies();
    }

    render(convexity = 2)
    difference(){
        rotate([-90,0,0])
        rotate([0,90,0])
        translate([0,-Height,-(OuterRad)])
        render(convexity = 2){
        HalfHinge(L=Height,Dia=Thick,Tol=0.3,Segments=6,centerLen=Height,Pin=1,Snap=0,Rev=0,$fn=180)
        translate([0,Height,(OuterRad)])
        rotate([0,-90,0])
        rotate([90,0,0])
        rotate([0,0,180])
        union(){
            //shell around the pole
            HollowRoof(length=Height,OuterDiameter = (OuterRad*2),WallThick=Thick);
            //nub ring to grip pole
            nubRing();
        }
        }
        CutoutForZipTies();
        translate([0,-.5,-1])
        cube([OuterRad,.5,Height+2]);
    }

    //peg
    render(convexity = 2)
    difference(){
        union(){
            //half circle extrusion
            translate([0,0,Thick])
            rotate([-90,0,0])
            rotate([0,0,180])
            HollowRoof(length=SpoolThick+OuterRad+Thick,OuterDiameter = PegDia,WallThick=Thick);

            //leg
            translate([(PegDia/2)-Thick,0,0])
            cube([Thick,SpoolThick+OuterRad+Thick,Thick]);

            //leg
            translate([-(PegDia/2),0,0])
            cube([Thick,SpoolThick+OuterRad+Thick,Thick]);
        }

        //cut out so that the peg meshes well with the pole shell
        translate([0,0,-1])
        cylinder(Height+2,PoleRad+(Thick/2),PoleRad+(Thick/2),$fn=45);

        //cutout for zip tie
        CutoutForZipTies();
    }

    //catch
    Catch();

}

module Catch(){
    translate([0,SpoolThick+OuterRad,0])
    union(){
        translate([0,0,Thick*2])
        rotate([-90,0,0])
        rotate([0,0,180])
        HollowRoof(length=Thick,OuterDiameter = PegDia,WallThick=Thick);

        //leg
        translate([-(PegDia/2),0,0])
        cube([Thick,Thick,Thick*2]);
        //leg
        translate([(PegDia/2)-Thick,0,0])
        cube([Thick,Thick,Thick*2]);
    }
}

module CutoutForZipTies(){
    //cutout for zip tie
    translate([0,0,ZipTieHeight-(ZipTieWidth/2)])
    linear_extrude(ZipTieWidth){
        difference(){
            circle(OuterRad+ZipTieWidth/2,$fn=45);
            circle(OuterRad-.5,$fn=45);

        }

    }
}

module HollowRoof(length=20,OuterDiameter = 10,WallThick=2){
    render(convexity = 2)
    linear_extrude(length){
        difference(){
            circle((OuterDiameter/2),$fn=45);
            circle((OuterDiameter/2)-WallThick,$fn=180);
            translate([-((OuterDiameter/2)+1),-((OuterDiameter/2)+1),0])
            square([((OuterDiameter/2)+1)*2,((OuterDiameter/2)+1)]);
        }
    }
}

module nubRing(){
    render(convexity = 2)
    union(){
        translate([0,0,ZipTieHeight]){
            difference(){
                rotate_extrude(){
                    translate([PoleRad,0,0])
                    circle(nubdia/2,$fn=45);
                }
                translate([-(PoleRad+nubdia),-(PoleRad+nubdia),-(nubdia+1)/2])
                cube([2*(PoleRad+nubdia),(PoleRad+nubdia+Thick),nubdia+1]);
            }
        }
    }
}

//HalfHinge(L=30,Dia=2,Tol=0.2,Segments=8,centerLen=40,Pin=1,Snap=0,Rev=1)
//crateSide(L=50,W=40,RailWidth=5,Thick=1,WebThick=.5);
//cube([50,40,1]);
module HalfHinge(L=50,Dia=5,Tol=0.2,Segments=4,centerLen=50,Pin=0,Snap=0,Rev=0,$fn=180){
    render(convexity = 2){
    Seg=Segments<4?4:Segments;

    cylLen = (L/Seg)-(Tol);
    cylOffset = 2*(L/Seg);
    union(){
        difference()
        {
            render(convexity = 2)
            children(0);

            //cut out to make room for the hinge
            if (Rev==1){
                translate([-(Dia/2),0,-(Dia/2)])
                cube([(Dia)+Tol,centerLen,2*Dia]);
            }else{
                translate([-(Dia/2),(centerLen-L)/2-Tol,-(Dia/2)])
                cube([(Dia)+Tol,L+2*Tol,2*Dia]);
            }

            //tolerance between the parts
            translate([-(Tol/2),0,-(Dia/2)])
            cube([(Tol),centerLen,2*Dia]);
        }

        //The hinge cylinders
        translate([0,(centerLen-L)/2,Dia/2])
        rotate([-90,0,0])
        for (i =[0:1:(Seg/2)-1])
        translate([0,0,(i*2*(L/Seg)+(Tol/2))])
        HingeExtrusion(OD=(Dia),ID=(Dia/2),Tol=Tol,Len=cylLen,Thick=(Dia/2),$fn=180);

        //Pin
        if (Pin==1){
            pinDia = (Dia/2)-(Tol/2);
            pinLen = (cylLen/2);
            BaseDia = (Dia*3/4);
            baseLen = (cylLen/2)-2*Tol;
            translate([0,((centerLen-L)/2),0])//account for hinge being centered
            for (i =[0:1:(Seg/4)-1]){
                translate([0,((i*2*(L/Seg))+(L/Seg)),Dia/2])
                rotate([-90,0,0]){
                    translate([0,0,(-baseLen-Tol)])//sink the base into the cylinder
                    Pin(pinDia=pinDia,BaseDia=BaseDia,pinLen=pinLen,baseLen=baseLen);
                }
            }
            translate([0,centerLen-(L/Seg),0])
            rotate([0,0,180])
            translate([0,((centerLen-L)/2),0])//account for hinge being centered
            for (i =[0:1:(Seg/4)-1.5]){
                translate([0,((i*2*(L/Seg))+(L/Seg)),Dia/2])
                rotate([-90,0,0]){
                    translate([0,0,(-baseLen-Tol)])//sink the base into the cylinder
                    Pin(pinDia=pinDia,BaseDia=BaseDia,pinLen=pinLen,baseLen=baseLen);
                }
            }
        }
        //Snap
        if (Snap==1){
            pinDia = (Dia/2)-(Tol/2);
            pinLen = (cylLen/2);
            BaseDia = (Dia*3/4);
            baseLen = (cylLen/2)-2*Tol;
            translate([0,((centerLen-L)/2),0])//account for hinge being centered
            for (i =[0:1:(Seg/4)-1]){
                translate([0,((i*2*(L/Seg))+(L/Seg)),Dia/2])
                rotate([-90,0,0]){
                    translate([0,0,(-baseLen-Tol)])//sink the base into the cylinder
                    Snap(snapDia=pinDia,BaseDia=BaseDia,pinLen=pinLen,baseLen=baseLen,snapheight=2*Tol);
                }
            }
            translate([0,centerLen-(L/Seg),0])
            rotate([0,0,180])
            translate([0,((centerLen-L)/2),0])//account for hinge being centered
            for (i =[0:1:(Seg/4)-1.5]){
                translate([0,((i*2*(L/Seg))+(L/Seg)),Dia/2])
                rotate([-90,0,0]){
                    translate([0,0,(-baseLen-Tol)])//sink the base into the cylinder
                    Snap(snapDia=pinDia,BaseDia=BaseDia,pinLen=pinLen,baseLen=baseLen,snapheight=2*Tol);
                }
            }
        }
    }
}
}

//HingeExtrusion();
module HingeExtrusion(OD=5,ID=2,Tol=.2,Len=10,Thick=3,$fn=180){
    linear_extrude(Len)
    difference(){
        union(){
            circle(OD/2);
            translate([0,Thick-(OD/2),0])
            square([(OD/2)+Tol+.01,Thick]);
        }
        circle(ID/2);
    }
}

//Pin();
module Pin(pinDia=2,BaseDia=4,pinLen=10,baseLen=5,$fn = 100){
    union(){
        //Pin
        Ring((pinDia/2),(pinDia/8),pinLen+baseLen);

        //base
        cylinder(baseLen,(BaseDia/2),(BaseDia/2));
    }
}
//Snap();
module Snap(snapDia=2,BaseDia=4,pinLen=10,baseLen=5,snapheight=1,$fn = 100){
    union(){
        //Snap
        translate([0,0,baseLen-(snapDia/2)+snapheight])
        sphere(snapDia/2);

        //base
        cylinder(baseLen,(BaseDia/2),(BaseDia/2));
    }
}

//Ring(20,10,2);
module Ring(OuterRad,InnerRad,Thick,$fn = 100){
    rotate_extrude(convexity = 15)
    {
        translate([InnerRad,0,0])
        square([OuterRad-InnerRad,Thick]);
    }
}
```


[User]
I'd like to have a parametric design for a film roll storage rack. It should hold standard 35mm film canisters, but be customizable for other sizes. I need it to be a grid of holders, with adjustable rows and columns. I also want to control things like the diameter and height of the canisters, the wall thickness of the rack, and the maximum bridge distance that is printable.

Specifically, the rack needs to have a base with a grid of individual holders, and a support structure to make it sturdy. Each holder should have a circular cutout to accommodate the film canister, and two diagonal supports to bridge the gap from the circular cutout to the sides. I'm thinking that the core structure will be a cube with some interior cutouts.

The parameters I want to be able to adjust are:

*   `rows`: Number of rows of holders (integer).
*   `columns`: Number of columns of holders (integer).
*   `rollDiameter`: Diameter of the film roll canister (float).
*   `rollHeight`: Height of the film roll canister (float).
*   `wallThickness`: Thickness of the rack walls (float).
*   `maxBridge`: Maximum bridge length for 3D printing (float).

The design should create a single module that can then be used in a loop to create the full grid. I want the whole thing to be rotated to make the base of the rack the bottom, rather than being horizontal as in the code I've provided.

I want to make it modular so I would like all the geometry in one module and the repetition in the main part of the file, similar to what I have already.

I'd prefer it if the main module was called `rack`. Could you please generate the necessary OpenSCAD file? I do not want to use any libraries.

[Assistant]
film-roll-rack.scad:
```
rows = 4; // [1:1:20]
columns = 2; // [1:1:20]

rollDiameter = 31; // [1:1:60]
rollHeight = 52; // [1:1:100]

wallThickness = 2.4; // [0.1:0.1:4]
maxBridge = 15; // [0:1:40]

/* [Hidden] */
holderDiameter = rollDiameter*0.9;
rackWidth = rollDiameter+4+wallThickness;
rackDepth = rollHeight-12;

module rack(wallThickness,rollDiameter,rackDepth,maxBridge,holderDiameter,rackWidth)
{
	/* STRUCTURE */
	difference()
	{
		difference()
		{
			cube([rackWidth+2*wallThickness,rackDepth,rackWidth+2*wallThickness], center=true);
			cube([rackWidth,rackDepth+wallThickness,rackWidth], center=true);
		}

		hull()
		{
			cube([rackWidth+4*wallThickness,maxBridge,rackWidth], center=true);
			cube([rackWidth+4*wallThickness,rackDepth-2*wallThickness,maxBridge], center=true);
		}
	}

	/* HOLDER */
	translate([0,0,holderDiameter/2-rackWidth/2])
		rotate([90,0,0])
		difference()
		{
			difference()
			{
				cylinder(h=rackDepth, d=holderDiameter+wallThickness, center=true);
				cylinder(h=rackDepth+wallThickness, d=holderDiameter, center=true);
			}

			union()
			{
				rotate([0,0,10])
					translate([0,0,-(rackDepth+4*wallThickness)/2])
					cube([rollDiameter,rollDiameter,rollHeight+4*wallThickness]);

				rotate([0,0,80])
					translate([0,0,-(rackDepth+4*wallThickness)/2])
					cube([rollDiameter,rollDiameter,rollHeight+4*wallThickness]);
			}
		}
}

rotate([-90,0,0])
{
	for(z = [0:1:(rows-1)], x = [0:1:(columns-1)])
	{
		translate([x*(rackWidth+wallThickness),0,z*(rackWidth+wallThickness)])
		rack(wallThickness,rollDiameter,rackDepth,maxBridge,holderDiameter,rackWidth);
	}
}
```


[User]
I'm looking to create a customizable rippled chalice in OpenSCAD, and I want to make sure it's parametric so I can easily adjust the shape and features. I’ve seen some designs that use a function plotting library, and I think that's the way to go.

Here are the key elements I want to be able to control:

*   **Overall Dimensions:**
    *   `chalice_height`: The total height of the chalice.
    *   `chalice_width`: A base width that influences the overall size.
*   **Stem:**
    *   `stem_width_factor`: A factor that modifies the base width to create a stem-like shape.
*   **Ripples:**
    *   `ripple_intensity`: How strong the ripple effect is.
    *   `ripple_count`: The number of ripples around the chalice.
    *   `ripple_spin`: How much the ripples twist as they go up the chalice.
    *   `ripple_log_ratio` and `ripple_log_offset`: Parameters for controlling the logarithmic aspect of the ripple height change.
*   **Lip:**
    *   `perimeter`: The thickness of the lip at the top of the chalice.  I want it to have a rounded profile.

The basic shape of the chalice should be derived from a mathematical function, similar to how the provided example does with a cosine and a log function. The ripples should also be based on a mathematical function, which are added to the base shape function. I'd like the final shape to be generated using an axial plotting technique, which is where you define a radius as a function of the height and angle.

I want to be able to define the base chalice shape and the ripple function independently, then combine them, and finally round the lip. It would be fantastic if the structure of the code makes it easy to adjust the core shape or the ripple function without messing up the lip generation.

For the function plotting I would like to use a library like the one from https://www.thingiverse.com/thing:2391851. I don't need you to include that library; just make sure the main code is using it to do the axial plotting.

Could you generate the necessary OpenSCAD files for this?

[Assistant]
ripple_chalice_customizer_version.scad:
```
// Created in 2017 by Ryan A. Colyer.
// This work is released with CC0 into the public domain.
// https://creativecommons.org/publicdomain/zero/1.0/
//
// https://www.thingiverse.com/thing:2392399

perimeter = 2;
chalice_height = 150;
chalice_width = 70;
stem_width_factor = 0.7;
log_scaling_ratio = 10;
ripple_intensity = 0.12;
ripple_count = 8;
ripple_spin = 1600;
ripple_log_ratio = 100;
ripple_log_offset = 5;
function basechalice(z) =
  (chalice_width * (1 - ripple_intensity) * 0.192) *
  (cos(log(z/(chalice_height/log_scaling_ratio)+1)*360) + 1
  + stem_width_factor);
function ripple(z, ang) =
  (chalice_width * ripple_intensity * 0.192) *
  (cos(ripple_count*ang-ripple_spin*log(z/(chalice_height/ripple_log_ratio) + 1
  + ripple_log_offset))+1);
function ripplechalice(z, ang) = basechalice(z) + ripple(z, ang);
function outerlip(z, ang) = let(
  zstart = chalice_height - perimeter,
  zdiff = z - zstart,
  rstart = ripplechalice(zstart, ang),
  rend = (basechalice(zstart) - perimeter / 2),
  rrelstart = rstart - rend,
  rratio = rrelstart / perimeter)
  z < chalice_height ?
    rend + sqrt(rrelstart*rrelstart*1.0001 - zdiff*zdiff*rratio*rratio) :
    rend;

function innerlip(z, ang) = let(
  zstart = chalice_height - perimeter,
  zdiff = z - zstart,
  rstart = basechalice(zstart) - perimeter,
  rend = (basechalice(zstart) - perimeter / 2),
  rrelstart = rend - rstart,
  rratio = rrelstart / perimeter)
  z < chalice_height ?
    rend - sqrt(rrelstart*rrelstart*1.0001 - zdiff*zdiff*rratio*rratio) :
    rend;

function AxialFunc1(z, ang) = (z < chalice_height - perimeter) ?
  ripplechalice(z, ang) :
  outerlip(z, ang);
function AxialFunc2(z, ang) = (z < chalice_height - perimeter) ?
  basechalice(z) - perimeter :
  innerlip(z, ang);

module RippleChalice() {
	difference() {
  	PlotAxialFunction(1, [0, 0.4, chalice_height], 180);
  	PlotAxialFunction(2, [perimeter, 0.4, chalice_height+1], 180);
	}
}

RippleChalice();

////// copied from plot_function.scad:
////// https://www.thingiverse.com/thing:2391851

// Plots the numbered function Func1 through Func9, where FuncN is 1 through 9.
// Each function is a function of x and y.
// minx_stepx_maxx should be [minx, stepx, maxx], and likewise for y,
// specifying the domain to be plotted.
// To guarantee a properly manifold shape, the routine will only render
// strictly positive values (z>0) of the defined function.  Add an offset if
// needed to achieve this.
module PlotFunction(FuncN, minx_stepx_maxx, miny_stepy_maxy) {
  minx = minx_stepx_maxx[0];
  stepx = minx_stepx_maxx[1];
  maxx = minx_stepx_maxx[2] + 0.001*stepx;
  miny = miny_stepy_maxy[0];
  stepy = miny_stepy_maxy[1];
  maxy = miny_stepy_maxy[2] + 0.001*stepy;
  minplot = 0.0005*(stepx+stepy);

  pointarrays = concat(
    [concat(  // Close miny edge of plot.
      [[maxx, miny-0.001*stepy, 0]],
      [[minx, miny-0.001*stepy, 0]],
      [
        for (x = [minx:stepx:maxx])
          [x, miny-0.001*stepy, 0.0001]
      ]
    )],

    [ for (y = [miny:stepy:maxy])
      concat(
        [[maxx, y, 0]],
        [[minx, y, 0]],
        [
          for (x = [minx:stepx:maxx]) let(
              z = CallFunc(x, y, FuncN),
              zchecked = z < minplot ? minplot : z
            )
            [x, y, zchecked]
        ]
      )
    ],

    [concat(  // Close maxy edge of plot.
      [[maxx, maxy+0.001*stepy, 0]],
      [[minx, maxy+0.001*stepy, 0]],
      [
        for (x = [minx:stepx:maxx])
          [x, maxy+0.001*stepy, 0.0001]
      ]
    )]
  );

  PlotClosePoints(pointarrays);
}

// Plots the numbered function PolarFunc1 through PolarFunc9, where
// PolarFuncN is 1 through 9.  Each function is a function of radius and
// angle.
// max_r is the outer radius, and min_step is the smallest step size between
// points.
// To guarantee a properly manifold shape, the routine will only render
// strictly positive values (z>0) of the defined function.  Add an offset if
// needed to achieve this.
module PlotPolarFunction(PolarFuncN, max_r, min_step=-1) {
  num_circle_steps = (min_step <= 0) ? 360 :
    ceil((max_r * 2*PI / min_step) / 8)*8;
  ang_step = 360 / num_circle_steps;
  eff_minstep = (min_step <= 0) ? 2*PI*max_r/num_circle_steps : min_step;
  num_r_steps = ceil(max_r / eff_minstep);
  r_step = (max_r - 0.001*eff_minstep) / num_r_steps;
  minplot = 0.001*r_step;

  pointarrays = concat(
    [
      [ for (a = [0:ang_step:359.9999])
          [max_r * cos(a), max_r * sin(a), 0]
      ]
    ],

    [ for (r = [max_r:-r_step:0.000001*r_step])
        [ for (a = [0:ang_step:359.9999]) let(
              z = CallPolarFunc(r, a, PolarFuncN),
              zchecked = z < minplot ? minplot : z
            )
            [r * cos(a), r * sin(a), zchecked]
        ]
    ]
  );

  PlotClosePoints(pointarrays);
}

// Plots the numbered function AxialFunc1 through AxialFunc9, where
// AxialFuncN is 1 through 9.  Each function is a function of z-height and
// angle, and returns the radius outward in the xy-plane.
// max_r is the outer radius, and min_step is the smallest step size between
// points.
// minz_stepz_maxz should be [minz, stepz, maxz], and likewise for y,
// specifying the domain to be plotted.
// To guarantee a properly manifold shape, the routine will only render
// strictly positive values (r>0) of the defined function.  Add an offset if
// needed to achieve this.
module PlotAxialFunction(AxialFuncN, minz_stepz_maxz, num_circle_steps=360) {
  ang_step = 360 / num_circle_steps;
  minz = minz_stepz_maxz[0];
  stepz = minz_stepz_maxz[1];
  maxz = minz_stepz_maxz[2] + 0.001*stepz;
  minplot = 0.001*stepz;

  pointarrays = [
    for (z = [minz:stepz:maxz])
      [ for (ai = [0:num_circle_steps-1]) let(
            a = ai * ang_step,
            r = CallAxialFunc(z, a, AxialFuncN),
            rchecked = r < minplot ? minplot : r
          )
          [rchecked * cos(a), rchecked * sin(a), z]
      ]

  ];

  PlotClosePoints(pointarrays);
}

// Relays function calls to Func1 through Func9
function CallFunc(x, y, n) =
  (n == 1) ? Func1(x, y) :
  (n == 2) ? Func2(x, y) :
  (n == 3) ? Func3(x, y) :
  (n == 4) ? Func4(x, y) :
  (n == 5) ? Func5(x, y) :
  (n == 6) ? Func6(x, y) :
  (n == 7) ? Func7(x, y) :
  (n == 8) ? Func8(x, y) :
  (n == 9) ? Func9(x, y) :
  FunctionNumberOutOfRange;

// Relays function calls to PolarFunc1 through PolarFunc9
function CallPolarFunc(r, ang, n) =
  (n == 1) ? PolarFunc1(r, ang) :
  (n == 2) ? PolarFunc2(r, ang) :
  (n == 3) ? PolarFunc3(r, ang) :
  (n == 4) ? PolarFunc4(r, ang) :
  (n == 5) ? PolarFunc5(r, ang) :
  (n == 6) ? PolarFunc6(r, ang) :
  (n == 7) ? PolarFunc7(r, ang) :
  (n == 8) ? PolarFunc8(r, ang) :
  (n == 9) ? PolarFunc9(r, ang) :
  PolarFunctionNumberOutOfRange;

// Relays function calls to AxialFunc1 through AxialFunc9
function CallAxialFunc(z, ang, n) =
  (n == 1) ? AxialFunc1(z, ang) :
  (n == 2) ? AxialFunc2(z, ang) :
  (n == 3) ? AxialFunc3(z, ang) :
  (n == 4) ? AxialFunc4(z, ang) :
  (n == 5) ? AxialFunc5(z, ang) :
  (n == 6) ? AxialFunc6(z, ang) :
  (n == 7) ? AxialFunc7(z, ang) :
  (n == 8) ? AxialFunc8(z, ang) :
  (n == 9) ? AxialFunc9(z, ang) :
  AxialFunctionNumberOutOfRange;

function isfinite(x) = (!(x!=x)) && (x<(1/0)) && (x>(-1/0));

// This generates a closed polyhedron from an array of arrays of points,
// with each inner array tracing out one loop outlining the polyhedron.
// pointarrays should contain an array of N arrays each of size P outlining a
// closed manifold.  The points must obey the right-hand rule.  For example,
// looking down, the P points in the inner arrays are counter-clockwise in a
// loop, while the N point arrays increase in height.  Points in each inner
// array do not need to be equal height, but they usually should not meet or
// cross the line segments from the adjacent points in the other arrays.
// (N>=2, P>=3)
// Core triangles:
//   [j][i], [j+1][i], [j+1][(i+1)%P]
//   [j][i], [j+1][(i+1)%P], [j][(i+1)%P]
//   Then triangles are formed in a loop with the middle point of the first
//   and last array.
module PlotClosePoints(pointarrays) {
  function recurse_avg(arr, n=0, p=[0,0,0]) = (n>=len(arr)) ? p :
    recurse_avg(arr, n+1, p+(arr[n]-p)/(n+1));

  N = len(pointarrays);
  P = len(pointarrays[0]);
  NP = N*P;
  lastarr = pointarrays[N-1];
  midbot = recurse_avg(pointarrays[0]);
  midtop = recurse_avg(pointarrays[N-1]);

  faces_bot = [
    for (i=[0:P-1])
      [0,i+1,1+(i+1)%len(pointarrays[0])]
  ];

  loop_offset = 1;
  bot_len = loop_offset + P;

  faces_loop = [
    for (j=[0:N-2], i=[0:P-1], t=[0:1])
      [loop_offset, loop_offset, loop_offset] + (t==0 ?
      [j*P+i, (j+1)*P+i, (j+1)*P+(i+1)%P] :
      [j*P+i, (j+1)*P+(i+1)%P, j*P+(i+1)%P])
  ];

  top_offset = loop_offset + NP - P;
  midtop_offset = top_offset + P;

  faces_top = [
    for (i=[0:P-1])
      [midtop_offset,top_offset+(i+1)%P,top_offset+i]
  ];

  points = [
    for (i=[-1:NP])
      (i<0) ? midbot :
      ((i==NP) ? midtop :
      pointarrays[floor(i/P)][i%P])
  ];
  faces = concat(faces_bot, faces_loop, faces_top);

  polyhedron(points=points, faces=faces, convexity=8);
}

////// end copied from plot_function.scad ////

```
ripple_chalice.scad:
```
// Created in 2017 by Ryan A. Colyer.
// This work is released with CC0 into the public domain.
// https://creativecommons.org/publicdomain/zero/1.0/
//
// https://www.thingiverse.com/thing:2392399

include <plot_function.scad>  // https://www.thingiverse.com/thing:2391851

perimeter = 2;
chalice_height = 150;
chalice_width = 70;
stem_width_factor = 0.7;
log_scaling_ratio = 10;
ripple_intensity = 0.12;
ripple_count = 8;
ripple_spin = 1600;
ripple_log_ratio = 100;
ripple_log_offset = 5;
function basechalice(z) =
  (chalice_width * (1 - ripple_intensity) * 0.192) *
  (cos(log(z/(chalice_height/log_scaling_ratio)+1)*360) + 1
	+ stem_width_factor);
function ripple(z, ang) =
  (chalice_width * ripple_intensity * 0.192) *
  (cos(ripple_count*ang-ripple_spin*log(z/(chalice_height/ripple_log_ratio) + 1
  + ripple_log_offset))+1);
function ripplechalice(z, ang) = basechalice(z) + ripple(z, ang);
function outerlip(z, ang) = let(
  zstart = chalice_height - perimeter,
  zdiff = z - zstart,
  rstart = ripplechalice(zstart, ang),
  rend = (basechalice(zstart) - perimeter / 2),
  rrelstart = rstart - rend,
  rratio = rrelstart / perimeter)
  z < chalice_height ?
    rend + sqrt(rrelstart*rrelstart*1.0001 - zdiff*zdiff*rratio*rratio) :
    rend;

function innerlip(z, ang) = let(
  zstart = chalice_height - perimeter,
  zdiff = z - zstart,
  rstart = basechalice(zstart) - perimeter,
  rend = (basechalice(zstart) - perimeter / 2),
  rrelstart = rend - rstart,
  rratio = rrelstart / perimeter)
  z < chalice_height ?
    rend - sqrt(rrelstart*rrelstart*1.0001 - zdiff*zdiff*rratio*rratio) :
    rend;

function AxialFunc1(z, ang) = (z < chalice_height - perimeter) ?
  ripplechalice(z, ang) :
  outerlip(z, ang);
function AxialFunc2(z, ang) = (z < chalice_height - perimeter) ?
  basechalice(z) - perimeter :
  innerlip(z, ang);

module RippleChalice() {
	difference() {
  	PlotAxialFunction(1, [0, 0.4, chalice_height], 180);
  	PlotAxialFunction(2, [perimeter, 0.4, chalice_height+1], 180);
	}
}

RippleChalice();

```


[User]
I want to design a sanding block that doesn't use screws to hold the sandpaper. I've seen a couple of designs that do this by using a combination of a block and a wedge. I'd like to be able to customize the block's dimensions and also have the option to print just the wedge for another project.

Here are the specific features I'm looking for:

1.  **Parametric Design:** Everything needs to be configurable, like the width, height, and length of the main block, and the paper thickness.
2.  **Main Block:** This part should have a main rectangular body, but with a space cut into it to hold the sandpaper and a wedge. This space for the paper and wedge should use the hull() function so that all edges are smooth.
3.  **Paper Insert:** The paper should fit into a slot cut into the block, angled slightly to help grip it. I want to control the size of this slot using the paperThickness variable.
4.  **Wedge:** This part should be separate from the block, and I want to be able to generate it on its own. The wedge should be designed to fit securely into the space created in the block.
5.  **Combined Printing:** I'd also like an option to print both the block and wedge together, for testing and to be able to print both together at once.
6.  **Module-Based:** Please organize the code using modules to keep it tidy, ideally with separate modules for the block and wedge and an overall "print\_part" module.
7.  **Units:** all dimensions should be in millimeters.

I'd like to control the printed object using a `part` variable which can be either `first` to print just the main block, `second` for just the wedge, or `both` to print both.

Could you generate the necessary OpenSCAD files for me? I don't use any external libraries, so no need to import anything.

[Assistant]
sanding-block.scad:
```
part = "both";  // [first:Block only,second:Wedge only,both:Block and wedge]

width = 10; // [1:1:200]
height = 15; // [10:1:100]
length = 140; // [40:1:300]
paperThickness = 0.45; // [0.05:0.05:2]

/* [HIDDEN] */
$fs=0.5;

module wedge(width)
{
	hull()
	{
		translate([0,0,-15]) rotate([90,0,0]) cylinder(h=width,d=5,center=true);
		rotate([90,0,0]) cylinder(h=width,d=2,center=true);
	}
}

module block(width,height,length,paperThickness)
{
	difference()
	{
		difference()
		{
			/* MAIN BLOCK */
			hull()
			{
				rotate([90,0,0]) cylinder(h=width,d=1,center=true);
				translate([length-height/2,0,height/2])
					rotate([90,0,0])
					cylinder(h=width,d=height,center=true);
			}

			/* PAPER INSERT */
			translate([(length-height/2)*0.7,0,-2])
				rotate([0,-30,0])
				cube([paperThickness*2,width*1.1,15],center=true);
		}

		/* WEDGE INSERT */
		translate([(length-height/2)*0.9,0,6])
			rotate([0,30,0])
			wedge(width*1.1);
	}
}

module print_part(part)
{
	if (part == "first")
	{
		translate([0,0,width/2]) rotate([90,0,0]) block(width,height,length,paperThickness);
	}
	else if (part == "second")
	{
		translate([0,0,width/2]) rotate([90,0,-90]) wedge(width);
	}
	else if (part == "both")
	{
		translate([0,0,width/2]) rotate([90,0,0]) block(width,height,length,paperThickness);
		translate([15,15,width/2]) rotate([90,0,90]) wedge(width);
	}
	else
	{
		translate([0,0,width/2]) rotate([90,0,0]) block(width,height,length,paperThickness);
		translate([15,15,width/2]) rotate([90,0,90]) wedge(width);
	}
}

print_part(part);

```


[User]
Hi, I'm looking to generate a customizable bracket for a 3D printer, specifically one that can be used as a dual-z motor mount or a regular single-z bracket depending on the parameters I set. I've got some specific requirements for how I want to be able to adjust it.

First, I'd like to be able to mirror the entire design along the Y axis so I can create a left or right version for dual z-axis setups. I also want the option to add a small text label to the bracket, and toggle the visibility of it.

The bracket needs to have a base and a profile mount. I'll need to be able to control the wall width and edge radius for the whole bracket, and then separately, I need to control the base width and edge radius. I'd like to be able to set the overall height of the bracket, and also the height of the optional motor mount if I decide to include it. The motor mount itself would sit on top of the profile.

For the profile, I need to specify the horizontal (y and z) and vertical (x and y) profile widths. It also needs to have holes for nuts, which need to be configurable. Specifically, I need to specify the number of horizontal nut rows along the Z-axis, and the number of vertical nut rows along both the x and y-axis directions. I need to be able to control the distance between the nut holes, and the radius of the holes themselves.

If the motor mount is included, it needs to have mounting holes for a Nema motor. I need to be able to set the motor hole radius as well as the radius of the motor mount holes and their diffusity, or spread between them.

I’m aiming to control the cylinder quality with a "quality" parameter.

I’m thinking I want to generate all of this as a single .scad file.

Could you generate the necessary OpenSCAD code?

[Assistant]
rbase_bracket.scad:
```

// Motor mount
add_motor=1; // [0:No, 1:Yes]
// Mirror everything
mirror_all=1; // [0:No, 1:Yes]
// Add or remove label
label=1; // [0:Remove, 1:Show]

// Wall width [mm]
wall_width = 3; // [1:0.1:8]
// Wall edge radius [mm]
edge_radius = 12; // [0:16]
// Base width [mm]
base_width = 2; // [1:0.1:8]
// Base edge radius [mm]
base_edge_radius = 6; // [0:16]
// Bracket height [mm]
height = 65; // [20:120]
// Motor mount height [mm]
motor_height = 50; // [40:120]

// Horizontal Profile - y Width [mm]
h_profile_y = 40; // [20:10:80]
// Horizontal Profile - z Width [mm]
h_profile_z = 20; // [20:10:80]
// Vertical Profile - x Width [mm]
v_profile_x = 40; // [20:10:80]
// Vertical Profile - y Width [mm]
v_profile_y = 20; // [20:10:80]

// Horizontal Profile Z Nut Rows
h_nuts_z = 1; // [1:1:4]
// Vertical Profile X Nut Rows
v_nuts_x = 2; // [1:1:4]
// Vertical Profile Y Nut Rows
v_nuts_y = 1; // [1:1:4]

// Nut hole distance [mm]
nut_distance = 18; // [6:1:60]
// Nut hole radius [mm]
nut_radius = 2; // [1:0.1:4]

// Motor hole radius [mm]
motor_hole_radius = 12; // [10:15]
// Motor mount holes radius [mm]
motor_mount_radius = 2; // [1:4]
// Motor mount diffusivity [mm]
motor_mount_holes_diffusity = 6; // [0:10]

// Cylinder edges (quality)
quality = 8; // [3:1:48]

translate([0,0,2*base_width])
if(mirror_all==1) {
    mirror([0,1,0])
    union(){
        difference(){
            profile_mount();
            fixation_holes();
            signature();
        }
        if(add_motor==1) {
            difference(){
                motor_mount();
                motor_mount_holes();
            }
        }
    }

}else {
    difference(){
        profile_mount();
        fixation_holes();
        signature();
    }
    if(add_motor==1) {
        difference(){
            motor_mount();
            motor_mount_holes();
        }
    }

}

module signature(){
    if(label==1) {
        if(mirror_all){
            translate([35,-15,base_width-3])
            rotate([0,0,180])
            mirror([0,1,0])
            linear_extrude(height=4)
            text("flxdev", 8, "sansserif");
        }else{
            translate([7,-15,base_width-3])
            linear_extrude(height=4)
            text("flxdev", 8, "sansserif");
        }
    }
}

module fixation_holes() {
    if(add_motor==0){
        translate([10,v_profile_y+height-10+base_edge_radius,0])
        translate([0,0,-3*base_width])
        cylinder(r=3,h=4*base_width, $fn=quality);

        translate([v_profile_x+height-h_profile_z+base_edge_radius/2-10,v_profile_y+height-10+base_edge_radius,0])
        translate([0,0,-3*base_width])
        cylinder(r=3,h=4*base_width, $fn=quality);
    }

    translate([10,-1/1.5*height+10,0])
    translate([0,0,-3*base_width])
    cylinder(r=3,h=4*base_width, $fn=quality);

    translate([v_profile_x+height-h_profile_z+base_edge_radius/2-10,-1/1.5*height+10,0])
    translate([0,0,-3*base_width])
    cylinder(r=3,h=4*base_width, $fn=quality);
}

module motor_mount(){
    // wall_base
    translate([0,v_profile_y+2*wall_width,0])
    cube([wall_width,v_profile_y,motor_height-wall_width]);

    // wall_motor
    translate([0,h_profile_y+2*wall_width,-2*base_width])
    cube([wall_width,50,motor_height+base_width]);

    translate([50-wall_width,h_profile_y+2*wall_width,-2*base_width])
    cube([wall_width,50,motor_height+base_width]);

    // wall_to_bracket
    translate([v_profile_x+wall_width,h_profile_y+wall_width,h_profile_z])
    cube([50-v_profile_x-wall_width,wall_width,motor_height-h_profile_z]);

    // roof_motor
    translate([0,h_profile_y+2*wall_width,motor_height-wall_width])
    cube([50,50,wall_width]);

    // roof_base
    translate([0,v_profile_y+2*wall_width,motor_height-wall_width])
    cube([v_profile_x,h_profile_y-v_profile_y,wall_width]);

    hull(){
        translate([v_profile_x,v_profile_y+2*wall_width,0])
        cube([wall_width,h_profile_y-v_profile_y,motor_height]);

        // Upper cylinder
        translate([v_profile_x+wall_width,v_profile_y+2*wall_width,height-edge_radius])
        rotate([90,0,-90])
        difference(){
            cylinder(r=edge_radius, h=wall_width);
            translate([0, -edge_radius-0.1, 0])
            cube([edge_radius+0.1, edge_radius*2+0.2, wall_width*2]);
        }
    }
}

module motor_mount_holes(){
    translate([50/2,50/2+h_profile_y+motor_mount_holes_diffusity/2,motor_height-1.5*wall_width])
    union(){
        hull(){
            cylinder(r=motor_hole_radius, h=2*wall_width);
            translate([0,motor_mount_holes_diffusity,0])
            cylinder(r=motor_hole_radius, h=2*wall_width);
        }

        hull(){
            translate([-31/2,-31/2,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
            translate([-31/2,-31/2+motor_mount_holes_diffusity,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
        }

        hull(){
            translate([-31/2,+31/2,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
            translate([-31/2,+31/2+motor_mount_holes_diffusity,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
        }

        hull(){
            translate([+31/2,+31/2,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
            translate([+31/2,+31/2+motor_mount_holes_diffusity,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
        }

        hull(){
            translate([+31/2,-31/2,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
            translate([+31/2,-31/2+motor_mount_holes_diffusity,0])
            cylinder(r=motor_mount_radius, h=2*wall_width);
        }
    }
}

module profile_mount(){
    base();

    difference(){
        union(){
            planar_side();
            non_planar_side();

            translate([0,0,0])
            cube([wall_width,v_profile_y+2*wall_width,height]);
        }
        v_nuts();
        h_nuts();
    }
}

module h_nuts(){
    for(k = [0:1:1]){
        translate([0,k*(h_profile_y+wall_width),0])
        for(j = [0:1:h_nuts_z-1]){
            translate([])
            for(i = [0:nut_distance:((height-h_profile_z)-h_profile_z/2-wall_width)]) {
                translate([i+wall_width+v_profile_x+h_profile_z/2,0-wall_width/2,h_profile_z/h_nuts_z/2+j*h_profile_z/h_nuts_z])
                rotate([-90,0,0])
                cylinder(r=nut_radius, h=wall_width*2);
            }
        }
    }
}

module non_planar_side(){
    // Connection
    if(add_motor==0)
        stabilizer();
    // Small
    hull(){
        translate([wall_width+v_profile_x,wall_width+h_profile_y,0])
        cube([(height-h_profile_z),wall_width,h_profile_z-edge_radius]);

        translate([wall_width+v_profile_x,wall_width+h_profile_y,0])
        cube([(height-h_profile_z)-edge_radius,wall_width,h_profile_z]);

        translate([height+v_profile_x-h_profile_z-edge_radius+wall_width,2*wall_width+h_profile_y,h_profile_z-edge_radius])
        rotate([90,-90,0])
        difference(){
            cylinder(r=edge_radius, h=wall_width);
            translate([-edge_radius,-edge_radius,-0.1])
            cube([edge_radius,2*edge_radius, wall_width+0.2]);

            translate([0,0,-0.1])
            cube([edge_radius,2*edge_radius, wall_width+0.2]);
        }
    }

    // Tall
    translate([wall_width,v_profile_y+wall_width,0])
    cube([v_profile_x,wall_width,height]);
}

module stabilizer() {
    hull(){
        translate([v_profile_x,v_profile_y+2*wall_width,0])
        cube([wall_width,h_profile_y-v_profile_y,h_profile_z]);

        // Upper cylinder
        translate([v_profile_x+wall_width,v_profile_y+2*wall_width,height-edge_radius])
        rotate([90,0,-90])
        difference(){
            cylinder(r=edge_radius, h=wall_width);
            translate([0, -edge_radius-0.1, 0])
            cube([edge_radius+0.1, edge_radius*2+0.2, wall_width*2]);
        }
        // Lower cylinder
        translate([v_profile_x,edge_radius+v_profile_y+height-2*edge_radius+2*wall_width,0])
        rotate([90,90,90])
        difference(){
            cylinder(r=edge_radius, h=wall_width);
            translate([0, -edge_radius-0.1, 0])
            cube([edge_radius+0.1, edge_radius*2+0.2, wall_width*2]);
        }
    }
}

module planar_side(){
    translate([+v_profile_x,0,0])
    scale([1,1/1.5,0.85])
    rotate([0,0,180])
    translate([-v_profile_x-wall_width,-v_profile_y-2*wall_width,0])
    stabilizer();

    hull(){
        translate([height+v_profile_x-h_profile_z-edge_radius+wall_width,wall_width,h_profile_z-edge_radius])
        rotate([90,-90,0])
        difference(){
            cylinder(r=edge_radius, h=wall_width);
            translate([-edge_radius,-edge_radius,-0.1])
            cube([edge_radius,2*edge_radius, wall_width+0.2]);

            translate([0,0,-0.1])
            cube([edge_radius,2*edge_radius, wall_width+0.2]);
        }

        translate([wall_width+v_profile_x-edge_radius,0,height-edge_radius])
        rotate([-90,0,0])
        cylinder(r=edge_radius, h=wall_width);

        translate([wall_width,0,0])
        cube([v_profile_x-edge_radius,wall_width,height]);

        translate([wall_width,0,0])
        cube([height+v_profile_x-h_profile_z,wall_width,h_profile_z-edge_radius]);
    }
}

module base(){
    translate([base_edge_radius,base_edge_radius-height/1.5,-2*base_width])
    minkowski() {
        cylinder(r=base_edge_radius, h=base_width, $fn=16);
        if(add_motor==1){
            cube([
                v_profile_x+wall_width+(height-h_profile_z)-2*base_edge_radius,
                -2*base_edge_radius+h_profile_y+2*wall_width+1/1.5*height+base_edge_radius,
                base_width
            ]);
        }
        else{
            cube([
                v_profile_x+wall_width+(height-h_profile_z)-2*base_edge_radius,
                1/1.5*height-2*base_edge_radius+2*wall_width+h_profile_y+height-(h_profile_y-v_profile_y),
                base_width
            ]);
        }
    }
}

module v_nuts(){
    for(k = [0:1:1]){
        translate([0,k*(v_profile_y+wall_width),0])
        for(j = [0:1:v_nuts_x-1]){
            translate([j*v_profile_x/v_nuts_x+v_profile_x/v_nuts_x/2+wall_width,-wall_width/2,0])
            v_nuts_line();
        }
    }

    for(j = [0:1:v_nuts_y-1]){
        translate([1.5*wall_width,j*v_profile_y/v_nuts_y+wall_width+v_profile_y/v_nuts_y/2])
        rotate([0,0,90])
        v_nuts_line();
    }
}

module v_nuts_line(){
    for(i = [nut_distance/2+nut_radius:nut_distance:height-nut_distance/2-wall_width]){
        translate([0,0,i])
        rotate([-90,0,0])
        cylinder(r=nut_radius, h=wall_width*2);
    }
}
```


[User]
Hi there! I'm looking for some help designing a parametric reading light that uses a smartphone's flashlight. I've been playing around with OpenSCAD and I think I can roughly visualize what I want, but I'd like an expert to make it a bit more robust.

The design will have a base that holds the phone, a cylindrical light guide, a diffusor, and a cap to secure the whole thing together. I'll need this to be adjustable to fit different phone sizes, flashlight positions and desired overall dimensions.

**Phone Settings:**

I'd like to control the phone's dimensions with the following parameters:
*   `phone_width` (mm)
*   `phone_height` (mm)
*   `phone_length` (mm)
*   `light_position_left` (distance of light from left edge, mm)
*   `light_position_top` (distance of light from top edge, mm)

**Base Settings:**

The base will have a few properties to manage:
*   `w` (wall width, mm)
*   `book_clamp_size` (length of the book clamp, mm)
*  `book_clamp_height` (height of the book clamp, mm)

**Cylinder Settings:**

This is the cylinder that will carry the light from the phone. I need to configure:
*   `light_radius` (inner radius, mm)
*   `light_wall_width` (wall thickness, mm)
*   `light_cylinder_height` (height of cylinder, mm)
*   `cylinder_mount_tolerance` (tolerance for cylinder mount, relative to diameter, %)
*   `quality` (number of edges for cylinder, determines smoothness)

**Diffusor Settings:**

This part will spread the light:
*   `diffusor_height` (mm)
*  `diffusor_width` (mm)
*   `angle` (diffusion angle, degrees)

**Cap Settings:**

Finally, the cap will secure the device:
*   `cap_tolerance` (tolerance in x and z, mm)
*   `cap_fixation_radius` (radius of fixation points, mm)
*   `cap_fixation_tolerance` (tolerance of fixation points, mm)
*   `logo_scale` (scale of the logo, relative to phone_width, %)
*   `logo_filename` (filename for logo)

Also, it would be helpful to be able to see each individual part separately, or see them assembled. I think a "show" parameter with the following values would do:
* `show = 0` (All + Assembled)
* `show = 1` (Base)
* `show = 2` (Cylinder)
* `show = 3` (Diffusor)
* `show = 4` (Cap)

I'd also need a module called `cap_fixation` that takes `cap_tolerance` and `fixation_tolerance` as parameters and uses cylinders to create the fixation points on the cap.

I believe that's everything!  I'd like to avoid relying on external libraries. Let me know if you have questions!

[Assistant]
reading_mobile_phone_lamp.scad:
```
/* [Visibility] */
// Show Part
show = 0; // [0:All+Assembled, 1:Base, 2:Cylinder, 3:Diffusor, 4:Cap]

/* [Phone Settings] */
// Phone Width [mm]
phone_width = 65; // [1:0.5:150]
// Phone Height [mm]
phone_height = 10; // [1:30]
// Phone Length [mm]
phone_length = 130; // [1:300]
// Phone Light Position from left edge [mm]
light_position_left = 22; // [1:150]
// Phone Light Position from top edge [mm]
light_position_top = 11; // [1:300]

/* [Base Settings] */
// Wall width [mm]
w = 1.5; // [1:5]
// Book clamp length [mm]
book_clamp_size = 40;
// [mm] (Should be greater then wall width because of cap)
book_clamp_height = 5; // [1:20]

/* [Cylinder Settings] */
// Cylinder inner radius [mm]
light_radius = 3; // [0.1:6]
// Cylinder Wall Width [mm]
light_wall_width = 1.2;
// Cylinder Height [mm]
light_cylinder_height = 80;
// Relative to diameter [%]
cylinder_mount_tolerance = 1.1;
// Cylinder quality [number of edges]
quality = 32;

/* [Diffusor Settings] */
// Diffusor Height [mm] (total height: +2*wall_width)
diffusor_height = 4;
// Diffusor Width [mm]
diffusor_width = 20;
// Diffusor Angle [degree]
angle = 90;

/* [Cap Settings] */
// Cap Tolerance in x and z [mm]
cap_tolerance = 0.4;
// Cap Fixation Radius [mm]
cap_fixation_radius = 0.6;
// Cap Fixation Tolerance (Radius+x) [mm]
cap_fixation_tolerance = 0.6;
// Logo scale, relative to phone_width [%]
logo_scale = 1; // [0:1]
// Logo Image
logo_filename = "book2.png"; // [image_surface:200x200]

cap_length = phone_length-(light_position_top+light_radius+w)-w;
cap_offset = light_position_top+light_radius+2*w;

if(show==0){
    base();
    lamp();
    cylinder_mount();
    translate([100,0,0])
    cap();
}else if(show==1){
    translate([0,0,w])
    rotate([90,0,0])
    base();
}
else if(show==2){
    translate([0,0,-w])
    cylinder_mount();
}
else if(show==3){
    rotate([90,0,0])
    translate([0,0,-light_cylinder_height])
    lamp();
}
else if(show==4){
    translate([0,0,phone_length+w])
    rotate([-90,0,0])
    cap();
}

module cylinder_mount(){
    difference(){
        light_cylinder();
        light_hole();
    }
}

module cap(){
    logo_size = (phone_width+2*w)*logo_scale;
    logo_y_pos = phone_length-(logo_size)/2-(phone_width+2*w-(logo_size))/2;
    translate([(phone_width+3*w)/2,logo_y_pos,2*w+2*cap_tolerance-0.3])
    resize(newsize=[logo_size,logo_size,0.3])
    rotate([0,0,180])
    surface(file = logo_filename, center=true, invert=false);

    difference(){
        union(){
            // Top
            translate([0,cap_offset,w+2*cap_tolerance])
            cube([phone_width+2*w+2*cap_tolerance, cap_length, w]);
            // Top
            translate([0,cap_offset,-phone_height-2*w])
            cube([phone_width+2*w+2*cap_tolerance, cap_length, w]);
            // right
            translate([-w,cap_offset,-phone_height-2*w])
            cube([w, cap_length,phone_height+4*w+2*cap_tolerance]);
            // right
            translate([phone_width+2*w+2*cap_tolerance,cap_offset,-phone_height-2*w])
            cube([w, cap_length,phone_height+4*w+2*cap_tolerance]);
            // front
            translate([-w,phone_length,-phone_height-2*w])
            cube([phone_width+4*w+2*cap_tolerance, w,phone_height+4*w+2*cap_tolerance]);

            translate([phone_width/2-4,cap_offset+10,0])
            cap_fixation(cap_tolerance, 0);
            translate([phone_width/2-4,cap_offset+20,0])
            cap_fixation(cap_tolerance, 0);
            translate([phone_width/2-4,cap_offset+30,0])
            cap_fixation(cap_tolerance, 0);
        }
        translate([(phone_width+3*w)/2,logo_y_pos,2*w+2*cap_tolerance-0.2])
        cube([logo_size,logo_size,0.5], center=true);
    }
}

module cap_fixation(cap_tolerance, fixation_tolerance) {
    translate([0,0,w+2*cap_tolerance])
    rotate([0,90,0])
    cylinder(r=cap_fixation_radius+fixation_tolerance,h=15,$fn=quality);

    translate([0,0,-phone_height-w])
    rotate([0,90,0])
    cylinder(r=cap_fixation_radius+fixation_tolerance,h=15,$fn=quality);
}

module lamp(){
    difference(){
        translate([0,0,2*w])
        union(){

            translate([phone_width-light_position_left-1.5-(light_radius+2),light_position_top,light_cylinder_height-2*w-book_clamp_height])
            hull(){
                cylinder(r=light_radius+light_wall_width+2,h=book_clamp_height+w);
                translate([3,0,0])
                cylinder(r=light_radius+light_wall_width+2,h=book_clamp_height+w);
            }
            translate([0,-w,0])
            union(){
                // Top
                translate([-w,light_position_top-light_radius-light_wall_width,light_cylinder_height+diffusor_height])
                cube([phone_width+2*w, diffusor_width, w]);

                // Bottom
                translate([-w,light_position_top-light_radius-light_wall_width,light_cylinder_height-w-0.1])
                cube([phone_width+2*w, diffusor_width, w]);

                // left
                translate([phone_width+w,light_position_top-light_radius-light_wall_width,light_cylinder_height+w/2])
                hull(){
                    translate([0,0,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                    translate([sin(angle)*diffusor_height,0,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([sin(angle)*diffusor_height,diffusor_width+sin(angle)*diffusor_height,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([0,diffusor_width,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                }
                // back
                translate([-w,light_position_top-light_radius-light_wall_width,light_cylinder_height+w/2])
                hull(){
                    translate([phone_width+2*w,0,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                    translate([sin(angle)*diffusor_height+phone_width+2*w,0,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([-sin(angle)*diffusor_height,0,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([0,0,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                }

                // front
                translate([-w,light_position_top-light_radius-light_wall_width+diffusor_width,light_cylinder_height+w/2])
                hull(){
                    translate([phone_width+2*w,0,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                    translate([sin(angle)*diffusor_height+phone_width+2*w,sin(angle)*diffusor_height,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([-sin(angle)*diffusor_height,sin(angle)*diffusor_height,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([0,0,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                }

                // right
                translate([-w,light_position_top-light_radius-light_wall_width,light_cylinder_height+w/2])
                hull(){
                    translate([0,0,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                    translate([-sin(angle)*diffusor_height,0,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([-sin(angle)*diffusor_height,diffusor_width+sin(angle)*diffusor_height,-w])
                    sphere(r=w/2, $fn=quality);
                    translate([0,diffusor_width,diffusor_height])
                    sphere(r=w/2, $fn=quality);
                }
            }

        }
        light_cylinder(cylinder_mount_tolerance);
        light_hole();
    }

}

// Light cylinder
module light_cylinder(mount_scale){
    translate([phone_width-light_radius-light_position_left,light_position_top,w])

    scale([mount_scale,mount_scale,1])
    cylinder(r=light_radius+light_wall_width, h=light_cylinder_height, $fn=quality);
    // Light hole
    //translate([phone_width-light_radius-light_position_left,light_position_top,-0.1])
    //cylinder(r=light_radius, h=lamp_height+w, $fn=quality);

    // Fix Bottom
    translate([phone_width-light_position_left+w-2*(light_radius+light_wall_width)-3, light_position_top-1, w])
    cube([4,2,book_clamp_height+w+0.1]);

    // Fix top
    translate([phone_width-light_position_left+w-2*(light_radius+light_wall_width)-3, light_position_top-1, w+light_cylinder_height-book_clamp_height-w-0.1])
    cube([4,2,book_clamp_height+w+0.1]);
}

module light_hole(){
    translate([phone_width-light_radius-light_position_left,light_position_top,-0.1])
    cylinder(r=light_radius, h=light_cylinder_height+2*w+0.2, $fn=quality);
}

module base(){

    difference(){
        union(){
            // Book clamp
            translate([-w, light_position_top+light_radius, w+book_clamp_height])
            cube([phone_width+2*w, book_clamp_size, w]);

            translate([-w, light_position_top+light_radius, w])
            cube([phone_width+2*w, 2*w, book_clamp_height]);

            /* Phone fix
            translate([phone_width/2-10,0,-phone_height-w])
            cube([20,phone_length,w]);
            translate([phone_width/2-10,phone_length,-phone_height-w])
            cube([20,w,8]);*/

            // Phone Box
            translate([-w,-w,-phone_height-w])
            cube([phone_width+2*w, w, phone_height+2*w]);

            translate([phone_width,0,-phone_height-w])
            cube([w, phone_length/2, phone_height+2*w]);

            translate([-w,0,-phone_height-w])
            cube([w, phone_length/2, phone_height+2*w]);

            // Phone Top
            cube([phone_width,phone_length/2,w]);

            // Phone Bottom
            translate([0,0,-phone_height-w])
            cube([phone_width,phone_length/2,w]);

            translate([-w, -w, w])
            cube([phone_width+2*w, light_position_top+light_radius+w, book_clamp_height+w]);
        }
        light_cylinder(1.1);
        light_hole();
        translate([phone_width/2-7.5,cap_offset+10,0])
        cap_fixation(0, cap_fixation_tolerance);
        translate([phone_width/2-7.5,cap_offset+20,0])
        cap_fixation(0, cap_fixation_tolerance);
        translate([phone_width/2-7.5,cap_offset+30,0])
        cap_fixation(0, cap_fixation_tolerance);
    }
}
```


[User]
Hey, I'm looking to create a customizable polygonal picture frame generator in OpenSCAD. I've already got a basic version working, but it's a bit clunky and I think you could probably do a much better job.

Here's what I'm envisioning:

**Core Functionality:**

*   **Polygonal Frame:** The core of it is a frame that can be any number of sides, from 3 up to at least 48.
*   **Mitered Joints:** Each side should be connected with mitered joints, and the outside length of each side should be adjustable.
*  **Units:** Allow users to input values in either millimeters or inches.
*   **Rabbit Cut:** I need an option to add a rabbit cut on the back of the frame for holding glass and artwork. This rabbit cut's width and depth should be adjustable, and it would be great to have an option to add a 45-degree chamfer for easier 3D printing.
*   **Base Thickness:** An optional base thickness should be configurable, so you can make the frame a solid piece instead of an open frame.

**Custom Profile:**
*  **Profile Dimensions:** The ability to specify a width and a thickness for a basic rectangular profile is needed
*   **Customizable Cuts:** This is where I want to get fancy. I need the ability to add a variety of cuts to the profile, with the option to turn them off. These cuts would be relative to the profile's top surface, not an overall coordinate system. Specifically:
    *   **Outside Edge Cut:** This cut should be able to be a specified radius, either with a number of facets or with a full rounded edge.  It needs an adjustable depth.
    *   **Inside Edge Cut:**  Similar to the outside edge cut but on the inside edge of the profile with adjustable depth and also should be able to be a specified radius, either with a number of facets or with a full rounded edge.
    *   **Center Cut:** This needs to be a circle cut along the center of the profile, with adjustable radius and depth.
    *   **Middle to Outside Cut:**  A circle cut between the center and the outside edge, with an adjustable radius, depth, and an offset from the center.
    *   **Middle to Inside Cut:** A circle cut between the center and the inside edge, with adjustable radius, depth, and offset from center.
    *   **Miter Cut:** A cut on the miter joint of each frame piece. This needs to be able to be a variable depth and radius.

**Libraries**

I'd like you to write this using the BOSL2 library for all the transformations.  I would also want you to incorporate the `segments()` function from the `dotSCAD` library for controlling the resolution of the cuts.

**Output**

I'm looking for a single OpenSCAD file that can generate any of the described frame variations. I think it's really important to have a modular design so it's easy to understand. It would be cool if you could make the modules as flexible as possible so they can be reused later. And please make it so the profiles for the frame are built relative to the top plane, not some global origin - that makes things easier to visualize.

I think that about covers everything.  Let me know if you have any questions.

[Assistant]
PolygonalFrame_mm_Rev29.scad:
```
//Polygonal Picture Frame based on Moulding Profile
//DXF Profiles used from this source:
//http://www.hornermillwork.com/cad-library/mouldings
//
//Openscad File created by: David Bunch 6/16/2017
//
/* [Main Variables] */
//A_Type = [108,211,260,3974,3975];
// Type of Frame to Use (DXF files will not work with Customizer)
//Type = -1;       //[-1:Custom,0:N-108.dxf,1:N-211.dxf,2:N-260.dxf,3:N-3974.dxf,4:N-3975]

//1. Units (mm or Inches)
Units = 1;          //[1:mm,25.4:inches]

//2. Number of Sides of Polygon
Sides = 8;          //[2:1:48]
                    //If less than 3 sides, it will draw only 1 Moulding without miter cuts
//3. Length of the outside Mitered side
Ln = 100;                   //[10:2:500]

//4. Optional Base Thickness
B_Thick = 0;     //[0:.5:12]

//5. Default Facet Resolution
I_Res = 24;         //[4:4:96]

/* [Rabbit Cuts] */

//6. Add Rabbit Cut
Rabbit_Cut_On = 1;      //[0:No,1:Yes]

//7. Width of Rabbit Cut
Rab_Cut_Wid = 6;     //[.5:.5:20]

//8. Depth of Rabbit Cut
Rab_Cut_Depth = 4;   //[.5:.5:20]

//9. Chamfer Top 45 degrees for 3d Printing
Rabbit_Chamfer_ON = 0;  //[0:No,1:Yes]

// -------------------------------------------
// Prefix variables Pr_ are used if Type = -1
// -------------------------------------------

/* [Custom Profiles] */

//10. Width of Profile
Pr_Wi = 38.0;          //[10:1:80]

//11. Thickness of Profile
Pr_Th = 19.0;         //[2:1:50]

/* [Custom Outside Edge Cut] */

//12. Outside Edge Cut (0=None, -1 = Rounded or # of Facets)
Pr_Out_Edge = -1;       //[-1:1:48]
                        //-1 = Rounded Top Edge instead of Chamfer of Fillet Cut

//13. Outside Edge Radius Cut
Pr_O_Rad = 6.4;       //[6.4:.2:16]

//14. Depth of Outside Edge Cut
Pr_O_Depth = 6.4;     //[0:.2:16]

/* [Custom Inside Edge Cut] */

//15. Inside Edge Cut (0=None, -1 = Rounded or # of Facets)
Pr_In_Edge = 4;         //[-1:1:48]
                        //-1 = Rounded Top Edge instead of Chamfer of Fillet Cut

//16. Inside Edge Radius Cut
Pr_I_Rad = 6.4;        //[6.4:.2:16]

//17. Depth of Outside Edge Cut
Pr_I_Depth = 6.4;        //[0:.2:16]

/* [Custom Center Cut] */

//18. Center Cut (0=None or # of Facets)
Pr_Cen = 0;            //[0:1:48]

//19. Inside Edge Radius Cut
Pr_Ce_Rad = 6.4;       //[6.4:.2:16]

//20. Depth of Center Cut
Pr_Ce_Depth = 4;       //[0:.5:12]

/* [Custom Middle towards Outside Cut] */

//21. Between Center & Outside Edge (0=None or # of Facets)
Pr_Mid_Out = 0;         //[0:1:48]
                        //# = Number of facets on Cuts

//22. Middle to Outside Edge Radius Cut
Pr_Mid_O_Rad = 3.2;   //[3.2:.2:12]

//23. Depth of Middle to Outside Edge Cut
Pr_Mid_O_Depth = 1;   //[0:.5:12]

//24. Offset from Center line of Moulding towards Outside Edge
Pr_Mid_O_Offset = 12; //[1:1:40]

/* [Custom Middle towards Inside Cut] */

//25. Between Center & Inside Edge (0=None # of Facets)
Pr_Mid_In = 0;          //[0:1:48]
                        //# = Number of facets on Cuts

//26. Middle to Inside Edge Radius Cut
Pr_Mid_I_Rad = 3.2;    //[3.2:.2:12]

//27. Depth of Middle to Inside Edge Cut
Pr_Mid_I_Depth = 1;    //[0:.5:12]

//28. Offset from Center line of Moulding towards Inside Edge
Pr_Mid_I_Offset = 10;  //[1:1:40]

/* [Custom Cut along Miter Joint] */

//29. Cut Along Miter Edge (0=None # of Facets)
Pr_Miter_Edge = 0;      //[0:1:48]
                        //# = Number of facets on Cuts

//30. Miter Edge Radius Cut
Pr_Mit_Rad = 12;      //[6:1:32]

//31. Depth of Miter Edge Cut
Pr_Mit_Depth = 2;     //[0:.5:12]

//32. Depth of Miter Edge Cut
Pr_Mit_Cut_Len = 200;   //[100:20:400]
// -------------------------------------------

/* [Hidden] */
Type = -1;       //[-1:Custom,0:N-108.dxf,1:N-211.dxf,2:N-260.dxf,3:N-3974.dxf,4:N-3975]
Len = Ln / Units;
Base_Thick = B_Thick / Units;

Rabbit_Cut_Wid = Rab_Cut_Wid / Units;
Rabbit_Cut_Depth = Rab_Cut_Depth / Units;

Pr_Wid = Pr_Wi / Units;
Pr_Thk = Pr_Th / Units;

Pr_Out_Rad = Pr_O_Rad / Units;
Pr_Out_Depth = Pr_O_Depth / Units;

Pr_In_Rad = Pr_I_Rad / Units;
Pr_In_Depth = Pr_I_Depth / Units;

Pr_Mid_Out_Rad = Pr_Mid_O_Rad / Units;
Pr_Mid_Out_Depth = Pr_Mid_O_Depth / Units;
Pr_Mid_Out_Offset = Pr_Mid_O_Offset / Units;

Pr_Cen_Rad = Pr_Ce_Rad / Units;
Pr_Cen_Depth = Pr_Ce_Depth / Units;

Pr_Mid_In_Rad = Pr_Mid_I_Rad / Units;
Pr_Mid_In_Depth = Pr_Mid_I_Depth / Units;
Pr_Mid_In_Offset = Pr_Mid_I_Offset / Units;

Pr_Miter_Rad = Pr_Mit_Rad / Units;
Pr_Miter_Depth = Pr_Mit_Depth / Units;
Pr_Miter_Cut_Len = Pr_Mit_Cut_Len / Units;
Pr_Miter_Cut_Len = Pr_Mit_Cut_Len / Units;

//Used for Cutting the tops of the Miter joints
Max_Pr_Wid = 200;       //Maximum Width of Profiles
Max_Pr_Thk = 200;       //Maximum Thickness of Profiles

Ang1 = 360 / Sides;
Ang2 = Ang1 / 2;
Ang3 = 90 - Ang2;

Len2 = Len / 2;
Wid2 = Len2 / tan(Ang2);

Rad = Len2 / cos(Ang3);         //Radius of Overall Frame
OD = Rad * 2;                   //Diameter of Overall Frame

Pr_Out_OD = Pr_Out_Rad * 2;     //Outer Edge Profile Cut Diameter
Pr_In_OD = Pr_In_Rad * 2;       //Inner Edge Profile Cut Diameter

//Array of numbered Profiles
A_Type = [108,211,260,3974,3975];
//These are the corresponding Widths of the A_Type profiles
A_Width = [15.875,63.5,32.5438,38.0162,15.1555];

DXF_Name = str("N-",A_Type[abs(Type)],".dxf");
echo(Wid2 = Wid2);
echo(Sides = Sides);
echo(Rad = Rad);
echo(Ang1 = Ang1);
echo(Ang2 = Ang2);
echo(Ang3 = Ang3);
echo(Len2 = Len2);
echo(Type = Type);
echo(DXF_Name = DXF_Name);
$fn = I_Res;

module Moulding()
{
    if (Type != -1)
    {
        translate([0,-Wid2,0])
//Orient Moulding along X-Axis initially
        difference()
        {
            rotate([0,90,0])
            rotate([0,0,90])
            linear_extrude(height = Len, center = true, convexity = 10)
            import(DXF_Name);
            M_Cuts();
            Miter_Cut();
        }
    } else
    {
        translate([0,-Wid2,0])
//Orient Moulding along X-Axis initially
        difference()
        {
            rotate([0,90,0])
            rotate([0,0,90])
            translate([0,0,-Len2])
            cube([Pr_Wid,Pr_Thk,Len]);

            M_Cuts();
            Out_Edge();
            Center_Cut();
            In_Edge();
            Mid_Out_Cut();
            Mid_In_Cut();
            Miter_Cut();
//            translate([10,0,0])
//            {
//                %M_Cuts();
//                %Out_Edge();
//                %Center_Cut();
//                %In_Edge();
//                %Mid_Out_Cut();
//                %Mid_In_Cut();
//            }
        }
    }
}
module M_Cuts()
{

//Only Miter cut if Sides are at least 3 sides
    if (Sides > 2)
    {
        for (m = [0,1])
        {
            mirror([m,0,0])
            translate([-Len2,0,-1])
            rotate([0,0,Ang3])
            cube([Len,Max_Pr_Wid,Max_Pr_Thk]);
        }
    }
    if (Rabbit_Cut_On == 1)
    {
        if (Type == -1)
        {
            Rab_Y_Offset = Pr_Wid - Rabbit_Cut_Wid;
            translate([-Len2-1,Rab_Y_Offset,-1])
            cube([Len + 2,Pr_Wid,Rabbit_Cut_Depth + 1]);
            if (Rabbit_Chamfer_ON == 1)
            {
                translate([0,Pr_Wid,Rabbit_Cut_Depth])
                rotate([0,90,0])
                cylinder(d=Rabbit_Cut_Wid * 2,h = Len + 1,center=true,$fn=4);
            }
        } else
        {
            Profile_Wid = A_Width[Type] / Units;
            echo(Profile_Wid = Profile_Wid);
            Rab_Y_Offset = Profile_Wid - Rabbit_Cut_Wid;
            translate([-Len2 - 1,Rab_Y_Offset,-1])
            cube([Len + 2,Profile_Wid,Rabbit_Cut_Depth + 1]);
            if (Rabbit_Chamfer_ON == 1)
            {
                translate([0,Profile_Wid,Rabbit_Cut_Depth])
                rotate([0,90,0])
                cylinder(d=Rabbit_Cut_Wid * 2,h = Len + 1,center=true,$fn=4);
            }
        }
    }
}
module In_M_Cuts()
{
    for (m = [0,1])
    {
        mirror([m,0,0])
        translate([-Len2-.01,0,-1])
        rotate([0,0,Ang3])
        cube([Len+.02,Max_Pr_Wid,Max_Pr_Thk]);
    }
}
module Out_Edge()
{
    if (Pr_Out_Edge > 0)
    {
        translate([0,0,Pr_Thk + Pr_Out_Rad - Pr_Out_Depth])
        rotate([0,90,0])
        cylinder(d=Pr_Out_OD,h=Len+2,center=true,$fn=Pr_Out_Edge);
    } else if (Pr_Out_Edge == -1)
    {
        translate([0,0,Pr_Thk + Pr_Out_Rad - Pr_Out_Depth])
        rotate([0,90,0])
        translate([-Pr_Out_Rad,-Pr_Out_Rad,0])
        difference()
        {
            translate([0,0,-Len2-1])
            cube([Pr_Out_OD,Pr_Out_OD,Len+2]);
            translate([Pr_Out_OD,Pr_Out_OD,0])
            cylinder(d=Pr_Out_OD,h=Len+4,center=true);
        }
    }
}
module In_Edge()
{
    if (Pr_In_Edge > 0)
    {
        difference()
        {
            translate([0,Pr_Wid,Pr_Thk + Pr_Out_Rad - Pr_In_Depth])
            rotate([0,90,0])
            cylinder(d=Pr_In_Rad * 2,h=Len+2,center=true,$fn=Pr_In_Edge);
        }
    } else if (Pr_In_Edge == -1)
    {
        translate([0,Pr_Wid,Pr_Thk + Pr_In_Rad - Pr_In_Depth])
        rotate([0,90,0])
        translate([-Pr_In_Rad,-Pr_In_Rad,0])
        difference()
        {
            translate([0,0,-Len2-1])
            cube([Pr_In_OD,Pr_In_OD,Len+2]);
            translate([Pr_In_OD,0,0])
            cylinder(d=Pr_In_OD,h=Len+4,center=true);
        }
    }
}
module Radius_Cut(P_Rad = Pr_Cen_Rad, P_Depth = Pr_Cen_Depth, P_Res = Pr_Cen, M_Ht = Len)
{
    if (P_Res > 0)
    {
        rotate([0,90,0])
        rotate([0,0,90])
        translate([0,P_Rad,0])
        {
            linear_extrude(height = M_Ht + 1, center = true, convexity = 10)
            translate([-P_Rad,0,0])
            square(P_Rad * 2,false);
            linear_extrude(height = M_Ht + 1, center = true, convexity = 10)
            circle(d=P_Rad * 2, $fn=P_Res);
        }
    }
}
//Cutout along center of Profile
module Center_Cut()
{
    if (Pr_Cen > 0)
    {
        translate([0,Pr_Wid/2,Pr_Thk - Pr_Cen_Depth])
        Radius_Cut(Pr_Cen_Rad,Pr_Cen_Depth,Pr_Cen);
    }
}
//Cutout between Center of Profile & Outside Edge
module Mid_Out_Cut()
{
    if (Pr_Mid_Out > 0)
    {
        translate([0,(Pr_Wid / 2) - Pr_Mid_Out_Offset,Pr_Thk - Pr_Mid_Out_Depth])
        Radius_Cut(Pr_Mid_Out_Rad,Pr_Mid_Out_Depth,Pr_Mid_Out);
    }
}
//Cutout between Center of Profile & Inside Edge
module Mid_In_Cut()
{
    if (Pr_Mid_In > 0)
    {
        translate([0,(Pr_Wid / 2) + Pr_Mid_In_Offset,Pr_Thk - Pr_Mid_In_Depth])
        Radius_Cut(Pr_Mid_In_Rad,Pr_Mid_In_Depth,Pr_Mid_In);
    }
}
//Cutout along the miter joints
module Miter_Cut()
{
    if (Pr_Miter_Edge > 0)
    {
        if (Sides > 2)
        {
            for (m = [0,1])
            {
                mirror([m,0,0])
                translate([-Len2,0,Pr_Thk - Pr_Miter_Depth])
                rotate([0,0,Ang3])
                Radius_Cut(Pr_Miter_Rad,Pr_Miter_Depth,Pr_Miter_Edge,Pr_Miter_Cut_Len);
            }
        }
    }
}
module DrawFinal()
{
    if (Sides < 3)
    {
        Moulding();     //Only draw one moulding
    } else
    {
        union()
        {
//Create all the segmented sides
            for (a = [0:Sides - 1])
            {
                rotate([0,0,a * Ang1])
                Moulding();
            }
            if (Base_Thick != 0)
            {
                rotate([0,0,-(90 + Ang2)])
                cylinder(d=OD,h=Base_Thick,$fn=Sides);
            }
        }
    }
}
DrawFinal();
```


[User]
I'm looking to create a test tower similar to the one I found online, but I'd like a parametric version built from scratch using OpenSCAD. The basic idea is to have a series of levels stacked vertically, each with a different setting that I can test.

Here's the breakdown of what I'd like:

*   **Overall Structure:** The tower should be composed of several identical levels stacked vertically.
*   **Number of Levels:** I'd like to be able to control the number of levels easily with a parameter, let's call it `num`.
*   **Level Parameters:** Each level should be identical except for a label showing an incrementing value.
    *   **Main Cube:** Each level has a main cube on the left side of a specified `size` and `depth`.
    *   **Overhang:** On the right, there should be an overhang structure with a 45-degree angle.  It should be the same `size` and `depth` as the main cube and should use a polyhedron like in the example.
    *   **Bridge:** Spanning between the main cube and the overhang, there should be a bridge with a specified `bridge_length` and `bridge_height`, with the same `depth` as the other parts. The bridge should be positioned 80% of the way up the side of the main cube.
    *   **Separator:** Below each level, I would like a thin horizontal separator with a chamfered end on one side to visually demarcate between levels, as per the example, and have the separator extend the width of the tower.
    *   **Label:** Each level should have a numerical label displayed on the face of the main cube, using the value associated with that level. The size of the label should scale with the level size.
*   **Floor:** There should be a base for the tower, a rectangle that spans the entire width of all the components and should have the same depth as the level components, minus 1, and a height equal to the bridge height.

*   **Customization:**
    *   **Start Value:**  I need a parameter for the starting value of the test, call it `start`.
    *   **Increment:** A parameter to control how much the value changes with each level, `increment`.
    *   **Direction:** A parameter called `direction` that allows the values to increase going up or down. It should be set to `-1` to have the largest value on the bottom and `1` to have the smallest value on the bottom.
    *   **Size:** A parameter to change the size of the cube (`size`).
    *   **Depth:** A parameter to change the depth of all features (`depth`).
    *    **Bridge Length**: A parameter to control the length of the bridge, call it `bridge_length`.
    *    **Bridge Height**: A parameter to control the height of the bridge, call it `bridge_height`.

I'd like the entire design to be generated from scratch without using libraries (e.g. MCAD, BOSL, etc.)

Could you generate the OpenSCAD code for this design? I'd like to be able to change all those parameters in the customizer. Thanks.

[Assistant]
ctt.scad:
```
// title      : Customizable Test Tower
// author     : Rob Parrett
// revision   : 0.3

start = 240; // [0:2:300]
increment = 10; // [2:50]
direction = -1; // [-1:Larger values on bottom, 1:Smaller values on bottom]
num = 4; // [1:1:20]
bridge_length = 20; // [5:1:40]
bridge_height = 1; // [0.1:0.1:2]
size = 16; // [10:1:50]
depth = 10; // [5:1:50]

module separator() {
    linear_extrude(height=1) {
        polygon(
            points = [
                [0, 0],
                [2, 0],
                [2, 0.5],
                [0, 2.5]
            ]
        );
    }
}

module overhangcube() {
    polyhedron(
        points = [
            [0, 0, 1],   // front face
            [0, 0, 0.8],
            [0.8, 0, 0],
            [1, 0, 0],
            [1, 0, 1],

            [0, 1, 1],   // rear face
            [0, 1, 0.8],
            [0.8, 1, 0],
            [1, 1, 0],
            [1, 1, 1]
        ],
        faces = [
            [5, 0, 1], // sides
            [5, 1, 6],

            [1, 2, 6],
            [2, 7, 6],

            [3, 7, 2],
            [8, 7, 3],

            [3, 9, 8],
            [3, 4, 9],

            [0, 5, 9],
            [0, 9, 4],

            [1, 0, 4], // front
            [1, 4, 2],
            [2, 4, 3],

            [9, 5, 6], // back
            [9, 6, 7],
            [9, 7, 8]
        ],
        concavity = 10
    );
}

module level(val) {
    difference()
    {
        union()
        {
            // left main cube
            translate([-1 * bridge_length / 2 - size, 0, 0])
            cube([size, depth, size]);

            // overhang
            translate([bridge_length / 2, 0, 0])
            scale([size, depth, size])
            overhangcube();

            // bridge
            translate([-1 * bridge_length / 2 - 1, 0, size * 0.8])
            cube([bridge_length + 2, depth, bridge_height]);
       }
       union()
       {
           // label
           translate([-1 * bridge_length / 2 - size / 2, 1, size / 2])
           label(val);

           // separator
           translate([-1 * bridge_length / 2 - size - 1, -1, 0])
           scale([bridge_length + size * 2 + 2, 1, 1])
           rotate([90, 0, 0])
           rotate([0, 90, 0])
           separator();
       }
   }
}

module label(val) {
    rotate([90, 0, 0])
    translate([0, 0, 0])
    resize([size-4, size-4], auto = true)
    linear_extrude(height=2) {
        text(text = str(val), valign = "center", halign="center", size = size - 6);
    }
}

// floor
translate([-1 * bridge_length / 2 - size, 1, 0])
cube([bridge_length + size * 2, depth - 1, bridge_height]);

for (i = [0 : num - 1]) {
    translate([0, 0, i * size])
    level(start + i * increment * direction);
}

```


[User]
Hey, I'm looking to create some customizable tokens using OpenSCAD. I need a design that allows for either numbers or text on the tokens, and ideally, I want to be able to put the design on both sides. I want to control the radius, height, and the quality of the cylinder, as well as the font size and height of the text. For number-based tokens, I'd like to set the number of pairs, and the min and max values of the numbers. For text-based tokens, I just need to specify the text. I'd also like an option to inverse the text so it's recessed into the token rather than protruding. Finally, I need to control if the text/number is on the top only or on both sides.

The design should be parametric, so I can easily change all these parameters. Could you help me with that?

[Assistant]
token.scad:
```
// Type
type = 0; // [0:Numbers, 1:Text]

// Radius [mm]
radius = 10; // [1:0.5:50]
// Height [mm]
height = 2; // [1:0.5:10]
// Quality (Cylinder edges)
quality = 128; // [8:2:256]

// Font size
font_size = 10; // [1:0.5:80]
// Font height
font_height = 1; // [0.2:0.2:5]
// Inverse font
inverse = 1; // [0:False, 1:True]
// Sides
sides = 1; // [0:Top only, 1:Top and bottom]

/* [Number based tokens] */
// Number of Pairs
pairs = 1; // [1:1:20]
// Starting number
range_min = 5; // [1:1:200]
// Ending number
range_max = 9; // [1:1:200]

/* [Text based tokens] */
// Signature
signature = "Hi!"; //

if(type==0) {
    for(i = [1:pairs]){
        translate([(2*radius+5)*(i-1), 0, 0])
        for(j = [range_min:range_max]) {
            signature = str(j);
            translate([0, (2*radius+5)*(j-range_min), 0])
            token(signature);
        }
    }
} else if(type==1){
    for(i = [1:pairs]){
        translate([(2*radius+5)*(i-1), 0, 0])
        token(signature);
    }
}

module token(signature) {
    if(inverse == 0) {
        union(){
            translate([0,0,height])
            make_signature(signature, font_height);

            if(sides==1) {
                rotate([0,180,0])
                make_signature(signature, font_height);
            }

            cylinder(r=radius, h=height, $fn = quality);
        }
    }else if(inverse == 1) {
        difference() {
            cylinder(r=radius, h=height, $fn = quality);
            translate([0,0,height-font_height+0.1])
            make_signature(signature, font_height+0.1);
            if(sides==1) {
                translate([0,0,font_height])
                rotate([0,180,0])
                make_signature(signature, font_height+0.1);
            }
        }
    }
}

module make_signature(signature, font_height) {
    linear_extrude(height=font_height)
    text(text = signature, size = font_size, valign = "center", halign="center");
}
```


[User]
Hey, I'd like to create a parametric OpenSCAD model for a View-Master reel, but I want a bit more control over the design than I've seen out there. I'm hoping you can help me build the code from scratch.

Here's what I'm thinking:

**Basic Structure:**
*   It needs to be a circular disc.
*   I need to be able to define the number of picture pairs on the reel (standard is 7, but I might want to experiment).
*   I want to set the total thickness of the disc.
*   I need to specify the outer diameter and the center hole diameter.

**Picture Windows:**
*   The windows for the images should be rectangular with rounded corners (fillets).
*   I need to set the width and height of the window.
*   I want to control the radius of the rounded corners.
*   I need to set the inset distance of the window from the edge of the disc.

**Film Details:**
*   I need to be able to specify film thickness - even if that is just for rendering/visualization purposes, not physically cutting into the final model.
*   I want to be able to specify film width and height, again probably just for rendering or maybe for creating a recessed slot for an actual film.

**Cog Holes:**
*   These should be rectangular cutouts.
*   I need to specify the width and height of these cog holes.
*   I need to specify the inset distance of these from the edge of the disc.
*   The number of cog holes should match the number of picture pairs.

**First Frame Indicators:**
*   I need to specify the width and depth/height of a pair of detents on the first frame.
*   I need to specify how far apart they are from each other
*   I need the detents to be oriented at a 45-degree angle.
*   I need to specify how far from the edge of the disc that these are located.

**Other Considerations:**
*   I'd like some kind of resolution factor to control the smoothness of the curves, but also so I can quickly preview a less-detailed version before doing a full render.
*   I want to be able to easily switch between creating:
    *   A 2D version (useful for exporting to DXF)
    *   A full-thickness 3D model.
    *   A half-thickness 3D model (for experimentation).
    *   A half-thickness 3D model with a film cutout.
*   I want to parameterize the number of cogs and windows based on the number of picture-pairs, as the existing code does it (number of windows = 2 \* picture pairs; number of cogs = number of picture pairs).

I don't need any fancy libraries to make this work, just the basic OpenSCAD functions for circles, squares, rotations, translations, extrudes, hulls, etc. Can you help me put this together?

[Assistant]
viewmaster.scad:
```
// improved viewmaster wheel
// inspired by: https://www.thingiverse.com/thing:28391
//
// Licenced under creative commons - attribution.
//   For the attribution requirement, please provide a link to:
//   https://www.thingiverse.com/thing:2402697
//
// NOTE: images are a pair of pictures with the camera shifted
// horizontally 64.35mm (approx 2 9/16in) between shots.

/* [main] */

// what to generate
show=1; // [0:2d version for dxf,1:3d full thickness,2:3d half thickness,3:3d half thickness less film]

// resolution 1=low(aka 1x) 2=mid 3=high
resfactor=2;

/* [main shape] */

// how many picture-pairs on the reel (standard is 7, don't know if other values will work)
num_pics=7;

// the total thickness of the disc
total_thickness=0.45;

// outside diameter
d=89.3;

// center hole diameter
center_d=4.8;

/* [picture windows] */

// width of the window
window_w=11.5;

// height of the window
window_h=10.5;

// round the corner of the windows (radius)
window_roundover_r=2.1;

//inset from edge
window_inset=6.65;

/* [film] */

// how thick the film is
film_thickness=0.15;

// how wide the embedded pictures are (not used)
film_w=15.45;

// how high the embedded pictures are (not used)
film_h=12.8;

/* [first frame bumps] */

// how far apart the bumps are
frame1_index_w=10;

// how deep the bumps are
frame1_index_h=1.5;

/* [cog holes] */

// width of the cog holes
cog_w=4.75;

// height of the cog holes
cog_h=2.35;

//inset from edge
cog_inset=2;

/* [hidden] */

// I'm pretty sure these are a function of the number of pictures
num_cogs=num_pics;
num_windows=num_pics*2;

// make $fn more automatic
function myfn(r)=max(3*r,12)*resfactor;
module circ(r=undef){circle(r=r,$fn=myfn(r));}

module window(){
	hull(){
		translate([window_roundover_r,window_roundover_r]) circ(r=window_roundover_r);
		translate([window_roundover_r,window_h-window_roundover_r]) circ(r=window_roundover_r);
		translate([window_w-window_roundover_r,window_h-window_roundover_r]) circ(r=window_roundover_r);
		translate([window_w-window_roundover_r,window_roundover_r]) circ(r=window_roundover_r);
	}
}

module windows(){
	for(a=[0:360/num_windows:359.99]){
		rotate([0,0,a]) translate([-d/2+window_inset,-window_h/2]) window();
	}
}

module cogs(){
	for(a=[0:360/num_cogs:359.99]){
		rotate([0,0,a-90]) translate([-d/2+cog_inset,-cog_h/2]) square([cog_w,cog_h]);
	}
}

// a pair of detents signifies the first frame
module frame1_index(){
	size=frame1_index_h;
	offs=0;
	translate([ frame1_index_w/2,d/2-offs]) rotate([0,0,45]) square([size,size],center=true);
	translate([-frame1_index_w/2,d/2-offs]) rotate([0,0,45]) square([size,size],center=true);
}

// this is good for creating a dxf for laser cutter
module wheel2D(){
	difference(){
		circ(r=d/2);
		circ(r=center_d/2);
		windows();
		cogs();
		frame1_index();
	}
}

module wheel3D(half=true,allowForFilmThickness=false){
	linear_extrude(total_thickness/(half?2:1)-(allowForFilmThickness?film_thickness/2:0)) wheel2D();
}

if(show==0){//2d version for dxf,
	wheel2D();
}else if(show==1){//3d full thickness
	wheel3D(false,false);
}else if(show==2){//3d half thickness
	wheel3D(true,false);
}else if(show==3){//3d half thickness less film]
	wheel3D(true,true);
}

```


[User]
Hey, I'm looking to get a custom bumper designed for my B-robot EVO 2. I have an existing design I like, but I need it to be fully parametric so I can easily adjust the size, text, and other features.

The current bumper has a roughly U-shaped profile with a flat central section. The dimensions are somewhat complex, defined by a list of 2D points that are then extruded. It has a height of 28mm. The text is placed on the front of the bumper, and there are some mounting holes, including two larger ones on the top and some smaller ones along the edges. There are also angled corner cuts on the ends.

I'd like a parametric OpenSCAD file that allows me to control the following:

1.  **Bumper Profile:** Instead of being defined by fixed point coordinates, I'd like to use a series of parameters to control the overall shape:
    *   `bumper_width`: overall width of the bumper
    *   `bumper_height`: overall height of the bumper
    *   `bumper_depth`: thickness of the bumper extrusion
    *   `bumper_curve_depth`: the depth of the curve on the sides of the bumper, i.e. how 'deep' the 'U' shape is.
    *   `bumper_curve_radius`: Radius of the corners of the curves.
    *   `bumper_flat_depth`: How much the center area flattens out.
    *   `bumper_flat_width`: Width of the flat portion of the bumper.

2.  **Text:**
    *   `bumper_text`: Text to display on the bumper
    *   `text_size`: Font size of the text
    *   `text_font`: A selection from a few basic fonts for the text, perhaps "Luckiest Guy", "Open Sans Bold", and "Raleway Black". I just need a couple of options that are a bit different.

3.  **Holes:**
    *   `large_hole_diameter`: diameter of the top mounting holes
    *   `large_hole_depth`: depth of the large mounting holes (can be set to be very long to make them through-holes)
    *   `small_hole_diameter`: diameter of the smaller mounting holes
    *   `small_hole_depth`: depth of the small mounting holes (can be set to be very long to make them through-holes)
    *   `bottom_hole_diameter`: diameter of the bottom mounting holes.
    *   `bottom_hole_depth`: depth of the bottom mounting holes.
    *   `hole_center_dist`: The distance from the center of the bumper to the center of the small and bottom holes.
    *   `large_hole_y_offset`: The Y-offset for the larger holes.

4.  **Corner Cuts:**
     *   `corner_cut_size`: Size of the corner cutting cubes
     *   `corner_cut_angle`: The angle of the corner cutting cubes.

The overall construction should still use the difference method, so the text, holes, and corner cuts are all subtracted from the main body.

I'd like the code to be well-commented and easy to modify further. Could you help me generate this?

[Assistant]
brobot_cbumper_V2.scad:
```
// BROBOT EVO 2 customizable bumper
// JJROBOTS
// For thinguiverse customizer tool

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

bumper_text = "JJROBOTS";

text_size = 9; //[3:12]

text_font = "font1"; //[font1,font2,font3]

// bumper
/* [Hidden] */
bumper = [[ -13.67812, -52.5 ], [ -13.6351, -65.00759 ], [ -13.24911, -74.43299 ], [ -12.48869, -82.53739 ], [ -11.37279, -89.26354 ], [ -9.86998, -94.66884 ], [ -8.05664, -98.67951 ], [ -6.82256, -100.49508 ], [ -5.61003, -101.82489 ], [ -4.37148, -102.85987 ], [ -2.92737, -103.64174 ], [ -1.08473, -104.24709 ], [ 1.10223, -104.69063 ], [ 3.54325, -105.0 ], [ 14.09606, -105.0 ], [ 14.09606, -108.0 ], [ 3.7702, -108.0 ], [ 1.12927, -107.61976 ], [ -1.15545, -107.09505 ], [ -3.1964, -106.37092 ], [ -4.93641, -105.44706 ], [ -6.36754, -104.37459 ], [ -8.0772, -102.65623 ], [ -9.88064, -100.37831 ], [ -10.97808, -98.60124 ], [ -11.95121, -96.52943 ], [ -12.8403, -93.95893 ], [ -13.74933, -90.41778 ], [ -14.60793, -86.27231 ], [ -15.21472, -82.37058 ], [ -15.83358, -75.42103 ], [ -16.25758, -65.86363 ], [ -16.44864, -54.83641 ], [ -16.43325, -52.49996 ], [ -13.67812, -52.5 ]];

difference(){
// Bumper
union(){
linear_extrude(height=28)
{
translate([-14-6,52.5,0])polygon(points=bumper);
translate([-14-6,-52.5,0])mirror([0,1,0])polygon(points=bumper);
}
translate([-6.25,52.5,0])cube([6.25,3,28]);
translate([-6.25,-52.5-3,0])cube([6.25,3,28]);
}

// Text
translate([-14-14-6-0.25,0,14])rotate([90,0,-90])linear_extrude(height=4)
{
    // We use three different google fonts
    if (text_font=="font1") text(font="Luckiest Guy",text=bumper_text,size=text_size,halign="center",valign="center");
    if (text_font=="font2") text(font="Open Sans:style=Bold",text=bumper_text,size=text_size,halign="center",valign="center");
    if (text_font=="font3") text(font="Raleway:style=Black",text=bumper_text,size=text_size,halign="center",valign="center");

}

// Holes
translate([-13.5,0,26.9])rotate([90,0,0])cylinder(r=3.25,h=200,$fn=16,center=true);

translate([-6.5,0,18.5])rotate([90,0,0])cylinder(r=1.65,h=200,$fn=16,center=true);
translate([-6.5,-52.5-3,18.5])rotate([90,0,0])cylinder(r=3.65,h=2.5,$fn=16,center=true);
translate([-6.5,52.5+3,18.5])rotate([90,0,0])cylinder(r=3.65,h=2.5,$fn=16,center=true);

// Borders cuts
translate([-3,52.5-0.5,0])rotate([0,30,0])cube([6,4,6]);
translate([-3,52.5-0.5,28])rotate([0,60,0])cube([6,4,6]);
translate([-3,-52.5-3.5,0])rotate([0,30,0])cube([6,4,6]);
translate([-3,-52.5-3.5,28])rotate([0,60,0])cube([6,4,6]);

}

```


[User]
Hey, I'm looking to design a custom fan/radiator mount for my PC case, specifically one that fits into three 5.25" drive bays. I want it to be parametric so I can tweak it for different fans, radiators, and case setups.

Here's what I'm thinking:

**Core Functionality:**

*   **Multi-bay Mount:** The mount should occupy the space of three 5.25" drive bays, essentially a rectangular prism.
*   **Fan Mounting:** It needs to be able to securely mount a 120mm fan (standard 105mm hole spacing). I'd like to optionally support 140mm fan/radiator mounts (standard 125mm hole spacing).
*   **Radiator Compatibility:** It should also be able to hold a standard 120mm fan sized radiator (with standard 105mm fan screw hole spacing), again, with optional support for 140mm fan/radiator mounts.
*   **Shroud:** I want a shroud around the fan/radiator, extending maybe 5mm in front of the fan/radiator mounting surface. The shroud should also have cutouts/holes for mounting the fan/radiator screws.
*   **Mounting to Case:** The mount needs to have screw holes that align with standard 5.25" bay mounting points. I need this to be configurable for different case hole placements.  In my case, these holes are in pairs spaced 12mm apart, with 43mm between pairs, but I'd like to be able to change these.
*   **Offset/Shift:** I need the ability to shift the mounted fan or radiator horizontally away from the center of the 3-bay space. I want to be able to configure the offset.
*   **Optional Upper Cutoff:** Sometimes, the mount might interfere with other parts, so an optional height cutoff for the upper part of the design would be great. I want to be able to specify how much the upper section is cut off.

**Key Parameters:**

*   `fan_size`:  "120mm" or "140mm". Defaults to 120mm.
*   `fan_hole_spacing`: Depending on `fan_size`, defaults to 105mm for 120mm, or 125mm for 140mm
*    `fan_diam`: 116 mm for a 120mm fan. This would depend on the `fan_size` parameter too.
*   `fan_shift`: Horizontal offset of the fan/rad from the center of the 3 bays.
*   `upper_cuttoff`: Vertical height of the optional cutoff for the upper part of the mount.
*   `hor_hole_diameter`: Diameter of the mounting holes for the 5.25" bay screws (I'm using #6-32 UNC, which is around 2.9mm diameter).
*   `fan_hole_diameter`: Diameter of the holes for fan/radiator mounting screws (M3, which is about 4.5mm).
*  `horizontal_hole_start`:  Vertical position of the 5.25 bay holes relative to the center of the 3 bay mount.
*  `horizontal_hole_offsets`: List of offsets for the 5.25 bay mounting holes, relative to the start position
*    `shroud_thickness`: Thickness of the shroud in mm.
*  `drawer_depth` Depth of the 5.25 bay drawer parts.
*  `drawer_width` Width of the mounting bracket of the 5.25 bay drawer parts.

I'm hoping this can be made as a parametric OpenSCAD design. I don't have a strong preference for libraries, but I'm open to suggestions. I think I will want to use the BOSL library. If you could provide me with the full scad file(s), that would be awesome.

[Assistant]
drivebay_fan_rad_holder.scad:
```
//How much the fan is shifted from the center of 3 bays
fan_shift=13; //[-20:0.5:140]

// Cuts part of the upper drawers, so the part fits better on small printer beds
upper_cuttoff=10; //[0:0.5:20]

// For HDD screws (#6-32 UNC)
hor_hole = 2.9;

// For M3 fan screws to have some wiggle room
fan_hole_d = 4.5;

// Height of the upper drawer hole relative to the center of 3 bays
horizontal_hole_start = 44;

// The holes on CM Storm Stryker are 12mm apart with 43mm between pairs
horizontal_hole_offsets = [0, 12, 86, 86+12];

// 5mm seems to be the standard, to use with 35mm screws
shroud_thickness = 5;

//105 for the 120mm fans
fan_hole_spacing = 105;

//Diameter of the main fan hole
fan_diam = 116;

main();

module main() {
    shroud();
    translate([0,0,shroud_thickness])
    mirror([0,0,1])
    difference(){
        union() {
            bracing();
            drawers(16);
            mirror([1,0,0]) { bracing();}
        }

        for (hole_offset = horizontal_hole_offsets)
            //uhh, value=list, really, OpenSCAD?
            translate([0,fan_shift-hole_offset+horizontal_hole_start,-10+shroud_thickness])
            rotate([0,90,0])
                cylinder($fn=12, d=hor_hole, h= 160,center=true);

        if (upper_cuttoff > 0)
        translate([0,-upper_cuttoff+fan_shift+75,-7.55+shroud_thickness])
            cube([150,25,30],center=true);

    }
};

module shroud () {
    fh = fan_hole_spacing;
    difference(){
        hull() four_cylinders(xs=fh,ys=fh, d=15, h=shroud_thickness, z=0);

        four_cylinders(xs=fh,ys=fh,
            d=fan_hole_d,h=shroud_thickness+1, z=-0.1);

        cylinder($fn=360, d=fan_diam, h=1+2*shroud_thickness,center=true);
    }
}

module four_cylinders(xs,ys, d, h, z) {
    for(x=[0:1]) {
        for (y=[0:1]){
            translate([(0.5-x)*xs,(0.5-y)*ys,z])
                cylinder(h=h,d=d, $fn=16);
        }
    }
};

module bracing() {
    fh = fan_hole_spacing;
    for(i=[-1:2:1])
    hull(){
        translate([-68,fan_shift,shroud_thickness-4])
            cube([2, 105, 8],center=true);
        translate([-8.9-fh/2,0,shroud_thickness/2])
            cube([3,fh*0.8,shroud_thickness], center=true);
    }
};

module drawers(depth=20,width=5) {
    // Values taken from SFF-8551 are in comments
    a1= 41.5;   //41.53, ehh, tolerance is +-0.25mm anyway
    a2= 44;     //42.3 plus two ~0.9mm steel divider tabs
    a5= 146.05;  //146.05, fits snugly

    for (j = [-1,1])
        translate([0,j*(a1+a2)/2 + fan_shift,-depth/2+shroud_thickness])
            difference() {
                cube([a5,a1,depth], center=true);
                cube([a5-width*2,a1+1,depth+1], center=true); }

};
```


[User]
Hey, I'm looking to create a customizable 3D model for a small, circular label or token, kind of like a small coin. I'd like the design to be parametric so I can easily adjust its size and the text on it.

Here's what I'm thinking:

*   **Shape:** It should be a simple cylinder.
*   **Diameter:** I need to be able to adjust the diameter, say, between 50 and 150 units.
*   **Height:**  I want to control the height, offering a few preset options: a thinner one (height of 1), a medium one (1.5), and a thicker one (2).
*   **Text:**  The important part - I want to emboss a text string centered on the cylinder. I want a few pre-defined text options to choose from: "Coffee", "Tea", "Water", "Café", "Chá", and "Agua". The text should be raised, not sunken.
*   **Smoothness:** Let's use $fn=128 for the cylinder's smoothness.

Can you generate the necessary OpenSCAD code for this? I expect to be able to adjust the `diametro` and `altura` variables and to be able to select an option for the `texto` variable. I don't need any additional library files beyond the standard included with OpenSCAD.

[Assistant]
ArtigoOpenSCad.scad:
```
diametro = 100; // [50:150]
altura   =   1; // [1:Fino,1.5:Medio,2:Maior]
texto    = "Coffee"; // [Coffee, Tea, Water, Café, Chá, Agua]
/* [Hidden] */
$fn = 128;
cylinder(d=diametro,h=altura);
linear_extrude(height=altura+0.2)
    text(texto,size=10,halign="center",valign="center");
```