Add bowden adapters for Greg's extruder + J-Head

gInnerGuide = 19;  // distance from top of hotend hole to bottom of bearings
gMountRad = 17/2;  // normally 16 for J-Head
gBoltSpacing = 25;  // each from center

gExtruderInset = 11;  // Bottom of extruder to top of hotend hole
gHotendInset = 4.5;  // Size of J-Head above lasercut part
gHotendGuide = 6;  // Top of J-Head to top of PTFE liner (where hollow setscrew is)

gMountsThick = 6;
gMountsWide = 10;
gHalfWidth = gMountsWide / 2;

// For McMaster 51055K972 (1/4" NPTF)
// slightly less than the screw thread on coupler
gScrewableInnerRad = 6.5+0.1;
// outer-inner=wall
gScrewableOuterRad = gScrewableInnerRad + 2.1;

gInnerTubeRadClearance = 2; // If using a 2-part liner, size of hole to let inner through

// TODO single layer bridging at bottom of gap
// TODO optional trap nuts on hotend side
// TODO tighten up mounting holes (they're loose on M4)
// TODO extend depth of screwable part (seems to bottom out about 1mm shy)

module PushFitting(screwDepth=14, screwRad=6.75, hexTall=6.3, hexShort=17.18/2, roundTall=3.3, roundRad=16.64/2,
    secondRad=14.5/2, secondTall=2, thirdRad=10/2, thirdTall=1.5) {
  difference() {
    union() {
      cylinder(r=hexShort/cos(30), h=hexTall, $fn=6);
      cylinder(r=roundRad, roundTall+hexTall, $fn=100);
      cylinder(r=secondRad, roundTall+hexTall+secondTall);
      cylinder(r=thirdRad, roundTall+hexTall+secondTall+thirdTall);
      translate([0,0,-screwDepth])
        cylinder(r=screwRad, h=screwDepth+1, $fn=100);
    }
    translate([0,0,-50]) cylinder(r=6.3/2, h=100);
  }
}

module CenteredRoundedCube(xyz, r=3) {
  hull() {
    for(x_scale=[-1,1])
      for(y_scale=[-1,1])
        translate([xyz[0]/2*x_scale, xyz[1]/2*y_scale, 0])
          cylinder(r=r, h=xyz[2]);
  }
}

module ExtruderMount(outerRad=false, zOffset=0) {
  difference() {
    union() {
      CenteredRoundedCube([gBoltSpacing*2+gHalfWidth*2, gMountsWide, gMountsThick], $fn=25);
      cylinder(r=gScrewableOuterRad, h=17+zOffset); // 1mm more than usual
      if(zOffset > 0) {
        cylinder(r=outerRad, h=zOffset);
        translate([0,0,zOffset])
          cylinder(r1=outerRad, r2=gScrewableOuterRad, h=outerRad-gScrewableOuterRad);
      }
    }
    translate([0,0,zOffset]) {
      translate([0,0,2]) cylinder(r=gScrewableInnerRad, h=15.1);
      translate([0,0,-50]) cylinder(r=gInnerTubeRadClearance, h=100, $fn=12);
    }
    for(x_scale=[-1,1])
      translate([gBoltSpacing*x_scale, 0, -1])
        cylinder(r=5/2, h=100);
  }
}

module HotendMount() {
  difference() {
    ExtruderMount(outerRad=gMountRad+4, zOffset=gHotendInset+2);
    translate([0,0,-1]) cylinder(r=gMountRad, h=gHotendInset+1, $fn=100);
  }
}

ExtruderMount();
translate([0,30,0]) HotendMount();

error: pathspec 'bowden/bowden.scad' did not match any file(s) known to git


Undo transparency of microusb connector

Undo transparency of microusb connector

/*
    Vitamin: MicroUSB
    Model of a Micro USB receptacle

    TODO: Add different types of Micro USB Connectors

    Derived from: http://www.farnell.com/datasheets/1693470.pdf

    Authors:
        Jamie Osborne (@jmeosbn)

    Local Frame:
        Part width is in x+ (meeting PCB edge), depth is through center in y+

    Parameters:
        None

    Returns:
        Model of a Micro USB receptacle (SMT)
*/

module MicroUSB_Receptacle() {
    // dimensions for micro usb header
    // http://www.farnell.com/datasheets/1693470.pdf
    depth  = 5.3;
    width  = 7.5;
    height = 2.8;
    flange = 7.8;                 // width of front flange
    offset  = 2.15 + 0.6 - 1.45;  // distance to overhang board edge

    color(Grey90)
    linear_extrude(height) {
        translate([0, offset - depth/2, 0])
            square(size=[flange, depth], center=true);
    }
}

/*
    Vitamin: MicroUSB
    Model of a Micro USB receptacle

    TODO: Add different types of Micro USB Connectors

    Derived from: http://www.farnell.com/datasheets/1693470.pdf

    Authors:
        Jamie Osborne (@jmeosbn)

    Local Frame:
        Part width is in x+ (meeting PCB edge), depth is through center in y+

    Parameters:
        None

    Returns:
        Model of a Micro USB receptacle (SMT)
*/

module MicroUSB_Receptacle() {
    // dimensions for micro usb header
    // http://www.farnell.com/datasheets/1693470.pdf
    depth  = 5.3;
    width  = 7.5;
    height = 2.8;
    flange = 7.8;                 // width of front flange
    offset  = 2.15 + 0.6 - 1.45;  // distance to overhang board edge

    color(Grey90, 0.3)
    linear_extrude(height) {
        translate([0, offset - depth/2, 0])
            square(size=[flange, depth], center=true);
    }
}


new carriage

new carriage

use <hardware.scad>;

// screw(length, nutpos, washer, bearingpos = -1)
//holderflat();
//m3bolt();

//capture_hollow();
//card();
//support();
tray();
module lmb6uu(){
    // with rod
    difference(){
        union(){
            cylinder(r=3.1, h=70, $fn=28, center=true);
            cylinder(r=6.1, h=19, $fn=64, center=true);
        }
        // rings on the bearing:
        for (i=[1,-1]){
            translate([0,0,19/4*i])
                difference(){
                    cylinder(r=6.15, h=1.1, $fn=64, center=true);
                    cylinder(r=5.6, h=1.1, $fn=64, center=true);
                }
            }
        }
}

module captured_drive(sep_from_lmb=22.1/2+6.1+1, nutht=7){
    // with two nuts
    screwsize = 5/16 * 25.4;
    echo("separation between centers of screw-nuts and lmb", sep_from_lmb);
    translate([0, sep_from_lmb, 35]){
        screw(70, 35-10.5, 0, bearingpos = -1, $fn=24);
        screw(70, 35+7.5, 0, bearingpos = -1);
    }
}

module holderflat(){
    translate([0,0,-12])
    linear_extrude(height=21.45){
            minkowski(){
                circle(r=2, $fn=36);
                translate([0,10,0])
                    square([18, 40], center=true);
            }
        }
}

module m3bolt(length=18){
    cylinder(r=1.62, h=length, $fn=24, center=true);
    translate([0,0,-length/2])
        cylinder(r=5.8/2, h=2.8, $fn=6, center=false);
    translate([0,0,length/2-2.8])
        cylinder(r=5.8/2, h=2.8, $fn=6, center=false);
}

module rivits(a=8, b=28, l=24.1){
    for (i=[1,-1]){
        rotate([0,90,0]) translate([5*i+1,b,0])
            #m3bolt(length=l);
        rotate([0,90,0]) translate([5*i+1,a,0])
            #m3bolt(length=l);
    }
}

module capture_hollow(){
    difference(){
        holderflat();
        #lmb6uu();
        #cube([1.5, 25, 24.5], center=true);
        #captured_drive();

        rotate([0,90,0]) translate([0,-9,0])
            #m3bolt(length=22.1);
        rivits(a=8, b=28, l=24.1);
    }
}
module card(x=63, y=87.97, curve=2.98, h=17.89/58){
    linear_extrude(height=h){
        minkowski(){
            square([x-curve*2, y-curve*2], center=true);
            circle(r=curve, $fn=36);
        }
    }
    //test size
    #translate([0,0,-1]) square([x, y], center=true);
}

module support(l= 110, thk=23.4, sections=4, gap=1.5){
    dsqr=(l/sections)+gap;
    start=l/sections;
    intersection(){
        translate([-l/2,0,40]) scale([2.5,1,1])
            sphere(r=l/2);
        difference(){
            cube([l+gap*(sections), l+gap*(sections), start-.05], center=true);
            for (i=[0:dsqr:l], j=[-2:2]){
                translate([i - l/2, j*dsqr, 0])
                    cube([start, start, start], center=true);
            }
        }
    }
}

module tray(){
    translate([0, 90, 0])
        card(h=1.2);
    support();
}

