[User]
Hey, I need to design a replacement plug for my car's wiper fluid reservoir. The existing design I have is pretty basic, but I'd like something a bit more robust and customizable. Here's what I'm thinking:

The plug should be a hollow, frustum-shaped cylinder with a lip at the top. The bottom diameter should be smaller than the top diameter. Both of these should be configurable as parameters. I want to be able to set the overall height of the plug too. Additionally, the wall thickness of the hollow cylinder needs to be configurable.

I also need a small vent hole on the side for pressure equalization – its position should be adjustable, or it should be placed somewhere that it cannot interfere with the proper sealing of the plug. Text engraving is nice, but optional. If I can do it, I want to make the text size configurable as well.

I'd like the code to be in OpenSCAD. Is that something you can help with? I'm looking for a fully parametric design, so I can adjust the parameters to fit different vehicles. I'm not particular about the libraries used, as long as they are robust. Perhaps a library that has a decent text engraving function would be useful.

[Assistant]
WiperFluidPlug.scad:
```
//
//  WiperFluidPlug.scad
//
//  EvilTeach
//
//  12/8/2015
//
//  25%   infill
//    .3  layer height
//   0    shells
//  60    feedrate
//        abs
//        no raft
//        no support

// Total height of the plug in MM
plugHeight         = 40.0;

// Total Diameter of the top of the plug in MM. This is expected to be larger than the bottom diameter
plugDiameterTop    = 53.0;

// Total Diameter of the bottom of the plug in MM
plugDiameterBottom = 50.0;

module main()
{
    // Make a very smooth print
    $fn = 360;

    topRadius     = plugDiameterBottom / 2.0;
    bottomRadius  = plugDiameterTop    / 2.0;

    // This is thick enough to make it strong enough
    thickness = 2.0;

    difference()
    {
        // Draw the basic cylinder
        cylinder(r2 = topRadius,
                 r1 = bottomRadius,
                  h = plugHeight);

        // Hollow out the basic cylinder
        translate([0, 0, thickness])
            cylinder(r2 = topRadius      - thickness,
                     r1 = bottomRadius   - thickness,
                      h = plugHeight     - thickness);

        // Add a small hole to allow pressure to equalize
        cylinder(r = 1, h = thickness);

        // Engrave some roughly relative text.
        translate([bottomRadius / 2, 8, 1])
            rotate([0, 180, 0])
                linear_extrude(1)
                    text("WIPER", size = 6);

        translate([bottomRadius / 2, -10, 1])
            rotate([0, 180, 0])
                linear_extrude(1)
                    text("FLUID", size = 6);
    }
}

main();
```


[User] Hey, I'm looking for a parametric OpenSCAD maze generator. I'd like to be able to specify the number of rows and columns, the wall thickness and height, and the block width. It's important that the maze is randomly generated each time I render it. Also, I'd like the option to include a solid bottom to the maze or not, configurable with a simple "YES" or "NO". Could you generate the necessary OpenSCAD files for me?

[Assistant]
maze_generator.scad:
```
rows = 10;
columns = 10;
wall_thickness = 1;
wall_height = 10;
block_width = 10;
bottom = "YES";

/*
 * constants, for clearness
 *
 */

// random directions, for picking up a direction to visit the next block
function PERMUTATION_OF_FOUR() = [
    [1, 2, 3, 4],
    [1, 2, 4, 3],
    [1, 3, 2, 4],
    [1, 3, 4, 2],
    [1, 4, 2, 3],
    [1, 4, 3, 2],
    [2, 1, 3, 4],
    [2, 1, 4, 3],
    [2, 3, 1, 4],
    [2, 3, 4, 1],
    [2, 4, 1, 3],
    [2, 4, 3, 1],
    [3, 1, 2, 4],
    [3, 1, 4, 2],
    [3, 2, 1, 4],
    [3, 2, 4, 1],
    [3, 4, 1, 2],
    [3, 4, 2, 1],
    [4, 1, 2, 3],
    [4, 1, 3, 2],
    [4, 2, 1, 3],
    [4, 2, 3, 1],
    [4, 3, 1, 2],
    [4, 3, 2, 1]
];

function NO_WALL() = 0;
function UP_WALL() = 1;
function RIGHT_WALL() = 2;
function UP_RIGHT_WALL() = 3;

function NOT_VISITED() = 0;
function VISITED() = 1;

/*
 * modules for creating a maze
 *
 */

// give a [x, y] point and length. draw a line in the x direction
module x_line(point, length, thickness = 1) {
    offset = thickness / 2;
    translate([point[0] - offset, point[1] - offset, 0])
        square([length + thickness, thickness]);
}

// give a [x, y] point and length. draw a line in the y direction
module y_line(point, length, thickness = 1) {
    offset = thickness / 2;
    translate([point[0] - offset, point[1] - offset, 0])
        square([thickness, length + thickness]);
}

// create the outer wall of maze
module maze_outer_wall(rows, columns, block_width = 5, wall_thickness = 1) {
    x_line([0, rows * block_width], columns * block_width, wall_thickness);
    y_line([0, block_width], (rows - 1) * block_width, wall_thickness);
}

// create the inner wall of maze
module maze_inner_wall(maze, block_width = 5, wall_thickness = 1) {
    for(i = [0:len(maze) - 1]) {
        cord = maze[i];
        x = (cord[0] - 1) * block_width;
        y = (cord[1] - 1) * block_width;
        v = cord[3];

        if(v == 1 || v == 3) {
            x_line([x, y], block_width, wall_thickness);
        }
        if(v == 2 || v == 3) {
            y_line([x + block_width, y], block_width, wall_thickness);
        }
    }
}

// create a maze
module maze(rows, columns, maze_vector, block_width = 5, wall_thickness = 1) {
     maze_outer_wall(rows, columns, block_width, wall_thickness);
     maze_inner_wall(maze_vector, block_width, wall_thickness);
}

/*
 * utilities functions
 *
 */

// comare the equality of [x1, y1] and [x2, y2]
function cord_equals(cord1, cord2) = cord1 == cord2;

// is the point visited?
function not_visited(cord, vs, index = 0) =
    index == len(vs) ? true :
        (cord_equals([vs[index][0], vs[index][1]], cord) && vs[index][2] == 1 ? false :
            not_visited(cord, vs, index + 1));

// pick a direction randomly
function rand_dirs() =
    PERMUTATION_OF_FOUR()[round(rands(0, 24, 1)[0])];

// replace v1 in the vector with v2
function replace(v1, v2, vs) =
    [for(i = [0:len(vs) - 1]) vs[i] == v1 ? v2 : vs[i]];

/*
 * functions for generating a maze vector
 *
 */

// initialize a maze
function init_maze(rows, columns) =
    [
	    for(c = [1 : columns])
	        for(r = [1 : rows])
		        [c, r, 0,  UP_RIGHT_WALL()]
	];

// find a vector in the maze vector
function find(i, j, maze_vector, index = 0) =
    index == len(maze_vector) ? [] : (
        cord_equals([i, j], [maze_vector[index][0], maze_vector[index][1]]) ? maze_vector[index] : find(i, j, maze_vector, index + 1)
    );

////
// NO_WALL = 0;
// UP_WALL = 1;
// RIGHT_WALL = 2;
// UP_RIGHT_WALL = 3;
function delete_right_wall(original_block) =
    original_block == NO_WALL() || original_block == RIGHT_WALL() ? NO_WALL() : UP_WALL();

function delete_up_wall(original_block) =
    (original_block == NO_WALL() || original_block == UP_WALL()) ? NO_WALL() : RIGHT_WALL();

function delete_right_wall_of(vs, is_visited, maze_vector) =
    replace(vs, [vs[0], vs[1] , is_visited, delete_right_wall(vs[3])] ,maze_vector);

function delete_up_wall_of(vs, is_visited, maze_vector) =
    replace(vs, [vs[0], vs[1] , is_visited, delete_up_wall(vs[3])] ,maze_vector);

function go_right(i, j, rows, columns, maze_vector) =
    go_maze(i + 1, j, rows, columns, delete_right_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));

function go_up(i, j, rows, columns, maze_vector) =
    go_maze(i, j - 1, rows, columns, delete_up_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));

function visit(v, maze_vector) =
    replace(v, [v[0], v[1], VISITED(), v[3]], maze_vector);

function go_left(i, j, rows, columns, maze_vector) =
    go_maze(i - 1, j, rows, columns, delete_right_wall_of(find(i - 1, j, maze_vector), NOT_VISITED(), maze_vector));

function go_down(i, j, rows, columns, maze_vector) =
    go_maze(i, j + 1, rows, columns, delete_up_wall_of(find(i, j + 1, maze_vector), NOT_VISITED(), maze_vector));

function go_maze(i, j, rows, columns, maze_vector) =
    look_around(i, j, rand_dirs(), rows, columns, visit(find(i, j, maze_vector), maze_vector));

function look_around(i, j, dirs, rows, columns, maze_vector, index = 0) =
    index == 4 ? maze_vector :
        look_around(
            i, j, dirs,
            rows, columns,
            build_wall(i, j, dirs[index], rows, columns, maze_vector),
            index + 1
        );

function build_wall(i, j, n, rows, columns, maze_vector) =
    n == 1 && i != columns && not_visited([i + 1, j], maze_vector) ? go_right(i, j, rows, columns, maze_vector) : (
        n == 2 && j != 1 && not_visited([i, j - 1], maze_vector) ? go_up(i, j, rows, columns, maze_vector)  : (
            n == 3 && i != 1 && not_visited([i - 1, j], maze_vector) ? go_left(i, j,rows, columns,  maze_vector)  : (
                n == 4 && j != rows && not_visited([i, j + 1], maze_vector) ? go_down(i, j, rows, columns, maze_vector) : maze_vector
            )
        )
    );

/*
 * create a maze
 *
 */
maze_vector = go_maze(1, 1, rows, columns, replace([columns, rows, 0, UP_RIGHT_WALL()], [columns, rows, 0, UP_WALL()], init_maze(rows, columns)));
linear_extrude(wall_height)
    maze(rows, columns, maze_vector, block_width, wall_thickness);

if(bottom == "YES") {
    translate([-wall_thickness / 2, -wall_thickness / 2, -wall_thickness])
	    linear_extrude(wall_thickness) square([block_width * columns + wall_thickness, block_width * rows + wall_thickness]);
}

```


[User]
I'd like to design a set of nested trays, like Russian nesting dolls, for storing small parts. I'm thinking of a rectangular shape with rounded corners, and I need to be able to specify the number of trays, as well as the overall dimensions of the outer tray. It would be great to have some control over the wall thickness and bottom thickness of each tray, as well as the spacing between nested trays.

Specifically, I need:

*   A way to specify the total length, width, and height of the *outermost* tray.
*   A parameter to control the number of trays in the set.
*   A radius for the rounded side corners – all trays will have the same corner radius.
*   A small radius for the bottom corners of the trays.
*   Separate parameters for the side wall thickness and bottom wall thickness.
*   A way to control the space between the side walls of nested trays, and a separate parameter to control the space between the bottom of nested trays.
*   An option to have the height of the inner trays be reduced so their tops are flush with the top of the outer tray when nested, or to keep them all at the same height as the outer tray if I want to stack them separately.
*   A "demo mode" which displays the trays stacked vertically, so I can preview the overall size, and a "printing mode" where the trays are arranged side-by-side for easier printing on a 3D printer.
*   A parameter to adjust the horizontal spacing when the trays are arranged side-by-side for printing.

I expect that this design will not require any external libraries, just the built in functions.

