Got the left side (30 degrees) side working

// https://www.github.com/agupta231

// User set variables
init_side_len = 50.8;
max_iter = 10;

echo(version());

module pattern(starting_pos, side_size, rotation_matrix, current_iter) {
  translate(starting_pos) {
    rotate(rotation_matrix) {
        cube(side_size);
    }
  }

  echo(cos(30 - rotation_matrix[1]));

  if(current_iter <= max_iter) {
    pattern(starting_pos + [side_size * sin(rotation_matrix[1]), 0, side_size * cos(rotation_matrix[1])], side_size * sqrt(3) / 2, rotation_matrix + [0, -30, 0], current_iter + 1);
    /*#pattern(starting_pos + [0, 0, 0], side_size / 2, rotation_matrix + [0, 60, 0], current_iter + 1);*/
  }
}

pattern([0, 0, 0], init_side_len, [0, 30, 0], 1, 0);

// https://www.github.com/agupta231

// User set variables
init_side_len = 50.8;

echo(version());

module pattern() {

}


screws/nut_trap_cut: reduce nut dia

screws/nut_trap_cut: reduce nut dia

include <system.scad>
include <shapes.scad>
include <transforms.scad>
include <misc.scad>

include <thread-data.scad>
include <nut-data.scad>

use <scad-utils/transformations.scad>

// naive, assume head height is same as thread size (generally true for cap heads)
function get_screw_head_h(thread) = get(ThreadSize, thread);
function get_screw_head_d(thread) = 2 * get(ThreadSize, thread);

module screw(nut, thread, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, orient=[0,0,1], align=[0,0,0])
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != undef, "screw: No nut or thread given");
    /*assert(nut!=undef && thread!=undef && nut_thread != thread_, "screw: Mismatched nut and thread");*/

    head_h = get_screw_head_h(nut);
    nut_h = get(NutThickness,nut)*tolerance;
    threadsize = get(ThreadSize, thread_);

    s = threadsize*tolerance;
    total_h = h;
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head(thread=thread_, orient=[0,0,1], align=[0,0,1]);
            }

            screw_thread(thread=thread_, h=h+.1, tolerance=tolerance, orient=[0,0,1], align=[0,0,0]);

            if(with_nut && nut != undef)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut(nut=nut, tolerance=tolerance, orient=[0,0,1], align=[0,0,-1]);
            }
        }

        if($show_vit)
        {
            translate([0,0,head_embed?-head_h:0])
            if(with_nut && nut != undef)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                %screw_nut(nut=nut, align=[0,0,-1]);
            }
        }
    }
}

module screw_cut(nut, thread, h=10, tolerance=1.05, head_embed=false, with_nut=true, nut_cut_h=1000, with_head=true, head_cut_h=1000, nut_offset=0, cut_access=true, orient=[0,0,1], align=[0,0,0])
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != undef, "screw_cut: No nut or thread given");
    /*assert(nut!=undef && thread!=undef && nut_thread != thread_, "screw_cut: Mismatched nut and thread");*/

    nut_h = get(NutThickness,nut)*tolerance;
    head_h = get_screw_head_h(thread_);
    assert(head_h != undef, "screw_cut: head_h is undef!");

    threadsize = get(ThreadSize, thread_);
    assert(threadsize != undef, "screw_cut: threadsize is undef!");

    s = threadsize*tolerance;
    total_h = h;
    assert(s != undef, "screw_cut: s is undef!");
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head_cut(thread=thread_, tolerance=tolerance, override_h=head_cut_h, align=[0,0,1]);
            }

            screw_thread_cut(thread=thread_, h=h+.1, tolerance=tolerance, orient=[0,0,1], align=[0,0,0]);

            if(with_nut && nut != undef)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut_cut(nut=nut, tolerance=tolerance, h=nut_cut_h, align=[0,0,-1]);
            }
        }
    }

    if($show_vit)
    {
        %screw(nut=nut, thread=thread, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
    }
}

