screws: start work on different screw heads

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

use <shapes.scad>
use <transforms.scad>
use <misc.scad>

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

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

    head_h = get_screw_head_h(head=head, thread=thread_);
    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=Z, align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head(head=head, thread=thread_, orient=Z, align=Z);
            }

            screw_thread(thread=thread_, h=h+.1, tolerance=tolerance, orient=Z, align=N);

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

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

module screw_cut(nut, thread, head="socket", 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=Z, align=N)
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "screw_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && nut_thread != thread_, "screw_cut: Mismatched nut and thread");*/

    nut_h = get(NutThickness,nut)*tolerance;
    assert(head != U, "screw_cut: head == U");

    head_h = get_screw_head_h(head=head, thread=thread_);
    assert(head_h != U, "screw_cut: head_h is U!");

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

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

            screw_thread_cut(thread=thread_, h=h+.1, tolerance=tolerance, orient=Z, align=N);

            if(with_nut && nut != U)
            {
                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=-Z);
            }

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

module screw_thread(thread, h=10, tolerance=1.00, orient=Z, align=N)
{
    assert(thread!=U, "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=Z, align=N)
{
    assert(thread!=U, "screw_thread_cut: thread is undef");
    threadsize = get(ThreadSize, thread);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(head="socket", thread, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(head != U, "screw_head: head == U");
    assert(thread!=U, "screw_head: thread == undef");

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(head=head, thread=thread);
    head_d = get_screw_head_d(head=head, thread=thread);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket")
        {
            difference()
            {
                cylindera(d=head_d, h = fallback(override_h,head_h));
                translate([0,0,head_h/2])
                cylindera(d=threadsize, h = head_d/2);
            }
        }
        else
        {
            c = head_d;
            f = head_h*1.25;
            r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

            d = r - f; // displacement to move sphere

            difference() {
                /*translate([0, 0, d])*/
                #spherea(r = r, align=-Z);

                translate([0, 0, -r])
                cubea(r*2);

                translate([0, 0, f/3])
                cylinder(r = hexRadius(threadsize), h = f, $fn = 6);

            } // end difference

        }
    }
}

module screw_head_cut(head="socket", thread, tolerance=1.05, override_h=U, orient=Z, align=N)
{
    assert(head != U, "screw_head: head == U");
    assert(thread!=U, "screw_head_cut: thread is undef");

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(head=head, thread=thread);
    head_d = get_screw_head_d(head=head, thread=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=Z);
}

module screw_nut(nut, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(nut!=U, "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=Z, align=N)
{
    assert(nut!=U, "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=Z, align=-Z);
            translate([0,0,-nut_thick+.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
            }
        }
    }
}

// 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);
function hex_radius(hexSize) = hexSize/2/sin(60);

module nut_trap_cut(nut, thread, head, trap_offset=10, screw_l=10*mm, screw_offset=0*mm, cut_screw=false, trap_h=10, trap_axis=-Y, orient=Z, align=N)
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "nut_trap_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && nut_thread != thread_, "nut_trap_cut: Mismatched nut and thread");*/

    threadsize = get(ThreadSize, thread_);
    head_h = get_screw_head_h(head=head, thread=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=Z, align=align)
    {
        if(cut_screw)
        {
            translate(-nut_h/2*Z)
            translate(screw_offset*Z)
            screw_cut($show_vit=false, nut=nut, thread=thread_, with_nut=false, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }
        else
        {
            translate([0,0,nut_h/2+screw_offset])
            screw_thread_cut($show_vit=false, thread=thread_, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }

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

                orient(axis=orient, axis_ref=Z)
                cubea(size=[nut_width_min,nut_width_min,nut_h], align=N);
            }
        }

        if($show_vit)
        {
            translate(-nut_h/2*Z)
            translate(screw_offset*Z)
            %screw(nut=nut, thread=thread_, with_nut=false, tolerance=1, h=screw_l, orient=-Z, align=Z);

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

    }
}

if(false)
{
    all_axes()
    translate($axis*5*mm)
    color($color)
    screw(nut=NutHexM3, h=10*mm, orient=-$axis, align=$axis);
}

// 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(X*dist)
        rotate([0,0,30])
        screw(nut=nut, h=get(NutWidthMax, nut)*5, head_embed=false, orient=-Z, align=Z);
    }
}

if(false)
{
    box_w = 150*mm;
    box_d = 10*mm;
    box_h = 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;

    /*all_axes()*/
    /*for($axis=[X])*/
    /*color($color)*/
    /*translate($axis*15)*/
    /*echo($axis)*/

    /*orient(axis=$axis, axis_ref=-X)*/
    for(y=[-1,1])
    translate(-y*Y*20*mm)
    difference()
    {
        cubea([box_w,box_d,box_h], align=X+Z);
        test_cuts(orient=y*Z);
        /*%test_cuts(orient=y, axis_ref=-Z);*/
    }

}

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

            screw_cut(nut=nut1, h=box_h, nut_offset=0*mm, head_embed=true, orient=orient, align=Z);
            screw_cut(nut=nut2, h=box_h, nut_offset=3*mm, head_embed=false, orient=orient, align=Z);
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=orient, align=Z);
            screw_cut(nut=nut4, h=box_h, head_embed=false, orient=orient, align=Z);

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

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

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

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

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

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

use <shapes.scad>
use <transforms.scad>
use <misc.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=Z, align=N)
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "screw: No nut or thread given");
    /*assert(nut!=U && thread!=U && 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=Z, align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head(thread=thread_, orient=Z, align=Z);
            }

            screw_thread(thread=thread_, h=h+.1, tolerance=tolerance, orient=Z, align=N);

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

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

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=Z, align=N)
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "screw_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && 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 != U, "screw_cut: head_h is U!");

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

    s = threadsize*tolerance;
    total_h = h;
    assert(s != U, "screw_cut: s is U!");
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, 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=Z);
            }

            screw_thread_cut(thread=thread_, h=h+.1, tolerance=tolerance, orient=Z, align=N);

            if(with_nut && nut != U)
            {
                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=-Z);
            }

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

module screw_thread(thread, h=10, tolerance=1.00, orient=Z, align=N)
{
    assert(thread!=U, "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=Z, align=N)
{
    assert(thread!=U, "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=U, orient=Z, align=N)
{
    assert(thread!=U, "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=U, orient=Z, align=N)
{
    assert(thread!=U, "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=Z);
}

module screw_nut(nut, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(nut!=U, "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=Z, align=N)
{
    assert(nut!=U, "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=Z, align=-Z);
            translate([0,0,-nut_thick+.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
            }
        }
    }
}

// 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_offset=0*mm, cut_screw=false, trap_h=10, trap_axis=-Y, orient=Z, align=N)
{
    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "nut_trap_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && 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=Z, align=align)
    {
        if(cut_screw)
        {
            translate(-nut_h/2*Z)
            translate(screw_offset*Z)
            screw_cut($show_vit=false, nut=nut, thread=thread_, with_nut=false, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }
        else
        {
            translate([0,0,nut_h/2+screw_offset])
            screw_thread_cut($show_vit=false, thread=thread_, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }

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

                orient(axis=orient, axis_ref=Z)
                cubea(size=[nut_width_min,nut_width_min,nut_h], align=N);
            }
        }

        if($show_vit)
        {
            translate(-nut_h/2*Z)
            translate(screw_offset*Z)
            %screw(nut=nut, thread=thread_, with_nut=false, tolerance=1, h=screw_l, orient=-Z, align=Z);

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

    }
}

if(false)
{
    all_axes()
    translate($axis*5*mm)
    color($color)
    screw(nut=NutHexM3, h=10*mm, orient=-$axis, align=$axis);
}

// 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(X*dist)
        rotate([0,0,30])
        screw(nut=nut, h=get(NutWidthMax, nut)*5, head_embed=false, orient=-Z, align=Z);
    }
}

if(false)
{
    box_w = 150*mm;
    box_d = 10*mm;
    box_h = 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;

    /*all_axes()*/
    /*for($axis=[X])*/
    /*color($color)*/
    /*translate($axis*15)*/
    /*echo($axis)*/

    /*orient(axis=$axis, axis_ref=-X)*/
    for(y=[-1,1])
    translate(-y*Y*20*mm)
    difference()
    {
        cubea([box_w,box_d,box_h], align=X+Z);
        test_cuts(orient=y*Z);
        /*%test_cuts(orient=y, axis_ref=-Z);*/
    }

}

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

            screw_cut(nut=nut1, h=box_h, nut_offset=0*mm, head_embed=true, orient=orient, align=Z);
            screw_cut(nut=nut2, h=box_h, nut_offset=3*mm, head_embed=false, orient=orient, align=Z);
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=orient, align=Z);
            screw_cut(nut=nut4, h=box_h, head_embed=false, orient=orient, align=Z);

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

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

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

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

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


