screws: use material module

screws: use material module

include <system.scad>
include <thread-data.scad>
include <nut-data.scad>
include <materials.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);

    material(Mat_Steel)
    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);
    material(Mat_Steel)
    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);
    material(Mat_Steel)
    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(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);
        }
    }
}


Corn base

Corn base

// Unicorn by Paul Houghton ©2015, CC BY-NC-AS license, https://creativecommons.org/licenses/
$fn=45;

scale = 1;

head_big_radius = 10*scale;
head_small_radius = 4.5*scale;
head_length = 18*scale;
head_angle = 50*scale;

horn_length = 20*scale;
horn_radius = 2.8*scale;

neck_radius = 2*scale;
neck_ratio = .2; // Flattens the interface to the top body
neck_top_x = 3*scale;

body_x = 15*scale;
body_z = 28*scale;
body_radius = 14*scale;
body_back_radius = 12*scale;
body_length = 33*scale;

leg_length = (28 + body_radius)*scale;
leg_radius = 4*scale;

cute_leg_first_ratio = 0.65;
cute_leg_second_ratio = 0.25;
cute_leg_third_ratio = 0.11;

base_thickness = 10*scale;
base_width = 40*scale;
base_corner_radius = 5*scale;
base_length = 70*scale;

module head() {
    rotate([0, -head_angle, 0]) {
        hull () {
            sphere(r=head_big_radius);
            translate([-head_length, 0, 0])
                sphere(r=head_small_radius);
        }
    }
}

module horn() {
    rotate([0, -head_angle, 0]) {
        translate([0, 0, head_big_radius - .2*scale])
        cylinder(h = horn_length, r1 = horn_radius, r2 = 0);
    }
}

module neck() {
    hull() {
        translate([neck_top_x, 0, 0]) rotate([0, 180, 0]) {
            cylinder(h = head_big_radius - .2*scale, r1 = neck_radius, r2 = neck_radius);
        }
        translate([body_x, 0, -body_z])
            difference() {
                sphere(r = body_radius);
                translate([body_radius*neck_ratio, -body_radius, -body_radius])
                    cube([body_radius, 2*body_radius, 2*body_radius]);
            }
        }
}

module mane() {
}

module body() {
    translate([body_x, 0, -body_z])
        hull() {
            sphere(r = body_radius);
            translate([body_length, 0, 0])
                sphere(r = body_back_radius);
        }
}

module leg(lengthwards=0, sideways=0, theta=20) {
    translate([body_x + lengthwards, sideways, -body_z])
        rotate([180 + theta, 0, 0]) {
        cylinder(h = leg_length, r1 = leg_radius, r2 = leg_radius);
        }
}

module cute_leg(lengthwards=0, sideways=0, downwards=0, theta=20, rise_angle=70) {
    translate([body_x + lengthwards, sideways, -body_z - downwards])
        rotate([180 + theta, rise_angle, 0]) {
            cylinder(h = leg_length*cute_leg_first_ratio, r1 = leg_radius, r2 = leg_radius);
            translate([0, 0, leg_length*cute_leg_first_ratio])
                union() {
                    sphere(r = leg_radius);
                    rotate([0, 90, 0]) {
                        cylinder(h = leg_length*cute_leg_second_ratio, r1 = leg_radius, r2 = leg_radius);
                    }
                        translate([leg_length*cute_leg_second_ratio, 0, 0])
                            union() {
                                sphere(r = leg_radius);
                                rotate([0, 90 + rise_angle, 0]) {
                                cylinder(h = leg_length*cute_leg_third_ratio, r1 = leg_radius, r2 = leg_radius);
                                }
                            }
                }
    }
}

module base() {
    translate([body_x + 0.2*body_length, 0, -leg_length - body_z])
        minkowski() {
            cube([base_length, base_width - 2*base_corner_radius, base_thickness/3], center = true);
            cylinder(h = base_thickness / 3, r = base_corner_radius);
        }
}

difference() { // difference() -> no base, or union() -> solid base
    union() {
        head();
        horn();
        neck();
        body();
        leg(theta=5, sideways=3);
        cute_leg(theta=-5, sideways=-3, downwards=3);
        leg(lengthwards = body_length, sideways=2, theta=15);
        leg(lengthwards = body_length, sideways=-2, theta=-15);
    }
 #   base();
}

// Chilicorn
$fn=45;

head_big_radius = 10;
head_small_radius = 4.5;
head_spacing = 18;
head_angle = 50;

horn_length = 20;
horn_radius = 2.8;

neck_radius = 2;
neck_ratio = .2; // Flattens the interface to the top body
neck_top_x = 3;

body_x = 15;
body_z = 28;
body_radius = 15;
body_back_radius = 13;
body_length = 33;

leg_length = 28 + body_radius;
leg_radius = 4;

cute_leg_first_ratio = 0.65;
cute_leg_second_ratio = 0.25;
cute_leg_third_ratio = 0.11;

module head() {
    rotate([0, -head_angle, 0]) {
        hull () {
            sphere(r=head_big_radius);
            translate([-head_spacing, 0, 0])
                sphere(r=head_small_radius);
        }
    }
}

module horn() {
    rotate([0, -head_angle, 0]) {
        translate([0, 0, head_big_radius - .2])
        cylinder(h = horn_length, r1 = horn_radius, r2 = 0);
    }
}

module neck() {
    hull() {
        translate([neck_top_x, 0, 0]) rotate([0, 180, 0]) {
            cylinder(h = head_big_radius - .2, r1 = neck_radius, r2 = neck_radius);
        }
        translate([body_x, 0, -body_z])
            difference() {
                sphere(r = body_radius);
                translate([body_radius*neck_ratio, -body_radius, -body_radius])
                    cube([body_radius, 2*body_radius, 2*body_radius]);
            }
        }
}

module mane() {
    rotate([0, -neck_angle + 180, 0]) {
        cylinder(h = neck_length + head_big_radius - .2, r1 = neck_radius, r2 = neck_radius);
    }
}

module body() {
    translate([body_x, 0, -body_z])
        hull() {
            sphere(r = body_radius);
            translate([body_length, 0, 0])
                sphere(r = body_back_radius);
        }
}

module leg(lengthwards=0, sideways=0, theta=20) {
    translate([body_x + lengthwards, sideways, -body_z])
        rotate([180 + theta, 0, 0]) {
        cylinder(h = leg_length, r1 = leg_radius, r2 = leg_radius);
        }
}

module cute_leg(lengthwards=0, sideways=0, downwards=0, theta=20, rise_angle=70) {
    translate([body_x + lengthwards, sideways, -body_z - downwards])
        rotate([180 + theta, rise_angle, 0]) {
            cylinder(h = leg_length*cute_leg_first_ratio, r1 = leg_radius, r2 = leg_radius);
            translate([0, 0, leg_length*cute_leg_first_ratio])
                union() {
                    sphere(r = leg_radius);
                    rotate([0, 90, 0]) {
                        cylinder(h = leg_length*cute_leg_second_ratio, r1 = leg_radius, r2 = leg_radius);
                    }
                        translate([leg_length*cute_leg_second_ratio, 0, 0])
                            union() {
                                sphere(r = leg_radius);
                                rotate([0, 90 + rise_angle, 0]) {
                                cylinder(h = leg_length*cute_leg_third_ratio, r1 = leg_radius, r2 = leg_radius);
                                }
                            }
                }
    }
}

head();
horn();
neck();
body();
leg(theta=5, sideways=3);
cute_leg(theta=-5, sideways=-3, downwards=3);
leg(lengthwards = body_length, sideways=2, theta=15);
leg(lengthwards = body_length, sideways=-2, theta=-15);


Better tail

Better tail

// Unicorn by Paul Houghton © 2015, CC BY-NC-AS license, https://creativecommons.org/licenses/
$fn=8;

scale = 1;

head_big_radius = 10*scale;
head_small_radius = 4.5*scale;
head_length = 18*scale;
head_angle = 50;

horn_length = 20*scale;
horn_radius = 2.8*scale;

mane_thickness = 2*horn_radius;
mane_radius = head_big_radius;
mane_height = head_big_radius * 0.7;
mane_x = head_big_radius * 0.28;
mane_length_x = 10*scale;
mane_length_z = 20*scale;

hair_thickness = mane_thickness / 8;
hair_spacing = mane_thickness / 2;

neck_radius = 3*scale;
neck_ratio = .2; // Flattens the interface to the top body
neck_top_x = 3*scale;

body_x = 15*scale;
body_z = 28*scale;
body_radius = 14*scale;
body_back_radius = 12*scale;
body_length = 33*scale;