[Assistant]
nested_trays.scad:
```

// Mode. Use "print" for actual printing.
mode = "printing";  // [demo, printing]

// Number of trays to generate.
num_trays = 3;

// Reduce the inner trays height to be flush with the outer tray.
nested_height = "y";  // [y, n]

// Total length of the outer tray.
outer_length = 95;

// Total width of the outer tray.
outer_width = 75;

// Total height of the outer tray.
outer_height = 15;

// Radius of the side corners. Same for all trays.
side_radius = 5;

// A small radius at the bottom corners of the trays.
bottom_radius = 1.0;

// The thickness of the side wall of each tray.
side_wall = 2;

// The thickness of the bottom of each tray.
bottom_wall = 1.6;

// Allow this space around trays when inserterd inout outer trays.
side_margin = 0.6;

// Assume this vertical space between nested trays. Used to tweak
// the nesteted height.
bottom_margin = 0.0;

// Vertical spacing in demo mode. Doesn't affect printed models.
demo_bottom_margin = 0.1;

// Space between trays on the printing bed.
printing_space = 5;

/* [Hidden] */

// Tiny distance. Used to maintain manifold.
eps1 = 0.001;

// Smoothness of rounded corners. Higher is smoother.
$fn = 90;

// Rounded on the sides.
module rounded_slab1(l, w, h, r1) {
  dx = l/2-r1;
  dy = w/2-r1;
  hull() {
    translate([dx, dy, 0]) cylinder(r=r1, h=h);
    translate([dx, -dy, 0]) cylinder(r=r1, h=h);
    translate([-dx, dy, 0]) cylinder(r=r1, h=h);
    translate([-dx, -dy, 0]) cylinder(r=r1, h=h);
  }
}

module rounded_slab2(l, w, h, r1, r2) {
   translate([0, 0, r2]) minkowski() {
    rounded_slab1(l-2*r2, w-2*r2, eps1, r1-r2);
    sphere(r=r2, $fn=32);
  }
  translate([0, 0, r2])rounded_slab1(l, w, h-r2, r1);
}

module tray(l, w, h, r1, r2) {
  difference() {
    rounded_slab2(l, w, h, r1, r2);
    translate([0, 0, bottom_wall])
      rounded_slab2(l-2*side_wall, w-2*side_wall, h, r1-side_wall, r2);
  }
}

// 0 = outer, 1 = one before outer, ...
module tray_by_index(i) {
  l= outer_length - i*2*(side_wall + side_margin);
  w= outer_width - i*2*(side_wall + side_margin);
  h = (nested_height == "y")
      ? (outer_height - i * (bottom_wall + bottom_margin))
      : outer_height;
  tray(l, w, h, side_radius, bottom_radius);
}

module demo_mode() {
  difference() {
    union() {
      for (i =[0:num_trays-1]) {
        translate([0, 0, i*(demo_bottom_margin + bottom_wall)]) tray_by_index(i);
      }
    }
    translate([0, 0, -eps1]) cube([outer_length, outer_width, 2*num_trays*outer_height]);
  }
}

module printing_mode() {
  for (i =[0:num_trays-1]) {
    translate([0, i*(printing_space + outer_width - i*(side_wall+side_margin)), 0]) tray_by_index(i);
  }
}

module main() {
  if (mode == "demo") {
    demo_mode();
  } else {
    printing_mode();
  }
}

main();

//rounded_slab2(100, 80, 15, 5, 2);

////translate([0, 0, 2]) rounded_slab2(100-4, 60-4, 15, 5-2, 2);

//translate([0, 0, 2-eps1])rounded_slab1(100, 60, 15-2+eps1, 5);

//translate([0, 0, 0]) rounded_slab2(100, 60, 15, 5, 2);

//#translate([0, 0, 2*eps1]) rounded_slab1(100, 60, 15, 5);

```


[User]
Hey there, I'm looking for some help designing a parametric OpenSCAD model based on the Lorenz system. I've seen some really cool visualizations of this chaotic attractor and would love to be able to generate my own versions with some adjustable parameters.

Essentially, I want to be able to specify the initial values for x, y, and z, along with the system constants sigma, beta, and rho, and the time step, dt. I'd also need to control the number of points calculated along the trajectory and the sphere size used to represent each point. I'm thinking a series of connected spheres, similar to a beaded necklace, would be a great way to visualize it, and being able to change the color of the spheres would be nice too.

I've got some specific ideas for features I'd love to include:
*   **Parameter Inputs**: sigma, beta, rho, dt, starting x, y, and z values, recursions (number of spheres), and sphere size. I want all of these to be easily changeable.
*   **Color Customization**: A way to set the color of the spheres, maybe a simple string parameter like "red", "blue", or a hex code. I am not sure if OpenSCAD allows gradients, but if it does, a start color and end color that would gradient with sphere index would be amazing.
*   **Sphere Visualization**: Each calculated point from the Lorenz equations should be represented by a sphere.
*   **Multiple Trajectories**: Ability to have multiple Lorenz systems in one output, with each having a different set of starting parameters/constants, number of points, and sphere size.
*   **Preview Mode**: A quick way to view just a few points in the trajectory so I can quickly evaluate changes to the parameters before rendering a high resolution result.

It'd be great if the code was relatively clean and well-commented, too, for readability.

I am not sure about necessary OpenSCAD libraries, but I assume I don't need to include any libraries myself, you would know what is necessary to get the job done.

Let me know if you need any more info, and thanks in advance for your help!

[Assistant]
UrbanAtWork_Lorenz_System_v1.14.scad:
```
// Lorenz System - Lorenz Chaotic attractor
// 2015-12-09
// by Urban Reininger with lots of help from David Morgan, JeanInNepean and Atartanian
//
// Tested with OpenSCAD 2015.03
//
// for OpenSCAD use beta=8.0/3.0;
//
// Parameters
sigma=10.0;
// is ~ 8/3:
beta = 2.6666666667;
rho=28.0;

// dt Move this just a small amount for chaotic results:
dt=0.009; //[0.01:0.001:0.02]

// Recursions (number of spheres):
recursions = 2000; // [1:1:3000]

// Sphere size (one is default):
size=1; // [1:1:11]

function gen_p(p,n=0)=n==0?p:concat([p],gen_p([
        p.x+dt*(-sigma*p.x+sigma*p.y),
        p.y+dt*(rho*p.x-p.y-p.x*p.z),
        p.z+dt*(-beta*p.z+p.x*p.y)
    ],n-1));

color("red")
for (i=gen_p([1,1,1],recursions)) translate(i) sphere(size);
```


[User]
I'm looking to design a parametric mirror mount for a laser, similar to a small screw, that I can attach to my RepRap Athena 3D printer. I have a basic design already, but I would like to have a more robust, parametric version. The goal is for it to be used as part of a laser trip-wire emergency stop system so precision and adjustability are important.

The mount should have a threaded section like a screw, with the thread parameters being adjustable (pitch, major diameter, number of rotations/length). It needs a slot cut through the cylindrical body, the width of which also needs to be a parameter, where the mirror is installed and can then be secured in place. The main parameters I'm looking for are:
    - thread pitch
    - thread major diameter
    - thread length (number of rotations)
    - slot width
    - mount body length (total length of the cylindrical section, with the thread and slot)
    - mount body diameter (diameter of the non-threaded cylindrical body)
    - mirror thickness (for slot depth, since the slot should go all the way through).

I would also like to be able to specify the total length of the mount, including a section where it connects to the printer - in this case, I'd like this to be a simple rectangular block. I think I'd like a second rectangular block on the opposite side for stability as well. I'll need parameters for the size and length of these blocks, which should also have their position specified with parameters relative to the cylindrical body. Finally, I'd like all units to be in millimeters.

I would like the design to be as modular and parametric as possible, using named modules and clear variable names. Could you help me create this as an OpenSCAD file? I don't need any libraries for this design.

[Assistant]
mirror_screw.scad:
```

slot  = 1; //since of slot for cut mirror

module screwthread_triangle(P) {
	difference() {
		translate([-sqrt(3)/3*P+sqrt(3)/2*P/8,0,0])
		rotate([90,0,0])
		cylinder(r=sqrt(3)/3*P,h=0.00001,$fn=3,center=true);

		translate([0,-P/2,-P/2])
		cube([P,P,P]);
	}
}

module screwthread_onerotation(P,D_maj,step) {
	H = sqrt(3)/2*P;
	D_min = D_maj - 5*sqrt(3)/8*P;

	for(i=[0:step:360-step])
	hull()
		for(j = [0,step])
		rotate([0,0,(i+j)])
		translate([D_maj/2,0,(i+j)/360*P])
		screwthread_triangle(P);

	translate([0,0,P/2])
	cylinder(r=D_min/2,h=2*P,$fn=360/step,center=true);
}

module thread(P,D,step,rotations) {
    // added parameter "rotations"
    // as proposed by user bluecamel
	for(i=[0:rotations])
	translate([0,0,i*P])
	screwthread_onerotation(P,D,step);
}

$fn = 100;
module screw(){
union(){

thread(2,6,10,10);
    translate([-3.5,-10,20])cube([7,20,7]);
}
}

module mirror_screw(){
    difference(){
        screw();
      translate([0,0,26])cube([slot,20,10], center = true);
    }
}
mirror_screw();
```


[User]
Hey, I'm looking to get some help designing a parametric LED tea light in OpenSCAD. I'd like it to be able to accommodate a standard CR2032 battery, a 5mm LED, and optionally have a switch. I want to be able to easily solder the components as well.

Here are the key features I need:

*   **Battery Holder:** It should have an integrated holder for a CR2032 coin cell battery. I'd like the battery to be held in with a clip type mechanism similar to the ones mentioned in the included description: Solarbotics (bhold2032) or digikey (BS-7).
*   **LED Holder:** There needs to be a cavity to hold a standard 5mm LED, with easy access for soldering to the leads.
*   **Switch:** This is optional, but I would like to be able to easily include a small slide switch in the design like the one linked in the description (digikey CKN10397).
*   **Parametric Design:** I need to be able to adjust the diameter and height of the tealight, as well as the outer diameter of the LED holder.
*   **Text:**  Include some small text labels to indicate the polarity of the LED leads (Long=+, Flat=-).
*   **Top Ring:** Should have a top ring with a push-fit, for placing "hats" on top of the tea light. The inner diameter, outer diameter and thickness of this ring should all be parameters.

I'd also like to be able to easily define a nozzle diameter for 3D printing.

I'd like to be able to choose whether to create the model with the switch or without, via a parameter.

I'm not picky about libraries, feel free to use whatever works best to get the job done. I don't have any preference over which MCAD or BOSL variant is used.