module screw_thread(thread, h=10, tolerance=1.00, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_thread: thread is undef");
    // TODO render thread
    threadsize = get(ThreadSize, thread);
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

module screw_thread_cut(thread, h=10, tolerance=1.05, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_thread_cut: thread is undef");
    threadsize = get(ThreadSize, thread);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(thread, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_head: thread is undef");

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(thread);
    head_d = get_screw_head_d(thread);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    difference()
    {
        cylindera(d=head_d, h = fallback(override_h,head_h));
        translate([0,0,head_h/2])
        cylindera(d=threadsize, h = head_d/2);
    }
}

module screw_head_cut(thread, tolerance=1.05, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_head_cut: thread is undef");

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(thread);
    head_d = get_screw_head_d(thread)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    translate([0,0,-head_h/2])
    cylindera(d=head_d, h=fallback(override_h, head_h), align=[0,0,1]);
}

module screw_nut(nut, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    assert(nut!=undef, "screw_nut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    cylindera($fn=nut_facets, d=nut_dia, h=fallback(override_h, nut_thick), orient=orient, align=align);
}

module screw_nut_cut(nut, tolerance=1.05, h=1000, orient=[0,0,1], align=[0,0,0])
{
    assert(nut!=undef, "screw_nut_cut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        translate([0,0,nut_thick/2])
        {
            screw_nut(nut, tolerance, orient=[0,0,1], align=[0,0,-1]);
            translate([0,0,-nut_thick+.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

// distance from center to flat on a polygon (taking in the diagonal distance)
function apothem(radius, facets) = radius/cos(180/facets);

function nut_radius(nut) = apothem(get(NutWidthMax, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = 2*nut_radius(nut);

module nut_trap_cut(nut, thread, trap_offset=10, screw_l=10*mm, screw_l_extra=2*mm, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,1], align=[0,0,0])
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != undef, "nut_trap_cut: No nut or thread given");
    /*assert(nut!=undef && thread!=undef && nut_thread != thread_, "nut_trap_cut: Mismatched nut and thread");*/

    threadsize = get(ThreadSize, thread_);
    head_h = get_screw_head_h(thread);
    nut_h = get(NutThickness, nut) +.5*mm;

    nut_width_min = get(NutWidthMin, nut);
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    total_h = nut_h;
    size_align(size=[nut_dia, nut_dia, total_h], orient=orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,nut_h/2-.1])
        screw_thread_cut(thread=thread_, tolerance=1.1, h=screw_l, orient=[0,0,-1], align=[0,0,1]);

        if(screw_l_extra>0)
        translate([0,0,-nut_h/2+.1])
        screw_thread_cut(thread=thread_, tolerance=1.1, h=screw_l_extra+.1, orient=[0,0,1], align=[0,0,-1]);

        hull()
        {
            orient(-orient)
            translate(-.15*mm*trap_axis)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(orient)
                {
                    rotate([0,0,30])
                    cylindera($fn=nut_facets, d=nut_dia, h=nut_h, align=[0,0,0]);
                }

                orient(orient)
                cubea(size=[nut_width_min,nut_width_min,nut_h], align=[0,0,0]);
            }
        }

        if($show_vit)
        {
            translate([0,0, screw_l])
            translate([0,0, -nut_h/2])
            %screw(nut=nut, thread=thread, tolerance=1, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);

            rotate([0,0,30])
            %screw_nut(nut=nut, thread=thread, tolerance=1, orient=[0,0,-1], align=[0,0,0]);
        }

    }
}

// all nuts
if(false)
{
    for(nuti=[0:1:len(AllNut)-1])
    {
        nut = AllNut[nuti];
        v_threadsize = v_get(AllNut,ThreadSize);
        v_nutwidthmin = v_get(AllNut,NutWidthMin);
        dist = v_cumsum(v_nutwidthmin, 0, nuti)[nuti]*1.2;
        translate(XAXIS*dist)
        rotate([0,0,30])
        screw(nut=nut, h=get(NutWidthMax, nut)*5, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
    }
}

if(false)
{
    box_w = 40*mm;
    box_h = 10*mm;
    box_d = 10*mm;
    o = 10*mm;

    /*$show_vit = true;*/
    $fs= 0.2;
    $fa = 4;

    nut1 = NutHexM3;
    nut2 = NutHexM5;
    nut3 = NutKnurlM3_3_42;
    nut4 = NutKnurlM3_5_42;

    difference()
    {
        /*rcubea([box_w,box_d/2,box_h], align=[1,-1,1]);*/
        rcubea([box_w,box_d,box_h], align=[1,0,1]);

        test_cuts();
    }
}

module test_cuts()
{
    union()
    {
        offset = 0;
        /*offset = -5;*/
        translate([0,offset,0])
        translate([5,0,0])
        stack(dist=10,axis=[1,0,0])
        {
            screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);
            /*screw_cut(thread=ThreadM5, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);*/
            /*screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);*/

            /*screw_cut(nut=nut1, h=box_h, nut_offset=0*mm, head_embed=true, orient=[0,0,-1], align=[0,0,1]);*/
            /*screw_cut(nut=nut2, h=box_h, nut_offset=3*mm, head_embed=false, orient=[0,0,-1], align=[0,0,1]);*/
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);
            screw_cut(nut=nut4, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);

            translate([0,0,-5*mm])
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,-1], align=[0,0,0]);

            /*translate([0,0,box_h/2])*/
                /*nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,1,0], orient=[0,0,1], align=[0,0,0]);*/

            /*translate([0,0,box_h/2])*/
                /*nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,1], orient=[0,1,0], align=[0,0,0]);*/

            /*translate([0,0,box_h/2])*/
                /*nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,-1], orient=[0,1,0], align=[0,0,0]);*/
        }
    }
}

include <system.scad>
include <shapes.scad>
include <transforms.scad>
include <misc.scad>

include <thread-data.scad>
include <nut-data.scad>

use <scad-utils/transformations.scad>

// naive, assume head height is same as thread size (generally true for cap heads)
function get_screw_head_h(thread) = get(ThreadSize, thread);
function get_screw_head_d(thread) = 2 * get(ThreadSize, thread);

module screw(nut, thread, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, orient=[0,0,1], align=[0,0,0])
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != undef, "screw: No nut or thread given");
    /*assert(nut!=undef && thread!=undef && nut_thread != thread_, "screw: Mismatched nut and thread");*/

    head_h = get_screw_head_h(nut);
    nut_h = get(NutThickness,nut)*tolerance;
    threadsize = get(ThreadSize, thread_);

    s = threadsize*tolerance;
    total_h = h;
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head(thread=thread_, orient=[0,0,1], align=[0,0,1]);
            }

            screw_thread(thread=thread_, h=h+.1, tolerance=tolerance, orient=[0,0,1], align=[0,0,0]);

            if(with_nut && nut != undef)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut(nut=nut, tolerance=tolerance, orient=[0,0,1], align=[0,0,-1]);
            }
        }

        if($show_vit)
        {
            translate([0,0,head_embed?-head_h:0])
            if(with_nut && nut != undef)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                %screw_nut(nut=nut, align=[0,0,-1]);
            }
        }
    }
}

module screw_cut(nut, thread, h=10, tolerance=1.05, head_embed=false, with_nut=true, nut_cut_h=1000, with_head=true, head_cut_h=1000, nut_offset=0, cut_access=true, orient=[0,0,1], align=[0,0,0])
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != undef, "screw_cut: No nut or thread given");
    /*assert(nut!=undef && thread!=undef && nut_thread != thread_, "screw_cut: Mismatched nut and thread");*/

    nut_h = get(NutThickness,nut)*tolerance;
    head_h = get_screw_head_h(thread_);
    assert(head_h != undef, "screw_cut: head_h is undef!");

    threadsize = get(ThreadSize, thread_);
    assert(threadsize != undef, "screw_cut: threadsize is undef!");

    s = threadsize*tolerance;
    total_h = h;
    assert(s != undef, "screw_cut: s is undef!");
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head_cut(thread=thread_, tolerance=tolerance, override_h=head_cut_h, align=[0,0,1]);
            }

            screw_thread_cut(thread=thread_, h=h+.1, tolerance=tolerance, orient=[0,0,1], align=[0,0,0]);

            if(with_nut && nut != undef)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut_cut(nut=nut, tolerance=tolerance, h=nut_cut_h, align=[0,0,-1]);
            }
        }
    }

    if($show_vit)
    {
        %screw(nut=nut, thread=thread, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
    }
}

