[User]
Okay, I'm looking to create a phone mount for my Essential PH-1, but I need it to be really customizable. I'd like the design to be broken into two main parts: an adapter that actually holds the phone and a bracket that allows for mounting on different surfaces.

For the adapter part, it needs to have a cutout for the phone itself and an insert that goes over the USB-C port on the bottom of the phone, as well as a place for the USB-C cable to come in the side. This cable insert is important because I want to be able to customize it so that different cable sizes will fit. The main body of the adapter will need to have a space for the cable to go, and have a channel for the phone to slot into. I need all three elements in the design, and they can either be separated or combined as the ai sees fit.

The bracket part will attach to the adapter, and I need it to be adjustable. Basically, I need to be able to angle the bracket up or down so that the phone can be level even if the mounting surface is slanted. I'm imagining something that allows for at least 180 degrees of total rotation.

Here are the parameters I think I need:

**Adapter:**

*   **Overall Dimensions:** The basic size of the adapter itself. Let's say roughly 71mm x 8mm x 33mm to start, but these should be adjustable if needed.
*   **Phone Insert Dimensions:** Cutout for the phone, around 72mm x 8.2mm x 6mm should do it for now.
*   **USB-C Port Dimensions:**  Around 12mm long, 7mm wide, and 23mm high should be enough, but I'd like to specify these.
*   **Cable Insert Diameter:** The diameter of the hole for the actual USB-C cable, I want to be able to change this as well as the hole for the cable shroud. Let's start with a cable diameter of 4mm and a shroud diameter of 10mm, but I need to be able to change these.
*   **USB Port Placement:**  The placement of where the USB-C port will be inserted into the adapter.

**Bracket:**

*   **Bracket Angle:** An angle that can be set to rotate the bracket anywhere from -90 to 90 degrees.
*   **Bracket Length:** Length of the bracket arm itself. 20mm should be a good starting length, though it should be adjustable.
*   **Bracket Thickness:** Keep it at 3mm.
*   **Attachment Point:** The place where the bracket connects to the adapter, start with it being offset by -10.1 on the x axis, and 9.4 on the z axis, relative to the center of the phone insert.

**Global:**

*   **Model Rotation:** The ability to rotate the entire model (not just the bracket) so it lays flat on the build surface. 360 degree adjustable rotation around the x axis will be necessary.

I'm looking for an OpenSCAD file or files that would allow me to adjust these parameters using the customizer. I'd prefer to not have to do any more editing on my end if possible.

I'm hoping for something that's relatively clean and easy to modify later if I need to. I don't need any fancy features or anything, just a solid, customizable model. I haven't used external libraries much yet so I'm not sure if I would need them for this, but if you think it will make the design better then I'm all for it.

[Assistant]
Ph-1BracketWithAdapter.scad:
```
/* [Global] */
// preview[view:north west, tilt:top]
/* [Bracket Arm] */
angle = 0; // [-90:90]
bracketLength = 20;
bracket = 1; //[0:Hide,1:Show]
bracketOffset = 0;
part = "Adapter"; // [Bracket:Modify Bracket,Adapter:Modify Adapter]

/* [Model Angle] */
//Rotate the model so it lays flay on the build surface
modelAngle = 0; // [360]
/* [USB End] */

//USB Port Sizes
usbCWidth = 7;
usbCLength = 12;
usbCHeight = 23;

/* [USB Cable] */

//USB Cable Sizes
usbCCableDiamiter = 4; // [2.0:8]
usbCCableShroudDiamiter = 10; // [2.0:11]

/* [Hidden] */
print_part();

module print_part() {
	if (part == "Bracket") {
		myBracket();
	} else if (part == "Adapter") {
		myAdapter();
	}
}

module myAdapter(){
    //Insert Body
    color("cyan",alpha=1)
    difference(){
        cube([71,8,33],center=true);
        cylinder(h=200, d1=usbCCableDiamiter+0.2 ,d2=usbCCableShroudDiamiter+0.2,center=true);

        //phone Insert
        translate([0,0,15])
            cube([72,8.2,6], center=true);

        //USB Insertion Port
        translate([-25,0,0])
            cube([18,7,34],center=true);

        //USB cable Insertion Port
        translate([-10,0,0])
            cube([20,usbCCableDiamiter+0.2,34], center = true);

        color("red")
        translate([0,0,13])
        cube([usbCLength,usbCWidth,usbCHeight*2],center=true);
    }
}

module myBracket() {
    //Mount for PH-1
    rotate([modelAngle,0,0]){
    cube([28,2.6,24.8], center=true);

    if (bracket){
        color("red"){
            if (angle >= 42)
                translate([-10.1,2,9.4])
                    rotate([angle,0,0])
                        cube([19.8, bracketLength,3], center=false);
            else if (angle <= 0)
                translate([-10.1,-1,9.4])
                    rotate([angle,0,0])
                        cube([19.8, bracketLength,3], center=false);
            else
                translate([-10.1,1,9.4])
                    rotate([angle,0,0])
                        cube([19.8, bracketLength,3], center=false);
        }
    }

    //Holding nub
        color("blue"){
            translate([0,-1.5,-8])
            rotate([0,90,0])
            cylinder(h=1.9,r1=1,r2=1,center=true);
        }
    }
}

```


[User]
I need an OpenSCAD design for a button support for a Raspberry Pi NES case. It's meant to work with the "Mini NES Pi 3 Case (Customizable)" from Thingiverse (thing:1887826) and the "\[RPI CUSTOM] Button and led for RPI 3" also on Thingiverse (thing:2587251).

The design should include the following:

*   A base with a horizontal section and a vertical tab for mounting.
*   Adjustable mounting plate with holes for buttons and LEDs.
*   The design needs to be parametric to accommodate different button depths and diameters, as well as different LED diameters.
*   Option for an LED "hat" to prevent light leakage in the case.

Here are the specific parameters I need to control:

**Basic:**

*   `_depth_button`: Depth of the buttons (in mm), default 6, range [6:0.5:15]
*   `_diameter_button`: Diameter of the buttons (in mm), default 1, range [1:0.5:8]

**LED:**

*   `_diameter_led`: Diameter of the LED (in mm), default 5, range [3,5]
*   `_led_hat`: Option to include an LED "hat" ("yes" or "no"), default "yes".

**Hidden Parameters (for internal design, should be configurable in the .scad):**

*   `_epaisseur`: Thickness of the base and vertical plate, default 1.6mm
*   `_epaisseur_patte`: Thickness of the vertical mounting tab, default 2mm
*   `_largeur`: Overall width of the support, default 38mm
*   `_hauteur_base_axe`: Height of the button holes and led holes from base , default 4mm
*    `_ajustement`:Adjustment of the button mounting plate from depth button, default 2.5mm

The base should have a tab (28mm wide, 3mm high and 3mm deep) for mounting on the case. The button holes should have a small cylinder for the button to sit in, as well as a small cutout on the outside to give space for the button to be pushed. The LED hole should also have a small cylinder on the top, to simulate the LED hat, to minimize light bleed. Please make the LED hole using the `polyhole` module used in the provided code.

[Assistant]
3DPrint-SupportNesButton.scad:
```
/* Permet de contruire un support pour les bouttons du boitier NES
By jeff le 10/2017
*/

//-------------------Declaration des variables

/* [Basic] */
//Buttons's depth (in mm)
_depth_button = 6; //[6:0.5:15]
//Buttons 's diameter (in mm)
_diameter_button = 1; //[1:0.5:8]

/* [LED] */
//Diameter LED (in mm)
_diameter_led = 5; //[3,5]
//LED's hat (Remove losing lighting in the case)
_led_hat = "yes"; //[yes,no]

/* [hidden] */
_epaisseur = 1.6;
_epaisseur_patte = 2;
_largeur = 38;
_hauteur_base_axe = 4;
_ajustement = 2.5;

//-------------------!Déclaration des variables

//-------------------Contruction de la forme

//Base fixe
base();

//Plaque variable
translate([0,_depth_button-_ajustement,0]){
	reglage(0);
}

//-------------------!Contruction de la forme

//Base horizontale
module base(){
	translate([-_largeur/2,2,-_epaisseur]){
		cube(size = [_largeur,20,_epaisseur], center = false);
	}
	//Patte d'arret
	translate([-28/2,15,-3-_epaisseur]){
		cube(size = [28,3,3], center = false);
	}
}//!module base

//Module de plaque percée
module reglage(_profondeur){

difference(){ //Soustraction de la base avec les trous des bouttons

	union(){
		//Patte verticale
		translate([-_largeur/2,_profondeur,0]){
			cube(size = [_largeur,_epaisseur_patte,12], center = false);
		};

		//Chapeau LED
		if(_led_hat == "yes"){

			translate([-15,-_epaisseur,_hauteur_base_axe]){
				rotate([90,0,0]){
					*cylinder(h=_epaisseur*2,r1=(_diameter_led/2),r2=(_diameter_led/2),center=true);
					polyhole(6,_diameter_led+1.5);
				}
			};

		}//!if

	}
	;

	//Trous a droite
	translate([6.1,1,_hauteur_base_axe]){
		trou_bouton(_diameter_button);
	}

	//Trous a gauche
	translate([-6.1,1,_hauteur_base_axe]){
		trou_bouton(_diameter_button);
	}

	//Trous LED
	translate([-15,1,_hauteur_base_axe]){
		rotate([90,0,0]){
			polyhole(_epaisseur*100,_diameter_led+0.5);
		}
	}

};

}//!Module reglage

//Module de trou des bouttons
module trou_bouton(_diametre){

	rotate([90,0,0]){
		*cylinder(h=_epaisseur*2,r=(_diametre/2),center=true);
		polyhole(_epaisseur*2,_diametre);
		translate([0,20/2,0]){
			cube(size = [_diametre,20,_epaisseur*2], center = true);
		}

	}//!rotate

}//!trou_bouton

//Module de trou
module polyhole(_h, _d) {
    _n = max(round(20 * _d),3);
    cylinder(h = _h, r = (_d / 2) / cos (180 / _n), $fn = _n,center = true);
}//!Module de trou

//Module de trou
module polyhole2(_h, _d1,_d2) {
    _n = max(round(20 * _d1),3);
    cylinder(h = _h, r1 = (_d1 / 2) / cos (180 / _n),r2 = (_d2 / 2) / cos (180 / _n), $fn = _n,center = true);
}//!Module de trou

```


[User]
I need a way to generate OpenLOCK compatible bases for tabletop gaming, and I'd like it to be flexible enough to handle a few different styles. I need a customizer that allows me to specify the size of the base in terms of the number of tiles (x and y dimensions), the size of a single tile (either 25mm, inch, or Wyloch which is about 31.75mm), whether to use OpenLOCK connectors, magnets, or both (and which wins if there's a conflict), and what the base should look like (plain or a stone texture). Also, I need to optionally add dynamic floor support, which means adding pegs to the bottom of each tile. I'd like to be able to generate square, diagonal, and curved bases.

Here's the specifics:

*   **Base Tile Size:** I should be able to specify the `x` and `y` dimensions as integers.
*   **Square Basis:** The size of a single tile needs to be selectable between "25mm", "inch" (25.4mm), and "wyloch" (31.75mm).
*   **OpenLOCK:** I need to choose whether to include OpenLOCK connectors, and if so, whether to make them a simple "true" connection, "triplex" connector (meaning OpenLOCK connectors on every side), or none at all ("false").
*   **Magnets:** I want to specify the diameter of the hole for magnets, with 0 to disable magnets. I generally use 5mm buckyball style magnets, so 6mm should be good, but I'd like to be able to control this.
*   **Priority:** If both magnets and OpenLOCK connectors are enabled, I need to choose whether OpenLOCK or the magnets should take precedence in the design.
*   **Style:** The exterior should be selectable between "plain" and "stone".
*  **Shape:** The base should be able to be square, diagonal, or curved.
*   **Dynamic Floors:** A boolean option should be included to enable or disable pegs for dynamic floors.

I'd also like the generated SCAD files to be well-commented and easy to understand. I'm not sure which libraries would be useful for this, so maybe you can recommend some?