leg_length = (33*scale + body_radius);
leg_radius = 4*scale;

cute_leg_first_ratio = 0.5;
cute_leg_second_ratio = 0.25;
cute_leg_third_ratio = 0.11;

tail_thickness = mane_thickness;
tail_radius = 10 * hair_thickness;
tail_x = 2*body_x + body_length - tail_radius;
tail_height = -body_z + 1.7*tail_radius;
tail_tip_length = 30;

base_thickness = 10*scale;
base_width = 40*scale;
base_corner_radius = 5*scale;
base_length = 100*scale;

module head() {
    rotate([0, -head_angle, 0]) {
        hull () {
            sphere(r=head_big_radius);
            translate([-head_length, 0, 0])
                sphere(r=head_small_radius);
        }
    }
}

module horn() {
    rotate([0, -head_angle, 0]) {
        translate([0, 0, head_big_radius - .2*scale])
        cylinder(h = horn_length, r1 = horn_radius, r2 = 0);
    }
}

module neck() {
    hull() {
        translate([neck_top_x, 0, 0]) rotate([0, 180, 0]) {
            cylinder(h = head_big_radius - .2*scale, r1 = neck_radius, r2 = neck_radius);
        }
        translate([body_x, 0, -body_z])
            difference() {
                sphere(r = body_radius);
                translate([body_radius*neck_ratio, -body_radius, -body_radius])
                    cube([body_radius, 2*body_radius, 2*body_radius]);
            }
        }
}

module hair_line(x = 0, z = 0, hair_radius = mane_radius, delta_x = body_x, delta_z = body_z) {
    translate([x, 0, z])
            difference() {
                hull() {
                    cylinder(h = mane_thickness, r = hair_radius);
                    translate([delta_x, -delta_z, 0])
                        cylinder(h = mane_thickness, r = hair_radius);
                }
                hull() {
                    cylinder(h = mane_thickness, r = hair_radius - hair_spacing);
                    translate([delta_x, -delta_z, 0])
                        cylinder(h = mane_thickness, r = hair_radius - hair_spacing);
                }
            }
}

module mane() {
    translate([mane_x, mane_thickness/2, mane_height])
        rotate([90, 0, 0]) {
                hull() {
                    translate([0, 0, hair_thickness])
                    cylinder(h = mane_thickness - 2*hair_thickness, r = mane_radius);
                    translate([body_x, -body_z, 0])
                       cylinder(h = mane_thickness - 2*hair_thickness, r = mane_radius);
                }
              hair_line();
              hair_line(hair_radius = mane_radius - 2*hair_spacing);
        }
}

module body() {
    translate([body_x, 0, -body_z])
        hull() {
            sphere(r = body_radius);
            translate([body_length, 0, 0])
                sphere(r = body_back_radius);
        }
}

module leg(lengthwards=0, sideways=0, theta=20) {
    translate([body_x + lengthwards, sideways, -body_z])
        rotate([180 + theta, 0, 0]) {
        cylinder(h = leg_length, r1 = leg_radius, r2 = leg_radius);
        }
}

module cute_leg(lengthwards=0, sideways=0, downwards=0, theta=20, rise_angle=70) {
    translate([body_x + lengthwards, sideways, -body_z - downwards])
        rotate([180 + theta, rise_angle, 0]) {
            cylinder(h = leg_length*cute_leg_first_ratio, r1 = leg_radius, r2 = leg_radius);
            translate([0, 0, leg_length*cute_leg_first_ratio])
                union() {
                    sphere($fn = 16, r = leg_radius);
                    rotate([0, 90, 0]) {
                        cylinder(h = leg_length*cute_leg_second_ratio, r1 = leg_radius, r2 = leg_radius);
                    }
                    translate([leg_length*cute_leg_second_ratio, 0, 0])
                        union() {
                            sphere($fn = 16, r = leg_radius);
                            rotate([0, 90 + rise_angle, 0]) {
                                cylinder(h = leg_length*cute_leg_third_ratio, r1 = leg_radius, r2 = leg_radius);
                            }
                        }
                }
    }
}

module tailhair_line(x = 0, z = 0, delta_x = body_x, delta_z = 1.2*body_z) {
    translate([x, 0, z - hair_thickness])
            difference() {
                hull() {
                    cylinder(h = tail_thickness, r = tail_radius);
                    translate([delta_x, -delta_z, 0])
                        cube([tail_tip_length, tail_tip_length - hair_thickness, tail_thickness]);
                }
                hull() {
                    cylinder(h = tail_thickness, r = tail_radius - hair_spacing);
                    translate([delta_x + hair_spacing, -delta_z + hair_spacing, 0])
                        cube([tail_tip_length, tail_tip_length - hair_thickness, tail_thickness]);
                }
            }
}

module t_hair() {
    translate([0, 0, -2*hair_thickness])
        difference() {
            hull() {
                cylinder(h = tail_thickness, r = tail_radius);
                translate([body_x, -1.2*body_z, 0]) rotate([0, 0, 11]) {
                    cube([tail_tip_length, tail_tip_length, tail_thickness]);
                }
            }
            hull() {
                cylinder(h = tail_thickness, r = tail_radius - hair_spacing);
                translate([body_x + hair_spacing, -1.2*body_z, 0]) rotate([0, 0, 11]) {
                    cube([tail_tip_length - hair_spacing, tail_tip_length - hair_spacing, tail_thickness]);
                }
            }
        }
}

module tail() {
    translate([tail_x, tail_thickness/2 - hair_thickness, tail_height])
        rotate([90, 0, 0]) {
            intersection() {
                union() {
                    hull() {
                        cylinder(h = tail_thickness - 2*hair_thickness, r = tail_radius);
                        translate([body_x, -1.2*body_z, 0])
                            rotate([0, 0, 11]) {
                               cube([tail_tip_length, tail_tip_length, tail_thickness - 2*hair_thickness]);
                            }
                    }
                    t_hair();
                }
                translate([0, 0, -hair_thickness])
                    cylinder($fn = 16, h = tail_thickness, r = tail_tip_length*1.25);
            }
        }
}

module base() {
    translate([body_x + 0.6*body_length, 0, -leg_length - body_z])
        minkowski() {
            cylinder(h = base_thickness / 3, r = base_corner_radius);
            cube([base_length, base_width - 2*base_corner_radius, base_thickness/3], center = true);
        }
}

difference() { // difference() -> no base, or union() -> solid base
    union() {
        head();
        horn();
        neck();
        mane();
        body();
        leg(theta=5, sideways=3*scale);
        cute_leg(theta=-5, sideways=-3*scale, downwards=3*scale);
        leg(lengthwards = body_length, sideways=2*scale, theta=15);
        leg(lengthwards = body_length, sideways=-2*scale, theta=-15);
        tail();
    }
    base();
}

// Unicorn by Paul Houghton © 2015, CC BY-NC-AS license, https://creativecommons.org/licenses/
$fn=12;

scale = 1;

head_big_radius = 10*scale;
head_small_radius = 4.5*scale;
head_length = 18*scale;
head_angle = 50;

horn_length = 20*scale;
horn_radius = 2.8*scale;

mane_thickness = 2*horn_radius;
mane_radius = head_big_radius;
mane_height = head_big_radius * 0.7;
mane_x = head_big_radius * 0.28;
mane_length_x = 10*scale;
mane_length_z = 20*scale;

hair_thickness = mane_thickness / 8;
hair_spacing = mane_thickness / 2;

neck_radius = 3*scale;
neck_ratio = .2; // Flattens the interface to the top body
neck_top_x = 3*scale;

body_x = 15*scale;
body_z = 28*scale;
body_radius = 14*scale;
body_back_radius = 12*scale;
body_length = 33*scale;

leg_length = (33*scale + body_radius);
leg_radius = 4*scale;

cute_leg_first_ratio = 0.5;
cute_leg_second_ratio = 0.25;
cute_leg_third_ratio = 0.11;

tail_thickness = mane_thickness;
tail_radius = 1.5 * body_back_radius / 3;
tail_x = 2*body_x + body_length - tail_radius;
tail_height = -body_z + 1.7*tail_radius;
tail_tip_length = 30;

base_thickness = 10*scale;
base_width = 40*scale;
base_corner_radius = 5*scale;
base_length = 100*scale;

module head() {
    rotate([0, -head_angle, 0]) {
        hull () {
            sphere(r=head_big_radius);
            translate([-head_length, 0, 0])
                sphere(r=head_small_radius);
        }
    }
}

module horn() {
    rotate([0, -head_angle, 0]) {
        translate([0, 0, head_big_radius - .2*scale])
        cylinder(h = horn_length, r1 = horn_radius, r2 = 0);
    }
}