error: pathspec 'CardStack/bolt_carriage.scad' did not match any file(s) known to git


Spaces around operators and after comma

Spaces around operators and after comma

/*  text on ....
    This is a rework of version 3 of write.scad to use the new OpenSCAD internal text() primitive.
    All credit to Harlan Martin (harlan@sutlog.com) for his great effort on the original.
    Great thanks to t-paul (and the OpenSCAD dev team) on adding the new text() primitive.
*/

/*
The arguments to be provided for each function are explictly in the modules.

All modules take close to all the arguments to text() [Not all features are supported in all text_on_object() modules though -- try them out warnings will be given if it is not supported]

text() params:
t
size
spacing
font
direction -- ltr, ttb, btt or rtl
language
script
halign -- left, right or center
valign -- baseline, bottom, top or center

All modules also take the additional arguments:
extrusion_height = depth of the letter, i.e. how far it sits proud
rotate
center //center the text at the location it is being written (NOT that the object is centered)

ALL faux-objects that the text is applied to have center=true
TODO: object_center=true/false (already done for cylinder)

The above arguemnts can be seen in text_extrude() as all modules call that module evetually (often multiple times).

locn_vector -- Where the faux-object has been translated to. TODO: Rename object to translate_vector?

Additional arguments for text_on_cube():

Additional arguments for text_on_cylinder():

Additional arguments for text_on_circle():

Additional arguments for text_on_sphere():

*/

// These control the default values for text_extrude(), text_on_sphere(), text_on_cube(), text_on_cylinder(), text_on_circle()
// if the arguments are not included in the call to the module.

// Defaults
// Defaults for all modules
default_t = "text_on";
default_size = 4; //TODO - Can we make this 10?? To match internal size? There is an underlying value in text() -- This masks that.
default_font = "Liberation Mono";
default_spacing = 1; //Spacing between characters. There is an underlying value in text() -- This masks that. We try and match it here.
default_rotate = 0; // text rotation (clockwise)
default_center = true; //Text-centering
default_scale = [1,1,1];
default_extrusion_height = 2; //mm letter extrusion height

//Defaults for Cube
default_cube_face = "front";     // default face (top,bottom,left,right,back,front)
default_sphere_rounded = false;     //default for rounded letters on text_on_sphere
default_cube_updown = 0; //mm up (-down) from center on face of cube
default_cube_rightleft = 0;         //mm right(-left) from center on face of cube

//Defaults for Sphere
default_sphere_northsouth = 0;
default_sphere_eastwest = 0;
default_sphere_spin = 0; //TODO:Different to rotate? or up/down. Better name?

//Defaults for Cylinder (including circle as it is on top/bottom)
default_circle_middle = 0;      //(mm toward middle of circle)
default_circle_ccw = false;  //write on top or bottom in a ccw direction
default_circle_eastwest = 0;
default_cylinder_face = "side";
default_cylinder_updown = 0;

//Internal values - don't play with these :)
//This is much more accurate than the PI constant internal to Openscad.
internal_pi = 3.1415926535897932384626433832795028841971693993751058209;
internal_pi2 = internal_pi * 2;

//Internal values - You might want to play with these if you are using a proportional font
internal_space_fudge = 0.80; //Fudge for working out lengths (widths) of strings

debug = true;

//---- Helper Functions ----
//String width (length from left to right or RTL) in OpenSCAD units
//NOTE: These are innacurate because we don't know the real spacing of the chars and so have to approximate
//They work for monospaced (fixed-width) fonts well
function width_of_text_char( size, spacing ) = (size * internal_space_fudge * spacing);
function width_of_text_string_num_length(length, size, spacing) = ( width_of_text_char( size, spacing ) * (length));
function width_of_text_string( t, size, spacing ) = ( width_of_text_string_num_length(len(t), size, spacing) );

function cylinder_center_adjusted_top( height, center ) = (center==true) ? height / 2 : height;
function cylinder_center_adjusted_bottom( height, center ) = (center==true) ? height / 2 : 0;

//Angle that measures width of letters on perimeter of a circle (and sphere and cylinder)
function rotation_for_character(size, spacing, r, rotate = 0) = ( width_of_text_char( size, spacing ) /(internal_pi2 * r)) * 360 * (1 - abs(rotate) / 90);

//Rotate 1/2 width of text if centering
//One less -- if we have a single char we are already centred..
function rotation_for_center_text_string( t, size, spacing, r, rotate, center) = (center) ? (width_of_text_string_num_length( len(t) - 1, size, spacing ) / 2 / (internal_pi2 * r) * 360) : 0;

//Rotate according to rotate and if centred text also 1/2 width of text
function rotation_for_center_text_string_and_rotate( t, size, spacing,r,rotate,center) = ((center) ? (width_of_text_string( t, size, spacing ) / 2 / (internal_pi2 * r) * 360) : 1) * (1 - abs(rotate) / 90);

//---- Text on Object Functions ----
//Text on the top or side of a cylinder.
//Supports writing on normal and slanty cylinders
//cylinder(h,r,center)
//cylinder(h,r1,r2,center)
module text_on_cylinder(t = default_t,
                        //Object-specific
                        locn_vec = [0,0,0],
                        r,
                        r1,
                        r2,
                        h,
                        face = default_cylinder_face,
                        updown = default_cylinder_updown,
                        rotate = default_rotate,
                        eastwest = default_circle_eastwest,
                        middle = default_circle_middle,
                        ccw = default_circle_ccw,
                        cylinder_center = false, //if the cylinder object we are writing on is center==true
                        //TODO: add rounded

                        //All objects
                        extrusion_height = default_extrusion_height,
                        center = default_center,
                        //All objects -- arguments as for text()
                        font = undef,
                        size = default_size,
                        direction = undef,
                        halign = undef,
                        valign = undef,
                        language = undef,
                        script = undef,
                        spacing = default_spacing
){
//    echo (str("text_on_cylinder:There are " ,len(t) ," letters in t" , t));
//    echo (str("text_on_cylinder:","h" , h));
//    echo (str("text_on_cylinder:","r=" , r));
//    echo (str("text_on_cylinder:","r1=" , r1));
//    echo (str("text_on_cylinder:","r2=" , r2));

    if((halign != undef) || (halign != undef))
    {
        echo (str("text_on_cylinder:","WARNING " , "halign and valign are NOT supported."));
    }

    rtl_sign = (direction == "rtl") ? -1 : 1;
    if ((face == "top") || (face == "bottom")){
        //Work on a circle
        locn_offset_vec = (face == "top" ) ? [0, 0, cylinder_center_adjusted_top(h, cylinder_center)] : [0, 0, cylinder_center_adjusted_bottom(h, cylinder_center)];
        rotation_angle = (face == "top" ) ? 0 : 180;
        int_radius = (r == undef) ? ((face == "top" ) ? r2 : r1 ) : r;  //Use the top/bottom radius for slanty-cylinders
        rotate(rotation_angle, [1, 0, 0])
        text_on_circle(t,
                locn_vec + locn_offset_vec,
                r = int_radius-size,
                font = font,size=size,
                spacing = spacing,
                direction = direction,
                language = language,
                script = script,
                halign = halign,
                valign = valign,
                extrusion_height = extrusion_height,
                rotate = rotate,
                eastwest = eastwest,
                middle = middle,
                ccw = ccw);
    }else{
        if((middle != undef) && (middle != default_circle_middle))
        {
            //TODO: Which others?
            //TODO: Which side things aren't supported on the circle
            echo (str("text_on_cylinder:","WARNING " , "middle NOT supported for the SIDE of a cylinder."));
        }
        //Work on the side
        locn_offset_vec = (cylinder_center == true) ? [0, 0, 0] : [0, 0, h / 2];
        rotate(-rtl_sign * rotation_for_center_text_string_and_rotate(t, size, spacing, r, rotate, center), [0, 0, 1])
        translate(locn_vec + locn_offset_vec)
        __internal_text_on_cylinder_side(t,
                locn_vec,
                r = r,
                h = h,
                r1 = r1,
                r2 = r2,
                cylinder_center = cylinder_center,
                center = center,
                font = font,
                size = size,
                spacing = spacing,
                direction = direction,
                language = language,
                script = script,
                halign = halign,
                valign = valign,
                extrusion_height = extrusion_height,
                rotate = rotate,
                face = face,
                updown = updown,
                eastwest = eastwest);
    }
}