[Assistant]
LEDTeaLight.scad:
```
// License:  Creative Commons Attribtion-NonCommercial-ShareAlike
// http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
//
// Author: Jetty, 10th December, 2015
// Parametric LED Tea Light
//
// Suggested Christmas tree settings:
//      tealight_diameter			= 42
//      tealight_height				= 14.65
//      led_holder_outer_diameter	= 9.8;
//
// Defaults (regular Tea Light Size - 1.5mm for top cover):
//      part = "noswitch"
//      tealight_diameters = 37.5
//      tealight_height = 15.5
//      led_holder_outer_diameter = 8.0

// preview[view:north, tilt:top diagonal]

// Customizer parameters
switch                          = "noswitch";   // [noswitch:No Switch, switch:With Switch]
tealight_diameter               = 37.5;         // [33.0:0.5:100.0]
tealight_height                 = 14.65;        // [14.65:0.05:35.0]
led_holder_outer_diameter       = 8.0;          // [8.0:0.1:13]
nozzle_diameter                 = 0.4;          // [0.05:0.05:2.0];

/* [Hidden] */
// DO NOT CHANGE THESE
switchClearance					= 0.1;
switchInsetFromEdge				= 2.0;
switchTravelBlockDimensions		= [5 + switchClearance * 2, 3.0 + switchClearance * 2, 4.0];
switchMainBodyDimensions		= [8.75 + switchClearance * 2, 4.45 + switchClearance * 2, 4.7 + 2.8 + switchClearance * 2];
switchChannelFlange				= [switchMainBodyDimensions[0] - 2,
								   switchMainBodyDimensions[1],
								   (tealight_diameter - led_holder_outer_diameter) / 2 - switchInsetFromEdge - switchMainBodyDimensions[2]];
switchRetainerBorder			= 1.5;
switchRetainerBlockDimensions	= [ switchMainBodyDimensions[0] + switchRetainerBorder * 2,
									switchMainBodyDimensions[2] + switchRetainerBorder,
									switchMainBodyDimensions[1]
								  ];

topRingThickness				= switchMainBodyDimensions[1];
baseHeight						= tealight_height - topRingThickness;
cr2032HolderDiameter			= 22.5;
cr2032HolderBlockWidth			= 8.0;
cr2032HolderBlockDepth			= 2.5;
cr2032HolderLeadDiameter		= 1.8;
cr2032HolderLead1Pos			= [-(cr2032HolderDiameter / 2 - 2.75), 0, 0];
cr2032HolderLead2Pos			= [cr2032HolderLead1Pos[0] + 20, cr2032HolderLead1Pos[1], cr2032HolderLead1Pos[2]];
cr2032HolderThickness			= baseHeight - 1.0;

ledHolderHeight					= 9.0;
ledHolderInsetDepth				= 1.5;
ledDiameter						= 6.0;	// Diameter of the lip of the led, not the led size
ledLeadThickness				= 1.0;

topRingInnerDiameter			= 30;

topLedVoidClearance				= 0.1;

textThickness                   = 0.5;
textSize                        = 3.0;
textPositiveOffset              = [cr2032HolderLead2Pos[0], 3, baseHeight + textThickness/2];
textLine2Offset                 = [0, 12.0, baseHeight + textThickness/2];
textLine1Offset                 = [0, textLine2Offset[1] - (textSize + 1), baseHeight + textThickness/2];

manifoldCorrection = 0.02;

$fn = 80;

if ( switch == "noswitch" )
	createWithoutSwitch();

if ( switch == "switch" )
	createWithSwitch();

// Text
color( [1.0, 0.0, 0.0] )
{
    translate( textPositiveOffset )
        linear_extrude( height=textThickness, center=true)
            text("+", font="Helvetica:Bold", valign="center", halign="center", size=textSize);

    translate( textLine1Offset )
        linear_extrude( height=textThickness, center=true)
            rotate( [0, 0, 180] )
                text("Led Flat=-,", font="Helvetica:Bold", valign="center", halign="center", size=textSize);

    translate( textLine2Offset )
        linear_extrude( height=textThickness, center=true)
            rotate( [0, 0, 180] )
                text("Long=+", font="Helvetica:Bold", valign="center", halign="center", size=textSize);
}

module createWithSwitch()
{
	difference()
	{
		union()
		{
			tealightBase();
			translate( [0, -tealight_diameter / 2 + switchInsetFromEdge, tealight_height] )
				translate( [-switchRetainerBlockDimensions[0]/2, 0, -switchRetainerBlockDimensions[2]] )
					cube( switchRetainerBlockDimensions, center=false );
		}
		translate( [0, -tealight_diameter / 2 + switchInsetFromEdge, tealight_height + manifoldCorrection] )
			switch();
	}
}

module createWithoutSwitch()
{
	tealightBase();
}

module switch()
{
	translate( [0, 0, -switchMainBodyDimensions[1] / 2] )
		rotate( [90, 0, 0] )
		{
			translate( [0, 0, switchTravelBlockDimensions[2] / 2 - manifoldCorrection] )
				cube( switchTravelBlockDimensions, center = true );
			translate( [0, 0, -switchMainBodyDimensions[2] / 2] )
				cube( switchMainBodyDimensions, center = true );
			translate( [0, 0, -(switchChannelFlange[2] / 2 + switchMainBodyDimensions[2]) + manifoldCorrection ] )
				cube( switchChannelFlange, center = true );
		}
}

module tealightBase()
{
	difference()
	{
		union()
		{
			// The main base
			cylinder( r=tealight_diameter / 2,	 h=baseHeight);

			// The led holder
			translate( [0, 0, baseHeight] )
				ledHolder();

			// The top ring
			translate( [0, 0, baseHeight - manifoldCorrection] )
				donut(tealight_diameter, topRingInnerDiameter, topRingThickness);
		}

		// The void for the battery holder
		translate( [0, 0, -manifoldCorrection] )
			union()
			{
				cylinder( r=cr2032HolderDiameter / 2, h=cr2032HolderThickness);
				translate( [(cr2032HolderDiameter + cr2032HolderBlockDepth) / 2, 0, cr2032HolderThickness/2] )
				{
					cube( [cr2032HolderBlockDepth, cr2032HolderBlockWidth, cr2032HolderThickness], center = true );
					translate( [-(cr2032HolderBlockDepth-manifoldCorrection), 0, 0] )
						cube( [cr2032HolderBlockDepth, cr2032HolderBlockWidth, cr2032HolderThickness], center = true );
				}
			}

		// The holes for the leads
		translate( cr2032HolderLead1Pos )
			cylinder( r=cr2032HolderLeadDiameter / 2, h=baseHeight + manifoldCorrection * 2);
		translate( cr2032HolderLead2Pos )
			cylinder( r=cr2032HolderLeadDiameter / 2, h=baseHeight + manifoldCorrection * 2);
	}
}

module ledHolder()
{
	difference()
	{
		cylinder( r=led_holder_outer_diameter / 2, h=ledHolderHeight );
		translate( [0, 0, (ledHolderHeight - ledHolderInsetDepth) + manifoldCorrection] )
			cylinder( r=ledDiameter / 2, h=ledHolderInsetDepth );
		translate( [-(led_holder_outer_diameter / 2 + manifoldCorrection), -ledLeadThickness / 2, -manifoldCorrection] )
			cube( [led_holder_outer_diameter + manifoldCorrection * 2, ledLeadThickness, ledHolderHeight + manifoldCorrection * 2] );
	}
}

module donut(outerDiameter, innerDiameter, thickness)
{
	union()
	difference()
	{
		cylinder( r=outerDiameter / 2, h=thickness );
		translate( [0, 0, -manifoldCorrection] )
			cylinder( r=innerDiameter / 2, h=thickness + manifoldCorrection * 2 );
	}
}
```


[User]
I'd like to create a candle-like hat for an LED tea light, and I need a parametric OpenSCAD design to do it. I've got an existing design that I really like, and I'd like to reproduce it from scratch, but I also need to add some extra features for a slightly different use case.

Here are the basic parameters I need:

*   `tealight_diameter`: This is the diameter of the tea light itself. It should default to 37.5mm, but be adjustable from 33mm to 100mm in 0.5mm increments.

*   `led_holder_outer_diameter`: This is the outer diameter of the LED holder. Default is 8mm, and I need to be able to adjust it between 8mm and 13mm in 0.1mm increments.

*   `nozzle_diameter`: This is for the simulated nozzle effect. Default to 0.4mm, and I need to control it between 0.05mm and 2.0mm in 0.05mm increments.

*   `candle_height_diameter_ratio`: This is the ratio of the candle height to its outer diameter. The default is 1.87, and I need it to be adjustable from 1.0 to 6.0 in 0.01 increments.

The design should create a base (a donut shape) that sits on the tea light, and then a candle shape that extends upwards from the base. The candle shape should have a slightly varied radius as it goes up, similar to a real candle. The original design uses a list of points to define the candle shape, which I’ve provided below:

```
candleCircles 			        = [
                                    [1.0,   0.0,  0.0,  0.0],
                                    [1.075, 0.05, 0.0,  0.0],
                                    [1.15,  0.1,  0.0,  0.0],
                                    [1.2,   0.15, 0.0,  0.0],
                                    [1.23,  0.2,  0.0,  0.0],
                                    [1.24,  0.25, 0.0,  0.0],
                                    [1.25,  0.3,  0.0,  0.0],
                                    [1.24,  0.35, 0.0,  0.0],
                                    [1.22,  0.4,  0.0,  0.0],
                                    [1.18,  0.45, 0.0,  0.0],
                                    [1.13,  0.5,  0.0,  0.0],
                                    [1.06,  0.55, 0.0,  0.0],
                                    [0.985, 0.6,  0.0,  0.0],
                                    [0.88,  0.65, 0.0,  0.15],
                                    [0.75,  0.7,  2.0,  0.5],
                                    [0.63,  0.75, 4.0,  1.0],
                                    [0.52,  0.8,  6.0,  1.5],
                                    [0.43,  0.85, 8.0,  2.0],
                                    [0.32,  0.9,  10.0, 2.8],
                                    [0.20,  0.95, 12.0, 3.6],
                                    [0.01,  1.0,  14.0, 4.4]
                                  ];
```

Each entry in the `candleCircles` list represents a circle defining the candle shape. The values are: `[radiusMultiplier, heightMultiplier[0-1], rotation, xTranslation]`. The radius is multiplied by the base radius, the height is multiplied by the total height of the candle. The rotation is in degrees, and the xTranslation is in mm. These should be used to generate the overall shape. Note that the candle's outer diameter is derived from `led_holder_outer_diameter` plus a bit of clearance and the `nozzle_diameter`.

I also want to add a small lip to the top of the base (donut) so that a small ring can attach to it. This lip should be on the outside of the donut, and should have a radius slightly larger than the main part of the donut. The height and thickness of the lip should be configurable. I'd like to add these as new parameters:

* `lip_height` (default 1mm, range 0.5mm to 3mm, 0.1mm increments)
* `lip_thickness` (default 0.5mm, range 0.2mm to 2mm, 0.1mm increments)
* `lip_radius_offset` (default 1mm, range 0.2mm to 3mm, 0.1mm increments)

Could you generate an OpenSCAD file that incorporates all of these features? I'd prefer not to use any external libraries, but if they would save you significant time and effort, please feel free to do so; just mention the library you use in your response.

[Assistant]
CandleHat.scad:
```
// License:  Creative Commons Attribtion-NonCommercial-ShareAlike
// http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
//
// Author: Jetty, 10th December, 2015
// Parametric Candle Hat For LED Tea Light
//

// preview[view:north, tilt:top diagonal]

// Customizer parameters
tealight_diameter			    = 37.5;		// [33:0.5:100.0]
led_holder_outer_diameter	    = 8.0;		// [8.0:0.1:13]
nozzle_diameter				    = 0.4;		// [0.05:0.05:2.0]
candle_height_diameter_ratio	= 1.87;		// [1.0:0.01:6.0]

/* [Hidden] */
// DO NOT CHANGE THESE
topThickness				    = 1.5;	// Thickness of the flange the candle is attached to (the top)
topLedVoidClearance		        = 0.1;

// [radiusMultipler, heightMultiplier[0-1], rotation, xTranslation ]
candleCircles 			        = [
                                    [1.0,   0.0,  0.0,  0.0],
                                    [1.075, 0.05, 0.0,  0.0],
                                    [1.15,  0.1,  0.0,  0.0],
                                    [1.2,   0.15, 0.0,  0.0],
                                    [1.23,  0.2,  0.0,  0.0],
                                    [1.24,  0.25, 0.0,  0.0],
                                    [1.25,  0.3,  0.0,  0.0],
                                    [1.24,  0.35, 0.0,  0.0],
                                    [1.22,  0.4,  0.0,  0.0],
                                    [1.18,  0.45, 0.0,  0.0],
                                    [1.13,  0.5,  0.0,  0.0],
                                    [1.06,  0.55, 0.0,  0.0],
                                    [0.985, 0.6,  0.0,  0.0],
                                    [0.88,  0.65, 0.0,  0.15],
                                    [0.75,  0.7,  2.0,  0.5],
                                    [0.63,  0.75, 4.0,  1.0],
                                    [0.52,  0.8,  6.0,  1.5],
                                    [0.43,  0.85, 8.0,  2.0],
                                    [0.32,  0.9,  10.0, 2.8],
                                    [0.20,  0.95, 12.0, 3.6],
                                    [0.01,  1.0,  14.0, 4.4]
                                  ];
candleOuterDiameter		        = led_holder_outer_diameter + topLedVoidClearance * 2 + nozzle_diameter * 4;
candleHeight			        = candle_height_diameter_ratio * candleOuterDiameter;

manifoldCorrection = 0.02;

$fn = 80;

candleTop();

module candleTop()
{
	donut(tealight_diameter, led_holder_outer_diameter + topLedVoidClearance * 2, topThickness);

	translate( [0, 0, topThickness] )
		shapeWithRotation(candleCircles, height = candleHeight, diameter = candleOuterDiameter);
}

// diameter is the bottom starting diameter

module shapeWithRotation(circles, height, diameter)
{
	radius = diameter / 2;

	difference()
	{
		// The outershell
		for ( i = [0:len(circles)-2] )
		{
			// Negative hull implemented by multiple hull of adjacent values
			hull()
			{
				translate( [circles[i][3], 0, height * circles[i][1]] )
					rotate( [0, circles[i][2], 0] )
						cylinder( r=radius * circles[i][0], h=0.1 );
				translate( [circles[i+1][3], 0, height * circles[i + 1][1]] )
					rotate( [0, circles[i + 1][2], 0] )
						cylinder( r=radius * circles[i + 1][0], h=0.1 );
			}
		}

		// The void inside
		for ( i = [0:len(circles)-2] )
		{
			// Negative hull implemented by multiple hull of adjacent values
			translate( [0, 0, -manifoldCorrection] )
				hull()
				{
					translate( [circles[i][3], 0, height * circles[i][1]] )
						rotate( [0, circles[i][2], 0] )
							cylinder( r=(radius * circles[i][0]) - nozzle_diameter * 2, h=0.1 );
					translate( [circles[i+1][3], 0, height * circles[i + 1][1]] )
						rotate( [0, circles[i + 1][2], 0] )
							cylinder( r=(radius * circles[i + 1][0]) - nozzle_diameter * 2, h=0.1 );
				}
		}
	}
}

module donut(outerDiameter, innerDiameter, thickness)
{
	union()
	difference()
	{
		cylinder( r=outerDiameter / 2, h=thickness );
		translate( [0, 0, -manifoldCorrection] )
			cylinder( r=innerDiameter / 2, h=thickness + manifoldCorrection * 2 );
	}
}
```