module neck() {
    hull() {
        translate([neck_top_x, 0, 0]) rotate([0, 180, 0]) {
            cylinder(h = head_big_radius - .2*scale, r1 = neck_radius, r2 = neck_radius);
        }
        translate([body_x, 0, -body_z])
            difference() {
                sphere(r = body_radius);
                translate([body_radius*neck_ratio, -body_radius, -body_radius])
                    cube([body_radius, 2*body_radius, 2*body_radius]);
            }
        }
}

module hair_line(x = 0, z = 0, hair_radius = mane_radius, delta_x = body_x, delta_z = body_z) {
    translate([x, 0, z])
            difference() {
                hull() {
                    cylinder(h = mane_thickness, r = hair_radius);
                    translate([delta_x, -delta_z, 0])
                        cylinder(h = mane_thickness, r = hair_radius);
                }
                hull() {
                    cylinder(h = mane_thickness, r = hair_radius - hair_spacing);
                    translate([delta_x, -delta_z, 0])
                        cylinder(h = mane_thickness, r = hair_radius - hair_spacing);
                }
            }
}

module mane() {
    translate([mane_x, mane_thickness/2, mane_height])
        rotate([90, 0, 0]) {
                hull() {
                    translate([0, 0, hair_thickness])
                    cylinder(h = mane_thickness - 2*hair_thickness, r = mane_radius);
                    translate([body_x, -body_z, 0])
                       cylinder(h = mane_thickness - 2*hair_thickness, r = mane_radius);
                }
              hair_line();
              hair_line(hair_radius = mane_radius - 2*hair_spacing);
        }
}

module body() {
    translate([body_x, 0, -body_z])
        hull() {
            sphere(r = body_radius);
            translate([body_length, 0, 0])
                sphere(r = body_back_radius);
        }
}

module leg(lengthwards=0, sideways=0, theta=20) {
    translate([body_x + lengthwards, sideways, -body_z])
        rotate([180 + theta, 0, 0]) {
        cylinder(h = leg_length, r1 = leg_radius, r2 = leg_radius);
        }
}

module cute_leg(lengthwards=0, sideways=0, downwards=0, theta=20, rise_angle=70) {
    translate([body_x + lengthwards, sideways, -body_z - downwards])
        rotate([180 + theta, rise_angle, 0]) {
            cylinder(h = leg_length*cute_leg_first_ratio, r1 = leg_radius, r2 = leg_radius);
            translate([0, 0, leg_length*cute_leg_first_ratio])
                union() {
                    sphere(r = leg_radius);
                    rotate([0, 90, 0]) {
                        cylinder(h = leg_length*cute_leg_second_ratio, r1 = leg_radius, r2 = leg_radius);
                    }
                    translate([leg_length*cute_leg_second_ratio, 0, 0])
                        union() {
                            sphere(r = leg_radius);
                            rotate([0, 90 + rise_angle, 0]) {
                                cylinder(h = leg_length*cute_leg_third_ratio, r1 = leg_radius, r2 = leg_radius);
                            }
                        }
                }
    }
}

module tailhair_line(x = 0, z = 0, delta_x = body_x, delta_z = 1.2*body_z) {
    translate([x, 0, z - hair_thickness])
            difference() {
                hull() {
                    cylinder(h = tail_thickness, r = tail_radius);
                    translate([delta_x, -delta_z, 0])
                        cube([tail_tip_length, tail_tip_length - hair_thickness, tail_thickness]);
                }
                hull() {
                    cylinder(h = tail_thickness, r = tail_radius - hair_spacing);
                    translate([delta_x + hair_spacing, -delta_z + hair_spacing, 0])
 #                       cube([tail_tip_length, tail_tip_length - hair_thickness, tail_thickness]);
                }
            }
}

module tail() {
    translate([tail_x, tail_thickness/2 - hair_thickness, tail_height])
        rotate([90, 0, 0]) {
            intersection() {
                union() {
                    hull() {
                        cylinder(h = tail_thickness - 2*hair_thickness, r = tail_radius);
                        translate([body_x, -1.2*body_z, 0])
                            cube([tail_tip_length, tail_tip_length, tail_thickness - 2*hair_thickness]);
                    }
color("blue")                  tailhair_line();
                }
                cylinder(h = tail_thickness, r = tail_tip_length*1.25);
            }
        }
}

module base() {
    translate([body_x + 0.6*body_length, 0, -leg_length - body_z])
        minkowski() {
            cylinder(h = base_thickness / 3, r = base_corner_radius);
            cube([base_length, base_width - 2*base_corner_radius, base_thickness/3], center = true);
        }
}

difference() { // difference() -> no base, or union() -> solid base
    union() {
        head();
        horn();
        neck();
        mane();
        body();
        leg(theta=5, sideways=3*scale);
        cute_leg(theta=-5, sideways=-3*scale, downwards=3*scale);
        leg(lengthwards = body_length, sideways=2*scale, theta=15);
        leg(lengthwards = body_length, sideways=-2*scale, theta=-15);
        tail();
    }
    base();
}


fixed height of internal element for keeping oring

use <m3d/fn.scad>

module oring(d_in, d_r)
{
  rotate_extrude(angle=360, convexity=20, $fn=fn(120))
    translate([d_in/2+d_r/2, 0, 0])
      circle(d=d_r, $fn=fn(40));
}

module oring_slot(d_in, d_r, d_ext, d_r_ext)
{
  rotate_extrude(angle=360, convexity=20, $fn=fn(120))
    hull()
    {
      translate([d_in/2+d_r/2, 0, 0])
        circle(d=d_r, $fn=fn(40));
      translate([d_ext/2+d_r_ext/2, 0, 0])
        circle(d=d_r_ext, $fn=fn(40));
    }
}

module nozzle()
{
  module body()
  {
    h1 = 5;
    cylinder(d1=32, d2=21, h=h1, $fn=fn(200));
    translate([0,0,h1])
    {
      h2 = 18;
      difference()
      {
        cylinder(d=21, h=h2, $fn=fn(200));
        translate([0, 0, h2/2])
        {
          d_in = 17-0.5;
          d_r = 2.5;
          oring_slot(d_in=d_in, d_r=d_r, d_ext=d_in+1.5, d_r_ext=d_r+0.75);
          %oring(d_in=d_in, d_r=d_r);
        }
      }
    }
  }

  difference()
  {
    body();
    translate([0,0,-1])
      cylinder(d=9, h=60, $fn=fn(50));
  }
}

nozzle();

use <m3d/fn.scad>

module oring(d_in, d_r)
{
  rotate_extrude(angle=360, convexity=20, $fn=fn(120))
    translate([d_in/2+d_r/2, 0, 0])
      circle(d=d_r, $fn=fn(40));
}

module oring_slot(d_in, d_r, d_ext, d_r_ext)
{
  rotate_extrude(angle=360, convexity=20, $fn=fn(120))
    hull()
    {
      translate([d_in/2+d_r/2, 0, 0])
        circle(d=d_r, $fn=fn(40));
      translate([d_ext/2+d_r_ext/2, 0, 0])
        circle(d=d_r_ext, $fn=fn(40));
    }
}

module nozzle()
{
  module body()
  {
    h = 5;
    cylinder(d1=32, d2=21, h=h, $fn=fn(200));
    translate([0,0,h])
    {
      difference()
      {
        cylinder(d=16+5, h=10, $fn=fn(200));
        translate([0, 0, 6])
        {
          d_in = 17-0.5;
          d_r = 2.5;
          oring_slot(d_in=d_in, d_r=d_r, d_ext=d_in+1.5, d_r_ext=d_r+0.75);
          %oring(d_in=d_in, d_r=d_r);
        }
      }
    }
  }

  difference()
  {
    body();
    translate([0,0,-1])
      cylinder(d=9, h=60, $fn=fn(50));
  }
}

nozzle();


Fix serial header holes not being drawn

Fix serial header holes not being drawn

/*
    Vitamin: ArduinoPro
    Model of an Arduino Pro Mini/Micro

    Derived from: https://github.com/sparkfun/Pro_Micro/
                     and: https://github.com/sparkfun/Arduino_Pro_Mini_328/

    Authors:
        Jamie Osborne (@jmeosbn)

    Local Frame:
        Point of origin is the centre of the bottom left pin (9)

    Parameters:
        type: can be "mini", or "micro";
                    otherwise returns a blank board with header pin holes

    Returns:
        Model of an Arduino Pro Mini/Micro with header holes
*/

// ArduinoPro Model Variants
ArduinoPro_Mini             = 1;            // default
ArduinoPro_Micro            = 2;