//circle(r)
module text_on_circle(t = default_t,
                      //Object-specific
                      locn_vec = [0, 0, 0],
                      r,
                      eastwest = default_circle_eastwest,
                      middle = default_circle_middle,
                      ccw = default_circle_ccw,

                      //All objects
                      extrusion_height = default_extrusion_height,
                      rotate = default_rotate,
                      center = default_center,

                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef,
                      valign = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
){
//    echo (str("text_on_circle:","There are " ,len(t) ," letters in t" , t));
//    echo (str("text_on_circle:","rotate=" , rotate));
//    echo (str("text_on_circle:","eastwest=" , eastwest));

    if((halign != undef) || (halign != undef))
    {
        echo (str("text_on_circle:","WARNING " , "halign and valign are NOT supported."));
    }

    ccw_sign = (ccw == true) ? 1 : -1;
    rtl_sign = (direction == "rtl") ? -1 : 1;
    ttb_btt_inaction = (direction == "ttb" || direction == "btt") ? 0 : 1;
    rotate_z_outer = -rotate + ccw_sign * eastwest;
    rotate_z_inner = -rtl_sign * ccw_sign * ttb_btt_inaction * rotation_for_center_text_string(t, size, spacing, r-middle, rotate, center);
    rotate( rotate_z_outer, [0, 0, 1] )
    rotate( rotate_z_inner, [0, 0, 1] )
    translate(locn_vec)
    for (l = [0 : len(t) - 1]){
        //TTB/BTT means no per letter rotation
        rotate_z_inner2 = -ccw_sign * 90 + ttb_btt_inaction * rtl_sign * ccw_sign * l * rotation_for_character(size, spacing, r - middle, rotate = 0);   //Bottom out=-270+r
        //TTB means we go toward center, BTT means away
        vert_x_offset = (direction == "ttb" || direction == "btt") ? (l * size * ((direction == "btt") ? -1 : 1)) : 0;
        rotate( rotate_z_inner2, [0, 0, 1] )
        translate([r - middle - vert_x_offset, 0, 0])
        rotate(-ccw_sign * 270, [0, 0, 1]) // flip text (botom out = -270)
        text_extrude(t[l],
                center = true,
                font = font,
                size = size,
                rotate = undef,
                spacing = spacing,
                direction = undef, //We don't pass direction ( misaligns inside text() ). TODO: Investigate why
                language = language,
                script = script,
                halign = halign,
                valign = valign,
                extrusion_height = extrusion_height);
    }
}

//Only expected to be called from another function. No defaults as expected to be done in parent.
//NOTE: This is hacked. Requires more mathematics than I feel like to do properly today....
//TODO: Refactor the two operations - side of normal and slanty
//No default checks in this funciton -- done in parent
module __internal_text_on_cylinder_side(t = default_t,
                      //Object-specific
                      locn_vec = [0,0,0],
                      r,
                      r1,
                      r2,
                      h,
                      cylinder_center,

                      //All objects
                      extrusion_height = default_extrusion_height,
                      center = undef,
                      rotate = default_rotate,

                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef, //Overridden
                      valign = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
)
{
//    echo (str("__internal_text_on_cylinder_side:There are " ,len(t) ," letters in t" , t));
//    echo (str("__internal_text_on_cylinder_side:","h=" , h));
//    echo (str("__internal_text_on_cylinder_side:","r=" , r));
//    echo (str("__internal_text_on_cylinder_side:","r1=" , r1));
//    echo (str("__internal_text_on_cylinder_side:","r2=" , r2));
//    echo (str("__internal_text_on_cylinder_side:","direction=" , direction));

    if((halign != undef) || (halign != undef))
    {
        echo (str("text_on_cylinder:","WARNING " , "halign and valign are NOT supported."));
    }

    wid = width_of_text_char( size, spacing ); //TODO: refactor this out?

    function calc_radius_at_height_offset(r1, r2, h_total, h_offset) = ( r1 + ((r2 - r1) * (h_total - h_offset) / h_total) );

    //Has to factor in up/downedness
    //Starts at middle height then height displacement is reduced under rotation and by the slope of the uneven radii
    function calc_height_offset_at_length(r1, r2, h, length, rotate, updown) = ( h / 2 - updown + length * rotate / 90 * cos( atan( (r2 - r1) / h ) )  );

    function calc_radius_at_length(r1, r2, h, length, rotate, updown) = ( calc_radius_at_height_offset(r1, r2, h, calc_height_offset_at_length(r1, r2, h, length, rotate, updown)));

    if(r == undef)
    {
        //Slanty-cylinder (truncated cone) warnings
        if((direction == "btt") || (direction == "ttb"))
        {
            //TODO: After the issues are resolved refactoring should give this pretty easily
            echo (str("text_on_cylinder:","WARNING" , " - Slanty-cylinders definitely don't directions TTB or BTT on sides yet. Setting direction to ltr."));
        }
        if(center == true)
        {
            echo (str("text_on_cylinder:","WARNING" , " - Slanty-cylinders don't support centering yet. Setting center to false. You can adjust updown and eastwest and achieve most of what you are after...."));
        }
    }

    r1 = (r1 != undef) ? r1 : r;
    r2 = (r2 != undef) ? r2 : r;
    //NOTE: r is not used after here. We operate on generalised slanty cone (r1 and r2)

      //TODO: Look at changing this to extrusion_height_center
    //and renaming the other as text_center
    rr1 = (center) ? r1 - extrusion_height / 2 : r1;
    rr2 = (center) ? r2 - extrusion_height / 2 : r2;

    ccenter = (r != undef) ? center : false; //We don't do (text) centering for the slanty cones/helical paths (yet? ever?). Needs to do quite a few offset calcs.
    ddirection = ((r == undef) && ((direction == "ttb") || (direction == "btt"))) ? "ltr" : direction; //We don't do ttb or btt directions on slanty
    rtl_sign = (ddirection == "rtl") ? -1 : 1;

        //This code takes care of slanty cylinders and "normal" cylinders
    translate([0, 0, updown])
    rotate(eastwest, [0, 0, 1])
    for (l = [0 : len(t) - 1]){
        //TODO: TTB and BTT need to have a different concept of path/length than this for RTL/LTR
           //width_of_... is half a char too long -- add 0.5 (counting from zero)
        length_to_center_of_char = width_of_text_string_num_length(l + 0.5, size, spacing);
        radius_here = calc_radius_at_length(rr1, rr2, h, length_to_center_of_char, rotate, updown);
        //Rotating into position and tangentially to surface -- Don't rotate per character for ttb/btt
        //-90 is to get centering at origin
        rotate_z_inner = -90 + rtl_sign * rotation_for_character(size, spacing, radius_here, rotate) * ((ddirection == "ttb" || ddirection== "btt") ?  0 : l);
        rotate(rotate_z_inner, [0, 0, 1])
        {
            //Positioning - based on (somewhat innacurate) string length
            //Offset per character to go up/down the side in ttb/btt -- TTB down, BTT up
            vert_z_char_offset = (ddirection == "ttb" || ddirection == "btt") ?  (l * size * ((ddirection == "ttb") ? -1 : 1 )) :  0 ;
            //Only if RTL/LTR and if center -- center the text (starts off in a more visually appealing location)
            vert_z_half_text_offset_tmp = (len(t) -1) / 2 * (rotate / 90 * wid);
            vert_z_half_text_offset = ((ddirection == "ttb" || ddirection == "btt") || (ccenter == false)) ? 0 : vert_z_half_text_offset_tmp;
            translate([ radius_here , 0, vert_z_char_offset - l * ((rotate) / 90 * wid) + vert_z_half_text_offset])

            //Flip to tangent on the sloping side (without respecting rotation impact on the tangent -- rotate seems a little off. TODO: Investigate).
            rotate( atan( (rr2 - rr1) /h), [0, 1, 0])
            //Flip onto face of "normal" cylinder
            rotate(90, [1, 0, 0])
            rotate(90, [0, 1, 0])

            //Modify the offset of the baselined text to center
            translate([0, (ccenter) ? -size / 2 : 0, 0])

            text_extrude(t[l],
                    center = false,
                    rotate = rotate,
                    font = font,
                    size = size,
                    spacing = spacing,
                    direction = undef, //We don't pass direction ( misaligns inside text() ). TODO: Investigate why
                    language = language,
                    script = script,
                    halign = "center", //This can be relaxed eventually
                    valign = "baseline", //Need this to keep all letters on the same line (could also support top -- otherw will make
                    extrusion_height = extrusion_height
                    );
        }
    }
}