[User]
I'm looking to create a parametric snowman hat designed to fit on top of an LED tea light. I'd like to have a base that fits around the tea light and then a hat section that tapers outwards and then back in.

Specifically, I need the following parameters to be adjustable:

*   `tealight_diameter`: The diameter of the LED tea light that the base will fit around.
*   `led_holder_outer_diameter`: The diameter of the hole in the base that will fit around the LED itself.
*   `nozzle_diameter`:  A value that will control the thickness of the "walls" of the hat; essentially the "resolution" of the hat's shape.

I'd also like the hat to be generated using a series of points that define its overall shape. I have a list of these points, where each point is defined by a radius multiplier, a height multiplier, and a horizontal translation. I would like to pass these as a parameter called `snowmanCircles`. Here is an example of how `snowmanCircles` should be formatted:

```
snowmanCircles = [
    [0.291908,0.000000,-0.007225],
    [0.320809,0.011594,-0.007225],
    [0.349711,0.023188,-0.007225],
    [0.372832,0.034783,-0.007225],
    ...
];
```
I will also need `snowmanScaling`, `hatThicknessTop` and `hatInsertThickness` as parameters.

The hat should have a flat top that is separate from the main body of the hat, that has a hole in the middle for the hat to fit into.

The hat should have a base that has a hole that is the size of `led_holder_outer_diameter` (with a small clearance), and a lip around the outside that has the same diameter as the `tealight_diameter`.

Finally, I need the code to be able to output two separate components, one for the base and one for the hat. It should also be designed to avoid manifold errors when printing by adding a small constant.

I think that covers everything. I'm assuming you'll be using built-in OpenSCAD functions for all of this, so I don't think any special libraries are required.

[Assistant]
SnowmanHat.scad:
```
// License:  Creative Commons Attribtion-NonCommercial-ShareAlike
// http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
//
// Author: Jetty, 10th December, 2015
// Parametric Snowman Hat For LED Tea Light
//

// preview[view:north, tilt:top diagonal]

// Customizer parameters
tealight_diameter			= 37.5;		// [33:0.5:100.0]
led_holder_outer_diameter	= 8.0;		// [8.0:0.1:13]
nozzle_diameter				= 0.4;		// [0.05:0.05:2.0]

/* [Hidden] */
// DO NOT CHANGE THESE
topThickness				= 1.5;	// Thickness of the flange the candle is attached to (the top)
topLedVoidClearance		    = 0.1;

// [radiusMultipler, heightMultiplier[0-1], xTranslation ]
snowmanCircles 			    = [
                                [0.291908,0.000000,-0.007225],
                                [0.320809,0.011594,-0.007225],
                                [0.349711,0.023188,-0.007225],
                                [0.372832,0.034783,-0.007225],
                                [0.390173,0.046377,-0.007225],
                                [0.407514,0.057971,-0.007225],
                                [0.424856,0.069565,-0.007225],
                                [0.436416,0.081159,-0.007225],
                                [0.447977,0.092754,-0.007225],
                                [0.459538,0.104348,-0.007225],
                                [0.465318,0.115942,-0.007225],
                                [0.471098,0.127536,-0.007225],
                                [0.476879,0.139130,-0.007225],
                                [0.476879,0.150725,-0.007225],
                                [0.476879,0.162319,-0.007225],
                                [0.476879,0.173913,-0.007225],
                                [0.476879,0.185507,-0.007225],
                                [0.471098,0.197101,-0.007225],
                                [0.468208,0.208696,-0.008671],
                                [0.462428,0.220290,-0.008671],
                                [0.453757,0.231884,-0.007225],
                                [0.445087,0.243478,-0.008671],
                                [0.433526,0.255072,-0.005780],
                                [0.419075,0.266667,-0.007225],
                                [0.404624,0.278261,-0.008671],
                                [0.387283,0.289855,-0.008671],
                                [0.367052,0.301449,-0.007225],
                                [0.343931,0.313043,-0.007225],
                                [0.315029,0.324638,-0.007225],
                                [0.323699,0.336232,-0.008671],
                                [0.343931,0.347826,-0.007225],
                                [0.361272,0.359420,-0.007225],
                                [0.372832,0.371014,-0.007225],
                                [0.384393,0.382609,-0.007225],
                                [0.395954,0.394203,-0.007225],
                                [0.401734,0.405797,-0.007225],
                                [0.407514,0.417391,-0.007225],
                                [0.407514,0.428986,-0.007225],
                                [0.413295,0.440580,-0.007225],
                                [0.413295,0.452174,-0.007225],
                                [0.410405,0.463768,-0.008671],
                                [0.407514,0.475362,-0.007225],
                                [0.401734,0.486957,-0.007225],
                                [0.395954,0.498551,-0.007225],
                                [0.384393,0.510145,-0.007225],
                                [0.378613,0.521739,-0.007225],
                                [0.361272,0.533333,-0.007225],
                                [0.349711,0.544928,-0.007225],
                                [0.326590,0.556522,-0.007225],
                                [0.309249,0.568116,-0.007225],
                                [0.280347,0.579710,-0.007225],
                                [0.251445,0.591304,-0.007225],
                                [0.251445,0.602899,-0.007225],
                                [0.268786,0.614493,-0.007225],
                                [0.283237,0.626087,-0.008671],
                                [0.291908,0.637681,-0.007225],
                                [0.303468,0.649275,-0.007225],
                                [0.306358,0.660870,-0.008671],
                                [0.309249,0.672464,-0.007225],
                                [0.309249,0.684058,-0.007225],
                                [0.309249,0.695652,-0.007225],
                                [0.303468,0.707246,-0.007225],
                                [0.297688,0.718841,-0.007225],
                                [0.291908,0.730435,-0.007225],
                                [0.280347,0.742029,-0.007225],
                                [0.263006,0.753623,-0.007225],
                                [0.245665,0.765217,-0.007225],
                                [0.263006,0.776812,-0.007225],
                                [0.280347,0.788406,-0.007225],
                                [0.280347,0.800000,-0.007225],
                                [0.280347,0.811594,-0.007225],
                                [0.245665,0.823188,-0.007225],
                                [0.245665,0.834783,-0.007225],
                                [0.245665,0.846377,-0.007225],
                                [0.245665,0.857971,-0.007225],
                                [0.245665,0.869565,-0.007225],
                                [0.245665,0.881159,-0.007225],
                                [0.245665,0.892754,-0.007225],
                                [0.245665,0.904348,-0.007225],
                                [0.245665,0.915942,-0.007225]
                              ];

snowmanScaling			    = 1.5;
snowmanOuterDiameter		= tealight_diameter * snowmanScaling;
snowmanHeight			    = tealight_diameter * snowmanScaling;
hatThicknessTop             = 0.82;
hatOffset                   = [tealight_diameter / 2 + 3, 0, 0];
hatInsertThickness          = 2.0;

manifoldCorrection = 0.02;

$fn = 80;

snowmanTop();
translate( hatOffset )
    snowmanHatCover();

module snowmanHatCover()
{
    hatDiameter = snowmanOuterDiameter * snowmanCircles[len(snowmanCircles)-1][0];
    innerHatDiameter = hatDiameter - (nozzle_diameter * 4 + topLedVoidClearance * 2);

    translate( [hatDiameter / 2, 0, 0] )
    {
        cylinder( r=hatDiameter / 2, h = hatThicknessTop );
        translate( [0, 0, hatThicknessTop - manifoldCorrection] )
               donut( innerHatDiameter, innerHatDiameter - nozzle_diameter * 4, hatInsertThickness );
    }
}

module snowmanTop()
{
	donut(tealight_diameter, led_holder_outer_diameter + topLedVoidClearance * 2, topThickness);

	translate( [0, 0, topThickness] )
		shape(snowmanCircles, height = snowmanHeight, diameter = snowmanOuterDiameter);
}

// diameter is the bottom starting diameter

module shape(circles, height, diameter)
{
	radius = diameter / 2;

	difference()
	{
		// The outershell
		for ( i = [0:len(circles)-2] )
		{
			// Negative hull implemented by multiple hull of adjacent values
			hull()
			{
				translate( [diameter * circles[i][2], 0, height * circles[i][1]] )
						cylinder( r=radius * circles[i][0], h=nozzle_diameter );
				translate( [diameter *  circles[i+1][2], 0, height * circles[i + 1][1]] )
						cylinder( r=radius * circles[i + 1][0], h=nozzle_diameter );
			}
		}

		// The void inside
		for ( i = [0:len(circles)-2] )
		{
			// Negative hull implemented by multiple hull of adjacent values
			translate( [0, 0, -manifoldCorrection] )
				hull()
				{
					translate( [diameter * circles[i][2], 0, height * circles[i][1]] )
							cylinder( r=(radius * circles[i][0]) - nozzle_diameter * 2, h=nozzle_diameter );
					translate( [diameter * circles[i+1][2], 0, height * circles[i + 1][1]] )
							cylinder( r=(radius * circles[i + 1][0]) - nozzle_diameter * 2, h=nozzle_diameter );
				}
		}
	}
}

module donut(outerDiameter, innerDiameter, thickness)
{
	union()
	difference()
	{
		cylinder( r=outerDiameter / 2, h=thickness );
		translate( [0, 0, -manifoldCorrection] )
			cylinder( r=innerDiameter / 2, h=thickness + manifoldCorrection * 2 );
	}
}
```


[User]
Hey, I'm looking to get an OpenSCAD design for a skid plate that attaches to a round carbon fiber arm, like on a robot arm or drone. This skid plate will protect the arm and the motor shaft, and needs to have screw holes.

Here's what I need:

*   **Base Shape:** The main body of the skid plate should be a short, slightly tapered cylinder. The bottom should be larger than the top, sort of like a short cone, but with cylindrical walls.
*   **Arm Diameter:** The main body will need to have an inner diameter of 'armDiameter', which I will specify and that should be parametric. This needs to be hollowed out so the arm can fit through it.
*   **Taper:** The 'plateTilt' parameter should control the slight taper, that is, the difference in diameter between the top and bottom of the main body.
*   **Height:** The overall height should also be parametric ('height').
*  **Motor Axle Protection:** There needs to be a hollow cylinder at the center, with a slightly smaller diameter, to provide a small gap around the motor axle. The depth of this hollow should be controlled by the parameter 'motorAxleIndent'.
*   **Screw Holes:** There need to be four screw holes, spaced symmetrically around the central hollow area. These holes should allow for countersunk screws.
*  **Hole Placement:** The screw holes must be arranged so that each one has a mounting tab (a solid piece) extending inwards in a rectangular shape for some adjustable distance between a minimum 'holeDistanceMin' and a maximum 'holeDistanceMax', and a circular hole at the far edge.
*   **Hole Diameters:**  The main hole diameter should be 'holeDiameter' and the counterbore should have a diameter of 'holeHeadDiameter'. The counterbore should extend downwards from some height controlled by 'screwHeight'.
*   **Parameters:** I need to be able to adjust 'armDiameter', 'plateTilt', 'screwHeight', 'height', 'motorAxleIndent', 'holeDiameter', 'holeHeadDiameter', 'holeDistanceMin', and 'holeDistanceMax'.

I'd like the design to be parametric, so I can adjust these dimensions easily later. I'm not picky about the exact way you achieve the screw hole/tab design, but it should be functionally similar to how it is in the example scad file and should create a mount for each screw. It would be really useful to have this in a single file.

Can you generate that for me?