// ArduinoPro Without Programming Port
ArduinoPro_No_Port          = 0;

// Show Header Pins
ArduinoPro_Pins_Normal      = 1;
ArduinoPro_Pins_Opposite    = 2;

// ArduinoPro Without Header Pins
ArduinoPro_No_Pins          = 0;            // default

// ArduinoPro PCB Variables
ArduinoPro_PCB_Pitch    = 2.54;                         // spacing of the holes
ArduinoPro_PCB_Inset    = ArduinoPro_PCB_Pitch /2;      // inset from board edge
ArduinoPro_PCB_Type     = 0.047 * 25.4; // .047 .063    // standard PCB thickness
ArduinoPro_PCB_Layers   = 0.035 * 2;                    // total copper layer thickness
ArduinoPro_PCB_Height   = ArduinoPro_PCB_Type +
                          ArduinoPro_PCB_Layers;        // height of the PCB (along z)
ArduinoPro_PCB_Length   = 1.3 * 25.4;                   // length of the PCB (along y)
ArduinoPro_PCB_Width    = 0.7 * 25.4;                   //  width of the PCB (along x)
ArduinoPro_PCB_Colour   = [26/255, 90/255, 160/255];    // colour of solder mask

// Show board clearance area for components
ArduinoPro_PCB_Clearance      = 3;
ArduinoPro_PCB_Clearance_Show = true;

module ArduinoPro_MicroUSB() {
    include <MicroUSB.scad>
    // Subtracting `ArduinoPro_PCB_Inset` compansates for board origin
    //-: Not sure if board origin would be better set after creation
    move_x  = ArduinoPro_PCB_Width / 2 - ArduinoPro_PCB_Inset;
    move_y  = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset;
    move_z  = ArduinoPro_PCB_Height;

    // Add USB header and move to top of board (along x)
    translate([move_x, move_y, move_z])
        MicroUSB_Receptacle();
}

module ArduinoPro_PCB() {
    // Bare PCB, origin through location for bottom left hole
    translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0])
        square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
}

module ArduinoPro_Header_Hole() {
    // Standard PCB hole
    holediameter        = 1.25;         // diameter of PCB hole
    circle(d = holediameter);
}

module ArduinoPro_Header_Pin() {
    // Standard PCB header pin
    pcbholepitch        = 2.54;         // spacing of PCB holes
    holediameter        = 1.25;         // diameter of PCB hole
    pinheight           =   11;         // length of PCB pins
    pinoffset           =    3;         // offset of PCB pins
    pinwidth            = 0.63;         // width/gauge of PCB pins
    spacerwidth         = 2.25;         // height of breakaway pin frame
    spacerheight        = 2.54;         // height of breakaway pin frame

    // Header Pins
    color("white")
    translate([0, 0, -pinoffset])
    linear_extrude(pinheight)
        square(pinwidth, center = true);

    // Pin Spacers
    color("black")
    linear_extrude(spacerheight)
        square(spacerwidth, center = true);

    // Break-Away Material
    color("black")
    translate([0, pcbholepitch/2, 0])
    linear_extrude(spacerheight)
        square([spacerwidth * 0.85, pcbholepitch - spacerwidth], center = true);
}

module ArduinoPro_Headers_Layout() {
    // distance between the two header rows
    // FIXME: improve this to be a multiple of 0.1 inch
    rowpitch  = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;
    // length for holes, leaving room for end header and insets
    rowlength = ArduinoPro_PCB_Length - ArduinoPro_PCB_Pitch - ArduinoPro_PCB_Inset*2;

    // Add headers to either side (along y)
    for (x = [0, rowpitch], y = [0 : ArduinoPro_PCB_Pitch : rowlength]) {
        translate([x, y, 0]) children();
    }
}

module ArduinoPro_Serial_Header_Layout() {
    // y position for header
    header_y = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset*2;
    // width for holes, leaving room for insets
    rowwidth = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;

    // Add serial header along top of board (along x)
    for (x = [ArduinoPro_PCB_Inset : ArduinoPro_PCB_Pitch : rowwidth]) {
        translate([x, header_y, 0]) children();
    }
}

module ArduinoPro(type = ArduinoPro_Mini, headerpins = 0, serialpins = 0) {
    color(ArduinoPro_PCB_Colour)
    linear_extrude(height=ArduinoPro_PCB_Height)
    difference() {
        // Base PCB
        ArduinoPro_PCB();

        // Common Headers for Pro Mini/Micro
        ArduinoPro_Headers_Layout()
            ArduinoPro_Header_Hole();

        // Pro Mini Serial Header
        if (type == ArduinoPro_Mini) {
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Hole();
        }
    }

    // Pro Mini Serial Header Pins
    serialontop = (serialpins != ArduinoPro_Pins_Opposite);
    if (serialpins > 0 && type == ArduinoPro_Mini) {
        // Offset for board height if located on top
        translate([0, 0, serialontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, serialontop ? 0 : 1 ])
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Pin();
    }

    // Common Header Pins
    headerontop = (headerpins == ArduinoPro_Pins_Opposite);
    if (headerpins > 0) {
        // Offset for board height located on top
        translate([0, 0, headerontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, headerontop ? 0 : 1 ])
            ArduinoPro_Headers_Layout()
                ArduinoPro_Header_Pin();
    }

    // Pro Micro USB port
    if (type == ArduinoPro_Micro) ArduinoPro_MicroUSB();

    // Indicate area for minimum board clearance
    if (ArduinoPro_PCB_Clearance_Show && !headerpins) {
        color(ArduinoPro_PCB_Colour, 0.1)
        translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0.5])
        linear_extrude(height=ArduinoPro_PCB_Clearance)
            square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
    }
}

// Example Usage
// ArduinoPro(ArduinoPro_Mini, ArduinoPro_Serial_Pins);
// ArduinoPro(ArduinoPro_Micro, ArduinoPro_Header_Pins);

/*
    Vitamin: ArduinoPro
    Model of an Arduino Pro Mini/Micro

    Derived from: https://github.com/sparkfun/Pro_Micro/
                     and: https://github.com/sparkfun/Arduino_Pro_Mini_328/

    Authors:
        Jamie Osborne (@jmeosbn)

    Local Frame:
        Point of origin is the centre of the bottom left pin (9)

    Parameters:
        type: can be "mini", or "micro";
                    otherwise returns a blank board with header pin holes

    Returns:
        Model of an Arduino Pro Mini/Micro with header holes
*/

// ArduinoPro Model Variants
ArduinoPro_Mini             = 1;            // default
ArduinoPro_Micro            = 2;

// ArduinoPro Without Programming Port
ArduinoPro_No_Port          = 0;

// Show Header Pins
ArduinoPro_Pins_Normal      = 1;
ArduinoPro_Pins_Opposite    = 2;

// ArduinoPro Without Header Pins
ArduinoPro_No_Pins          = 0;            // default

// ArduinoPro PCB Variables
ArduinoPro_PCB_Pitch    = 2.54;                         // spacing of the holes
ArduinoPro_PCB_Inset    = ArduinoPro_PCB_Pitch /2;      // inset from board edge
ArduinoPro_PCB_Type     = 0.047 * 25.4; // .047 .063    // standard PCB thickness
ArduinoPro_PCB_Layers   = 0.035 * 2;                    // total copper layer thickness
ArduinoPro_PCB_Height   = ArduinoPro_PCB_Type +
                          ArduinoPro_PCB_Layers;        // height of the PCB (along z)
ArduinoPro_PCB_Length   = 1.3 * 25.4;                   // length of the PCB (along y)
ArduinoPro_PCB_Width    = 0.7 * 25.4;                   //  width of the PCB (along x)
ArduinoPro_PCB_Colour   = [26/255, 90/255, 160/255];    // colour of solder mask

// Show board clearance area for components
ArduinoPro_PCB_Clearance      = 3;
ArduinoPro_PCB_Clearance_Show = true;

module ArduinoPro_MicroUSB() {
    include <MicroUSB.scad>
    // Subtracting `ArduinoPro_PCB_Inset` compansates for board origin
    //-: Not sure if board origin would be better set after creation
    move_x  = ArduinoPro_PCB_Width / 2 - ArduinoPro_PCB_Inset;
    move_y  = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset;
    move_z  = ArduinoPro_PCB_Height;

    // Add USB header and move to top of board (along x)
    translate([move_x, move_y, move_z])
        MicroUSB_Receptacle();
}

module ArduinoPro_PCB() {
    // Bare PCB, origin through location for bottom left hole
    translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0])
        square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
}

module ArduinoPro_Header_Hole() {
    // Standard PCB hole
    holediameter        = 1.25;         // diameter of PCB hole
    circle(d = holediameter);
}