//sphere(r)
//NB: Iterates through characters/glyphs and presents them individually (but supports actions across the entire string still)
//supports all features of text() except: halign and valign
module text_on_sphere(t = default_t,
                      //Object-specific
                      locn_vec = [0,0,0],
                      r,
                      eastwest = default_sphere_eastwest,
                      northsouth = default_sphere_northsouth,
                      rotate  = default_rotate,
                      spin = default_sphere_spin,
                      rounded  = default_sphere_rounded,
                      //All objects
                      extrusion_height = default_extrusion_height,
                      center = default_center, //center = false doesn't really even make sense to do (IMHO)
                      scale = default_scale,
                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef, //Not supported - only here to enable a warning
                      valign = undef, //Not supported - only here to enable a warning
                      language = undef,
                      script = undef,
                      spacing = default_spacing
){
    //echo ("text_on_sphere:There are " ,len(t) ," letters in t" , t);

    if((halign != undef) || (halign != undef))
    {
        echo (str("text_on_sphere:","WARNING " , "halign and valign are NOT supported (functionality used in centering)."));
    }

    //TODO: refactor this?
    rtl_sign = (direction == "rtl") ? -1 : 1;

    //TODO: Look at changing this to extrusion_height_center
    //and renaming the other as text_center
    //If we are centered - we sink the radius by half the
    //extrusion height to draw "just below the surface"
    rr = (center) ? r - extrusion_height / 2 : r ;

    rotate(eastwest, [0, 0, 1])
    rotate(-northsouth, [1, 0, 0])
    rotate(spin, [0, 1, 0])
    {
    //This tries to center the text (for RTL text).
    ttb_btt_inaction = (direction == "ttb" || direction == "btt") ? 0 : 1;
    rotate( -rtl_sign * ttb_btt_inaction * rotation_for_center_text_string(t, size, spacing, rr, rotate, center), [0, 0, 1])
    {
        translate(locn_vec)
        if ( rounded == false ){
            __internal_text_on_sphere_helper(t = t,
                    r = rr,
                    rotate = rotate,
                    center = center,
                    scale = scale,
                    font = font,
                    size = size,
                    spacing = spacing,
                    direction = direction,
                    language = language,
                    script = script,
                    halign = halign,
                    valign = valign,
                    extrusion_height = extrusion_height
                );
        }else{
            //If rounding then clip the text inside an inner sphere and outer sphere
            intersection()
            {
            __internal_text_on_sphere_helper(t = t,
                    r = rr,
                    rotate = rotate,
                    center = center,
                    scale = scale,
                    font = font,
                    size = size,
                    spacing = spacing,
                    direction = direction,
                    language = language,
                    script = script,
                    halign = halign,
                    valign = valign,
                    extrusion_height = extrusion_height * 2 //Make it proud to clip it off.
            );

            //Shell - bounding inner and outer
            difference()
            {   //rounded outside
                sphere(rr + extrusion_height);
                // rounded inside for indented text
                sphere( rr  );
            }

            }
        }
        }
    }
}

//internal function -- don't call directly
//No default checks in this funciton -- done in parent
module __internal_text_on_sphere_helper(t = default_t,
                      //Object-specific
                      r,
                      //All objects
                      extrusion_height = default_extrusion_height,
                      center = default_center,
                      scale = default_scale,
                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      //halign           = undef,
                      //valign           = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
)
{
    rtl_sign = (direction == "rtl") ? -1 : 1;
    ttb_btt_inaction = (direction == "ttb" || direction == "btt") ? 0 : 1;
    ttb_btt_action = (direction == "ttb" || direction == "btt") ? 1 : 0;

    for (l = [0 : len(t) - 1]){
        rotate_z_inner = -90 + rtl_sign * ttb_btt_inaction * l * rotation_for_character(size, spacing, r, 0);

        rotate( rotate_z_inner, [0, 0, 1] )
        {
        translate_sign = (direction == "ttb" || direction == "btt") ? ((direction == "btt") ? 1 : -1)  : 0 ;
        //translate_effect = (direction=="ttb" || direction=="btt") ? 1  :  0 ;
        //Translate letter to be located on the sphere in up/down direction when we are doing TTB and BTT
        translate(r * [cos(0 + ttb_btt_action * rotation_for_character(size, spacing, r, rotate) * l), 0, translate_sign * ttb_btt_action * sin(0 +  rotation_for_character(size, spacing, r, rotate) * l ) ])
        //Rotate letter to be tangential to the new part of the sphere when we are doing TTB and BTT
        rotate(-90 * translate_sign * (0 + ttb_btt_action * rotation_for_character(size, spacing, r, rotate) * l ) / 90 , [0, 1, 0])
        //Flip character into position to be flush against sphere
        rotate(90, [1, 0, 0])
        rotate(90, [0, 1, 0])

        //Modify the offset of the baselined text to center
        translate([0, (center) ? -size / 2 : 0 , 0])

        text_extrude(t[l],
            center = false,
            rotate = rotate,
            scale = scale,
            font = font,
            size = size,
            spacing = spacing,
            direction = undef, //We don't pass direction ( misaligns inside text() ). TODO: Investigate why
            language = language,
            script = script,
            halign = "center", //This can be relaxed eventually
            valign = "baseline", //Need this to keep all letters on the same line (could also support top -- otherw will make wonky letters)
            extrusion_height = extrusion_height );
        }
    }
}

//cube(size)
//cube([width,h,depth])
//NB: cube_size is used instead of size (the name size is used in the text module)
//NB: Passes through text as strings -- supports all features of text()
module text_on_cube(  t = default_t,
                      //Object-specific
                      cube_size, //number or 3-vector
                      face = default_cube_face,
                      rightleft = default_cube_rightleft,
                      updown = default_cube_updown,
                      //All objects
                      locn_vec = [0, 0, 0],
                      extrusion_height = default_extrusion_height,
                      center = undef,
                      rotate = default_rotate,
                      scale = default_scale,
                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef,
                      valign = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
){
    //echo (str("text_on_cube:","There are " ,len(t) ," letters in t" , t));
    //echo (str("text_on_cube:","cube_size" , cube_size));

    if((halign != undef) || (halign != undef))
    {
        echo (str("text_on_cube:","WARNING " , "halign and valign are NOT supported."));
    }

    int_cube_size = (str(cube_size)[0] != "[") ? [cube_size, cube_size, cube_size] : cube_size;
    rotate_x = ( (face == "front") || (face == "back") || (face == "left") || (face == "right") ) ? 90
                : ((face == "bottom") ? 180 : 0) ; //Top is zero
    rotate_y = ( (face == "back") || (face == "left") || (face == "right") ) ? (face == "back") ? 180 : ((face == "left") ? -90 : 90) //Right is 90
                : 0 ; //Top, bottom, front are zero
    locn_vec_offset =
            (face == "front") ?               [+rightleft, -int_cube_size[1] / 2, +updown]
            :((face == "back") ?              [+rightleft, +int_cube_size[1] / 2, +updown]
                : ((fac e== "left") ?         [-int_cube_size[0] / 2, +rightleft, +updown]
                    : ((face == "right") ?    [+int_cube_size[0] / 2, +rightleft, +updown]
                        : ((face == "top") ?  [+rightleft, +updown, +int_cube_size[2] / 2]
                            :                 [+rightleft, -updown, -int_cube_size[2] / 2]
                            )))); //bottom

    translate(locn_vec + locn_vec_offset)
    rotate(rotate_x, [1, 0, 0])
    rotate(rotate_y, [0, 1, 0]) // rotate around the y axis (z before rotation)
    text_extrude(t,
            center = center,
            rotate = rotate,
            scale = scale,
            font = font,
            size = size,
            spacing = spacing,
            direction = direction, //Does this misalign inside text()? the individual character modules do.
            language = language,
            script = script,
            halign = halign,
            valign = valign,
            extrusion_height = extrusion_height );
}

function default_if_undef(val, default_val) = (val != undef) ? val : default_val;

//Print a single character or a string at the desired extrusion height
//Passes on values to text() that are passed in
//TODO: Add x,y,z rotations get text facing the right way from the start)
module text_extrude( t = default_t,
                     extrusion_height = default_extrusion_height,
                     center = default_center, //Fudgy. YMMV. //TODO:center_extrusion, or extrusion offset??
                     rotate = default_rotate,
                     scale = default_scale, //For scaling by different on axes (for widening etc)
                     //Following are test() params (in addition to t=)
                     font = default_font,
                     size = default_size,
                     direction = undef,
                     halign  = undef,
                     valign = undef,
                     language = undef,
                     script = undef,
                     spacing = default_spacing
)
{
    //echo (str("text_extrude:","There are " ,len(t) ," letters in text" , t));
    //echo (str("text_extrude:","extrusion_height=" , extrusion_height));

    if(center == true)
    {
        if((halign != undef) || (valign != undef))
        {
            echo (str("text_extrude:","WARNING " , "When center is true, then halign and valign are NOT supported."));
        }
    }

    //As arguments are explicitly set as undef (from higher functions) as they come down (they don't get defaults in this function as they are set as something)
    //we need to check and replace any that we don't want to be undef
    t = default_if_undef(t, default_t);
    font = default_if_undef(font, default_font);
    extrusion_height = default_if_undef(extrusion_height, default_extrusion_height);
    center = default_if_undef(center, default_center);
    rotate = default_if_undef(rotate, default_rotate);
    spacing = default_if_undef(spacing, default_spacing);
    size = default_if_undef(size, default_size);

    halign = (center) ? "center" : halign ;
    valign = (center) ? "center" : valign ;
    extrusion_center = (center) ? true : false ;

    scale( scale )
    rotate(rotate, [0, 0, -1]) //TODO: Do we want to make this so that the entire vector can be set?
    {
        linear_extrude(height = extrusion_height, convexity = 10, center = extrusion_center)
        text(text = t,
                size = size,
                $fn = 40,
                font = font,
                direction = direction,
                spacing = spacing,
                halign = halign,
                valign = valign,
                language = language,
                script = script);
    }
}