module screw_thread(thread, h=10, tolerance=1.00, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_thread: thread is undef");
    // TODO render thread
    threadsize = get(ThreadSize, thread);
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

module screw_thread_cut(thread, h=10, tolerance=1.05, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_thread_cut: thread is undef");
    threadsize = get(ThreadSize, thread);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(thread, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_head: thread is undef");

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(thread);
    head_d = get_screw_head_d(thread);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    difference()
    {
        cylindera(d=head_d, h = fallback(override_h,head_h));
        translate([0,0,head_h/2])
        cylindera(d=threadsize, h = head_d/2);
    }
}

module screw_head_cut(thread, tolerance=1.05, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    assert(thread!=undef, "screw_head_cut: thread is undef");

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(thread);
    head_d = get_screw_head_d(thread)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    translate([0,0,-head_h/2])
    cylindera(d=head_d, h=fallback(override_h, head_h), align=[0,0,1]);
}

module screw_nut(nut, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    assert(nut!=undef, "screw_nut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    cylindera($fn=nut_facets, d=nut_dia, h=fallback(override_h, nut_thick), orient=orient, align=align);
}

module screw_nut_cut(nut, tolerance=1.05, h=1000, orient=[0,0,1], align=[0,0,0])
{
    assert(nut!=undef, "screw_nut_cut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        translate([0,0,nut_thick/2])
        {
            screw_nut(nut, tolerance, orient=[0,0,1], align=[0,0,-1]);
            translate([0,0,-nut_thick+.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

// distance from center to flat on a polygon (taking in the diagonal distance)
function apothem(radius, facets) = radius/cos(180/facets);

function nut_radius(nut) = apothem(get(NutWidthMax, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = 2*nut_radius(nut);

module nut_trap_cut(nut, thread, trap_offset=10, screw_l=10*mm, screw_l_extra=2*mm, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,1], align=[0,0,0])
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != undef, "nut_trap_cut: No nut or thread given");
    /*assert(nut!=undef && thread!=undef && nut_thread != thread_, "nut_trap_cut: Mismatched nut and thread");*/

    threadsize = get(ThreadSize, thread_);
    head_h = get_screw_head_h(thread);
    nut_h = get(NutThickness, nut) +.5*mm;

    nut_width_min = get(NutWidthMin, nut);
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut)+.1*mm;
    total_h = nut_h;
    size_align(size=[nut_dia, nut_dia, total_h], orient=orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,nut_h/2-.1])
        screw_thread_cut(thread=thread_, tolerance=1.1, h=screw_l, orient=[0,0,-1], align=[0,0,1]);

        if(screw_l_extra>0)
        translate([0,0,-nut_h/2+.1])
        screw_thread_cut(thread=thread_, tolerance=1.1, h=screw_l_extra+.1, orient=[0,0,1], align=[0,0,-1]);

        hull()
        {
            orient(-orient)
            translate(-.15*mm*trap_axis)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(orient)
                {
                    rotate([0,0,30])
                    cylindera($fn=nut_facets, d=nut_dia, h=nut_h, align=[0,0,0]);
                }

                orient(orient)
                cubea(size=[nut_width_min,nut_width_min,nut_h], align=[0,0,0]);
            }
        }

        if($show_vit)
        {
            translate([0,0, screw_l])
            translate([0,0, -nut_h/2])
            %screw(nut=nut, thread=thread, tolerance=1, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);

            rotate([0,0,30])
            %screw_nut(nut=nut, thread=thread, tolerance=1, orient=[0,0,-1], align=[0,0,0]);
        }

    }
}

// all nuts
if(false)
{
    for(nuti=[0:1:len(AllNut)-1])
    {
        nut = AllNut[nuti];
        v_threadsize = v_get(AllNut,ThreadSize);
        v_nutwidthmin = v_get(AllNut,NutWidthMin);
        dist = v_cumsum(v_nutwidthmin, 0, nuti)[nuti]*1.2;
        translate(XAXIS*dist)
        rotate([0,0,30])
        screw(nut=nut, h=get(NutWidthMax, nut)*5, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
    }
}

if(false)
{
    box_w = 40*mm;
    box_h = 10*mm;
    box_d = 10*mm;
    o = 10*mm;

    /*$show_vit = true;*/
    $fs= 0.2;
    $fa = 4;

    nut1 = NutHexM3;
    nut2 = NutHexM5;
    nut3 = NutKnurlM3_3_42;
    nut4 = NutKnurlM3_5_42;

    difference()
    {
        /*rcubea([box_w,box_d/2,box_h], align=[1,-1,1]);*/
        rcubea([box_w,box_d,box_h], align=[1,0,1]);

        test_cuts();
    }
}

module test_cuts()
{
    union()
    {
        offset = 0;
        /*offset = -5;*/
        translate([0,offset,0])
        translate([5,0,0])
        stack(dist=10,axis=[1,0,0])
        {
            screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);
            /*screw_cut(thread=ThreadM5, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);*/
            /*screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);*/

            /*screw_cut(nut=nut1, h=box_h, nut_offset=0*mm, head_embed=true, orient=[0,0,-1], align=[0,0,1]);*/
            /*screw_cut(nut=nut2, h=box_h, nut_offset=3*mm, head_embed=false, orient=[0,0,-1], align=[0,0,1]);*/
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);
            screw_cut(nut=nut4, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);

            translate([0,0,-5*mm])
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,-1], align=[0,0,0]);

            /*translate([0,0,box_h/2])*/
                /*nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,1,0], orient=[0,0,1], align=[0,0,0]);*/

            /*translate([0,0,box_h/2])*/
                /*nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,1], orient=[0,1,0], align=[0,0,0]);*/

            /*translate([0,0,box_h/2])*/
                /*nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,-1], orient=[0,1,0], align=[0,0,0]);*/
        }
    }
}


rolled back changes, done on a separate branch now

include <Write.scad>

/*
 * configuration
 */
names = ["JOHN", "JANE", "BILLY"];
brushes_count = len(names);
//$fn=200;

/*
 * modules
 */

module lower_tub()
{
  translate([0, (20+4)/2, 0])
    difference()
    {
      cylinder(h=10+3, r=(20+3)/2);
      translate([0,0,3])
        cylinder(h=10+3, r2=20/2, r1=16/2);
    }
}

module upper_ring()
{
  translate([0, (24+5)/2, 0])
    difference()
    {
      cylinder(h=10, r=(24+5)/2);
      cylinder(h=10, r=(24+0)/2);
    }
}

module back_wall()
{
  // lower part
  translate([-40/2, 0, 0])
    cube([40, 3, 20]);
  // upper part
  translate([-40/2, 0, 100-10])
    cube([40, 3, 20]);
  // connector
  translate([-10/2, 0, 0])
    cube([10, 3, 100]);
}

module brush_holder()
{
  lower_tub();
  translate([0,0,100-5])
    upper_ring();
  back_wall();
  // lower mounting
  difference()
  {
    translate([-15/2, 3, 0])
      cube([15, 4, 10+3]);
    translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
      hull()
        lower_tub();
  }
  // upper mounting
  translate([0, 0, 100-5])
  {
    difference()
    {
      translate([-25/2, 3, 0])
        cube([25, 10, 10]);
      translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
        hull()
          upper_ring();
    }
  }
}