screw: misc fixes

screw: misc fixes

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]);*/
        }
    }
}

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]);
            }
        }
    }
}

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");

    thickness = get(NutThickness,nut)*tolerance;
    d = get(NutWidthMin, nut)*tolerance;
    facets = get(NutFacets, nut);
    nut_hex_radius = hex_radius(get(NutWidthMax, nut))+.1;
    cylindera($fn=get(NutFacets, nut), r=nut_hex_radius, h=fallback(override_h, thickness), 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");

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

function hex_radius(hexSize) = hexSize/2/sin(60);

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 = get(NutWidthMin, nut);
    nut_hex_radius = hex_radius(nut_width)+.1*mm;
    s = nut_hex_radius;
    total_h = nut_h;
    size_align(size=[s, s, 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=get(NutFacets, nut), r=nut_hex_radius, h=nut_h, align=[0,0,0]);
                }

                orient(orient)
                cubea(size=[nut_width,nut_width,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_nutwidth = v_get(AllNut,NutWidthMin);
        dist = v_cumsum(v_nutwidth, 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;
    box_h = 10;
    box_d = 10;
    o = 10;

    /*$show_vit = true;*/
    $fs= 0.1;
    $fa = 5;

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

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

        test_cuts();
    }
    /*difference()*/
    /*{*/
        /*cubea([box_w,box_d/2,box_h], align=[1,-1,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*mm, nut_offset=0*mm, head_embed=true, orient=[0,0,-1], align=[0,0,1]);*/
            /*screw_cut(nut=nut2, h=box_h*mm, 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,5,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=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]);
        }
    }
}


The font names were added.

The font names were added.

use <../../external-resources/batman/batman.scad>

use <../../shapes/heart/heart.scad>
use <../../shapes/open-cylinder/open-cylinder.scad>

module lightSignal(baseHeight = 2,
                    icon1 = "",
                    icon1_scale = 1,
                    icon1_x = 0,
                    icon1_y = 0,
                    icon2 = "",
                    icon2_scale = 1.0,
                    icon2_x = 0,
                    icon2_y = 0,
                    text1 = "",
					text1_fontName = "Bauhaus 93:style=Regular",
                    text1_fontSize = 7.5,
                    text1_x = 0,
                    text1_y = 0,
                    text2 = "",
					text2_fontName = "Bauhaus 93:style=Regular",
                    text2_fontSize = 7.5,
                    text2_x = 0,
                    text2_y = 0)
{
	difference()
	{
		lightSignal_shell(baseHeight, showOriginal = false);

		lightSignal_cutouts(icon1,
                                    icon1_scale,
                                    icon1_x,
                                    icon1_y,
                                    icon2,
                                    icon2_scale,
                                    icon2_x,
                                    icon2_y,
                                    text1,
									text1_fontName,
                                    text1_fontSize,
                                    text1_x,
                                    text1_y,
                                    text2,
									text2_fontName,
                                    text2_fontSize,
                                    text2_x,
                                    text2_y);
	}
}

/** Support functions and moduules follow. **/

// DO NOT CHANGE THE RADIUS; IT MACHES THE ORIGINAL MODEL
function lightSignal_stlBaseInnerRadius() = 18.5;

function lightSignal_stlBaseOuterRadius() = lightSignal_stlBaseInnerRadius() + 2.5;

module lightSignal_cutouts(icon1,
                            icon1_scale,
                            icon1_x,
                            icon1_y,
                            icon2,
                            icon2_scale,
                            icon2_x,
                            icon2_y,
                            text1,
							text1_fontName,
                            text1_fontSize,
                            text1_x,
                            text1_y,
                            text2,
							text2_fontName,
                            text2_fontSize,
                            text2_x,
                            text2_y)
{
		lightSignal_textCutouts(text1,
								text1_fontName,
                                text1_fontSize,
                                text1_x,
                                text1_y,
                                text2,
								text2_fontName,
                                text2_fontSize,
                                text2_x,
                                text2_y);

		lightSignal_iconCutouts(icon1,
                                icon1_scale,
                                icon1_x,
                                icon1_y,
                                icon2,
                                icon2_scale,
                                icon2_x,
                                icon2_y);
}

module lightSignal_iconCutouts(icon1,
                                icon1_scale,
                                icon1_x,
                                icon1_y,
                                icon2,
                                icon2_scale,
                                icon2_x,
                                icon2_y)
{
    lightSignal_oneIconCutout(icon1,
                                icon1_scale,
                                icon1_x,
                                icon1_y);

    lightSignal_oneIconCutout(icon2,
                                icon2_scale,
                                icon2_x,
                                icon2_y);
}

module lightSignal_oneIconCutout(
                    icon1,
                    icon1_scale,
                    icon1_x,
                    icon1_y)
{
    if(icon1 == "")
    {
        // do nothing
    }
    else
    {
        zScale = 3;
        translate([icon1_x, icon1_y, -1.01])
        if(icon1 == "heart")
        {
                scale([icon1_scale, icon1_scale, zScale])
                heartThumbnail();
        }
        else if(icon1 == "bat")
        {
                scale([icon1_scale, icon1_scale, zScale])
                batmanLogoThumbnail();
        }
    }
}

module lightSignal_oneTextCutout(text, fontName, fontSize, x, y)
{
    if(text == "")
    {
        // do nothing
    }
    else
    {
        extrudeHeight = 6;
        zTranslate = -3;

        translate([x, y, zTranslate])
        linear_extrude(height = extrudeHeight)
        text(text = text, font = fontName, size = fontSize);
    }
}

module lightSignal_shell(baseHeight,
                        showOriginal = false)
{
	signalStl = "../../../../../../../../../../../../Versioning/world/beto-land-world/3d-printing/super-heroes/batman/bat-signal/customizable_phone_bat_signal_20150130-9347-hv0ikc-0.stl";

	stlBaseInnerRadius = lightSignal_stlBaseInnerRadius();
	stlBaseOuterRadius = lightSignal_stlBaseOuterRadius();

	union()
	{
		// this is the top hole/cutout
		zTopHoleTranslate = 35;
		color("blue")
		translate([0, 0, zTopHoleTranslate])
		openCylinder(height=1, outerRadius = 12, innerRadius=6);

		// connector for the shaft and top hole
		color("pink")
		translate([0, 0, zTopHoleTranslate-3])
		openCylinder(height=3.1, outerRadius = 19, innerRadius=8);

		// this is the bottom wide shaft
		zTranslate = -baseHeight / 2.0;
		color("orange")
		translate([0, 0, zTranslate])
		openCylinder(height=zTopHoleTranslate, outerRadius = stlBaseOuterRadius, innerRadius = stlBaseInnerRadius);

		// this thing was modeld after this original
		if(showOriginal)
		{
			color("yellow")
			translate([0, 0, zTranslate])
			import(signalStl);
		}

		// This is the bottom disk, that holds the text/icon cutout.
		color("green")
		cylinder(r=stlBaseInnerRadius+0.1, h=baseHeight, center=true);
	}
}

module lightSignal_textCutouts(text1,
								text1_fontName,
                                text1_fontSize,
                                text1_x,
                                text1_y,
                                text2,
								text2_fontName,
                                text2_fontSize,
                                text2_x,
                                text2_y)
{
    lightSignal_oneTextCutout(text1, text1_fontName, text1_fontSize, text1_x, text1_y);

    lightSignal_oneTextCutout(text2, text2_fontName, text2_fontSize, text2_x, text2_y);
}

use <../../external-resources/batman/batman.scad>

use <../../shapes/heart/heart.scad>
use <../../shapes/open-cylinder/open-cylinder.scad>

module lightSignal(baseHeight = 2,
                    icon1 = "",
                    icon1_scale = 1,
                    icon1_x = 0,
                    icon1_y = 0,
                    icon2 = "",
                    icon2_scale = 1.0,
                    icon2_x = 0,
                    icon2_y = 0,
                    text1 = "",
                    text1_fontSize = 7.5,
                    text1_x = 0,
                    text1_y = 0,
                    text2 = "",
                    text2_fontSize = 7.5,
                    text2_x = 0,
                    text2_y = 0)
{
	difference()
	{
		lightSignal_shell(baseHeight, showOriginal = false);

		lightSignal_cutouts(icon1,
                                    icon1_scale,
                                    icon1_x,
                                    icon1_y,
                                    icon2,
                                    icon2_scale,
                                    icon2_x,
                                    icon2_y,
                                    text1,
                                    text1_fontSize,
                                    text1_x,
                                    text1_y,
                                    text2,
                                    text2_fontSize,
                                    text2_x,
                                    text2_y);
	}
}

/** Support functions and moduules follow. **/

// DO NOT CHANGE THE RADIUS; IT MACHES THE ORIGINAL MODEL
function lightSignal_stlBaseInnerRadius() = 18.5;

function lightSignal_stlBaseOuterRadius() = lightSignal_stlBaseInnerRadius() + 2.5;

module lightSignal_cutouts(icon1,
                            icon1_scale,
                            icon1_x,
                            icon1_y,
                            icon2,
                            icon2_scale,
                            icon2_x,
                            icon2_y,
                            text1,
                            text1_fontSize,
                            text1_x,
                            text1_y,
                            text2,
                            text2_fontSize,
                            text2_x,
                            text2_y)
{
		lightSignal_textCutouts(text1,
                                        text1_fontSize,
                                        text1_x,
                                        text1_y,
                                        text2,
                                        text2_fontSize,
                                        text2_x,
                                        text2_y);

		lightSignal_iconCutouts(icon1,
                                        icon1_scale,
                                        icon1_x,
                                        icon1_y,
                                        icon2,
                                        icon2_scale,
                                        icon2_x,
                                        icon2_y);
}

module lightSignal_iconCutouts(icon1,
                                icon1_scale,
                                icon1_x,
                                icon1_y,
                                icon2,
                                icon2_scale,
                                icon2_x,
                                icon2_y)
{
    lightSignal_oneIconCutout(icon1,
                                icon1_scale,
                                icon1_x,
                                icon1_y);

    lightSignal_oneIconCutout(icon2,
                                icon2_scale,
                                icon2_x,
                                icon2_y);
}

module lightSignal_oneIconCutout(
                    icon1,
                    icon1_scale,
                    icon1_x,
                    icon1_y)
{
    if(icon1 == "")
    {
        // do nothing
    }
    else
    {
        zScale = 3;
        translate([icon1_x, icon1_y, -1.01])
        if(icon1 == "heart")
        {
                scale([icon1_scale, icon1_scale, zScale])
                heartThumbnail();
        }
        else if(icon1 == "bat")
        {
                scale([icon1_scale, icon1_scale, zScale])
                batmanLogoThumbnail();
        }
    }
}

module lightSignal_oneTextCutout(text, fontSize, x, y)
{
    if(text == "")
    {
        // do nothing
    }
    else
    {
        extrudeHeight = 6;
        zTranslate = -3;
        fontName = "Bauhaus 93:style=Regular";

        translate([x, y, zTranslate])
        linear_extrude(height = extrudeHeight)
        text(text = text, font = fontName, size = fontSize);
    }
}

module lightSignal_shell(baseHeight,
                        showOriginal = false)
{
	signalStl = "../../../../../../../../../../../../Versioning/world/beto-land-world/3d-printing/super-heroes/batman/bat-signal/customizable_phone_bat_signal_20150130-9347-hv0ikc-0.stl";

	stlBaseInnerRadius = lightSignal_stlBaseInnerRadius();
	stlBaseOuterRadius = lightSignal_stlBaseOuterRadius();

	union()
	{
		// this is the top hole/cutout
		zTopHoleTranslate = 35;
		color("blue")
		translate([0, 0, zTopHoleTranslate])
		openCylinder(height=1, outerRadius = 12, innerRadius=6);

		// connector for the shaft and top hole
		color("pink")
		translate([0, 0, zTopHoleTranslate-3])
		openCylinder(height=3.1, outerRadius = 19, innerRadius=8);

		// this is the bottom wide shaft
		zTranslate = -baseHeight / 2.0;
		color("orange")
		translate([0, 0, zTranslate])
		openCylinder(height=zTopHoleTranslate, outerRadius = stlBaseOuterRadius, innerRadius = stlBaseInnerRadius);

		// this thing was modeld after this original
		if(showOriginal)
		{
			color("yellow")
			translate([0, 0, zTranslate])
			import(signalStl);
		}

		// This is the bottom disk, that holds the text/icon cutout.
		color("green")
		cylinder(r=stlBaseInnerRadius+0.1, h=baseHeight, center=true);
	}
}

module lightSignal_textCutouts(text1,
                                text1_fontSize,
                                text1_x,
                                text1_y,
                                text2,
                                text2_fontSize,
                                text2_x,
                                text2_y)
{
    lightSignal_oneTextCutout(text1, text1_fontSize, text1_x, text1_y);

    lightSignal_oneTextCutout(text2, text2_fontSize, text2_x, text2_y);
}


detailed sonar holder and platform

detailed sonar holder and platform

$fs = 0.1;
$fa = 5;

use <hcsr04.scad>

module wheel() {
    color("black") rotate([90, 90, 0]) difference() {
        #cylinder(d=47, h=23, center=true);
        cylinder(d=30, h=26, center=true);
    }
}

module base() {

    // 4 wheels
    translate([77.5, 60, 47/2]) wheel();
    translate([-77.5, 60, 47/2]) wheel();
    translate([77.5, -60, 47/2]) wheel();
    translate([-77.5, -60, 47/2]) wheel();

    // front axe assemby - slightly longer
    translate([77.5-5, 0, 47/2]) color("gray") cube(size=[25, 103, 26], center=true);
    // rear axe assemby
    translate([-77.5, 0, 47/2]) color("gray") cube(size=[26, 97, 26], center=true);

    color("gray") translate ([0, 0, 12]) {

        // base plate
        linear_extrude(height = 2) base_plate();
        linear_extrude(height = 7) difference() {
            base_plate();
            offset(-2) base_plate();
        }

        // shaft
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        //shaft ribs
        translate ([14, 4, 23]) cube(size=[67, 2, 4], center=false);
        translate ([14, -6, 23]) cube(size=[67, 2, 4], center=false);
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        translate ([-81, 4, 23]) cube(size=[45, 2, 6], center=false);
        translate ([-81, -6, 23]) cube(size=[45, 2, 6], center=false);
        // servo
        linear_extrude(height = 15)  polygon([
            [29,0], [79,0],
            [79,-23], [70,-23],[49,-40],[29,-40]
        ]);

        // motor
        translate ([-79+30, -16, 23/2+2]) rotate([0, 90, 0]) cylinder(d=23, h=32, center=false);

        // gear
        translate ([-79+23, 0, 34/2]) rotate([0, 90, 0]) cylinder(d=34, h=6, center=false);

        // battery
        translate ([-5/2, 30/2+7, 16/2+2]) cube(size=[84, 30, 16], center=true);

        // battery holder
        translate ([-79+23, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([79-29, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([-5/2, 20, 22]) cube(size=[110, 13, 2], center=true);

        // front shocks
        translate ([162/2, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[23,44],[18,48],[5,41],[-5,41],[-18,48],[-23,44], [-38,0],[38,0]]);

        // rear shocks
        translate ([-162/2-16, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[25,48],[20,48],[5,38],[-5,38],[-20,48],[-25,48], [-38,0],[38,0]]);
    }
}

module base_plate() {
    polygon([
        [-79,25], [-70,25],[-54,40],[49,40],[70,23], [79,23],
        [79,-23], [70,-23],[49,-40],[-54,-40],[-70,-25], [-79,-25]
    ]);
}

module platform() {

    difference() {
    color("black") translate ([0, 0, 12+32+4]) difference() {
        union() {
            linear_extrude(height = 3) intersection() {
                difference() {
                    offset(-10) offset(30) offset(-20)
                       polygon([
                         [-200,25], [-70,25],[-44,60],[44,60],[70,23], [200,23],
                         [200,-23], [70,-23],[44,-60],[-44,-60],[-70,-25], [-200,-25]
                       ]);

                    offset(5) offset(-5) translate ([-2.5, 0, 0]) difference() {
                        square(size=[90,70], center=true);
                        translate ([-45, -35, 0]) circle(r=7.5, center=true);
                        translate ([ 45, -35, 0]) circle(r=7.5, center=true);                    translate ([-45,  35, 0]) circle(r=7.5, center=true);                    translate ([ 45,  35, 0]) circle(r=7.5, center=true);                }

                }
                square(size=[162,120], center=true);
            }

            intersection() { translate ([0, 0, 100]) cube(size=[200,200,200], center=true); union() {
            // shock tower mount points
            // rear
            #translate ([-81, -25, 0]) { hull() {
                cube(size=[4, 7, 12-3.5], center=false);
                translate ([4/2, 3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            translate ([8/2, 3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            #translate ([-81, 25-7, 0]) { hull() {
                cube(size=[4, 7, 12-3.5], center=false);
                translate ([4/2, 7-3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            translate ([8/2, 7-3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            // front
            #translate ([81-4, -46/2, 0]) hull() {
                cube(size=[4, 7, 8-3.5], center=false);
                translate ([4/2, 3.5, 8-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            #translate ([81-4, 46/2-7, 0]) hull() {
                cube(size=[4, 7, 8-3.5], center=false);
                translate ([4/2, 7-3.5, 8-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            }}
        }

        // board mount holes
        translate ([-(45-2.5)-2.5,  (35-2.5), 0]) cylinder(d=2.2, h=10, center=true);
        translate ([-(45-2.5)-2.5, -(35-2.5), 0]) cylinder(d=2.2, h=10, center=true);
        translate ([ (45-2.5)-2.5,  (35-2.5), 0]) cylinder(d=2.2, h=10, center=true);
        translate ([ (45-2.5)-2.5, -(35-2.5), 0]) cylinder(d=2.2, h=10, center=true);

        // servo wire hole
        translate ([55, -20, 0]) cylinder(d=10, h=10, center=true);
        translate ([55,  20, 0]) cylinder(d=10, h=10, center=true);

        // mount holes
        // front
        #translate ([81, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81, 42.5/2-3/2, 8-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        #translate ([81,-42.5/2+3/2, 8-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);

        #translate ([81-4-5/2, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=6.1, h=5, center=true);
        #translate ([81-4-5/2,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=6.1, h=5, center=true);

        // rear
        #translate ([-81, 46.5/2-3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81, 46.5/2-3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
    }
    arrangebottom(30) hbaseholes(center=true);
    //arrangebottom(45) hbaseholes();
    }
}

module board() {

    // base
    color("yellow") translate ([-2.5, 0, 43]) cube(size=[90, 70, 1.2], center=true);

    // teensy
    color("green") translate ([-25, 0, 43+5]) cube(size=[20, 63, 10], center=true);

    // MPU-9250
    color("red") translate ([0, 15, 43+5]) cube(size=[20, 20, 10], center=true);
}

module esc() {
    color("green") cube(size=[36, 26, 2], center=true);
    color("black") translate ([36/2, 0, 0]) rotate([0, 90, 0]) cylinder(d=8, h=16, center=false);

    // esc support box ?
    // hcolor("black") translate ([0, 0, -11]) cube(size=[30, 20, 20], center=true);
}

module vsonar() {

    // vertical sonar
    translate ([0, -10, 45]) rotate([0, 90, 0]) hcsr04();

    // mount plate
    color("gray") translate ([1.5, -10, -6]) cube(size=[3, 20, 51], center=false);
    color("gray") translate ([-8.5, -10, -6]) cube(size=[10, 20, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 22.5]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module hbaseholes(center = false)
{
    translate ([-5,   0, -15]) cylinder(d=3.2, h=15, center=false);
    if (!center) {
        translate ([-5,  19, -15]) cylinder(d=3.2, h=15, center=false);
        translate ([-5, -19, -15]) cylinder(d=3.2, h=15, center=false);
    }
}

module hmount() {
    // mount plate
    color ("gray") {

        // front
        difference() {
            translate ([1.5, -48/2, -6]) #hull() {
                cube(size=[3, 48, 22], center=false);
                translate ([0, 43, 22]) rotate([90, 0, 90]) cylinder(r=5, h=3, center=false);
                translate ([0, 5, 22]) rotate([90, 0, 90]) cylinder(r=5, h=3, center=false);
            }

            translate ([0, -45/2, 0]) rotate([90, 0, 90]) {

                // sonar
                translate([16/2+1,18/2+1,1.3]) cylinder(d=16.5, h=15);
                translate([16/2+27+1,18/2+1,1.3]) cylinder(d=16.5, h=15);

                //xtal(s)
                translate([45/2-3.25,20-4,1.3]) hull()
                {
                    translate([0,0,0]) cylinder(d=5, h=5);
                    translate([6.5,0,0]) cylinder(d=5, h=5);
                }
                translate([45/2-3.25, 4,1.3]) hull()
                {
                    translate([0,0,0]) cylinder(d=5, h=5);
                    translate([6.5,0,0]) cylinder(d=5, h=5);
                }

                // screws
                translate([2.5,2.5,4.5]) screw2x6bore();
                translate([2.5+40,2.5+15,4.5]) screw2x6bore();
                translate([2.5+40,2.5,4.5]) screw2x6bore();
                translate([2.5,2.5+15,4.5]) screw2x6bore();
            }

            translate ([3, 0, 10])
                cube(size=[5, 20, 9], center=true);
        }

        //base
        difference() {
            #hull() {
                translate ([-3.5, -48/2, -6]) cube(size=[5, 48, 5], center=false);
                translate ([-3.5, -48/2+5, -6]) cylinder(r=5, h=5, center=false);
                translate ([-3.5, 48/2-5, -6]) cylinder(r=5, h=5, center=false);
            }
            #hbaseholes();
        }
    }
}

module screw2x6bore() {
    rotate([180, 0, 0]) {
        cylinder(d=2, h=6);
        translate ([0, 0, -1.3])
            cylinder(d1=2*3.6, d2=0, h=2*1.3);
    }
}

module hsonar() {

    // horizontal sonar
    translate ([0, -45/2, 0]) rotate([90, 0, 90]) hcsr04();

    hmount();

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 10]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module car()
{
    base();
    platform();
    board();

    //translate ([10, -23, 35]) esc();
    translate ([-10, 0, 40]) rotate([0, 0, 180]) esc();
}

// full model - vertical sonars
module fullv() {
    car();

    translate ([68, 0, 55]) vsonar();
    translate ([60, 25, 55]) rotate([0, 0, 30]) vsonar();
    translate ([60, -25, 55]) rotate([0, 0, -30]) vsonar();
    translate ([35, 35, 55]) rotate([0, 0, 60]) vsonar();
    translate ([35, -35, 55]) rotate([0, 0, -60]) vsonar();
}

// full model - horizontal sonars
module fullh() {
    car();

    translate ([68, 0, 55]) hsonar();
    translate ([40, 35, 55]) rotate([0, 0, 30]) hsonar();
    translate ([40, -35, 55]) rotate([0, 0, -30]) hsonar();
    translate ([-10, 35, 55]) rotate([0, 0, 60]) hsonar();
    translate ([-10, -35, 55]) rotate([0, 0, -60]) hsonar();
}

module arrangebottom(a) {
    translate ([68, 0, 57]) children();
    translate ([40, 40, 57]) rotate([0, 0, a]) children();
    translate ([40, -40, 57]) rotate([0, 0, -a]) children();

    translate ([5, 52.5, 42]) rotate([180, 0, 2*a]) children();
    translate ([5, -52.5, 42]) rotate([180, 0, -2*a]) children();
}

module fullb() {
    car();
    arrangebottom(30) hsonar();
}

platform();

//fullb();

//translate ([0, 0, 4.5]) rotate([0, 90, 0]) hmount();

//screw2x6bore();

//projection(cut=true) translate ([0, 0, -47]) platform();

use <hcsr04.scad>

module wheel() {
    color("black") rotate([90, 90, 0]) difference() {
        #cylinder(d=47, h=23, center=true);
        cylinder(d=30, h=26, center=true);
    }
}

module base() {

    // 4 wheels
    translate([77.5, 60, 47/2]) wheel();
    translate([-77.5, 60, 47/2]) wheel();
    translate([77.5, -60, 47/2]) wheel();
    translate([-77.5, -60, 47/2]) wheel();

    // front axe assemby - slightly longer
    translate([77.5-5, 0, 47/2]) color("gray") cube(size=[25, 103, 26], center=true);
    // rear axe assemby
    translate([-77.5, 0, 47/2]) color("gray") cube(size=[26, 97, 26], center=true);

    color("gray") translate ([0, 0, 12]) {

        // base plate
        linear_extrude(height = 2) base_plate();
        linear_extrude(height = 7) difference() {
            base_plate();
            offset(-2) base_plate();
        }

        // shaft
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        //shaft ribs
        translate ([14, 4, 23]) cube(size=[65, 2, 4], center=false);
        translate ([14, -6, 23]) cube(size=[65, 2, 4], center=false);
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        translate ([-79, 4, 23]) cube(size=[43, 2, 6], center=false);
        translate ([-79, -6, 23]) cube(size=[43, 2, 6], center=false);
        // servo
        linear_extrude(height = 15)  polygon([
            [29,0], [79,0],
            [79,-23], [70,-23],[49,-40],[29,-40]
        ]);

        // motor
        translate ([-79+30, -16, 23/2+2]) rotate([0, 90, 0]) cylinder(d=23, h=32, center=false);

        // gear
        translate ([-79+23, 0, 34/2]) rotate([0, 90, 0]) cylinder(d=34, h=6, center=false);

        // battery
        translate ([-5/2, 30/2+7, 16/2+2]) cube(size=[84, 30, 16], center=true);

        // battery holder
        translate ([-79+23, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([79-29, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([-5/2, 20, 22]) cube(size=[110, 13, 2], center=true);

        // front shocks
        translate ([79, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[23,41], [-23,41],[-38,0],[38,0]]);

        // rear shocks
        translate ([-79-16, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[25,45], [-25,45],[-38,0],[38,0]]);
    }
}

module base_plate() {
    polygon([
        [-79,25], [-70,25],[-54,40],[49,40],[70,23], [79,23],
        [79,-23], [70,-23],[49,-40],[-54,-40],[-70,-25], [-79,-25]
    ]);
}

module platform() {

    color("black") translate ([0, 0, 46]) difference() {
        union() {
            #linear_extrude(height = 3)
                difference() {
                    offset(20) offset(-20)
                       polygon([
                         [-79,25], [-70,25],[-44,60],[44,60],[70,23], [79,23],
                         [79,-23], [70,-23],[44,-60],[-44,-60],[-70,-25], [-79,-25]
                       ]);

                    offset(5) offset(-10) polygon([
                        [-54,40],[29,40],[29,-40],[-54,-40]
                    ]);
                }

            // shock tower mount points
            translate ([-79, -25, 0]) cube(size=[5, 50, 11], center=false);
            translate ([79-5, -23, 0]) cube(size=[5, 46, 7], center=false);

            // joint mount plates to body
            translate ([-79, -25, 0]) cube(size=[15, 50, 3], center=false);
            translate ([79-15, -23, 0]) cube(size=[15, 46, 3], center=false);
        }

        // board mount holes
        #translate ([-54, 31, 0])  cylinder(d=3.2, h=10, center=true);
        #translate ([-54, -31, 0]) cylinder(d=3.2, h=10, center=true);
        #translate ([29, 31, 0])   cylinder(d=3.2, h=10, center=true);
        #translate ([29, -31, 0])  cylinder(d=3.2, h=10, center=true);
    }
}

module board() {

    // base
    color("yellow") translate ([-12.5, 0, 45]) cube(size=[90, 70, 1], center=true);

    // teensy
    color("green") translate ([-25, 0, 45+5]) cube(size=[20, 63, 10], center=true);

    // MPU-9250
    color("red") translate ([0, 15, 45+5]) cube(size=[20, 20, 10], center=true);
}

module vsonar() {

    // vertical sonar
    translate ([0, -10, 45]) rotate([0, 90, 0]) hcsr04();

    // mount plate
    color("gray") translate ([1.5, -10, -6]) cube(size=[3, 20, 51], center=false);
    color("gray") translate ([-8.5, -10, -6]) cube(size=[10, 20, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 22.5]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module esc() {
    color("green") cube(size=[36, 26, 2], center=true);
    color("black") translate ([36/2, 0, 0]) rotate([0, 90, 0]) cylinder(d=8, h=16, center=false);

    // esc support box ?
    // hcolor("black") translate ([0, 0, -11]) cube(size=[30, 20, 20], center=true);
}

module hsonar() {

    // horizontal sonar
    translate ([0, -45/2, 0]) rotate([90, 0, 90]) hcsr04();

    // mount plate
    color("gray") translate ([1.5, -45/2, -6]) cube(size=[3, 45, 26], center=false);
    color("gray") translate ([-8.5, -45/2, -6]) cube(size=[10, 45, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 10]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module car()
{
    base();
    platform();
    board();

    //translate ([10, -23, 35]) esc();
    translate ([-10, 0, 40]) rotate([0, 0, 180]) esc();
}

// full model - vertical sonars
module fullv() {
    car();

    translate ([68, 0, 55]) vsonar();
    translate ([60, 25, 55]) rotate([0, 0, 30]) vsonar();
    translate ([60, -25, 55]) rotate([0, 0, -30]) vsonar();
    translate ([35, 35, 55]) rotate([0, 0, 60]) vsonar();
    translate ([35, -35, 55]) rotate([0, 0, -60]) vsonar();
}

// full model - horizontal sonars
module fullh() {
    car();

    translate ([68, 0, 55]) hsonar();
    translate ([40, 35, 55]) rotate([0, 0, 30]) hsonar();
    translate ([40, -35, 55]) rotate([0, 0, -30]) hsonar();
    translate ([-10, 35, 55]) rotate([0, 0, 60]) hsonar();
    translate ([-10, -35, 55]) rotate([0, 0, -60]) hsonar();
}

module fullb() {
    car();

    translate ([68, 0, 55]) hsonar();
    translate ([40, 40, 55]) rotate([0, 0, 30]) hsonar();
    translate ([40, -40, 55]) rotate([0, 0, -30]) hsonar();

    translate ([5, 50, 40]) rotate([180, 0, 60]) hsonar();
    translate ([5, -50, 40]) rotate([180, 0, -60]) hsonar();
}

fullb();

//projection(cut=true) translate ([0, 0, -47]) platform();


bearing: remove redundant/duplicate

bearing: remove redundant/duplicate

use <shapes.scad>
include <bearing_data.scad>
include <units.scad>

module bearing(bearing_type, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    h = override_h==undef ? bearing_type[2] : override_h;
    size_align(size=[bearing_type[1],bearing_type[1],h], align=align ,orient=orient)
    difference()
    {
        // outer
        fncylindera(h=h, d=bearing_type[1], align=[0,0,0]);
        // inner
        fncylindera(h=h+.1, d=bearing_type[0], align=[0,0,0]);
        // clips
        if(len(bearing_type) > 3)
        {
            clip_depth=.5;
            for(z=[-1,1])
            translate([0,0,z*bearing_type[3]/2])
            difference()
            {
                fncylindera(h=1*mm, d=bearing_type[2]+1, align=[0,0,-z]);
                fncylindera(h=1*mm+.1, d=bearing_type[4]-clip_depth, align=[0,0,-z]);
            }

        }
    }
}

module bearing_mount_holes(bearing_type, ziptie_type=[2*mm, 3*mm], ziptie_bearing_distance=3*mm, tolerance=1.01, orient=[1,0,0], ziptie_dist=undef, show_zips=false)
{
    ziptie_thickness = ziptie_type[0];
    ziptie_width = ziptie_type[1]+0.6*mm;

    ziptie_dist_ = (ziptie_dist==undef?bearing_type[3]/2:ziptie_dist);

    orient(orient)
    {
        // Main bearing cut
        fncylindera(h=bearing_type[2]*tolerance, d=bearing_type[1]*tolerance, orient=[0,0,1]);

        for(z=[-1,1])
        translate([0,0,z*ziptie_dist_ - z*1/2])
        hollow_cylinder(
                d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                thickness = ziptie_thickness*2,
                h = ziptie_width,
                taper=false,
                orient=[0,0,1],
                align=[0,0,0]
                );

        // for linear rod
        fncylindera(d=bearing_type[0]*1.5, h=100, orient=[0,0,1]);

        if(show_zips)
        {
            for(z=[-1,1])
            translate([0,0,z*ziptie_dist_])
            {
                %hollow_cylinder(
                        d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                        thickness = ziptie_thickness,
                        h = ziptie_width,
                        orient=[0,0,1],
                        align=[0,0,-z]
                        );
            }
        }
    }
}

if(false)
{
    b=bearing_igus_rj4jp_01_12;
    bearing_mount_holes(b, orient=[0,0,1]);
    translate([30,0,0])
    bearing(b, orient=[0,0,1]);
}

use <shapes.scad>
include <bearing_data.scad>
include <units.scad>

module bearing(bearing_type, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    h = override_h==undef ? bearing_type[2] : override_h;
    size_align(size=[bearing_type[1],bearing_type[1],h], align=align ,orient=orient)
    difference()
    {
        // outer
        fncylindera(h=h, d=bearing_type[1], align=[0,0,0]);
        // inner
        fncylindera(h=h+.1, d=bearing_type[0], align=[0,0,0]);
        // clips
        if(len(bearing_type) > 3)
        {
            clip_depth=.5;
            for(z=[-1,1])
            translate([0,0,z*bearing_type[3]/2])
            difference()
            {
                fncylindera(h=1*mm, d=bearing_type[2]+1, align=[0,0,-z]);
                fncylindera(h=1*mm+.1, d=bearing_type[4]-clip_depth, align=[0,0,-z]);
            }

        }
    }
}

module bearing_mount_holes(bearing_type, ziptie_type=[2*mm, 3*mm], ziptie_bearing_distance=3*mm, tolerance=1.01, orient=[1,0,0], ziptie_dist=undef, show_zips=false)
{
    ziptie_thickness = ziptie_type[0];
    ziptie_width = ziptie_type[1]+0.6*mm;

    ziptie_dist_ = (ziptie_dist==undef?bearing_type[3]/2:ziptie_dist);

    orient(orient)
    {
        // Main bearing cut
        fncylindera(h=bearing_type[2]*tolerance, d=bearing_type[1]*tolerance, orient=[0,0,1]);

        for(z=[-1,1])
        translate([0,0,z*ziptie_dist_ - z*1/2])
        hollow_cylinder(
                d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                thickness = ziptie_thickness*2,
                h = ziptie_width,
                taper=false,
                orient=[0,0,1],
                align=[0,0,0]
                );

        // bearing
        fncylindera(h=bearing_type[2], d=bearing_type[1], orient=[0,0,1]);

        // for linear rod
        fncylindera(d=bearing_type[0]*1.5, h=100, orient=[0,0,1]);

        if(show_zips)
        {
            for(z=[-1,1])
            translate([0,0,z*ziptie_dist_])
            {
                %hollow_cylinder(
                        d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                        thickness = ziptie_thickness,
                        h = ziptie_width,
                        orient=[0,0,1],
                        align=[0,0,-z]
                        );
            }
        }
    }
}

if(false)
{
    b=bearing_igus_rj4jp_01_12;
    bearing_mount_holes(b, orient=[0,0,1]);
    translate([30,0,0])
    bearing(b, orient=[0,0,1]);
}