[User]
Hey, I need a parametric rigid shaft coupler designed in OpenSCAD. I've got a couple of existing designs I've worked with, and I'll try to explain what I need as clearly as possible.

Essentially, it's a cylindrical coupler with two different sized bores for different shaft diameters. It will have a gap cut through the side to allow it to clamp down on the shafts, and there will be bolts running perpendicular to the shafts to tighten the coupler.

Here's the breakdown of the parameters I need:

*   **`OD`**: The outside diameter of the coupler cylinder.
*   **`Ht`**: The total height of the coupler.
*   **`ShaftSmall`**: The diameter of the smaller shaft bore. This should have a slight allowance for a slip fit.
*   **`ShaftLarge`**: The diameter of the larger shaft bore. Same here, a little extra for slip fit.
*   **`GapDist`**: The width of the gap cut in the side of the cylinder.
*   **`M3`**: The diameter of the bolt holes (I'm using M3 bolts).
*   **`M3Nut`**: The diameter of the recess for the M3 nuts.
*   **`BoltLen`**: The length of the bolts.
*  **`M3_DX`**: The horizontal (X) offset of the bolt hole from the center.
*  **`M3_DZ1`**: The vertical (Z) offset of the first bolt hole.
*  **`M3_DZ2`**: The vertical (Z) offset of the second bolt hole.
*   **`IresBig`**: Resolution for the larger circles like the outside of the coupler.
*   **`IresSmall`**: Resolution for the smaller circles like the shaft bores.
*   **`ChamferSize`**: The radius of the chamfer applied to the top and bottom edges of the cylinder.
*   **`PartType`**: An option to generate either a single part or two halves. 1 will mean a standard part with a single gap; 2 will mean two halves with the same bolt pattern and gap, mirrored.

I think that's pretty much it. I'm not doing anything too complicated here. I'd like to see the code generate the basic shape, then cut the bores, the gap, and the bolt holes. If `PartType` is 2, the second half should have all the holes and gap cuts too, mirrored. Also, can you include the chamfer on the top and bottom if `ChamferSize` is greater than 0?

I don't have any preferences for how you structure the code, just as long as it's parametric and generates the coupler as described above. Please make sure that the design is based on primitive shapes and operations, that is, nothing in the code should use an imported .stl.

It looks like the code I linked is using some fairly standard operations, so I don't think there's any need to use external libraries, but if you see a way that would make it easier, I'm open to that. Thanks!

[Assistant]
ShaftCoupler_rev7.scad:
```
//Parametric Coupler
//By David Bunch 8/9/2015
//
//This design is based on the Rigid Coupler for the
//Mostly printed CNC machine http://www.thingiverse.com/thing:724999
//To couple different or same size Shafts together,
//usually a nema 17 motor to a threaded rod
//The little bolts used to tighten this design are M3 x 14mm or 16mm length
//CUSTOMIZER VARIABLES

//1. Outside Diameter of Coupler (try 20 for 5mm to 5mm)
OD = 22;

//2. Total Height of Coupler
Ht = 25.4;

//3. Small Coupler Connection (5mm default)
ShaftSmall = 5.25;              //Add 5% to make more of a slip fit
                                //Tightening bolts will snug this up
                               //6.66 = 1/4"(6.35mm)

//4. Large Coupler Connection (8mm default)
ShaftLarge = 8.4;              //Add 5% to make more of a slip fit
                               //8.4 = 8mm, 6.3 = 6mm, 5.25 = 5mm

//5. Gap Cut size for Tightening Coupler
GapDist = 2.2;

//6. Coupling Bolt Diameter used for Tightening (M3 default)
M3 = 3.4;              //Use 3.65 for #6 bolts

//7. Coupling Bolt Diameter used for Tightening
M3Nut = 6.5;           //if using #6 Nuts use 9.25mm
                        //4mm nuts 8.08mm (
                        //3mm nuts 6.5mm (This size worked good for me)

//8. Bolt Length (14mm long bolt is default)
BoltLen = 14;         //This should still be a good length for
                        //14mm or 16mm length bolts will just
                        //        stick out a little beyond locknut

//9. X Offset for Bolt Tightening Holes (try 6 for 5mm to 5mm)
M3_DX=7;

//10. 1st Z Offset for Bolt Tightening Holes
M3_DZ1 = 6;

//11. 2nd Z Offset for Bolt Tightening Holes
M3_DZ2 = 19.4;

//12. Resolution large Circles
IresBig = 88;

//13. Resolution of Small Circles
IresSmall = 34;

//14. Chamfer Radius at Top & bottom
ChamferSize = 1.5;        //Set width of chamfer at top & bottom

//15. 1 part or 2 Halves
PartType = 1;   //2 Halves are useful if your 2 shafts are already in place

//CUSTOMIZER VARIABLES END

M3_Thk = (BoltLen - GapDist - 5.2) / 2;
echo("M3_Thk = ", M3_Thk);

GapHalf = GapDist / 2;
M3Nut_DY = M3_Thk + GapHalf;

Rad = OD / 2;

//This is the Chamfer used at the bottom & top of coupling
module ChamferCyl()
{
    if (ChamferSize > 0)
    {
        rotate_extrude(convexity = 10, $fn = IresBig)
        translate([Rad, 0, 0])
        circle(r = ChamferSize, $fn = 4);
    }
}
//These are the holes for the tightening bolts & nuts
module BoltAndNutCut()
{
//Drill hole all the way through
    translate([-M3_DX,Rad,0])
    rotate([90,0,0])
    cylinder(d=M3,h=OD,$fn=IresSmall);
//Cut for hex nut on one end
    translate([-M3_DX,-M3Nut_DY,0])
    rotate([90,0,0])
    rotate([0,0,30])
    cylinder(d=M3Nut,h=Rad,$fn=6);
//Cut for hex nut on the other end
    translate([-M3_DX,M3Nut_DY,0])
    rotate([-90,0,0])
    rotate([0,0,30])
    cylinder(d=M3Nut,h=Rad,$fn=6);
}
module HorizontalHoles()
{
    translate([0,0,M3_DZ1])
    BoltAndNutCut();            //Lower Horizontal Hole
    translate([0,0,M3_DZ2])
    BoltAndNutCut();            //Upper Horizontal Hole
}
//Cut out the holes, gap & draw final part
module DrawFinal()
{
    difference()
    {
        cylinder(d=OD,h=Ht,$fn=IresBig);        //Draw the main cylinder
        translate([0,0,-1])
        cylinder(d=ShaftSmall,h=Ht+2,$fn=IresSmall);    //Cut small shaft hole from bottom
        translate([0,0,Ht / 2])                         //Start 2nd hole half way up
        cylinder(d=ShaftLarge,h=Ht,$fn=IresSmall);      //Cut large or same size shaft hole
        translate([-(Rad+.01),-GapHalf,-1])
        cube([Rad,GapDist,Ht+2]);       //Cut gap for tightening
//Cut bottom bolt tightening hole
        HorizontalHoles();  //Cut horizontal holes for tightening bolts
//See if user wants to draw this as 2 halves instead of just 1 gap cut
        if (PartType == 2)
        {
            rotate([0,0,180])
            {
                HorizontalHoles();  //Cut horizontal holes for tightening bolts
                translate([-(Rad+.01),-GapHalf,-1])
                cube([Rad,GapDist,Ht+2]);       //Cut gap for tightening
            }
        }
        if (ChamferSize > 0)
        {
            ChamferCyl();                   //Chamfer the top
            translate([0,0,Ht])
            ChamferCyl();                   //Chamfer the bottom
        }
    }
}

DrawFinal();
```


[User]
Hey, I'm looking to design a custom sub-kick microphone enclosure for 3D printing, and I want to be able to easily adjust it for different speakers. I've got a pretty good idea of the design I want and a rough idea of the parameters that need to be adjustable. I'd really like your help generating the OpenSCAD files.

Essentially, it's going to be a cylindrical speaker enclosure that mounts to a stand with a triangular support structure, and it needs to have a place for an XLR connector. Here's a breakdown of the parameters and the features I need:

**Speaker Enclosure:**

*   **`speaker_diameter`**: The outer diameter of the speaker, in mm.
*   **`speaker_hole_cutout`**: The diameter of the hole in the baffle for the speaker, in mm.
*   **`baffle_depth`**: The depth of the baffle itself, in mm.
*   **`speaker_holder_thickness`**: The thickness of the main part that holds the speaker, in mm.
*   **`baffle_beef`**: A general "beefiness" factor that affects the overall thickness of the structure, in mm. This one is a little less descriptive, but I think this will help maintain design consistency.
*   **`number_holes`**: The number of bolt holes for mounting the speaker to the baffle.
*   **`speaker_extra_hole_rotate`**:  An additional rotation for the bolt holes (in degrees), so you can offset them as needed to make them aesthetically pleasing.
*   **`hole_size`**: The diameter of the mounting bolt holes, in mm.
*  **`hole_offset`**: The distance that the bolt holes are offset from the midpoint between the `speaker_diameter` and the `speaker_hole_cutout`, in mm.

**Stand:**

*   **`stand_height`**: The height of the stand below the speaker enclosure, in mm.
*  **`base_length`**: The length of the base of the stand, in mm.
*   **`triangle_supports_height`**: The height of the triangular support structures, in mm.
*  **`triangle_supports_length`**: The length of the triangular support structures, in mm.
*   **`back_triangle_support`**: An offset value to raise the back vertices of the triangle supports. This helps make them flush with the stand, in mm.
*   **`save_plastic`**: The diameter of a circular cutout in the base of the stand, in mm.

**XLR Mount:**

*   **`XLR_jack_move_forward_back`**: An offset value that moves the XLR panel forward or backward relative to the cylindrical enclosure, in mm.
*   **`XLR_jack_move_up_down`**: An offset value that moves the XLR panel up or down relative to the stand, in mm.
*   **`XLR_up_down`**: An offset value that moves the XLR connector itself up or down within the mounting panel, in mm.
*   **`raise_jack_corner`**:  An offset value to raise the front corner of the XLR mounting panel, in mm.
*   **`raise_rear_jack_corner`**: An offset value to raise the rear corner of the XLR mounting panel, in mm.
*   **`xlr_mount_thickness`**: The thickness of the mounting panel for the XLR connector, in mm.

**Other:**

*   **`res`**: Resolution of circles and cylinders for rendering (a high value should result in a smoother render).

*   **`ready_for_print`**: A string that is either "Yes" or "No". If it is "Yes," the entire model is rotated for optimal printing and support material minimization.

I would really appreciate if the design could be modularized into separate OpenSCAD modules as much as makes sense, and also I'd like for the XLR mount to be mirrored. Also, I'd like for the support triangles to use a polygon with a couple of intermediate points. For the speaker mounting holes, I was just doing a for loop, but is there a better way to do it?

I think that covers all the important details. Thanks for your help! I'm not familiar with all the available libraries, so I'm just going to leave it to you to choose.

[Assistant]
sub_kick_maker.scad:
```
// preview[view:northwest]

//Resolution of Model

res = 500;

//Speaker Total Diameter mm

speaker_diameter = 177.5;

//Speaker Hole Diameter mm

speaker_hole_cutout = 143;

//Speaker Baffle Depth mm

baffle_depth = 4;

// Thickness of Part that Holds Speaker mm

speaker_holder_thickness = 15;

// "Beefiness" of the Entire Structure mm

baffle_beef = 10;

// Number of Baffle Holes for Bolts

number_holes = 4;

// Additional Rotation to Baffle Holes (Allows you to make odd numbers of baffle holes look nice)

speaker_extra_hole_rotate = 45;

//Size of Baffle Bolt Holes Diameter mm

hole_size = 7;

//Offset of Baffle Holes mm

hole_offset = 3;

//Height of Stand

stand_height = 101;

//Length of Base

base_length=150;

//Height of Triangle Supports

triangle_supports_height = 102;

//Length of Triangle Supports

triangle_supports_length = 150;

//Raise Rear Vertices of Triangle Supports to be Flush with Base. Should equal "Beefiness" value

back_triangle_support = 10;

//Size of Base Circle Cutout

save_plastic=55;

// Move the XLR Panel Forward or Backward

XLR_jack_move_forward_back = 17;

// Move the XLR Panel Up or Down

XLR_jack_move_up_down = -3;

// Move XLR Jack Up or Down (Remember you can use negative numbers too!)

XLR_up_down = 2;

// Raise XLR Panel Front Corner to Intersect with Triangle Support

raise_jack_corner = 53;

// Raise XLR Panel Rear Corner to Intersect with Triangle Support

raise_rear_jack_corner = 29;

// Thickness of XLR Panel. 3 is the maximum panel depth recommended by Neutrik

xlr_mount_thickness = 3;

//Orient Sub-Kick Properly for 3D Printing? (Rotates model so no support will be necessary - Choose "Yes"!)
ready_for_print = "No"; // [Yes, No]

module sub_holder(){

difference(){

rotate([0,90,0]) cylinder(speaker_holder_thickness,(speaker_diameter/2)+baffle_beef,(speaker_diameter/2)+baffle_beef, $fn=res);

rotate([0,90,0]) translate([0,0,-1]) cylinder(speaker_holder_thickness+2,(speaker_hole_cutout/2),(speaker_hole_cutout/2), $fn=res);

rotate([0,90,0]) translate([0,0,-1]) cylinder(baffle_depth+1,(speaker_diameter/2),(speaker_diameter/2), $fn=res);

for ( booyah = [0 : number_holes] )
{
    rotate( (booyah * 360 / number_holes) + speaker_extra_hole_rotate, [1, 0, 0])
    translate([0, ((speaker_diameter/2) + (speaker_hole_cutout/2))/2 + hole_offset, 0])
    rotate([0,90,0]) translate([0,0,-1]) cylinder(speaker_holder_thickness+2,(hole_size/2),(hole_size/2), $fn=res/2);}

}

}

module stand_risers(){

rotate([0,180,0]) translate([-speaker_holder_thickness,(speaker_diameter/2),0]) cube([speaker_holder_thickness,baffle_beef,stand_height]);

difference(){
rotate([0,0,180])translate([-speaker_holder_thickness,0,-stand_height]) cube([base_length,(speaker_diameter/2)+baffle_beef,baffle_beef]);

//Circle cutout

 translate([((-base_length+speaker_holder_thickness)/2),0,-stand_height+(baffle_beef/2)]) cylinder((baffle_beef+2),save_plastic,save_plastic, $fn=res, center=true);

}

rotate([0,-90,90])translate([-stand_height,-speaker_holder_thickness,(speaker_diameter/2)]) linear_extrude(height = baffle_beef) polygon(points=[[0,0],[triangle_supports_height,0],[back_triangle_support,triangle_supports_length],[10,10],[triangle_supports_height-25,10],[back_triangle_support+2,triangle_supports_length-25]], paths=[[0,1,2],[3,4,5]]);

}

module XLR_TRS_Mount(){

translate([XLR_jack_move_up_down,0,0])

 difference(){

 union(){

translate([0,0,-xlr_mount_thickness/2])linear_extrude(xlr_mount_thickness) polygon(points=[[-20,-20],[-20,20],[raise_jack_corner,20],[raise_rear_jack_corner,-20]], paths=[[0,1,2,3]]);

}

translate([XLR_up_down,0,0]) cylinder(xlr_mount_thickness+5,24.5/2,24.5/2, $fn=res/3, center=true);
translate([XLR_up_down+(24/2),19/2,0]) cylinder(xlr_mount_thickness+5,4/2,4/2, $fn=res/3, center=true);
translate([XLR_up_down-(24/2),-19/2,0]) cylinder(xlr_mount_thickness+5,4/2,4/2, $fn=res/3, center=true);
}
}

module Mount_reflect(){

translate([XLR_jack_move_up_down,0,0])

translate([0,0,-xlr_mount_thickness/2])linear_extrude(xlr_mount_thickness) polygon(points=[[-20,-20],[-20,20],[raise_jack_corner,20],[raise_rear_jack_corner,-20]], paths=[[0,1,2,3]]);

//translate([0,22.5,5]) cube([40,5,15], center = true);
//translate([0,-22.5,5]) cube([40,5,15], center = true);

}

if (ready_for_print == "Yes"){

rotate([0,90,0]) union(){
sub_holder();
stand_risers();
mirror([0,1,0]) stand_risers();
translate([-XLR_jack_move_forward_back,(speaker_diameter/2)+baffle_beef-xlr_mount_thickness/2,-stand_height+30]) rotate([-90,-90,0]) XLR_TRS_Mount();
  translate([-XLR_jack_move_forward_back,(-speaker_diameter/2)+(-baffle_beef+xlr_mount_thickness/2),-stand_height+30]) rotate([-90,-90,0]) Mount_reflect();
}

} else {

union(){
sub_holder();
stand_risers();
mirror([0,1,0]) stand_risers();
translate([-XLR_jack_move_forward_back,(speaker_diameter/2)+baffle_beef-xlr_mount_thickness/2,-stand_height+30]) rotate([-90,-90,0]) XLR_TRS_Mount();

    translate([-XLR_jack_move_forward_back,(-speaker_diameter/2)+(-baffle_beef+xlr_mount_thickness/2),-stand_height+30]) rotate([-90,-90,0]) Mount_reflect();

}

}

```


[User]
I'm looking to design a customizable hook that can clamp onto a desk or other similar surface. I've got a pretty clear idea of how I want it to work, and I'd like your help generating the OpenSCAD code for it.

The basic concept is a hook with a flat, vertical back that rests against the desk edge. The hook then extends out horizontally, and underneath the horizontal portion, there's a clamping section that grips the underside of the desk. This clamping section is angled slightly inward to improve grip.

I'd like the design to be fully parametric. I want to be able to control the following dimensions:

*   `deskTopWidth`: The thickness of the desk it's clamping onto.
*   `hookLength`: The horizontal length of the hook extending outward.
*   `hookHeight`: The height of the vertical back portion of the hook.
*   `topGrab`: The length of the horizontal grab portion that contacts the desk.
*   `bottomGrab`: The length of the angled grip section.
*   `grabAngle`: The angle of the angled grip section relative to vertical.
*   `hookWidth`: The width of the hook.
*   `hookThickness`: The thickness of the material used for the hook.
*  `tolerance`: A tolerance value to be added to `deskTopWidth`

Also, I'd like rounded corners on the two inside corners where the back meets the horizontal section and where the horizontal section meets the vertical part that goes down. It might be useful to make the rounded corner creation modular.

I’m envisioning a design where all of these parameters can be adjusted using the OpenSCAD customizer, making it easy to modify for different desk thicknesses and hook needs. Could you generate the necessary OpenSCAD file(s) for this? I don’t need any special libraries or anything unless it’s necessary to achieve the desired rounding effect. Thanks!

[Assistant]
Hook-v9.scad:
```
// all measurements in mm
deskTopWidth = 25;

hookLength = 30;
hookHeight = 15;

topGrab = 40;
bottomGrab = 70;

grabAngle = 88;

hookWidth = 25;
hookThickness = 4;

// tolerance for desktopWidth based on printer experience
tolerance=0.4;

module Hook() {
    // build and move primitives

    cube([hookThickness, hookWidth, hookHeight]);
    cube([hookLength+hookThickness,hookWidth,hookThickness]);
    // add twice the hook thickness to the the height of the gap
    translate ([hookLength+hookThickness,0,-hookThickness])
        cube([hookThickness,hookWidth,deskTopWidth+tolerance+2*hookThickness]);
    translate ([hookThickness*2+hookLength,0,deskTopWidth-hookThickness*2+tolerance+2*hookThickness])
        cube([topGrab,hookWidth,hookThickness]);

    // rotate for additional grab about the y axis
    // need to rotate prior to translation otherwise the element will become quite disjointed

    // failed to properly account for the grab angle
    translate ([hookThickness*2+hookLength,0,-hookThickness])
        rotate([0,-90+grabAngle,0])
        cube([bottomGrab,hookWidth,hookThickness]);

    // round the inside corners
    translate ([hookThickness,0,hookThickness])
        RoundedCorner();
    translate([hookLength+hookThickness,0,hookThickness])
        rotate([0,-90,0])
        RoundedCorner();
}

module RoundedCorner() {
    // modularise the corner and translate back to origin
    translate([hookThickness/2,hookWidth/2,hookThickness/2])
    difference() {
        cube ([hookThickness,hookWidth,hookThickness],center=true);
        translate([hookThickness/2,-hookWidth/4,hookThickness/2])
        rotate([90,0,0])
        cylinder(r=hookThickness,h=hookWidth*2,center=true);
    }
}
// make transparent during rounded corner creation
//rotate([0,0,45])
//rotate([90,0,0])
Hook();

```


[User]
Hey, I'm looking to get a custom battery holder designed in OpenSCAD, specifically for 18650 batteries. I'd like it to be parametric so I can easily adjust it.

Here's what I'm thinking:

*   **Basic Structure:** It should have a rectangular base with circular cutouts for the batteries. The number of batteries it holds should be adjustable, let's say from 1 to 8.

*   **Battery Dimensions:** The diameter of the cutout should be slightly larger than the 18650 battery, like 21mm so there is a bit of clearance (18 + 3).

*   **Holder Height:** I'd want to control the height of the holder as well. I'm thinking a range from 10mm to 30mm would be useful.

*   **Base Thickness:** There should be some extra space at the bottom of the battery cutouts, maybe 2 to 5mm.

*   **Spacing:** There needs to be some space between the battery cutouts and the edges of the base and also in between the individual batteries. Let's say I want to control this with a parameter, somewhere between 2 and 10mm for both.

*   **Optional Clips:** Finally, I'd like to make the clips optional so I can turn them off if I don't want them. If they're enabled, I want them to be on one side of each battery cutout.

Could you put this together as an OpenSCAD file? I don't need it to be super fancy, just functional.

[Assistant]
18650_holder.scad:
```
// 18650 holder
//
// http://www.thingiverse.com/mikegi/about

number_of_batteries = 2; // [1:8]
battery_diameter =  18 + 3 ;
holder_height = 17; // [10:30]
space_on_bottom = 3; // [2:5]
space_between_holders_and_edges = 3; // [2:10]
clips = "true"; // [true, false]

difference()
{
translate( [-(battery_diameter + space_between_holders_and_edges *2)/2, 0,0])
cube([ battery_diameter + space_between_holders_and_edges *2  , battery_diameter * number_of_batteries + space_between_holders_and_edges * (number_of_batteries + 1) , holder_height]);

translate([0, -( battery_diameter/2) ,space_on_bottom ])
for (i = [ 1:number_of_batteries ])
{
translate([0,(space_between_holders_and_edges + battery_diameter) * i, 0])
cylinder( h = holder_height, d = battery_diameter);

}
}

if ( clips == "true" )
{
translate([0, -( battery_diameter/2) ,0])
for (i = [ 1:number_of_batteries ])
{
translate([0,(space_between_holders_and_edges + battery_diameter) * i, 0])
{
translate([ - (battery_diameter/2 + space_between_holders_and_edges + 7), -5, 0 ])
cube( [3,10,holder_height] );
translate([- (battery_diameter/2 + space_between_holders_and_edges + 6), -5,holder_height-5])
cube( [6,10,5] );
}
}

}

```


[User]
I'm trying to design some IKEA-style plugs for 3D printing, and I want a parametric OpenSCAD file to make it easy to adjust the dimensions. Basically, the plug has a base cylinder, then a conical section, and then another shorter cylinder on top.

Here's a breakdown:
*   **Base:** A cylinder with a specified radius and height.
*   **Cone:** Starts at the top of the base cylinder, widens outwards to a larger radius over a specified height, and then there is a cylinder that is of the same larger radius over a specified height.
*   **Overall:** The base cylinder's radius is going to be important, as well as the total height of the plug. And how high the cone section is.

I'd also like the ability to easily create arrays of these plugs for efficient printing. I'm thinking of a square array. I should be able to specify the total number of plugs I want in the array. I'd like the spacing between plugs to also be parametric, probably based on the overall size of the plug.

It would be fantastic if I can also adjust the level of detail, so that I can lower the resolution for a quick print, or increase it for a nicer surface finish. I’ve seen that the `$fn` variable controls that for circles and cylinders in OpenSCAD so it should be possible to adjust this.

Finally, I am not sure why, but I've seen people suggest changing the base radius to something else before changing it back to the radius we want.. Perhaps that’s something we can also check for in the scad file.

Is this possible? I'd be grateful for your help.

[Assistant]
ikeaPlug.scad:
```
$fn = 100;

$baseHeight = 12;
$baseRadius = 2.4;
$coneDimension = 3;
$topHeight = 10;
spacing = 2 * ($baseRadius + $coneDimension) + 1;
$amount = 10;

module cone(){
    union(){
        cylinder(r = $baseRadius, h = $topHeight);
        translate([0,0,$topHeight]){
            cylinder(r1 = $baseRadius, r2 = $baseRadius + $coneDimension, h = $coneDimension);
            translate([0,0,$coneDimension]){
                cylinder(r = $baseRadius, h = $baseHeight);
            }
        }
    }
}

module array(x){
    dimension = ceil(sqrt(x));
    for(i = [0:dimension - 1]){
        for(j = [0:dimension - 1]){
            if(dimension * i + j < x){
                translate([i * spacing, j * spacing, 0]){
                    cone();
                }
            }
        }
    }
}

array($amount);
```


[User]
Hey there, I'm looking to design a customizable herringbone planetary gear bearing and I need some help creating the OpenSCAD files for it. I've seen some cool designs online, and I've got a pretty clear idea of what I want, but I need it to be fully parametric, so I can adjust it for different projects.

Here are the key features and parameters I'm thinking of:

*   **General Structure:** It should be a planetary gearset with a central sun gear, multiple planet gears orbiting around it, and an outer ring gear. All gears should be herringbone type. The whole thing should function as a combined radial and thrust bearing, kind of like a pre-assembled 3D printed bearing.

*   **Dimensions:**
    *   Outer Wheel Diameter: The overall diameter of the outer cylinder (outer ring gear).
    *   Ring Gear Diameter: The inner diameter of the outer ring gear (where the teeth are cut out).
    *   Thickness: The total thickness of the bearing.
    *   Clearance: A small separation between the teeth of the gears.
    *  Pressure Angle: The involute gear teeth pressure angle of obliquity.

*   **Gears:**
    *   Number of Planets: The number of planet gears.
    *   Planet Teeth Count: Number of teeth on each planet gear.
    *   Sun Tooth Count: Number of teeth on the central sun gear (should be calculated based on planet count and planet teeth count to fit correctly).
    *   Ring Gear Teeth Count:  Number of teeth on the ring gear (also calculated based on the other tooth counts).
    *   TeethToTwistAcross:  The number of teeth each gear tooth will cross helically for the herringbone feature.

*   **Infill:**
    *   Honeycomb Infill: I'd like a honeycomb infill pattern inside each gear to save material.
    *   Infill Hole Size: The size of the individual honeycomb holes.
    *   Infill Strength:  A parameter to control the honeycomb wall thickness, and thus the infill strength (expressed as a percentage)
    *   Infill Border Size: A parameter for the outer edge wall thickness of the honeycomb.

*   **Precision:**
    *   A parameter to control the precision of the gear teeth, which would affect the number of vertices in the involute curves and the number of slices in the extrusion.

*   **Center Hole:**
    *   Center HEX Hole Width:  A hex-shaped hole in the center of the sun gear. I may not always need this, so I should be able to set it to zero if not desired.

*   **Keychain Tab:**
    *   A boolean parameter to add a keychain tab onto the outside of the bearing.
	*  KeychainThickness: The thickness of the keychain tab.

*   **Parametric:** All of these parameters should be easily adjustable via OpenSCAD's customizer.

I'm expecting the design will need the use of a few helper modules to create the gears, including involute gear generation and herringbone shaping.

For libraries, I think I need to use the following for the math/gear generation functions: `involute`, `involute_intersect_angle` .

I think that covers all the requirements. Let me know if you need any other info. Looking forward to seeing the design!

[Assistant]
HerringbonePlanetaryGearBearing_HoneyComb.scad:
```
// Herringbone Planetary gear bearing (customizable)

echo("------------------------ BEGIN ------------------------");

// (Diameter of the outer cylinder)
OuterWheelDiameter  = 65;
// (Ring gear cut out diameter from the outer wheel)
RingGearDiameter   	= 60;
Thickness           = 18;
// (separation between the gear teeth)
Clearance           = 0.4;
Planets             = 5;
PlanetTeethCount    = 8;
SunToothCountEstimate  = 10;
// (The involute gear teeth pressure angle of obliquity)
PressureAngle       = 45;
// (The # of teeth each gear tooth will cross helically)
TeethToTwistAcross  = 0.9;
// (0=NoFill; The size of the HoneyComb holes )
Infill_HoleSize     = 2;
// (Changes Honeycomb wall thickness)
Infill_Strength		= 33;
// (The outer edge wall thickness of the HoneyComb)
Infill_BorderSize	= 1;
// (Effects # of vertices via involute tooth steps & # of slices per gear extrude)
Precision			= 11;
// (0=NoHole; The HEX hole width in the sun gear)
CenterHEXHoleWidth  = 6.7;
// (Add a Keychain holder on the outside)
Keychain = "no"; // [yes, no]
// The thickness of the KeyChainHole
KeychainThickness = 5;

// PRECALCULATIONS --------------------------------------------------------
InFill_HoleStep = (Infill_HoleSize*3.5) + (((Infill_Strength/100)*(Infill_HoleSize*4)));
MaxTeethDepthRatio = 0.5*1;
PiExact = 1*3.141592653589793238462643383279502884197169399375105820974944592307816406286;
PlanetCount = round(Planets);
PlanetToothCount = round(PlanetTeethCount);
PlanetToothCount_Step1 = round(2/PlanetCount*(SunToothCountEstimate+PlanetToothCount));
PlanetToothCount_Step2 = PlanetToothCount_Step1*PlanetCount%2!=0 ? PlanetToothCount_Step1+1 : PlanetToothCount_Step1;
SunToothCount = PlanetToothCount_Step2*PlanetCount/2-PlanetToothCount;
RingToothCount=SunToothCount+2*PlanetToothCount;
pitchD=0.9*RingGearDiameter/(1+min(PiExact/(2*RingToothCount*tan(PressureAngle)),PiExact*MaxTeethDepthRatio/RingToothCount));
Pitch=pitchD*PiExact/RingToothCount;
helix_angle=atan(2*TeethToTwistAcross*Pitch/Thickness);
phi = $t * 360 / PlanetCount;
PlanetOffset = pitchD/2*(SunToothCount+PlanetToothCount)/RingToothCount;
PlanetRotationMultiplier = SunToothCount/PlanetCount*360/PlanetToothCount-phi*(SunToothCount+PlanetToothCount)/PlanetToothCount-phi;

// USER INFO --------------------------------------------------------------
echo("Planets",Planets);

echo("SunToothCount",SunToothCount);
echo("PlanetToothCount",PlanetTeethCount);
echo("RingToothCount", RingToothCount);

echo("PlanetOffset",PlanetOffset);

echo("RingGearDiameter",RingGearDiameter);
echo("Thickness",Thickness);
echo("Clearance",Clearance);

echo("TeethToTwistAcross",TeethToTwistAcross);
echo("helix_angle=",helix_angle);
echo("PressureAngle",PressureAngle);
echo("Pitch",Pitch);

echo("CenterHEXHoleWidth",CenterHEXHoleWidth);

// PRIMARY BUILD ----------------------------------------------------------
translate([0,0,Thickness/2]){
    // OUTER RING GEAR
	difference(){
        //cylinder(r=OuterWheelDiameter/2,h=Thickness,center=true,$fn=(Precision*10));

		union()
			{
				pitch_radius 		= RingToothCount*Pitch/(2*PiExact);
				depth 				= Pitch/(2*tan(PressureAngle));
				outer_radius 		= Clearance<0 ? pitch_radius+depth/2-Clearance : pitch_radius+depth/2;

				//RingGearDiameter/2
				cylinder(r=outer_radius+Infill_BorderSize+0.5,h=Thickness,center=true,$fn=(Precision*10));
				Infill_Cylinder(IRadius=OuterWheelDiameter/2,IHeight=Thickness,IPrecision=Precision,
								IHoleSize=Infill_HoleSize, IHoleStep=InFill_HoleStep, IBorderSize=Infill_BorderSize);
			}

		herringbone(RingToothCount,Pitch,PressureAngle,MaxTeethDepthRatio,-Clearance,helix_angle,Thickness+0.2);
	}
    // SUN GEAR
	rotate([0,0,(PlanetToothCount+1)*180/SunToothCount+phi*(SunToothCount+PlanetToothCount)*2/SunToothCount])
	difference(){
		mirror([0,1,0])
			herringbone_adv(SunToothCount,Pitch,PressureAngle,MaxTeethDepthRatio,Clearance,helix_angle,Thickness,
							Infill_HoleSize, Infill_Strength, Infill_BorderSize, CenterHEXHoleWidth);
	}
    // PLANET GEARS
	for(i=[1:PlanetCount])
     rotate([0,0,i*360/PlanetCount+phi])
      translate([PlanetOffset,0,0])
       rotate([0,0,i*PlanetRotationMultiplier])
		herringbone_adv(PlanetToothCount,Pitch,PressureAngle,MaxTeethDepthRatio,Clearance,helix_angle,Thickness,
						Infill_HoleSize, Infill_Strength, Infill_BorderSize, 0);

	// KEYCHAIN TORUS
	if( Keychain == "yes")
	{
		echo("DRAWING KEYHOLE");

		translate([(OuterWheelDiameter/2)+(KeychainThickness*1.5), 0, -(Thickness/2)+(KeychainThickness/2)])
			CreateKeyChainTab(KeychainThickness);
	}
}

module CreateKeyChainTab(KeychainHoleThickness = 5)
{
	difference()
	{
		union()
		{
			// Base
			translate([-(KeychainHoleThickness/2),0, 0])
				cube([KeychainHoleThickness*3,KeychainHoleThickness*2,KeychainHoleThickness], center = true);

			// Endcap
			translate([KeychainHoleThickness,0, 0])
			rotate([90,0,0])
				cylinder(d = KeychainHoleThickness, h=(KeychainHoleThickness*2), center = true, $fn=(Precision*10));

			// Side1
			translate([-(KeychainHoleThickness/2),KeychainHoleThickness, 0])
			rotate([0,90,0])
				cylinder(d = KeychainHoleThickness, h=(KeychainHoleThickness*3), center = true, $fn=(Precision*10));

			// Side2
			translate([-(KeychainHoleThickness/2),-(KeychainHoleThickness), 0])
			rotate([0,90,0])
				cylinder(d = KeychainHoleThickness, h=(KeychainHoleThickness*3), center = true, $fn=(Precision*10));

			// Corner1
			translate([(KeychainHoleThickness),(KeychainHoleThickness), 0])
				sphere(d = KeychainHoleThickness, $fn=(Precision*10));

			// Corner2
			translate([(KeychainHoleThickness),-(KeychainHoleThickness), 0])
				sphere(d = KeychainHoleThickness, $fn=(Precision*10));
		}

		color("Red")
		translate([0,0, -(KeychainHoleThickness)])
			cylinder(r = KeychainHoleThickness/1.75, h=(KeychainHoleThickness*2), $fn=(Precision*10));
	}
}

module Infill_Cylinder(IRadius=10,IHeight=10,IPrecision=10, IHoleSize=3.5, IHoleStep=10, IBorderSize=3 )
{
	union()
	{
		difference()
		{
			cylinder(r=IRadius,h=IHeight,center=true,$fn=(IPrecision*10));

			Infill_Cylinder_Pattern(IC_Radius=IRadius, IC_Height=IHeight+1, IC_Precision=IPrecision, HoleSize=IHoleSize, HoleStep=IHoleStep);
		}

		difference()
		{
			// Hole border
			cylinder(r=IRadius,h=IHeight,center=true,$fn=(IPrecision*10));
			// Hole
			cylinder(r=IRadius-IBorderSize,h=IHeight+1,center=true,$fn=(IPrecision*10));
		}
	}
}

module herringbone_adv( number_of_teeth=15, circular_pitch=10, pressure_angle=28, depth_ratio=1, GearClearance=0, helix_angle=0, gear_GearThickness=5,
						Infill_HoleSize, Infill_Strength, Infill_BorderSize, CenterHEXHoleWidth)
{
	union()
		{
			difference()
			{
				// herringbone gear
				herringbone(number_of_teeth,circular_pitch,pressure_angle,depth_ratio,GearClearance,helix_angle,gear_GearThickness);

				// center hole (HEX)
				cylinder(r=CenterHEXHoleWidth/sqrt(3),h=gear_GearThickness+1,center=true,$fn=6);

				 pitch_radius 	= number_of_teeth*circular_pitch/(2*PiExact);
				 base_radius 	= pitch_radius*cos(pressure_angle);
				 depth 			= circular_pitch/(2*tan(pressure_angle));
				 root_radius1 	= pitch_radius-depth/2-GearClearance/2;
				 root_radius 	= (GearClearance<0 && root_radius1<base_radius) ? base_radius : root_radius1;
				 min_radius 	= max (base_radius,root_radius);

				// InFill Honeycomb
				Infill_Cylinder_Pattern(IC_Radius=  min_radius-Infill_BorderSize, IC_Height=gear_GearThickness+2, IC_Precision=Precision,
								HoleSize=Infill_HoleSize, HoleStep=InFill_HoleStep);
			}

			// center hole (HEX)
			if(CenterHEXHoleWidth > 0)
			{
				difference()
				{
					// Hole border
					cylinder(r=CenterHEXHoleWidth/sqrt(3)+Infill_BorderSize,h=gear_GearThickness,center=true,$fn=(Precision*10));//6);
					// Hole
					cylinder(r=CenterHEXHoleWidth/sqrt(3),h=gear_GearThickness+1,center=true,$fn=6);
				}
			}
		}
}

module Infill_Cylinder_Pattern( IC_Radius=10, IC_Height=10, IC_Precision=10, HoleSize=3, HoleStep=3 )
{
    if(HoleSize>0)
	{

	// https://en.wikipedia.org/wiki/Circle_packing#Packings_in_the_plane
	// For further examination try:  https://en.wikipedia.org/wiki/Hexagonal_lattice
	HoneyCombRatio = PiExact/(2*sqrt(3));

	intersection()
	{
		cylinder(r=IC_Radius, h=IC_Height, center=true, $fn=(IC_Precision*10));

		//HONEYCOMB EXTRUSION PATTERN
		union()
		{
			StartPosition = (IC_Radius+HoleStep);
			XStep = (HoleStep*HoneyCombRatio);
			YStep = (HoleStep*0.5);
			XOffset = StartPosition - (floor(StartPosition / XStep)*XStep);
			YOffset = StartPosition - (floor(StartPosition / YStep)*YStep);

			for(x=[-StartPosition+XOffset:XStep:IC_Radius+HoleStep])
			{
				for(y=[-StartPosition+YOffset:YStep:IC_Radius+HoleStep])
				{
					translate([x,y,0])
						cylinder(r=HoleSize, h=IC_Height+2, center=true, $fn=6);

					translate([x+(HoleStep*(0.5*HoneyCombRatio)),y+(HoleStep*0.75),0])
						cylinder(r=HoleSize, h=IC_Height+2, center=true, $fn=6);
				}
			}
		}
	}
	}
}

// MODULES & FUNCTIONS ----------------------------------------------------
module herringbone( number_of_teeth=15, circular_pitch=10, pressure_angle=28, depth_ratio=1, clearance=0, helix_angle=0, gear_thickness=5)
{
	union()
	{
		gear(number_of_teeth, circular_pitch, pressure_angle, depth_ratio, clearance, helix_angle, gear_thickness/2);
		mirror([0,0,1])
			gear(number_of_teeth, circular_pitch, pressure_angle, depth_ratio, clearance, helix_angle, gear_thickness/2);
	}
}

module gear( number_of_teeth=15, circular_pitch=10, pressure_angle=28, depth_ratio=1, clearance=0, helix_angle=0, gear_thickness=5, flat=false)
{
	pitch_radius = number_of_teeth*circular_pitch/(2*PiExact);
	twist=tan(helix_angle)*gear_thickness/pitch_radius*180/PiExact;

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

module flat_extrude(h,twist,flat)
{
	if(flat==false)
		linear_extrude(height=h,twist=twist,slices=Precision)
            children(0);
	else
		children(0);
}

module gear2D( number_of_teeth, circular_pitch, pressure_angle, depth_ratio, clearance)
{
	pitch_radius 		= number_of_teeth*circular_pitch/(2*PiExact);
	base_radius 		= pitch_radius*cos(pressure_angle);
	depth 				= circular_pitch/(2*tan(pressure_angle));
	outer_radius 		= clearance<0 ? pitch_radius+depth/2-clearance : pitch_radius+depth/2;
	root_radius1 		= pitch_radius-depth/2-clearance/2;
	root_radius 		= (clearance<0 && root_radius1<base_radius) ? base_radius : root_radius1;
	backlash_angle 		= clearance/(pitch_radius*cos(pressure_angle)) * 180 / PiExact;
	half_thick_angle	= 90/number_of_teeth - backlash_angle/2;
	pitch_point 		= involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
	pitch_angle 		= atan2 (pitch_point[1], pitch_point[0]);
	min_radius 			= max (base_radius,root_radius);

	intersection()
	{
		rotate(90/number_of_teeth)
			circle($fn=number_of_teeth*3,r=pitch_radius+depth_ratio*circular_pitch/2-clearance/2);
		union()
		{
			rotate(90/number_of_teeth)
				circle($fn=number_of_teeth*2, r=max(root_radius,pitch_radius-depth_ratio*circular_pitch/2-clearance/2));

			for (i = [1:number_of_teeth])rotate(i*360/number_of_teeth)
			{
				halftooth( pitch_angle, base_radius, min_radius, outer_radius, half_thick_angle);
				mirror([0,1])
					halftooth ( pitch_angle, base_radius, min_radius, outer_radius, half_thick_angle);
			}
		}
	}
}

module halftooth( pitch_angle, base_radius, min_radius, outer_radius, half_thick_angle)
{
	index = [ for (i = [0 : 1 : Precision]) i ];

	start_angle = max(involute_intersect_angle (base_radius, min_radius)-5,0);
	stop_angle = involute_intersect_angle (base_radius, outer_radius);
	angle = index*(stop_angle-start_angle)/index[len(index)-1];

	p = concat([[0,0]],[for (a = [ 0 : len(angle) - 1 ]) involute(base_radius,angle[a]+start_angle) ]);

	difference(){
		rotate(-pitch_angle-half_thick_angle)polygon(points=p);
		square(2*outer_radius);
	}
}

// MATH FUNCTIONS -----------------------------------------------------
// Find the angle of the involute about the base radius at the given distance (radius) from it's center.
// source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html
function involute_intersect_angle(base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / PiExact;

// Calculate the involute position for a given base radius and involute angle.
function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*PiExact/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*PiExact/180*cos (involute_angle))
];

echo("------------------------- END -------------------------");

```


[User]
I'm trying to generate a 3D printable shape that's kind of a twisted column, and I want to be able to control a bunch of parameters to fine-tune it.

Specifically, I want a shape built by stacking layers of extruded polygons. Each layer should be a circle with a certain number of points, so imagine a regular polygon with `edges` number of sides. As we go up in layers, the rotation of each layer around the Z-axis should be controlled by a polynomial function defined by `rot(x) = $rot3 * x * x * x + $rot2 * x * x + $rot1 * x + $rot0`, where `x` is the current layer divided by the total number of layers. The total amount of rotation will also be controlled by a parameter called `endRotation`, so that at layer `x = 1`, the shape is rotated by `endRotation` degrees. Each layer is extruded upwards with thickness of `layerHeight`.

Additionally, I want to be able to perturb the shape of the polygons in each layer.  So, I'd like to introduce a parameter called `diff`, which should also be a polynomial function: `diff(x) = $diff3 * x * x * x + $diff2 * x * x + $diff1 * x + $diff0`, where again `x` is the current layer divided by the total number of layers. This `diff(x)` value will be added to the indices of the polygon points, which changes the geometry in a twisting pattern. I also want to control which edges get these perturbations -  A parameter called `modulo` controls this, such that only every `modulo` edge is perturbed.

So, the parameters I want to control are:

*   `height`: Total height of the shape
*   `radius`: The radius of the base circle
*   `layerHeight`: The height of each layer
*   `edges`: The number of sides in the polygon
*   `modulo`: Controls which edges are perturbed
*   `endRotation`: Total rotation of the shape at the top.
*   `$rot3`, `$rot2`, `$rot1`, `$rot0`: Coefficients for the rotation polynomial.
*   `$diff3`, `$diff2`, `$diff1`, `$diff0`: Coefficients for the difference polynomial.

Could you generate the OpenSCAD file for me?

[Assistant]
Shape.scad:
```
$fn = 3;

height = 70;
radius = 20;
layerHeight = 0.1;
layers = floor(height / layerHeight);
edges = 6;
modulo = 1;
endRotation = 135;

$rot3 = 0.5;
$rot2 = -0.5;
$rot1 = 0;
$rot0 = 0;

$diff3 = 0;
$diff2 = 0;
$diff1 = 1;
$diff0 = 0;

function diff(x) = $diff3 * x * x * x + $diff2 * x * x + $diff1 * x + $diff0; //2 * ( x - 1 / 2) * ( x - 1 / 2); //0.5 * (1 + 0.5 * cos(360 * (x - 1)));
function rot(x) = $rot3 * x * x * x + $rot2 * x * x + $rot1 * x + $rot0; //exp(ln(x) * 2);

module shape(){
    union(){
        for(i = [1:layers]){
            translate([0,0,(i - 1) * layerHeight]){
                rotate([0,0,rot(i / layers) * endRotation]){
                    for(j = [1:edges]){
                        if(j%modulo == 0){
                            linear_extrude(height = layerHeight){
                                polygon(points  =   [   [0, 0],
                                                        [radius * sin(j / edges * 360), radius * cos(j / edges * 360)],
                                                        [radius * sin((j + diff(i / layers))/ edges * 360), radius * cos((j + diff(i / layers)) / edges * 360)]
                                                    ],
                                        paths   =   [   [0, 1, 2]   ]);
                                polygon(points  =   [   [0, 0],
                                                        [radius * sin((j + diff(i / layers))/ edges * 360), radius * cos((j + diff(i / layers)) / edges * 360)],
                                                        [radius * sin((j + 2) / edges * 360), radius * cos((j + 2) / edges * 360)],
                                                    ],
                                        paths   =   [   [0, 1, 2]   ]);
                            }
                        }
                        else if((j - 1)%modulo != 0){
                            linear_extrude(height = layerHeight){
                                polygon(points  =   [   [0, 0],
                                                        [radius * sin(j / edges * 360), radius * cos(j / edges * 360)],
                                                        [radius * sin((j + 1) / edges * 360), radius * cos((j + 1) / edges * 360)]
                                                    ],
                                        paths   =   [   [0, 1, 2]   ]);
                            }
                        }
                    }
                }
            }
        }
    }
}

shape();
```


[User]
Hi! I'm looking to create a set of customizable, nature-inspired castles in OpenSCAD. I've been playing around with some designs, but I'd like to generate something more parametric and flexible. I'm hoping you can help me with the code for these.

My vision is for a series of small "Pixie Castles" that aren't really meant to be realistic castles, but rather artistic interpretations using patterns found in nature and mathematical models. I've got a few different variations in mind, which should all be controlled by parameters that users can adjust.

Here are the core parameters I'd like to include:

*   **CastleHeight:** This will be the overall approximate height of the castle in millimeters. I'd like to set a reasonable range for this, like 30mm to 150mm.
*   **CastleType:** I want to be able to switch between "SandMold" and "Lantern" versions. The SandMold would be a solid shape, while the Lantern should be hollow with a space inside (if using transparent filament, a tea light could be placed inside). This is something that will influence the object construction.
*   **CastleShape:** This will define the basic geometric shape of the castle. I'm interested in these options: "Solitary" (a simple cylinder/cone), "Outpost" (a cylinder/cone with a single entrance), "Triangle", "Quadrilateral", "Pentagon", "Hexagon", "Tee" (three entrances), "Cross" (four entrances), and "Line" (two entrances opposite each other).
*   **CastleVariation:** This will determine the kind of pattern or design on the main body of the castle, and I want to include "PixieEye" (a hexagon pattern), "PixieFlower" (based on a Fibonacci pattern), "PixieShell" (using a nautilus shell model), "PixieIce" (using a Koch curve), and "PixieWall" (a simple wall segment that can be combined with the castles).
*   **OnlyPixieFlower:** This will only be used when "CastleVariation" is "PixieFlower", and it should control the angle of the Fibonacci pattern (e.g., 137.5, with a range from 135.0 to 140).

I'd like the code to be set up in a way that the dimensions of various elements, such as the door width, door height, walkway, etc., will all be scaled relative to the *CastleHeight* parameter.

For the "PixieWall" variation, I need it to be a simple wall section, and the height parameter should also match the castles, so they fit together well when printed at the same *CastleHeight*. The "SandMold" and "Lantern" options will also apply to the wall, determining whether it's a solid piece or has a hollowed-out interior. The wall itself should have some simple detailing, like an entrance with a small walkway.

Additionally, it would be great if the castles (and maybe the wall) could have a small stamp on the top to indicate the *CastleShape* and angle (e.g. 60° for Triangle, 90° for Quadrilateral, 108° for Pentagon, and 120° for Hexagon).

I think that covers all the main features. Can you help me generate the OpenSCAD code for this design? I'm not really using any external libraries here so I don't think I'll need to specify any for you.

[Assistant]
PixieCastleV7.scad:
```
$fn=64*1;

//CUSTOMIZER VARIABLES

//Set the approximate height of you castle in mm :
CastleHeight = 65;	//	[30:150]

//Choose sand mold or lantern. (If you print as Lantern with transparent filament and a height above 38mm, you can fit a LED tea light inside.)
CastleType = "SandMold";//[SandMold,Lantern]

//Choose the shape of your castle.
CastleShape = "Quadrilateral";//[Solitary,Outpost,Triangle,Quadrilateral,Pentagon,Hexagon,Tee,Cross,Line]

//Choose the type of your Pixie Castle, or Pixie Wall element. (The wall element should be printed with the same height setting as the Castle to make them fit together, eg. both at 65mm.)
CastleVariation = "PixieEye";//[PixieEye,PixieFlower,PixieShell,PixieIce,PixieWall]

// This setting only affects the Pixie Flower Castle. It specifies the angle of the Fibonacci pattern, see text.
OnlyPixieFlower = 137.5;//[ 135.0 , 135.5 , 136.0 , 136.5 , 137.0 , 137.5 , 138.0 , 138.5 , 139.0 , 139.5 , 140]

//CUSTOMIZER VARIABLES END

PrintThickness = 1.5*1;//mm
CastleBase   = CastleHeight/1.6;
CastleTop    = CastleHeight/1.8;
DoorWidth    = CastleHeight*0.6;
DoorHeight   = CastleHeight*0.7;
DoorDepth    = CastleHeight*0.17;
WalkWay      = CastleHeight*0.22;
WalkWayDepth = CastleHeight*0.15;
WallLength   = (CastleTop*0.9+DoorDepth)*2;

if(CastleVariation!="PixieWall"){
    if(CastleType == "SandMold"){
        difference(){
            NegativeEye();
            union(){
                PositiveEye();
                anglestamp();
           }
       }

    }else{
        difference(){
            PositiveEye();
            insidelantern();
        }
    }
}

if(CastleVariation == "PixieWall"){

    if(CastleType == "SandMold"){
        difference(){
            basewall(true);
            PositiveWall();
        }
    }else{
        difference(){
           PositiveWall();
           InsideWall();
        }
    }

}

module insidelantern(){
   translate([0,0,-0.1]){
    sph = CastleHeight*0.7;
   /* translate([0,0,-0.1]){
        difference(){
            cylinder(r1=CastleBase*0.88, r2=CastleTop*0.88, h=CastleHeight);
            translate([-50,-50,CastleHeight*0.7]){cube([100,100,100]);}
        }
    }*/
    intersection(){
        cylinder(r1=CastleBase*0.88, r2=CastleTop*0.88, h=CastleHeight);
        translate([0,0,-sph+CastleHeight*0.8]){
            sphere(r=sph);
        }
    }
    }
}

module InsideWall(){
    difference(){
        intersection(){
            translate([PrintThickness,PrintThickness,-0.1]){
                cube([  WallLength-PrintThickness*2,
                    DoorWidth-PrintThickness*2,
                    DoorHeight-WalkWayDepth-PrintThickness]);
                }
                //
                ra = CastleHeight/2;
                rotate([0,90,0]){
                translate([-DoorHeight+WalkWayDepth+ra+PrintThickness,DoorWidth/2,0]){
                    cylinder(r=ra,h=WallLength+0.2);
                }
        }

                }

            union(){

                translate([-0.1,-20+PrintThickness,0]){
                    rotate([-3,0,0]){
                       cube([WallLength+0.2,20,CastleHeight]);
                    }
                }
                translate([-0.1,DoorWidth-PrintThickness,0]){
                    rotate([+3,0,0]){
                       cube([WallLength+0.2,20,CastleHeight]);
                    }
                }
           }

        }

}

module PositiveWall(){
    hole = CastleHeight/10;
    wwa = CastleHeight*0.02;//walkwayslope
    difference(){
        basewall(false);

        union(){

            if(CastleType == "SandMold"){

                rotate([0,2,0]){
                    translate([-20,0,0]){
                        cube([20,DoorWidth,DoorHeight*1.2]);
                    }
                }
                translate([WallLength,0,0]){
                        rotate([0,-2,0]){
                        cube([20,DoorWidth,DoorHeight*1.2]);
                    }
               }
            }

            translate([-0.1,DoorWidth/2,DoorHeight-WalkWayDepth+0.1]){
                rotate([90,0,90]){
                    linear_extrude(height=WallLength+0.2){
                        polygon(points=[ [-WalkWay/2,0],
                        [-WalkWay/2-wwa,WalkWayDepth],
                        [WalkWay/2+wwa,WalkWayDepth],
                        [WalkWay/2,0]  ]);
                    }
                }
            }
            sp = WallLength/4;
            rotate([-90,0,0]){
                translate([0,-DoorHeight,-0.1]){
                    cylinder(r=hole,h=DoorWidth+0.2);
                }
                translate([sp,-DoorHeight,-0.1]){
                    cylinder(r=hole,h=DoorWidth+0.2);
                }
                translate([sp*2,-DoorHeight,-0.1]){
                    cylinder(r=hole,h=DoorWidth+0.2);
                }
                translate([sp*3,-DoorHeight,-0.1]){
                    cylinder(r=hole,h=DoorWidth+0.2);
                }
                translate([sp*4,-DoorHeight,-0.1]){
                    cylinder(r=hole,h=DoorWidth+0.2);
                }

            }
            translate([-0.1,-20,0]){
                rotate([-3,0,0]){
                   cube([WallLength+0.2,20,CastleHeight]);
                }
            }
            translate([-0.1,DoorWidth,0]){
                rotate([+3,0,0]){
                    cube([WallLength+0.2,20,CastleHeight]);
                }
            }
        }
    }
}

module basewall(extend){
    if(extend){
        translate([-PrintThickness,-PrintThickness,0.1]){
            cube([WallLength+PrintThickness*2,DoorWidth+PrintThickness*2,DoorHeight+PrintThickness]);
        }
    }else{
        cube([WallLength,DoorWidth,DoorHeight]);
    }
}

module anglestamp(){
    if(CastleShape == "Triangle"){
        translate([0,0,CastleHeight+PrintThickness]){
            rotate([90,0,45+150]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([90,0,45+90]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([0,0,+45]){
                translate([CastleHeight/8,CastleHeight/15,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("60°", size=CastleHeight/8,center=false);
                   }
                }
                translate([0,-CastleHeight/6,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("Triangle", size=CastleHeight/9,center=false);
                   }
                }
            }
        }
    }

    if(CastleShape == "Quadrilateral"){
        translate([0,0,CastleHeight+PrintThickness]){
            rotate([90,0,45+180]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([90,0,45+90]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([0,0,+45]){
                translate([CastleHeight/8,CastleHeight/15,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("90°", size=CastleHeight/8,center=false);
                   }
                }
                translate([-CastleHeight/5,-CastleHeight/6,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("Quadrilateral", size=CastleHeight/9,center=false);
                   }
                }
            }
        }
    }

    if(CastleShape == "Pentagon"){
        translate([0,0,CastleHeight+PrintThickness]){
            rotate([90,0,45+198]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([90,0,45+90]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([0,0,+45]){
                translate([CastleHeight/8,CastleHeight/15,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("108°", size=CastleHeight/8,center=false);
                   }
                }
                translate([0,-CastleHeight/6,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("Pentagon", size=CastleHeight/9,center=false);
                   }
                }
            }

        }
    }

    if(CastleShape == "Hexagon"){
        translate([0,0,CastleHeight+PrintThickness]){
            rotate([90,0,45+210]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([90,0,45+90]){
                cylinder(r=0.6,h=CastleHeight);
            }
            rotate([0,0,+45]){
                translate([CastleHeight/8,CastleHeight/15,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("120°", size=CastleHeight/8,center=false);
                   }
                }
                translate([0,-CastleHeight/6,-0.6]){
                   linear_extrude(height = 1.2) {
                       text("Hexagon", size=CastleHeight/9,center=false);
                   }
                }
            }
        }
    }

}

module NegativeEye(){
    translate([0,0,0.1]){
        basecone(true);
        if(CastleShape=="Outpost"){
            basedoor(0,true);
        }
        if(CastleShape=="Triangle"){
            basedoor(0,true);
            basedoor(60,true);
        }
        if(CastleShape=="Quadrilateral"){
            basedoor(0,true);
            basedoor(90,true);
        }
        if(CastleShape=="Pentagon"){
            basedoor(0,true);
            basedoor(108,true);
        }
        if(CastleShape=="Hexagon"){
            basedoor(0,true);
            basedoor(120,true);
        }
        if(CastleShape=="Tee"){
            basedoor(0,true);
            basedoor(90,true);
            basedoor(180,true);
        }
        if(CastleShape=="Cross"){
            basedoor(0,true);
            basedoor(90,true);
            basedoor(-90,true);
            basedoor(180,true);
        }
        if(CastleShape=="Line"){
            basedoor(0,true);
            basedoor(180,true);
        }
    }
}

/*
module PositiveFlower(){
    baseA();
    intersection(){
        basecone(false);
        translate([0,0,CastleHeight*0.8-0.1]){
            fibonacci();
        }
    }
 }
*/

module PositiveEye(){
    baseA();
    intersection(){
        basecone(false);
        translate([0,0,CastleHeight*0.8-0.1]){

            if(CastleVariation == "PixieEye"){hexagonpattern();}
            if(CastleVariation == "PixieFlower"){fibonacci();};
            if(CastleVariation == "PixieShell"){nautilus();};
            if(CastleVariation == "PixieIce"){koch();};
        }
    }
    if(CastleShape=="Outpost"){
            basedoor(0,false);
        }
        if(CastleShape=="Triangle"){
            basedoor(0,false);
            basedoor(60,false);
        }
        if(CastleShape=="Quadrilateral"){
            basedoor(0,false);
            basedoor(90,false);
        }
        if(CastleShape=="Pentagon"){
            basedoor(0,false);
            basedoor(108,false);
        }
        if(CastleShape=="Hexagon"){
            basedoor(0,false);
            basedoor(120,false);
        }
        if(CastleShape=="Tee"){
            basedoor(0,false);
            basedoor(90,false);
            basedoor(180,false);
        }
        if(CastleShape=="Cross"){
            basedoor(0,false);
            basedoor(90,false);
            basedoor(-90,false);
            basedoor(180,false);
        }
        if(CastleShape=="Line"){
            basedoor(0,false);
            basedoor(180,false);
        }
}

module basecone(extend){
    if(extend){
        cylinder(r1=CastleBase+PrintThickness,r2=CastleTop+PrintThickness,h=CastleHeight+PrintThickness);
     }else{
        cylinder(r1=CastleBase,r2=CastleTop,h=CastleHeight);
    }
}

module basedoor(angle,extend){
    if(extend){
        rotate([0,0,45+angle]){
            translate([CastleTop*0.9-PrintThickness,-DoorWidth/2-PrintThickness,0]){
                cube([
                    DoorDepth+PrintThickness*2,
                    DoorWidth+PrintThickness*2,
                    CastleHeight+PrintThickness]);
            }
        }
    }else{
        difference(){
            rotate([0,0,45+angle]){
                translate([CastleTop*0.9,-DoorWidth/2,0]){
                    cube([DoorDepth,DoorWidth,DoorHeight]);
                }
            }

            rotate([0,0,45+angle]){
                wwa = CastleHeight*0.02;//walkwayslope
                translate([0,0,DoorHeight-WalkWayDepth+0.1]){
                    rotate([90,0,90]){
                        linear_extrude(height=WallLength+0.2){
                            polygon(points=[ [-WalkWay/2,0],
                            [-WalkWay/2-wwa,WalkWayDepth],
                            [WalkWay/2+wwa,WalkWayDepth],
                            [WalkWay/2,0]  ]);
                        }
                    }
                }

                translate([0,DoorWidth/2,0]){
                    rotate([3,0,0]){
                        cube([CastleTop*2,20,DoorHeight*1.2]);
                    }
                }
                translate([0,-DoorWidth/2-20,0]){
                    rotate([-3,0,0]){
                        cube([CastleTop*2,20,DoorHeight*1.2]);
                    }
                }

                sp = WallLength/6;
                hole = CastleHeight/10;
                rotate([-90,0,0]){
                translate([CastleTop*0.9+DoorDepth,-DoorHeight,-DoorWidth/2]){
                    cylinder(r=hole,h=DoorWidth+0.2);
                }
            }

                if(CastleType == "SandMold"){
                    translate([CastleTop*0.9+DoorDepth,-DoorWidth/2,0]){
                        rotate([0,-2,0]){
                            cube([DoorDepth,DoorWidth,DoorHeight*1.2]);
                        }
                    }
                }

            }
        }
    }
}

module nautilus(){
    sc = CastleTop/11.4;
    scale([sc,sc,sc]){

        intersection(){
            cylinder(r=12,h=10);
            translate([-1.4,1.8,0]){ // højre,op,
                a=0.9;
                b=0.2;
                for(theta=[180:20:780]){
                    t = (theta/360)*2*3.14;
                    d = a*exp(b*t);
                    rotate([0,0,theta]){
                        translate([d,0,0]){
                            translate([0,0,-t/6]){
                                sphere(r=t/2,$fa=10);
                            }
                        }
                    }
                }
            }
        }
    }
}

/*module nautilus(){
    translate([0,0,0]){
    a=CastleHeight*0.024;
    b=CastleHeight*0.004;
    for(theta=[0:20:360*2.5]){
        t = (theta/360)*2*3.14;
        d = a*exp(b*t);
        rotate([0,0,theta]){
            translate([d,0,0]){
                sphere(r=(t/2)*(CastleHeight/50));
            }
        }
    }
}
}*/

module fibonacci(){
    c = CastleHeight/10;
    br = CastleHeight/7.3;
    hh = CastleHeight*0.2;

    for(a=[0:40]){ //40

        theta = a*OnlyPixieFlower;//137.5
        d = c*sqrt(a);

        rotate([0,0,theta]){
            translate([d,0,0]){
                //sphere(r=br,center=true);
                cylinder(r1=br,r2=0.0,h=hh);
                //cylinder(r1=2,r2=1,h=1);
            }
        }
    }
}

module hexagonpattern(){
        difference(){
            hexagonpillars();
            translate([-100,-100,-50]){cube([200,200,50]);}
        }

    }

module hexagonpillars(){
    r = CastleHeight/6;
    h = CastleHeight/8;

    hexagon(0,0,         0.2*h,r);
    hexagon(0, r*1.72,    1.1*h,r);
    hexagon(0, r*1.72*2,  0.6*h,r);
    hexagon(0,-r*1.72,   1.2*h,r);
    hexagon(0,-r*1.72*2, 0.4*h,r);

    hexagon(r*1.48,r*0.86,    0.6*h,r);
    hexagon(r*1.48,r*0.86*3,  3*h,r);//!
    hexagon(r*1.48,-r*0.86,   0.2*h,r);
    hexagon(r*1.48,-r*0.86*3, 3*h,r);//!

    hexagon(-r*1.48,r*0.86,    0.8*h,r);
    hexagon(-r*1.48,r*0.86*3,  3*h,r);//!
    hexagon(-r*1.48,-r*0.86,   0.4*h,r);
    hexagon(-r*1.48,-r*0.86*3, 3*h,r);//!

    hexagon(r*2.95,r*1.72,     1.3*h,r);
    hexagon(r*2.95,0,          3*h,r);//!
    hexagon(r*2.95,-r*1.72,    0.4*h,r);

    hexagon(-r*2.95,r*1.72,    1.1*h,r);
    hexagon(-r*2.95,0,         3*h,r);//!;
    hexagon(-r*2.95,-r*1.72,   1.1*h,r);
    }

module baseA(){
    difference(){
        intersection(){
            translate([-100,-100,]){cube([200,200,CastleHeight*0.8]);}
            basecone(false);
        }
        pillars();
        }
    }

module pillars(){
    for(a=[0:30:360]){
        rotate([0,0,a]){
            translate([CastleHeight/1.59,0,-0.1]){
                //cylinder(r=CastleHeight/10,h=CastleHeight+2);
                //cube( [CastleHeight/10, CastleHeight/6, CastleHeight+2]);
                rotate([0,0,30]){
                linear_extrude(height = CastleHeight*2, center = true, convexity = 10, twist = 0){
                    circle(r = CastleHeight/15, $fn=6);
                }
            }
            }
        }
    }
}

module hexagon(x,y,h,radius){
   translate([x,y,0]){
        linear_extrude(height = CastleHeight/10+h, center = true, convexity = 10, twist = 0){
            circle(r = radius, $fn=6);
        }
    }
}

cx = 144.2276;
cy = 137.1114;

module koch(){
    rotate([0,0,-10]){
    resize([CastleTop*2,CastleTop*2,CastleHeight*0.2]){
        linear_extrude(height=20){
            difference(){
                koch2();
                scale([0.6,0.6,1]){ koch1(); }
            }
            scale([0.3,0.3,1]){ koch0(); }
        }
    }
    cylinder(r1=CastleTop*1.05, r2=CastleTop*0.8,  h=CastleHeight/7);
}
}

module koch0(){
    translate([-cx,-cy,0]){
    polygon(points=[
  [100.0000,  100.0000],
  [198.4808,  117.3648],
  [134.2020,  193.9693],
  [100.0000,  100.0000]]);
    }
}

module koch1(){
    translate([-cx,-cy,0]){
    polygon(points=[
  [100.0000,  100.0000],
  [132.8269,  105.7883],
  [155.0287,   75.8555],
  [165.6539,  111.5765],
  [198.4808,  117.3648],
  [177.0545,  142.8996],
  [191.8762,  177.0933],
  [155.6283,  168.4344],
  [134.2020,  193.9693],
  [122.8013,  162.6462],
  [ 85.7779,  158.3853],
  [111.4007,  131.3231],
  [100.0000,  100.0000]]);
}}

module koch2(){
    translate([-cx,-cy,0]){
    polygon(points=[
  [100.0000,  100.0000],
  [110.9423,  101.9294],
  [118.3429,   91.9518],
  [121.8846,  103.8588],
  [132.8269,  105.7883],
  [140.2275,   95.8107],
  [133.9502,   83.4213],
  [147.6281,   85.8331],
  [155.0287,   75.8555],
  [158.5704,   87.7625],
  [172.2483,   90.1743],
  [162.1121,   99.6695],
  [165.6539,  111.5765],
  [176.5962,  113.5060],
  [183.9967,  103.5284],
  [187.5385,  115.4354],
  [198.4808,  117.3648],
  [191.3387,  125.8764],
  [196.2793,  137.2743],
  [184.1966,  134.3880],
  [177.0545,  142.8996],
  [181.9951,  154.2975],
  [195.8633,  155.0559],
  [186.9356,  165.6954],
  [191.8762,  177.0933],
  [179.7936,  174.2070],
  [170.8660,  184.8465],
  [167.7109,  171.3207],
  [155.6283,  168.4344],
  [148.4862,  176.9461],
  [153.4267,  188.3439],
  [141.3441,  185.4577],
  [134.2020,  193.9693],
  [130.4018,  183.5282],
  [118.0606,  182.1079],
  [126.6016,  173.0872],
  [122.8013,  162.6462],
  [110.4602,  161.2259],
  [102.8693,  172.8569],
   [98.1191,  159.8056],
   [85.7779,  158.3853],
   [85.7779,  158.3853],
   [94.3188,  149.3646],
   [89.5686,  136.3133],
  [102.8598,  140.3438],
  [111.4007,  131.3231],
  [107.6004,  120.8821],
   [95.2593,  119.4618],
  [103.8002,  110.4410],
  [100.0000,  100.0000] ]);
  }
  }

```


[User]
Hey, I'm looking to get a parametric hub designed in OpenSCAD, and I found this old file online that's close to what I need, but I think it could be way better and more flexible. It's called "BUM_HUB_6001_hubba_hubba_V1.1.scad", and it basically creates a hub with two cylindrical axles connected by a cone. I'd like to be able to control the radii and heights of both axles, the width and height of a flange on the larger axle, and the distance between the axles (which determines the cone height, minus the flange height).

I definitely want it to be parametric. The specific parameters I need are:

*   **Smaller\_Axle\_Radius**: Radius of the smaller diameter cylinder (the bottom one in the original code, but I don't really care about orientation).
*   **Smaller\_Axle\_Height**: Height of the smaller diameter cylinder.
*   **Smaller\_Axle\_Flat**:  A flat face on the side of the smaller axle - this was used to transition to the cone, but perhaps there's a better way to do this?
*   **Larger\_Axle\_Radius**: Radius of the larger diameter cylinder (the top one in the original code).
*   **Larger\_Axle\_Height**: Height of the larger diameter cylinder.
*   **flange\_width**: Width of the flange on the larger cylinder (extending out radially).
*   **flange\_height**: Height of the flange.
*   **how\_far\_apart\_are\_they**: The total distance between the bases of the two cylinders (including the flange).

I want to be able to choose whether the hub is solid, hollow (for a rod to pass through), or a shell (like the original file).

*   If hollow for a rod, I need a **rod\_radius** parameter.
*   If like a shell, I need a **shell\_thickness** parameter.

Also, the original code used a `build_plate.scad` library, and I think that's a good idea. So please include something similar, ideally with options for different printers/plate sizes like the original had. I don't need the build plate to be an actual part of the design, just a visual guide during the design.

The original code had some weirdness going on with how it created the shell, where the shell thickness didn't stay constant, especially for shallow cones. I would like a constant shell thickness regardless of the cone angle. It would also be great to have a smooth transition between the shell and the cylinder.

I think that covers it.  Let me know if you need any clarification.

[Assistant]
BUM_HUB_6001_hubba_hubba_V1.1.scad:
```
//bummster's hubba hubba file.
//v1 August 15, 2015.
//ask me questions about this file through the thingiverse comments @ http://www.thingiverse.com/thing:969819

//This is how to get the library for the build plate visual.
include <utils/build_plate.scad>

//CUSTOMIZER VARIABLES  <-- this doesn't seem to do a darn thing.
//  Provide a radius for the small diameter cylinder.  It's the one on the bottom.  All dimensions are in mm.
Smaller_Axle_Radius=8;

//  How tall should the small diameter cylinder be?
Smaller_Axle_Height=7;

//  How large of a flat should the small diamenter cylinder have against it?
Smaller_Axle_Flat = 1;

//  Provide a Radius for the larger diameter cylinder.  It's the one on the top
Larger_Axle_Radius=19;

//  How tall should the larger diameter cylinder be?
Larger_Axle_Height=30;

//  How wide should the flange be against the larger cylinder?  The flange sits against the face of whatever this is potentially fit into.
flange_width=1;

//  How tall should this flange be?
flange_height=1;

//  How far apart are the two things from each other?  This will help determine the shape of the cone between the two cylinders.  The cone height plus the flange height equals this number.
how_far_apart_are_they = 10;

//Gotta use the callout like below to get a menu tab to appear.
/* [Make it hollow] */

//  Do you need this to be hollow?
i_need_it_hollow = 2; //[0:No,1: Hollow enough for a rod,2:Like a shell]

//  For Hollow enough for a rod:  What rod radius do you need?
rod_radius = 3;

//  For Like a shell: What shell thickness do you need?  It should be smaller than the radius of the small cylinder if you want a hole through the entire thing.  Values larger than the radius of the small cylinder will give you a flat at the same plane as the flange.
shell_thickness = 1;

/* [Build Plate Reference] */

//	This section creates the build plates for scale
//	for display only, doesn't contribute to final object
build_plate_selector = 3; //[0:Replicator 2,1: Replicator,2:Thingomatic,3:Manual]

//	when Build Plate Selector is set to "manual" this controls the build plate x dimension
build_plate_manual_x = 100; //[100:400]

//	when Build Plate Selector is set to "manual" this controls the build plate y dimension
build_plate_manual_y = 100; //[100:400]

//Gotta use the callout like below to hide variables.  Really annoying when you don't know how to do this.
/* [Hidden] */
$fa=0.5;
$fs=0.5;

var_cone_angle_percentage = 1;
var_cone_height_offset = 1;
//  How tall should the conical profile be that joins the two axles?
cone_height = how_far_apart_are_they - flange_height;

//CUSTOMIZER VARIABLES END <-- this doesn't seem to do a darn thing.

//	This is just a Build Plate for scale
build_plate(build_plate_selector,build_plate_manual_x,build_plate_manual_y);

if (i_need_it_hollow == 0) {

//here's the initial axle_a being created
cylinder(r=Smaller_Axle_Radius,h = Smaller_Axle_Height);

//here's the cone being created.  the cone goes from the r of axle_a to the r of axle_b plus whatever the flange width is.
translate([0,0,Smaller_Axle_Height]) cylinder(r1=Smaller_Axle_Radius+Smaller_Axle_Flat, r2=Larger_Axle_Radius+flange_width, h=cone_height);

//now we are going to create the flange itself.
translate([0,0,Smaller_Axle_Height+cone_height]) cylinder(r=Larger_Axle_Radius+flange_width,h=flange_height);

//and now we are creating the the final axle b
translate([0,0,Smaller_Axle_Height+cone_height+flange_height]) cylinder(r=Larger_Axle_Radius,h=Larger_Axle_Height);
}
if (i_need_it_hollow == 1) {
    difference(){
        //This is the same stuff as i_need_it_hollow == 0
        union(){
            cylinder(r=Smaller_Axle_Radius,h = Smaller_Axle_Height);
            translate([0,0,Smaller_Axle_Height])
                cylinder(r1=Smaller_Axle_Radius+Smaller_Axle_Flat, r2=Larger_Axle_Radius+flange_width, h=cone_height);
            translate([0,0,Smaller_Axle_Height+cone_height])
                cylinder(r=Larger_Axle_Radius+flange_width,h=flange_height);
            translate([0,0,Smaller_Axle_Height+cone_height+flange_height])
                cylinder(r=Larger_Axle_Radius,h=Larger_Axle_Height);
        }
        //Here's the rod cylinder that we'll use to make the difference function work.
        translate([0,0,-rod_radius/10])
            cylinder(r=rod_radius,h=Smaller_Axle_Height + Larger_Axle_Height + flange_height + cone_height + rod_radius);
    }
}
if (i_need_it_hollow == 2) {
    //if(shell_thickness > Smaller_Axle_Radius)
    difference(){
        //This is the same stuff as i_need_it_hollow == 0
        union(){
            cylinder(r=Smaller_Axle_Radius,h = Smaller_Axle_Height);
            translate([0,0,Smaller_Axle_Height])
                cylinder(r1=Smaller_Axle_Radius+Smaller_Axle_Flat, r2=Larger_Axle_Radius+flange_width, h=cone_height);
            translate([0,0,Smaller_Axle_Height+cone_height])
                cylinder(r=Larger_Axle_Radius+flange_width,h=flange_height);
            translate([0,0,Smaller_Axle_Height+how_far_apart_are_they])
                cylinder(r=Larger_Axle_Radius,h=Larger_Axle_Height);
        }
        //Here is the void we want to make.  What we're going to do is ignore the flange and assume it's part of the cone itself.  That leaves us with 3 objects to make the void and give us a smooth inner surface with a nice sharp transition with no steps.
        var_cone_angle_percentage = atan(how_far_apart_are_they/(Larger_Axle_Radius - Smaller_Axle_Radius)) / 90;
        //echo("the var_cone_angle_percentage value is ", var_cone_angle_percentage);
        var_cone_height_offset = shell_thickness * var_cone_angle_percentage;
        //echo("the var_cone_height_offset value is ", var_cone_height_offset);

        union(){
        translate([0,0,-shell_thickness/10])
            cylinder(r=Smaller_Axle_Radius - shell_thickness, h=Smaller_Axle_Height+shell_thickness/10 + var_cone_height_offset+shell_thickness);
        translate([0,0,Smaller_Axle_Height + var_cone_height_offset])
            cylinder(r1=Smaller_Axle_Radius - shell_thickness, r2=Larger_Axle_Radius - shell_thickness, h=how_far_apart_are_they);
        if (var_cone_angle_percentage == 0) {
            //echo ("i'm in here and Smaller_Axle_Height + how_far_apart_are_they + shell_thickness is ", Smaller_Axle_Height + shell_thickness);
            translate([0,0,Smaller_Axle_Height + how_far_apart_are_they + shell_thickness])
            cylinder(r=Larger_Axle_Radius - shell_thickness,h=Larger_Axle_Height+shell_thickness);
        }
        else {
            translate([0,0,Smaller_Axle_Height + how_far_apart_are_they + var_cone_height_offset])
            cylinder(r=Larger_Axle_Radius - shell_thickness,h=Larger_Axle_Height+shell_thickness);
        }
        }
    }
}
```


[User]
Hey, I'm looking to get a design made in OpenSCAD for a small customizable nameplate.

Basically, I need something that will print quickly but will let people personalize it. The core idea is to have extruded text for initials on a small base with a hole for a keychain or something.

So, the design should have:

1.  A text string that is configurable at the top level. This should be the "initials" that get extruded.
2.  The text should be extruded upwards from the base. The text should be centered along the length of the base, but not necessarily along the width, or z axis.
3.  A rectangular base underneath the extruded text. The base should be a separate object from the extruded text.
4.  A single cylindrical hole near one end of the base. It should go all the way through the base.

I'd like to be able to tweak the dimensions of the base, the height of the text, and the position and size of the hole. Ideally, I'd like to control the font used for the initials and the text size too. Please make these all adjustable through variables at the top level of the file. I'm not super picky about the fonts used - the default will probably be fine, but the ability to change it is important.

I'd also like to avoid having a ton of variables that I don't need, if that makes sense? I'd rather not have every dimension be a separate variable if I can help it.

I don't have a particular need for libraries, but if you think there is a library that could be helpful, I'm open to it. I think this is a simple enough design that I don't need any though. I'd really just like the basic OpenSCAD code.

Thanks!

[Assistant]
InitialMaker.scad:
```
myInitials = "MAK";

union() {
    translate([0,1,0])linear_extrude(1) {
        text(myInitials,$fn=32);
    };
    difference() {
        translate([0,0,-1])cube([40,12,1]);
        translate([36,6,-2])cylinder(r=2,h=5,$fn=32);
    };
};
```


[User]
Okay, I'd like to design a parametric sundial, specifically for use at a beach or in a backyard. I want it to be accurate for a short period, like a few days, and be easy to set up without needing to find true north. I'm thinking that, because of the precalculated time adjustments, I just need a level surface, rather than needing to find true north.

Here are the key requirements and features I'd like it to have:

**Location Specific Parameters:**

*   **Label:**  A text label for the location (e.g., "San Francisco").
*   **Latitude:**  The latitude of the location (a positive number).  I want to make sure that I can specify if its North or South.
*   **Hemisphere:**  A string indicating "North" or "South".
*   **DST:** An on/off switch for Daylight Savings Time.  Ideally a string "yes" or "no".
*   **Accurate:** A toggle that, if yes, exposes additional date parameters, and uses EOT calculation to adjust hour angles. String value, "yes" or "no".
*   **Month:** A string for the month, like "JAN", "FEB", "MAR", etc.
*   **Day:** A number between 1 and 31 representing the day of the month.
*   **Longitude:** The longitude of the location (positive for East, negative for West of GMT).
*   **Local\_Meridian:**  The longitude of the local time zone's reference meridian.

**Style and Size Parameters:**

*   **Sundial\_diameter:** Overall diameter of the sundial.
*   **Marker\_width:** Width of the lines and markers.
*   **guide:** Diameter of a central hole. I'd like this to be used for a string/rod that could be used to make the sundial much larger at the beach, as well as place the gnomon.

**Output Options:**

*   **show:** A toggle to choose between an assembled view or separate pieces for printing. String "assembled" or "for printing".

**Internal Parameters (you can set these to reasonable defaults):**

*   **Gnomon\_width:** Width of the gnomon.  (5mm would probably be fine, for now).
*   **gnomon\_length:** Length of the gnomon. You'll need to do some math based on the latitude and sundial diameter. The document I'm basing this on suggested `1.09 * (Sundial_diameter*0.44) * sin (113.44 - Latitude)`.
*   **split\_dial**: A simple "yes" or "no" to split the dial into two pieces to allow smaller printers to print the dial.

**Features:**

*   The sundial should be designed to mark hours from 6 am to 6 pm.
*   It should have hour and half-hour markers.
*   It needs a gnomon that is angled correctly for the given latitude.
*   There should be anchor pins for the style (gnomon) piece to help it stay in the sand.
*   I want labels for the location and date.
*   The sundial should use a formula to calculate the Equation of Time (EOT) based on the date for accuracy, if the `Accurate` variable is set to "yes". The calculation I have is:
    *  `_mean_ang_vel = 360 / 365.24`
    * `_earth_angle(day) = _mean_ang_vel * (day + 10)`
    * `_solistice_to_date(day) = _earth_angle(day) + 1.914 * sin(_mean_ang_vel * (day - 2))`
    * `_speed_diff(day) = (_earth_angle(day) - atan(tan(_solistice_to_date(day)) / cos(23.44))) / 180`
    *  `Eqn_of_time(day) = 720 * (_speed_diff(day) - round(_speed_diff(day)))`
*   It should use the local meridian, EOT, and DST to get the hour lines correct. The adjustment should be calculated as `Longitude - Local_Meridian + Eqn_of_time(today(Month, Day))/4` and then adjusted for DST if enabled.
*   The hour lines will need to be projected onto the horizontal plane of the sundial using: `hla = atan(sin_lat * tan(hra))`.

I'm not using any special libraries so don't worry about including code for them. I'd just like the OpenSCAD files, and I'm comfortable working with them from here.

I think that's it. This should give you enough info to generate the scad files.

[Assistant]
sand_sundial.scad:
```
//
//Sundial calculator for the Beach.
//
// Precalculating the Equation of time and DST offsets means it can be printed for a specific date
//  and be lined up perfectly and be accurate for a few days only.
//
// San Francisco Lat,long 37.7833 N, 122.4167 W  ref -120
// London        Lat,long 51.5072 N, 0.1275 W    ref 0  (W is -ve)
// NY            Lat,long 40.7127 N, 74.0059 W   ref -70
// Auckland      Lat,long 36.848461 S, 174.74 E  ref 165
//
// E.g. Google reports Auckland latitude as -36.848461. The -ve means South.
//   In DMS its 36deg 50min 54.4596sec S.

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

/* [Location] */
// Label for this location
Label = "San Francisco";
// What is your Latitude as reported by Googling "'yourcity' Latitude" ? Always positive.
Latitude = 37.7833;
// North or South of Equator
Hemisphere = "North"; // [North, South]
// Daylight Savings Time
DST = "yes"; // [yes, no]
// More accuracy. fill in rest of values
Accurate = "yes"; // [yes, no]
// Month
Month = "AUG"; // [JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC]
// Date of Month
Day = 18; //[1:31]
// Longitude (more accurate) -ve numbers West of GMT. E.g. USA
Longitude = -122.4167;
// Where your time is taken from(look up on special map). Sometimes one increment greater than your longitude.
Local_Meridian = -120; // [-180:15:180]

/* [Style] */
// Overall Size of the Dial. You can make large and scale when you print.
Sundial_diameter = 180;
// Width of markers. (1-2mm ideal)
Marker_width = 2; // [1:0.5:6]
//Central hole for using string to make Sundial much larger at Beach. (mm)
guide=6;

/* [printing] */
// Show assembled or ready for printing.
show = "assembled"; // [assembled, for printing]

/* [Hidden] */
Gnomon_width = 5; // Math not right yet to allow changes, style :(
// gnomon length from http://www.mysundial.ca/tsp/gnomon_height.html
gnomon_length = 1.09 * (Sundial_diameter*0.44) * sin (113.44 - Latitude);
//
split_dial = "yes"; // [yes, no]

// constants
pi = 3.14159253590;
Delta = 0.5;
sin_lat = sin(Latitude);

function DMS(d,m,s=0) = d + (m* 1/60) + (s* 1/3600);
function degrees_to_DMS(value) = [floor(value),
			floor((value - floor(value))*60),
			floor((value - floor(value) - floor((value - floor(value))*60)/60)*360000)/100];
//echo("dms=",DMS(36,50,54.4596));
//echo("fract = ", degrees_to_DMS(Latitude));

dates = [["JAN",0],  ["FEB",31], ["MAR",59], ["APR",90],
		 ["MAY",120],["JUN",151],["JUL",181],["AUG",212],
		 ["SEP",243],["OCT",273],["NOV",304],["DEC",334] ];
// how many days from 1st of year (Jan 1 = 0)
function today(month, date) = dates[search([month], dates, num_returns_per_match=1)[0]][1] + date - 1;

// Calculate eqtn of Time (coarse +/- 4 seconds)
_mean_ang_vel = 360 / 365.24;
function _earth_angle(day) = _mean_ang_vel * (day + 10);
function _solistice_to_date(day) = _earth_angle(day) + 1.914 * sin(_mean_ang_vel * (day - 2));
function _speed_diff(day) = (_earth_angle(day) - atan(tan(_solistice_to_date(day)) / cos(23.44))) / 180;
function Eqn_of_time(day) = 720 * (_speed_diff(day) - round(_speed_diff(day)));

// testing EOT
// now_deg = Longitude - Local_Meridian;
// now = Eqn_of_time(today("SEP", 20));
// echo("today", today("JAN", 1));
// echo("EOT", now, now_deg - (now/4), now_deg*4 + now );

//-------------------------------------------------------------------
module half_round(rad, angle, height=2) {
	// make the half round that attaches to the time markers.
	// Holds it all together
	rotate([0,0,angle])
	difference() {
		cylinder(r=rad/2, h=height, $fn=100);
		translate([0,0,-Delta])
			cylinder(r=rad/2-Marker_width, h=height+Delta*2, $fn=100);
		translate([rad/2+Marker_width/2, 0, 0])
			cube(size=rad+Delta*2, center=true);
	}
}

module gnomon(lat) {
	// needs special calc for each Latitude
	difference() {
		translate([-(1.5*Gnomon_width*cos(lat)),0,-cos(90-lat)*Gnomon_width*1.4])
		rotate([0,-lat,0])
		scale([3,1,1])
			cylinder(d=5, h=gnomon_length, $fn=3);
		//
		translate([-Sundial_diameter, -5, -40])
			cube(size=[Sundial_diameter, 10, 40]);
	}
}

module guide_hole(diam, height=Marker_width) {
	// hole for pin to enable making Sundial much larger
	//  and for larger gnomon placement.
	difference() {
		cylinder(d=guide+12, h=height, $fn=6);
		translate([0,0,-Delta])
			cylinder(d=guide, h=height+Delta*2, $fn=6);
		translate([Delta,0,-Delta]) //some slack
			gnomon(Latitude);
	}
}

// Hour helper labels
module one(dist) {
	translate([-Marker_width/1.5,0,-dist])
		rotate([0,0,45])
		cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
}
module two(dist) {
	translate([-Marker_width/1.5,0,-dist]) {
		rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		translate([0,Sundial_diameter/40,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
	}
}
module four(dist) {
	translate([-Marker_width/1.5,0,-dist]) {
		rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		translate([0,Sundial_diameter/30,0])
		rotate([12,0,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		translate([0,Sundial_diameter/80,0])
		rotate([-12,0,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		// underline
		translate([0,Sundial_diameter/55+Sundial_diameter/45,Sundial_diameter/21])
		rotate([90,0,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
	}
}
module nine(dist) {
	translate([-Marker_width/1.5,0,0]) {
		translate([0,0,-dist]) {
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		translate([0,Sundial_diameter/30,0])
		rotate([18,0,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		translate([0,Sundial_diameter/55,0])
		rotate([-18,0,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		// underline
		translate([0,Sundial_diameter/55+Sundial_diameter/40,Sundial_diameter/21])
		rotate([90,0,0])
			rotate([0,0,45])
			cylinder(h=Sundial_diameter/20, d=Marker_width, $fn=4);
		}
	}
}

module pins(pos) {
	// to anchor Style into Sand.
	pin_length = max(Sundial_diameter/8, 18);
	translate([pos, 0, -pin_length+Delta ])
		//cylinder(h=pin_length, d2=Marker_width, d1=Marker_width*0.4, $fn=6);
		translate([0,0,pin_length])
		rotate([0,180,0])
		linear_extrude(height=pin_length, scale=[0.2,1])
			square([Gnomon_width, Gnomon_width*0.87],center=true);
}

module style() {
	gnomon(Latitude);
	size_factor = Sundial_diameter/8;
	// support structure
	difference() {
		// support block
		translate([-Sundial_diameter/5.04, -Gnomon_width*0.87/2, 0])
			cube(size=[size_factor*1.3, Gnomon_width*0.87, Sundial_diameter*0.3*sin(90-Latitude)]);
		// Basically same as Gnomon but cube to cut away
		rotate([0,-Latitude,0])
		scale([3,1,1])
		translate([-Sundial_diameter/(Sundial_diameter/10)/2.8, -Gnomon_width/2-Delta, -size_factor/5])
			cube(size=[size_factor/1.2, Gnomon_width+Delta*2, gnomon_length*1.4], $fn=3);
	}
	// pins to anchor style in sand
	pins(-Sundial_diameter/6);
	pins(-Sundial_diameter/12);
}

module label(angle) {
	msg = (Accurate=="no") ? str(Label) :str(Label," ",Month," ",Day);
	rotate([0,0,270+angle])
	translate([Sundial_diameter/20,0,0])
	resize([Sundial_diameter/3,0,0])
	linear_extrude(height=Marker_width)
		text(msg, valign="baseline");
}

module sundial() {
	// dial lines
	hour_factor = 2.2;
	// TZ and EOT and DST adjustments
	TZ_offset = Longitude - Local_Meridian + Eqn_of_time(today(Month, Day))/4 ;
	TZ_DST_offset = (DST=="yes") ? TZ_offset+15 : TZ_offset;
	echo(str("Longitude and EOT adjustment is ", (Longitude - Local_Meridian)* 4 + Eqn_of_time(today(Month, Day)), " minutes"));
	if (DST=="yes")
		echo("Daylight adj = +1 hour");
		echo();
	for (h=[-6:0.5:6]) {
		hra_ = 15 * h; // in degrees
		hra = (Accurate=="no") ? hra_ : hra_ - TZ_DST_offset;
		hla = atan(sin_lat * tan(hra));
		hla_corrected = (sign(hra)==sign(hla)) ? hla : -90-(90-hla);
		//echo("Results",h,hla, hra, tan(hra),"#",hla_corrected);
		// rods
		rotate([hla_corrected,90,0]) {
			length_factor = (h == round(h)) ? 0.4 : 0.25 ; // half hour marker is shorter
			translate([0,0,(h == round(h)) ? -Sundial_diameter/hour_factor: -Sundial_diameter/hour_factor*0.96 ])
			translate([0,0,Sundial_diameter*(1-length_factor)/5/hour_factor])
			scale([2,1,1])
				cylinder(h=Sundial_diameter/2*length_factor, d=Marker_width, $fn=12);
		}
		// 6 hour marker extensions
		if (h == -6 || h==6) {
			rotate([hla_corrected,90,0])
			translate([0,0,-guide/2-Sundial_diameter/5])
			scale([2,1,1])
				cylinder(h=Sundial_diameter/5, d=Marker_width, $fn=12);
		}
		// numbers
		dist = Sundial_diameter/2.1;
		time = (Hemisphere=="North") ? h : h*-1;
		if (time==1) {
			rotate([hla_corrected,90,0])
			one(dist);    }
		if (time==4) {
			rotate([hla_corrected-2,90,0])
			four(dist);   }
		if (time==-3) {
			rotate([hla_corrected-2,90,0])
			nine(dist);   }
		// above-sand holder arcs to keep it together
		if (h == -6) {
			//translate([0,0,Marker_width/4])
				half_round(Sundial_diameter/2, 270-hla_corrected, Marker_width);
			//translate([0,0,Marker_width/4])
				half_round(Sundial_diameter/1.5, 270-hla_corrected, Marker_width);
			// Label
			label(270-hla_corrected);
		}
	}
}

//-------------------------------------------------------------------
// Tell user the DMS Latitude so they can check if
//  they have the right representation of their desired Altitude.
echo();
echo(str("Latitude of ", Latitude, " expressed in DMS is:"));
lat_mds =  degrees_to_DMS(Latitude);
echo(str(lat_mds[0]," Degrees ", lat_mds[1]," Minutes ", lat_mds[2], " Seconds."));
echo();

if (show == "assembled") {
	// show it in place
	sundial();
	style(Latitude);
	guide_hole(guide);
} else {
	// lay it down for printing in parts
	translate([0,0,Marker_width])
	rotate([180,0,0])
	sundial();
	guide_hole(guide);
	translate([-Sundial_diameter/2, gnomon_length/2, Marker_width])
		rotate([90,0,Latitude])
		style(Latitude);
}

// Numbers 4,2*length_factor
// split the main dial for small printers.
```


[User]
Hey, I'm looking to design a new extruder holder for my Prusa i3. I want it to be able to swivel, but the one I have now doesn't swivel enough and is positioned a little off. The main thing I need is for the extruder to mount in the *center* of the frame, when looked at from the front.

Here's what I'm envisioning:

**Key Features:**

*   **Swivel Mount:** The extruder should be able to rotate around a pivot point.
*   **Frame Mount:** The holder needs to securely attach to the Prusa i3 frame (acrylic, I think).
*   **Extruder Mount:**  It needs mounting points for the extruder.
*   **Centered Extruder:** The extruder should be positioned in the middle of the frame when viewed from the front. This is the most important part, as my current one is off-center.
*   **Parametric Design:** I'd like the design to be parametric so I can adjust dimensions later if I need to.

**Specific Dimensions/Parameters:**

*   **Frame Thickness:** I'll need a parameter for the frame's thickness (around 8.5mm, but I'd like to make it adjustable).
*   **Frame Mounting Distance:** The distance between the mounting holes on the frame (around 100mm).
*   **Frame Mounting Hole Diameter:** The diameter of the mounting holes on the frame (around 3.6mm).
*   **Extruder Mounting Distance:**  The distance between the extruder's mounting holes (around 40mm).
*   **Extruder Mounting Hole Diameter:** The diameter of the extruder's mounting holes (around 3.6mm).
*    **Pivot Diameter:** The diameter of the pivot (around 4.8 mm).
*   **Clearance:** I need to make sure there is adequate clearance for the parts to swivel without hitting the frame or extruder. This is where my current design failed a bit, so I'd like to avoid that.

I would also like the design to be in two parts. One part will mount to the frame, and the other will mount to the extruder, with the swivel joint connecting them.

I'd like the design to use the BOSL2 library, as I'm familiar with its functionality. Could you generate a parametric OpenSCAD file (or multiple files) that achieve this? I'm not sure if multiple files will make it easier, but I am open to either solution. Thanks!

[Assistant]
Prusa_I3_Extruder_Holder.scad:
```
/* [Global] */

// Which one would you like to see?
part = "both"; // [Extruder Holder,Frame Holder,both]

// Pivot point diameter
Pivot_Dia = 4.8;

/* [Frame Holder] */

// I3 Frame thickness (of acrylic)
Frame_Thickness = 8.5;

// I3 Frame mounting hole distance
Frame_Mounting_Dist = 100;

// I3 Frame mounting hole diameter
Frame_Mounting_Dia = 3.6;

/* [Extruder Holder] */

// Extruder mounting hole diameter
Extr_Mounting_Dia = 3.6;

// Extruder mounting hole distance
Extr_Mounting_Dist = 40;

print_part();

module print_part() {
	if (part == "Extruder Holder") {
		extr_holder();
	} else if (part == "Frame Holder") {
		frame_holder();
	} else {
		color("Green") translate([-6, Frame_Thickness/2+2+6, 3]) extr_holder();
        frame_holder();
	}
};

module extr_holder()
{
    difference()
    {
        union()
        {
            cube([20,12,4], center=true);

            translate([0,12+6,3.5-2])
                cube([20,24,7], center=true);

            translate([0,-2-6,(Extr_Mounting_Dist * 1.2 + 7)/2 - 2])
                cube([20,4,Extr_Mounting_Dist* 1.2 + 7], center=true);
            translate([(20-3)/2,0,+2+1.5])
                cube([3,12,3], center=true);
            translate([-(20-3)/2,0,+2+1.5])
                cube([3,12,3], center=true);
        };

        union()
        {
            cylinder(d=Pivot_Dia, h=7,center=true);
            translate([0,-2-6,7]) union()
            {
                rotate([90,0,0])
                    cylinder(d=Extr_Mounting_Dia, h=5, center=true);

                translate([0,0,Extr_Mounting_Dist])
                    rotate([90,0,0])
                        cylinder(d=Extr_Mounting_Dia, h=5, center=true);

                translate([0,0,14]) rotate([90,0,0])
                    cylinder(d=13.5, h=5, center=true);
            };
        };
    };
};

module frame_holder()
{
    difference()
    {
        union()
        {
        translate([0,Frame_Thickness / 2 + 1,-6-3]) cube([Frame_Mounting_Dist * 1.1,2,12], center=true);

         translate([0,-Frame_Thickness / 2 - 1,-6-3])cube([Frame_Mounting_Dist * 1.1,2,12], center=true);

        translate([0,0,-1.5])
            cube([Frame_Mounting_Dist * 1.1,Frame_Thickness+4,3], center=true);

            translate([-6,Frame_Thickness/2+2+6,-6])
                cube(12, center=true);
        };

        union()
        {
            translate([Frame_Mounting_Dist/2,0,-7.5-3]) rotate([90,0,0])
            cylinder(d=Frame_Mounting_Dia, h=Frame_Thickness + 7, center=true);

        translate([-Frame_Mounting_Dist/2,0,-7.5-3]) rotate([90,0,0])
            cylinder(d=Frame_Mounting_Dia, h=Frame_Thickness + 7, center=true);
        };

        translate([-6,Frame_Thickness/2+2+6,-6])
        cylinder(d=Pivot_Dia, h=13,center=true);
    };
};
```