[Assistant]
ArmSkidPlate.scad:
```
armDiameter=32;
plateTilt=2;
screwHeight=0.5;
height=2.5;

motorAxleIndent=0.5;

holeDiameter=3;
holeHeadDiameter=6;
holeDistanceMin=8;
holeDistanceMax=10;

difference() {
    cylinder(d=armDiameter,d2=armDiameter-plateTilt,h=height,$fn=64);
	 cylinder(d=holeDistanceMin,h=motorAxleIndent,$fn=64);

    for(r=[0,90,180,270])
    {
        rotate([0,0,r+45])
        union() {
				translate([holeDistanceMin,0,-1])
				cylinder(d=holeDiameter,h=height,$fn=32);
            translate([holeDistanceMin,0,screwHeight])
            cylinder(d=holeHeadDiameter,d2=holeHeadDiameter+plateTilt,h=height,$fn=32);

				translate([holeDistanceMin,-holeDiameter/2,-1])
				cube([holeDistanceMax-holeDistanceMin,holeDiameter,height]);

				translate([holeDistanceMax,0,-1])
				cylinder(d=holeDiameter,h=height,$fn=32);
            translate([holeDistanceMax,0,screwHeight])
            cylinder(d=holeHeadDiameter,d2=holeHeadDiameter+plateTilt,h=height,$fn=32);
        }
    }
}

```


[User]
I'm looking to create a parametric battery box for AA batteries, similar to the one I found on Thingiverse, but I'd like it generated from scratch, and have a few specific features I need.

The box should be able to hold a variable number of AA batteries, configurable through a parameter. I need to be able to specify the number of cells, with a reasonable upper limit, say up to 50.

I need three distinct parts generated: the battery *holder*, the *cover*, and a design that includes *all* the parts together in their intended assembly positions. These parts should be selectable through a single parameter, I would like to be able to view the models separately, or as a combined assembly.

The holder should have integrated spring contacts, suitable for the surface mount battery contacts from Digikey, specifically the SN-T5-1 and SN-T5-2. These parts need to be integrated into the design parametrically.

There should be parametric mounting lugs, with options for "topbottom", "sides", or "none". If lugs are chosen they need to be parametric based on the screw diameter and thickness.

I'd like to parameterize the width of the channels between battery cells. There should be one parameter for the main channel width (center_channel_width) and another for other channel widths (other_channel_width) along the sides of the battery box. I also want to specify a parameter for the clearance between the cover and the holder, this can be called coverRetainerClearance.

I'd also like a parameter for the nozzle diameter of the 3D printer, this would be used to adjust the design for different nozzle sizes.

The battery box should have text labels for "+" signs on the positive terminals.

I would like the box to include cover retainers, and parameterize the cover retainer clearance.

I’d like to see the final result of all the parts together, with the cover slightly offset so I can view both the cover and the holder simultaneously.

I expect to use the code output with OpenSCAD and don't want any external libraries, I would prefer for it to be all native code. Please also ensure there are manifold corrections applied where needed, as well as standard OpenSCAD $fn settings to produce smooth curves.

Please provide a fully parametric OpenSCAD solution based on these requirements.

[Assistant]
BatteryBox.scad:
```
// License:  Creative Commons Attribtion-NonCommercial-ShareAlike
// http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
//
// Author: Jetty, 10th December, 2015
// Parametric AA Battery Box With Contacts
//

// preview[view:north, tilt:top diagonal]

// Customizer parameters
part                            = "holder";        // [holder:Holder, cover:Cover, all:All Parts]
cells                           = 4;            // [1:50]
mounting_lugs                   = "topbottom";  // [topbottom, sides, none]
mounting_lug_screw_diameter     = 3;            // [1:0.1:9]
mounting_lug_thickness          = 4;            // [0.5:0.1:10]
center_channel_width            = 3.0;          // [0.2:0.1:7.0]
other_channel_width             = 2.5;          // [0.2:0.1:5.0]
coverRetainerClearance          = 0.1;          // [0.0:0.05:0.3]
nozzle_diameter                 = 0.4;          // [0.05:0.05:0.7]

/* [Hidden] */
// DO NOT CHANGE THESE
AACellLength                    = 50.5;     // 49.2 - 50.5mm nominal
AACellDiameter                  = 14.5;     // 13.5 - 14.5mm nominal
bottomThickness                 = 3;
endThickness                    = 2;
sideThickness                   = 0.5;
endSideThickness                = 2.0;
negContactLength                = 4.5;        // This is the length when the spring is compressed
posContactLength                = 1.55;
cellBarrelLength                = AACellLength + negContactLength + posContactLength;
singleCellHolderDimensions      = [AACellDiameter + sideThickness * 2, cellBarrelLength + endThickness * 2, AACellDiameter / 2 + bottomThickness];
textSize                        = 8;
textDepth                       = 1.20;
textOffsetPosTop                = [0, AACellLength / 2 - 5, bottomThickness];
textOffsetPosBottom             = [textOffsetPosTop[0], -textOffsetPosTop[1], textOffsetPosTop[2]];
contactDimensions               = [10.8, nozzle_diameter + 0.1, 13.2];
contactRetainerThickness        = 0.82;
contactClearance                = 8.8;
contactThickness                = 1.23;
contactRetainerDimensions       = [ singleCellHolderDimensions[0],
                                    contactDimensions[2],
                                    endThickness + contactDimensions[1] + contactRetainerThickness];
contactRetainerCornerRadius     = 3.0;
contactLugDimensions            = [3.2, contactDimensions[1], 8.7];
mountLugInset                   = 12;
mountLugThickness               = 4;
mountingLugScaling              = 1.25;
undersideChannellingThickness   = bottomThickness - 1;
lugVoidLength                   = (contactLugDimensions[2] - (bottomThickness - undersideChannellingThickness)) + 1;
lugVoidWidth                    = contactLugDimensions[0] + 1;
coverThickness                  = 0.27 * 3;
coverDifferenceDimensions       = [(singleCellHolderDimensions[0] * cells + endSideThickness * 2) * 2,
                                   singleCellHolderDimensions[1] * 2,
                                   (contactRetainerDimensions[1] + bottomThickness) * 2];
holderCoverSpacing              = 3;
coverRetainerDiameter           = 3;
coverRetainerOffset             = [ other_channel_width / 2 + coverRetainerDiameter / 2 + 1.25,
                                    singleCellHolderDimensions[1] / 2 - (coverRetainerDiameter / 2 + 1),
                                    0];
coverRetainerHeight             = undersideChannellingThickness;
coverRetainerVerticalClearance  = 0.5;

$fn = 80;
manifoldCorrection = 0.02;

if  ( part == "holder" )
{
    holder();
}

if  ( part == "cover" )
{
    translate( [0, 0, coverThickness] )
        cover();
}

if  ( part == "all" )
{
    all();
}

module coverRetainer()
{
    translate( [0, 0, coverRetainerHeight / 2] )
        cylinder( r=coverRetainerDiameter / 2, h=coverRetainerHeight - coverRetainerVerticalClearance, center = true );
}

module coverRetainerVoid()
{
    translate( [0, 0, coverRetainerHeight / 2 + manifoldCorrection] )
        cylinder( r=(coverRetainerDiameter + coverRetainerClearance) / 2, h=coverRetainerHeight + manifoldCorrection * 2, center = true );
}

module all()
{
    rotate( [0, 0, 90] )
    {
        lugsTranslateY = ( mounting_lugs == "topbottom" ) ?
                                (-( (mounting_lug_screw_diameter * mountingLugScaling * mountingLugScaling) * 2 +
                                    (mounting_lug_screw_diameter * mountingLugScaling) * 2))
                                                          : 0;

        translate( [0, singleCellHolderDimensions[1] / 2 -(lugsTranslateY - holderCoverSpacing)/ 2, 0] )
        {
            holder();
            translate( [0, -singleCellHolderDimensions[1], coverThickness] )
                translate( [0, lugsTranslateY, 0] )
                    translate( [0, -holderCoverSpacing, 0] )
                        cover();
        }
    }
}

module holder()
{
    difference()
    {
        multipleCells(cells, mounting_lugs);

        translate( [0, 0, -coverDifferenceDimensions[2] / 2 + manifoldCorrection] )
            cube( coverDifferenceDimensions, center = true );
    }
}

module cover()
{
    difference()
    {
        multipleCells(cells, mounting_lugs);

        translate( [0, 0, coverDifferenceDimensions[2] / 2 - manifoldCorrection] )
            cube( coverDifferenceDimensions, center = true );

    }

    // Cover retainers
    translate( [0, 0, -manifoldCorrection] )
        multipleCellsRetainersOnly(cells);
}

module coverPlateBlock()
{
    translate( [0, 0, - coverThickness / 2] )
        cube( [singleCellHolderDimensions[0] * cells + endSideThickness * 2, singleCellHolderDimensions[1], coverThickness], center = true );
}

module lugVoid()
{
    translate( [0, -(lugVoidLength - lugVoidWidth / 2) + manifoldCorrection, 0] )
    {
        cylinder( r=lugVoidWidth / 2, h=undersideChannellingThickness, center = true );
        translate( [0, (lugVoidLength - lugVoidWidth / 2) / 2, 0] )
            cube( [lugVoidWidth, lugVoidLength - lugVoidWidth / 2, undersideChannellingThickness], center = true );
    }
}

module horizontalChannel(width)
{
    cube( [singleCellHolderDimensions[0] + manifoldCorrection * 2, width, undersideChannellingThickness], center = true );
}

module verticalChannel(width)
{
    cube( [width, singleCellHolderDimensions[1] - (endThickness + contactDimensions[1]) * 2, undersideChannellingThickness], center = true );
}

module undersideTabsAndChanneling()
{
    translate( [0, 0, undersideChannellingThickness / 2 - manifoldCorrection] )
    {
        translate( [0, singleCellHolderDimensions[1] / 2 - endThickness - contactDimensions[1], 0] )
        {
            lugVoid();

            // Lug Void Side Channel
            translate( [0, -(lugVoidLength - (other_channel_width / 2 + lugVoidWidth / 4)), 0] )
                horizontalChannel(other_channel_width);
        }

        translate( [0, -(singleCellHolderDimensions[1] / 2 - endThickness - contactDimensions[1]), 0] )
        {
            rotate( [180, 0, 0] )
                    lugVoid();

            // Lug Void Side Channel
            translate( [0, (lugVoidLength - (other_channel_width / 2 + lugVoidWidth / 4)) , 0] )
                horizontalChannel(other_channel_width);
        }

        // Center Channel
        horizontalChannel(center_channel_width);

        // Vertical Channel
        verticalChannel(other_channel_width);
    }
}

module mountingLug()
{
    translate( [-mounting_lug_screw_diameter * mountingLugScaling * mountingLugScaling, 0, - coverThickness] )
        difference()
        {
            union()
            {
                cylinder( r=mounting_lug_screw_diameter * mountingLugScaling, h=mounting_lug_thickness + coverThickness );
                translate( [0, -mounting_lug_screw_diameter * mountingLugScaling, 0] )
                    cube( [ mounting_lug_screw_diameter * mountingLugScaling * mountingLugScaling,
                            mounting_lug_screw_diameter * mountingLugScaling * 2,
                            mounting_lug_thickness + coverThickness] );

            }
            translate( [0, 0, -manifoldCorrection] )
                cylinder( r=mounting_lug_screw_diameter / 2, h=mounting_lug_thickness + coverThickness + manifoldCorrection * 2 );
        }
}

module multipleCells(cellCount, mounting_lugs)
{
    if ( mounting_lugs == "sides" )
    {
        translate( [- ((cellCount * singleCellHolderDimensions[0]) + endSideThickness * 2) / 2, 0, 0] )
        {
            translate( [0, singleCellHolderDimensions[1] / 2 - (mountLugInset + mounting_lug_screw_diameter), 0] )
                mountingLug();
            translate( [0, -(singleCellHolderDimensions[1] / 2 - (mountLugInset + mounting_lug_screw_diameter)), 0] )
                mountingLug();
        }

        translate( [((cellCount * singleCellHolderDimensions[0]) + endSideThickness * 2) / 2, 0, 0] )
        {
            translate( [0, singleCellHolderDimensions[1] / 2 - (mountLugInset + mounting_lug_screw_diameter), 0] )
                rotate( [0, 0, 180] )
                    mountingLug();
            translate( [0, -(singleCellHolderDimensions[1] / 2 - (mountLugInset + mounting_lug_screw_diameter)), 0] )
                rotate( [0, 0, 180] )
                    mountingLug();
        }
    }

    translate( [- ((cellCount * singleCellHolderDimensions[0]) + endSideThickness * 2) / 2, 0, 0] )
        translate( [endSideThickness, 0, 0,] )
            for ( c = [0:cellCount-1] )
            {
                // Adds thin side bar on the left
                translate( [0, -singleCellHolderDimensions[1] / 2, 0] )
                {
                    if ( c == 0 )
                    {
                        translate( [-endSideThickness, 0, 0] )
                            sideBar();
                    }

                    // Adds thin side bar on the right
                    if ( c == (cellCount - 1) )
                    {
                         translate( [singleCellHolderDimensions[0] + c * singleCellHolderDimensions[0], 0, 0] )
                            sideBar();
                    }
                }

                translate( [singleCellHolderDimensions[0] / 2 + c * singleCellHolderDimensions[0], 0, 0] )
                    singleCell( (cellCount == 1 ) ? "both" : ((c == 0) ? "left" : ((c == cellCount-1) ? "right" : "none")), c);

                if ( mounting_lugs == "topbottom" && ( c == 0 || c == (cellCount - 1)) )
                {
                    translate( [singleCellHolderDimensions[0] / 2 + c * singleCellHolderDimensions[0], -singleCellHolderDimensions[1] / 2, 0] )
                        rotate( [0, 0, 90] )
                            mountingLug();
                    translate( [singleCellHolderDimensions[0] / 2 + c * singleCellHolderDimensions[0], singleCellHolderDimensions[1] / 2, 0] )
                        rotate( [0, 0, -90] )
                            mountingLug();
                }
            }

    // Cover plate
    coverPlateBlock();
}

module multipleCellsRetainersOnly(cellCount)
{
    translate( [- ((cellCount * singleCellHolderDimensions[0]) + endSideThickness * 2) / 2, 0, 0] )
        translate( [endSideThickness, 0, 0,] )
            for ( c = [0:cellCount-1] )
            {
                translate( [singleCellHolderDimensions[0] / 2 + c * singleCellHolderDimensions[0], 0, 0] )
                    singleCellRetainersOnly();
            }
}

module sideBar()
{
    difference()
    {
        cube( [ endSideThickness,
                singleCellHolderDimensions[1],
                contactRetainerDimensions[1] + bottomThickness - contactRetainerCornerRadius] );

        // The cylinder cutout for fingers - Commented out for structural reasons
        //translate( [sideThickness/2, singleCellHolderDimensions[1] / 2, AACellDiameter / 2 + bottomThickness + 5] )
        //    rotate( [0, 90, 0] )
        //        cylinder( r=AACellDiameter / 2, h = sideThickness + manifoldCorrection * 2, center = true );

        // Center Channel
        translate( [0, singleCellHolderDimensions[1] / 2, undersideChannellingThickness / 2 - manifoldCorrection] )
            horizontalChannel(center_channel_width);
    }
}

module singleCell(corners, index)
{
    difference()
    {
        union()
        {
            // The retainer blocks
            translate( [0, 0, -manifoldCorrection] )
            {
                translate( [0, (singleCellHolderDimensions[1] - contactRetainerDimensions[2]) / 2, 0] )
                    retainerBlock(contactRetainerDimensions, contactRetainerCornerRadius, corners);
                translate( [0, - (singleCellHolderDimensions[1] - contactRetainerDimensions[2]) / 2, 0] )
                    retainerBlock(contactRetainerDimensions, contactRetainerCornerRadius, corners);
            }

            difference()
            {
                // The box for the cell
                translate( [0, 0, singleCellHolderDimensions[2] / 2] )
                    cube( singleCellHolderDimensions, center = true );

                // The cylinder cutout for the box
                translate( [0, 0, AACellDiameter / 2 + bottomThickness] )
                    rotate( [-90, 0, 0] )
                        cylinder( r=AACellDiameter / 2, h = cellBarrelLength, center = true );

                // The cylinder cutout for fingers
                translate( [0, 0, AACellDiameter / 2 + bottomThickness] )
                    rotate( [0, 90, 0] )
                        cylinder( r=AACellDiameter / 2, h = singleCellHolderDimensions[0] + manifoldCorrection * 2, center = true );

                // The positive mark text
                translate( ( index % 2 == 0 ) ? textOffsetPosTop : textOffsetPosBottom )
                    linear_extrude( height=textDepth, center=true)
                        text("+", font="Helvetica:Bold", valign="center", halign="center", size=textSize);
            }
        }

        // The contact voids
        translate( [0, 0, bottomThickness] )
        {
            translate( [0, -(singleCellHolderDimensions[1] / 2 - endThickness), 0] )
                contact();

            translate( [0, singleCellHolderDimensions[1] / 2 - endThickness, 0] )
                rotate( [0, 0, 180] )
                    contact();
        }

        // Underside tabs and channelling
        undersideTabsAndChanneling();

        // Cover retainer voids
        translate( coverRetainerOffset )
            coverRetainerVoid();
        translate( - coverRetainerOffset )
            coverRetainerVoid();
        translate( [-coverRetainerOffset[0], coverRetainerOffset[1], coverRetainerOffset[2]] )
            coverRetainerVoid();
        translate( [coverRetainerOffset[0], -coverRetainerOffset[1], coverRetainerOffset[2]] )
            coverRetainerVoid();
    }
}

module singleCellRetainersOnly()
{
    // Cover retainers
    translate( coverRetainerOffset )
        coverRetainer();
    translate( - coverRetainerOffset )
        coverRetainer();
    translate( [-coverRetainerOffset[0], coverRetainerOffset[1], coverRetainerOffset[2]] )
        coverRetainer();
    translate( [coverRetainerOffset[0], -coverRetainerOffset[1], coverRetainerOffset[2]] )
        coverRetainer();
}

// Creates a retainer block, if corners="left", rounded corner is on the left
// if corners="right", rounded corner is on the right
// if corners="none", there are no rounded corners, it's rectangular

module retainerBlock(dimensions, radius, corners)
{
    translate( [0, 0, dimensions[1] / 2 + bottomThickness] )
        rotate( [90, 0, 0] )
            hull()
            {
                // Top Left corner
                translate( [-dimensions[0] / 2 + radius - endSideThickness, dimensions[1] / 2 - radius, 0] )
                {
                    if ( corners == "left" || corners == "both" )    cylinder( r=radius, h = dimensions[2], center = true );
                    else                                             cube( [radius * 2, radius * 2, dimensions[2]], center = true );
                }

                // Top Right corner
                translate( [dimensions[0] / 2 - radius + endSideThickness, dimensions[1] / 2 - radius, 0] )
                {
                    if ( corners == "right" || corners == "both" )   cylinder( r=radius, h = dimensions[2], center = true );
                    else                                             cube( [radius * 2, radius * 2, dimensions[2]], center = true );
                }

                // Bottom Corners
                translate( [0, -(dimensions[1] / 2 - radius), 0] )
                {
                    // Bottom left corner
                    translate( [-(dimensions[0] / 2 - radius) - (( corners == "left" || corners == "both" ) ? sideThickness : 0), 0, 0] )
                        cube( [radius * 2, radius * 2, dimensions[2]], center = true );

                    // Bottom right corner
                    translate( [dimensions[0] / 2 - radius + (( corners == "right" || corners == "both" ) ? sideThickness : 0), 0, 0] )
                        cube( [radius * 2, radius * 2, dimensions[2]], center = true );
                }
        }
}

module contact()
{
    translate( [0, contactDimensions[1] / 2, 0] )
    {
        // Main plate
        translate( [0, 0, contactDimensions[2] / 2] )
            cube( contactDimensions, center = true );

        // Solder Lug
        translate( [0, 0, -(contactLugDimensions[2] / 2 - manifoldCorrection)] )
        {
            cube( contactLugDimensions, center = true);
            //translate( [0, (contactLugDimensions[2] - 1) / 2, contactLugDimensions[2] / 2 - 2 + contactLugDimensions[1] / 4 ] )
              //  % cube( [contactLugDimensions[0], contactLugDimensions[2] - 1, contactLugDimensions[1]], center = true );
        }

        // Contact and opening
        translate( [0, contactThickness / 2, contactDimensions[2] / 2] )
            rotate( [90, 0, 0] )
            {
                // Contact
                cylinder( r=contactClearance / 2, h=contactThickness, center=true );

                // Contact opening
                translate( [0, contactRetainerDimensions[1] / 4, 0] )
                    cube( [contactClearance, contactRetainerDimensions[1] / 2, contactThickness], center = true );
            }
    }
}

```