/*  text on ....
    This is a rework of version 3 of write.scad to use the new OpenSCAD internal text() primitive.
    All credit to Harlan Martin (harlan@sutlog.com) for his great effort on the original.
    Great thanks to t-paul (and the OpenSCAD dev team) on adding the new text() primitive.
*/

/*
The arguments to be provided for each function are explictly in the modules.

All modules take close to all the arguments to text() [Not all features are supported in all text_on_object() modules though -- try them out warnings will be given if it is not supported]

text() params:
t
size
spacing
font
direction -- ltr, ttb, btt or rtl
language
script
halign -- left, right or center
valign -- baseline, bottom, top or center

All modules also take the additional arguments:
extrusion_height = depth of the letter, i.e. how far it sits proud
rotate
center //center the text at the location it is being written (NOT that the object is centered)

ALL faux-objects that the text is applied to have center=true
TODO: object_center=true/false (already done for cylinder)

The above arguemnts can be seen in text_extrude() as all modules call that module evetually (often multiple times).

locn_vector -- Where the faux-object has been translated to. TODO: Rename object to translate_vector?

Additional arguments for text_on_cube():

Additional arguments for text_on_cylinder():

Additional arguments for text_on_circle():

Additional arguments for text_on_sphere():

*/

// These control the default values for text_extrude(), text_on_sphere(), text_on_cube(), text_on_cylinder(), text_on_circle()
// if the arguments are not included in the call to the module.

// Defaults
// Defaults for all modules
default_t = "text_on";
default_size = 4; //TODO - Can we make this 10?? To match internal size? There is an underlying value in text() -- This masks that.
default_font = "Liberation Mono";
default_spacing = 1; //Spacing between characters. There is an underlying value in text() -- This masks that. We try and match it here.
default_rotate = 0; // text rotation (clockwise)
default_center = true; //Text-centering
default_scale = [1,1,1];
default_extrusion_height = 2; //mm letter extrusion height

//Defaults for Cube
default_cube_face = "front";     // default face (top,bottom,left,right,back,front)
default_sphere_rounded = false;     //default for rounded letters on text_on_sphere
default_cube_updown = 0; //mm up (-down) from center on face of cube
default_cube_rightleft = 0;         //mm right(-left) from center on face of cube

//Defaults for Sphere
default_sphere_northsouth = 0;
default_sphere_eastwest = 0;
default_sphere_spin = 0; //TODO:Different to rotate? or up/down. Better name?

//Defaults for Cylinder (including circle as it is on top/bottom)
default_circle_middle = 0;      //(mm toward middle of circle)
default_circle_ccw = false;  //write on top or bottom in a ccw direction
default_circle_eastwest = 0;
default_cylinder_face = "side";
default_cylinder_updown = 0;

//Internal values - don't play with these :)
//This is much more accurate than the PI constant internal to Openscad.
internal_pi = 3.1415926535897932384626433832795028841971693993751058209;
internal_pi2 = internal_pi*2;

//Internal values - You might want to play with these if you are using a proportional font
internal_space_fudge = 0.80; //Fudge for working out lengths (widths) of strings

debug = true;

//---- Helper Functions ----
//String width (length from left to right or RTL) in OpenSCAD units
//NOTE: These are innacurate because we don't know the real spacing of the chars and so have to approximate
//They work for monospaced (fixed-width) fonts well
function width_of_text_char( size, spacing ) = (size * internal_space_fudge * spacing);
function width_of_text_string_num_length(length, size, spacing) = ( width_of_text_char( size, spacing ) * (length));
function width_of_text_string( t, size, spacing ) = ( width_of_text_string_num_length(len(t), size, spacing) );

function cylinder_center_adjusted_top( height, center ) = (center==true) ? height/2 : height ;
function cylinder_center_adjusted_bottom( height, center ) = (center==true) ? height/2 : 0 ;

//Angle that measures width of letters on perimeter of a circle (and sphere and cylinder)
function rotation_for_character(size, spacing, r, rotate = 0) = ( width_of_text_char( size, spacing ) /(internal_pi2*r))*360*(1-abs(rotate)/90);

//Rotate 1/2 width of text if centering
//One less -- if we have a single char we are already centred..
function rotation_for_center_text_string( t, size, spacing,r,rotate,center) = (center) ? (width_of_text_string_num_length( len(t)-1, size, spacing )/2/(internal_pi2*r)*360) : 0 ;

//Rotate according to rotate and if centred text also 1/2 width of text
function rotation_for_center_text_string_and_rotate( t, size, spacing,r,rotate,center) = ((center) ? (width_of_text_string( t, size, spacing )/2/(internal_pi2*r)*360) : 1) * (1-abs(rotate)/90);

//---- Text on Object Functions ----
//Text on the top or side of a cylinder.
//Supports writing on normal and slanty cylinders
//cylinder(h,r,center)
//cylinder(h,r1,r2,center)
module text_on_cylinder(t = default_t,
                        //Object-specific
                        locn_vec = [0,0,0],
                        r,r1,r2,h,
                        face = default_cylinder_face,
                        updown = default_cylinder_updown,
                        rotate = default_rotate,
                        eastwest = default_circle_eastwest,
                        middle = default_circle_middle,
                        ccw = default_circle_ccw,
                        cylinder_center = false, //if the cylinder object we are writing on is center==true
                        //TODO: add rounded

                        //All objects
                        extrusion_height = default_extrusion_height,
                        center = default_center,
                        //All objects -- arguments as for text()
                        font = undef,
                        size = default_size,
                        direction = undef,
                        halign = undef,
                        valign = undef,
                        language = undef,
                        script = undef,
                        spacing = default_spacing
){
//    echo (str("text_on_cylinder:There are " ,len(t) ," letters in t" , t));
//    echo (str("text_on_cylinder:","h" , h));
//    echo (str("text_on_cylinder:","r=" , r));
//    echo (str("text_on_cylinder:","r1=" , r1));
//    echo (str("text_on_cylinder:","r2=" , r2));

    if((halign!=undef) || (halign!=undef))
    {
        echo (str("text_on_cylinder:","WARNING " , "halign and valign are NOT supported."));
    }

    rtl_sign = (direction=="rtl") ? -1 : 1;
    if ((face=="top")||(face=="bottom") ){
        //Work on a circle
        locn_offset_vec = (face=="top" ) ? [0,0,cylinder_center_adjusted_top(h,cylinder_center)] : [0,0,cylinder_center_adjusted_bottom(h,cylinder_center)] ;
        rotation_angle = (face=="top" ) ? 0 : 180 ;
        int_radius = (r==undef) ? ((face=="top" ) ? r2 : r1 ) : r;  //Use the top/bottom radius for slanty-cylinders
        rotate(rotation_angle,[1,0,0])
        text_on_circle(t,locn_vec+locn_offset_vec,r = int_radius-size,
                font = font,size=size,
                spacing = spacing,direction = direction,language = language,script = script,halign = halign,valign = valign,
                extrusion_height = extrusion_height,
                rotate = rotate,
                eastwest = eastwest,middle = middle,ccw = ccw);
    }else{
        if((middle!=undef) && (middle!=default_circle_middle))
        {
            //TODO: Which others?
            //TODO: Which side things aren't supported on the circle
            echo (str("text_on_cylinder:","WARNING " , "middle NOT supported for the SIDE of a cylinder."));
        }
        //Work on the side
        locn_offset_vec = (cylinder_center==true) ? [0,0,0] : [0,0,h/2];
        rotate(-rtl_sign * rotation_for_center_text_string_and_rotate(t, size, spacing,r,rotate,center), [0,0,1])
        translate(locn_vec+locn_offset_vec)
        __internal_text_on_cylinder_side(t,locn_vec,r = r,h = h,r1 = r1,r2 = r2,
            cylinder_center =c ylinder_center,
            center = center,
            font = font,size = size,
            spacing = spacing,direction = direction,language = language,script = script,halign = halign,valign = valign,
            extrusion_height = extrusion_height,
            rotate = rotate,face = face,updown = updown,
            eastwest = eastwest);
    }
}