/*
 * main program
 */

rotate([90, 0, 0])
{
  for(i = [0:brushes_count-1])
  {
    translate([i*30,4,55])
      rotate([-90, 90, 0])
        scale([2,1,1])
          write(names[i], t=2, h=8, center=true);
    translate(i * [30, 0, 0])
      brush_holder();
  }
}

include <Write.scad>

/*
 * configuration
 */
names = ["LIS"];
brushes_count = len(names);
//$fn=200;

/*
 * modules
 */

module lower_tub()
{
  translate([0, (20+4)/2, 0])
    difference()
    {
      cylinder(h=10+3, r=(20+3)/2);
      translate([0,0,3])
        cylinder(h=10+3, r2=20/2, r1=16/2);
    }
}

module upper_ring()
{
  translate([0, (24+5)/2, 0])
    difference()
    {
      cylinder(h=10, r=(24+5)/2);
      cylinder(h=10, r=(24+0)/2);
    }
}

module back_wall()
{
  // lower part
  translate([-40/2, 0, 0])
    cube([40, 3, 20]);
  // upper part
  translate([-40/2, 0, 100-10-25])
    cube([40, 3, 20]);
  // connector
  translate([-10/2, 0, 0])
    cube([10, 3, 100-25]);
}

module brush_holder()
{
  lower_tub();
  translate([0,0,100-5-25])
    upper_ring();
  back_wall();
  // lower mounting
  difference()
  {
    translate([-15/2, 3, 0])
      cube([15, 4, 10+3]);
    translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
      hull()
        lower_tub();
  }
  // upper mounting
  translate([0, 0, 100-5-25])
  {
    difference()
    {
      translate([-25/2, 3, 0])
        cube([25, 10, 10]);
      translate([0, 0.1, 0]) // needed to make model simple (aka: manifold)
        hull()
          upper_ring();
    }
  }
}

/*
 * main program
 */

rotate([90, 0, 0])
{
  for(i = [0:brushes_count-1])
  {
    translate([i*30,4,45])
      rotate([-90, -90, 0])
        scale([2,1,1])
          write(names[i], t=2, h=8, center=true);
    translate(i * [30, 0, 0])
      brush_holder();
  }
}


shapes: Extend fncylindera to support orient param

use <misc.scad>

// translate children
module lineup(arr=undef)
{
    /*echo(arr);*/
    /*echo($children);*/
    if($children>0)
    {
        for (i = [0 : $children-1])
            translate(arr[i]) children(i);
    }
}

module stack(separations)
{
    union()
    {
        for (i = [0:len(separations)-1])
        {
            offset = v_sum(separations,i);
            /*echo("i",i,"offset",offset);*/
            translate ([0,0,offset])
            {
                child(i);
            }
        }
    }
}

module orient(zaxes, roll=0)
{
    zaxes = len(zaxes.x) == undef && zaxes.x != undef? [zaxes] : zaxes;
    for(zaxis=zaxes)
    {
        rotate(_orient_angles(zaxis))
        /*rotate(roll*z)*/
            children();
    }
}

module size_align(size=[10,10,10], align=[0,0,0], orient=[0,0,1])
{
    bounds = _rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1];
    t=hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]);
    translate(t)
    {
        orient(orient)
        {
            children();
        }
    }
}

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module cylindera(h=10, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, align=[0,0,0], extra_h=0,extra_r=undef,extra_d=undef,extra_align=[0,0,0])
{
    extra_r_=(extra_r==undef?0:extra_r);
    extra_d_=(extra_d==undef?0:extra_d);
    extra_sizexy=extra_r_*2 + extra_d_;
    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {
        r_=(r==undef?0:r);
        d_=(d==undef?0:d);
        sizexy=r_*2 + d_;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r+extra_r_, r1=r1, r2=r2, d=d+extra_d_, d1=d1, d2=d2, center=true);
        }
    }
}

module fncylinder(r, r2, d, d2, h, fn, center=false, enlarge=0, fnr=0.4){
    translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
        if (fn==undef) {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            }
        } else {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
            }
        }
    }
}

// specify segment length with fnr, $fn not needed but if desired use fn instead but if desired use fn instead
module fncylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        fn,
        fnr=0.4,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r_= useDia?d/2:(r==undef?0:r);
    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    extra_sizexy=extra_r_*2;

    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align)
    {
        fn_=fn==undef?(floor(2*(r_+extra_r_)*pi/fnr)):fn;

        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align, fn_);
        }

        sizexy=r_*2;
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true, $fn=fn_);
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

/*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/
/*fncylindera(h=10, r=5, extra_r=2, align=[0,0,1], orient=[1,0,0]);*/

use <misc.scad>

// translate children
module lineup(arr=undef)
{
    /*echo(arr);*/
    /*echo($children);*/
    if($children>0)
    {
        for (i = [0 : $children-1])
            translate(arr[i]) children(i);
    }
}

module stack(separations)
{
    union()
    {
        for (i = [0:len(separations)-1])
        {
            offset = v_sum(separations,i);
            /*echo("i",i,"offset",offset);*/
            translate ([0,0,offset])
            {
                child(i);
            }
        }
    }
}

module orient(zaxes, roll=0)
{
    zaxes = len(zaxes.x) == undef && zaxes.x != undef? [zaxes] : zaxes;
    for(zaxis=zaxes)
    {
        rotate(_orient_angles(zaxis))
        /*rotate(roll*z)*/
            children();
    }
}

module size_align(size=[10,10,10], align=[0,0,0], orient=[0,0,1])
{
    bounds = _rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1];
    t=hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]);
    translate(t)
    {
        orient(orient)
        {
            children();
        }
    }
}

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module cylindera(h=10, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, align=[0,0,0], extra_h=0,extra_r=undef,extra_d=undef,extra_align=[0,0,0])
{
    extra_r_=(extra_r==undef?0:extra_r);
    extra_d_=(extra_d==undef?0:extra_d);
    extra_sizexy=extra_r_*2 + extra_d_;
    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {
        r_=(r==undef?0:r);
        d_=(d==undef?0:d);
        sizexy=r_*2 + d_;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r+extra_r_, r1=r1, r2=r2, d=d+extra_d_, d1=d1, d2=d2, center=true);
        }
    }
}