[User]
I'd like to design a parametric screwdriver handle that can store a magnetic chuck and six driver bits, and also has a few other features. I've got a basic concept down, but need help making it into a fully parametric OpenSCAD design.

Here's what I'm after:

The main body should be a cylinder, and I'd like to be able to define the overall diameter and length. Let's call these `body_diameter` and `body_length`.  I'm also using a variable called `bodywidth` in my test code, but it would be better to derive this from the diameter in the future.

I want to have six scalloped cutouts around the handle for grip. I need to be able to set the spacing of these scallops (like my `scalspc` variable). I also want to be able to set the radius of these cutouts.

The screwdriver needs a hex-shaped cutout on one end to accept a standard 1/4" hex bit. This should be parametric, so I can adjust the bit width (`shaftWidth` and `hexShaft` in my code) and depth of the cutout. Additionally, a slightly looser cutout of the same shape, but a different depth,  should be located further down the handle for storing an additional bit. This stored bit cutout should have slightly looser tolerances than the working bit cutout.

There should be a cutout for storing a standard magnetic chuck (like the ones that come with bit sets). This should be a simple cylinder, and I need to be able to specify its diameter and depth.  There should also be a small, cylindrical cutout for the magnet that retains the chuck.

Finally, there needs to be six bit storage cutouts, arranged in a circle. Each of these should be a hex cutout with a magnet hole, and the size of the bits and magnet need to be settable.

Lastly, I'd like a rounded butt-end to the handle.

I think it might be best to use the following modules, and I'm wondering if you can suggest any changes to the module layout:
- A main body module.
- A module to make the bit storage cutouts and magnet holes,
- A module to do the rounded butt-end.

I'd like to use the `BOSL2` library if possible, to make some of this easier. For example, using the `polyhedron` module for the hex shapes would be a good use of the library. I'm hoping this will also make generating the rounded butt-end easier. Also I like how `BOSL2` helps with specifying units, so we can make this design in inches but output it in mm.

I think that's it for now. Let me know what you come up with!