module ArduinoPro_Header_Pin() {
    // Standard PCB header pin
    pcbholepitch        = 2.54;         // spacing of PCB holes
    holediameter        = 1.25;         // diameter of PCB hole
    pinheight           =   11;         // length of PCB pins
    pinoffset           =    3;         // offset of PCB pins
    pinwidth            = 0.63;         // width/gauge of PCB pins
    spacerwidth         = 2.25;         // height of breakaway pin frame
    spacerheight        = 2.54;         // height of breakaway pin frame

    // Header Pins
    color("white")
    translate([0, 0, -pinoffset])
    linear_extrude(pinheight)
        square(pinwidth, center = true);

    // Pin Spacers
    color("black")
    linear_extrude(spacerheight)
        square(spacerwidth, center = true);

    // Break-Away Material
    color("black")
    translate([0, pcbholepitch/2, 0])
    linear_extrude(spacerheight)
        square([spacerwidth * 0.85, pcbholepitch - spacerwidth], center = true);
}

module ArduinoPro_Headers_Layout() {
    // distance between the two header rows
    // FIXME: improve this to be a multiple of 0.1 inch
    rowpitch  = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;
    // length for holes, leaving room for end header and insets
    rowlength = ArduinoPro_PCB_Length - ArduinoPro_PCB_Pitch - ArduinoPro_PCB_Inset*2;

    // Add headers to either side (along y)
    for (x = [0, rowpitch], y = [0 : ArduinoPro_PCB_Pitch : rowlength]) {
        translate([x, y, 0]) children();
    }
}

module ArduinoPro_Serial_Header_Layout() {
    // y position for header
    header_y = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset*2;
    // width for holes, leaving room for insets
    rowwidth = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;

    // Add serial header along top of board (along x)
    for (x = [ArduinoPro_PCB_Inset : ArduinoPro_PCB_Pitch : rowwidth]) {
        translate([x, header_y, 0]) children();
    }
}

module ArduinoPro(type = ArduinoPro_Mini, headerpins = 0, serialpins = 0) {
    color(ArduinoPro_PCB_Colour)
    linear_extrude(height=ArduinoPro_PCB_Height)
    difference() {
        // Base PCB
        ArduinoPro_PCB();

        // Common Headers for Pro Mini/Micro
        ArduinoPro_Headers_Layout()
            ArduinoPro_Header_Hole();

        // Pro Mini Serial Header
        if (type == ArduinoPro_Mini) {
            ArduinoPro_Serial_Header_Layout();
                ArduinoPro_Header_Hole();
        }
    }

    // Pro Mini Serial Header Pins
    serialontop = (serialpins != ArduinoPro_Pins_Opposite);
    if (serialpins > 0 && type == ArduinoPro_Mini) {
        // Offset for board height if located on top
        translate([0, 0, serialontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, serialontop ? 0 : 1 ])
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Pin();
    }

    // Common Header Pins
    headerontop = (headerpins == ArduinoPro_Pins_Opposite);
    if (headerpins > 0) {
        // Offset for board height located on top
        translate([0, 0, headerontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, headerontop ? 0 : 1 ])
            ArduinoPro_Headers_Layout()
                ArduinoPro_Header_Pin();
    }

    // Pro Micro USB port
    if (type == ArduinoPro_Micro) ArduinoPro_MicroUSB();

    // Indicate area for minimum board clearance
    if (ArduinoPro_PCB_Clearance_Show && !headerpins) {
        color(ArduinoPro_PCB_Colour, 0.1)
        translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0.5])
        linear_extrude(height=ArduinoPro_PCB_Clearance)
            square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
    }
}

// Example Usage
// ArduinoPro(ArduinoPro_Mini, ArduinoPro_Serial_Pins);
// ArduinoPro(ArduinoPro_Micro, ArduinoPro_Header_Pins);


main cap part (no mountings yet)

main cap part (no mountings yet)

wall=2;
spacing=0.5;
r_int=30.5/2;
r_round=wall;
h=25;
$fn=1/3*360;

module ring_(r_ring, r_round)
{
//  $fn=200;
  rotate_extrude()
    translate([r_ring-r_round, 0, 0])
      circle(r=r_round);
}

module rounded_cylinder_(r_cyl, r_round, h)
{
  translate(r_round*[0,0,1])
  {
    for(dz=[0,h-2*r_round])
      translate([0,0,dz])
        hull()
          ring_(r_cyl, r_round);
    cylinder(r=r_cyl, h=h-2*r_round);
  }
}

module empty_cylinder_()
{

  difference()
  {
    rounded_cylinder_(r_int + spacing + wall, r_round, h);
    translate(wall*[0,0,1])
      rounded_cylinder_(r_int + spacing, r_round, h);
  }
}

empty_cylinder_();

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


removed scale echo from openscad conversion

measurement = 55;

SCALE = (measurement + 5)/55;

echo(SCALE=SCALE);


Move SMT components into own module

Move SMT components into own module

- Refine some component measurements

/*
    Vitamin: ArduinoPro
    Model of an Arduino Pro Mini/Micro

    Derived from: https://github.com/sparkfun/Pro_Micro/
             and: https://github.com/sparkfun/Arduino_Pro_Mini_328/

    Authors:
        Jamie Osborne (@jmeosbn)

    Local Frame:
        Point of origin is the centre of the bottom left pin (9)

    Parameters:
        type: can be "mini", or "micro";
              otherwise returns a blank board with header pin holes

    Returns:
        Model of an Arduino Pro Mini/Micro with header holes
*/

// ArduinoPro Model Variants
ArduinoPro_Mini             = 1;            // default
ArduinoPro_Micro            = 2;

// ArduinoPro Without Programming Port
ArduinoPro_No_Port          = 0;

// Show Header Pins
ArduinoPro_Pins_Normal      = 1;
ArduinoPro_Pins_Opposite    = 2;

// ArduinoPro Without Header Pins
ArduinoPro_No_Pins          = 0;            // default

// ArduinoPro PCB Variables
ArduinoPro_PCB_Pitch    = 2.54;                         // spacing of the holes
ArduinoPro_PCB_Inset    = ArduinoPro_PCB_Pitch /2;      // inset from board edge
ArduinoPro_PCB_Type     = 0.047 * 25.4; // .047 .063    // standard PCB thickness
ArduinoPro_PCB_Layers   = 0.035 * 2;                    // total copper layer thickness
ArduinoPro_PCB_Height   = ArduinoPro_PCB_Type +
                          ArduinoPro_PCB_Layers;        // height of the PCB (along z)
ArduinoPro_PCB_Length   = 1.3 * 25.4;                   // length of the PCB (along y)
ArduinoPro_PCB_Width    = 0.7 * 25.4;                   //  width of the PCB (along x)
ArduinoPro_PCB_Colour   = [26/255, 90/255, 160/255];    // colour of solder mask

// Show board clearance area for components
ArduinoPro_PCB_Clearance      = 4 - ArduinoPro_PCB_Height;
ArduinoPro_PCB_Clearance_Show = true;

module ArduinoPro_MicroUSB()
{
    include <MicroUSB.scad>
    // Subtracting `ArduinoPro_PCB_Inset` compansates for board origin
    //-: Not sure if board origin would be better set after creation
    move_x  = ArduinoPro_PCB_Width / 2 - ArduinoPro_PCB_Inset;
    move_y  = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset;
    move_z  = ArduinoPro_PCB_Height;

    // Add USB header and move to top of board (along x)
    translate([move_x, move_y, move_z])
        MicroUSB_Receptacle();
}

module ArduinoPro_PCB()
{
    // Bare PCB, origin through location for bottom left hole
    translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0])
        square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
}

module ArduinoPro_Header_Hole()
{
    // Standard PCB hole
    holediameter        = 1.25;         // diameter of PCB hole
    circle(d = holediameter);
}

module ArduinoPro_Header_Pin(rotation = 0)
{
    // Standard PCB header pin
    pcbholepitch        = 2.54;         // spacing of PCB holes
    holediameter        = 1.25;         // diameter of PCB hole
    pinheight           =   11;         // length of PCB pins
    pinoffset           =    3;         // offset of PCB pins
    pinwidth            = 0.63;         // width/gauge of PCB pins
    spacerwidth         = 2.25;         // height of breakaway pin frame
    spacerheight        = 2.25;         // height of breakaway pin frame

    // Header Pins
    color("white")
    translate([0, 0, -pinoffset])
    linear_extrude(pinheight)
        square(pinwidth, center = true);

    // Pin Spacers
    color("black")
    linear_extrude(spacerheight)
        square(spacerwidth, center = true);