[Assistant]
bases.scad:
```
/* [Base Tile Size] */
x = 2; //[1,2,3,4,5,6]
y = 2; //[1,2,3,4,5,6]

/* [Square Basis] */
// What is the size in mm of a square?
square_basis = "inch"; // [25mm:Dwarven Forge/Hirstarts, inch:OpenLOCK, wyloch:Wyloch]

/* [OpenLOCK] */
openlock = "true";// [true,triplex,false]

/* [Magnets] */
// Size of hole for magnet.  6 works well for 5mm buckyball style magnets.  0 to eliminate.
magnet_hole = 6;

/* [Priority] */
// Do you want openlock or magnets to win when the two conflict
priority = "openlock"; // [openlock,magnets]

/* [Style] */
// What should the base look like on the exterior
style = "plain"; // [stone,plain]

/* [Shape] */
// What type of tile is this for
shape = "square"; // [square,diagonal,curved]

/* [Dynamic Floors] */
// Add support for dynamic floors
dynamic_floors = "false";

/*
 * Openlock connection bay
 */
module openlock_chamber(buffer=0) {
    translate([-buffer,-7,1.4]) cube([2+buffer,7*2,4.2]);
    hull() {
        translate([0,-6,1.4]) cube([2,6*2,4.2]);
        translate([3+0.01,-5,1.4]) cube([2,5*2,4.2]);
    }
    translate([5,-5,1.4]) cube([8,5*2,4.2]);
    translate([7.55,-5.25,1.4]) cube([6,5.5*2,4.2]);
}

module openlock_supports(buffer=0) {
    translate([0-buffer*2,-0.5,1.4-buffer]) cube([10+buffer*2,1,4.2+buffer*2]);
}

module openlock_positive() {
    translate([0,-8,0]) cube([2,16,6]);
}

module openlock_negative() {
    difference() {
        openlock_chamber(1);
        //openlock_supports(1);
    }
}

module magnet_positive(magnet_hole=5.5) {
    if (magnet_hole > 0) {
        translate([magnet_hole/2+1,0,0]) cylinder(6,magnet_hole/2+1,magnet_hole/2+1, $fn=100);
    }
}

module magnet_negative(magnet_hole=5.5) {
    if (magnet_hole > 0) {
        translate([magnet_hole/2+1,0,1]) cylinder(8,magnet_hole/2,magnet_hole/2, $fn=100);
        translate([magnet_hole/2+1,0,-1]) cylinder(10,.9,.9,$fn=50);
    }
}

module center_connector_positive(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if (edge == 1) {
        if (priority == "openlock" && (single || triplex)) {
            openlock_positive(magnet_hole);
        } else {
            magnet_positive(magnet_hole);
        }
    } else {
        if (priority == "openlock" && triplex) {
            openlock_positive(magnet_hole);
        } else {
            magnet_positive(magnet_hole);
        }
    }
}

module center_connector_negative(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if (edge == 1) {
        if (priority == "openlock" && (single || triplex)) {
            openlock_negative(magnet_hole);
        } else {
            magnet_negative(magnet_hole);
        }
    } else {
        if (priority == "openlock" && triplex) {
            openlock_negative(magnet_hole);
        } else {
            magnet_negative(magnet_hole);
        }
    }
}

module joint_connector_positive(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if(single || triplex) {
        openlock_positive();
    }
}

module joint_connector_negative(edge, ordinal, magnet_hole=5.5, single=true, triplex=false, priority="openlock") {
    if(single || triplex) {
        openlock_negative();
    }
}

module openlock_base(x,y,square_basis,
        shape="square",style="plain",magnet_hole=6,openlock="true",priority="openlock",dynamic_floors="false") {
    single = openlock == "true" ? true : false;
    triplex = openlock == "triplex" ? true : false;
    df = dynamic_floors == "true" ? true : false;
    edge_width = magnet_hole >= 5.55 ? magnet_hole + 1 : 6.55;
    difference() {
        union() {
            if (style == "stone") {
                stone_base(x,y,square_basis,shape,edge_width);
            } else if (style == "plain") {
                plain_base(x,y,square_basis,shape,edge_width);
            }
            if (df) {
                cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([square_basis*x-square_basis/2-4.75,0,0]) cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([0,square_basis*y-square_basis/2-4.75,0]) cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([square_basis*x-square_basis/2-4.75,square_basis*y-square_basis/2-4.75,0]) cube([square_basis/2+4.75,square_basis/2+4.75,6]);
                translate([square_basis/2+3.75,square_basis/2+3.75,0]) cube([square_basis*x-(square_basis/2+3.75)*2,square_basis*y-(square_basis/2+3.75)*2,6]);
                if (x > 2) {
                    for ( i = [2 : x-1] ) {
                        translate([(i-.5)*square_basis-9.5/2,0,0]) cube([9.5,square_basis/2+4.75,6]);
                        translate([(i-.5)*square_basis-9.5/2,square_basis*y-square_basis/2-4.75,0]) cube([9.5,square_basis/2+4.75,6]);
                    }
                }
                if (y > 2) {
                    for ( i = [2 : y-1] ) {
                        translate([0,(i-.5)*square_basis-9.5/2,0]) cube([square_basis/2+4.75,9.5,6]);
                        translate([square_basis*x-square_basis/2-4.75,(i-.5)*square_basis-9.5/2,0]) cube([square_basis/2+4.75,9.5,6]);
                    }
                }
            }

            for ( i = [0 : y-1] ) {
                translate([0,square_basis*(i+1)-square_basis/2,0]) center_connector_positive(y,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*x,square_basis*(i+1)-square_basis/2,0]) rotate([0,0,180]) center_connector_positive(y,i,magnet_hole,single,triplex,priority);
                }
            }
            if (y > 1) {
                for ( i = [1 : y-1] ) {
                    translate([0,square_basis*i,0]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    if (shape == "square") {
                        translate([square_basis*x,square_basis*i,0]) rotate([0,0,180]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    }
                }
            }
            for ( i = [0 : x-1] ) {
                translate([square_basis*(i+1)-square_basis/2,0,0]) rotate([0,0,90]) center_connector_positive(x,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*(i+1)-square_basis/2,square_basis*y,0]) rotate([0,0,-90]) center_connector_positive(x,i,magnet_hole,single,triplex,priority);
                }
            }
            if (x > 1) {
                for ( i = [1 : x-1] ) {
                    translate([square_basis*i,0,0]) rotate([0,0,90]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    if (shape == "square") {
                        translate([square_basis*i,square_basis*y,0]) rotate([0,0,-90]) joint_connector_positive(y,i,magnet_hole,single,triplex,priority);
                    }
                }
            }
        }

        for ( i = [0 : y-1] ) {
            translate([0,square_basis*(i+1)-square_basis/2,0]) center_connector_negative(y,i,magnet_hole,single,triplex,priority);
            if (shape == "square") {
                translate([square_basis*x,square_basis*(i+1)-square_basis/2,0]) rotate([0,0,180]) center_connector_negative(y,i,magnet_hole,single,triplex,priority);
            }
        }
        if (y > 1) {
            for ( i = [1 : y-1] ) {
                translate([0,square_basis*i,0]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*x,square_basis*i,0]) rotate([0,0,180]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                }
            }
        }
        for ( i = [0 : x-1] ) {
            translate([square_basis*(i+1)-square_basis/2,0,0]) rotate([0,0,90]) center_connector_negative(x,i,magnet_hole,single,triplex,priority);
            if (shape == "square") {
                translate([square_basis*(i+1)-square_basis/2,square_basis*y,0]) rotate([0,0,-90]) center_connector_negative(x,i,magnet_hole,single,triplex,priority);
            }
        }
        if (x > 1) {
            for ( i = [1 : x-1] ) {
                translate([square_basis*i,0,0]) rotate([0,0,90]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                if (shape == "square") {
                    translate([square_basis*i,square_basis*y,0]) rotate([0,0,-90]) joint_connector_negative(y,i,magnet_hole,single,triplex,priority);
                }
            }
        }
        if(df) {
            for ( i = [0 : x-1] ) {
                for ( j = [0 : y-1] ) {
                    translate([i*square_basis, j*square_basis,0]) translate([square_basis/2,square_basis/2,6-2.1]) cylinder(2.5,5.5/2,5.5/2, $fn=100);
                }
            }
        }
    }
}

module plain_base(x,y,square_basis,shape,edge_width) {
    difference() {
        intersection() {
            translate([0,0,0]) cube([square_basis*x, square_basis*y, 6]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([x,y,1]) cylinder(8,square_basis,square_basis,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis,0,0]) rotate([0,0,45]) {
                    cube([10.2/2,square_basis*x*2,6]);
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,6]);
                }
            }
        }

        intersection() {
            translate([edge_width,edge_width,0]) translate([1,1,-1]) cube([square_basis*x-((edge_width+1)*2),square_basis*y-((edge_width+1)*2),8]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([((x*square_basis)-edge_width)/square_basis,((y*square_basis)-edge_width)/square_basis,1]) cylinder(8,square_basis,square_basis,$fn=200);
            }
        }
    }
    if(shape == "diagonal") {
        intersection() {
            translate([x*square_basis,0,0]) rotate([0,0,45]) {
                cube([10.2/2,square_basis*x*2,6]);
                mirror([1,0,0]) cube([10.2/2,square_basis*x*2,6]);
            }
            translate([0,0,0]) cube([square_basis*x, square_basis*y, 6]);
        }
    }
}

module stone_base(x,y,square_basis,shape,edge_width) {
    module generate_stones() {
        intersection() {
            union() {
                for (i = [0:xblocks]) {
                    for (j = [0:yblocks]) {
                        translate([i*10.2,j*10.2,0]) cube([9.2 + (i==xblocks ? 10.2 : 0),9.2 + (j==yblocks ? 10.2 : 0),5.5]);
                    }
                }
            }
            cube([length, width, 6]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([x,y,1]) cylinder(8,square_basis,square_basis,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis,0,0]) rotate([0,0,45]) {
                    cube([10.2/2,square_basis*x*2,6]);
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,6]);
                }
            }
        }
    }

    module generate_interior() {
        intersection() {
            translate([1,1,0]) cube([length-2, width-2, 6]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([x,y,1]) cylinder(8,square_basis-0.5,square_basis-0.5,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis,0,0]) rotate([0,0,45]) {
                    cube([10.2/2-1,square_basis*x*2,6]);
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,6]);
                }
            }
        }
    }

    length = square_basis*x;
    width = square_basis*y;
    xblocks = floor(length / 10.2);
    yblocks = floor(width / 10.2);

    difference() {
        union() {
            generate_stones();
            generate_interior();
        }
        intersection() {
            translate([edge_width,edge_width,0]) translate([1,1,-1]) cube([square_basis*x-((edge_width+1)*2),square_basis*y-((edge_width+1)*2),8]);
            if(shape == "curved") {
                translate([0,0,-1]) scale([((x*square_basis)-edge_width)/square_basis,((y*square_basis)-edge_width)/square_basis,1]) cylinder(8,square_basis,square_basis,$fn=200);
            } else if (shape == "diagonal") {
                translate([x*square_basis-sqrt(5.1*5.1+5.1*5.1),0,-1]) rotate([0,0,45]) {
                    mirror([1,0,0]) cube([square_basis*x*2,square_basis*x*2,8]);
                }
            }
        }
    }
}

function keyLookup (data, key) = search(key, data, num_returns_per_match=1)[0];

basis = [
    ["25mm", 25],
    ["inch", 25.4],
    ["wyloch", 31.75]
];
square_basis_number = basis[keyLookup(basis, [square_basis])][1];

color("Grey") openlock_base(x,y,square_basis_number,shape=shape,style=style,magnet_hole=magnet_hole,openlock=openlock,priority=priority,dynamic_floors=dynamic_floors);

```


[User]
I need some help designing a set of parametric rafter cord hooks for my unfinished basement. I'm using engineered I-beam joists, and I need to hang extension cords and ethernet cables from them. I'd like the hooks to clip onto the joists without screws or glue, and be strong enough to hold some weight. I saw a design on Thingiverse that was inspired by Prusa cable spool mounts and that looks like the kind of springy clip I'd like to use, so I'll describe that more.

Here's a breakdown of what I need:

**Core Functionality:**

*   **Clipping Mechanism:** The primary way these hooks attach is by clipping over the bottom of the I-beam joist. There should be a springy, flexible part that allows the hook to grip tightly. I saw an existing design that used a thin piece of plastic that "snaps" over the joist edge; the code for that is included at the bottom if it's helpful.
*   **Cord Holding:** The hooks need to hold at least one cord, but I'd like to be able to scale them up to hold more. Extension cords are pretty thick (around 10mm diameter), so the cord holding part should accommodate that, and perhaps be able to hold multiple of them. There should be two orientations available - inline (where the cords all hang along the length of the joist) and cross (where the cord comes down perpendicular to the joist).

