[User]
I'd like to create a parametric OpenSCAD design for a customizable bipedal robot, similar to the Otto DIY robot. The robot should have a head, body, two legs, and two feet. I want to be able to adjust several parameters to customize the robot.

Specifically, the design needs to have these adjustable parameters:

*   **Part Selection:** I need to be able to select which parts to render: "all", "head", "body", "leg", "foot\_left", "foot\_right".
*   **Brain Type:** I'd like to choose between different Arduino board mounting options in the head. The choices should be "nano\_shield" (Arduino Nano with servo shield), "nano\_proto" (Arduino Nano with proto board), "uno\_shield" (Arduino Uno with servo shield), and "uno" (Arduino Uno with just wires). The mounting holes should change accordingly based on the brain type chosen.
*   **Servo Types:** There should be separate options for the hip and ankle servos. I want to be able to select between "sg90" (nylon gear micro servo) and "mg90s" (metal gear micro servo) for each.
*   **Body Dimensions:**  I need to be able to adjust the `body_width`, `body_depth`, and `body_height`. The head's dimensions should be based on the body's width and depth.
*   **Head Height:** There should be a parameter to adjust the `head_height`.
*   **Shell Thickness:** I'd like separate parameters for the `body_thickness` and `head_thickness`.
*   **Nose Details:** There needs to be parameters for the `nose_diameter` and the `nose_distance` (the vertical distance between the center of the eyes and the nose).
*   **Brain Screw Size:** I need a parameter for the size of the screws used to secure the Arduino board, `brain_screw_size`.
*    **Brain Screw Through:** A flag to either have the brain mounting screws go all the way through the skull or not (the depth of these holes should be adjustable).

I'd also like the legs to have a parameter to specify if they are solid or hollow. This is a printer-specific concern for me and I'd need the option to make them solid for better print quality on my printer.

I think that covers it. I'm looking for a design that's fully parametric, making it easy to adjust the robot's dimensions and features. I'm also hoping for a clean and well-structured OpenSCAD code. Please use appropriate libraries for things like chamfers. I'm not going to specify any code explicitly - please use whatever you think is best.