//circle(r)
module text_on_circle(t=default_t,
                      //Object-specific
                      locn_vec = [0,0,0],
                      r,
                      eastwest = default_circle_eastwest,
                      middle = default_circle_middle,
                      ccw = default_circle_ccw,

                      //All objects
                      extrusion_height = default_extrusion_height,
                      rotate = default_rotate,
                      center = default_center,

                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef,
                      valign = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
){
//    echo (str("text_on_circle:","There are " ,len(t) ," letters in t" , t));
//    echo (str("text_on_circle:","rotate=" , rotate));
//    echo (str("text_on_circle:","eastwest=" , eastwest));

    if((halign!=undef) || (halign!=undef))
    {
        echo (str("text_on_circle:","WARNING " , "halign and valign are NOT supported."));
    }

    ccw_sign = (ccw==true) ? 1 : -1;
    rtl_sign = (direction=="rtl") ? -1 : 1;
    ttb_btt_inaction = (direction=="ttb" || direction=="btt") ? 0 : 1;
    rotate_z_outer = -rotate + ccw_sign*eastwest;
    rotate_z_inner = -rtl_sign * ccw_sign * ttb_btt_inaction * rotation_for_center_text_string( t, size, spacing, r-middle, rotate, center);
    rotate( rotate_z_outer, [0,0,1] )
    rotate( rotate_z_inner, [0,0,1] )
    translate(locn_vec)
    for (l=[0:len(t)-1]){
        //TTB/BTT means no per letter rotation
        rotate_z_inner2 = -ccw_sign * 90 + ttb_btt_inaction*rtl_sign*ccw_sign*l*rotation_for_character(size, spacing, r-middle, rotate=0);   //Bottom out=-270+r
        //TTB means we go toward center, BTT means away
        vert_x_offset = (direction=="ttb" || direction=="btt") ? (l * size * ((direction=="btt") ? -1 : 1)) : 0;
        rotate( rotate_z_inner2, [0,0,1] )
        translate([r - middle - vert_x_offset,0,0])
        rotate(-ccw_sign*270,[0,0,1]) // flip text (botom out = -270)
        text_extrude(t[l],center = true,
            font = font,size = size,
            rotate = undef,
            spacing = spacing,
            direction = undef, //We don't pass direction ( misaligns inside text() ). TODO: Investigate why
            language = language,script = script,halign = halign,valign = valign,
            extrusion_height = extrusion_height );
    }
}

//Only expected to be called from another function. No defaults as expected to be done in parent.
//NOTE: This is hacked. Requires more mathematics than I feel like to do properly today....
//TODO: Refactor the two operations - side of normal and slanty
//No default checks in this funciton -- done in parent
module __internal_text_on_cylinder_side(t = default_t,
                      //Object-specific
                      locn_vec = [0,0,0],
                      r,r1,r2,h,
                      cylinder_center,

                      //All objects
                      extrusion_height = default_extrusion_height,
                      center = undef,
                      rotate = default_rotate,

                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef, //Overridden
                      valign = undef,
                      language         = undef,
                      script = undef,
                      spacing = default_spacing
)
{
//    echo (str("__internal_text_on_cylinder_side:There are " ,len(t) ," letters in t" , t));
//    echo (str("__internal_text_on_cylinder_side:","h=" , h));
//    echo (str("__internal_text_on_cylinder_side:","r=" , r));
//    echo (str("__internal_text_on_cylinder_side:","r1=" , r1));
//    echo (str("__internal_text_on_cylinder_side:","r2=" , r2));
//    echo (str("__internal_text_on_cylinder_side:","direction=" , direction));

    if((halign!=undef) || (halign!=undef))
    {
        echo (str("text_on_cylinder:","WARNING " , "halign and valign are NOT supported."));
    }

    wid = width_of_text_char( size, spacing ); //TODO: refactor this out?

    function calc_radius_at_height_offset(r1,r2,h_total,h_offset) = ( r1 + ((r2-r1) * (h_total-h_offset)/h_total) );

    //Has to factor in up/downedness
    //Starts at middle height then height displacement is reduced under rotation and by the slope of the uneven radii
    function calc_height_offset_at_length(r1,r2,h,length,rotate, updown) = ( h/2 - updown + length * rotate/90 * cos( atan( (r2-r1)/h ) )  );

    function calc_radius_at_length(r1,r2,h,length,rotate,updown) = ( calc_radius_at_height_offset(r1,r2,h,calc_height_offset_at_length(r1,r2,h,length,rotate,updown)));

    if(r==undef)
    {
        //Slanty-cylinder (truncated cone) warnings
        if((direction=="btt") || (direction=="ttb"))
        {
            //TODO: After the issues are resolved refactoring should give this pretty easily
            echo (str("text_on_cylinder:","WARNING" , " - Slanty-cylinders definitely don't directions TTB or BTT on sides yet. Setting direction to ltr."));
        }
        if(center==true)
        {
            echo (str("text_on_cylinder:","WARNING" , " - Slanty-cylinders don't support centering yet. Setting center to false. You can adjust updown and eastwest and achieve most of what you are after...."));
        }
    }

    r1 = (r1!=undef) ? r1 : r;
    r2 = (r2!=undef) ? r2 : r;
    //NOTE: r is not used after here. We operate on generalised slanty cone (r1 and r2)

      //TODO: Look at changing this to extrusion_height_center
    //and renaming the other as text_center
    rr1 = (center) ? r1-extrusion_height/2 : r1;
    rr2 = (center) ? r2-extrusion_height/2 : r2;

    ccenter = (r!=undef) ? center : false; //We don't do (text) centering for the slanty cones/helical paths (yet? ever?). Needs to do quite a few offset calcs.
    ddirection = ((r==undef) && ((direction=="ttb")||(direction=="btt"))) ? "ltr" : direction; //We don't do ttb or btt directions on slanty
    rtl_sign = (ddirection=="rtl") ? -1 : 1;

        //This code takes care of slanty cylinders and "normal" cylinders
    translate([0,0,updown])
    rotate(eastwest,[0,0,1])
    for (l=[0:len(t)-1]){
        //TODO: TTB and BTT need to have a different concept of path/length than this for RTL/LTR
           //width_of_... is half a char too long -- add 0.5 (counting from zero)
        length_to_center_of_char = width_of_text_string_num_length(l+0.5,size,spacing);
        radius_here = calc_radius_at_length(rr1,rr2,h, length_to_center_of_char, rotate, updown);
        //Rotating into position and tangentially to surface -- Don't rotate per character for ttb/btt
        //-90 is to get centering at origin
        rotate_z_inner = -90 + rtl_sign * rotation_for_character(size, spacing, ( radius_here ), rotate) * ((ddirection=="ttb" || ddirection=="btt") ?  0 : l);
        rotate(rotate_z_inner,[0,0,1])
        {
            //Positioning - based on (somewhat innacurate) string length
            //Offset per character to go up/down the side in ttb/btt -- TTB down, BTT up
            vert_z_char_offset = (ddirection=="ttb" || ddirection=="btt") ?  (l * size * ((ddirection=="ttb") ? -1 : 1 )) :  0 ;
            //Only if RTL/LTR and if center -- center the text (starts off in a more visually appealing location)
            vert_z_half_text_offset_tmp = (len(t)-1)/2 * (rotate/90*wid);
            vert_z_half_text_offset = ((ddirection=="ttb" || ddirection=="btt") || (ccenter==false)) ? 0 : vert_z_half_text_offset_tmp;
            translate([ radius_here , 0, vert_z_char_offset - l * ((rotate)/90*wid) + vert_z_half_text_offset])

            //Flip to tangent on the sloping side (without respecting rotation impact on the tangent -- rotate seems a little off. TODO: Investigate).
            rotate( atan( (rr2-rr1)/h ) , [0,1,0])
            //Flip onto face of "normal" cylinder
            rotate(90,[1,0,0])
            rotate(90,[0,1,0])

            //Modify the offset of the baselined text to center
            translate([0,(ccenter) ? -size/2 : 0,0])

            text_extrude(t[l],
                center = false,
                rotate = rotate,
                font = font,size = size,
                spacing = spacing,
                direction = undef, //We don't pass direction ( misaligns inside text() ). TODO: Investigate why
                language = language,script = script,
                halign = "center", //This can be relaxed eventually
                valign = "baseline", //Need this to keep all letters on the same line (could also support top -- otherw will make
                extrusion_height = extrusion_height
                );
        }
    }
}