module fncylinder(r, r2, d, d2, h, fn, center=false, enlarge=0, fnr=0.4){
    translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
        if (fn==undef) {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            }
        } else {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
            }
        }
    }
}

// specify segment length with fnr, $fn not needed but if desired use fn instead but if desired use fn instead
module fncylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        fn,
        fnr=0.4,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r_= useDia?d/2:(r==undef?0:r);
    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_d/2);

    extra_sizexy=extra_r_*2;

    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {

        fn_=fn==undef?(floor(2*(r_+extra_r_)*pi/fnr)):fn;

        if(debug)
            echo(useDia, h, r_, r1_, r2_, extra_r_, align, fn_);

        sizexy=r_*2;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true, $fn=fn_);
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

/*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/
/*%cylindera(h=10, r=5, align=[-1,0,0], extra_r=5);*/


'echo's commented out

'echo's commented out

/* 	Version 3
	Added support for font selection (default is Letters.dxf)
	Added WriteCube module
	Added Rotate for text (rotates on the plane of the text)
	Added writesphere
	Added space=     (spacing between characters in char widths) def=1
	Added writecylinder()

 By Harlan Martin
 harlan@sutlog.com
 January 2012

 (The file TestWrite.scad gives More usage examples)
 (This module requires the file Letters.dxf to reside in the same folder)
 (The file Letters.dfx was created with inkscape..Each letter is in its own layer)
 (This module seperates each letter in the string and imports it from Letters.dfx)

*/

	pi=3.1415926535897932384626433832795028841971693993751058209;
	pi2=pi*2;

// These control the default values for write() writesphere() writecube()
// if the parameters are not included in the call. Feel free to set your own
// defaults.

//default settings
	center=false;
	h = 4;			 //mm letter height
	t = 1; 			//mm letter thickness
	space =1; 			//extra space between characters in (character widths)
	rotate=0;			// text rotation (clockwise)
	font = "Letters.dxf";	//default for aditional fonts

// write cube defaults
	face = "front";	 // default face (top,bottom,left,right,back,front)
	up =0;		 //mm up from center on face of cube
	down=0;
	right =0;		 //mm left from center on face of cube
	left=0;

// write sphere defaults
	rounded=false;	 //default for rounded letters on writesphere
	north=0; 		// intial text position (I suggest leave these 0 defaults)
	south=0;
	east=0;
	west=0;
	spin=0;
// writecylinder defaults
	middle=0;     //(mm toward middle of circle)
	ccw=false;   //write on top or bottom in a ccw direction
 	r1=0; 	//(not implimented yet)
	r2=0;	 	//(not implimented yet)

// Contact me if your interested in how to make your own font files
// Its tedious and time consuming, but not very hard

module writecylinder(text,where,radius,height){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360;
	//angle of half width of text
	function mmangle(radius)=(widall/(pi2*radius)*360);