[Assistant]
OttoDIY_CUSTOM.scad:
```
// Part to print
part="all"; // [all:Preview Bot,head:Head,body:Body,leg:Leg,foot_left:Left Foot,foot_right:Right Foot]

// Brain type (hole pattern in head)
brain_type="nano_shield"; // [nano_shield:Stock (Arduino Nano + Servo Shield),nano_proto:Arduino Nano + Proto board,uno_shield:Arduino Uno + Servo Shield,uno:Arduino Uno (and wires)]

// Servo Type for hip
servo_type_hip="sg90"; // [sg90:SG90 (nylon gear micro servo),mg90s:MG90S (metal gear micro servo)]

// Servo Type for ankle
servo_type_ankle="sg90"; // [sg90:SG90 (nylon gear micro servo),mg90s:MG90S (metal gear micro servo)]

// Body Width (Head width is based off this)
body_width=67; // [67:200]

// Body Depth (Head depth is based off this)
body_depth=68; // [68:200]

// Body Height
body_height=38; // [20:200]

// Head Height
head_height=34; // [20:200]

// Body Shell Thickness
body_thickness=1.75; // [0.25:0.25:8]

// Head Shell Thickness
head_thickness=2; // [0.25:0.25:8]

// Nose Diameter (6 = Small Toggle Switch)
nose_diameter=6; // [0:24]
// Vertical distance between center of eyes and nose
nose_distance=15; // [-8:190]

// Brain Screw Size (2 = Stock)
brain_screw_size=2; // [2:5]

// Make Brain Screw thru Skull
brain_screw_thru=0; // [1:Yes,0:No]

// Solid leg
leg_solid=0; // [1:Yes, solid,0:No, my printer doesn't like those overhangs]

/* [Hidden] */
part_clearance=0.25;

arduino_holes=[[-27,-7],[-27,20.9],[25.2,26.1],[23.825,-22.25]];
proto_holes=[[27,-10],[-17.9,-10],[26,25.5],[-17.7,25.5]];

print_part();

module print_part() {
  warnings()
    draw_part();
}

module draw_part() {
  if(part=="head")
    head();
  else if(part=="body")
    body();
  else if(part=="leg")
    leg();
  else if(part=="foot_left")
    foot();
  else if(part=="foot_right")
    mirror([1,0]) foot();
  else if(part=="all")
    rotate([0,0,-90]) otto();
}
module otto() {
  head(move=1);
  body(move=1);
  mirrory() {
    translate([0,body_width/2-33.5,0])
    {
      mirror([1,0]) foot(move=1);
      translate([0,24,-1]) mirror([0,0,1]) leg(move=0);
    }
  }
}
function brain_type_text() = (
  brain_type=="nano_shield"?"Arduino Nano + Servo Shield":(
  brain_type=="uno_shield"?"Arduino Uno + Servo Shield":(
  brain_type=="nano_proto"?"Arduino Nano + Proto board":"Unknown")));
module warnings() {
  if(brain_type=="nano_shield")
  {
    if(body_width<67)
      error(str("If ",brain_type_text()," is used, Body Width must be >= 67!"));
    else if(body_depth<67)
      error(str("If ",brain_type_text()," is used, Body Depth must be >= 67!"));
    else children();
  } else if(brain_type=="uno_shield"||brain_type=="uno")
  {
    if(body_width<81)
      error("If Arduino Uno is used, body width MUST be greater than 81!");
    else children();
  } else children();
}
module error(s) {
  echo(str("***ERROR*** ",s));
  rotate([0,0,-45])
        rotate([80,0,0]) color("red") text(s);
}
module body(dims=[body_depth-1,body_width,body_height]) {
  left=dims[0]/-2; // -33.5
  botm=dims[1]/-2; // -33.5
  right=dims[0]/2; // 34
  servozoff=servo_type_hip=="sg90"?2:0;
  *#import("Otto_DIY/files/OTTO_body_v3.stl");
  mirrorx(0.4) mirrory(0.25) translate([left+body_thickness,botm+body_thickness+13.775,body_thickness]) {
      cube([dims[0]/2-9,2.5,12.4]);
      translate([0,2.5,12.39]) rotate([90,0,90]) mirror([1,0]) linear_extrude(dims[0]/2-9,convexity=10) polygon([[0,0],[1.2,0.825],[2.5,0.825],[2.5,0]]);
  }
  mirrory() mirrorx() translate([left+body_thickness-.01,botm+6,dims[2]-16]) difference(){
    cube([2,13.7,5]);
    translate([0,-.01]) rotate([0,41]) cube([3,13.72,5]);
  }
  mirrory() for(x=[0,28.2]) translate([x-9.5,botm+body_thickness,body_thickness]) difference() {
    union(){
      cube([2,13.775,6.18-servozoff]);
      translate([0.98,6.85,0]) cylinder(d1=5.7,d2=4.4,h=0.85,$fn=30);
      translate([0.98,6.85,0.84]) cylinder(d=4.4,h=5.35-servozoff,$fn=40);
    }
      translate([0.98,6.85,-.01]) cylinder(d=1.9,h=7,$fn=20);
  }
  for(mx=[0,1],my=[0,1]) mirror([mx,0]) mirror([0,my]) translate([mx?-11:0,0])
  translate([left+body_thickness+22.2,botm+body_thickness,body_thickness]) difference() { union() {
      if(!mx&&!my)
        translate([-10.7,6.61])
          cylinder(d=16,h=6.25-servozoff,$fn=50);
      else if(!mx&&my)
        translate([-17.5,0,.01]) cube([11.9,13.2,6-servozoff]);
      translate([-1-(left+33),5.64,0]) mirror([1,0]) cube([(mx?-22:-12)-left,2,6.1-servozoff]);
    }
    if(!mx&&!my)
      translate([-10.72,6.61,-.01]) cylinder(d=12,h=6.27,$fn=40);
    else if(!mx&&my)
      translate([-15.9,5,-.01]) {
        cube([8.35,8.2,7]);
        translate([0,-6]) cube([8.35,4,7]);
      }
  }
  difference() {
      translate([left,botm,0]) box_chamfer(dims,ch=2,chvx=5,chvy=5);
//    translate([left+1.75,botm+1.75,2]) box_chamfer([dims[0]-3.5,dims[1]-3.5,dims[2]],ch=1,chvx=4,chvy=4,inside=1);
    translate([left+body_thickness,botm+body_thickness,2]) box_chamfer([dims[0]-body_thickness*2,dims[1]-body_thickness*2,dims[2]],ch=1,chvx=4,chvy=4,inside=1);
    translate([0,0,-1]) linear_extrude(10,convexity=10) {
      mirrory() {
        translate([.1,botm+8.5]) circle(d=12,$fn=30);
        translate([6,botm+8.5]) circle(d=servo_type_hip=="mg90s"?6.5:7,$fn=20);
        offset(-1) offset(1)
        translate([-14.5,-15]) square([29,4]);
      }
      translate([left+9,-botm-13.5]) square([5.2,5.2]);
      translate([left+12.8,botm+8.35]) {
        circle(d=2,$fn=20);
        for(r=[2:360/7:359]) rotate([0,0,r]) translate([4.1,0]) circle(d=2,$fn=20);
      }
    }
    mirrory() translate([-11.7,right-body_thickness-.51,dims[2]-11]) {  cube([22.35,body_thickness+0.6,4]);
      translate([0,body_thickness+.02,4.1]) rotate([-35,0]) mirror([0,0,1]) mirror([0,1,0]) cube([22.35,4,5.4]);
    }
  }
}
module head(dims=[
    body_width-(body_thickness+part_clearance)*2,
    body_depth-(body_thickness+part_clearance)*2,
    head_height],brain_type=brain_type,head_thickness=head_thickness,move=0) {
  left=dims[0]/-2; // -31.5
  botm=dims[1]/-2; // -32.25
  right=dims[0]/2; // 31.5
  translate(move?[0,0,body_height+head_height-3]:[]) rotate(move?[180,0,-90]:[]) {
    //#import("Otto_DIY/files/OTTO_head_v3.stl");
    difference(){
      translate([left,botm,0]) box_chamfer(dims,ch=2,chy1=3.5,chvx=5.5,chvy=4);
      translate([left+head_thickness,botm+head_thickness+1.501,head_thickness]) box_chamfer([dims[0]-head_thickness*2,dims[1]-head_thickness*2-1.5,dims[2]],ch=1,chvx=2.75,chvy=2.75,inside=1);
      translate([left,botm-.01,dims[2]-3.8]) cube([dims[0],1.5,10]);
      for(x=[-13.25,13.25])
        translate([x,botm-.01,15]) rotate([-90,0]) cylinder(d=16.5,h=4,$fn=50);
      brain_holes(brain_type,top=dims[1]/2-20,right=dims[0]/2);
      translate([-5.6,-29.555,3.75]) {
        translate([11.25,0]) rotate([-90,0]) rotate([0,0,180]) intersection() {
          box_chamfer([11.3,7.6,2],ch=0,chvx=1.6,chvy=1.6);
          translate([0,0,-.8]) box_chamfer([11.3,7.6,4],ch=1.6,chvx=0,chvy=0);

        }
      }
      if(nose_diameter>0&&dims[2]-(nose_diameter/2+nose_distance)>18)
      {
        translate([0,botm-.01,15+nose_distance]) rotate([-90,0]) cylinder(d=nose_diameter,h=head_thickness+2.02,$fn=30);
      } else echo(str("Warning: Hiding nose."));
    }
    // tabs
    mirrorx() translate([-left-2,-9.25,dims[2]]) rotate([-90,0]) mirror([0,1,0]) linear_extrude(21,convexity=10) polygon([[0,0],[0,8.4],[1.98,8.4],[4.1,6.3],[4.1,4.2],[2,2.5],[2,0],]);
    mirrory(0.75) mirrorx(0) translate([left+4.5,botm+1.5,dims[2]]) rotate([90,0]) mirror([0,0,1]) linear_extrude(2) polygon([[0,0],[0,6],[2,8],[12,8],[14,6],[14,1.5],[15.5,0]]);
    brain(brain_type=brain_type,top=dims[1]/2-20,right=dims[0]/2);
  }
}
module leg(move=0) {
  bo=servo_type_ankle=="sg90"?0:(
    servo_type_ankle=="mg90s"?1.6:0);
  translate(move?[0,24,-40]:[]) rotate([0,0,0]) union(){
  //#import("Otto_DIY/files/OTTO_leg_v4.stl");
  difference() {
    translate([-14.5,-8.25,0]) {
      intersection() {
        cube([29,16.5,38.5]);
        union(){
          box_chamfer([29,16.5,20],2);
          translate([0,0,38.6]) mirror([0,0,1]) box_chamfer([29,16.5,20],1.25,chvx=2,chvy=2);
          *translate([1,1,30])
            box_chamfer2([29-2,16.5-2,7],2);
        }
      }
    }
    translate([-12.5,-6.25,4.25]) cube([25,12.5,50]);
    translate([12,-3,5]) cube([6,6,7.5]);
    translate([0.5,0,2.6-(servo_type_hip=="mg90s"?0:1)]) rotate([0,0,90]) {
      linear_extrude(3.4)
        polygon([[-3.1,0],[-2,20],[2,20],[2.8,0]]);
      translate([0,0,-3.01]) cylinder(d=servo_type_ankle=="mg90s"?7.8:7.4,h=8,$fn=30);

    }
    translate([-14.5-.01,0,28.5]) rotate([0,90,0]) {  cylinder(d=4,h=5,$fn=30);
      rotate([0,0,90]) translate([0,0,5]) {
        cylinder(d=12,h=30,$fn=30);
        translate([0,-5.5]) cylinder(d=servo_type_ankle=="mg90s"?6.5:7,h=30,$fn=20);
        translate([-6,0]) cube([12,30,30]);
      }
    }
    if(!leg_solid)
      mirrory() translate([-11.525,-8.3,4.9]) mirror([0,1,0]) rotate([90,0]) linear_extrude(5) {
      //square([21.565,12.93]);
      polygon([[0,0],[0,5.7],[6.1,12.93],[21.565-5.7,12.93],[21.565,5.7],[21.565,0]]);
    }
    translate([-15,0,9]) rotate([0,90,0]) cylinder(d=2.5,h=5,$fn=20);
  }
  difference() {
    translate([8.55-bo,-3.8,4]) cube([4+bo,7.6,7.5]);
    translate([10-bo,-3,5]) cube([4+bo,6,8]);
    translate([8.5-bo,0,9]) rotate([0,90,0]) cylinder(d=2.2,h=2,$fn=20);
  }
}
}
module foot(move=0) {
  servohornoff=(servo_type_ankle=="sg90"?2:0);
  translate(move?[0,34.5,-48]:[])
  //*translate([0,44,0]) import("Otto_DIY/files/OTTO_footL_v4.stl");
  difference(){
    union(){
      translate([-31,-20,0]) {
        intersection() {
          cube([62,40,5]);
          translate([0,0,-3]) box_chamfer3([62,40,8.01],2);
          *translate([2.8,2.8,0]) box_chamfer2([56.3,34.4,2.5],4);
        }
      }
      translate([15.8,-9.5,15.75]) sphere(d=4,$fn=30);
      for(m=[0,1]) mirror([m,0])
      translate([-21.15,-20,0]) difference() {
        intersection(){
          cube([4+(m?1.1:1.5),21,24.5+(m?0:2)]);
          box_chamfer3([41.8,21,25+(m?0:2)],2);
          *translate([2.8,2.8,0]) box_chamfer2([36.2,15.4,22.5],4);
        }
        translate([5.5,-.01,-.01]) cube([31.3,21.02,25.02]);
        if(m==0)
        translate([-.01,10.5,15.5]) rotate([0,90]) {
            cylinder(d=7.3,h=6+servohornoff,$fn=30);
            translate([-8,0]) cylinder(d=1,h=6+servohornoff,$fn=10);
            rotate([0,0,90]) linear_extrude(2+servohornoff) {
            polygon([[-3.5,0],[-2,10+(m?0:2)],[2,10+(m?0:2)],[3.5,0]]);
          }
        }
      }
    }
    translate([-15.7,-21.01,1]) {
      translate([0,-1,0]) box_chamfer3([31.8,26.02,10],2);
      *intersection(){
        cube([31.8,25.02,10]);
        translate([2,0,2.8]) box_chamfer2([27.3,22,8],4);
      }
    }
  }
}
module brain_holes(brain_type=brain_type,
    right=(body_width-(body_thickness+part_clearance)*2)/2,
    top=(body_depth-(body_thickness+part_clearance)*2)/2-20) {
    blo=(brain_type=="uno_shield"||brain_type=="uno"?14:0);
    bto=(brain_type=="uno_shield"?4:(brain_type=="nano_shield"?-.5:0));
  if(brain_type=="nano_proto") {
    translate([right-2.76,-.2,20.5]) rotate([0,90]) rotate([0,0,90]) usb_mini();
  }
  if(brain_type=="nano_shield"||brain_type=="uno_shield"||brain_type=="uno")
  {
    translate([right-31.5-blo,top-12.5-bto,brain_screw_thru?-.01:head_thickness]) for(pos=arduino_holes) translate(pos) cylinder(d=brain_screw_size,h=3+head_thickness+.02,$fn=24);
  }
  if(brain_type=="nano_shield") {
    translate([0,top-12])
    {
    translate([right+.01,18.163,12.875]) rotate([0,-90]) cylinder(d=8,h=4,$fn=24);
    translate([right-2.76,12.5,4.815]) cube([2.06,10.5,14.2]);
    translate([right-2.76,-2.4,19.5]) rotate([0,90]) rotate([0,0,90]) usb_mini();
    }
  } else if(brain_type=="uno_shield"||brain_type=="uno") {
    translate([right-head_thickness-.01,top,7]) {
      cube([head_thickness+.02,8.9+part_clearance*2,10.9+part_clearance*2]);
      translate([0,-31.7]) cube([head_thickness+.02,12+part_clearance*2,10.9+part_clearance*2]);
    }
  }
}
module brain(brain_type=brain_type,
  right=(body_width-(body_thickness+part_clearance)*2)/2,
  top=(body_depth-(body_thickness+part_clearance)*2)/2-20)
{
  blo=(brain_type=="uno_shield"||brain_type=="uno"?14:0);
  bto=(brain_type=="uno_shield"?4:(brain_type=="nano_shield"?-.5:0));
  translate([right-31.5-blo,top-12.5-bto]) {
  if(brain_type=="nano_shield"||brain_type=="uno_shield"||brain_type=="uno") {
    translate([-25.4,-25,2]) mirror([0,1]) cube([2,4.9+(top-12),3.9]);
    translate([-27-brain_screw_size/2,-8,2]) mirror([1,0]) cube([3-brain_screw_size/2+(right-34),2,3]);
    translate([-27-brain_screw_size/2,20,2]) mirror([1,0]) cube([3-brain_screw_size/2+(right-34),1.98,3]);
    translate([-25.375,29.075,2]) cube([2,1.5+bto,3.9]);
    translate([23.626,29.075,2]) cube([2,1.5+bto,3.9]);
    translate([27,25,2]) cube([4,2,3]);
    translate([22.877,-24,2]) mirror([0,1]) {
      translate([0,1.125]) cube([2,4.875+(top/2+bto-6),3.9]);
      cube([2,6,3]);
    }
    translate([0,0,1.99]) for(pos=arduino_holes)
      translate(pos) brain_screw();
  } else if(brain_type=="nano_proto") {
    translate([0,2,2]) cube([10,4,3]);
    translate([0,0,2]) for(pos=proto_holes)
       translate(pos) {
         difference() {
           union() {
             brain_screw();
             if(pos[1]>0)
              translate([-1,2]) cube([2,4,3]);
             else if(pos[0]>15)
               translate([0,-1]) cube([4,2,3]);
           }
           translate([0,0,-.01]) cylinder(d=2,h=4.02,$fn=20);
       }
     }
     }
  }
}
module brain_screw(brain_screw_size=brain_screw_size) {
  difference() {
    union(){
      cylinder(d=brain_screw_size+2.3,h=3,$fn=30);
      cylinder(d1=brain_screw_size+4,d2=brain_screw_size+2.3,h=1,$fn=30);
    }
    translate([0,0,-.01]) cylinder(d=brain_screw_size,h=4.02,$fn=20);
  }
}
module usb_mini() {
  linear_extrude(3,convexity=10) {
    translate([0.6,0]) union() {
      translate([0,0.1]) square([8-1.202,4]);
      for(x=[0.1,6.7]) translate([x,0.1]) circle(r=0.1,$fn=20);
      translate([0.1,0]) square([6.6,4]);
    }
    mirrorx(3.999) translate([0.4,1.81]) difference() {
      square([0.2,0.2]);
      circle(r=0.2,$fn=20);
    }
    translate([0,2.008]) union() {
      translate([0.1,0.2]) square([7.8,1.9]);
      translate([0.2,0]) square([7.6,2.1]);
      translate([0,0.1]) square([8,1.9]);
      for(x=[0.2,7.8])
        translate([x,0.2]) circle(r=0.2,$fn=20);
      for(x=[0.1,7.9])
        translate([x,2]) circle(r=0.1,$fn=20);
    }
  }
}

module box_chamfer3(dims,ch=1,bot=1)
{
  render() intersection() {
    cube(dims);
    minkowski()
    {
      translate([ch,ch,ch]) cube([dims[0]-ch*2,dims[1]-ch*2,dims[2]-ch*2]);
      *sphere(r=ch/sin(60),$fn=10);
      for(m=[0,1]) mirror([0,0,m])
        cylinder(r1=ch,r2=m?(bot?0:ch):0,h=ch,$fn=4);
    }
  }
}
module box_chamfer2(dims,ch=1)
{
  render() minkowski()
  {
    cube(dims);
    intersection()
    {
      rotate([45,0,45]) cube(ch,center=true);
      rotate([45,0,-45]) cube(ch,center=true);
    }
  }
}
module box_chamfer(dims,ch=1,chx1="auto",chx2="auto",chy1="auto",chy2="auto",chvx="auto",chvy="auto",inside=0) {
  x1=chx1=="auto"?ch:chx1;
  x2=chx2=="auto"?ch:chx2;
  y1=chy1=="auto"?ch:chy1;
  y2=chy2=="auto"?ch:chy2;
  vx=chvx=="auto"?ch:chvx;
  vy=chvy=="auto"?ch:chvy;
  difference(){
    cube(dims);
    if(x1)
    {
      translate([x1,-.01]) rotate([0,-45]) mirror([1,0]) cube([x1*2,dims[1]+.02,x1*2]);
      *if(vx)
      translate([9.9,0]) rotate([0,0,45]) translate([-5+x1,0]) translate([x1,-.01]) rotate([0,-45]) mirror([1,0])  cube([x1*2,dims[1]+.02,x1*2]);
    }
    if(x2)
      translate([dims[0]-x2,-.01]) rotate([0,45]) cube([x2*2,dims[1]+.02,x2*2]);
    if(y1)
      translate([-.01,y1]) rotate([45,0]) mirror([0,1,0]) cube([dims[0]+.02,y1*2,y1*2]);
    if(y2)
      translate([-.01,dims[1]-y2]) rotate([-45,0]) cube([dims[0]+.02,y2*2,y2*2]);
    if(vx)
    {
      mirrorx(dims[0]/2) {
        translate([vx,0,-.01]) rotate([0,0,45]) mirror([1,0]) cube([vx*2,vx*2,dims[2]+.02]);
        translate([inside?-1.4:-1.5,inside?0:-1.1]) rotate([0,0,45])
        mirror([1,0,0]) rotate([0,45,0])
        translate([-vx,-vx]) translate([0,0,vx/-.75]) cube([10,vx*2,vx*2]);
      }
    }
    if(vy)
      mirrorx(dims[0]/2) {
        translate([0,dims[1]-vy,-.01]) rotate([0,0,-45]) mirror([1,0]) cube([vy*2,vy*2,dims[2]+.02]);
        translate([0,dims[1]+(inside?-0.25:0.5),-.01])
          rotate([0,0,-45]) mirror([1,0,0])
          rotate([0,-45,0])
          translate([-vx,-vx]) translate([0,0,vx/-.75])
          cube([10,vx*2,vx*2]);
      }
  }
}
module mirrory(offset=0)
{
  translate([0,offset,0]) for(m=[0,1]) mirror([0,m,0]) translate([0,offset*-1,0]) children();
}
module mirrorx(offset=0)
{
  translate([offset,0]) for(m=[0,1]) mirror([m,0]) translate([offset*-1,0]) children();
}
module otto_stl() {
  translate([0,0,66]) rotate([180,0,-90]) import("Otto_DIY/files/OTTO_head_v3.stl");
  import("Otto_DIY/files/OTTO_body_v3.stl");
  translate([0,-34.5,-48]) import("Otto_DIY/files/OTTO_footR_v4.stl");
  translate([0,34.5,-48]) import("Otto_DIY/files/OTTO_footL_v4.stl");
  for(y=[-25,25])
    translate([0,y,-40]) rotate([0,0,0]) import("Otto_DIY/files/OTTO_leg_v4.stl");
}
```


[User]
Hey, I'm looking to have a bottle stand designed for 3D printing. I've seen a few designs online, and I'd like something that allows me to invert bottles so I can get every last drop out. I'm thinking a modern, kind of trapezoidal shape, but hollowed out, and with a hole at the top for the bottle neck.

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

*   **`depth`**: The depth or length of the stand, basically how far the bottle will extend horizontally. I'd like to be able to adjust it from 1 to 250 units.
*   **`tall`**:  How tall the stand is, or rather the distance between the base and the point where the bottle neck hole is. Range from 1 to 300 units.
*   **`bottleHole`**: The diameter of the hole at the top, for the bottle neck. This should be adjustable between 1 and 250 units, in 0.1 increments.
*   **`topWidth`**: The width of the top part of the trapezoid, at the bottle hole end. Range from 1 to 300 units.
*   **`baseWidth`**: The width of the bottom part of the trapezoid. Range from 1 to 300 units.