**Parameters (that I'd like to be able to adjust):**

*   `joist_width`: The width of the joist's bottom flange. This will likely need to be around 45mm (1 3/4"), but needs to be adjustable.
*   `joist_height`: The height of the joist's bottom flange.  This needs to be adjustable, but it will likely be around 35mm (1 3/8").
*    `joist_overhang`: The horizontal space between the inside of the clip and the edge of the joist - probably should be about 15mm.
*   `clip_overhang`: The depth of the "hook" section that clamps onto the bottom of the joist - around 12mm.
*   `clip_length`: The length of the hook - about 17mm in my current design.
*   `wall_thickness`: How thick the plastic is for the hook's main body; maybe 5mm.
*   `cord_radius`: Radius of the cord we'll hang - 5mm is a good starting point.
*    `cord_holder_thickness`: How thick the part that holds the cord is - wall_thickness + 1 or 2 mm, should be adjustable.
*    `num_cords`: How many cords to support - start with 1, but should be adjustable.
*   `cord_holder_length`: Total length of the cord holder, should change with num_cords.
*   `cross_cord_depth`: Depth of the cross-orientation cord holder, so how far down the cords should be held - default 15mm.
*   `cross_cord_clip_length`: The length of the clip/lip that keeps the cord in. Probably around the cord_holder_length.

**Specific Design Requests:**

*   **Two Orientations:** There should be two options for the cord holder:
    *   "Normal" or Inline: The cord(s) will hang along the joist length.
    *   "Vertical" or Cross: The cords will hang down perpendicular to the joist.
*   **Thumb Nub:** I like the thumb nub on my current design, it makes it much easier to get the hanger off.  It should be included and customizable.
*   **Flexible Section:**  Please use the 'hull' technique from the attached code to create the springy section, as I find it works well.
*   **No libraries required:** I'm not currently using any libraries for this, and would prefer that the design be self-contained, if possible.

I think that's everything. Let me know if you have any questions.
```
// rafter cord hooks - for engineered trusses
// hook method stolen from prusa cable spool mount

$fn = 100;
hook_orientation = "vertical";  // choose "normal" (horizontal) or "vertical"

num_cords = 1;   // then number of cords being hanged
                 // the max should be equal to width of the
                 // beam hook hk_wid - currently about (4) 10mm dia cords

wall_thk = 5;

trs_wid = 45+.5;  // was +1  // width of the bottom of the truss
trs_ht = 35+1;   // height of the bottom of the truss
trs_ovr = 15;  // overhang space between core and edge

hk_ovr = 12;   // how much of the hook will be on the truss overhang

hk_len = 17;  // 40;   // length of the hook (shorter than width)
hk_wid = trs_wid + wall_thk*2;
hk_ht = trs_ht + 2*wall_thk;

hngr_rad = 5;  // hanger radius - extension cord diameter is 10
hngr_thk = wall_thk+1;
hngr_len = hngr_rad + (num_cords-1)*(hngr_rad*2);   // one hanger diameter per cord
v_cab_thk = 15;

//translate([-wall_thk,0,0])
difference()
{
//hk_ang = atan(hk_ovr/(hk_len/2));
linear_extrude(height=hk_len)
polygon([
  [0,0],
  [hk_wid, 0],    // right-most coord, no y
  [hk_wid, hk_ht], // right-most, y=bracket top
  [hk_wid - wall_thk-hk_ovr, hk_ht],  // going back to make the hook
  [hk_wid - wall_thk-hk_ovr, wall_thk+trs_ht+1], // now down to make the thickness
    [hk_wid - wall_thk-hk_ovr+2, wall_thk+trs_ht], // now down to make the thickness

  [hk_wid - wall_thk, wall_thk+trs_ht],  // back out to make the lip
  [hk_wid - wall_thk, wall_thk],  // down to the inner surface
  [wall_thk, wall_thk],           // back toward the origin
  [wall_thk, wall_thk+trs_ht],    // up to start the other hook
  //[wall_thk+8, wall_thk+trs_ht + 1], // out a bit (8), and up 1
    [wall_thk+10, wall_thk+trs_ht], // out a bit (8), flat
    [wall_thk+12, wall_thk+trs_ht+1], // out a bit (8), up one
  [wall_thk+12, wall_thk+trs_ht + wall_thk], // now up to make it thick
  [4,wall_thk+trs_ht + wall_thk],  // back a bit to start the thumb nub
  [3.5, wall_thk+trs_ht + wall_thk+5],  // up and back to start the nub top
  [.5, wall_thk+trs_ht + wall_thk+5],  // back towards orig to finish nub top
  [0, wall_thk+trs_ht + wall_thk],    // back at x==0, top of the hook
  [0,0]]);                           // back to origin (not needed)

  crv_rad = wall_thk-1;
  // carve out some thickness to make more flexible
  translate([0-wall_thk,wall_thk,-.5])
  //rotate([90,0,0])
  hull()
  {
    translate([0,crv_rad,0]) cylinder(r=wall_thk-1, h=hk_len+1);
    translate([0,trs_ht-wall_thk-2,0]) cylinder(r=wall_thk-1, h=hk_len+1);
    translate([wall_thk,trs_ht-wall_thk-2,0]) cylinder(r=wall_thk-1, h=hk_len+1);
    translate([wall_thk,crv_rad,0]) cylinder(r=wall_thk-1, h=hk_len+1);
  }  // end hull()

}  // end difference()

if(hook_orientation == "normal")
{
// add the cable carrier
linear_extrude(height=hk_len)
translate([hk_wid,0,0])
rotate(180)
union()
{
curve_2d(hngr_rad, hngr_thk, wall_thk, hngr_len, 90);
translate([hngr_thk+hngr_rad+hngr_len,
            hngr_thk+wall_thk+hngr_rad,0]) rotate(-90)
  curve_2d(2, wall_thk+1, 0, 0, 90);
translate([wall_thk+hngr_thk,-wall_thk,0])
  rotate(90)
   #curve_2d(wall_thk, wall_thk, 00, 0, 90);

 // the smoothing-over of the hook tip
 translate([hngr_thk/2+hngr_thk+hngr_rad+hngr_len+2,
            wall_thk+hngr_rad-2])
   scale([(hngr_thk)/2,1])
    circle(d=2);
}
}  // end if(hook_orienttation == "normal")

if(hook_orientation == "vertical")
{
//echo(hk_wid=hk_wid-30, hngr_len = hngr_len);

translate([hk_wid/2 - v_cab_thk/2,0,0])
rotate([0,-90,180])
 linear_extrude(height=v_cab_thk)
  cable_keeper_2d();

// also need to extend a lip above the hook to help keep the cord in
translate([v_cab_thk/2+hk_wid/2 - v_cab_thk/2,0,hk_len - 0 + hngr_len])
   union()
    {
    translate([-v_cab_thk/3,0,0])
     rotate([-90,0,0])
    hull()
    {
        cylinder(d=v_cab_thk/3, h=wall_thk);
        translate([v_cab_thk-v_cab_thk/3,0,0])
          cylinder(d=v_cab_thk/3, h=wall_thk);
    }  // end hull
    translate([-v_cab_thk/2,0,-hngr_len]) cube([v_cab_thk,wall_thk,hngr_len]);
    }  // end union
}  // end if(hook_orientation == "vertical"

// for 90-degree orientation, the hook must be printed separately
//  so we can orient it flat for strength when printing.
//  (will need change to base, as well - maybe a notch?

// curve_2d (r_in, thick, len1, len2, angle)
//
//  create a radiused curve with attached plates
//  parameters:
//     r_in    inside radius of curve - how sharp the curve
//     thick   thickness of the entire curve plate (sets outside radius)
//     len1    length of first plate  (if 0, no plate added)
//     len2    length of the second plate (if 0, no plate added)
//     angle   how far around the circle the curve goes before the
//             rest of the plate is attched -- the remaining plate
//               is len - start.
//
// working from standard x-axis-based
//  angle measurements: 0deg: x=1,  y=0
//                     45deg: x=1,  y=1
//                     90deg: x=0,  y=1
//                    180deg: x=-1, y=0
// but rotated and translated to return object with the
//  angle origin along y-axis and increases clockwise toward x-axis.
//
// NOTE: currently the curve is added to len1 and len2.  Someday will
//        change so curve section consumes part of len1 and len2.
//        so that a len1+len2 square column is bent starting where
//        len1 and len2 join.

module curve_2d(r_in=10,thick=5,len1=10,len2=10,ang=45)
{
r_out = r_in + thick;

// don't allow angles <0 or <180
angle0 = ang>180 ? 180 : ang;
angle = angle0<0 ? 0 : angle0;
angle = ang;
echo(ang = ang,  angle0 = angle0, angle = angle);
// Calculate the beginning points for the second plate.  This will
//  be the end points of the curve we just completed.

x1 = cos(angle)* r_in;
y1 = sin(angle) * r_in;
x2 = cos(angle) * r_out;
y2 = sin(angle) * r_out;

translate([r_out,len1]) rotate([0,180])// move the finished curve to zero-origin
union()
 {
 difference()   // diff two circles and two squares
  {
  circle(r_out, $fn=150);   // make a circle of the outer radius

  circle(r_in, $fn = 150);  // remove a circle of the inner radius

  translate([-r_out,-r_out-.1]) // use a box to lop off the bottom of the circles
   square([r_out*2,r_out+.1]);

  rotate(angle+180)       // spin a square clockwise and wipe out unneeded circle
   translate([-r_out,-r_out])
    square([r_out*2,r_out]);
 }

// attach the first plate to the start of the curve
translate([r_in,0])
 rotate(-90)
  square([len1,r_out-r_in]);

// make a square for the second plate, rotate and translate it into place
translate([x2,y2]) rotate(angle+90) square([len2,thick]);
}  // end union
}  // end module curve_2d

module cable_keeper_2d(ck_len = 30)
{
  //linear_extrude(height=hk_len)
//translate([hk_wid,0,0])
//rotate(180)
difference()
{
union()
{
curve_2d(hngr_rad, hngr_thk, wall_thk, hngr_len, 90);
translate([hngr_thk+hngr_rad+hngr_len,
            hngr_thk+wall_thk+hngr_rad,0]) rotate(-90)
  curve_2d(2, wall_thk+1, 0, 0, 90);
translate([wall_thk+hngr_thk,-wall_thk,0])
  rotate(90)
   curve_2d(wall_thk, wall_thk, 00, 0, 90);

 // the smoothing-over of the hook tip
 translate([hngr_thk/2+hngr_thk+hngr_rad+hngr_len+2,
            wall_thk+hngr_rad-2])
   scale([(hngr_thk)/2,1])
    circle(d=2);
}  // end union()

translate([0,-20]) square([20,20]);
}  // end difference()
}  // end module cable_keeper()
```

[Assistant]
rafter_cord_hook_prusa_style.scad:
```
// rafter cord hooks - for engineered trusses
// hook method stolen from prusa cable spool mount

$fn = 100;
hook_orientation = "vertical";  // choose "normal" (horizontal) or "vertical"

num_cords = 1;   // then number of cords being hanged
                 // the max should be equal to width of the
                 // beam hook hk_wid - currently about (4) 10mm dia cords

wall_thk = 5;

trs_wid = 45+.5;  // was +1  // width of the bottom of the truss
trs_ht = 35+1;   // height of the bottom of the truss
trs_ovr = 15;  // overhang space between core and edge

hk_ovr = 12;   // how much of the hook will be on the truss overhang

hk_len = 17;  // 40;   // length of the hook (shorter than width)
hk_wid = trs_wid + wall_thk*2;
hk_ht = trs_ht + 2*wall_thk;

hngr_rad = 5;  // hanger radius - extension cord diameter is 10
hngr_thk = wall_thk+1;
hngr_len = hngr_rad + (num_cords-1)*(hngr_rad*2);   // one hanger diameter per cord
v_cab_thk = 15;

//translate([-wall_thk,0,0])
difference()
{
//hk_ang = atan(hk_ovr/(hk_len/2));
linear_extrude(height=hk_len)
polygon([
  [0,0],
  [hk_wid, 0],    // right-most coord, no y
  [hk_wid, hk_ht], // right-most, y=bracket top
  [hk_wid - wall_thk-hk_ovr, hk_ht],  // going back to make the hook
  [hk_wid - wall_thk-hk_ovr, wall_thk+trs_ht+1], // now down to make the thickness
    [hk_wid - wall_thk-hk_ovr+2, wall_thk+trs_ht], // now down to make the thickness

  [hk_wid - wall_thk, wall_thk+trs_ht],  // back out to make the lip
  [hk_wid - wall_thk, wall_thk],  // down to the inner surface
  [wall_thk, wall_thk],           // back toward the origin
  [wall_thk, wall_thk+trs_ht],    // up to start the other hook
  //[wall_thk+8, wall_thk+trs_ht + 1], // out a bit (8), and up 1
    [wall_thk+10, wall_thk+trs_ht], // out a bit (8), flat
    [wall_thk+12, wall_thk+trs_ht+1], // out a bit (8), up one
  [wall_thk+12, wall_thk+trs_ht + wall_thk], // now up to make it thick
  [4,wall_thk+trs_ht + wall_thk],  // back a bit to start the thumb nub
  [3.5, wall_thk+trs_ht + wall_thk+5],  // up and back to start the nub top
  [.5, wall_thk+trs_ht + wall_thk+5],  // back towards orig to finish nub top
  [0, wall_thk+trs_ht + wall_thk],    // back at x==0, top of the hook
  [0,0]]);                           // back to origin (not needed)

  crv_rad = wall_thk-1;
  // carve out some thickness to make more flexible
  translate([0-wall_thk,wall_thk,-.5])
  //rotate([90,0,0])
  hull()
  {
    translate([0,crv_rad,0]) cylinder(r=wall_thk-1, h=hk_len+1);
    translate([0,trs_ht-wall_thk-2,0]) cylinder(r=wall_thk-1, h=hk_len+1);
    translate([wall_thk,trs_ht-wall_thk-2,0]) cylinder(r=wall_thk-1, h=hk_len+1);
    translate([wall_thk,crv_rad,0]) cylinder(r=wall_thk-1, h=hk_len+1);
  }  // end hull()

}  // end difference()

if(hook_orientation == "normal")
{
// add the cable carrier
linear_extrude(height=hk_len)
translate([hk_wid,0,0])
rotate(180)
union()
{
curve_2d(hngr_rad, hngr_thk, wall_thk, hngr_len, 90);
translate([hngr_thk+hngr_rad+hngr_len,
            hngr_thk+wall_thk+hngr_rad,0]) rotate(-90)
  curve_2d(2, wall_thk+1, 0, 0, 90);
translate([wall_thk+hngr_thk,-wall_thk,0])
  rotate(90)
   #curve_2d(wall_thk, wall_thk, 00, 0, 90);

 // the smoothing-over of the hook tip
 translate([hngr_thk/2+hngr_thk+hngr_rad+hngr_len+2,
            wall_thk+hngr_rad-2])
   scale([(hngr_thk)/2,1])
    circle(d=2);
}
}  // end if(hook_orienttation == "normal")

if(hook_orientation == "vertical")
{
//echo(hk_wid=hk_wid-30, hngr_len = hngr_len);

translate([hk_wid/2 - v_cab_thk/2,0,0])
rotate([0,-90,180])
 linear_extrude(height=v_cab_thk)
  cable_keeper_2d();

// also need to extend a lip above the hook to help keep the cord in
translate([v_cab_thk/2+hk_wid/2 - v_cab_thk/2,0,hk_len - 0 + hngr_len])
   union()
    {
    translate([-v_cab_thk/3,0,0])
     rotate([-90,0,0])
    hull()
    {
        cylinder(d=v_cab_thk/3, h=wall_thk);
        translate([v_cab_thk-v_cab_thk/3,0,0])
          cylinder(d=v_cab_thk/3, h=wall_thk);
    }  // end hull
    translate([-v_cab_thk/2,0,-hngr_len]) cube([v_cab_thk,wall_thk,hngr_len]);
    }  // end union
}  // end if(hook_orientation == "vertical"

// for 90-degree orientation, the hook must be printed separately
//  so we can orient it flat for strength when printing.
//  (will need change to base, as well - maybe a notch?

// curve_2d (r_in, thick, len1, len2, angle)
//
//  create a radiused curve with attached plates
//  parameters:
//     r_in    inside radius of curve - how sharp the curve
//     thick   thickness of the entire curve plate (sets outside radius)
//     len1    length of first plate  (if 0, no plate added)
//     len2    length of the second plate (if 0, no plate added)
//     angle   how far around the circle the curve goes before the
//             rest of the plate is attched -- the remaining plate
//               is len - start.
//
// working from standard x-axis-based
//  angle measurements: 0deg: x=1,  y=0
//                     45deg: x=1,  y=1
//                     90deg: x=0,  y=1
//                    180deg: x=-1, y=0
// but rotated and translated to return object with the
//  angle origin along y-axis and increases clockwise toward x-axis.
//
// NOTE: currently the curve is added to len1 and len2.  Someday will
//        change so curve section consumes part of len1 and len2.
//        so that a len1+len2 square column is bent starting where
//        len1 and len2 join.

module curve_2d(r_in=10,thick=5,len1=10,len2=10,ang=45)
{
r_out = r_in + thick;

// don't allow angles <0 or <180
angle0 = ang>180 ? 180 : ang;
angle = angle0<0 ? 0 : angle0;
angle = ang;
echo(ang = ang,  angle0 = angle0, angle = angle);
// Calculate the beginning points for the second plate.  This will
//  be the end points of the curve we just completed.

x1 = cos(angle)* r_in;
y1 = sin(angle) * r_in;
x2 = cos(angle) * r_out;
y2 = sin(angle) * r_out;

translate([r_out,len1]) rotate([0,180])// move the finished curve to zero-origin
union()
 {
 difference()   // diff two circles and two squares
  {
  circle(r_out, $fn=150);   // make a circle of the outer radius

  circle(r_in, $fn = 150);  // remove a circle of the inner radius

  translate([-r_out,-r_out-.1]) // use a box to lop off the bottom of the circles
   square([r_out*2,r_out+.1]);

  rotate(angle+180)       // spin a square clockwise and wipe out unneeded circle
   translate([-r_out,-r_out])
    square([r_out*2,r_out]);
 }

// attach the first plate to the start of the curve
translate([r_in,0])
 rotate(-90)
  square([len1,r_out-r_in]);

// make a square for the second plate, rotate and translate it into place
translate([x2,y2]) rotate(angle+90) square([len2,thick]);
}  // end union
}  // end module curve_2d

module cable_keeper_2d(ck_len = 30)
{
  //linear_extrude(height=hk_len)
//translate([hk_wid,0,0])
//rotate(180)
difference()
{
union()
{
curve_2d(hngr_rad, hngr_thk, wall_thk, hngr_len, 90);
translate([hngr_thk+hngr_rad+hngr_len,
            hngr_thk+wall_thk+hngr_rad,0]) rotate(-90)
  curve_2d(2, wall_thk+1, 0, 0, 90);
translate([wall_thk+hngr_thk,-wall_thk,0])
  rotate(90)
   curve_2d(wall_thk, wall_thk, 00, 0, 90);

 // the smoothing-over of the hook tip
 translate([hngr_thk/2+hngr_thk+hngr_rad+hngr_len+2,
            wall_thk+hngr_rad-2])
   scale([(hngr_thk)/2,1])
    circle(d=2);
}  // end union()

translate([0,-20]) square([20,20]);
}  // end difference()
}  // end module cable_keeper()
```


[User]
Okay, I need a parametric spool holder for my 3D printer. I'd like it to be customizable for different spool sizes. The design should have a central hub with arms extending outwards, and optional end stops to keep the spool from sliding off.

Here's what I'm thinking:

*   **Core Parameters:**
    *   `_diameter_spool`: The interior diameter of the spool (the hole the holder will be sized for). I need to be able to adjust this, and I will want to add 0.5mm to the actual diameter so there's a bit of play.
    *   `_diameter_hole_center`: The diameter of the center hole for the axle to pass through (this needs to also be parametric).
    *   `_epaisseur`: The thickness of the main body of the holder.
*   **Arm Parameters:**
    *   `_nb_rayon`: The number of arms extending out from the center.
*   **End Stop Parameters:**
    *   `_diametre_anneau`: The diameter of the end stops.
    *   `_epaisseur_anneau`: The thickness of the end stops.
    *    `_nb_anneau`: The number of end stops (I might want to make a simple wheel without any stops).
*   **OpenSCAD Specific:**
     * I need to have the option to generate code that will run on thingiverse (or not). If thingiverse = "yes" the arms and the end stops will be generated in a different way (using only the first four rotation positions - 0, 90, 180 and 270 degrees). If set to "no" I need to be able to generate any number of arms and end stops

The main body of the holder should be a disk with the center hole, and arms that extend outwards. I guess that the arms should be slightly inset into the main disk (like in the file attached), and the end stops should be small cylinders attached to the outside of the disk, on both sides of the spool.

I think that's everything. I'm expecting to get at least two .scad files, one that generates the basic shape and another one which generates the end-stops, so that I can chose to generate a simple wheel or a "normal" spool holder.

Let me know if you have any questions.

[Assistant]
3DPrint-SpoolHolder.scad:
```
/* Permet de contruire un spool holder parametric
By jeff le 10/2017
*/

//-------------------Declaration des variables

/* [Basic] */
//Interior Spool's diameter (in mm)
_diameter_spool = 70; //
//Axe's diameter (in mm)
_diameter_hole_center = 8.5;	//[1:0.5:100]

/* [Advanced] */
//Thickness (in mm)
_epaisseur = 7;//[1:1:150]

//Arms's quantity
_nb_rayon = 3;	//[2:1:10]

//EndStop's diameter (in mm)
_diametre_anneau = 10;	//[0:1:100]
//EndStop's thickness (in mm)
_epaisseur_anneau = 2;	//[1:1:10]
//EndStop's quantity
_nb_anneau = 3;	//[0:1:100]

/* [hidden] */

// Write no if your are generating this this with openscad.
//You will have more option
_thingiverse = "no"; //[yes,no]

//-------------------!Déclaration des variables

//-------------------Contruction de la forme

//Base fixe
base();

//Anneau de butée
if (_nb_anneau>0){

	if (_thingiverse == "no"){
		for (_i=[0:(360/_nb_anneau):360])
			rotate([0,0,_i]){
				anneau();
			}
			;
	}else{

		rotate([0,0,0]){anneau();}
		rotate([0,0,90]){anneau();}
		rotate([0,0,180]){anneau();}
		rotate([0,0,270]){anneau();}

	}
}

//-------------------!Contruction de la forme

//Module de base
module base(){

	difference(){ //Anneau exterieur

		polyhole(_epaisseur,_diameter_spool);

		polyhole(_epaisseur+10,_diameter_spool - 10 );

	}

	difference(){

		union(){
			polyhole(_epaisseur,_diameter_hole_center+5);

			if (_thingiverse == "no"){
				for (_i=[0:(360/_nb_rayon):360])

					rotate([0,0,_i]){
						bras();
					};

			}else{

				rotate([0,0,0]){bras();}
				rotate([0,0,90]){bras();}
				rotate([0,0,180]){bras();}
				rotate([0,0,270]){bras();}

			}//!if

		};

		polyhole(_epaisseur+10,_diameter_hole_center );

	}

}//!module base

//Module des anneaux stop
module anneau(){
	translate([_diameter_spool/2,0,(_epaisseur/2)-(_epaisseur_anneau/2)]){
		polyhole(_epaisseur_anneau,_diametre_anneau);
	}
}//!Module anneaux

//Module de trou
module polyhole(_h, _d) {
    _n = max(round(20 * _d),3);
    cylinder(h = _h, r = (_d / 2) / cos (180 / _n), $fn = _n,center = true);
}//!Module de trou

//Module des rayons
module bras(){
	translate([(_diameter_spool-1)/2,1,(_epaisseur/2)*-1]){
		rotate([0,0,180]){
			cube(size = [((_diameter_spool-1)/2),2,_epaisseur], center = false);
		}
	}
}//!Module bras

```


[User]
Hey, I need some help designing a parametric Y-axis motor mount for a Prusa i3 style 3D printer. I've got a pretty good idea of what I need, but I'm not great at OpenSCAD, and I want this to be super customizable.

Here's the basic idea:

It should hold a NEMA 17 stepper motor, and have mounting points for 8.5mm diameter linear rails. The design is going to be mirrored from most other designs, so the motor will be on the left side (looking from the front of the printer) and the motor shaft should be level with the top rail. I'd also like the design to keep the motor as close to the rails as possible to reduce the lever arm, while still giving the belt enough space.

Here's all of the parameters I want to be able to adjust:

*   `motor_hole_distance`: Distance between the motor mounting holes (should be 31.0 for NEMA 17).
*   `thickness`: Overall thickness of the mount (keep belt close to the motor).
*   `screw_d`: Diameter of the motor mounting screws (M3).
*   `screw_head_d`: Diameter of the countersink for the screw head.
*   `screw_head_sink`: Depth of the screw head countersink.
*  `belt_slit_wall_thickness`: The amount of solid material surrounding the belt cutout in the Z axis.
*   `rail_distance`: Distance between the two rail mounting points.
*   `rail_diameter`: Diameter of the linear rails.
*   `rail_to_body`: Distance between the rail mounting points and the main body of the mount.

The main body of the mount should be a cube with rounded edges. Then, there should be countersunk holes for the four motor mounting screws. Finally, there should be a cutout for the belt, and mounting points for the linear rails.

I think the rail mounting points should be cylinder shapes on the top surface of the mount connected by two cuboids that extend from the side of the mount. I was also thinking of adding a connecting block between the two rails but I'm not totally sure.

I'm not super concerned about having a large amount of detail in the mounting blocks for the linear rails, but I do want the countersunk mounting holes to be accurate.

I'd like to be able to adjust these parameters in the OpenSCAD file. Please include all code for the design, I don't need any external libraries for this project.

[Assistant]
yaxis_motor_holder.scad:
```
$motor_hole_distance = 31.0; // NEMA 17 Stepper
$thickness = 20; // keep belt as close to the motor as possible to reduce leverage on the rails
$screw_d = 3.4; // M3 screw H13
$screw_head_d = 6; // diameter of the sinkhole for the screw head
$screw_head_sink = 3; // depthness of the sinkhole
$belt_slit_wall_thickness = 3; // space in Z direction on each side
$rail_distance = 20;
$rail_diameter = 8.5; // M8 screw H13
$rail_to_body = 15;

$fn = 64;

difference() {
    union() {
        // main body
        translate([-2.5,-2.5])
            cube([$motor_hole_distance + 5,     $motor_hole_distance + 5,$thickness]);

        // edges
        cylinder(h=$thickness, d=10);

        translate([$motor_hole_distance,0])
            cylinder(h=$thickness, d=10);

        translate([0, $motor_hole_distance])
            cylinder(h=$thickness, d=10);

        translate([$motor_hole_distance, $motor_hole_distance])
            cylinder(h=$thickness, d=10);

        // rail mounting holes
        $rail_outerradius = $rail_diameter + 6;
        // middle hole
        translate([$motor_hole_distance/2,$motor_hole_distance+$rail_to_body,0])
            cylinder(h=$thickness, d=$rail_outerradius);
        // sidehole
        translate([$motor_hole_distance/2 + $rail_distance,$motor_hole_distance+$rail_to_body,0])
            cylinder(h=$thickness, d=$rail_outerradius);
        // connecting block near body
        translate([$motor_hole_distance/2-$rail_outerradius/2,$motor_hole_distance,0])
            cube([$rail_distance+$rail_outerradius/2,$rail_to_body,$thickness]);
        // connecting block outer
        translate([$motor_hole_distance/2,$motor_hole_distance + $rail_to_body,0])
            cube([$rail_distance,$rail_outerradius/2,$thickness]);
    }

    union() {
        // big round hole
        translate([$motor_hole_distance/2, $motor_hole_distance/2, -1])
            cylinder(h=$thickness+2, d = $motor_hole_distance/1.15);

        // screw holes + screwheadsinks
        screw_cutout(0,0);
        screw_cutout($motor_hole_distance,0);
        screw_cutout(0,$motor_hole_distance);
        screw_cutout($motor_hole_distance, $motor_hole_distance);

        // belt cutout
        translate([$motor_hole_distance/2-$motor_hole_distance/1.5/2,-10,$belt_slit_wall_thickness])
            cube([$motor_hole_distance/1.5,$motor_hole_distance/2+10, $thickness-$belt_slit_wall_thickness * 2]);

        // rail mounting holes
        $rail_outerradius = $rail_diameter + 5;
        translate([$motor_hole_distance/2,$motor_hole_distance+$rail_to_body,-1])
            cylinder(h=$thickness + 2, d=$rail_diameter);
        translate([$motor_hole_distance/2+$rail_distance,$motor_hole_distance+$rail_to_body,-1])
            cylinder(h=$thickness + 2, d=$rail_diameter);
    }

}

module screw_cutout(x,y) {
    translate([x,y,$thickness-$screw_head_sink])
        cylinder(h=50, d=$screw_head_d);
    translate([x,y,-1])
        cylinder(h=$thickness+2,d=$screw_d);
}
```


[User]
Bonjour! I'm looking to create a customizable stopper for cylindrical holes, inspired by a design I have but want to make more flexible. I need an OpenSCAD file that lets me define the following parameters:

*   **`_diameter_small`**: The diameter of the smaller, top part of the stopper (in millimeters).
*   **`_diameter_big`**: The diameter of the larger, base part of the stopper (in millimeters).
*   **`_height`**: The total height of the stopper (in millimeters).
*  **`_hole_depth`**: The depth of the cylindrical hole inside the stopper (in millimeters)
*  **`_diameter_hole`**: The diameter of the cylindrical hole inside the stopper (in millimeters)

The stopper should have a rounded base, like a sphere cut in half, transitioning into a smaller cylindrical section with rounded edges. There should be a cylindrical hole going up into the base of the stopper. The general shape should be similar to what I already have.

I'd like to be able to easily modify these dimensions and have the design update accordingly. Could you generate a single OpenSCAD file for me that does this? I'm not using any libraries yet, but if any library would help make this more clean, feel free to use them.

[Assistant]
3DPrint-bouchon.scad:
```
/* Permet de contruire un support pour les bouttons du boitier NES
By jeff le 10/2017
*/

//-------------------Declaration des variables

/* [Basic] */
//Buttons 's diameter (in mm)
_diameter_small = 10;
_diameter_big = 20;
_height = 30;

/* [Hole] */
_hole_depth = 10;
_diameter_hole = 10;

/* [hidden] */

//-------------------!Déclaration des variables

//-------------------Contruction de la forme

//Base fixe
difference(){
	base();

	trou();

}

//-------------------!Contruction de la forme

//Base horizontale
module base(){

	$fn=64;
	hull(){
		//Boule a la base
		translate([0,0,_height-_diameter_big/2])sphere(r=_diameter_big/2);
		//forme du haut
		translate([0,0,0.5]) polyhole(1,_diameter_small+2);
		*translate([0,0,_diameter_small/2]) sphere(r=_diameter_small/2);
	}

}//!module base

module trou(){
	translate([0,0,_hole_depth/2]){
		polyhole(_hole_depth,_diameter_hole);
	}
}

//Module de trou
module polyhole(_h, _d) {
    _n = max(round(20 * _d),3);
    cylinder(h = _h, r = (_d / 2) / cos (180 / _n), $fn = _n,center = true);
}//!Module de trou

//Module de trou
module polyhole2(_h, _d1,_d2) {
    _n = max(round(20 * _d1),3);
    cylinder(h = _h, r1 = (_d1 / 2) / cos (180 / _n),r2 = (_d2 / 2) / cos (180 / _n), $fn = _n,center = true);
}//!Module de trou

```


[User]
I'm looking to create a 3D printable Sierpinski pyramid that can be printed in spiral vase mode. I've seen some designs online, but I'm hoping to get a parametric model that gives me a lot of control over the final shape, and more importantly, ensures printability using the spiral mode.

Specifically, I'd like the model to have these features:

*   **Sierpinski Pyramid Structure:** The core should be a subtractive implementation, where the shape is created by carving away from a solid pyramid rather than building up smaller ones. I think this approach will ensure that the generated geometry is manifold and easier to work with in boolean operations.
*   **Parametric Order:** I want to be able to control the order of the Sierpinski fractal, preferably up to at least order 5.  The customizer can handle a limit of 4, but for an OpenSCAD model, 5 is crucial.
*   **Parametric Size:** I need a parameter to set the size of the smallest pyramid in the fractal. It should be adjustable.
*   **Vertical Scale Factor:** A parameter to control the vertical scale of the pyramid. This should allow me to make it more like a standard pyramid, or taller and thinner.
*   **Layer Height Awareness:** The model should automatically align itself to the specified layer height that I will use for printing. This should minimize issues with overlapping geometries and ensure that the connections between levels are thick enough to print. Specifically, any connections should be at least 0.42mm wide and should include a minor "fudge factor" to ensure they are not precisely on top of another geometry, thus avoiding non-manifold shapes.
*   **Shift:**  A parameter to shift the entire model vertically, which I could use to add a solid bottom layer or to fine-tune the layers for optimal spiral printing.
*   **Adjustable Gap Width:** The design needs a parameter for the gap width between the pyramid elements. It must be at least 0.1mm to work with spiral mode in slicers like Slic3r, maybe with the ability to override the default gap size.
*   **Spiral Vase Mode Compatibility:** The resulting design *must* be printable in a continuous spiral vase mode with no retractions. This requires carefully designed gap widths and connection points that ensure a single, continuous outline for each layer, which is necessary for spiral printing. It must also handle the case where there are small zig-zags.

I'd like the model to include a `tetrahole` module to create the inverted pyramid shapes for the fractal. It should be a subtractive shape, slightly larger than the hole it makes. Also, a recursive `ss` module to generate the sierpinski pattern. I think this function should create not only the negative shapes but also the gaps between parts, to maintain a single continuous outline.

Could you provide me with an OpenSCAD file (or files) that implement all of these features? I'm not sure if this requires external libraries. Please be clear in your response about any dependencies and explain any assumptions you may have made.

[Assistant]
fractal_sierpinski_spiral-subtractive.scad:
```
// Subtractive implementation of Sierpinski pyramid by DrLex, 2017/10
// Based on Thing:2573402 by aeropic
// Released under Creative Commons - Attribution license

// Order of sierpinski fractal. Customizer is limited to 4, because 5 would timeout anyway. Use OpenSCAD for higher order numbers.
order = 3; //[0,1,2,3,4]
// Size (half diagonal) of smallest pyramid.
size = 1.5; //[.5:.1:20]
// Vertical scale factor
zscale = 1.0; //[.5:.1:2]

/* [Advanced] */
// Layer height you will be printing at; entering the right value here will ensure perfect alignment of the structure.
layers = 0.2;
// Shift the whole print up by this distance; use this to add a solid bottom layer, and/or nudge the layers to avoid that your slicer breaks the spiral vase in case of bad alignment.
shift = 0.0;
// Gap width, must be at least 0.1 to make spiral vase mode work in Slic3r.
gap = 0.10; //[.01:.01:.5]

/* [Hidden] */
sq2 = sqrt(2);
// align each 'floor' with layer height, such that connections between floors are at least 0.42mm wide
estimate = zscale*(size-sq2*0.21);
eps = (size-layers*floor(estimate/layers)/zscale)/sq2;
conn = 0.46;
rtop = 0.04;
// All lines marked with 'MF' include some fudge factor to avoid exactly overlapping geometries, which usually lead to non-manifold results when combined in a Boolean fashion
epsh = 1.01*zscale*sq2*(eps+gap/2)+0.01; //MF

totalsize = pow(2,order) * (size*sq2 - 2*eps) + 2*eps;

translate([0,0,shift]) {
    difference() {
        rotate([0,0,45]) cylinder(r1=totalsize/sq2, r2=rtop, h=zscale*(totalsize/sq2-rtop), $fn=4);
        ss(order-1);
    }
}
if(shift > 0) {
    translate([-totalsize/2, -totalsize/2, 0]) cube([totalsize, totalsize, shift+0.01]); //MF
}

// Construct a tetrahedron that slightly extends beyond the pyramid surface so we're not doing booleans at perfectly matching surfaces, which never ends well
module tetrahole(r) {
    h = zscale*sq2*r/2*.999; //MF
    r2 = r/2*.999; //MF
    rx = 1.01*r;
    r2x = 1.025*r2;
    polyhedron(
        points=[ [0,0,0], [rx,0,0], [r2,-r2,h], [r2,r2,h], [r2x,-r2,h], [r2x,r2,h] ],
        faces=[ [0,2,4,1],[0,1,5,3],[0,3,2],[2,3,5,4],[1,4,5] ]
    );
}

// sierpinsky recursive code
module ss(ord){
    k = pow(2,ord);
    w = size *k;
    w2 = k * (size*sq2 - 2*eps) - 2*eps;

    if(ord > -1) {
        // recursion for the 6 subparts
        translate([-k*eps+w/sq2, -k*eps+w/sq2, 0]) ss(ord-1);
        translate([k*eps-w/sq2, k*eps-w/sq2, 0]) ss(ord-1);
        translate([k*eps-w/sq2, -k*eps+w/sq2, 0]) ss(ord-1);
        translate([-k*eps+w/sq2, k*eps-w/sq2, 0]) ss(ord-1);
        translate([0, 0, zscale*(w-sq2*k*eps)]) rotate([180,0,0]) ss(ord-1);
        translate([0, 0, zscale*(w-sq2*k*eps)]) ss(ord-1);

        // create both the holes and the gaps to ensure a single outline curve
        translate([conn, -gap/2, -0.01])  cube([sq2*w, gap, epsh]);
        translate([2*eps, 0, zscale*sq2*eps]) tetrahole(w2);
        rotate([0,0,90]) {
            translate([conn, -gap/2, -0.01])  cube([sq2*w, gap, epsh]);
            translate([2*eps, 0, zscale*sq2*eps]) tetrahole(w2);
        }
        rotate([0,0,180]) {
            translate([conn, -gap/2, -0.01]) cube([sq2*w, gap, epsh]);
            translate([2*eps, 0, zscale*sq2*eps]) tetrahole(w2);
        }
        rotate([0,0,270]) {
            translate([conn, -gap/2, -0.01])  cube([sq2*w, gap, epsh]);
            translate([2*eps, 0, zscale*sq2*eps]) tetrahole(w2);
        }
    }
 } // end module ss

```


[User]
Okay, I'm looking to create a bean stopper for my coffee grinder. I have a basic design in mind, and I'd like to use OpenSCAD to make it parametric so I can adjust it for different grinders.

The basic idea is that it'll have three main parts: a funnel that fits into the grinder's existing hopper, a body section that acts as the main structural part, and a bottom tube that connects to the grinder itself. There will also be a stopper plate added on. The funnel will have a slot, and the bottom tube will either be round or square depending on the grinder.

Here are the specific dimensions I’m thinking of, but I need them to be adjustable parameters:

**Funnel:**
*   `funnel_outer_diameter`: This is the outer diameter of the funnel where it inserts into the existing hopper. I'll need to measure this with a caliper. It should have a default of 34.8mm
*   `funnel_inner_diameter`: The inner diameter of the funnel. Default 30.4mm.
*   `funnel_slot_depth`: How deep the funnel inserts into the grinder. Default is 10mm.

**Body:**
*   `stopper_body_height`: The height of the main body of the stopper. Default 30mm.
*   `stopper_body_diameter`: The diameter of the main body. Default 40mm.
*   `stopper_body_length`: The length of the stopper body extending from the hopper. Default 40mm.
*   `stopper_plate_thick`: Thickness of the stopper plate that extends from the body. Default 2mm.
*  `stopper_plate_additional_length`: Length that the stopper plate extends past the stopper body. Default 10mm.
*   `stopper_plate_pulling_hole_diameter`: Diameter of a hole in the stopper plate to help pull it. Default 16mm.
*   `stopper_plate_text`: Text to engrave on the stopper plate (e.g. "Coffee"). Default "Coffee".
*   `stopper_plate_text_engrave_depth`: How deep to engrave the text. Default 1mm.
*   `stopper_plate_text_size`: Size of the engraved text. Default 8.

**Bottom Tube:**
*   `bottom_tube_diameter`: The outer diameter of the tube that connects to the grinder. Default 30mm.
*   `bottom_tube_thick`: The thickness of the bottom tube. Default 2.5mm.
*   `bottom_tube_height`: The height/length of the bottom tube. Default 10mm.

**Other Considerations:**
*   `tube_type`: This should be a variable that lets me choose either "Round" or "Square" for the bottom tube, which corresponds to the shape of the grinder inlet. Default should be "Round".
*   There needs to be a tolerance setting, which adds or subtracts from some values based on the layer height to ensure parts can fit together. This should be controlled by a boolean parameter `enable_tolerance` (default is `true`). A `tolerance` parameter (default 0.1) should be used if `enable_tolerance` is `true`.
*   I want to use `$fn = 200` for smooth curves.

Could you generate an OpenSCAD file (or files, if necessary) that includes these parameters and creates the bean stopper design?

[Assistant]
bean_stoper.scad:
```
/* [Print Settings] */

enable_tolerance = true; // [true,false]

// Select the tolerance with layer height value to print.
tolerance = 0.1; // [0.05:Layer Height is 0.3,0.1:Layer Height is 0.2, 0.2:Layer Height is 0.1,0.3:Layer Height is 0.05]

/* [Funnel] */

funnel_outer_diameter = 34.8; // [20:0.1:60]
funnel_inner_diameter = 30.4; // [20:0.1:60]
funnel_slot_depth = 10; // [1:0.1:20]

/* [Body] */

stopper_body_height = 30;
stopper_body_diameter = 40;
stopper_body_length = 40; // [30:1:50]
stopper_plate_thick = 2; // [1:0.1:5]
stopper_plate_additional_length = 10; // [0:1:20]
stopper_plate_pulling_hole_diameter = 16; // [10:0.1:30]
stopper_plate_text = "Coffee";
stopper_plate_text_engrave_depth = 1;
stopper_plate_text_size = 8;

/* [Bottom Tube] */

bottom_tube_diameter = 30;  // [10:0.1:50]
bottom_tube_thick = 2.5;
bottom_tube_height = 10;

/* [Hidden] */

tube_type = "Round"; // [Square:Square slot to the grinder,Round:Round slot to the grinder]
//TODO: let funnel slot also fit the square funnel.

hole_diameter = funnel_inner_diameter-4;
stopper_plate_length = stopper_body_length + stopper_plate_additional_length;

$fn = 200;

// Update value is the tolerance trigger has on
if (enable_tolerance){
    funnel_outer_diameter = funnel_outer_diameter+(tolerance*2);
    funnel_inner_diameter = funnel_inner_diameter-(tolerance*2);
    bottom_tube_diameter = bottom_tube_diameter-(tolerance*2);
}

//
//
translate([0,0,stopper_body_diameter])
rotate([90,0,0])
union(){
    translate([0,0,-bottom_tube_height])
        createBottom(tube_type,bottom_tube_diameter, bottom_tube_thick, bottom_tube_height);
    difference(){
        createMiddle(body=[stopper_body_height,stopper_body_diameter,stopper_body_length], funnel=[funnel_outer_diameter,funnel_inner_diameter,funnel_slot_depth], tunnel=hole_diameter);

        translate([0,5,stopper_body_height*0.75])
        scale([1.1,1.05,1.20])
            createStopPlate(stopper_plate_thick,stopper_plate_length, stopper_body_diameter, hole_diameter, stopper_plate_pulling_hole_diameter);
    }
}

translate([stopper_body_diameter,0,0])
difference(){
    createStopPlate(stopper_plate_thick,stopper_plate_length, stopper_body_diameter, hole_diameter, stopper_plate_pulling_hole_diameter);

    linear_extrude(height=stopper_plate_thick)
    translate([0,-stopper_plate_length])
            circle(d=stopper_plate_pulling_hole_diameter);

    translate([0,0,stopper_plate_thick-stopper_plate_text_engrave_depth])
    linear_extrude(height=10)
    rotate([0,0,-90])
    text(text=stopper_plate_text, size=stopper_plate_text_size, valign="center",halign="left");
}

module createBottom(slot_type, diameter, thick=2, h=20){
    if (slot_type=="Round"){
        linear_extrude(height=h)
        difference(){
          circle(d=diameter, center=true);
          circle(d=diameter-thick*2, center=true);
        }
    }else if(slot_type=="Square"){
        width = diameter * cos(45);
        inner_width = (diameter - thick*2) * cos(45);
        linear_extrude(height=h)
        difference(){
          square([width,width], center=true);
          square([inner_width,inner_width], center=true);
        }
    }
}
//
module createMiddle(body=[40,40,30], funnel=[30,27,5], tunnel=25){

    h_body = body[0];   // height of the stopper body
    d_body = body[1];   // diameter of the body attach to the funnel
    l_body = body[2];
    od_funnel = funnel[0];  // outer diameter of the funnel
    id_funnel = funnel[1];  // inner diameter of the funnel
    dp_funnel = funnel[2];  // funnel insert distance

    difference(){
        hull(){
            // Join the cyliner and cube as the shape of the body.
            cylinder(h=h_body,d=d_body,center=false);

            translate([0,0,h_body/2])
            rotate([90,0,0])
            linear_extrude(height=l_body, scale=[0.7,1])
                square(size=[d_body,h_body],center=true);
        }

        // make slot for funnel
        translate([0,0,h_body])
        difference(){
            cylinder(h=dp_funnel,d=od_funnel,center=true);
            cylinder(h=dp_funnel,d=id_funnel,center=true);
        }

        // Cut through
        translate([0,0,h_body])
        rotate([180,0,0])
        linear_extrude(height=h_body, scale=0.6)
        circle(d=tunnel,center=true);

    }
}
//
module createStopPlate(plate_thick=2, plate_length=40, body_diameter, hole_diameter, pulling_hole){

    adjusted_diameter = hole_diameter*0.8;

    linear_extrude(height=plate_thick)
    hull(){
        circle(d=adjusted_diameter,center=true);
        translate([0,-adjusted_diameter])
        square([adjusted_diameter,plate_length],center=true);

        translate([0,-plate_length])
            circle(d=adjusted_diameter);
    }
}

```


[User]
I'm looking to generate a parametric battery holder in OpenSCAD. I need to be able to specify the number of battery rows and columns, the battery diameter and length, the width of the cutout to help remove the battery, the bottom height of the holder, the wall thickness, and the thickness of the battery tabs and the diameter of the holes for the power cables.

Here are the specifics:
*   **Battery Arrangement:** I need to define the `rows` and `columns` of batteries.
*   **Battery Dimensions:** I need to be able to set the `batteryDiameter` and `batteryLength`.
*   **Removal Cutout:** There should be a `batteryHolderPullWidth` to make battery removal easier.
*   **Holder Dimensions:** I need to control the `batteryHolderBottom` height and `batteryHolderWalls` thickness.
*  **Connector Details:** I need to set the `batteryConnectorThickness` and the `batteryHolderHoleDiameter` for power cables.

The design should create a rectangular base with cylindrical cutouts to hold the batteries. It also needs cutouts for easy battery removal, and mounting holes for power cables. I would like all parameters to be modifiable.

I'm not sure if this helps you but I am using a very similar holder that I have designed previously. I'm going to attach that in case it would help for context.

The default settings should be for four AA batteries, that is, two rows and two columns.

[Assistant]
battery_holder.scad:
```
/* [General] */
// Amount of battery rows
rows = 2; // [1:10]
// Amount of battery columns
columns = 2; // [1:10]

// Diameter of the battery
batteryDiameter = 15;
// Length of the battery
batteryLength = 50;

// With of the cutout to help removing the battery
batteryHolderPullWidth = 15;

// Bottom Height
batteryHolderBottom = 1;
// Wall thickness
batteryHolderWalls = 1;

/* [Connector] */
// Thickness of the battery tabs
batteryConnectorThickness = 1.75;
// Diameter of the holes for power cables
batteryHolderHoleDiameter = 3;

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

spacing = 0.2;
batteryRadius = batteryDiameter / 2;
batteryHolderHeight = batteryHolderBottom + batteryRadius;
batteryHolderHeightOuter = batteryHolderBottom + batteryDiameter;
batteryHolderLength = (batteryLength * columns) + (batteryHolderWalls + batteryConnectorThickness) * 2;
batteryHolderLengthInner = (batteryLength) * columns;

batteryXOffset = batteryHolderWalls + batteryConnectorThickness;
batteryPullOffset = batteryLength / 2 - batteryHolderPullWidth / 2;
batteryHolderWidth = (batteryDiameter + batteryHolderWalls) * rows + batteryHolderWalls;

batteryHolderHoleRadius = batteryHolderHoleDiameter / 2;

batteryHolder();

module batteryHolder() {
  difference() {
    group() {
      difference() {
        cube([batteryHolderLength, batteryHolderWidth, batteryHolderHeightOuter]);
        translate([batteryHolderWalls + batteryConnectorThickness, -1, batteryHolderHeight]) {
          cube([batteryHolderLengthInner, batteryDiameter * rows + batteryHolderWalls * (rows + 1) + 2, batteryHolderHeight + 1]);
      }
      }

      for(i=[1:1:rows]) {
        rotate([0, 90, 0])
          translate([-batteryRadius - batteryHolderBottom, batteryRadius + batteryHolderWalls + (batteryDiameter + batteryHolderWalls) * (i - 1), 0])
            cylinder(h=batteryLength * columns + (batteryHolderWalls + batteryConnectorThickness) * 2, r =batteryRadius + batteryHolderWalls);
      }
    }

    translate([-1,-1,batteryHolderHeightOuter])
      cube([batteryHolderLength + 2, batteryHolderWidth + 2, batteryHolderHeightOuter]);

    for(i=[1:1:rows]) {
      rotate([0, 90, 0]) {
        translate([-batteryRadius - batteryHolderBottom, (batteryRadius + batteryHolderWalls) + (batteryDiameter + batteryHolderWalls) * (i - 1), batteryHolderWalls + batteryConnectorThickness])
          cylinder(h=batteryLength * columns, r =batteryRadius);
      }
    }

    translate([batteryHolderWalls + batteryConnectorThickness, -1, batteryHolderHeight * 1.5]) {
      cube([batteryHolderLengthInner, (batteryDiameter + batteryHolderWalls) * rows + batteryHolderWalls + 2, batteryHolderHeight + 1]);
    }

    rotate([0, 90, 0]) {
      translate([-batteryRadius - batteryHolderBottom, batteryRadius + batteryHolderWalls, -1]) {
        cylinder(h=batteryHolderWalls + 2, r=batteryHolderHoleRadius);
      }
      translate([-batteryRadius - batteryHolderBottom, batteryRadius + batteryHolderWalls * 2 + (batteryDiameter + batteryHolderWalls) * (rows - 1), -1]) {
        cylinder(h=batteryHolderWalls + 2, r=batteryHolderHoleRadius);
      }
    }

    translate([batteryHolderWalls, batteryHolderWalls, batteryHolderBottom])
      cube([batteryConnectorThickness + spacing, (batteryDiameter + batteryHolderWalls) * rows - batteryHolderWalls, batteryHolderBottom + batteryDiameter + 1]);

    translate([batteryHolderWalls + batteryConnectorThickness + batteryLength * columns - spacing, batteryHolderWalls, batteryHolderBottom])
      cube([batteryConnectorThickness + spacing,  (batteryDiameter + batteryHolderWalls) * rows - batteryHolderWalls, batteryHolderBottom + batteryDiameter + 1]);

    for(i=[1:1:columns]) {
      translate([batteryXOffset + batteryPullOffset + (batteryLength * (i - 1)), -1, batteryHolderHeight / 3])
        cube([batteryHolderPullWidth, batteryHolderWidth + 2, batteryHolderHeight * 2]);

      translate([batteryXOffset + batteryLength / 8 + (batteryLength * (i - 1)), -1, batteryHolderHeight])
        cube([batteryLength / 8 * 6, batteryHolderWidth + 2, batteryHolderHeight * 2]);
    }

    translate([batteryXOffset, -1, batteryHolderHeight])
        cube([batteryLength / 8 * 6, batteryHolderWidth + 2, batteryHolderHeight * 2]);
  }
}
```


[User]
I'd like to create a customizable 2D origami fox design using OpenSCAD, similar to the one described in the provided Thingiverse link and code.  I need a design that allows me to adjust the overall size, height, and line thicknesses. The design should consist of an outer outline and several inner cut lines, as defined by the polygon points in the original code. The inner lines should have rounded ends, and I should be able to control their radius. I need to be able to flip the design horizontally.

Specifically, I need the following parameters to be customizable:

*   `max_size_in_millimeter`: The maximum length of the longest side of the fox, which should be used to scale both x and y dimensions proportionally.
*   `model_height_in_millimeter`: The height or extrusion of the fox.
*   `outline_size_in_millimeter`: The thickness of the outer outline.
*   `inline_size_in_millimeter`: The thickness of the inner cut lines.
*   `inline_edge_radius_in_millimeter`: The radius of the rounded ends of the inner lines.
*   `flip_model`: A boolean or string option to flip the model horizontally ("yes" or "no").

The core shape should follow the points defined in the original code for the outer outline and inner cut polygons; I'll provide those points again:

**Outer Points:**
```
A1 = [238, 114];
A2 = [332, 136];
A3 = [432, 117];
A4 = [423, 178];
A5 = [440, 219];
A6 = [504, 265];
A7 = [505, 329];
A8 = [451, 391];
A9 = [413, 402];
A10 = [377, 415];
A11 = [336, 400];
A12 = [334, 376];
A13 = [347, 364];
A14 = [300, 265];
A15 = [280, 240];
A16 = [228, 220];
A17 = [249, 167];
```
**Inner Points:**
```
B1 = [315, 281];
B2 = [335, 264];
B3 = [355, 281];
B4 = [335, 303];
B5 = [343, 295];
B6 = [382, 253];
B7 = [396, 244];
B8 = [372, 316];
B9 = [357, 358];
B10 = [394, 335];
```
**Inner Polygons:**
```
C1 = [A16, A17, A1, A2];
C2 = [A2, A3, A4, A5];
C3 = [A16, A2, B2, B1, A15];
C4 = [B2, A2, A5, B7, B6, B3];
C5 = [B1, B2, B3, B5, B4];
C6 = [A14, A13, B5, B4, B1];
C7 = [A13, B9, B8, B7, B6, B3, B5];
C8 = [B7, A5, A6, B10, B8];
C9 = [A6, A10, A9, A8, A7];
C10 = [A6, A10, A11, A12, A13, B9, B10];
C11 = [B9, B10, B8];
```

Please generate the OpenSCAD code that does this. I don't need any external libraries.

[Assistant]
customizable_origami_cute_fox.scad:
```
/*
 * Customizable Origami - Cute Fox - https://www.thingiverse.com/thing:2616323
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2017-10-31
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

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

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.5; //[0.5:0.1:20]

// Thickness of the inner outline.
inline_size_in_millimeter = 0.7; //[0.5:0.1:20]

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.9; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [238, 114];
A2 = [332, 136];
A3 = [432, 117];
A4 = [423, 178];
A5 = [440, 219];
A6 = [504, 265];
A7 = [505, 329];
A8 = [451, 391];
A9 = [413, 402];
A10 = [377, 415];
A11 = [336, 400];
A12 = [334, 376];
A13 = [347, 364];
A14 = [300, 265];
A15 = [280, 240];
A16 = [228, 220];
A17 = [249, 167];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17];

// Inner Points
B1 = [315, 281];
B2 = [335, 264];
B3 = [355, 281];
B4 = [335, 303];
B5 = [343, 295];
B6 = [382, 253];
B7 = [396, 244];
B8 = [372, 316];
B9 = [357, 358];
B10 = [394, 335];

// Polygons
C1 = [A16, A17, A1, A2];
C2 = [A2, A3, A4, A5];
C3 = [A16, A2, B2, B1, A15];
C4 = [B2, A2, A5, B7, B6, B3];
C5 = [B1, B2, B3, B5, B4];
C6 = [A14, A13, B5, B4, B1];
C7 = [A13, B9, B8, B7, B6, B3, B5];
C8 = [B7, A5, A6, B10, B8];
C9 = [A6, A10, A9, A8, A7];
C10 = [A6, A10, A11, A12, A13, B9, B10];
C11 = [B9, B10, B8];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11];

min_x = A16[0];
min_y = A1[1];
max_x = A7[0];
max_y = A10[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
Hey, I'm looking to create a customizable 2D origami style sausage dog design using OpenSCAD. I want to be able to control the overall size of the model, its height, and the thickness of both the outer and inner outlines. It's based on an existing design, so I have the coordinates for the outline and the cut polygons. I'm not a programmer so I have trouble with OpenSCAD syntax, so I'm hoping you can help generate the code for me.

Here's the specifics:

*   **Overall Size:** I need to be able to specify the maximum size of the longest side (width or height) of the final model in millimeters, and the shorter side should be scaled proportionally.
*   **Model Height:** The height of the extruded model, which will be a fixed value for the 2D print.
*   **Outline Thickness:** I want to control the thickness of the outer outline in millimeters.
*   **Inner Outline Thickness:** I need to also control the thickness of the inner outlines or cut lines, also in millimeters.
*   **Inner Outline Rounding:** The inner outlines should have rounded edges, so I need a parameter for the radius of these rounded corners.
*   **Flip:** There should also be an option to flip the model horizontally.
*   **Points and Polygons:** I will provide the outline and cut polygons' points.

Here are the outline points:

```
A1 = [14, 148];
A2 = [146, 134];
A3 = [232, 54];
A4 = [232, 35];
A5 = [452, 7];
A6 = [435, 32];
A7 = [526, 186];
A8 = [1355, 230];
A9 = [1503, 218];
A10 = [1691, 101];
A11 = [1775, 83];
A12 = [1526, 252];
A13 = [1543, 292];
A14 = [1549, 476];
A15 = [1532, 575];
A16 = [1518, 580];
A17 = [1467, 704];
A18 = [1449, 778];
A19 = [1335, 778];
A20 = [1440, 715];
A21 = [1430, 609];
A22 = [1393, 618];
A23 = [1335, 407];
A24 = [760, 522];
A25 = [703, 523];
A26 = [500, 648];
A27 = [495, 712];
A28 = [491, 778];
A29 = [379, 778];
A30 = [455, 735];
A31 = [454, 675];
A32 = [312, 510];
A33 = [300, 508];
A34 = [305, 270];
A35 = [258, 350];
A36 = [248, 242];
A37 = [58, 225];
```

And here are the polygons formed by those points:

```
C1 = [A1, A37, A2];
C2 = [A3, A2, A37, A36];
C3 = [A35, A36, A3, A4, A5, A6, A34];
C4 = [A34, A6, A7];
C5 = [A34, A33, A7];
C6 = [A32, A33, A7, A24, A25];
C7 = [A32, A31, A26, A25];
C8 = [A31, A30, A27, A26];
C9 = [A28, A29, A30, A27];
C10 = [A24, A7, A8, A23];
C11 = [A8, A9, A23];
C12 = [A9, A10, A11, A12];
C13 = [A12, A13, A23, A9];
C14 = [A13, A14, A23];
C15 = [A23, A22, A14];
C16 = [A14, A22, A21, A16, A15];
C17 = [A16, A17, A20, A21];
C18 = [A17, A18, A19, A20];
```

I'm looking for the final .scad file that I can open in OpenSCAD. Let me know if you need anything else!

[Assistant]
customizable_origami_sausage_dog.scad:
```
/*
 * Customizable Origami - Sausage Dog - https://www.thingiverse.com/thing:2618266
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2017-10-30
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

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

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.5; //[0.5:0.1:20]

// Thickness of the inner outline.
inline_size_in_millimeter = 0.7; //[0.5:0.1:20]

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.4; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [14, 148];
A2 = [146, 134];
A3 = [232, 54];
A4 = [232, 35];
A5 = [452, 7];
A6 = [435, 32];
A7 = [526, 186];
A8 = [1355, 230];
A9 = [1503, 218];
A10 = [1691, 101];
A11 = [1775, 83];
A12 = [1526, 252];
A13 = [1543, 292];
A14 = [1549, 476];
A15 = [1532, 575];
A16 = [1518, 580];
A17 = [1467, 704];
A18 = [1449, 778];
A19 = [1335, 778];
A20 = [1440, 715];
A21 = [1430, 609];
A22 = [1393, 618];
A23 = [1335, 407];
A24 = [760, 522];
A25 = [703, 523];
A26 = [500, 648];
A27 = [495, 712];
A28 = [491, 778];
A29 = [379, 778];
A30 = [455, 735];
A31 = [454, 675];
A32 = [312, 510];
A33 = [300, 508];
A34 = [305, 270];
A35 = [258, 350];
A36 = [248, 242];
A37 = [58, 225];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37];

// Polygons
C1 = [A1, A37, A2];
C2 = [A3, A2, A37, A36];
C3 = [A35, A36, A3, A4, A5, A6, A34];
C4 = [A34, A6, A7];
C5 = [A34, A33, A7];
C6 = [A32, A33, A7, A24, A25];
C7 = [A32, A31, A26, A25];
C8 = [A31, A30, A27, A26];
C9 = [A28, A29, A30, A27];
C10 = [A24, A7, A8, A23];
C11 = [A8, A9, A23];
C12 = [A9, A10, A11, A12];
C13 = [A12, A13, A23, A9];
C14 = [A13, A14, A23];
C15 = [A23, A22, A14];
C16 = [A14, A22, A21, A16, A15];
C17 = [A16, A17, A20, A21];
C18 = [A17, A18, A19, A20];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18];

min_x = A1[0];
min_y = A5[1];
max_x = A11[0];
max_y = A18[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
I'm looking to create a customizable origami sparrow design in OpenSCAD. I've seen one that allows for adjustable size and line thickness, and I'd like to recreate something similar.

Here are the key features I need:

*   **Shape:** The design is based on a series of interconnected points that define the sparrow's outline and internal cuts, like in the attached example. I will supply the points as well as the polygon definitions for each. The overall shape is roughly a stylized bird.
*   **Customizable Size:** I need to be able to specify the maximum dimension of the model. The design should scale proportionally so that the entire design fits within the specified bounds.
*   **Customizable Height:** I need to be able to specify the extrusion height.
*   **Line Thickness:** I need control over both the outer outline thickness and the inner cut line thickness. Specifically, the outer outline is a filled area, and the inner cuts are just lines, not filled areas. The inner cut lines should have rounded edges. I need to be able to specify the radius of these rounded ends. The inner and outer thickness and radius can be controlled separately.
*   **Mirroring:** I'd like an option to mirror the entire design along the y-axis (flip it).

I'll provide the coordinates of the points and the polygon definitions for the outlines and cut lines in the example code, so you can use those directly, I would also like to be able to define the resolution using `$fn`.

Here's the data that defines the shape from the example file. Please use these same point definitions and polygon defintions.

```
// Outer Points
A1 = [11, 297];
A2 = [144, 203];
A3 = [127, 165];
A4 = [182, 99];
A5 = [228, 48];
A6 = [367, 9];
A7 = [531, 104];
A8 = [845, 190];
A9 = [1163, 26];
A10 = [1197, 4];
A11 = [1031, 198];
A12 = [927, 256];
A13 = [932, 269];
A14 = [1139, 353];
A15 = [993, 347];
A16 = [1201, 598];
A17 = [1110, 565];
A18 = [1255, 829];
A19 = [797, 517];
A20 = [623, 557];
A21 = [656, 612];
A22 = [425, 657];
A23 = [515, 605];
A24 = [371, 630];
A25 = [505, 556];
A26 = [355, 548];
A27 = [254, 481];
A28 = [215, 317];
A29 = [189, 295];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29];

// Inner Points
B1 = [220, 258];
B2 = [246, 67];
B3 = [430, 196];
B4 = [524, 331];
B5 = [887, 228];
B6 = [999, 163];
B7 = [529, 557];
B8 = [549, 589];
B9 = [598, 561];

// Polygons
C1 = [A5, A6, A7, B3, B2];
C2 = [A7, A8, B5, A12, A13];
C3 = [A8, A9, B6, B5];
C4 = [B5, B6, A9, A10, A11, A12];
C5 = [A7, A13, A14, A15, B4, B3];
C6 = [B4, A15, A16, A17];
C7 = [B4, A19, A18, A17];
C8 = [A19, A20, B9, B7, A25, A26, A27, A28, A29, B1, A2, A3, A4, B2, B3, B4];
C9 = [A25, A24, A23, B8, B7];
C10 = [A20, A21, A22, A23, B8, B9];
C11 = [B8, B9, B7];
C12 = [A29, A1, B1];
C13 = [A1, A2, B1];
C14 = [A4, B2, A5];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14];
```

I don't need any additional libraries to be included in the generated SCAD file.

[Assistant]
customizable_origami_sparrow.scad:
```
/*
 * Customizable Origami - Sparrow - https://www.thingiverse.com/thing:2619670
 * by Dennis Hofmann - https://www.thingiverse.com/mightynozzle/about
 * created 2017-11-01
 * version v1.0
 *
 * Changelog
 * --------------
 * v1.0:
 *      - final design
 * --------------
 *
 * This work is licensed under the Creative Commons - Attribution - NonCommercial - ShareAlike license.
 * https://creativecommons.org/licenses/by-nc-sa/3.0/
 */

 // Parameter Section //
//-------------------//

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

// The maximum size of the longest side. The shorter side will be automatically resized in same ratio.
max_size_in_millimeter = 120; //[20:300]

// The height of the model.
model_height_in_millimeter = 5; //[0.2:0.2:100]

// Thickness of the outer outline.
outline_size_in_millimeter = 1.4; //[0.5:0.1:20]

// Thickness of the inner outline.
inline_size_in_millimeter = 0.7; //[0.5:0.1:20]

// Roundiness of the ends of the inner outlines.
inline_edge_radius_in_millimeter = 0.3; //[0.0:0.1:5]

// Flip model
flip_model = "no"; //[yes,no]

/*[hidden]*/
max_size = max_size_in_millimeter;
model_height = model_height_in_millimeter;
$fn=32;

// Outer Points
A1 = [11, 297];
A2 = [144, 203];
A3 = [127, 165];
A4 = [182, 99];
A5 = [228, 48];
A6 = [367, 9];
A7 = [531, 104];
A8 = [845, 190];
A9 = [1163, 26];
A10 = [1197, 4];
A11 = [1031, 198];
A12 = [927, 256];
A13 = [932, 269];
A14 = [1139, 353];
A15 = [993, 347];
A16 = [1201, 598];
A17 = [1110, 565];
A18 = [1255, 829];
A19 = [797, 517];
A20 = [623, 557];
A21 = [656, 612];
A22 = [425, 657];
A23 = [515, 605];
A24 = [371, 630];
A25 = [505, 556];
A26 = [355, 548];
A27 = [254, 481];
A28 = [215, 317];
A29 = [189, 295];

outline = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29];