	if ((face=="top")||(face=="bottom") ){
		if (face=="top" ){
			if (center==true){
				writecircle(text,where+[0,0,height/2],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}else{
				writecircle(text,where+[0,0,height],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}
		}else{
			rotate(180,[1,0,0])
			if (center==true){
				writecircle(text,where+[0,0,height/2],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}else{
				writecircle(text,where+[0,0,0],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}
		}

	}else{
//		if (radius>0){
			if (center==true)  {
				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
				translate(where)
				writethecylinder(text,where,radius,height,r1=radius,r2=radius,h=h,
					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
					east=east,west=west,center=center,space=space,rounded=rounded);
			} else{
				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
				translate(where+[0,0,height/2])
					writethecylinder(text,where,radius,height,r1=radius,r2=radius,h=h,
					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
					east=east,west=west,center=center,space=space,rounded=rounded);
			}
// the remarked out code is for cone shaped cylinders (not complete)
//		}else{
//			if (center==true)  {
//				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
//				translate(where)
//				writethecylinder(text,where,radius,height,r1=r1,r2=r2,h=h,
//					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
//					east=east,west=west,center=center,space=space,rounded=rounded);
//			} else{
//				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
//				translate(where+[0,0,height/2])
//					writethecylinder(text,where,radius,height,r1=r1,r2=r2,h=h,
//					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
//					east=east,west=west,center=center,space=space,rounded=rounded);
//			}
//		}
	}
}
module writecircle(text,where,radius){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360;
	//angle of half width of text
	function mmangle(radius)=(widall/(pi2*radius)*360);

	if (ccw==true){
		rotate(-rotate+east-west,[0,0,1]){
			rotate(-mmangle(radius-middle),[0,0,1]){
			translate(where)
				for (r=[0:len(text)-1]){
					rotate(-90+r*NAngle(radius-middle),[0,0,1]) // bottom out=-270+r
					translate([radius-middle,0,0])
					//rotate(90,[1,0,0])
					//rotate(90,[0,1,0])
					rotate(-270,[0,0,1])  // flip text (botom out = -270)
					write(text[r],center=true,h=h,t=t,font=font);
				}
			}
		}
	}else{
		rotate(-rotate-east+west,[0,0,1]){
			rotate(mmangle(radius-middle),[0,0,1]){
			translate(where)
				for (r=[0:len(text)-1]){
					rotate(90-r*NAngle(radius-middle),[0,0,1]) // bottom out=-270+r
					translate([radius-middle,0,0])
					//rotate(90,[1,0,0])
					//rotate(90,[0,1,0])
					rotate(270,[0,0,1])  // flip text (botom out = -270)
					write(text[r],center=true,h=h,t=t,font=font);
				}
			}
		}
	}

}
module writethecylinder(text,where,radius,height,r1,r2){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360*(1-abs(rotate)/90);
	//angle of half width of text

	function mmangle(radius)=(widall/(pi2*radius)*360);
			translate([0,0,up-down])
			rotate(east-west,[0,0,1])
			for (r=[0:len(text)-1]){
				rotate(-90+(r*NAngle(radius)),[0,0,1])
				translate([radius,0,-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid)])
				rotate(90,[1,0,0])
				rotate(90,[0,1,0])
				write(text[r],center=true,h=h,rotate=rotate,t=t,font=font);
		//echo("zloc=",height/2-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid));
			}

}

module writesphere(text,where,radius){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;

	//echo("-----------------",widall,wid,mmangle(radius));
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360;
	//angle of half width of text
	function mmangle(radius)=(widall/(pi2*radius)*360);

	rotate(east-west,[0,0,1]){
	rotate(south-north,[1,0,0]){
	rotate(spin,[0,1,0]){
	rotate(-mmangle(radius),[0,0,1]){
		if ( rounded== false ){
			translate(where)
			for (r=[0:len(text)-1]){
				rotate(-90+r*NAngle(radius),[0,0,1])
				translate([radius,0,0])
				rotate(90,[1,0,0])
				rotate(90,[0,1,0])
				write(text[r],center=true,h=h,rotate=rotate,t=t,font=font);
			}
		}else{
			difference(){
				translate(where)
				for (r=[0:len(text)-1]){
					rotate(-90+r*NAngle(radius),[0,0,1])
					translate([radius,0,0])
					rotate(90,[1,0,0])
					rotate(90,[0,1,0])
					write(text[r],center=true,h=h,rotate=rotate,t=t*2+h,font=font);
				}
				difference(){ //rounded outside
					sphere(radius+(t*2+h)*2);
					sphere(radius+t/2);
				}
				sphere(radius-t/2); // rounded inside for indented text
			}
		}
	}
}}}
}

module writecube(text,where,size){
	if (str(size)[0] != "["){
		// its a square cube (size was not a matrix so make it one)
		writethecube(text,where,[size,size,size],h=h,rotate=rotate,space=space,
		t=t,font=font,face=face,up=up,down=down,right=right,left=left);

	}else{
		// its not square
		writethecube(text,where,size,h=h,rotate=rotate,space=space,
		t=t,font=font,face=face,up=up,down=down,right=right,left=left);
	}
}
// I split the writecube module into 2 pieces.. easier to add features later
module writethecube(text,where,size){
		if (face=="front") {
			translate([where[0]+right-left,where[1]-size[1]/2,where[2]+up-down])
			rotate(90,[1,0,0])
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="back") {
			translate([where[0]+right-left,where[1]+size[1]/2,where[2]+up-down])
			rotate(90,[1,0,0])   // rotate around the x axis
			rotate(180,[0,1,0])  // rotate around the y axis (z before rotation)
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="left") {
			translate([where[0]-size[0]/2,where[1]-right+left,where[2]+up-down ])
			rotate(90,[1,0,0])   // rotate around the x axis
			rotate(90,[0,-1,0])  // rotate around the y axis  (z before rotation)
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="right") {
			translate([where[0]+size[0]/2,where[1]+right-left,where[2] +up-down])
			rotate(90,[1,0,0])   // rotate around the x axis
			rotate(90,[0,1,0])  // rotate around the y axis  (z before rotation)
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="top") {
			translate([where[0]+right-left,where[1]+up-down,where[2]+size[2]/2 ])
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="bottom") {
			translate([where[0]+right-left,where[1]-up+down,where[2]-size[2]/2 ])
			rotate(180,[1,0,0])
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
}

module write(word){

	//echo (h);
	//echo (word);
	//echo ("There are " ,len(word) ," letters in this string");
//	echo ("The second letter is ",word[1]);
//	echo (str(word[0],"_"));
rotate(rotate,[0,0,-1]){
	for (r = [0:len(word)]){   // count off each character
		// if the letter is lower case, add an underscore to the end for file lookup
		if ((word[r] == "a" ) || (word[r]== "b")  || (word[r]== "c")
	 	  || (word[r]== "d") || (word[r]== "e") || (word[r]== "f")
	 	  || (word[r]== "g") || (word[r]== "h")  || (word[r]== "i")
       	  	  || (word[r]== "j") || (word[r]== "k") || (word[r]== "l")
       	 	  || (word[r]== "m") || (word[r]== "n") || (word[r]== "o")
       	 	  || (word[r]== "p") || (word[r]== "q") || (word[r]== "r")
	 	  || (word[r]== "s") || (word[r]== "t") || (word[r]== "u")
       	 	  || (word[r]== "v") || (word[r]== "w") || (word[r]== "x")
       	 	  || (word[r]== "y" )|| (word[r]== "z")){
			if (center == true)  {
				translate([0,-h/2,0]){
					scale([.125*h,.125*h,t]){
						translate([ (-len(word)*5.5*space/2) + (r*5.5*space),0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r],"_"));
						}
					}
				}
			}else{
				translate([0,0,t/2]){
					scale([.125*h,.125*h,t]){
						translate([r*5.5*space,0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r],"_"));
						}
					}
				}
			}

		}else{
			if (center == true)  {
				translate([0,-h/2,0]){
					scale([.125*h,.125*h,t]){
						translate([ (-len(word)*5.5*space/2) + (r*5.5*space),0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r]));
						}
					}
				}
			}else{
				translate([0,0,t/2]){
					scale([.125*h,.125*h,t]){
						translate([r*5.5*space,0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r]));
						}
					}
				}
			}
		}
	}
}
}

/*writecylinder test
translate([0,0,0])
%cylinder(r=20,h=40,center=true);
color([1,0,0])
writecylinder("rotate=90",[0,0,0],20,40,center=true,down=0,rotate=90);
writecylinder("rotate = 30,east = 90",[0,0,0],20,40,center=true,down=0,rotate=30,east=90);
writecylinder("ccw = true",[0,0,0],20,40,center=true,down=0,face="top",ccw=true);
writecylinder("middle = 8",[0,0,0],20,40,h=3,center=true,down=0,face="top",middle=8);
writecylinder("face = top",[0,0,0],20,40,center=true,down=0,face="top");
writecylinder("east=90",[0,0,0],20,40,h=3,center=true,down=0,face="top",east=90);
writecylinder("west=90",[0,0,0],20,40,h=3,center=true,down=0,face="top",ccw=true,west=90);
writecylinder("face = bottom",[0,0,0],20,40,center=true,down=0,face="bottom");
*/
/*writesphere test
sphere(20);
color([1,0,0])
writesphere("Hello World",[0,0,0],20,t=1,h=6);
*/
/* writecube test
translate([30,30,30])
cube([10,15,30],center=true);
write("hello",center=true,rotate =30);
color([1,0,0])
writecube( "front",[30,30,30],[10,15,30],h=5,rotate=-90);
color([0,1,0])
writecube( "back",[30,30,30],size=[10,15,30],h=5,face="back",rotate=90,t=4);
color([0,0,1])
writecube( "left",[30,30,30],[10,15,30],h=5,face="left",up=5);
color([1,1,0])
writecube( "right",where=[30,30,30],size=[10,15,30],h=5,face="right",rotate=55);
color([1,0,1])
writecube( "top",where=[30,30,30],size=[10,15,30],h=5,face="top");
color([1,1,1])
writecube( "bttm",where=[30,30,30],size=[10,15,30],h=5,face="bottom",rotate=90);
*/