The overall shape should be a hollow trapezoidal prism, with a rounded interior. Basically, it would be like a solid trapezoid, with the inner volume removed, and a hole for the bottle neck. I'd like it designed for 3d printing, so consider tolerances etc.

I'd prefer if the design was done in OpenSCAD. Thanks!

[Assistant]
BottleStand3.1.scad:
```
// Modern Inverted Bottle Stand
// by Urban Reininger - aka: UrbanAtWork on Thingiverse and Twitter
// Version 0.1 - May 2016

// Depth of stand
depth = 90; // [1:250]
// How Tall?
tall = 40; // [1:300]
// Bottle Hole Size
bottleHole = 40; // [1:0.1:250]
// Top Width - top of trapazoid
topWidth = 70; // [1:300]
// Base Width - bottom of trapazoid
baseWidth =100;   // [1:300]

// preview[view:south, tilt:bottom diagonal]

// detail level
//$fn =100;

// RENDERS
color("orange")
rotate([0,0,0])
difference(){

    linear_extrude(height = depth, center = true, convexity = 10){
        difference(){

            offset(r = 10){
                hull(){
                    translate([tall,-topWidth,0])
                        circle(30);
                    translate([tall,topWidth,0])
                        circle(30);

                    translate([0,-baseWidth,0])
                        circle(30);
                    translate([0,baseWidth,0])
                        circle(30);
                }
            }

        // the cut out
                hull(){
                    translate([tall,-topWidth,0])
                        circle(30);
                    translate([tall,topWidth,0])
                        circle(30);

                    translate([0,-baseWidth,0])
                        circle(30);
                    translate([0,baseWidth,0])
                        circle(30);
                }
            }
        }

   // cut out for bottle top
        translate([tall,0,0])
        rotate([0,90,0])
        cylinder(d=bottleHole,h=60, center=false);
    }
```


[User]
Hey there! I'm looking to generate some 3D printable models for the game Tak, and I'd love for you to help me create the OpenSCAD files. I've got some basic shapes in mind, and I'd like to make them parametric so I can adjust them later.