// Inner Points
B1 = [220, 258];
B2 = [246, 67];
B3 = [430, 196];
B4 = [524, 331];
B5 = [887, 228];
B6 = [999, 163];
B7 = [529, 557];
B8 = [549, 589];
B9 = [598, 561];

// Polygons
C1 = [A5, A6, A7, B3, B2];
C2 = [A7, A8, B5, A12, A13];
C3 = [A8, A9, B6, B5];
C4 = [B5, B6, A9, A10, A11, A12];
C5 = [A7, A13, A14, A15, B4, B3];
C6 = [B4, A15, A16, A17];
C7 = [B4, A19, A18, A17];
C8 = [A19, A20, B9, B7, A25, A26, A27, A28, A29, B1, A2, A3, A4, B2, B3, B4];
C9 = [A25, A24, A23, B8, B7];
C10 = [A20, A21, A22, A23, B8, B9];
C11 = [B8, B9, B7];
C12 = [A29, A1, B1];
C13 = [A1, A2, B1];
C14 = [A4, B2, A5];

cut_polygons = [C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14];

min_x = A1[0];
min_y = A10[1];
max_x = A18[0];
max_y = A18[1];

x_size = max_x - min_x;
y_size = max_y - min_y;

x_factor = max_size / x_size;
y_factor = max_size / y_size;