    // Break-Away Material
    color("black")
    // FIXME: material needs to be rotated based on vector argument
    rotate(rotation, 0, 0)
    translate([0, pcbholepitch/2, 0])
    linear_extrude(spacerheight)
        square([spacerwidth * 0.85, pcbholepitch - spacerwidth], center = true);
}

module ArduinoPro_Headers_Layout()
{
    // distance between the two header rows
    // FIXME: improve this to be a multiple of 0.1 inch
    rowpitch  = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;
    // length for holes, leaving room for end header and insets
    rowlength = ArduinoPro_PCB_Length - ArduinoPro_PCB_Pitch - ArduinoPro_PCB_Inset*2;

    // Add headers to either side (along y)
    for (x = [0, rowpitch], y = [0 : ArduinoPro_PCB_Pitch : rowlength]) {
        translate([x, y, 0]) children();
    }
}

module ArduinoPro_Serial_Header_Layout()
{
    // y position for header
    header_y = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset*2;
    // width for holes, leaving room for insets
    rowwidth = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;

    // Add serial header along top of board (along x)
    for (x = [ArduinoPro_PCB_Inset : ArduinoPro_PCB_Pitch : rowwidth]) {
        translate([x, header_y, 0]) children();
    }
}

module ArduinoPro_SMT_Components(type = ArduinoPro_Mini)
{
    // Distance from origin to middle along y
    moveX = ArduinoPro_PCB_Width/2 - ArduinoPro_PCB_Inset;

    // Controller IC
    color(Grey20)
    translate([moveX, 0.5 * 25.4, ArduinoPro_PCB_Height])
    rotate([0,0,45])
    linear_extrude(height=1)
      square(sqrt(pow(0.4 * 25.4, 2)/2), center=true);

    // Reset switch for Pro Mini
    if (type == ArduinoPro_Mini) {
        translate([moveX, 0.15 * 25.4, ArduinoPro_PCB_Height])
        union() {
            color("silver")
            linear_extrude(height=1.7)
                square([6, 3.5], center=true);
            color("darkorange")
            translate([0, 0, 1.7])
            linear_extrude(height=1.0)
                square([3, 2], center=true);
        }
    }

    // Crystal for Pro Micro
    if (type == ArduinoPro_Micro) {
        color("silver")
        translate([moveX, 0.15 * 25.4, ArduinoPro_PCB_Height])
        linear_extrude(height=1)
            square([6, 3.5], center=true);
    }

    // Capacitors etc.
    moveY = (type == ArduinoPro_Mini ? 0.9 : 0.8) * 25.4;
    color("silver")
    translate([moveX/2, moveY, ArduinoPro_PCB_Height])
    linear_extrude(height=2)
    union() {
        square([1.5, 3.5], center=true);
        translate([7.5, 0, 0])
          square([1.5, 3.5], center=true);
    }

    // Other components
    color("silver")
    translate([moveX, moveY, ArduinoPro_PCB_Height])
    linear_extrude(height=1)
    union() {
        square([1, 2.5], center=true);
        translate([0, 3, 0])
            square([2.5, 1.5], center=true);
    }
}

module ArduinoPro(type = ArduinoPro_Mini, headerpins = 0, serialpins = 0)
{
    color(ArduinoPro_PCB_Colour)
    linear_extrude(height=ArduinoPro_PCB_Height)
    difference() {
        // Base PCB
        ArduinoPro_PCB();

        // Common Headers for Pro Mini/Micro
        ArduinoPro_Headers_Layout()
            ArduinoPro_Header_Hole();

        // Pro Mini Serial Header
        if (type == ArduinoPro_Mini) {
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Hole();
        }
    }

    // Pro Mini Serial Header Pins
    serialontop = (serialpins != ArduinoPro_Pins_Opposite);
    if (serialpins > 0 && type == ArduinoPro_Mini) {
        // Offset for board height if located on top
        translate([0, 0, serialontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, serialontop ? 0 : 1 ])
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Pin(rotation = 90);
    }

    // Common Header Pins
    headerontop = (headerpins == ArduinoPro_Pins_Opposite);
    if (headerpins > 0) {
        // Offset for board height located on top
        translate([0, 0, headerontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, headerontop ? 0 : 1 ])
            ArduinoPro_Headers_Layout()
                ArduinoPro_Header_Pin();
    }

    // Pro Micro USB port
    if (type == ArduinoPro_Micro) ArduinoPro_MicroUSB();

    // Surface mount components
    ArduinoPro_SMT_Components(type);

    // Indicate area for minimum board clearance
    if (ArduinoPro_PCB_Clearance_Show && !headerpins) {
        color(ArduinoPro_PCB_Colour, 0.1)
        translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, ArduinoPro_PCB_Height])
        linear_extrude(height=ArduinoPro_PCB_Clearance)
            square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
    }
}

// Example Usage
// ArduinoPro(ArduinoPro_Micro, ArduinoPro_Pins_Normal);
// ArduinoPro(ArduinoPro_Mini,  ArduinoPro_Pins_Normal, ArduinoPro_Pins_Normal);

/*
    Vitamin: ArduinoPro
    Model of an Arduino Pro Mini/Micro

    Derived from: https://github.com/sparkfun/Pro_Micro/
             and: https://github.com/sparkfun/Arduino_Pro_Mini_328/

    Authors:
        Jamie Osborne (@jmeosbn)

    Local Frame:
        Point of origin is the centre of the bottom left pin (9)

    Parameters:
        type: can be "mini", or "micro";
              otherwise returns a blank board with header pin holes

    Returns:
        Model of an Arduino Pro Mini/Micro with header holes
*/

// ArduinoPro Model Variants
ArduinoPro_Mini             = 1;            // default
ArduinoPro_Micro            = 2;

// ArduinoPro Without Programming Port
ArduinoPro_No_Port          = 0;

// Show Header Pins
ArduinoPro_Pins_Normal      = 1;
ArduinoPro_Pins_Opposite    = 2;

// ArduinoPro Without Header Pins
ArduinoPro_No_Pins          = 0;            // default

// ArduinoPro PCB Variables
ArduinoPro_PCB_Pitch    = 2.54;                         // spacing of the holes
ArduinoPro_PCB_Inset    = ArduinoPro_PCB_Pitch /2;      // inset from board edge
ArduinoPro_PCB_Type     = 0.047 * 25.4; // .047 .063    // standard PCB thickness
ArduinoPro_PCB_Layers   = 0.035 * 2;                    // total copper layer thickness
ArduinoPro_PCB_Height   = ArduinoPro_PCB_Type +
                          ArduinoPro_PCB_Layers;        // height of the PCB (along z)
ArduinoPro_PCB_Length   = 1.3 * 25.4;                   // length of the PCB (along y)
ArduinoPro_PCB_Width    = 0.7 * 25.4;                   //  width of the PCB (along x)
ArduinoPro_PCB_Colour   = [26/255, 90/255, 160/255];    // colour of solder mask

// Show board clearance area for components
ArduinoPro_PCB_Clearance      = 3;
ArduinoPro_PCB_Clearance_Show = true;

module ArduinoPro_MicroUSB() {
    include <MicroUSB.scad>
    // Subtracting `ArduinoPro_PCB_Inset` compansates for board origin
    //-: Not sure if board origin would be better set after creation
    move_x  = ArduinoPro_PCB_Width / 2 - ArduinoPro_PCB_Inset;
    move_y  = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset;
    move_z  = ArduinoPro_PCB_Height;

    // Add USB header and move to top of board (along x)
    translate([move_x, move_y, move_z])
        MicroUSB_Receptacle();
}

module ArduinoPro_PCB() {
    // Bare PCB, origin through location for bottom left hole
    translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0])
        square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
}

module ArduinoPro_Header_Hole() {
    // Standard PCB hole
    holediameter        = 1.25;         // diameter of PCB hole
    circle(d = holediameter);
}

module ArduinoPro_Header_Pin(rotation = 0) {
    // Standard PCB header pin
    pcbholepitch        = 2.54;         // spacing of PCB holes
    holediameter        = 1.25;         // diameter of PCB hole
    pinheight           =   11;         // length of PCB pins
    pinoffset           =    3;         // offset of PCB pins
    pinwidth            = 0.63;         // width/gauge of PCB pins
    spacerwidth         = 2.25;         // height of breakaway pin frame
    spacerheight        = 2.54;         // height of breakaway pin frame

    // Header Pins
    color("white")
    translate([0, 0, -pinoffset])
    linear_extrude(pinheight)
        square(pinwidth, center = true);

    // Pin Spacers
    color("black")
    linear_extrude(spacerheight)
        square(spacerwidth, center = true);