Specifically, I need four types of pieces: white flatstones, black flatstones, white capstones, and black capstones. I've got some rough ideas about their shapes and dimensions, but they need to be flexible. I'll specify the base dimensions in inches (and we'll convert that in the code to mm later), and I'd like them to have a parameter for edge roundness. This roundness will be a percentage (0 to 1) that we'll use to round off the sharp edges of the pieces.

**Here's a breakdown of each piece:**

*   **White Flatstone:** This is basically a trapezoidal prism. The top of the trapezoid is wider than the bottom. I need a parameter to specify the base width and height of the trapezoid. The total height of the prism should be parameterized as well.
*   **Black Flatstone:** This one is a cylinder with a flat side, kind of like a D shape when viewed from above. The diameter of the circle, and the height of the cylinder are important parameters.
*   **White Capstone:** This is a truncated pyramid - basically, a square based pyramid with the top cut off. We'll need the dimensions of the top square, the bottom square, and the overall height.
*   **Black Capstone:** This is basically a sphere with a flat base. We need the diameter of the sphere and a way to make it flat at a specific height from the base.

I'll need to have a top-level file where I can select which piece I want to print, specify the number of copies, and set the printer bed dimensions. The pieces should be laid out on the bed automatically based on the count and dimensions of each piece. I want to be able to select from `"white flatstone"`, `"black flatstone"`, `"white capstone"`, or `"black capstone"` for the piece.

Finally, I'd like to include a clamp function that forces values to remain within a minimum/maximum range.

Could you handle the parametric design and the automatic layout? It would be super helpful. I don't think I need any additional libraries beyond standard OpenSCAD functionalities. Let me know if you need more details!

[Assistant]
Tak.scad:
```
// choose a piece to print
piece = "black capstone"; // [white flatstone,black flatstone,white capstone,black capstone]
// the width of your print bed (x axis)
print_bed_width = 108; // [20:1000]
// the depth of your print bed (y axis)
print_bed_depth = 108; // [20:1000]
// maximum number of pieces to print
print_count = 2; // [1:139]
// if it's too high, the flatstones won't be able to stand on edge
edge_roundness = 0.4; //[0:0.01:1]

// clamp function, ensures a value is within a certain range:
// [clamp(0,[3:5]), clamp(4,[3:5]), clamp(6,[3:5])]
// results in: [3,4,5]
function clamp(val,rng) = max(rng[0],min(rng[2],val));

// measurements
in = 254/10;

// The white flatstones: a flat trapezoidal prism
module tak_white_flatstone(roundness){
  r = clamp(roundness,[0:0.99999999])*3/16*in;
  color("white") minkowski(){
    translate([0,0,r]) linear_extrude(3/8*in-2*r){
      polygon([
        [0+r, 0+r],
        [5/4*in-r, 0+r],
        [1*in-r,1*in-r],
        [1/4*in+r,1*in-r]
      ]);
    }
    sphere(d=r*2, $fs=0.25);
  }
}

// the black flatstones; a circle with a flattened edge
module tak_black_flatstone(roundness){
  r = clamp(roundness,[0:0.99999999])*3/16*in;
  color("grey") minkowski(){
    translate([0,0,r]) intersection(){
      translate([5/8*in,3/8*in,0])
        cylinder(h=3/8*in-2*r, d=5/4*in-2*r, $fa=0.25);
      translate([0,r,0]) cube([2*in,2*in,2*in]);
    }
    sphere(d=r*2, $fs=0.25);
  }
}

// the white capstones, truncated pyramid
module tak_white_capstone(roundness){
  r = clamp(roundness,[0:0.99999999])*3/16*in;
  color("white") minkowski(){
    translate([5/8*in,5/8*in,r]) rotate([0,0,45])
      cylinder(
        d1=(5/4*in-2*r)*sqrt(2),
        d2=(3/4*in-2*r)*sqrt(2),
        h=1*in-2*r, $fn=4
      );
    sphere(d=r*2, $fs=0.25);
  }
}

// the black capstones, sphere with flattened base
module tak_black_capstone(roundness){
  r = clamp(roundness,[0:0.99999999])*3/16*in;
  color("grey") minkowski(){
    intersection(){
      translate([5/8*in,5/8*in,3/8*in]) sphere(d=5/4*in-2*r, $fa=0.25);
      translate([0,0,r]) cube([2*in,2*in,2*in]);
    }
    sphere(d=r*2, $fs=0.25);
  }
}

module tak_stone(type, roundness){
  if(type=="white flatstone")
    tak_white_flatstone(roundness=roundness);
  if(type=="black flatstone")
    tak_black_flatstone(roundness=roundness);
  if(type=="white capstone")
    tak_white_capstone(roundness=roundness);
  if(type=="black capstone")
    tak_black_capstone(roundness=roundness);
}

// lay them out
for(i=[0:print_count-1]){
  wc = floor(print_bed_width/(1.25*in+2)); // how many wide we can go (x axis)
  dc = floor(print_bed_depth/(1.25*in+2)); // maximum rows deep (y axis)
  pos = [i%wc, floor(i/wc),0];// grid position for this stone (x,y)
  if(i<wc*dc)
    translate(pos*(1.25*in+2)) tak_stone(piece, edge_roundness);
}

```


[User]
I'd like to design a macro lens holder for mobile devices, like phones and tablets, so I can use them as a sort of microscope. I have a few ideas on features and customizations, and I'd like it to be created using OpenSCAD if possible.

Here's the breakdown of what I'm envisioning:

**Core Functionality**

*   **Lens Holding:** The primary function, of course, is to hold a small lens. The default lens size I have in mind is around 7mm in diameter and 3.3mm in height. But I'd like this to be easily adjustable in the design, so I can adapt it for different lenses.
*   **Mounting:** The holder should have a way to be mounted to a device, ideally using rubber bands. I'd like to incorporate a design that allows for a secure, reliable attachment to the mobile device camera.
*   **Lens Spacing:** It would be nice if I could stack multiple lenses, so the design should support an optional "total lens" parameter. This would include an adjustable distance between lenses when using more than one.

**Customizable Parameters:**

I’d really love to be able to control these parameters via OpenSCAD's Customizer:

*   `lens_diameter`: The diameter of the lens (default: 7.04mm).
*   `lens_height`: The height of the lens (default: 3.3mm).
*   `lens_total`: The number of lenses to accommodate (default: 1).
*  `lens_distance`: Distance between lenses if lens_total > 1 (default: 0).
*   `lens_holder_wall_thickness`: The thickness of the lens holder walls (default: 1.6mm).
*   `rubber_band_holder_shape`:  Either `cylinder` or `prism` for the shape of the rubber band holders (default: `prism`).
*   `rubber_band_holder_height`:  Height of rubber band holders (default: 2).
*   `rubber_band_holder_width`: Width of rubber band holders (default: 8).
*   `keychain_ring`:  A boolean (`true`/`false`) option to add a keychain ring for portability (default: `true`).
*   `keychain_ring_outer_diameter`: Outer diameter of the keychain ring (default: 4.6mm).
*  `keychain_ring_inner_diameter`: Inner diameter of the keychain ring (default: 3.2mm).
*   `keychain_ring_height`: Height of the keychain ring (default: 2mm).

**Design Details:**

*   **Rounded Base:** It would look nice if the base of the lens holder had rounded corners, controllable by a `base_rounded_radius` parameter (default 0, but maybe 0.8 for a slight rounding).
*   **Keychain Ring:** If the keychain ring is enabled, it should be placed off-center from the main lens holder. I'd also like some control over the offset with a `keychain_offset` parameter.
*   **Lens Support:** The holder should have a support structure, kind of a flange to help hold the lens. I'd like control over the flange's size with a parameter called `lens_holder_support_size`.

**Libraries:**

I don't anticipate needing anything too fancy, but I think we might benefit from using the BOSL2 library, just to help with some of the more complex geometry. I think the standard OpenSCAD libraries for primitives and transformations will be enough, though, and I'd prefer to avoid introducing too much complexity.

Can you generate the OpenSCAD code for this? Let me know if you have any questions.

[Assistant]
simple-macro-lens-holder-v2_1.scad:
```
// Customizable Simple Macro Lens Holder
//
// Default parameters are for the lens:
//      Size: 7 x 3.3 mm
//      BFL : 6.47 mm
//      ELF : 8.0 mm
//
//  2016.05.18 by gsyan
//
//  update : 2016.05.22
//

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

/* [Parameters] */

//Default parameters are for the lens : Size: 7 x 3.3 mm , BFL : 6.47 mm , ELF : 8.0 mm
lens_diameter = 7.04;

lens_height = 3.3;

//Increase this value you can plug more than 1 lens
lens_total = 1;

//Lens distance adapt for lens_total > 1
lens_distance = 0;

lens_holder_wall_thickness = 1.6;

//
keychain_ring = "true"; //[true:enabled,false:disabled]

rubber_band_holder_shape = "prism"; //[cylinder:cylinder, prism:prism]
rubber_band_holder_height = 2;
rubber_band_holder_width = 8;

keychain_ring_outer_diameter = 4.6;
keychain_ring_inner_diameter = 3.2;
keychain_ring_height = 2;

/* [Hidden] */
fn = 36;
base_rounded_radius = 0; //0.8;
keychain_offset = 0.5;
lens_holder_support_size = 2.4;

module prism(l, w, h){
    polyhedron(
        points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
        faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
               );
}

module lens_holder_support() {
    resize([lens_holder_support_size+lens_diameter+lens_holder_wall_thickness/2,lens_diameter+lens_holder_wall_thickness,lens_height/2])
        cylinder(h=lens_height/2,d1=lens_holder_support_size+lens_diameter+lens_holder_wall_thickness/2,d2=lens_diameter+lens_holder_wall_thickness/2,$fn=8);
}

module ring_support() {
    difference() {
        translate([keychain_ring_outer_diameter/2-1-keychain_offset,keychain_ring_outer_diameter/2,0])
            rotate([0,0, -90])
                prism(keychain_ring_outer_diameter,1,lens_height-keychain_ring_height);

        difference() {
            translate([keychain_ring_outer_diameter/-2,keychain_ring_outer_diameter/-2-0.1,-0.1])
                cube([ keychain_ring_outer_diameter-keychain_offset+0.01,keychain_ring_outer_diameter+0.2, lens_height-keychain_ring_height+0.2]);
            translate([0,0, -0.1])            cylinder(h=keychain_ring_height+0.2, r=keychain_ring_outer_diameter/2, $fn=36);
        }

    }
}

module rubber_band_holder_cylinder() {
    union() {
        rotate(a=[90,0,0])
            cylinder(h=rubber_band_holder_width+1, d=rubber_band_holder_height, $fn=36);

        translate([0,(rubber_band_holder_width+1)*-1, rubber_band_holder_height/2-0.1])
            cube([0.1, rubber_band_holder_width+1,1]);
    }
}

module rubber_band_holder_prism() {
    resize([rubber_band_holder_height, rubber_band_holder_width+0.2, rubber_band_holder_height+0.1]) rotate([135,0,90]) prism(10, 10, 10);
}
module ring() {
    difference() {
        union() {
            cylinder(h=keychain_ring_height, r=keychain_ring_outer_diameter/2, $fn=36);
            translate([0,0,keychain_ring_height]) ring_support();
        }
        translate([0,0,-10]) cylinder(h=keychain_ring_height+20, r=keychain_ring_inner_diameter/2, $fn=36);
    }
}

module rounded(size, r) {
    //2 cube + 4 cylinder
    fn = 18;
    union() {
        translate([r, 0, 0]) cube([size[0]-2*r, size[1], size[2]]);
        translate([0, r, 0]) cube([size[0], size[1]-2*r, size[2]]);

        translate([r, r, 0]) cylinder(h=size[2], r=r, $fn=fn);
        translate([size[0]-r, r, 0]) cylinder(h=size[2], r=r, $fn=fn);
        translate([r, size[1]-r, 0]) cylinder(h=size[2], r=r, $fn=fn);
        translate([size[0]-r, size[1]-r, 0]) cylinder(h=size[2], r=r, $fn=fn);
    }
}

module base() {
    union() {
        //base : cube
        translate([0, rubber_band_holder_width/-2, 0])
        rounded([lens_diameter+lens_holder_wall_thickness+rubber_band_holder_height*4,rubber_band_holder_width, lens_height],base_rounded_radius);

        //base : cylinder
        translate([(lens_diameter+lens_holder_wall_thickness+rubber_band_holder_height*4)/2, 0, 0])
        cylinder(h=lens_height*lens_total+lens_distance*(lens_total-1), r=(lens_diameter+lens_holder_wall_thickness)/2, $fn=fn);

        //lens holder support
        if(lens_total > 1) translate([(lens_diameter+lens_holder_wall_thickness+rubber_band_holder_height*4)/2, 0, lens_height])
        lens_holder_support();

        //keychain ring
        if(keychain_ring == "true") translate([keychain_offset-keychain_ring_outer_diameter/2,0])       ring();
    }
}
module holder() {
    difference() {
        base();

        //lens hole
        translate([(lens_diameter+lens_holder_wall_thickness+rubber_band_holder_height*4)/2, 0, -0.1])
        cylinder(h=lens_height*lens_total+lens_distance*(lens_total-1)+1, r=(lens_diameter+0.2)/2, $fn=fn);

        //Ruber Band Holder hole

        if( rubber_band_holder_shape == "cylinder") {

        //left rubber band hole
        translate([rubber_band_holder_height+0.4, (rubber_band_holder_width+1)/2,lens_height-rubber_band_holder_height/2])
            rubber_band_holder_cylinder();

        //right rubber band hole
        translate([lens_diameter+lens_holder_wall_thickness+rubber_band_holder_height*3-0.4, (rubber_band_holder_width+1)/2,lens_height-rubber_band_holder_height/2])
            rubber_band_holder_cylinder();
        }
        else {

        //left rubber band hole
        translate([rubber_band_holder_width/8+0.4,rubber_band_holder_width/-2-0.1,lens_height+0.1-rubber_band_holder_height])
        rubber_band_holder_prism();

        //right rubber band hole
        translate([lens_diameter+lens_holder_wall_thickness+rubber_band_holder_height*2.5-0.4,rubber_band_holder_width/-2-0.1,lens_height+0.1-
        rubber_band_holder_height]) rubber_band_holder_prism();
        }

    }
}

holder();

```
simple-macro-lens-holder-v2.scad:
```
// Customizable Simple Macro Lens Holder
//
// Default parameters are for the lens:
//      Size: 7 x 3.3 mm
//      BFL : 6.47 mm
//      ELF : 8.0 mm
//
//  2016.05.18 by gsyan
//
//  update : 2016.05.20
//

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

/* [LENS] */

//Default parameters are for the lens : Size: 7 x 3.3 mm , BFL : 6.47 mm , ELF : 8.0 mm
lens_diameter = 7.04;

lens_height = 3.3;

lens_total = 1;

//Lens distance adapt for lens_total > 1
lens_distance = 0;

lens_holder_wall_thickness = 1.6;

/* [Ruber_Band] */

rubber_band_hole_diameter = 2;

rubber_band_holder_width = 8;

/* [Hidden] */
fn = 36;

module base() {
    union() {
        //base : cube
        translate([0, rubber_band_holder_width/-2, 0])
        cube([lens_diameter+lens_holder_wall_thickness+rubber_band_hole_diameter*3,rubber_band_holder_width, lens_height]);    //base : cylinder
        translate([(lens_diameter+lens_holder_wall_thickness+rubber_band_hole_diameter*3)/2, 0, 0])
        cylinder(h=lens_height*lens_total+lens_distance*(lens_total-1), r=(lens_diameter+lens_holder_wall_thickness)/2, $fn=fn);
    }
}
module holder() {
    difference() {
        base();

        //lens hole
        translate([(lens_diameter+lens_holder_wall_thickness+rubber_band_hole_diameter*3)/2, 0, -0.1])
        cylinder(h=lens_height*lens_total+lens_distance*(lens_total-1)+1, r=(lens_diameter+0.2)/2, $fn=fn);

        /*
        translate([(lens_diameter+lens_holder_wall_thickness+rubber_band_hole_diameter*3)/2, 0, -0.2])
        cylinder(h=lens_height, r=(lens_diameter-0.1)/2, $fn=fn);
        */

        //left rubber band hole
        translate([rubber_band_hole_diameter, (rubber_band_holder_width+1)/2, lens_height-rubber_band_hole_diameter/2]) rotate(a=[90,0,0])
        cylinder(h=rubber_band_holder_width+1, d=rubber_band_hole_diameter, $fn=36);
        translate([rubber_band_hole_diameter, (rubber_band_holder_width+1)/-2, lens_height-rubber_band_hole_diameter/2+0.5]) cube([0.1, rubber_band_holder_width+1,1]);

        //right rubber band hole
        translate([lens_diameter+lens_holder_wall_thickness+rubber_band_hole_diameter*2, (rubber_band_holder_width+1)/2, lens_height-rubber_band_hole_diameter/2]) rotate(a=[90,0,0])
        cylinder(h=rubber_band_holder_width+1, d=rubber_band_hole_diameter, $fn=36);
        translate([lens_diameter+lens_holder_wall_thickness+rubber_band_hole_diameter*2, (rubber_band_holder_width+1)/-2, lens_height-rubber_band_hole_diameter/2+0.5]) cube([0.1, rubber_band_holder_width+1,1]);
    }
}

holder();

```
simple-macro-lens-holder.scad:
```
// Customizable Simple Macro Lens Holder
// preview[view:south, tilt:top];
/* [Parameters] */
lens_diameter = 7;

holder_height = 3.5;

rubber_band_hole_diameter = 2;

/* [Hidden] */
rubber_holder_width = 8;

module base() {
    union() {
        translate([0, rubber_holder_width/-2, 0])
        cube([lens_diameter+3+rubber_band_hole_diameter*3,rubber_holder_width, holder_height]);
        translate([(lens_diameter+3+rubber_band_hole_diameter*3)/2, 0, 0])
        cylinder(h=holder_height, r=(lens_diameter+3)/2, $fn=36);
    }
}
module holder() {
    difference() {
        base();

        translate([(lens_diameter+3+rubber_band_hole_diameter*3)/2, 0, 0.2])
        cylinder(h=holder_height, r=(lens_diameter+0.2)/2, $fn=36);

        translate([(lens_diameter+3+rubber_band_hole_diameter*3)/2, 0, -0.2])
        cylinder(h=holder_height, r=(lens_diameter-0.1)/2, $fn=36);

        translate([rubber_band_hole_diameter, (rubber_holder_width+1)/2, holder_height-rubber_band_hole_diameter/2+0.01]) rotate(a=[90,0,0])
        cylinder(h=rubber_holder_width+1, d=rubber_band_hole_diameter, $fn=36);

        translate([lens_diameter+3+rubber_band_hole_diameter*2, (rubber_holder_width+1)/2, holder_height-rubber_band_hole_diameter/2+0.01]) rotate(a=[90,0,0])
        cylinder(h=rubber_holder_width+1, d=rubber_band_hole_diameter, $fn=36);
    }
}

holder();
```


[User]
Hey there, I need an OpenSCAD design for a parametric eyelet. I want to be able to attach flexible sheet material to hooks, like a PVC sheet. I’m thinking the eyelet will need a few different parts:

First, there should be a ring that goes around the actual hole in the sheet material, a bit like a grommet, but more substantial. This ring should have an adjustable height, as well as inner and outer diameter which is different between the top of the ring and the bottom, to allow for slightly tapered shapes.

Next, a base which extends from the eyelet ring. This will be the main attachment point to the flexible material, so I'd like that to also have adjustable height, and an adjustable inner and outer diameter. Again, I would like the inner and outer diameter to be different between the top of the base and bottom, to allow for slightly tapered shapes.

Then, coming out of the base, I’ll need a “hook ring” where the hook will be attached. This ring needs an adjustable height and width.

Finally, the actual hook itself. This part should start at the hook ring with a certain width, and then slightly increase in width before tapering back in at the top. I need the ability to adjust the height of the hook’s base (where it connects to the hook ring) and its middle part as well as the hook’s top, and also the width of these parts.  Also, I need to add radial splits to the design. This way, we can better customize the design depending on the hook. I want to control how many splits there are and how wide those splits should be.

I’d like the design to be fully parametric, so I can tweak all those dimensions easily. Could you generate the necessary OpenSCAD code? I don’t need any special libraries, just the standard built-in functions of OpenSCAD.

[Assistant]
v1.scad:
```
$fn=72;

eyeletRingDiameterOffset = 0.2;
eyeletRingTopWidth = 4;
eyeletRingBottomWidth = 7;
eyeletRingHeight= 2;

eyeletDiameter = 14;
outerTopWidth = 7;
outerBottomWidth = 4;
baseHeigth = 1.5;

hookRingWidth=2;
hookRingHeight=2.8;

hookTopWidth = 0.5;
hookMiddleWidth=2.4;
hookTopHeight = 0.0;
hookMiddleHeight = 0.6;

numberOfSplits = 3;
hookSplitWidth = 1;

eyelet();

module eyelet() {
		translate([eyeletDiameter+max(outerBottomWidth,outerTopWidth)+max(eyeletRingTopWidth,eyeletRingBottomWidth)+2,0,0]) {

		difference() {

			cylinder(h=eyeletRingHeight,r1=eyeletDiameter/2+hookRingWidth+eyeletRingBottomWidth,r2=eyeletDiameter/2+hookRingWidth+eyeletRingTopWidth);
					translate([0,0,-0.1]) {
						cylinder(h=eyeletRingHeight+0.2,r=eyeletDiameter/2+hookRingWidth+eyeletRingDiameterOffset);
					}
			}
		}

		//-------------------BASE
		difference() {

		cylinder(h=baseHeigth,r1=eyeletDiameter/2+outerBottomWidth,r2=eyeletDiameter/2+outerTopWidth);

			translate([0,0,-0.1]) {
				cylinder(h=baseHeigth+0.2,r=eyeletDiameter/2);
			}
		}

		difference() {
		//-------------------HOOK RING

			union() {
				translate([0,0,baseHeigth]) {
				difference() {
				cylinder(h=hookRingHeight,r=eyeletDiameter/2+hookRingWidth);

				translate([0,0,-0.1]) {
					cylinder(h=hookRingHeight+0.2,r=eyeletDiameter/2);
				}}
				}

				//-------------------HOOK

				translate([0,0,baseHeigth+hookRingHeight]) {

				difference() {
					union() {
						cylinder(h=hookMiddleHeight,r1=eyeletDiameter/2+hookRingWidth,r2=eyeletDiameter/2+hookMiddleWidth);
						translate([0,0,hookMiddleHeight]) {
						cylinder(h=hookTopHeight,r1=eyeletDiameter/2+hookMiddleWidth,r2=eyeletDiameter/2+hookTopWidth);

						}
					}
					translate([0,0,-0.1]) {
						cylinder(h=hookMiddleHeight+hookTopHeight+0.2,r=eyeletDiameter/2);
					}
				}

				}
			}

		// HOOK SPLITS

			for(pos=[0:1:numberOfSplits]) {

				rotate([0,0,(180 / numberOfSplits)*pos]) {
					translate([0,0,baseHeigth+30]) {
					cube([500,hookSplitWidth,60],true);
					}
				}
			}
		}
}

```


[User]
Hey, I'm looking to create a customizable vacuum crevice tool attachment. I'd like to be able to control a bunch of different parameters to fit various vacuum cleaners and needs.

Here's a breakdown of what I want:

**Base/Connection to Vacuum:**
*   **Base Diameter:** This should be the diameter of the vacuum cleaner pipe connection plus a bit of clearance. Let's say it's a range from 20mm to 80mm.
*   **Base Overlap:** The length of the pipe that goes *into* the vacuum cleaner hose – range from 10 to 100 mm
*   **Base Chamfer Length:** The length of the sloped section that transitions from the pipe to the nozzle – range from 20 to 100 mm.
*   **Base Thickness:**  The thickness of the base material itself – range from 0.5 to 5 mm

**Nozzle:**
*   **Nozzle Length:** The overall length of the nozzle from the base connection – range from 50 to 400 mm.
*   **Nozzle Outer A:**  The first dimension of the nozzle's rectangular cross-section – range from 4 to 120 mm
*   **Nozzle Outer B:**  The second dimension of the nozzle's rectangular cross-section – range from 4 to 120 mm
*   **Nozzle Fillet Radius:** The radius of the curves at the corners of the nozzle's rectangular cross-section– range from 1 to 60 mm
*   **Nozzle Thickness:** The thickness of the nozzle's material – range from 0.5 to 5 mm.

**Nozzle Tip Chamfer:**
*   **Nozzle Chamfer A:** The depth of the chamfer at the tip of the nozzle – range from 0 to 120 mm.
*   **Nozzle Chamfer B:** The length of the chamfer at the tip of the nozzle – range from 0 to 150 mm.

I'd like the design to:

1.  Create a cylindrical base with the specified diameter, overlap, and material thickness.
2.  Transition smoothly to the rectangular nozzle via a chamfered section.
3.  Have a rectangular nozzle with filleted corners as specified.
4.  Have a chamfered tip at the end of the nozzle.
5.  Ensure that internal dimensions are calculated based on external dimensions and thickness, so a solid object is created.

I'd also appreciate it if you could include some logic to handle edge cases:

1.  Limit fillet radius to not be greater than half the nozzle width or height.
2.  Limit base chamfer length based on total length, and avoid making the chamfer too long.
3.  Limit nozzle chamfer A based on the width of the nozzle.
4.  Limit nozzle chamfer B based on available nozzle length.

Could you generate the necessary OpenSCAD code (or multiple files, if that makes sense) to achieve this? I don't need any special libraries for this. Thanks!

[Assistant]
Customizable_Vacuum_Crevice_Tip2.scad:
```
/*----------------------------------------------------------------------------*/
/*  Created by Ziv Botzer                                                     */
/*  18.5.2016                                                                 */
/*  3.1.2017 increased maximum values                                         */
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/*-------                           SETTINGS                          --------*/
/*----------------------------------------------------------------------------*/

// Diameter of your vacuum cleaner pipe + clearance (34.6mm worked good for me)
Base_Diameter = 34.6; // [20:0.1:80]

// Length of pipe overlapping vacuum clear pipe
Base_Overlap = 30; // [10:1:100]

// Length of chamfered area between nozzle and base
Base_Chamfer_Length = 30;  // [20:1:100]

// Material thickness at base
Base_Thickness = 1.8; // [0.5:0.2:5]

// Length of nozzle, total height of model
Nozzle_Length = 140; // [50:1:400]

// First dimension of nozzle section
Nozzle_Outer_A = 16; // [4:0.5:120]

// Second dimension of nozzle section
Nozzle_Outer_B = 8; // [4:0.5:120]

// Fillet radius of nozzle section
Nozzle_Fillet_Radius = 3; // [1:0.5:60]

// Material thickness along nozzle
Nozzle_Thickness = 1.4; // [0.5:0.2:5]

// Chamfer depth of nozzle tip
Nozzle_Chamfer_A = 20; // [0:1:120]

// Chamfer length of nozzle tip
Nozzle_Chamfer_B = 20; // [0:1:150]

/////////////

/* [Hidden] */

$fn=150;

Nozzle_Inner_A = Nozzle_Outer_A - Nozzle_Thickness;
Nozzle_Inner_B = Nozzle_Outer_B - Nozzle_Thickness;

mainRadius = Base_Diameter/2;

Nozzle_Fillet_s1 = (Nozzle_Fillet_Radius < Nozzle_Outer_A/2) ? Nozzle_Fillet_Radius : Nozzle_Outer_A/2-0.5;
Nozzle_Fillet = (Nozzle_Fillet_s1 < Nozzle_Outer_B/2) ? Nozzle_Fillet_s1 : Nozzle_Outer_B/2-0.5;
echo(Nozzle_Fillet);

// trim base chamfer length depending on maximum length and overlap length
Base_Chamfer_Length_ = ((Base_Overlap + Base_Chamfer_Length + 10) < Nozzle_Length) ?
    Base_Chamfer_Length : (Nozzle_Length - Base_Overlap - 10);

// trim chamfer A at width of nozzle
Nozzle_Chamfer_A_ = (Nozzle_Chamfer_A < Nozzle_Outer_A) ? Nozzle_Chamfer_A : Nozzle_Outer_A;

// trim chamfer B at length of nozzle - cylinder
Nozzle_Chamfer_B_ = (Nozzle_Chamfer_B < Nozzle_Length - (Base_Overlap + Base_Chamfer_Length)) ? Nozzle_Chamfer_B : (Nozzle_Length - (Base_Overlap + Base_Chamfer_Length_));

// WARNINGS
if ((Nozzle_Fillet_Radius >= Nozzle_Outer_A/2) || (Nozzle_Fillet_Radius >= Nozzle_Outer_B/2)) {
    echo ("Fillet size reduced to allow rebuild");
}
if ((Base_Overlap + Base_Chamfer_Length + 10) < Nozzle_Length) {
    echo ("Base chamfer length has been shortened to allow rebuild");
}
if ((Nozzle_Chamfer_A < Nozzle_Outer_A) ||
   (Nozzle_Chamfer_B < Nozzle_Length - (Base_Overlap + Base_Chamfer_Length))) {
    echo ("Nozzle chamfer has been shortened to allow rebuild");
}

difference() {
    // positive form
    union() {
        make_base ( mainRadius + Base_Thickness, Base_Overlap + Base_Thickness, Base_Chamfer_Length_);
        make_nozzle(Nozzle_Length, Nozzle_Outer_A, Nozzle_Outer_B, Nozzle_Fillet,
                    Base_Overlap + Base_Chamfer_Length_/2);
    }

    // negative form
    union() {
        translate([0,0,-0.2]) make_base ( mainRadius, Base_Overlap, Base_Chamfer_Length_);

        translate([0,0,Nozzle_Thickness])
        make_nozzle(Nozzle_Length+10, Nozzle_Outer_A-2*Nozzle_Thickness, Nozzle_Outer_B-2*Nozzle_Thickness,
            (Nozzle_Fillet-Nozzle_Thickness <= 0) ?
            0.1 :  Nozzle_Fillet - Nozzle_Thickness,
            Base_Overlap + Base_Chamfer_Length_/2 + Nozzle_Thickness);
    }

    // trim triangle for long angle
    translate([-0.05,0,Nozzle_Length+0.01] )
      rotate([90,0,0])
      linear_extrude(Nozzle_Outer_B+1, center=true)
                    polygon( points = [[Nozzle_Outer_A/2-Nozzle_Chamfer_A_,0],
                                        [Nozzle_Outer_A/2+0.1,0],
                                        [Nozzle_Outer_A/2+0.1,-Nozzle_Chamfer_B_]] );
}

module make_base( radius, cylinder_length, chamfer_length ) {
    union() {
        linear_extrude(cylinder_length) circle (radius);
        translate([0,0,cylinder_length-0.05]) linear_extrude(chamfer_length, scale=0.1) circle (radius);
    }
}

module make_nozzle( length, a, b, filletR, offset_z ) {
    union() {
        translate([0,0,offset_z])
        linear_extrude(length-offset_z) {
            minkowski() {
                square ( [a-2*filletR, b-2*filletR], center = true);
                circle(filletR);
            }
        }

        translate([0,0,offset_z+0.1])
        rotate([0,180,0])
            linear_extrude(offset_z, scale=0.1) {
                minkowski() {
                    square ( [a-2*filletR, b-2*filletR], center = true);
                    circle(filletR);
                }
            }
    }
}

```


[User]
Hi! I'm looking to get a custom thumb spanner designed for 3D printing, specifically one that can attach to a keyring. I have a basic design in mind, similar to the provided .scad file, but I'd like to get a more refined and robust parametric version.

Here's what I'm after:

*   **Dual-Sided Spanner:** The spanner should have two different sized openings on either end.
*   **Parametric Sizing:** I need to be able to specify the edge-to-edge diameter of each opening (upper and lower) as well as the overall thickness of the tool. The provided scad file uses `upper_dia` and `lower_dia` but that's not exactly what I'd like to be able to configure, I'd prefer diameters that reflect the flats of the nuts/bolts rather than the circumscribed cylinder that the current code implements - I'd still want to be able to specify the wall thickness around the nut though, similar to the current `additional_thickness` variable.
*   **Handle:** It should have a handle section that is joined by a 'waist' or a thin portion where the key ring loop will attach.
*   **Keyring Attachment:** A loop or hole for attaching to a keyring.
*   **Thickness:** I need to be able to specify the thickness of the main body of the wrench (`handle_thickness`), and the thinner connecting sections of the handle (`handle_thickness_2`). Also, a single overall height (`height`) variable.
*   **Length:** The length of the handles (`length`).
*   **Testing Mode:** A "testing" mode that generates a cylinder for checking sizing. I'd like to also specify the test cylinder's diameter (`test_diameter`).
*   **Text labels:** I'd like to be able to label the spanner with text, either on the top and bottom or in the middle.
*   **Font:** I'd also like to specify which font to use in these labels.

I would expect the solution to be provided as one or more OpenSCAD files. Let me know if you need more information!

[Assistant]
PropSpanner_V3.scad:
```
/*
    Customizable Two-Sided Keyring Thumb Spanner

    Set the 'testing' variable to 1 and then use the test_diameter variable to help you size the edge to edge diameter (upper_dia/lower_dia) to get the correct size for your spanner. Add in some tolerance for material shrinkage.

    Try to keep the lower_dia variable as your smaller spanner to avoid needing support. Remember to add tolerance for any shrinking you get, it can be worse closer to the heated bed.

    - by Harlo
    - 22/05/2016.

        ADDING TEXT:

        *   Don't forget to add in a reference to your desired font. Use variable 'font_var' to load your desired font into all the text modules automatically.
        **  Uncomment the text modules and the cutting references if you plan on adding them in.
        *** There are two text versions/options in the wrench_outer() module. Either use both the text_8mm (lower) & text_10mm (upper) modules together OR the text_any_mm(). Avoid using both.
*/

//Set to '0' for your final render
testing = 1; //[0,1]
//Edge to Edge Length
test_diameter = 8.5; //[0.1:0.1:20]
//Main Diameter Upper - set to accomodate the tube
upper_dia = 9.8; // [0.5:0.1:30]
//Main Diameter Lower - set to accomodate the tube
lower_dia = 9.8; //[0.5:0.1:30]
//Main Handle Thickness
handle_thickness = 5; //[5:0.1:20]
//Secondary Handle Thickness
handle_thickness_2 = 10; //[0:0.1:40]
//Wall thickness (around the nut)
additional_thickness = 3; //[2:0.1:15]
//Z Height
height = 14; //[3:0.1:60]
//Length of the handle
length = 35; //[25:0.1:100]

//Internal

key_ring_dia = 4*1;
key_ring_z_scale = 1*1;
key_ring_res = 60*1;

wrench_outer();

if (testing == 1){
    test_cut_cylinder();
}

/*
module text_10mm(){
    translate([0,-(upper_dia+additional_thickness)/2,height/4]){
        rotate([270,0,180]){
            text_module("8", 4.5);
        }
    }
}

module text_8mm(){
    translate([0,-(upper_dia+additional_thickness)/2,-height/4]){
        rotate([270,0,180]){
            text_module("8", 4.5);
        }
    }
}

module text_any_mm(){
    translate([0,-(upper_dia+additional_thickness)/2,0]){
        rotate([270,0,180]){
            text_module(label, label_size);
        }
    }
}

module text_module(text_in, text_size){
    scale([1,1,0.01])
    {
        linear_extrude(h = 1, center = true, convexity = 4) {
            text (text_in, size = text_size,font = font_var, halign = "center", valign = "center", $fn = 32 );
        }
    }
}

*/

module wrench_outer(){
    difference(){
        union(){
            cylinder(h = height ,d = upper_dia + additional_thickness*2, center = true, $fn = 6);
            handles();

        }
        inner_cuts();
        key_ring_cut();
        //text_10mm(); //TOP
        //text_8mm(); //BOTTOM
        //text_any_mm(); //CENTER
    }
}

module test_cut_cylinder(){
      cylinder(h = height*2 ,d = test_diameter, center = true, $fn = 60);
}

module key_ring_cut(){
    translate([-length/2 + key_ring_dia/2.25,0,height/2 - (key_ring_dia * key_ring_z_scale)/1.25]){
        rotate([90,0,0]){
            scale([1,key_ring_z_scale,1]){
                cylinder(h = handle_thickness*2, d = key_ring_dia, center = true, $fn = key_ring_res);
            }
        }
    }

}

module handles(){
    hull(){
        translate([-length/2,0,0]){
            cylinder(h = height, d = handle_thickness, center = true, $fn = 60);
        }
        translate([length/2,0,0]){
            cylinder(h = height, d = handle_thickness, center = true, $fn = 60);
        }

        translate([0,0,2]){
            rotate([0,90,0]){
                cylinder(h = 1, d = handle_thickness_2, center = true, $fn = 4);
            }
        }
        translate([0,0,-2]){
            rotate([0,90,0]){
                cylinder(h = 1, d = handle_thickness_2, center = true, $fn = 4);
            }
        }

    }
}

module inner_cuts(){
    translate([0,0,height/2]){
        cylinder (h = height, d = upper_dia, center = true, $fn = 6);
    }

    translate([0,0,-height/2]){
        cylinder (h = height, d = lower_dia, center = true, $fn = 6);
    }
}
```


[User]
Hey! I've got this idea for a customizable spool that I want to 3D print. I've seen some cool ones that use OpenSCAD but none of them quite fit my needs.

Basically, I need a spool that's made of two halves that can be pushed together. The two halves will interlock with keyways on a central tube. I need to be able to adjust the main diameter of the spool, the central hole diameter, the width of the spool (the distance between the two plates), the thickness of the outer and inner rims, the plate thickness, and even the diameter of some small through-holes for securing the ends of wire or ribbon.

I also want some more advanced parameters. The spool has radial arms supporting the outer rim, and I need to specify how many arms there are and the angle they span. The interlocking keyways should also be configurable in number. To get a good fit, it should be possible to configure the interference between the interlocking parts. The space between the two halves when pushed together should also be a variable. And I'd like to be able to set the offset of the central axle holes from the plate edges, and the radius of a filet on the arms.

I imagine each half will have a plate and a bit of a tube section that forms the center, and it should generate an assembly of both halves next to each other on the screen for previewing.

I'm not particularly attached to any library. If there's one that makes it easier for you, then you choose it. Oh, but I do want to use `linear_extrude` and `rotate_extrude` in order to achieve the shapes, and I want to be able to use user-defined functions like `s()` and `c()` to make the math a bit simpler. I'd also like to use helper modules to organize the code.

Here's a summary of the parameters I need:

**Basic Parameters:**
*   `full_diameter`:  The overall diameter of the spool.
*   `hole_diameter`: The diameter of the center hole.
*   `winding_diameter`: The diameter the wire actually winds around (larger than the hole to allow for keyways).
*   `winding_width`: The width of the spool (distance between plates).
*   `outer_rim`: Thickness of the outer rim.
*   `inner_rim`: Thickness of the inner rim.
*   `plate_thickness`: Thickness of the end plates.
*  `through_hole_diameter`: Diameter of holes in the rims and on the axle.

**Advanced Parameters:**
*   `arms`: Number of radial arms supporting the rim.
*   `arm_arc`: The angle of each arm.
*   `keyways`: The number of keyways for interlocking.
*   `interference`: The interference fit between the two halves.
*   `inter_piece_gap`: Space between the two halves.
*   `reel_hole_edge_offset`: Offset of the axle holes from the plate edge.
*   `sector_filet_radius`: Radius of the filet on the radial arms.

Can you put together an OpenSCAD file for me?

[Assistant]
Customizable_Spool_V1.0.scad:
```
/* [Basics] */
// Diameter of the reel
full_diameter = 80;
// Diameter of the hole through the centre of the reel
hole_diameter = 10;
// Diameter of the rod that materials are wound on to.
winding_diameter = hole_diameter + 8;  // allows 4mm for keyways and keys
// The distance between the two plates
winding_width = 15;
// Thickness of the outer rim on each half of the reel
outer_rim = 5;
// Thickness of the inner rim on each half of the reel
inner_rim = 2;
// Thickness of the plates on each end of the reel
plate_thickness = 1;
// Diameter of holes for retaining spooled material can be set to zero if not required (must be smaller than the outer rim!)
through_hole_diameter = 1.5;

/* [Advanced] */
// Number of arms supporting the outer rim
arms = 3;
// The number of degrees making up each arm
arm_arc = 15;
// Number of keyways loking the two halves together (should be an odd number if through holse are required)
keyways = 3;
// Distance between interference fit surfaces
interference = 0.15;
// Space between the two halves of the reel
inter_piece_gap = 2;
// Distance from plate for the holes on the centre axle
reel_hole_edge_offset = 1;
// The radius of the filet on the radial arms of each plate
sector_filet_radius = 3;

// Constants
// Fudge factor for avoiding vertex/line/plane intersections
$fn=50 * 1;
d = 0.1 / 10;

// Radii
full_radius = full_diameter / 2;
hole_radius = hole_diameter / 2;
winding_radius = winding_diameter / 2;
half_arm = arm_arc / 2;
through_hole_radius = through_hole_diameter / 2;
mid_plate_rim_radius = full_radius - outer_rim / 2;

// Iterators
function divide_circle(divisions) = [0:360/divisions:359];
keyway_angles = divide_circle(keyways);
arm_angles = divide_circle(arms);

// Angles
keyway_angle = 360 / keyways;
arm_angle = 360 / arms;

// Functions
// Scaled sine for full radius
function s(theta, scale_factor=1) = full_radius * sin(theta) * scale_factor;
// Scaled cosine for full radius
function c(theta, scale_factor=1) = full_radius * cos(theta) * scale_factor;
// Scaled point for full radius
function p(theta, scale_factor=1) = [s(theta, scale_factor), c(theta, scale_factor)];

// Builds and extrudes a single plate
module plate() {
    // Defines the region between the inner and outer rim
    module inner(fudge=0) {
        difference() {
            circle(r=full_radius - outer_rim + fudge);
            circle(r=winding_radius + inner_rim - fudge);
        }
    }
    // Defines a through hole for the rim
    module through_hole() {
        translate([0, mid_plate_rim_radius, 0])
            circle(r=through_hole_radius);
    }

    module arms() {
        // Arms with outer radius
        difference() {
            inner(3 * d);
            // Radiused space between arms
            offset(r=sector_filet_radius) offset(r=-sector_filet_radius)
                // Space between arms
                difference() {
                    inner(2 * d);
                    // Build arms
                    intersection() {
                        inner(d);
                        for (a=arm_angles) {
                            polygon([[0, 0], p(a - half_arm, 2), p(a + half_arm, 2)]);
                        }
                    }
                }
        }
    }

    linear_extrude(height=plate_thickness)
    union() {
        difference() {
            // Outer perimiter
            circle(r=full_radius);
            // Hole perimiter
            circle(r=hole_radius);
            // Spokes cut out
            inner();
            // Through holes
            for (a=arm_angles) {
                rotate([0, 0, a])
                    through_hole();
                rotate([0, 0, a + arm_angle / 2])
                    through_hole();
            }
        }
        // Arms
        arms();
    }
}

//plate();

module centre_tube(inner) {
    mid_dia = (hole_radius + winding_radius) / 2;
    key_x_section = (winding_radius - hole_radius) / 3;
    half_x = key_x_section / 2;
    quarter_x = key_x_section / 4;

    fit = interference / 2;
    large_radius = inner ? mid_dia - fit : winding_radius;
    small_radius = inner ? hole_radius : mid_dia + fit;

    module through_hole() {
        translate([0, 0, 0])
            rotate([90, 0, 0])
                cylinder(h=large_radius + 1, r=through_hole_radius);
    }

    union() {
        difference() {
            // Outer surface
            cylinder(h=winding_width, r=large_radius);
            // Inner surface
            translate([0, 0, -1])
                cylinder(h=winding_width + 2, r=small_radius);
            if (inner) {
                // Remove key ways from outside surface
                for (a=keyway_angles) {
                    rotate([0, 0, a])
                        translate([-half_x - fit / 2, large_radius - 3 * quarter_x - fit / 2, -1])
                            cube([key_x_section + fit, key_x_section + fit, winding_width + 2]);
                }
                // Add the bevel to aid locating the keys in the keyways
                b = (large_radius - small_radius) / 2;
                translate([0, 0, winding_width - b + 2 * d])
                    rotate_extrude(convexity=10)
                        translate([-large_radius - 2 * d, 0, 0])
                            polygon([[0, 0], [0, b], [b, b]]);
            }
            // Remove threading hole from top and bottom
            translate([0, 0, winding_width - reel_hole_edge_offset])
                through_hole();
            translate([0, 0, reel_hole_edge_offset])
                through_hole();
        }
        if (!inner) {
            // Add keys to inside surface
            for (a=keyway_angles) {
                rotate([0, 0, a])
                    translate([-half_x + fit / 2, small_radius - 3 * quarter_x + fit / 2, 0])
                        cube([key_x_section - fit, key_x_section - fit, winding_width]);
            }
        }
    }
}
// centre_tube();

module half_reel(inner) {
    union() {
        plate();
        translate([0, 0, plate_thickness - d])
            centre_tube(inner);
    }
}

// Build the two halves of the reel
union() {
    half_reel(true);
    translate([full_diameter + inter_piece_gap, 0, 0])
        half_reel(false);
}

```


[User]
I need a custom transition piece for a model rocket, and I'm planning to 3D print it. I've got the basic dimensions, but I'd like a parametric OpenSCAD file so I can easily adjust things later.

Essentially, it’ll look like a cylinder, a truncated cone, and then another cylinder, all joined end-to-end. Here are the key parameters I want to control:

*   **shoulder1\_diameter:** The diameter of the first cylindrical section (where the model rocket body tube is glued onto)
*   **shoulder1\_length:** The length of the first cylindrical section
*   **transition\_diameter\_1:** The diameter of the wider end of the cone/truncated cone
*  **transition\_diameter\_2:** The diameter of the narrower end of the cone/truncated cone
*   **transition\_length:** The length of the transition section
*   **shoulder2\_diameter:** The diameter of the second cylindrical section (the other end where another tube would go)
*   **shoulder2\_length:** The length of the second cylindrical section

I'd like the resulting file to create a solid object, but I'd also like to control the wall thickness separately so I can create hollow parts or adjust for printing if needed. Let's call that parameter **wall_thickness**. I’d like to be able to set it so that wall_thickness = 0 renders a solid, not just a thin shell.

Could you please generate an OpenSCAD file for me using these parameters? I don't want to have to install any custom libraries if possible, so just the base OpenSCAD functions, please.

[Assistant]
Transition.scad:
```
// variable description
shoulder1_diameter = 65.4;
shoulder1_length = 20;
transition_diameter_1 = 66.1;
transition_length = 120;
transition_diameter_2 = 41.6;
shoulder2_diameter = 40.1;
shoulder2_length = 30;
//

$fn=150;
union(){
translate([0,0,shoulder1_length/2])cylinder(shoulder1_length,shoulder1_diameter/2,shoulder1_diameter/2,center=true);
translate([0,0,(transition_length/2 +shoulder1_length )])cylinder(transition_length,transition_diameter_1/2,transition_diameter_2/2,center=true);
translate([0,0,(shoulder1_length + transition_length + shoulder2_length/2)])cylinder(shoulder2_length,shoulder2_diameter/2,shoulder2_diameter/2,center=true);
}
```


[User]
I'd like to design a customizable tape dispenser using OpenSCAD. I want it to have a main body with a hole for the tape roll and a cutter. I'm also aiming for it to be parametric so that I can easily adjust dimensions for different tape sizes.

Here are the parameters I'd like to control:

*   **`BaseWidth`**: The width of the main box.
*   **`BaseLength`**: The length of the main box.
*   **`BaseHeight`**: The height of the main box.
*   **`OutsideLLength`**: How far the larger outer supports extend outwards from the main body.
*   **`OutsideSLength`**: How far the smaller outer supports extend outwards from the main body.
*   **`BottomThickness`**: The thickness of the base/bottom of the dispenser.
*   **`MHoleWidth`**: The width of the main hole for the tape.
*   **`MHoleLength`**: The length of the main hole for the tape.
*  **`RPole`**: The radius of the pole that holds the tape roll.

The dispenser should have a generally rectangular base, with some additional smaller boxes on top and on the sides that provide extra support. Specifically, I need 10 support structures total - five on each side, mirrored across the XZ plane. They should all extend slightly past the main base. The mirrored supports on the other side should have the same dimensions as the first 5 but should have a rotation of 180 degrees around the Z-axis. I'd like there to be a large, rectangular hole in the middle of the base to hold the tape roll. The pole that the tape sits on should be placed on top of the base and extend beyond the sides of the main body. Finally, I would like the cutter to be represented by a rectangular solid that has a slight overlap with the edges of the main hole that should be removed from the overall geometry. The pole that holds the tape should be a separate module from the main body as well. This pole should have a radius that's slightly smaller than the pole that is removed from the main geometry. I think that's everything I need for now!

[Assistant]
TapeDispenser.scad:
```
//Customizable Tape Dispenser

//Main Box Width
BaseWidth = 45;

//Main Box Length
BaseLength = 120;

//Main Box Height
BaseHeight = 50;

//Outside Large Box (How far it goes out)
OutsideLLength = 10;

//Outside Small Box (How far it goes out)
OutsideSLength = 5;

BottomThickness = 5;

//Main Hole Width
MHoleWidth = 35;

//Main Hole Length
MHoleLength = 110;

//Radius of Pole
RPole = 5;

difference(){
    //Base Cube
    union(){
        cube([BaseLength,BaseWidth,BaseHeight]);
        translate([-BaseLength/24,-OutsideSLength,0]){
            cube([20,20,40]);
        }
        translate([BaseLength/3,-OutsideLLength,0]){
            cube([20,20,30]);
        }
        translate([5*BaseLength/12,-OutsideSLength,0]){
            cube([30,20,40]);
        }
        translate([BaseLength/6,-OutsideSLength,BaseHeight/2]){
            cube([25,20,10]);
        }
        translate([BaseLength/6,-OutsideLLength,BaseHeight/2]){
            cube([10,20,25]);
        }
        translate([BaseLength/12,-OutsideLLength,0]){
            cube([15,20,35]);
        }
        translate([BaseLength/2,-OutsideLLength,BaseHeight/2]){
            cube([15,20,20]);
        }
        translate([-OutsideLLength,2*BaseWidth/9,0]){
            cube([15,10,25]);
        }
        rotate([0,0,180]){
            translate([-BaseLength,-BaseWidth, 0]){
                translate([-BaseLength/24,-OutsideSLength,0]){
                    cube([20,20,40]);
                }
                translate([BaseLength/3,-OutsideLLength,0]){
                    cube([20,20,30]);
                }
                translate([5*BaseLength/12,-OutsideSLength,0]){
                    cube([30,20,40]);
                }
                translate([BaseLength/6,-OutsideSLength,25]){
                    cube([25,20,10]);
                }
                translate([BaseLength/6,-OutsideLLength,25]){
                    cube([10,20,25]);
                }
                translate([BaseLength/12,-OutsideLLength,0]){
                    cube([15,20,35]);
                }
                translate([BaseLength/2,-OutsideLLength,30]){
                    cube([15,20,15]);
                }
                translate([-OutsideLLength,2*BaseWidth/9,0]){
                    cube([15,10,25]);
                }
            }
        }
    }
    //Main Hole
    translate([(BaseLength-MHoleLength)/2, (BaseWidth-MHoleWidth)/2,BottomThickness]){
        cube([MHoleLength,MHoleWidth,BaseHeight]);
    }
    //Pole
    translate([BaseLength/2.5, BaseWidth+OutsideLLength+100,BaseHeight/1.75]){
        rotate([90,0,0]){
        cylinder(BaseWidth+(OutsideLLength*2)+200,RPole,RPole);
        }
    }
    //Cutter
    translate([(BaseLength-MHoleLength)-0.5, (BaseWidth-MHoleWidth)/2,BaseHeight-5]){
        cube([MHoleLength,MHoleWidth,BaseHeight]);
    }
}
//Pole
translate([10, BaseWidth+OutsideLLength+10,0]){
    cylinder(BaseWidth+(OutsideLLength*2)+2,RPole-0.4,RPole-0.4);
}
```


[User]
Hey, I'm looking to create a parametric screw jack design in OpenSCAD. I've seen a few different approaches, but I'd like one that's a little more flexible. Here’s what I'm envisioning:

The screw jack should have a base, a threaded rod (or bolt), a nut, and a top.

The base should be a stepped cylinder, so it flares out at the bottom, like a truncated cone connected to a standard cylinder. I want to be able to control the diameter and height of the bottom flared part, as well as the total height of the base. I need it to have a hole through the center for the threaded rod to go through and a recess on top to fit the nut. I'll also need to control the hole size so I can adjust the fit.

The top should have two options: a flat top and a swivel top. Both should have a cylindrical base, with internal threads to screw onto the bolt. The flat top is just a cylinder with some knurling for grip on the top. The swivel top should have a hemisphere at the top, and I’d like a bit of clearance between the hemisphere and the top cylinder for smooth movement.

I want to be able to adjust the diameter and height of both top types, the size of the sphere, and the clearance.

For the knurling on the jack top, I'd like control over the number of knurls, the depth, width, and the angle.

The threaded rod (or bolt) should be a simple cylinder with the same thread dimensions, and the nut is just a standard hex nut with a hole through it. I'd like to control these dimensions too. I need to be able to specify the length of the bolt based on the base height, but I don't want to have to figure that out myself, the code should handle it.

I'm hoping for all of this to be fully parametric, so I can easily change dimensions. It needs to be able to control all of the dimensions above. It also needs to be able to selectively render individual components and all components at once. It should be written using standard OpenSCAD primitives and without external libraries.  I want to be able to use a variable to switch between rendering the entire jack, just the base, just the jack top, just the nut, or just the bolt.  I'd also like the different parts rendered in different colors when displaying all parts at once.

[Assistant]
screwJack.scad:
```
/***********************************************************************
Name ......... : screwJack.scad
Description....: Parametric Screw Jack
Author ....... : Garrett Melenka
Version ...... : V1.0 2016/05/21
Licence ...... : GPL
***********************************************************************/

//Part Display Options
part = 0; //[0:All, 1:Base, 2: Jack Top, 3: Nut, 4: Bolt]

//Settings for Jack Base
//Diameter of Jack Base
baseDiameter = 50;
//Total Height of Jack Base
baseTotalHeight = 50;
//Height of Jack base Taper
baseTaperHeight = 25;
//Base taper ratio of total base height
baseTaper = 0.5;

//Settings for Jack Top
//Diameter of Jack Top
jackTopDiameter = 20;
//Height of Jack Top
jackTopHeight = 30;
//Jack Top Option
jackTopOption = 1; //[0:Flat Jack Top, 1: Swivel Top]
swivelClearance = 1;

//Number of knurls around Knob Diameter
boltKnobKnurlNum = 20;
//Depth of knurls
boltKnobKnurlDepth = 1.5;
//Width of knurls
boltKnobKnurlWidth = 1.5;
//Angle of knurling
boltKnobKnurlAngle = 120;

//Screw Hole Scaling Factor-overside base hole to allow screw clearance
boltHoleScale = 1.1;
//Dimensions of Nut and Bolt
//Diameter of bolt
boltDiameter = 8.25;
boltLength = baseTotalHeight;
echo("required bolt length:",baseTotalHeight);

//Width of nut- measure corner to corner distance on nut
nutWidth = 14.75;
//Nut thickness- measure thickness of nut
nutThickness = 7.0;

//******************************************************************************
//Base of the Screw Jack
//******************************************************************************
module screwJackBase()
{
    difference(){
    translate([0,0,baseTaperHeight*0.5]){
    union(){
    cylinder(r1 = baseDiameter*0.5, r2=baseDiameter*0.5*baseTaper, h = baseTaperHeight, center = true);
    translate([0,0,baseTaperHeight]){
    cylinder(r = baseDiameter*0.5*baseTaper, h = baseTotalHeight - baseTaperHeight, center = true);
    }
    }
    }
    translate([0,0,baseTotalHeight-nutThickness*0.5]){

        cylinder(r=nutWidth*0.5, h = nutThickness, center = true, $fn=6);
    }

    translate([0,0,baseTotalHeight*0.5]){
    cylinder(r = boltDiameter*0.5*boltHoleScale, h = baseTotalHeight, center = true);
    }
    }

}

//******************************************************************************
//Jack Top- two options: 0-no swivel top 1: swivel top
//******************************************************************************

module jackTop()
{
    if (jackTopOption ==0)
    {
    difference(){
    cylinder(r = jackTopDiameter*0.5, h = jackTopHeight, center = false);

    cylinder(r=nutWidth*0.5, h = nutThickness, center = false, $fn=6);

     for (i = [1:1:boltKnobKnurlNum]){
    //add knurling to jack top
    rotate([0,0,360*i/boltKnobKnurlNum])
    {

        linear_extrude(height = jackTopHeight*2, center = true, twist = boltKnobKnurlAngle){
            translate([jackTopDiameter*0.5, 0,0]){
        square(size = [boltKnobKnurlDepth,boltKnobKnurlWidth], center = true);
            }
        }

        linear_extrude(height = jackTopHeight*2, center = true, twist = -boltKnobKnurlAngle){
            translate([jackTopDiameter*0.5, 0,0]){
        square(size = [boltKnobKnurlDepth,boltKnobKnurlWidth], center = true);
            }
        }
    }
    }

    }
    }
    if (jackTopOption == 1){
        difference(){
    cylinder(r = jackTopDiameter*0.5, h = jackTopHeight*0.5, center = false);

    cylinder(r=nutWidth*0.5, h = nutThickness, center = false, $fn=6);
    //add knurling to jack top
     for (i = [1:1:boltKnobKnurlNum]){

    rotate([0,0,360*i/boltKnobKnurlNum])
    {

        linear_extrude(height = jackTopHeight*2, center = true, twist = boltKnobKnurlAngle){
            translate([jackTopDiameter*0.5, 0,0]){
        square(size = [boltKnobKnurlDepth,boltKnobKnurlWidth], center = true);
            }
        }

        linear_extrude(height = jackTopHeight*2, center = true, twist = -boltKnobKnurlAngle){
            translate([jackTopDiameter*0.5, 0,0]){
        square(size = [boltKnobKnurlDepth,boltKnobKnurlWidth], center = true);
            }
        }
    }
    }

    }

    translate([0,0,jackTopHeight*0.5+jackTopDiameter*0.4*0.6])
    {
    sphere(r = jackTopDiameter*0.4);
    }

    translate([0,0,jackTopHeight*0.5 + swivelClearance]){
    %difference(){
    cylinder(r = jackTopDiameter*0.5, h = jackTopHeight*0.5, center = false);
    translate([0,0,jackTopDiameter*0.45*0.5])
        {
    sphere(r = jackTopDiameter*0.45);
    }
    }
    }

    }

}

//******************************************************************************
//Nut
//*********************************************************************************
module nut()
{
    difference(){
    cylinder(r=nutWidth*0.5, h = nutThickness, center = true, $fn=6);

    cylinder(r = boltDiameter*0.5, h=nutThickness, center = true);
    }

}

//******************************************************************************
//Bolt
//********************************************************************************
module bolt()
{

    cylinder(r=boltDiameter*0.5, h = boltLength, center = true);

    translate([0,0,boltLength*0.5]){
    cylinder(r=nutWidth*0.5, h = nutThickness, center = true, $fn=6);
    }

}

//*******************************************************************************
//Rendering and Display of Parts
//********************************************************************************
$fn = 60;
if (part == 0)
{
//Display screw jack base
screwJackBase();

//Display Nut
translate([0,0,baseTotalHeight-nutThickness*0.5]){
color("red")
nut();
}

//Display Bolt
translate([0,0,baseTotalHeight]){
color("blue")
bolt();
}

//Jack Top
translate([0,0,baseTotalHeight+boltLength*0.5-nutThickness*0.5]){
color("green")
jackTop();
}
}

if (part == 1)
{
//Display screw jack base
screwJackBase();

}

if (part == 2)
{
    //Display Jack Top
    jackTop();

}

if (part == 3)
{
    //Display screw jack base
    nut();

}

if (part == 4)
{
    //Display bolt
    bolt();

}
```


[User]
I need a parametric OpenSCAD design for a bed fixation component. This component is used to attach a bed to a linear rail in a 3D printer.

**Key Features and Dimensions:**

*   **Height:** The distance between the plate and the center of an 8mm rod should be adjustable. I'd like to be able to set this height between 10mm and 50mm, ideally with 0.5mm increments.
*   **Width:** The width should also be adjustable, ranging from 10mm to 45mm, again with 0.5mm increments.
*   **Screw Spacing:** The design should accommodate two screws for mounting. The spacing between these screws should be adjustable between 20mm and 35mm, with 0.5mm increments.
*   **Bearing Options:** This is where it gets a little more complex. I need to be able to choose between several different bearing options:
    1. A "printed bearing" option, which is essentially a cylinder with a specific pattern of indents. The cylinder has a diameter of 13mm, and the indents create a kind of gear-like shape.
    2. A 15mm bearing with no gap. This would be represented by a simple cylinder with an adjustable diameter to account for printer accuracy.
    3. A 15mm bearing with a gap. Similar to the previous option, but with four holes spaced 90 degrees apart around the circumference to accommodate small rods or filament for securing the bearing. The holes should be 1.75mm in diameter.
    4. A 15mm bearing held in place with filament. This is very similar to the prior option, but the holes are smaller - probably for aesthetic reasons.
*   **Bearing Shift Position:** I want the ability to offset the bearing's position slightly along the horizontal axis. An adjustment range of 0 to 1mm, with 0.1mm increments, would be perfect.
*   **Tolerance:** To account for variations in printer accuracy, I'd like to include a tolerance parameter. This would allow me to slightly adjust the size of the bearing hole, with a range of -0.3mm to 1mm, in 0.05mm increments.

**Shape and Structure:**

The component should have a central cylindrical part with a diameter of 41mm and an adjustable width. This cylinder connects to a rectangular base (43mm x 43mm) that is centered beneath it. The base extends down and transitions into a smaller rectangular section that houses the screws. This section should have an adjustable height (which is the primary height parameter). The bearing is located at the top, and there should be smooth transitions (using `hull()`) between the different sections.

The existing code indicates that the `dent()` function is used to create the indents for the printed bearing. Here's how it looks:

```scad
module dent(angle) {
rotate([0,0,angle]) translate([tolerance,0,0]) hull() {
translate([4.3,-0.4,0]) cylinder(d=0.5,h=width+4,center=true);
translate([4.325,0.1,0]) cylinder(d=0.5,h=width+4,center=true);
translate([6.5,0.2,0]) cylinder(d=0.5,h=width+4,center=true);
translate([6.2,2.55,0]) cylinder(d=0.5,h=width+4,center=true);
}
}
```

**Libraries:**

No specific libraries are required for this project. You can use standard OpenSCAD functions.

Could you help me design this parametric OpenSCAD file?

[Assistant]
Bed_fixation_002.scad:
```
//Set height : distance between the plate and the center of the 8mm rod
height=29.5;//[10:0.5:50]

//Set width
width=17;//[10:0.5:45]

//Screw spacing
Screw_spacing=30;//[20:0.5:35]

//What kind of bearing? or bearing mount?
bearing_option=1;//[0:printed bearing,1:15mm bearing no gap,2:15mm bearing with gap,3:15mm bearing hold with filament]
//Offset bearing position
bearing_shift_position=0;//[0:0.1:1]

//printer accuracy, positive value will add some space for bearings plug
tolerance=0;//[-0.3:0.05:1]
//definition
$fn=40;//[40:low,60:medium,100:high]

//////////////////////////////////////////////
module dent(angle) {
rotate([0,0,angle]) translate([tolerance,0,0]) hull() {
translate([4.3,-0.4,0]) cylinder(d=0.5,h=width+4,center=true);
translate([4.325,0.1,0]) cylinder(d=0.5,h=width+4,center=true);
translate([6.5,0.2,0]) cylinder(d=0.5,h=width+4,center=true);
translate([6.2,2.55,0]) cylinder(d=0.5,h=width+4,center=true);
}
}
module bearing(a) {
    if(a==0) {
        difference() {
            cylinder(d=13,h=width+2,center=true);
            for (i=[0:360/9:360-360/9]) dent(i);
        }
    }

    else if(a==1) {
        cylinder(d=15+2*tolerance,h=width+2,center=true);
    }

    else if(a==2) {
        difference() {
            cylinder(d=15+2*tolerance+2,h=width+2,center=true);
            for (i=[45:90:315]) rotate([0,0,i]) translate([7.5+tolerance+1.75/2,0,0]) cylinder(d=1.75,h=width+2+2,center=true);
            }
    }

    else if(a==3) {
        cylinder(d=15+2*tolerance+1,h=width+2,center=true);
        for (i=[45:90:315]) rotate([0,0,i]) translate([7.5+tolerance+1.25/2,0,0]) cylinder(d=1.75,h=width+2+2,center=true);
    }
}

module Common_part() {
    difference() {
        union() {
            difference() {
                translate([0,10,0]) cylinder(d=41,h=width,center=true);
                translate([0,43/2+10,0]) cube([43,43,width+2],center=true);
            }
            translate([0,5+height/2,0]) cube([41,height-10,width],center=true);
        }
        hull() {
            for (i=[17.75,17.75+height]) translate([0,i,0]) scale([1,0.9,1]) cylinder(d=15,h=width+2,center=true);}

        for(i=[Screw_spacing/2,-Screw_spacing/2]) translate([i,-2.5,0]) rotate([90,0,0]) rotate([0,0,0]) cylinder(d=6.5,h=14,$fn=6,center=true);
        for(i=[Screw_spacing/2,-Screw_spacing/2]) translate([i,-2.5,0]) rotate([-90,0,0]) cylinder(d=3.4,h=height+5);

    }

}

difference() {
    Common_part();
    translate([bearing_shift_position,0,0]) bearing(bearing_option);
}

```


[User]
Okay, I'm looking to create a cylindrical pen holder design using OpenSCAD, and I'd like it to have some unique features. The pen holder should be customizable in terms of size and thickness, and I want to incorporate text and symbols onto its surface.

Here's a breakdown of what I envision:

**Basic Structure:**

*   The pen holder will be a cylinder with a hollow interior for holding pens.
*   The height, radius, and wall thickness of the cylinder should be customizable parameters.
*   It will have a closed bottom, but the top will be open.

**Aesthetic Features:**

*   **Text on the Surface:** I want to be able to wrap text around the outer surface of the cylinder. The text should be readable when looking at the cylinder from the side. I need support for lengthy text input that may include multiple lines.
*   **Chinese Characters:** The text should be able to handle Chinese characters as well as English.
*   **Symbol at the Bottom:** On the bottom surface of the pen holder, I want to have a customizable symbol or short text phrase (kind of like a logo).
*   **Author:** Somewhere on the bottom or side, there should be a place to inscribe the author's name (or a short phrase).

**Advanced Features:**

*   **Chamfered Edges:** I'd like the top and bottom edges of the cylinder to have chamfered or rounded edges. This will make the design look more polished and less sharp.
*   **Dividing Lines:** Between each line of text, I want to have a thin, horizontal line that wraps around the cylinder. These lines will help to visually separate the text.
*   **Inner Wall:** I would like to have the option to add an inner wall to the cylinder with a custom thickness. This would be good for providing additional strength or creating a double-walled structure.
*   **Custom Fonts:** I would like to be able to specify the font used for the text and the symbol. For Chinese text, it would be great to support the "AdobeFanHeitiStd-Bold" or "Noto Sans CJK TC" font. For other text, a simple font like "Courier New" or "Verdana" would be fine.

**Libraries:**

*   This design may require the use of the MCAD library.

Could you help me create a parametric OpenSCAD file that implements these features? I want to be able to customize the text, symbol, dimensions, and other features easily. I want the ability to generate an interesting design similar to the one implemented in `penbox.scad`.

[Assistant]
penbox.scad:
```
button_symbol = "Strange sentence";
button_author = "gugod" ;
fn_c = 30;

//characters = "【摩訶般若波羅密多心經】觀自在菩薩，行深般若波羅蜜多時。照見五蘊皆空，渡一切苦厄。舍利子，色不異空，空不異色，色即是空，空即是色，受想行識，亦復如是。舍利子，是諸法空相，不生不滅，不垢不淨，不增不減。是故空中無色，無受想行識，無眼耳鼻舌身意，無色聲香味觸法，無眼界，乃至無意識界。無無明，亦無無明盡，乃至無老死，亦無老死盡。無苦集滅道，無智亦無得。以無所得故，菩提薩埵，依般若波羅蜜多故，心無罣礙，無罣礙故，無有恐怖，遠離顛倒夢想，究竟涅槃。三世諸佛，依般若波羅蜜多故，得阿耨多羅三藐三菩提。故知般若波羅蜜多，是大神咒，是大明咒，是無上咒，是無等等咒，能除一切苦，真實不虛。故說般若波羅蜜多咒，即說咒曰：揭諦揭諦，波羅揭諦，波羅僧揭諦，菩提薩婆訶。";
characters = "話說我又忘了收衣服了 衣服好可憐,孤怜怜地晾了好幾天 主人渡假時，答錄機的紅燈 很少人經過的路上，的閃光紅燈 三十天沒被attach的screen 四十年沒被想過的老人 幾百年沉在河底的戒指 在第10集結束時,主角的飛踢還沒落下,可是一直都沒有出現的第11集 被上升氣流排擠而到角落的氧氣 被早上六點客人叫醒的吉野家店員 趟在收銀機裡三個星期無法找開的二百元紙鈔 很久沒被karma的keyword生鏽機關槍,斷電的插頭 ";
thickness = 3 ;

inner_wall = "YES";
google_font = "AdobeFanHeitiStd-Bold";//"Noto Sans CJK TC:style=Black";

function PI() = 3.14159;

// Given a `radius` and `angle`, draw an arc from zero degree to `angle` degree. The `angle` ranges from 0 to 90.
// Parameters:
//     radius - the radius of arc
//     angle - the angle of arc
//     width - the width of arc
module a_quarter_arc(radius, angle, width = 1) {
    outer = radius + width;
    intersection() {
        difference() {
            offset(r = width) circle(radius, $fn=fn_c);
            circle(radius, $fn=fn_c);
        }
        polygon([[0, 0], [outer, 0], [outer, outer * sin(angle)], [outer * cos(angle), outer * sin(angle)]]);
    }
}

// Given a `radius` and `angle`, draw an arc from zero degree to `angle` degree. The `angle` ranges from 0 to 360.
// Parameters:
//     radius - the radius of arc
//     angle - the angle of arc
//     width - the width of arc
module arc(radius, angles, width = 1) {
    angle_from = angles[0];
    angle_to = angles[1];
    angle_difference = angle_to - angle_from;
    outer = radius + width;
    rotate(angle_from)
        if(angle_difference <= 90) {
            a_quarter_arc(radius, angle_difference, width);
        } else if(angle_difference > 90 && angle_difference <= 180) {
            arc(radius, [0, 90], width);
            rotate(90) a_quarter_arc(radius, angle_difference - 90, width);
        } else if(angle_difference > 180 && angle_difference <= 270) {
            arc(radius, [0, 180], width);
            rotate(180) a_quarter_arc(radius, angle_difference - 180, width);
        } else if(angle_difference > 270 && angle_difference <= 360) {
            arc(radius, [0, 270], width);
            rotate(270) a_quarter_arc(radius, angle_difference - 270, width);
       }
}

// It has the same visual effect as `cylinder_character`, but each character is created by the `text` module. Use this module if your `arc_angle` is small enough and you want to render a model quickly.
// Parameters:
//     character - 3D character you want to create
//     arc_angle - angle which the character go across
//     radius - the cylinder radius
//     font - the character font
//     thickness - the character thickness
//     font_factor - use this parameter to scale the calculated font if necessary
module fake_cylinder_character(character, arc_angle, radius, font = "Courier New:style=Bold", thickness = 1, font_factor = 1) {

    half_arc_angle = arc_angle / 2;
    font_size = 2 * radius * sin(half_arc_angle) * font_factor;

    translate([radius - 0.2, -0.5, 0])
    rotate([90, 0, 90])
    linear_extrude(thickness)
    text(character, font = font, size = font_size, halign = "center");
}

// Create a character tower for chinese. It uses the font "微軟正黑體:style=Bold". If you want to print it easily, set the `inner_wall` parameter to `"YES"`. It will add an inner wall with the thickness of the half `thickness` value.
// Parameters:
//     symbol - the bottom symbol
//     characters - the characters around the tower
//     thickness - the character thickness
//     inner_wall - `"YES"` will add an inner wall with the thickness of the half `thickness` value.
// Create a character tower for chinese. It uses the font "微軟正黑體:style=Bold". If you want to print it easily, set the `inner_wall` parameter to `"YES"`. It will add an inner wall with the thickness of the half `thickness` value.
// Parameters:
//     symbol - the bottom symbol
//     characters - the characters around the tower
//     thickness - the character thickness
//     inner_wall - `"YES"` will add an inner wall with the thickness of the half `thickness` value.
module penbox_with_chinese_characters(symbol, characters, thickness = 1, inner_wall = "NO") {
    radius = 50;

    characters_of_a_circle = 30;
	arc_angle = 360 / characters_of_a_circle;

    half_arc_angle = arc_angle / 2;
    font_size = 2.2 * radius * sin(half_arc_angle);
    z_desc = font_size / characters_of_a_circle;

    max_height  =   z_desc * len(characters) + font_size * 1.5 ;

   union(){
        //  圓桶
        difference() {
            rotate([0,0,6])translate([0, 0, 0])
            linear_extrude(max_height)
            circle(radius, $fn=fn_c);

            translate([0, 0, thickness])
            linear_extrude(max_height - thickness + 0.1)
            circle(radius - thickness, $fn=fn_c);

            /* 簽名 */
            translate([0, -font_size / 2 - 1, thickness - 0.5])
                linear_extrude(thickness)
                    text(symbol,
                        font = "Verdana",
                        size = font_size / 2,
                        halign = "center",
                        valign = "center");

            translate([0, font_size / 2 + 1, thickness - 0.5])
                linear_extrude(thickness)
                    text(button_author,
                        font = "Verdana",
                        size = font_size / 2 ,
                        halign = "center",
                        valign = "center");

            //  外部倒角
            difference() {
                rotate_extrude(convexity=10,$fn=fn_c)
                    translate([radius,0,0])
                        square(thickness*4,true);

                translate([0,0,thickness*2])
                    rotate_extrude(convexity=10,$fn=fn_c)
                        translate([radius-thickness*2,0,0])
                            circle(thickness*2,$fn=fn_c) ;
            }

            //  分隔線
            for(i = [0 : len(characters) + characters_of_a_circle - 2]) {
                translate([0, 0, max_height - z_desc * i - 0.7])
                    rotate([-2, 0, i * arc_angle])
                        linear_extrude(0.6)
                            arc(radius - thickness * 0.2,
                                [0, arc_angle + half_arc_angle],
                                thickness);
            }

            //  文字
            for(i = [0 : len(characters) - 1]) {
                translate([0, 0, max_height - font_size - z_desc * i + 3])
                    rotate([0, 0.6, i * arc_angle])
                        fake_cylinder_character(characters[i],
                            arc_angle,
                            radius - thickness * 0.25 ,
                            font = google_font,
                            thickness = thickness / 2,
                            font_factor = 0.65);
            }
        }
        //  內部倒角
        difference() {
            translate([0,0,thickness*1.5])
                rotate_extrude(convexity=10,$fn=fn_c)
                    translate([radius-thickness*1.5,0,0])
                        square(thickness,true);

            translate([0,0,thickness*2])
                rotate_extrude(convexity=10,$fn=fn_c)
                    translate([radius-thickness*2,0,0])
                        circle(thickness,$fn=fn_c) ;
        }
    }
}

penbox_with_chinese_characters(button_symbol, characters, thickness, inner_wall = inner_wall);

```