inline_size = x_size > y_size ? inline_size_in_millimeter / x_factor / 2: inline_size_in_millimeter / y_factor / 2;
inline_edge_radius = x_size > y_size ? inline_edge_radius_in_millimeter / x_factor: inline_edge_radius_in_millimeter / y_factor;
outline_size = x_size > y_size ? outline_size_in_millimeter / x_factor - inline_size: outline_size_in_millimeter / y_factor - inline_size;

 // Program Section //
//-----------------//

if(x_size > y_size) {
    resize(newsize=[max_size, x_factor * y_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
} else {
    resize(newsize=[y_factor * x_size, max_size, model_height]){
        if(flip_model == "yes") {
            mirror([0,1,0]) {
                rotate([180,180,0]) {
                    create(outline, cut_polygons);
                }
            }
        } else {
            create(outline, cut_polygons);
        }
    }
}

 // Module Section //
//----------------//

module create() {
    linear_extrude(height=1) {
        difference() {
            offset(r = -0) {
                offset(r = +outline_size) {
                    polygon(points = outline, convexity = 10);
                }
            }

            for(cut_polygon = [0:len(cut_polygons)]) {
                offset(r = +inline_edge_radius) {
                    offset(r = -inline_size - inline_edge_radius) {
                        polygon(points = cut_polygons[cut_polygon], convexity = 10);
                    }
                }
            }
        }
    }
}

```


[User]
I'm looking to generate a parametric OpenSCAD design for a clip that attaches to the side of small parts bins, specifically the ones from thingiverse.com/thing:2222574. I've already got something roughed out, but I'd like a more robust solution that I can easily tweak.

Here's how I envision it:

The clip will have a rectangular face plate where I can place a label. The face plate should be defined by a `face_width`, `face_height`, and `face_thick` parameters. These will determine the dimensions of the rectangle for the label.

On the back of the face plate, there will be two tabs that grip the bin wall. These tabs will have a `tab_width`, `tab_depth`, and a `tab_position` that defines the horizontal center point between the tabs. There should also be a `fit_wall` parameter, defining the gap between the tabs, which should match the thickness of the bin wall; I don't want the design to add any tolerance for the gap.

I need a cutout between the two tabs on the back, but it only needs to be a small rectangular relief, and that dimension can be set to half of the face thickness.

The design should be completely parametric, using all of the parameters I've described. The current clip is designed for walls that are about 2mm thick, but I want to be able to adjust that with `fit_wall`.

I'd also like for it to be reasonably easy to adapt for different bin styles if I end up using containers with different thicknesses or tab designs. I'm not sure what the best way to achieve that is but am open to suggestions. Ideally, I'd like to avoid any need to do manual rotations or translations, so I'm hoping you can build those into the base design. I think I'd like to have a custom module to define the tab shape too.

I would prefer for the files to be completely self-contained, without using any libraries. Could you generate the necessary .scad file(s) for me?

[Assistant]
SCrewTrayClip.scad:
```
// Label Clip for Small Parts bin

face_width = 30;
face_height = 12;
face_thick=1.2;
fit_wall = 2;
tab_width = 2.5;
tab_depth = 6;
tab_position = 5;
/* [Hidden] */
tab_pts_left = [[tab_position-tab_width-fit_wall/2,0],[tab_position-fit_wall/2,0],[tab_position-fit_wall/2,tab_depth],[tab_position-tab_width,tab_depth]];
tab_pts_right = [[tab_position+fit_wall/2,0],[tab_position+tab_width+fit_wall/2,0],[tab_position+tab_width,tab_depth],[tab_position+fit_wall/2,tab_depth]];

rotate([-180,0,0])
difference(){
linear_extrude(height = face_thick)
            square([face_width, face_height]);
linear_extrude(height = face_thick/2)
translate([tab_position-fit_wall/2,-0.010,0])
            square([fit_wall,face_height+0.01]);
}
rotate([90,0,0]) difference(){linear_extrude(height = face_height/1.2) translate([0,0,face_height]) polygon(points=tab_pts_left);
    linear_extrude(height = face_height - face_height/1.2) translate([0,0,face_height]) polygon(points=tab_pts_left);
    }
rotate([90,0,0]) difference(){linear_extrude(height = face_height/1.2) polygon(points=tab_pts_right);linear_extrude(height = face_height-face_height/1.2) polygon(points=tab_pts_right);
}

//translate([tab_position-tab_width-fit_wall/2, 0, 0])
//        linear_extrude(height = tab_depth)
//            square([tab_width, height]);
//translate([tab_position+fit_wall/2, 0, 0])
//        linear_extrude(height = tab_depth)
//            square([tab_width, height]);

```