/* 	Version 3
	Added support for font selection (default is Letters.dxf)
	Added WriteCube module
	Added Rotate for text (rotates on the plane of the text)
	Added writesphere
	Added space=     (spacing between characters in char widths) def=1
	Added writecylinder()

 By Harlan Martin
 harlan@sutlog.com
 January 2012

 (The file TestWrite.scad gives More usage examples)
 (This module requires the file Letters.dxf to reside in the same folder)
 (The file Letters.dfx was created with inkscape..Each letter is in its own layer)
 (This module seperates each letter in the string and imports it from Letters.dfx)

*/

	pi=3.1415926535897932384626433832795028841971693993751058209;
	pi2=pi*2;

// These control the default values for write() writesphere() writecube()
// if the parameters are not included in the call. Feel free to set your own
// defaults.

//default settings
	center=false;
	h = 4;			 //mm letter height
	t = 1; 			//mm letter thickness
	space =1; 			//extra space between characters in (character widths)
	rotate=0;			// text rotation (clockwise)
	font = "Letters.dxf";	//default for aditional fonts

// write cube defaults
	face = "front";	 // default face (top,bottom,left,right,back,front)
	up =0;		 //mm up from center on face of cube
	down=0;
	right =0;		 //mm left from center on face of cube
	left=0;

// write sphere defaults
	rounded=false;	 //default for rounded letters on writesphere
	north=0; 		// intial text position (I suggest leave these 0 defaults)
	south=0;
	east=0;
	west=0;
	spin=0;
// writecylinder defaults
	middle=0;     //(mm toward middle of circle)
	ccw=false;   //write on top or bottom in a ccw direction
 	r1=0; 	//(not implimented yet)
	r2=0;	 	//(not implimented yet)

// Contact me if your interested in how to make your own font files
// Its tedious and time consuming, but not very hard

module writecylinder(text,where,radius,height){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360;
	//angle of half width of text
	function mmangle(radius)=(widall/(pi2*radius)*360);