    // Break-Away Material
    color("black")
    // FIXME: material needs to be rotated based on vector argument
    rotate(rotation, 0, 0)
    translate([0, pcbholepitch/2, 0])
    linear_extrude(spacerheight)
        square([spacerwidth * 0.85, pcbholepitch - spacerwidth], center = true);
}

module ArduinoPro_Headers_Layout() {
    // distance between the two header rows
    // FIXME: improve this to be a multiple of 0.1 inch
    rowpitch  = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;
    // length for holes, leaving room for end header and insets
    rowlength = ArduinoPro_PCB_Length - ArduinoPro_PCB_Pitch - ArduinoPro_PCB_Inset*2;

    // Add headers to either side (along y)
    for (x = [0, rowpitch], y = [0 : ArduinoPro_PCB_Pitch : rowlength]) {
        translate([x, y, 0]) children();
    }
}

module ArduinoPro_Serial_Header_Layout() {
    // y position for header
    header_y = ArduinoPro_PCB_Length - ArduinoPro_PCB_Inset*2;
    // width for holes, leaving room for insets
    rowwidth = ArduinoPro_PCB_Width - ArduinoPro_PCB_Inset*2;

    // Add serial header along top of board (along x)
    for (x = [ArduinoPro_PCB_Inset : ArduinoPro_PCB_Pitch : rowwidth]) {
        translate([x, header_y, 0]) children();
    }
}

module ArduinoPro(type = ArduinoPro_Mini, headerpins = 0, serialpins = 0) {
    color(ArduinoPro_PCB_Colour)
    linear_extrude(height=ArduinoPro_PCB_Height)
    difference() {
        // Base PCB
        ArduinoPro_PCB();

        // Common Headers for Pro Mini/Micro
        ArduinoPro_Headers_Layout()
            ArduinoPro_Header_Hole();

        // Pro Mini Serial Header
        if (type == ArduinoPro_Mini) {
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Hole();
        }
    }

    // Distance to middle from origin
    moveX = ArduinoPro_PCB_Width/2 - ArduinoPro_PCB_Inset;

    // Controller IC
    color(Grey20)
    translate([moveX, 0.5*25.4, ArduinoPro_PCB_Height])
    rotate([0,0,45])
    linear_extrude(height=1)
      square(2*sqrt(.4*25.4), center=true);

    // Reset switch (or crystal for Pro Micro)
    color("silver")
    translate([moveX, 0.15*25.4, ArduinoPro_PCB_Height])
    linear_extrude(height=1)
        square([5, 3.5], center=true);

    // Capacitors
    moveY = (type == ArduinoPro_Mini ? 0.9 : 0.8) * 25.4;
    color("silver")
    translate([moveX/2, moveY, ArduinoPro_PCB_Height])
    linear_extrude(height=2)
    union() {
        square([1.5, 3.5], center=true);
        translate([7.5, 0, 0])
          square([1.5, 3.5], center=true);
    }

    // Other components
    color("silver")
    translate([moveX, moveY, ArduinoPro_PCB_Height])
    linear_extrude(height=1)
    union() {
        square([1, 2.5], center=true);
        translate([0, 3, 0])
            square([2.5, 1.5], center=true);
    }

    // Pro Mini Serial Header Pins
    serialontop = (serialpins != ArduinoPro_Pins_Opposite);
    if (serialpins > 0 && type == ArduinoPro_Mini) {
        // Offset for board height if located on top
        translate([0, 0, serialontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, serialontop ? 0 : 1 ])
            ArduinoPro_Serial_Header_Layout()
                ArduinoPro_Header_Pin(rotation = 90);
    }

    // Common Header Pins
    headerontop = (headerpins == ArduinoPro_Pins_Opposite);
    if (headerpins > 0) {
        // Offset for board height located on top
        translate([0, 0, headerontop ? ArduinoPro_PCB_Height : 0])
            mirror([0, 0, headerontop ? 0 : 1 ])
            ArduinoPro_Headers_Layout()
                ArduinoPro_Header_Pin();
    }

    // Pro Micro USB port
    if (type == ArduinoPro_Micro) ArduinoPro_MicroUSB();

    // Indicate area for minimum board clearance
    if (ArduinoPro_PCB_Clearance_Show && !headerpins) {
        color(ArduinoPro_PCB_Colour, 0.1)
        translate([-ArduinoPro_PCB_Inset, -ArduinoPro_PCB_Inset, 0.5])
        linear_extrude(height=ArduinoPro_PCB_Clearance)
            square(size = [ArduinoPro_PCB_Width, ArduinoPro_PCB_Length]);
    }
}

// Example Usage
// ArduinoPro(ArduinoPro_Micro, ArduinoPro_Pins_Normal);
// ArduinoPro(ArduinoPro_Mini,  ArduinoPro_Pins_Normal, ArduinoPro_Pins_Normal);


Add some commenting to the switch mount scad file

// This box is the housing for the scoring buttons that get mounted
// under the pingpong table. The buttons I used are these:
// https://www.sparkfun.com/products/11275
// In hindsight, these buttons are rather large. You could use smaller
// buttons and adjust some of these values accordingly.

// The overall radius of the button. The datasheet reports 100mm, but
// mine both measure 98.
button_radius = 49;

// The radius of the hole the button back needs.
hole_radius = 14.5;

// There's a bar on the front of my table that is 40mm high
table_padding = 40;

// I want 30mm around the button's hole
bottom_padding = 30;
extra_padding = 2;

// The thickness of the box walls
wall_thickness = 3;

// Dimensions for the overall box
mount_height = table_padding + extra_padding + button_radius + hole_radius + bottom_padding;
mount_depth = 50;
mount_width = (hole_radius * 2) + (bottom_padding * 2);

$fn=100;
font = "monaco.dxf";

// Comment or uncomment the body or cover, depending on which you need to render

// Body
union() {
    difference() {
        bottom();
        // You don't have to put my name in your box ;)
        name();
    }

    difference() {
        sides();
        cover_screws();
        mount_screws();
    }
}

// Cover
/*
difference() {
    translate([0, 0, mount_depth-wall_thickness])
    cover();
    cover_screws();
    // Remove this line if you don't want the project's name on the cover
    project();
}
*/

// You shouldn't have to configure anything below this, except maybe text
// attributes at the bottom if you're putting your own text in it.

module screw_mount() {
    difference() {
        cube([10, wall_thickness, 10]);

        rotate([90, 0, 0])
        translate([5, 5, -wall_thickness-1])
        cylinder(r=2, h=wall_thickness+2);
    }
}

module bottom() {
    difference() {
    hull() {
        // lower left
        translate([wall_thickness*2, wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // lower right
        translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // upper right
        translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);

        // upper left
        translate([0, mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);
    }

    union() {
        translate([mount_width/2, wall_thickness+7.5, -1])
        cylinder(r=3, h=wall_thickness+2);

        translate([mount_width/2-4.5, wall_thickness+7.5-2.5, wall_thickness-.8])
        cube(size=[9, 5, 1]);
    }
    }
}

module sides() {
    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);

            // upper left
            translate([0, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);
        }

        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);
        }
    }

    intersection() {
        translate([wall_thickness, wall_thickness, 0])
        cube([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), mount_depth]);

        union() {
            translate([wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);
        }
    }
}

module cover() {
    hole_center = mount_height - table_padding - button_radius;

    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);
        }

        translate([mount_width/2, hole_center, -1])
        cylinder(r=hole_radius, h=wall_thickness*2);
    }

    // Fake button
    // translate([mount_width/2, hole_center, 5])
    // cylinder(r=button_radius, h=20);
}