[Assistant]
Screwdriver2.scad:
```
$fn = 60;
// Overall radius (half the diameter) of the screwdriver.
bodywidth = 14;
// Spacing of the scalloped cutouts.  Smaller for a deeper cut.
scalspc = 15;
// Face-face diameter of the hex bit; 1/4" is 6.35mm.  Give it a little extra if your printer prints holes tight.
shaftWidth = 6.7;
// Face-face diameter of the hex bit.
bitwidth = 6.7;
bitheight = 32;
hexwidth = bitwidth / pow(3,.5);
hexShaft = shaftWidth / pow(3,.5);
//module mainbody(scalspc) {
module bits(bitwd,bitht) {
    for (numb = [0:5]) {
    // Makes the hex bit cutouts
    rotate([0,0,60*numb])
    translate([9.5,0,0]) rotate([0,0,30]) cylinder (bitht, bitwd, bitwd, $fn=6);
    // makes the holes for bit-retaining magnets.
    rotate([0,0,60*numb]) translate([9,0,0]) rotate([0,0,30]) cylinder (33,1.59,1.59); }
}

difference() {
// Main screwdriver body.
cylinder(95, bodywidth,bodywidth);
    // Chuck storage cutout.
    cylinder(40,5.25,5.25);
    // Chuck retaining magnet cutout.
    cylinder (95,2.38,2.38);
    // next part makes the six scalloped cutouts in the handle
    for (numb = [0:5]) {
     rotate([0,0,60*numb])
    translate([scalspc,0,0]) cylinder (95,4,4); }
    // Hex cutout for the main drive
    translate([0,0,70]) cylinder(25,hexShaft, hexShaft, $fn=6);
    // Hex cutout for storage in the handle; note it's a little looser.
    translate([0,0,40]) cylinder(25,hexShaft*1.05, hexShaft*1.05, $fn=6);
    // Ring cutout towards the business end of the handle.
    translate([0,0,84.5]) rotate_extrude(convexity=12) translate([15,0,0]) circle(r=4.25);
    // This calls the bits module
    bits(hexwidth,bitheight);
    // This makes the rounded butt-end.
    difference() {
        cube (size = [30,30,12], center = true);
        translate([0,0,32]) sphere (32);
        }
}

```
Screwdriver2.scad:
```
$fn = 60;
// Overall radius (half the diameter) of the screwdriver.
bodywidth = 14;
// Spacing of the scalloped cutouts.  Smaller for a deeper cut.
scalspc = 15;
// Face-face diameter of the hex bit; 1/4" is 6.35mm.  Give it a little extra if your printer prints holes tight.
shaftWidth = 6.7;
// Face-face diameter of the hex bit.
bitwidth = 6.7;
bitheight = 32;
hexwidth = bitwidth / pow(3,.5);
hexShaft = shaftWidth / pow(3,.5);
//module mainbody(scalspc) {
module bits(bitwd,bitht) {
    for (numb = [0:5]) {
    // Makes the hex bit cutouts
    rotate([0,0,60*numb])
    translate([9.5,0,0]) rotate([0,0,30]) cylinder (bitht, bitwd, bitwd, $fn=6);
    // makes the holes for bit-retaining magnets.
    rotate([0,0,60*numb]) translate([9,0,0]) rotate([0,0,30]) cylinder (33,1.59,1.59); }
}

difference() {
// Main screwdriver body.
cylinder(95, bodywidth,bodywidth);
    // Chuck storage cutout.
    cylinder(40,5.25,5.25);
    // Chuck retaining magnet cutout.
    cylinder (95,2.38,2.38);
    // next part makes the six scalloped cutouts in the handle
    for (numb = [0:5]) {
     rotate([0,0,60*numb])
    translate([scalspc,0,0]) cylinder (95,4,4); }
    // Hex cutout for the main drive
    translate([0,0,70]) cylinder(25,hexShaft, hexShaft, $fn=6);
    // Hex cutout for storage in the handle; note it's a little looser.
    translate([0,0,40]) cylinder(25,hexShaft*1.05, hexShaft*1.05, $fn=6);
    // Ring cutout towards the business end of the handle.
    translate([0,0,84.5]) rotate_extrude(convexity=12) translate([14,0,0]) circle(r=6.25);
    // This calls the bits module
    bits(hexwidth,bitheight);
    // This makes the rounded butt-end.
    difference() {
        cube (size = [30,30,12], center = true);
        translate([0,0,32]) sphere (32);
        }
}

```


[User]
I'd like to generate a 3D maze, specifically a maze cube where each face has its own unique random maze. I have found an existing OpenSCAD script to base this on, and I'd like something similar, but I'd like it to be more modularized and easier to adjust, especially the edge pieces. I'd like to have parameters to control the dimensions of the cube in terms of the number of maze blocks along each axis (x\_blocks, y\_blocks, z\_blocks), as well as the wall thickness, wall height, and individual block width. It'd be nice to be able to toggle the display of the edge pieces on and off, similar to the original file. Also it'd be great if the code was well-commented so I could easily understand and modify it. I'm thinking this will probably need a main file and at least one support file to keep everything organized.

Here are the parameters from the original file:

*   `x_blocks`: Number of blocks along the x-axis.
*   `y_blocks`: Number of blocks along the y-axis.
*   `z_blocks`: Number of blocks along the z-axis.
*   `wall_thickness`: Thickness of the maze walls.
*  `wall_height`: Height of the maze walls.
*   `block_width`: Width/depth of each maze block.
*   `edge_enabled`: String, "YES" or anything else to toggle edge pieces.

I'm not requesting any external libraries. Could you generate the necessary OpenSCAD files, please?

[Assistant]
random_maze_cube_generator.scad:
```
x_blocks = 10;
y_blocks = 10;
z_blocks = 10;
wall_thickness = 1;
wall_height = 2;
block_width = 5;
edge_enabled = "YES";

/*
 * constants, for clearness
 *
 */

// random directions, for picking up a direction to visit the next block
function PERMUTATION_OF_FOUR() = [
    [1, 2, 3, 4],
    [1, 2, 4, 3],
    [1, 3, 2, 4],
    [1, 3, 4, 2],
    [1, 4, 2, 3],
    [1, 4, 3, 2],
    [2, 1, 3, 4],
    [2, 1, 4, 3],
    [2, 3, 1, 4],
    [2, 3, 4, 1],
    [2, 4, 1, 3],
    [2, 4, 3, 1],
    [3, 1, 2, 4],
    [3, 1, 4, 2],
    [3, 2, 1, 4],
    [3, 2, 4, 1],
    [3, 4, 1, 2],
    [3, 4, 2, 1],
    [4, 1, 2, 3],
    [4, 1, 3, 2],
    [4, 2, 1, 3],
    [4, 2, 3, 1],
    [4, 3, 1, 2],
    [4, 3, 2, 1]
];

function NO_WALL() = 0;
function UP_WALL() = 1;
function RIGHT_WALL() = 2;
function UP_RIGHT_WALL() = 3;

function NOT_VISITED() = 0;
function VISITED() = 1;

/*
 * modules for creating a maze
 *
 */

// give a [x, y] point and length. draw a line in the x direction
module x_line(point, length, thickness = 1) {
    offset = thickness / 2;
    translate([point[0] - offset, point[1] - offset, 0])
        square([length + thickness, thickness]);
}

// give a [x, y] point and length. draw a line in the y direction
module y_line(point, length, thickness = 1) {
    offset = thickness / 2;
    translate([point[0] - offset, point[1] - offset, 0])
        square([thickness, length + thickness]);
}

// create the outer wall of maze
module maze_outer_wall(rows, columns, block_width = 5, wall_thickness = 1) {
    x_line([0, rows * block_width], columns * block_width, wall_thickness);
    y_line([0, block_width], (rows - 1) * block_width, wall_thickness);
}

// create the inner wall of maze
module maze_inner_wall(maze, block_width = 5, wall_thickness = 1) {
    for(i = [0:len(maze) - 1]) {
        cord = maze[i];
        x = (cord[0] - 1) * block_width;
        y = (cord[1] - 1) * block_width;
        v = cord[3];

        if(v == 1 || v == 3) {
            x_line([x, y], block_width, wall_thickness);
        }
        if(v == 2 || v == 3) {
            y_line([x + block_width, y], block_width, wall_thickness);
        }
    }
}

// create a maze
module maze(rows, columns, maze_vector, block_width = 5, wall_thickness = 1) {
     maze_outer_wall(rows, columns, block_width, wall_thickness);
     maze_inner_wall(maze_vector, block_width, wall_thickness);
}

/*
 * utilities functions
 *
 */

// comare the equality of [x1, y1] and [x2, y2]
function cord_equals(cord1, cord2) = cord1 == cord2;

// is the point visited?
function not_visited(cord, vs, index = 0) =
    index == len(vs) ? true :
        (cord_equals([vs[index][0], vs[index][1]], cord) && vs[index][2] == 1 ? false :
            not_visited(cord, vs, index + 1));

// pick a direction randomly
function rand_dirs() =
    PERMUTATION_OF_FOUR()[round(rands(0, 24, 1)[0])];

// replace v1 in the vector with v2
function replace(v1, v2, vs) =
    [for(i = [0:len(vs) - 1]) vs[i] == v1 ? v2 : vs[i]];

/*
 * functions for generating a maze vector
 *
 */

// initialize a maze
function init_maze(rows, columns) =
    [
	    for(c = [1 : columns])
	        for(r = [1 : rows])
		        [c, r, 0,  UP_RIGHT_WALL()]
	];

// find a vector in the maze vector
function find(i, j, maze_vector, index = 0) =
    index == len(maze_vector) ? [] : (
        cord_equals([i, j], [maze_vector[index][0], maze_vector[index][1]]) ? maze_vector[index] : find(i, j, maze_vector, index + 1)
    );

////
// NO_WALL = 0;
// UP_WALL = 1;
// RIGHT_WALL = 2;
// UP_RIGHT_WALL = 3;
function delete_right_wall(original_block) =
    original_block == NO_WALL() || original_block == RIGHT_WALL() ? NO_WALL() : UP_WALL();

function delete_up_wall(original_block) =
    (original_block == NO_WALL() || original_block == UP_WALL()) ? NO_WALL() : RIGHT_WALL();

function delete_right_wall_of(vs, is_visited, maze_vector) =
    replace(vs, [vs[0], vs[1] , is_visited, delete_right_wall(vs[3])] ,maze_vector);

function delete_up_wall_of(vs, is_visited, maze_vector) =
    replace(vs, [vs[0], vs[1] , is_visited, delete_up_wall(vs[3])] ,maze_vector);

function go_right(i, j, rows, columns, maze_vector) =
    go_maze(i + 1, j, rows, columns, delete_right_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));

function go_up(i, j, rows, columns, maze_vector) =
    go_maze(i, j - 1, rows, columns, delete_up_wall_of(find(i, j, maze_vector), VISITED(), maze_vector));

function visit(v, maze_vector) =
    replace(v, [v[0], v[1], VISITED(), v[3]], maze_vector);

function go_left(i, j, rows, columns, maze_vector) =
    go_maze(i - 1, j, rows, columns, delete_right_wall_of(find(i - 1, j, maze_vector), NOT_VISITED(), maze_vector));

function go_down(i, j, rows, columns, maze_vector) =
    go_maze(i, j + 1, rows, columns, delete_up_wall_of(find(i, j + 1, maze_vector), NOT_VISITED(), maze_vector));

function go_maze(i, j, rows, columns, maze_vector) =
    look_around(i, j, rand_dirs(), rows, columns, visit(find(i, j, maze_vector), maze_vector));

function look_around(i, j, dirs, rows, columns, maze_vector, index = 0) =
    index == 4 ? maze_vector :
        look_around(
            i, j, dirs,
            rows, columns,
            build_wall(i, j, dirs[index], rows, columns, maze_vector),
            index + 1
        );

function build_wall(i, j, n, rows, columns, maze_vector) =
    n == 1 && i != columns && not_visited([i + 1, j], maze_vector) ? go_right(i, j, rows, columns, maze_vector) : (
        n == 2 && j != 1 && not_visited([i, j - 1], maze_vector) ? go_up(i, j, rows, columns, maze_vector)  : (
            n == 3 && i != 1 && not_visited([i - 1, j], maze_vector) ? go_left(i, j,rows, columns,  maze_vector)  : (
                n == 4 && j != rows && not_visited([i, j + 1], maze_vector) ? go_down(i, j, rows, columns, maze_vector) : maze_vector
            )
        )
    );

module maze_cube(blocks, block_width, wall_thickness, wall_height) {
    x_blocks = blocks[0];
    y_blocks = blocks[1];
    z_blocks = blocks[2];

    length = block_width * x_blocks + wall_thickness * 2;
    width = block_width * y_blocks + wall_thickness * 2;
    height = block_width * z_blocks + wall_thickness * 2;

   maze_vector1 = go_maze(1, 1, y_blocks, x_blocks, replace([1, 1, 0, UP_RIGHT_WALL()], [1, 1, 0, RIGHT_WALL()],
        replace([x_blocks, y_blocks, 0, UP_RIGHT_WALL()], [x_blocks, y_blocks, 0, UP_WALL()], init_maze(y_blocks, x_blocks))
    ));

    maze_vector2 = go_maze(1, 1, y_blocks, x_blocks, replace([x_blocks, 1, 0, UP_RIGHT_WALL()], [x_blocks, 1, 0, RIGHT_WALL()], init_maze(y_blocks, x_blocks)));

    maze_vector3 = go_maze(1, 1, x_blocks, z_blocks, replace([z_blocks, x_blocks, 0, UP_RIGHT_WALL()], [z_blocks, x_blocks, 0, UP_WALL()], init_maze(x_blocks, z_blocks)));

    maze_vector4 = go_maze(1, 1, z_blocks, x_blocks, replace([x_blocks, 1, 0, UP_RIGHT_WALL()], [x_blocks, 1, 0, UP_WALL()], init_maze(z_blocks, x_blocks)));

    maze_vector5 = go_maze(1, 1, z_blocks, y_blocks, replace([y_blocks, 1, 0, UP_RIGHT_WALL()], [y_blocks, 1, 0, RIGHT_WALL()], init_maze(z_blocks, y_blocks)));

    maze_vector6 = go_maze(1, 1, y_blocks, z_blocks,  replace([z_blocks, 1, 0, UP_RIGHT_WALL()], [z_blocks, 1, 0, RIGHT_WALL()], init_maze(y_blocks, z_blocks)));

    cube([length, width, height]);

    // 1
    translate([wall_thickness, wall_thickness, -wall_height])
        linear_extrude(wall_height)
        union() {
            y_line([0, 0], block_width);
            maze(y_blocks, x_blocks, maze_vector1, block_width, wall_thickness);
        }

    // 5
    translate([wall_thickness, wall_thickness, height])
         linear_extrude(wall_height)
            maze(y_blocks, x_blocks, maze_vector2, block_width, wall_thickness);
    // 6
    translate([length - wall_thickness, -wall_height, height - wall_thickness])
         rotate([90, 90, 180]) linear_extrude(wall_height)
            maze(x_blocks, z_blocks, maze_vector3, block_width, wall_thickness);
    // 3
    translate([wall_thickness, width, height - wall_thickness])
        rotate([-90, 0, 0]) linear_extrude(wall_height)
            maze(z_blocks, x_blocks, maze_vector4, block_width, wall_thickness);
    // 4
    translate([-wall_height, width - wall_thickness, height - wall_thickness])
         rotate([90, 180, 90])linear_extrude(wall_height)
            maze(z_blocks, y_blocks, maze_vector5, block_width, wall_thickness);

    // 2
    translate([length, width - wall_thickness, wall_thickness])
         rotate([0, -90, 180]) linear_extrude(wall_height)
            maze(y_blocks, z_blocks, maze_vector6, block_width, wall_thickness);

    if(edge_enabled == "YES") {
        edge_square_width = 1.5 * wall_thickness + wall_height;

        translate([wall_thickness / 2 + block_width, -wall_height, -wall_height])
            cube([block_width * (x_blocks - 1) + 1.5 * wall_thickness + wall_height, edge_square_width, edge_square_width]);

        translate([0, width - 1.5 * wall_thickness, -wall_height])
            cube([length + wall_height, edge_square_width, edge_square_width]);

        translate([-wall_height , -wall_height, -wall_height])
            cube([edge_square_width, y_blocks * block_width + wall_height * 2 + wall_thickness * 2, edge_square_width]);

        translate([x_blocks * block_width + wall_thickness / 2, -wall_height, -wall_height])
            cube([edge_square_width, (y_blocks - 1) * block_width + wall_height + wall_thickness * 1.5, edge_square_width]);

        //

        translate([-wall_height, -wall_height, height - edge_square_width + wall_height])
            cube([block_width * (x_blocks - 1) + 1.5 * wall_thickness + wall_height, edge_square_width, edge_square_width]);

        translate([-wall_height, width - 1.5 * wall_thickness, height - edge_square_width + wall_height])
            cube([length + wall_height - wall_thickness / 2, edge_square_width, edge_square_width]);

        translate([-wall_height , block_width + wall_thickness / 2, height - edge_square_width + wall_height])
            cube([edge_square_width, (y_blocks - 1) * block_width , edge_square_width]);

        translate([x_blocks * block_width + wall_thickness / 2, -wall_height, height - edge_square_width + wall_height])
            cube([edge_square_width, y_blocks * block_width + wall_height * 2 + wall_thickness * 2, edge_square_width]);

        //

        translate([-wall_height, -wall_height, 0])
            cube([edge_square_width, edge_square_width, height]);

        translate([length - 1.5* wall_thickness, -wall_height, 0])
            cube([edge_square_width, edge_square_width, height]);

        translate([-wall_height, width - 1.5 * wall_thickness, 0])
            cube([edge_square_width, edge_square_width, height - block_width - wall_thickness / 2]);

        translate([length - 1.5 * wall_thickness, width - 1.5 * wall_thickness, 0])
            cube([edge_square_width, edge_square_width, height - block_width - wall_thickness / 2]);
    }
}

/*
 * create a maze
 *
 */

maze_cube([x_blocks, y_blocks, z_blocks], block_width, wall_thickness, wall_height);
```