	if ((face=="top")||(face=="bottom") ){
		if (face=="top" ){
			if (center==true){
				writecircle(text,where+[0,0,height/2],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}else{
				writecircle(text,where+[0,0,height],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}
		}else{
			rotate(180,[1,0,0])
			if (center==true){
				writecircle(text,where+[0,0,height/2],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}else{
				writecircle(text,where+[0,0,0],radius-h,rotate=rotate,font=font,h=h,t=t,
				space=space,east=east,west=west,middle=middle,ccw=ccw);
			}
		}

	}else{
//		if (radius>0){
			if (center==true)  {
				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
				translate(where)
				writethecylinder(text,where,radius,height,r1=radius,r2=radius,h=h,
					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
					east=east,west=west,center=center,space=space,rounded=rounded);
			} else{
				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
				translate(where+[0,0,height/2])
					writethecylinder(text,where,radius,height,r1=radius,r2=radius,h=h,
					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
					east=east,west=west,center=center,space=space,rounded=rounded);
			}
// the remarked out code is for cone shaped cylinders (not complete)
//		}else{
//			if (center==true)  {
//				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
//				translate(where)
//				writethecylinder(text,where,radius,height,r1=r1,r2=r2,h=h,
//					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
//					east=east,west=west,center=center,space=space,rounded=rounded);
//			} else{
//				rotate(-mmangle(radius)*(1-abs(rotate)/90),[0,0,1])
//				translate(where+[0,0,height/2])
//					writethecylinder(text,where,radius,height,r1=r1,r2=r2,h=h,
//					rotate=rotate,t=t,font=font,face=face,up=up,down=down,
//					east=east,west=west,center=center,space=space,rounded=rounded);
//			}
//		}
	}
}
module writecircle(text,where,radius){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360;
	//angle of half width of text
	function mmangle(radius)=(widall/(pi2*radius)*360);

	if (ccw==true){
		rotate(-rotate+east-west,[0,0,1]){
			rotate(-mmangle(radius-middle),[0,0,1]){
			translate(where)
				for (r=[0:len(text)-1]){
					rotate(-90+r*NAngle(radius-middle),[0,0,1]) // bottom out=-270+r
					translate([radius-middle,0,0])
					//rotate(90,[1,0,0])
					//rotate(90,[0,1,0])
					rotate(-270,[0,0,1])  // flip text (botom out = -270)
					write(text[r],center=true,h=h,t=t,font=font);
				}
			}
		}
	}else{
		rotate(-rotate-east+west,[0,0,1]){
			rotate(mmangle(radius-middle),[0,0,1]){
			translate(where)
				for (r=[0:len(text)-1]){
					rotate(90-r*NAngle(radius-middle),[0,0,1]) // bottom out=-270+r
					translate([radius-middle,0,0])
					//rotate(90,[1,0,0])
					//rotate(90,[0,1,0])
					rotate(270,[0,0,1])  // flip text (botom out = -270)
					write(text[r],center=true,h=h,t=t,font=font);
				}
			}
		}
	}

}
module writethecylinder(text,where,radius,height,r1,r2){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360*(1-abs(rotate)/90);
	//angle of half width of text

	function mmangle(radius)=(widall/(pi2*radius)*360);
			translate([0,0,up-down])
			rotate(east-west,[0,0,1])
			for (r=[0:len(text)-1]){
				rotate(-90+(r*NAngle(radius)),[0,0,1])
				translate([radius,0,-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid)])
				rotate(90,[1,0,0])
				rotate(90,[0,1,0])
				write(text[r],center=true,h=h,rotate=rotate,t=t,font=font);
		//echo("zloc=",height/2-r*((rotate)/90*wid)+(len(text)-1)/2*((rotate)/90*wid));
			}

}

module writesphere(text,where,radius){
	wid=(.125* h *5.5 * space);
	widall=wid*(len(text)-1)/2;

	echo("-----------------",widall,wid,mmangle(radius));
	//angle that measures width of letters on sphere
	function NAngle(radius)=(wid/(pi2*radius))*360;
	//angle of half width of text
	function mmangle(radius)=(widall/(pi2*radius)*360);

	rotate(east-west,[0,0,1]){
	rotate(south-north,[1,0,0]){
	rotate(spin,[0,1,0]){
	rotate(-mmangle(radius),[0,0,1]){
		if ( rounded== false ){
			translate(where)
			for (r=[0:len(text)-1]){
				rotate(-90+r*NAngle(radius),[0,0,1])
				translate([radius,0,0])
				rotate(90,[1,0,0])
				rotate(90,[0,1,0])
				write(text[r],center=true,h=h,rotate=rotate,t=t,font=font);
			}
		}else{
			difference(){
				translate(where)
				for (r=[0:len(text)-1]){
					rotate(-90+r*NAngle(radius),[0,0,1])
					translate([radius,0,0])
					rotate(90,[1,0,0])
					rotate(90,[0,1,0])
					write(text[r],center=true,h=h,rotate=rotate,t=t*2+h,font=font);
				}
				difference(){ //rounded outside
					sphere(radius+(t*2+h)*2);
					sphere(radius+t/2);
				}
				sphere(radius-t/2); // rounded inside for indented text
			}
		}
	}
}}}
}

module writecube(text,where,size){
	if (str(size)[0] != "["){
		// its a square cube (size was not a matrix so make it one)
		writethecube(text,where,[size,size,size],h=h,rotate=rotate,space=space,
		t=t,font=font,face=face,up=up,down=down,right=right,left=left);

	}else{
		// its not square
		writethecube(text,where,size,h=h,rotate=rotate,space=space,
		t=t,font=font,face=face,up=up,down=down,right=right,left=left);
	}
}
// I split the writecube module into 2 pieces.. easier to add features later
module writethecube(text,where,size){
		if (face=="front") {
			translate([where[0]+right-left,where[1]-size[1]/2,where[2]+up-down])
			rotate(90,[1,0,0])
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="back") {
			translate([where[0]+right-left,where[1]+size[1]/2,where[2]+up-down])
			rotate(90,[1,0,0])   // rotate around the x axis
			rotate(180,[0,1,0])  // rotate around the y axis (z before rotation)
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="left") {
			translate([where[0]-size[0]/2,where[1]-right+left,where[2]+up-down ])
			rotate(90,[1,0,0])   // rotate around the x axis
			rotate(90,[0,-1,0])  // rotate around the y axis  (z before rotation)
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="right") {
			translate([where[0]+size[0]/2,where[1]+right-left,where[2] +up-down])
			rotate(90,[1,0,0])   // rotate around the x axis
			rotate(90,[0,1,0])  // rotate around the y axis  (z before rotation)
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="top") {
			translate([where[0]+right-left,where[1]+up-down,where[2]+size[2]/2 ])
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
		if (face=="bottom") {
			translate([where[0]+right-left,where[1]-up+down,where[2]-size[2]/2 ])
			rotate(180,[1,0,0])
			write(text,center=true,h=h,rotate=rotate,t=t,font=font);
		}
}

module write(word){

	echo (h);
	echo (word);
	echo ("There are " ,len(word) ," letters in this string");
//	echo ("The second letter is ",word[1]);
//	echo (str(word[0],"_"));
rotate(rotate,[0,0,-1]){
	for (r = [0:len(word)]){   // count off each character
		// if the letter is lower case, add an underscore to the end for file lookup
		if ((word[r] == "a" ) || (word[r]== "b")  || (word[r]== "c")
	 	  || (word[r]== "d") || (word[r]== "e") || (word[r]== "f")
	 	  || (word[r]== "g") || (word[r]== "h")  || (word[r]== "i")
       	  	  || (word[r]== "j") || (word[r]== "k") || (word[r]== "l")
       	 	  || (word[r]== "m") || (word[r]== "n") || (word[r]== "o")
       	 	  || (word[r]== "p") || (word[r]== "q") || (word[r]== "r")
	 	  || (word[r]== "s") || (word[r]== "t") || (word[r]== "u")
       	 	  || (word[r]== "v") || (word[r]== "w") || (word[r]== "x")
       	 	  || (word[r]== "y" )|| (word[r]== "z")){
			if (center == true)  {
				translate([0,-h/2,0]){
					scale([.125*h,.125*h,t]){
						translate([ (-len(word)*5.5*space/2) + (r*5.5*space),0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r],"_"));
						}
					}
				}
			}else{
				translate([0,0,t/2]){
					scale([.125*h,.125*h,t]){
						translate([r*5.5*space,0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r],"_"));
						}
					}
				}
			}

		}else{
			if (center == true)  {
				translate([0,-h/2,0]){
					scale([.125*h,.125*h,t]){
						translate([ (-len(word)*5.5*space/2) + (r*5.5*space),0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r]));
						}
					}
				}
			}else{
				translate([0,0,t/2]){
					scale([.125*h,.125*h,t]){
						translate([r*5.5*space,0,0])
						linear_extrude(height=1,convexity=10,center=true){
							import(file = font,layer=str(word[r]));
						}
					}
				}
			}
		}
	}
}
}

/*writecylinder test
translate([0,0,0])
%cylinder(r=20,h=40,center=true);
color([1,0,0])
writecylinder("rotate=90",[0,0,0],20,40,center=true,down=0,rotate=90);
writecylinder("rotate = 30,east = 90",[0,0,0],20,40,center=true,down=0,rotate=30,east=90);
writecylinder("ccw = true",[0,0,0],20,40,center=true,down=0,face="top",ccw=true);
writecylinder("middle = 8",[0,0,0],20,40,h=3,center=true,down=0,face="top",middle=8);
writecylinder("face = top",[0,0,0],20,40,center=true,down=0,face="top");
writecylinder("east=90",[0,0,0],20,40,h=3,center=true,down=0,face="top",east=90);
writecylinder("west=90",[0,0,0],20,40,h=3,center=true,down=0,face="top",ccw=true,west=90);
writecylinder("face = bottom",[0,0,0],20,40,center=true,down=0,face="bottom");
*/
/*writesphere test
sphere(20);
color([1,0,0])
writesphere("Hello World",[0,0,0],20,t=1,h=6);
*/
/* writecube test
translate([30,30,30])
cube([10,15,30],center=true);
write("hello",center=true,rotate =30);
color([1,0,0])
writecube( "front",[30,30,30],[10,15,30],h=5,rotate=-90);
color([0,1,0])
writecube( "back",[30,30,30],size=[10,15,30],h=5,face="back",rotate=90,t=4);
color([0,0,1])
writecube( "left",[30,30,30],[10,15,30],h=5,face="left",up=5);
color([1,1,0])
writecube( "right",where=[30,30,30],size=[10,15,30],h=5,face="right",rotate=55);
color([1,0,1])
writecube( "top",where=[30,30,30],size=[10,15,30],h=5,face="top");
color([1,1,1])
writecube( "bttm",where=[30,30,30],size=[10,15,30],h=5,face="bottom",rotate=90);
*/