module cover_screws() {
    translate([wall_thickness+3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([wall_thickness+3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);
}

module mount_screws() {
    spacing = 15;

    translate([spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);
}

// Text
module letter(l, h=100, i=0) {
    union() {
        linear_extrude(height=h) import(font, layer=l[i]);
        translate([dxf_dim(file=font, name="advx", layer=l[i]), dxf_dim(file=font, name="advy", layer=l[i]), 0])
        child();
    }
}

module word(wrd, h=100, i=0) {
    if (i < len(wrd)) {
        letter(wrd, h, i) word(wrd, h, i+1);
    } else {
        child();
    }
}

module name() {
    translate([18.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Scott", 1000);

    translate([46.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Barron", 1000);

    translate([34.5, mount_height - 35, wall_thickness-1.5])
    scale(0.002)
    word("2014", 1000);
}

module project() {
    translate([22, mount_height-20, mount_depth-1.5])
    scale(0.002)
     word("Pingduino", 1000);
}

$fn=100;

button_radius = 49;
hole_radius = 14.5;
table_padding = 40;
extra_padding = 2;
bottom_padding = 30;

wall_thickness = 3;

mount_height = table_padding + extra_padding + button_radius + hole_radius + bottom_padding;
mount_depth = 50;
mount_width = (hole_radius * 2) + (bottom_padding * 2);

font = "monaco.dxf";

// Body
union() {
    difference() {
        bottom();
        name();
    }

    difference() {
        sides();
        cover_screws();
        mount_screws();
    }
}

// Cover
// difference() {
//     translate([0, 0, mount_depth-wall_thickness])
//     cover();
//     cover_screws();
//     project();
// }

module screw_mount() {
    difference() {
        cube([10, wall_thickness, 10]);

        rotate([90, 0, 0])
        translate([5, 5, -wall_thickness-1])
        cylinder(r=2, h=wall_thickness+2);
    }
}

module bottom() {
    difference() {
    hull() {
        // lower left
        translate([wall_thickness*2, wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // lower right
        translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
        cylinder(r=wall_thickness*2, h=wall_thickness);

        // upper right
        translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);

        // upper left
        translate([0, mount_height-(wall_thickness*2), 0])
        cube(size=[wall_thickness*2, wall_thickness*2, wall_thickness]);
    }

    union() {
        translate([mount_width/2, wall_thickness+7.5, -1])
        cylinder(r=3, h=wall_thickness+2);

        translate([mount_width/2-4.5, wall_thickness+7.5-2.5, wall_thickness-.8])
        cube(size=[9, 5, 1]);
    }
    }
}

module sides() {
    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness*2, h=mount_depth);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);

            // upper left
            translate([0, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness*2, wall_thickness*2, mount_depth]);
        }

        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=mount_depth+1);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, mount_depth+1]);
        }
    }

    intersection() {
        translate([wall_thickness, wall_thickness, 0])
        cube([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), mount_depth]);

        union() {
            translate([wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([mount_width-wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);

            translate([wall_thickness, mount_height-wall_thickness, mount_depth-6-wall_thickness])
            cylinder(r=9, h=6);
            translate([wall_thickness, mount_height-wall_thickness, mount_depth-10-wall_thickness])
            cylinder(r1=3, r2=9, h=4);
        }
    }
}

module cover() {
    hole_center = mount_height - table_padding - button_radius;

    difference() {
        hull() {
            // lower left
            translate([wall_thickness*2, wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // lower right
            translate([mount_width-(wall_thickness*2), wall_thickness*2, 0])
            cylinder(r=wall_thickness, h=wall_thickness);

            // upper right
            translate([mount_width-(wall_thickness*2), mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);

            // upper left
            translate([wall_thickness, mount_height-(wall_thickness*2), 0])
            cube(size=[wall_thickness, wall_thickness, wall_thickness]);
        }

        translate([mount_width/2, hole_center, -1])
        cylinder(r=hole_radius, h=wall_thickness*2);
    }

    // Fake button
    // translate([mount_width/2, hole_center, 5])
    // cylinder(r=button_radius, h=20);
}

module cover_screws() {
    translate([wall_thickness+3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, wall_thickness+3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([mount_width-wall_thickness-3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);

    translate([wall_thickness+3.5, mount_height-wall_thickness-3.5, mount_depth/2])
    cylinder(r=1.5, h=30);
}

module mount_screws() {
    spacing = 15;

    translate([spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, mount_depth-spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);

    translate([mount_width-spacing, mount_height, spacing])
    rotate([90, 0, 0])
    cylinder(r=2, h=wall_thickness+2);
}

// Text
module letter(l, h=100, i=0) {
    union() {
        linear_extrude(height=h) import(font, layer=l[i]);
        translate([dxf_dim(file=font, name="advx", layer=l[i]), dxf_dim(file=font, name="advy", layer=l[i]), 0])
        child();
    }
}

module word(wrd, h=100, i=0) {
    if (i < len(wrd)) {
        letter(wrd, h, i) word(wrd, h, i+1);
    } else {
        child();
    }
}

module name() {
    translate([18.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Scott", 1000);

    translate([46.5, mount_height - 20, wall_thickness-1.5])
    scale(0.002)
    word("Barron", 1000);

    translate([34.5, mount_height - 35, wall_thickness-1.5])
    scale(0.002)
    word("2014", 1000);
}

module project() {
    translate([22, mount_height-20, mount_depth-1.5])
    scale(0.002)
     word("Pingduino", 1000);
}


bearing_data: add some sf1 bushings

bearing_data: add some sf1 bushings


body: top_shoulder position

body: top_shoulder position

include <constants.scad>;
HEIGHT_BODY = 44.5;
DIAMETER_BODY = 10.4;
BORDER_RADIUS_BODY = 0.2;
HEIGHT_NIPPLE = 0.8;

module top_surface()
{
    position_z = -(HEIGHT_NIPPLE + BORDER_RADIUS_BODY);
    position = [0,0,position_z];

    correction_diameter = (2 * BORDER_RADIUS_BODY);
    diameter_base = DIAMETER_BODY - correction_diameter;

    translate(position)
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = diameter_base,
        $fn = FINE);
}

module top_shoulder()
{
    position_ring_z = -(HEIGHT_NIPPLE + BORDER_RADIUS_BODY);
    position_ring = [0,0,position_ring_z];

    position_circle_x = radius(DIAMETER_BODY)-BORDER_RADIUS_BODY;
    position_circle = [position_circle_x, 0, 0];

    translate(position_ring)
        rotate_extrude(convexity = CONVEXITY, $fn = FINE)
            translate(position_circle)
                circle(r = BORDER_RADIUS_BODY, $fn = FINE);
}

module body()
{
    top_surface();
    top_shoulder();

//Main body cylinder
translate([0,0,-(HEIGHT_BODY - BORDER_RADIUS_BODY)])
    cylinder(
        h = (HEIGHT_BODY - (HEIGHT_NIPPLE + (2* BORDER_RADIUS_BODY))),
        d = DIAMETER_BODY,
        $fn = FINE);

//Body bottom shoulder
translate([0,0,-(HEIGHT_BODY - BORDER_RADIUS_BODY)])
    rotate_extrude(convexity = CONVEXITY, $fn = FINE)
    translate([(DIAMETER_BODY/2)-BORDER_RADIUS_BODY, 0, 0])
        circle(r = BORDER_RADIUS_BODY, $fn = FINE);

//Bottom face of body
translate([0,0,-(HEIGHT_BODY)])
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = (DIAMETER_BODY - (2 * BORDER_RADIUS_BODY)),
        $fn = FINE);
}

body();

include <constants.scad>;
HEIGHT_BODY = 44.5;
DIAMETER_BODY = 10.4;
BORDER_RADIUS_BODY = 0.2;
HEIGHT_NIPPLE = 0.8;

module top_surface()
{
    position_z = -(HEIGHT_NIPPLE + BORDER_RADIUS_BODY);
    position = [0,0,position_z];

    correction_diameter_base = (2 * BORDER_RADIUS_BODY);
    diameter_base = DIAMETER_BODY - correction_diameter_base;

    translate(position)
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = diameter_base,
        $fn = FINE);
}

module top_shoulder()
{
   translate([0,0,-(HEIGHT_NIPPLE + BORDER_RADIUS_BODY)])
        rotate_extrude(convexity = CONVEXITY, $fn = FINE)
            translate([(DIAMETER_BODY/2)-BORDER_RADIUS_BODY, 0, 0])
                circle(r = BORDER_RADIUS_BODY, $fn = FINE);
}

module body()
{
    top_surface();
    top_shoulder();

//Main body cylinder
translate([0,0,-(HEIGHT_BODY - BORDER_RADIUS_BODY)])
    cylinder(
        h = (HEIGHT_BODY - (HEIGHT_NIPPLE + (2* BORDER_RADIUS_BODY))),
        d = DIAMETER_BODY,
        $fn = FINE);

//Body bottom shoulder
translate([0,0,-(HEIGHT_BODY - BORDER_RADIUS_BODY)])
    rotate_extrude(convexity = CONVEXITY, $fn = FINE)
    translate([(DIAMETER_BODY/2)-BORDER_RADIUS_BODY, 0, 0])
        circle(r = BORDER_RADIUS_BODY, $fn = FINE);

//Bottom face of body
translate([0,0,-(HEIGHT_BODY)])
    cylinder(
        h = BORDER_RADIUS_BODY,
        d = (DIAMETER_BODY - (2 * BORDER_RADIUS_BODY)),
        $fn = FINE);
}

body();


holder's draft

holder's draft

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