//sphere(r)
//NB: Iterates through characters/glyphs and presents them individually (but supports actions across the entire string still)
//supports all features of text() except: halign and valign
module text_on_sphere(t = default_t,
                      //Object-specific
                      locn_vec = [0,0,0],
                      r,
                      eastwest = default_sphere_eastwest,
                      northsouth = default_sphere_northsouth,
                      rotate  = default_rotate,
                      spin = default_sphere_spin,
                      rounded  = default_sphere_rounded,
                      //All objects
                      extrusion_height = default_extrusion_height,
                      center = default_center, //center = false doesn't really even make sense to do (IMHO)
                      scale = default_scale,
                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef, //Not supported - only here to enable a warning
                      valign = undef, //Not supported - only here to enable a warning
                      language = undef,
                      script = undef,
                      spacing = default_spacing
){
    //echo ("text_on_sphere:There are " ,len(t) ," letters in t" , t);

    if((halign!=undef) || (halign!=undef))
    {
        echo (str("text_on_sphere:","WARNING " , "halign and valign are NOT supported (functionality used in centering)."));
    }

    //TODO: refactor this?
    rtl_sign = (direction=="rtl") ? -1 : 1;

    //TODO: Look at changing this to extrusion_height_center
    //and renaming the other as text_center
    //If we are centered - we sink the radius by half the
    //extrusion height to draw "just below the surface"
    rr = (center) ? r-extrusion_height/2 : r ;

    rotate(eastwest,[0,0,1])
    rotate(-northsouth,[1,0,0])
    rotate(spin,[0,1,0])
    {
    //This tries to center the text (for RTL text).
    ttb_btt_inaction = (direction=="ttb" || direction=="btt") ? 0 : 1;
    rotate( -rtl_sign * ttb_btt_inaction * rotation_for_center_text_string(t, size, spacing, rr, rotate, center), [0,0,1])
    {
        translate(locn_vec)
        if ( rounded == false ){
            __internal_text_on_sphere_helper(t = t,r = rr,
                rotate = rotate,
                center = center,
                scale = scale,
                font = font,size = size,
                spacing = spacing,
                direction = direction,
                language = language,script = script,halign = halign,valign = valign,
                extrusion_height = extrusion_height
            );
        }else{
            //If rounding then clip the text inside an inner sphere and outer sphere
            intersection()
            {
            __internal_text_on_sphere_helper(t = t,r = rr,
                rotate = rotate,
                center = center,
                scale = scale,
                font = font,size = size,
                spacing = spacing,
                direction = direction,
                language = language,script = script,halign = halign,valign = valign,
                extrusion_height = extrusion_height*2 //Make it proud to clip it off.
            );

            //Shell - bounding inner and outer
            difference()
            {   //rounded outside
                sphere(rr+extrusion_height);
                // rounded inside for indented text
                sphere( rr  );
            }

            }
        }
        }
    }
}

//internal function -- don't call directly
//No default checks in this funciton -- done in parent
module __internal_text_on_sphere_helper(t = default_t,
                      //Object-specific
                      r,
                      //All objects
                      extrusion_height = default_extrusion_height,
                      center = default_center,
                      scale = default_scale,
                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      //halign           = undef,
                      //valign           = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
)
{
    rtl_sign = (direction=="rtl") ? -1 : 1;
    ttb_btt_inaction = (direction=="ttb" || direction=="btt") ? 0 : 1;
    ttb_btt_action = (direction=="ttb" || direction=="btt") ? 1 : 0;

    for (l = [0:len(t)-1]){
        rotate_z_inner = -90 + rtl_sign * ttb_btt_inaction * l * rotation_for_character(size, spacing, r, 0);

        rotate( rotate_z_inner, [0,0,1] )
        {
        translate_sign = (direction=="ttb" || direction=="btt") ? ((direction=="btt") ? 1 : -1)  : 0 ;
        //translate_effect = (direction=="ttb" || direction=="btt") ? 1  :  0 ;
        //Translate letter to be located on the sphere in up/down direction when we are doing TTB and BTT
        translate(r * [cos(0 + ttb_btt_action * rotation_for_character(size, spacing, r, rotate) * l ), 0, translate_sign * ttb_btt_action * sin(0 +  rotation_for_character(size, spacing, r, rotate) * l ) ])
        //Rotate letter to be tangential to the new part of the sphere when we are doing TTB and BTT
        rotate(-90 * translate_sign * (0 + ttb_btt_action * rotation_for_character(size, spacing, r, rotate) * l )/90 , [0,1,0])
        //Flip character into position to be flush against sphere
        rotate(90,[1,0,0])
        rotate(90,[0,1,0])

        //Modify the offset of the baselined text to center
        translate([0,(center) ? -size/2 : 0 ,0])

        text_extrude(t[l],
            center = false,
            rotate = rotate,
            scale = scale,
            font = font,
            size = size,
            spacing = spacing,
            direction = undef, //We don't pass direction ( misaligns inside text() ). TODO: Investigate why
            language = language,script = script,
            halign = "center", //This can be relaxed eventually
            valign = "baseline", //Need this to keep all letters on the same line (could also support top -- otherw will make wonky letters)
            extrusion_height = extrusion_height );
        }
    }
}

//cube(size)
//cube([width,h,depth])
//NB: cube_size is used instead of size (the name size is used in the text module)
//NB: Passes through text as strings -- supports all features of text()
module text_on_cube(  t = default_t,
                      //Object-specific
                      cube_size, //number or 3-vector
                      face = default_cube_face,
                      rightleft = default_cube_rightleft,
                      updown = default_cube_updown,
                      //All objects
                      locn_vec = [0,0,0],
                      extrusion_height = default_extrusion_height,
                      center = undef,
                      rotate = default_rotate,
                      scale = default_scale,
                      //All objects -- arguments as for text()
                      font = undef,
                      size = default_size,
                      direction = undef,
                      halign = undef,
                      valign = undef,
                      language = undef,
                      script = undef,
                      spacing = default_spacing
){
    //echo (str("text_on_cube:","There are " ,len(t) ," letters in t" , t));
    //echo (str("text_on_cube:","cube_size" , cube_size));

    if((halign!=undef) || (halign!=undef))
    {
        echo (str("text_on_cube:","WARNING " , "halign and valign are NOT supported."));
    }

    int_cube_size = (str(cube_size)[0] != "[") ? [cube_size,cube_size,cube_size] : cube_size;
    rotate_x = ( (face=="front") || (face=="back") || (face=="left") || (face=="right") ) ? 90
                : ((face=="bottom") ? 180 : 0) ; //Top is zero
    rotate_y = ( (face=="back") || (face=="left") || (face=="right") ) ? (face=="back") ? 180 : ((face=="left") ? -90 : 90) //Right is 90
                : 0 ; //Top, bottom, front are zero
    locn_vec_offset =
            (face=="front") ?             [+rightleft,   -int_cube_size[1]/2, +updown]
            :((face=="back")?             [+rightleft,   +int_cube_size[1]/2, +updown]
                : ((face=="left")?         [-int_cube_size[0]/2, +rightleft,   +updown]
                    : ((face=="right")?    [+int_cube_size[0]/2, +rightleft,   +updown]
                        : ((face=="top")?  [+rightleft,   +updown,             +int_cube_size[2]/2]
                            :              [+rightleft,   -updown,             -int_cube_size[2]/2]
                            )))); //bottom

    translate(locn_vec + locn_vec_offset)
    rotate(rotate_x,[1,0,0])
    rotate(rotate_y,[0,1,0])  // rotate around the y axis (z before rotation)
    text_extrude(t,
        center = center,
        rotate = rotate,
        scale = scale,
        font = font,
        size = size,
        spacing = spacing,
        direction = direction, //Does this misalign inside text()? the individual character modules do.
        language = language,
        script = script,
        halign = halign,
        valign = valign,
        extrusion_height = extrusion_height );
}

function default_if_undef(val, default_val) = (val!=undef) ? val : default_val;

//Print a single character or a string at the desired extrusion height
//Passes on values to text() that are passed in
//TODO: Add x,y,z rotations get text facing the right way from the start)
module text_extrude( t = default_t,
                     extrusion_height = default_extrusion_height,
                     center = default_center, //Fudgy. YMMV. //TODO:center_extrusion, or extrusion offset??
                     rotate = default_rotate,
                     scale = default_scale, //For scaling by different on axes (for widening etc)
                     //Following are test() params (in addition to t=)
                     font = default_font,
                     size = default_size,
                     direction = undef,
                     halign  = undef,
                     valign = undef,
                     language = undef,
                     script = undef,
                     spacing = default_spacing
)
{
    //echo (str("text_extrude:","There are " ,len(t) ," letters in text" , t));
    //echo (str("text_extrude:","extrusion_height=" , extrusion_height));

    if(center==true)
    {
        if((halign!=undef) || (valign!=undef))
        {
            echo (str("text_extrude:","WARNING " , "When center is true, then halign and valign are NOT supported."));
        }
    }

    //As arguments are explicitly set as undef (from higher functions) as they come down (they don't get defaults in this function as they are set as something)
    //we need to check and replace any that we don't want to be undef
    t = default_if_undef(t,default_t);
    font = default_if_undef(font,default_font);
    extrusion_height = default_if_undef(extrusion_height,default_extrusion_height);
    center = default_if_undef(center,default_center);
    rotate = default_if_undef(rotate,default_rotate);
    spacing = default_if_undef(spacing,default_spacing);
    size = default_if_undef(size,default_size);

    halign = (center) ? "center" : halign ;
    valign = (center) ? "center" : valign ;
    extrusion_center = (center) ? true : false ;

    scale( scale )
    rotate(rotate,[0,0,-1]) //TODO: Do we want to make this so that the entire vector can be set?
    {
        linear_extrude(height = extrusion_height,convexity = 10,center = extrusion_center)
        text(text = t, size = size,
            $fn = 40,
            font = font, direction = direction, spacing = spacing,
            halign = halign,
            valign = valign,
            language = language, script = script);
    }
}