[User]
Hey, I'm looking to create a parametric corner piece for a suitcase, something I can easily modify for different projects. I have an existing file that I can share to show you the general shape, but I'd like a clean rewrite.

Specifically, the corner piece should have three main adjustable parameters: `taille` which defines the overall height of the corner, `ep` which controls the thickness of the material, and `dhole` which sets the diameter of an optional hole. I would like the default to be without a hole.

The overall shape is formed by hulling three corner pieces that should all be created by minkowski'ing a 2D triangle and a sphere. The triangle should start at the origin (0,0) and have vertices at (taille, 0) and (0, taille). The sphere used for the minkowski operation should have a radius equal to the `ep` parameter.

I need to be able to toggle the hole on or off. If `hole` is set to "yes", there needs to be a hole that runs through the three sides of the corner. The holes should be centered on the edges of the corner at a distance of about `taille*0.33` from the origin and should extend beyond the corner piece. I expect to be able to use it to attach the corner to a larger object.

I'm not using any external libraries. Can you help me with this?

[Assistant]
cornersuitcase.scad:
```
//+-------------------------------------------------------------+
//|              OPENSCAD CORNER suitecase - coin valise        |
//|         Remix from corner and handle baggage by javitoraz   |
//|                  2015 gaziel@gmail.com                      |
//+-------------------------------------------------------------+

//height of the corner
taille=50;

//thinkness
ep=3;

// Do You want a hole ?
hole="yes"; //[yes ,no]

// diameter for the hole
dhole=3;

$fn=25+25;

difference(){
    poly();
    if (hole=="yes"){
        rotate([90,0,0]) translate([taille*0.33,taille*0.33,-ep])cylinder(d=dhole, h=666);
        rotate([0,-90,0]) translate([taille*0.33,taille*0.33,-ep])cylinder(d=dhole, h=666);
        translate([taille*0.33,taille*0.33,-ep])cylinder(d=dhole,h=666);
    }
    cube(taille*3);
}

module poly(){
    hull(){
        angle();
        rotate([0,-90,0])angle();
        rotate([90,0,0])angle();
    }
}
module angle(){
    minkowski(){
        linear_extrude(height = 1)
            polygon(
                points=[[0,0],[taille,0],[0,taille]],
                paths = [ [0,1,2]]);
            sphere(ep);
    }
}

```


[User]
I need a parametric OpenSCAD design for a jalousie rope knob. It should be a hollow, truncated cone shape with a rounded top and bottom edge.

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

*   **`length`**: The overall length of the knob.
*   **`bottomDiameter`**: The diameter of the base of the truncated cone.
*   **`topDiameter`**: The diameter of the top of the truncated cone.
*   **`thickness`**: The thickness of the knob's walls.

The knob should be hollow. The rounded edges on the top and bottom should be created by a revolved circle, kind of like a torus segment that's cut off by the cone walls. I'd also like to set `$fn` to control the smoothness of the curves. I'd like the default `$fn` value to be 50.

I don't think I need any external libraries for this. Could you generate the OpenSCAD file for this?

[Assistant]
jalousie_rope_knob.scad:
```

// lenght of knob
length = 24;

// bottom (outer) diameter of knob
bottomDiameter = 15;

// top (outer) diameter of knob
topDiameter = 7.5;

// wall thickness
thickness = 2;

/** some better quality than default */
$fn=50;

module knob() {
  union() {
    difference() {
      cylinder (r1=bottomDiameter/2, r2=topDiameter/2, h=length);
      translate ([0,0,-0.1]) cylinder (r1=bottomDiameter/2-thickness, r2=topDiameter/2-thickness, h=length+0.2);
    }
    rotate_extrude (convexity = 10) translate ([-bottomDiameter/2+thickness/2,0,0]) circle (d=thickness);
    translate ([0,0,length]) rotate_extrude (convexity = 10) translate ([-topDiameter/2+thickness/2,0,0]) circle (d=thickness);
  }
}

knob();

```


[User]
I need a parametric OpenSCAD design for a replacement cap for a trailer position light. It's a fairly straightforward cylindrical cap with a few key features.

Here are the crucial dimensions and details:

*   **Overall Shape:** The cap is essentially a cylinder with a stepped profile.
*   **Major Diameter:** The outer rim should have a diameter of `major_dia`.
*   **Minor Diameter:** The main body of the cap should have a diameter of `minor_dia`.
*   **Rim Thickness:** The thickness of the outer rim is `rim`.
*   **Body Height:** The height of the main body is `bodyheight`.
*   **Chamfer:** There is a chamfer on the body, defined by the `chamfer` parameter.
*   **Wall Thickness:** The main wall thickness should be `wall`.
*   **Support Wall Thickness:** The thickness of internal support walls should be `supportwall`.
*   **Roof Thickness:** The thickness of the top roof is `roof`.

The cap has a rim, then a straight cylindrical section that flares out at the base of that section, finally ending in the thinnest 'roof' section. There's an internal 'skeleton' of supporting walls, arranged radially, that are meant to give the roof section some strength, whilst allowing it to be thin to let light through.

I'd like the design to be fully parametric, so I can adjust all these dimensions.

I expect to get a single .scad file and I'm not using any external libraries. Thanks!

[Assistant]
cap_light.scad:
```
//
//  design by egil kvaleberg, 4 january 2016
//
//  cap for trailer position light
//

// diameter of outside rim
major_dia = 46.0;
// diameter of body
minor_dia = 42.0;
// thickness of rim;
rim = 2.75;

// height of body
bodyheight = 18.0;
// body chamfer
chamfer = 7.0;

// should be thin to increase amount of light
wall = 1.0;
supportwall = 0.7;
// you probably want to make this thin to increase amount of light it lets through
roof = 0.45;

/* [Hidden] */
d=0.01;

difference() {
    union() {
        cylinder(d=major_dia, h=rim, $fn=120);
        translate([0, 0, rim-d]) cylinder(d=minor_dia, h=rim+d, $fn=120);
        translate([0, 0, 2*rim-d]) cylinder(d1=minor_dia,  d2=minor_dia-chamfer*0.5, h=bodyheight-chamfer+d, $fn=120);
        translate([0, 0, 2*rim+bodyheight-chamfer-d]) cylinder(d1=minor_dia-chamfer*0.5, d2=minor_dia-chamfer*0.5-chamfer*2, h=chamfer+d, $fn=120);
    }
    difference () {
        union() {
            translate([0, 0, -d]) cylinder(d=minor_dia-2*wall, h=rim+2*d, $fn=120);
            translate([0, 0, rim-d]) cylinder(d=minor_dia-2*wall, h=rim+d, $fn=120);
            translate([0, 0, 2*rim-d]) cylinder(d1=minor_dia-2*wall,  d2=minor_dia-chamfer*0.5-2*wall, h=bodyheight-chamfer+d, $fn=120);
            translate([0, 0, 2*rim+bodyheight-chamfer-d])
                cylinder(d1=minor_dia-chamfer*0.5-2*wall, d2=minor_dia-chamfer*0.5-chamfer*2-2*wall, h=chamfer+d-roof, $fn=120);
        }
        union() { // internal walls supporting roof and walls
            for (a = [0:45:180-d]) rotate([0, 0, a]) {
                difference () {
                    translate([-minor_dia/2,-supportwall/2,0]) cube(size=[minor_dia, supportwall, 2*rim+bodyheight-chamfer]);
                    union () {
                        translate([0, 0, -d]) cylinder(d1=minor_dia-2*wall, d2=minor_dia-2*wall-2*3*roof, h=2*rim+2*d, $fn=120);
                        translate([0,0,2*rim-d]) cylinder(d1=minor_dia-2*wall-2*3*roof, d2=minor_dia-chamfer*0.5-2*wall-2*3*roof, h=bodyheight-chamfer+2*d, $fn=120);
                    }
                }
                translate([0, 0, 2*rim+bodyheight-chamfer]) {
                    difference () {
                        translate([-minor_dia/2,-supportwall/2,0]) cube(size=[minor_dia, supportwall, chamfer]);
                        translate([0,0,-d]) cylinder(d1=minor_dia-chamfer*0.5-2*wall-2*3*roof, d2=minor_dia-chamfer*0.5-chamfer*2-2*wall-2*3*roof, h=chamfer+d-roof, $fn=120);
                    }
                    translate([-minor_dia/2,-supportwall/2,chamfer-roof-(roof*(a==0 ? 4 : 3))]) cube(size=[minor_dia, supportwall, chamfer]);
                }
            }
        }
    }
}
```