klammer update

klammer update

$fn=100;
//Variables
r1=1.5;
r2=1.5;
d1=1.5;
len1=33;
len2=31;
len3=15;
module stick_hull() {
	hull() {
		translate([0,len1-r1])circle(r=r1);
		translate([0,-len2+r2+len3])circle(r=r2);
        translate([0,-len2+r2])translate([-(r2*2-d1),d1/2])square(d1,center=true);
    }
    translate([0,3])internal();
}

module internal(d=1.5,n=5) {
	for(i=[0:d:(n-1)*d]) {
		translate([r1-0.1,i])scale(v=[1,1])rotate(a=[0,0,45])square(1.5,center=true);
	}
}
module ring() {
	intersection(){
		difference() {
			circle(r=9);
			circle(r=7);
		}
		translate([-4,-11])square(8);
	}
}
module klammer(x=3,y=3.7) {
	difference() {
        union() {
            translate([-y,0])rotate(a=[0,0,-x])stick_hull();
            mirror([1,0])translate([-y,0])rotate(a=[0,0,-x])stick_hull();
            translate([0,8])ring();
        }
        translate([0,31])hull()resize([15])claw();
        }
    translate([0,31])resize([7.17])claw();
}
module claw(o1=-0.6,o2=0.6) {
    difference() {
        intersection() {
            hull()for(i=[-1,1])translate([i*0.5,0])circle(r=2);
            translate([0,3])square([10,6],center=true);
        }
       polygon(points=[[-1-o1,0],[-1.5-o1,0.5],[-1-o1,1],[-2.5-o1,2],[-0.5-o2,2],[-0.5-o2,1.8],[1-o2,1],[0.5-o2,0.5],[1-o2,0]]);
    }
}
//Extrusion
intersection() {
    linear_extrude(height=20)klammer();
    cube([15,100,40],center=true);
}

$fn=100;
//Variables
r1=1.25;
r2=1.75;
len1=32;
len2=33;
module stick_hull() {
	hull() {
		translate([0,len1-r1])circle(r=r1);
		translate([0,-len2+r2])circle(r=r2);
	}
}
module stick_cut() {
	for(i=[0:1.3:2]) {
		translate([r1+0.1,i])scale(v=[1,1])rotate(a=[0,0,45])square(1.5,center=true);
	}
}
module stick1(x) {
		stick_hull();
		translate([-0.4,x])stick_cut();
}
module stick2(x) {
	difference() {
		stick_hull();
		translate([0,x])stick_cut();
	}
}
module ring() {
	intersection(){
		difference() {
			circle(r=9);
			circle(r=6);
		}
		translate([-4,-11])square(8);
	}
}
module klammer(x=5.1,y=4.5) {
	translate([-y,0])rotate(a=[0,0,-x])stick1(29);
    mirror([1,0])translate([-y,0])rotate(a=[0,0,-x])stick2(29);
	translate([0,6])ring();
}
//Extrusion
intersection() {
    linear_extrude(height=20)klammer();
    cube([18,100,40],center=true);
}


Create 1US.scad

Create 1US.scad

error: pathspec 'SCAD/1US.scad' did not match any file(s) known to git


new 3dmodel

new 3dmodel

$fn = 150;

R = 50;
ballShell = 3;
supportX = 0.7*R;
supportY = 0.15*R;
supportZ = 1.25*R;
mik = 2;
sThickness = 5;
supportBaseHeight = 5;
baseHeight = 31;

module box(Xdim, Ydim, Zdim, thickness, application)
//Creates a box, dimensions are internal
{
	difference() {
		//translate([10,0,-thickness])
		cube([Xdim + thickness, Ydim + thickness, Zdim], center = true);
		translate([0, 0, thickness / 2]) cube([Xdim, Ydim, Zdim], center = true);
		if(application == "servo")
	{
		translate([-Xdim/2,0,-0.5*Zdim])cube([5,Ydim+2*thickness,Zdim/2+thickness], center=true);
		translate([+Xdim/2,0,-0.5*Zdim])cube([5,Ydim+2*thickness,Zdim/2+thickness], center=true);
		translate([+Xdim/2,0,0])cube([thickness/2,0.3*Ydim,Zdim], center=true);
		translate([-Xdim/2,0,0])cube([thickness/2,0.3*Ydim,Zdim], center=true);
	}
	}
}

module support() {
	difference() {
		union() {
			intersection() {
				sphere(R);
				translate([-R, -R+(supportY+sThickness)/2, 0])  cube([500, 25, 200], center = true);
			}

		}
	}

	translate([0, -R+(supportY+sThickness/2), -supportZ/2]) {
		minkowski() {
			box(supportX, supportY, supportZ, sThickness , "none");
			cylinder(r = mik, h = 1);
			//rotate([90,0,0])cylinder(r = mik, h = 1);
		}
	}
}

module base() {
translate([0, 0, -supportZ])
		minkowski() {
			cylinder(r= R+mik, h= supportBaseHeight);
		rotate([90,0,0])cylinder(r = mik, h = 1);
}
}

sphere(R);
support();
mirror([0, 10, 0]) support();
bottom();
base();
module bottom() {
	translate([0, 0, -supportZ - supportBaseHeight - baseHeight]){
	difference() {

		difference() {
			minkowski() {
				cylinder(r = R + 6, h = baseHeight);
				rotate([90, 0, 0]) cylinder(r = mik, h = 1);
			}

			translate([0, 0, 5]) cylinder(r = (R + mik)-2*sThickness, h = 10 * baseHeight);
		}
	translate([0, 0, baseHeight-supportBaseHeight]) cylinder(r = R + mik + 2, h = 10*supportBaseHeight);
	}

translate([0, 0, 17 - 3]) box(24.5, 13, 17, 3, "servo");
}

}

$fn = 250;

R = 50;
ballShell = 3;
supportX = 35;
supportY = 8;
supportZ = 60;
mik = 2;
sThickness = 5;
supportBaseHeight = 5;
baseHeight = 31;

module box(Xdim, Ydim, Zdim, thickness, application)
//Creates a box, dimensions are internal
{
	difference() {
		//translate([10,0,-thickness])
		cube([Xdim + thickness, Ydim + thickness, Zdim], center = true);
		translate([0, 0, thickness / 2]) cube([Xdim, Ydim, Zdim], center = true);
		if(application == "servo")
	{
		translate([-Xdim/2,0,-0.5*Zdim])cube([5,Ydim+2*thickness,Zdim/2+thickness], center=true);
		translate([+Xdim/2,0,-0.5*Zdim])cube([5,Ydim+2*thickness,Zdim/2+thickness], center=true);
		translate([+Xdim/2,0,0])cube([thickness/2,0.3*Ydim,Zdim], center=true);
		translate([-Xdim/2,0,0])cube([thickness/2,0.3*Ydim,Zdim], center=true);
	}
	}
}

module support() {
	difference() {
		union() {
			intersection() {
				sphere(R);
				translate([-R, -R+(supportY+sThickness)/2, 0])  cube([500, 25, 200], center = true);
			}

		}
	}

	translate([0, -R+(supportY+sThickness/2), -supportZ/2]) {
		minkowski() {
			box(supportX, supportY, supportZ, sThickness , "none");
			cylinder(r = mik, h = 1);
			//rotate([90,0,0])cylinder(r = mik, h = 1);
		}
	}
}

module base() {
translate([0, 0, -supportZ])
		minkowski() {
			cylinder(r= R+mik, h= supportBaseHeight);
		rotate([90,0,0])cylinder(r = mik, h = 1);
}
}

sphere(R);
support();
mirror([0, 10, 0]) support();
//need to understnad -2 in  2*R-5-mik-2
base();

translate([0, 0, -supportZ-supportBaseHeight-baseHeight])
difference(){
{difference(){
	minkowski() {
cylinder(r= R+6, h = baseHeight);
rotate([90,0,0])cylinder(r = mik, h = 1);
}

translate([0, 0, 5])cylinder(r= (R+mik)/2, h = 10*baseHeight);
}
translate([0, 0, 5])cylinder(r= R+mik+2, h = 10*baseHeight);

}

translate([0, 0, 17-3])	box(24.5, 13, 17, 3,"servo");}