metric-screw: use fallback func

metric-screw: use fallback func

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

include <metric-thread-data.scad>
include <metric-hexnut-data.scad>
include <metric-knurlnut-data.scad>

use <scad-utils/transformations.scad>

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

module screw(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

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

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

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

module screw_cut(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, cut_access=true, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

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

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

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

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

module screw_thread(thread=ThreadM3, h=10, tolerance=1.00, orient=[0,0,1], align=[0,0,0])
{
    // TODO render thread
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

module screw_thread_cut(thread=ThreadM3, h=10, tolerance=1.05, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    difference()
    {
        cylindera(d=head_d, h = fallback(override_h,head_h));
        translate([0,0,head_h/2])
        cylindera(d=threadsize, h = head_d/2);
    }
}

module screw_head_cut(nut=MHexNutM3, tolerance=1.05, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    translate([0,0,-head_h/2])
    cylindera(d=head_d, h=fallback(override_h, head_h), align=[0,0,1]);
}

module screw_nut(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    facets = lookup(MHexNutFacets, nut);
    cylindera($fn=lookup(MHexNutFacets, nut), d=d, h=fallback(override_h, thickness), orient=orient, align=align);
}

module screw_nut_cut(nut=MHexNutM3, tolerance=1.05, h=1000, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    size_align(size=[d,d,thickness], orient=orient, align=align)
    {
        translate([0,0,thickness/2])
        {
            screw_nut(nut, tolerance, orient=[0,0,1], align=[0,0,-1]);
            translate([0,0,-thickness+.01])
            {
                cylindera(d=d*1.1, h=h, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

module nut_trap_cut(nut=MHexNutM3, trap_offset=10, screw_l=10*mm, screw_l_extra=2*mm, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)+.5*mm;
    thread = get(MHexNutThread, nut);

    nut_width_min = lookup(MHexNutWidthMin, nut)+.2*mm;
    nut_width_max = lookup(MHexNutWidthMax, nut)+.2*mm;
    s = nut_width_min;
    total_h = nut_h;

    size_align(size=[s, s, total_h], orient=orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,nut_h/2-.1])
        screw_thread_cut(thread=thread, tolerance=1.1, h=screw_l, orient=[0,0,-1], align=[0,0,1]);

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

        hull()
        {
            orient(-orient)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(orient)
                cylindera($fn=lookup(MHexNutFacets, nut), d=nut_width_max, h=nut_h, align=[0,0,0]);

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

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

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

    }

}

function get(key, dict) =
    let(x= search(MHexNutThread, MHexNutM3))
    dict[x[0]];

if(false)
{
    nut1 = MHexNutM3;
    nut2 = MHexNutM5;
    nut3 = MKnurlInsertNutM3_3_42;
    nut4 = MKnurlInsertNutM3_5_42;

    /*translate([0,20,0])*/
    /*translate([0,20,0])*/
    /*for(axis1=[0:len(AXES)-1])*/
    /*[>for(axis2=AXES)<]*/
    /*translate(20*AXES[axis1])*/
    /*{*/
        /*ta = v_rotate(90, AXES[axis1])*AXES[axis1];*/
        /*echo(AXES[axis1], ta);*/
        /*nut_trap_cut(nut=nut1, trap_axis=ta, orient=AXES[axis1]);*/
    /*}*/

    /*stack(d=30, axis=[1,0,0])*/
    /*{*/
        /*stack(d=20, axis=[0,1,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[1,0,0]);*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[-1,0,0]);*/
        /*}*/

        /*stack(d=20, axis=[1,0,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,1,0]);*/

            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,-1,0]);*/
        /*}*/
    /*}*/

    box_w = 100;
    box_h = 10;
    box_d = 10;
    o = 10;

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

    difference()
    {
        cubea([box_w,box_d/2,box_h], align=[1,1,1]);

        test_cuts();
    }
    /*difference()*/
    /*{*/
        /*cubea([box_w,box_d/2,box_h], align=[1,-1,1]);*/

        /*test_cuts();*/
    /*}*/

}

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

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

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

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

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

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

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

include <metric-thread-data.scad>
include <metric-hexnut-data.scad>
include <metric-knurlnut-data.scad>

use <scad-utils/transformations.scad>

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

module screw(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

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

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

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

module screw_cut(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, cut_access=true, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

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

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

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

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

module screw_thread(thread=ThreadM3, h=10, tolerance=1.00, orient=[0,0,1], align=[0,0,0])
{
    // TODO render thread
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

module screw_thread_cut(thread=ThreadM3, h=10, tolerance=1.05, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    difference()
    {
        cylindera(d=head_d, h = override_h==undef?head_h:override_h);
        translate([0,0,head_h/2])
        cylindera(d=threadsize, h = head_d/2);
    }
}

module screw_head_cut(nut=MHexNutM3, tolerance=1.05, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut)*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=override_h==undef?head_h:override_h, align=[0,0,1]);
}

module screw_nut(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    facets = lookup(MHexNutFacets, nut);
    cylindera($fn=lookup(MHexNutFacets, nut), d=d, h=override_h==undef?thickness:override_h, orient=orient, align=align);
}

module screw_nut_cut(nut=MHexNutM3, tolerance=1.05, h=1000, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    size_align(size=[d,d,thickness], orient=orient, align=align)
    {
        translate([0,0,thickness/2])
        {
            screw_nut(nut, tolerance, orient=[0,0,1], align=[0,0,-1]);
            translate([0,0,-thickness+.01])
            {
                cylindera(d=d*1.1, h=h, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

module nut_trap_cut(nut=MHexNutM3, trap_offset=10, screw_l=10*mm, screw_l_extra=2*mm, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)+.5*mm;
    thread = get(MHexNutThread, nut);

    nut_width_min = lookup(MHexNutWidthMin, nut)+.2*mm;
    nut_width_max = lookup(MHexNutWidthMax, nut)+.2*mm;
    s = nut_width_min;
    total_h = nut_h;

    size_align(size=[s, s, total_h], orient=orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,nut_h/2-.1])
        screw_thread_cut(thread=thread, tolerance=1.1, h=screw_l, orient=[0,0,-1], align=[0,0,1]);

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

        hull()
        {
            orient(-orient)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(orient)
                cylindera($fn=lookup(MHexNutFacets, nut), d=nut_width_max, h=nut_h, align=[0,0,0]);

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

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

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

    }

}

function get(key, dict) =
    let(x= search(MHexNutThread, MHexNutM3))
    dict[x[0]];

if(false)
{
    nut1 = MHexNutM3;
    nut2 = MHexNutM5;
    nut3 = MKnurlInsertNutM3_3_42;
    nut4 = MKnurlInsertNutM3_5_42;

    /*translate([0,20,0])*/
    /*translate([0,20,0])*/
    /*for(axis1=[0:len(AXES)-1])*/
    /*[>for(axis2=AXES)<]*/
    /*translate(20*AXES[axis1])*/
    /*{*/
        /*ta = v_rotate(90, AXES[axis1])*AXES[axis1];*/
        /*echo(AXES[axis1], ta);*/
        /*nut_trap_cut(nut=nut1, trap_axis=ta, orient=AXES[axis1]);*/
    /*}*/

    /*stack(d=30, axis=[1,0,0])*/
    /*{*/
        /*stack(d=20, axis=[0,1,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[1,0,0]);*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[-1,0,0]);*/
        /*}*/

        /*stack(d=20, axis=[1,0,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,1,0]);*/

            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,-1,0]);*/
        /*}*/
    /*}*/

    box_w = 100;
    box_h = 10;
    box_d = 10;
    o = 10;

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

    difference()
    {
        cubea([box_w,box_d/2,box_h], align=[1,1,1]);

        test_cuts();
    }
    /*difference()*/
    /*{*/
        /*cubea([box_w,box_d/2,box_h], align=[1,-1,1]);*/

        /*test_cuts();*/
    /*}*/

}

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

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

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

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

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

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


Update knurled cap M5 demo

Update knurled cap M5 demo

include <cap.scad>;

// Note that I get a very strange behavior with F5 mode, a fixed polygon covers
// half my screen and some of the tee part is missing.  When rendering in F6
// mode, everying behaves.

M5_head = 8.8/2;
M5_tall = 5;
M5_pegrad = 4/2;

num_caps = 1;

union() {
  for(i=[1:num_caps]) {
    translate([i*40, 0, 0])
      Knob(outerRad=M5_head*1.65, pegRad=M5_pegrad, capRad=M5_head,
           chamfer=0.9, $fn=100);
  }
}

// vim: ft=c sw=2 sts=2 ts=2 et

error: pathspec 'knurled-cap/demo_cap_m5.scad' did not match any file(s) known to git


Got the enclosure and the struts working

// Program by Ankur Gupta
// www.github.com/agupta231
// Jan 2017

/**
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/

init_size = 50;
iteration_multiplier = 0.5;
iterations = 5;
hull_width = 7;
strut_width = 3;

echo(version());
echo("Total Size: ---------");
echo(((init_size * iteration_multiplier) * (1 - pow(iteration_multiplier, iterations))) / (1 - iteration_multiplier) * 2 + init_size);
echo("---------------------");

module aux_cubes(current_iter, starting_pos) {
    iter_size = init_size * pow(iteration_multiplier, current_iter);
    displacement = (init_size * (pow(iteration_multiplier, current_iter) + pow(iteration_multiplier, current_iter - 1))) / 2;

    for(i = [[displacement, 0, 0], [-displacement, 0, 0], [0, displacement, 0], [0, -displacement, 0], [0, 0, displacement], [0, 0, -displacement]]) {
        new_pos = i + starting_pos;

        translate(i + starting_pos) {
            cube(iter_size, center = true);
        }

        if(current_iter < iterations) {
            aux_cubes(current_iter + 1, new_pos);
        }
    }
}

module struts(total_length) {
    strut_length = total_length * sqrt(3) + hull_width / 2;

    for(i = [[35, 0, -45], [35, 0, 45], [-35, 0, 45], [-35, 0, -45]]) {
        rotate(i) {
            cube([strut_width, strut_length, strut_width], center = true);
        }
    }
}

module enclosure() {
    total_length = ((init_size * iteration_multiplier) * (1 - pow(iteration_multiplier, iterations))) / (1 - iteration_multiplier) * 2 + init_size;

    union() {
        difference() {
            cube(total_length + hull_width, center = true);

            for(i = [[hull_width + 1, 0, 0], [0, hull_width + 1, 0], [0, 0, hull_width + 1], [-hull_width - 1, 0, 0], [0, -hull_width - 1, 0], [0, 0, -hull_width - 1]]) {
                translate(i) {
                    cube(total_length, center = true);
                }
            }
        }

        struts(total_length);
    }
}

union() {
    //cube(init_size, center = true);
    //saux_cubes(1, [0, 0, 0]);

    enclosure();

}

// Program by Ankur Gupta
// www.github.com/agupta231
// Jan 2017

/**
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/

init_size = 50;
iteration_multiplier = 0.5;
iterations = 5;

echo(version());

module aux_cubes(current_iter, starting_pos) {
    iter_size = init_size * pow(iteration_multiplier, current_iter);
    displacement = (init_size * (pow(iteration_multiplier, current_iter) + pow(iteration_multiplier, current_iter - 1))) / 2;

    for(i = [[displacement, 0, 0], [-displacement, 0, 0], [0, displacement, 0], [0, -displacement, 0], [0, 0, displacement], [0, 0, -displacement]]) {
        new_pos = i + starting_pos;

        translate(i + starting_pos) {
            cube(iter_size, center = true);
        }

        if(current_iter < iterations) {
            aux_cubes(current_iter + 1, new_pos);
        }
    }
}

union() {
    cube(init_size, center = true);

    aux_cubes(1, [0, 0, 0]);
}


fixed colusion of LCD mounting with cable guide drill

use <lcd.scad>
use <menu_knob.scad>
use <menu_knob_manipulator.scad>
use <reset_button.scad>
use <sdcard_reader.scad>
use <cable_guide.scad>

boxSize = [143, 148, 6+7];
lcdOffset = boxSize - [98+5, 60+5, 12];
encoderOffset = [20-14/2, boxSize[1]-30/2-15/2-3, boxSize[2]-(6+7)];
sdCardOffset = [35, 80, boxSize[2]-6];
resetButtonOffset = [encoderOffset[0]+14/2, 68, 1];

//rotate([180, 0, 0])
{
  difference()
  {
    union()
    {
      // main mounting legs
      for(offset = [ [boxSize[0]-16, 0, boxSize[2]-7], [boxSize[0]-70, 0, boxSize[2]-7] ])
        translate(offset)
          cube([16, 40+13, 7]);
      // side mounting wing
      translate([15, 0, 6])
        cube([18, 20, 7]);

      difference()
      {
        // main working area
        cube(boxSize);
        // prusa's framework  corner
        translate([15, 0, 0])
          cube([143-15, 53, boxSize[2]]);
        // LCD
        translate(lcdOffset)
          lcdBoard();
        // encoder
        translate(encoderOffset)
        {
          translate([-2, -1/2, -8])
            cube([14+2*2, 12+1, 8+6]);
          menuKnob();
        }
        // SD card mount
        translate(sdCardOffset)
          rotate([0,180,0])
            sdCardReader();
        // reset button
        translate(resetButtonOffset)
        {
          translate([0, 0, -resetButtonOffset[2]])
            cylinder(r=(16+1)/2, h=boxSize[2])
          resetButton();
        }
        // cable guide drill
        translate([boxSize[0]-98-5, 40+16+6, 0])
          cableGuide();
        // side mounting wing cut-in, so that screw will hold tight
        cube([15, 40, 6]);
      }
    }

    // mounting drills
    for(offsetOY = [ 13/2+5/2, 40+13+5])
      for(offsetOX = [15/2, boxSize[0]-70+16/2, boxSize[0]-16/2])
        translate([offsetOX, offsetOY, -1])
          cylinder(r=5/2, h=6+7+2, $fs=1);
  }

  // LCD stub
  %translate(lcdOffset)
    lcdBoard();
  // encoder stub
  %translate(encoderOffset)
  {
    menuKnob();
    translate([7, 6, 23+4])
      rotate([180,0,0])
        menuKnobManipulator();
  }
  // SD card mount stub
  %translate(sdCardOffset)
    rotate([0,180,0])
      sdCardReader();
  // reset button stub
  %translate(resetButtonOffset)
    resetButton();
}

use <lcd.scad>
use <menu_knob.scad>
use <menu_knob_manipulator.scad>
use <reset_button.scad>
use <sdcard_reader.scad>
use <cable_guide.scad>

boxSize = [143, 148, 6+7];
lcdOffset = boxSize - [98+5, 60+5, 12];
encoderOffset = [20-14/2, boxSize[1]-30/2-15/2-3, boxSize[2]-(6+7)];
sdCardOffset = [35, 80, boxSize[2]-6];
resetButtonOffset = [encoderOffset[0]+14/2, 68, 1];

//rotate([180, 0, 0])
{
  difference()
  {
    union()
    {
      // main mounting legs
      for(offset = [ [boxSize[0]-16, 0, boxSize[2]-7], [boxSize[0]-70, 0, boxSize[2]-7] ])
        translate(offset)
          cube([16, 40+13, 7]);
      // side mounting wing
      translate([15, 0, 6])
        cube([18, 20, 7]);

      difference()
      {
        // main working area
        cube(boxSize);
        // prusa's framework  corner
        translate([15, 0, 0])
          cube([143-15, 53, boxSize[2]]);
        // LCD
        translate(lcdOffset)
          lcdBoard();
        // encoder
        translate(encoderOffset)
        {
          translate([-2, -1/2, -8])
            cube([14+2*2, 12+1, 8+6]);
          menuKnob();
        }
        // SD card mount
        translate(sdCardOffset)
          rotate([0,180,0])
            sdCardReader();
        // reset button
        translate(resetButtonOffset)
        {
          translate([0, 0, -resetButtonOffset[2]])
            cylinder(r=(16+1)/2, h=boxSize[2])
          resetButton();
        }
        // cable guide drill
        translate([boxSize[0]-98-5, 40+16+10, 0])
          cableGuide();
        // side mounting wing cut-in, so that screw will hold tight
        cube([15, 40, 6]);
      }
    }

    // mounting drills
    for(offsetOY = [ 13/2+5/2, 40+13+5])
      for(offsetOX = [15/2, boxSize[0]-70+16/2, boxSize[0]-16/2])
        translate([offsetOX, offsetOY, -1])
          cylinder(r=5/2, h=6+7+2, $fs=1);
  }

  // LCD stub
  %translate(lcdOffset)
    lcdBoard();
  // encoder stub
  %translate(encoderOffset)
  {
    menuKnob();
    translate([7, 6, 23+4])
      rotate([180,0,0])
        menuKnobManipulator();
  }
  // SD card mount stub
  %translate(sdCardOffset)
    rotate([0,180,0])
      sdCardReader();
  // reset button stub
  %translate(resetButtonOffset)
    resetButton();
}


feat: add an operator to animate a mirroring

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2022 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Operators that animate child modules with respect to particular rules.
 *
 * @package operator/animate
 * @author jsconan
 */

/**
 * Mirrors the child modules, interpolating the axis with respect to the `$t` variable.
 *
 * @param Vector [from] - The axis from where starts the interpolation.
 * @param Vector [to] - The axis to where ends the interpolation.
 * @param Number [start] - The start threshold under what the from-axis will persist and above what it will be interpolated.
 * @param Number [end] - The end threshold above what the to-axis will persist and under what it will be interpolated.
 * @param Number [domain] - The percentage domain used to compute the thresholds (default: 100).
 * @param Vector [values] - A list of axis composing the range to interpolate.
 * @param Vector [range] - A pre-built interpolation range. If missing, it will be built from the parameters `from`, `to`, `start`, `end`, `domain`.
 * @returns Number
 */
module mirrorAnimate(from, to, start, end, domain, values, range) {
    mirror(interpolateStep3D(step=$t, low=from, high=to, start=start, end=end, domain=domain, values=values, range=range)) {
        children();
    }
}

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


[3d] Remove mousears, add configurable body chamfer and walls now full  3mm

// preview[view:northeast, tilt:topdiagonal]

/* [Options] */
// Pit probe type
Control_Probe = "Thermocouple"; // [Thermocouple,Thermistor]
// Raspberry Pi Model
Pi_Model = "3B/2B/1B+"; // [3B/2B/1B+,Connectorless,1A+,Zero]
// Which case halves
Pieces = "Both"; // [Both,Top,Bottom]
/* [Advanced] */
// Thickness of side walls
wall = 3;
// Thickness of top and bottom faces
wall_t = 2;
// External corner radius on the body
body_corner_radius = 4;
// Height of the body edge bead chamfer
body_chamfer_height = 1.5;

/* [Hidden] */
w = inch(3.75)+0.5; // overall interior case width
d = inch(3.75)-0.5; // overall interior case depth
h_b = 32; // overall interior case height

probe_centerline = 9.0; // case is split along probe centerline on the probe side
case_split = 12.4;  // and the case split on the other 3 sides

pic_ex = 2;
lcd_mount_t = 7;

body_chamfer_height_t = body_chamfer_height;
body_chamfer_height_b = body_chamfer_height;

e = 0.01;

hm43_split();

function inch(x) = x*25.4;

module cube_fillet_chamfer(size,f,c,$fn=32) {
  hull() {
    translate([f,f,c]) linear_extrude(height=size[2]-2*c) minkowski() {
      square([size[0]-2*f, size[1]-2*f]);
      circle(r=f, $fn=$fn);
    }
    translate([f+c,f+c,0]) linear_extrude(height=size[2]) minkowski() {
      square([size[0]-2*(f+c), size[1]-2*(f+c)]);
      circle(r=f, $fn=$fn);
    }
  }
}

module jhole(d, h) {
  translate([0,0,h/2]) cube([2*(wall+pic_ex),d,h], center=true);
}

module phole() {
  dia=4.5;
  // Hole for thermistor probe jack
  rotate([0,90,0]) cylinder(2*wall, d=dia, $fn=16);
  // because 3d print tends to curl up slightly between the probe holes,
  // do not go right to the edge on the final layer (stop 0.25mm short on each side)
  translate([0,-(dia+0.5)/2, -0.3]) cube([2*wall, dia+0.5, 0.6]);
}

module screwhole() {
  // Screw hole for bottom of case (including nut)
  //translate([0,0,-e]) cylinder(h_b+wall_t, d=3.4, $fn=18);
  translate([0,0,-e]) {
    cylinder(0.4, d1=7.4, d2=6.6, $fn=6);
    translate([0,0,0.4]) cylinder(3, d=6.6, $fn=6);
  }
  translate([0,0,3+0.2]) cylinder(h_b+2*wall_t, d=3.4, $fn=18);
  translate([0,0,h_b+wall_t]) cylinder(3, d=5.5, $fn=18);
}

module screwhole2() {
  translate([0,0,-e]) cylinder(3, d=6, $fn=18);
  translate([0,0,3+0.4]) cylinder(h_b-3-0.4, d=3.4, $fn=18);
}

module pic_ex_cube() {
  translate([0,33.75,2])
    cube_fillet([pic_ex+e, 59.5, 20.8],
      vertical=[0, pic_ex, pic_ex, 0],
      top=[0,pic_ex,0,0],
      bottom=[0,pic_ex,0,0]);
}

module screw_pimount() {
  // 2mm height is good for screw holes
  difference() {
    cylinder(h=2.25, d=6.4, $fn=18);
    //cylinder(h=2+e, d=2.5, $fn=16);
  }
}

module btn_rnd(dia=10) {
  cylinder(wall_t+2*e, d1=dia, d2=dia+1.5*wall_t, $fn=24);
  translate([-6.5,-6.5,0]) cube([13,13,0.75+e]);
}

module btn_square(sq=13) {
  translate([-sq/2,-sq/2,0]) cube([sq,sq,wall_t+2*e]);
}

module tc_plusminus() {
  T=0.75+e;
  H=2;
  W=6;
  // Minus
  translate([0,2,0])
    cube_fillet([T, W, H], top=[0,0,0,T]);
  translate([0,-(2+W),0]) {
    cube_fillet([T, W, H], top=[0,0,0,T]);
    translate([0,(W-H)/2,(H-W)/2])
      cube_fillet([T, H, W], top=[0,0,0,T]);
  }
}

module led_hole() {
  cylinder(wall_t+2*e, d=3.4, $fn=16);
}

module nuttrap() {
  ww_w=3;
  ww_d=2.7;
  nut_h=2.8;
  nut_ingress = 5.8; //nut_d * sin(60);
  nut_d = nut_ingress / sin(60);
  oa_h=wall_t+0.4+nut_h+wall_t+6.7;

  // bottom half for M3 socket cap screw (flush)
  difference() {
    translate([-5.5/2-ww_w, -nut_ingress/2-e, 0])
      cube_fillet([5.5+2*ww_w, nut_ingress+ww_d*0.8+e, 6], vertical=[3.4,3.4], $fn=20);
    // socket cap
    translate([0,0,-e]) cylinder(3.5, d=6, $fn=18);
    // screw shaft
    translate([0,0,3.5+0.3]) cylinder(oa_h-3, d=3.4, $fn=18);
  }

  // top half M3 nut trap
  translate([0,0,h_b+wall_t-oa_h])
  difference() {
    translate([-(nut_d/2+ww_w), -nut_ingress/2-e, 0])
      cube_fillet([nut_d+2*ww_w, nut_ingress+ww_d+e, oa_h],
        vertical=[3.4,3.4], $fn=20);
    // M3 screw
    translate([0,0,-e]) cylinder(wall_t, d1=4, d2=3.4, $fn=16);
    // nut hole / M3 extra
    translate([0,0,wall_t+0.3]) {
      translate([-0.4,0,0]) // nut offset slightly deeper for easier alignment
        cylinder(nut_h*1.5+e, d=nut_d, $fn=6);  // nut
      cylinder(oa_h-wall_t-0.3, d=4, $fn=16);  // M3 with plenty of clearance
    }
    // nut ingress
    translate([0,-nut_ingress/2,wall_t+0.3])
      cube([nut_d/2+ww_w+e,nut_ingress,nut_h+e]);
  }
}

module locklip_p(l, l_offset=1,
  lip_insert_depth=2.0, // how deep V to insert
  lip_v_off=0.2, // extra height before starting insert
  lip_h_off=0.4, // back connector away from mating area
  lip_w=1.5  // thickness of attachment beam
  ) {
  translate([l_offset,0,0]) rotate([90,0,0]) rotate([0,90,0])
    linear_extrude(height=l-2*l_offset) polygon(points=[
      [0, -lip_w-lip_insert_depth-lip_h_off],
      [0, 0],
      [-lip_insert_depth-lip_h_off, 0],
      [-lip_insert_depth-lip_h_off, lip_v_off],
      [-lip_h_off, lip_v_off+lip_insert_depth],
      [-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth,],
      [-lip_w-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth],
      [-lip_w-lip_insert_depth-lip_h_off, 0]
    ]);
}

module locklip_n(l, l_offset=1,
  lip_insert_depth=2.2, // how deep V to insert
  lip_tip_clip=0.3, // how much to shave off the top tip
  ) {
  translate([l-l_offset,0,0]) rotate([90,0,0]) rotate([0,-90,0])
    linear_extrude(height=l-2*l_offset) polygon(points=[
      [0.1, -3*lip_insert_depth],  // 0.1 to add depth to keep extrusion manifold
      [0.1, -lip_tip_clip],
      [-lip_insert_depth+lip_tip_clip, -lip_tip_clip],
      [-e, -lip_insert_depth],
      [-lip_insert_depth, -2*lip_insert_depth]
    ]);
}

module lcd_screw() {
  rotate([180]) difference() {
    //cylinder(lcd_mount_t, d=2.5+3.2, $fn=16);
    cylinder(lcd_mount_t+e, d=2.5, $fn=16);
  }
}

module lcd_mount() {
  // Assuming starting at bottom left screw hole
  lcd_screw();
  //translate([75,0,0]) lcd_screw(); // bottom right hole obscured by PCB
  translate([0,31,0]) lcd_screw();
  translate([75,31,0]) lcd_screw();
}

module lcd_neg() {
  // Assuming starting at bottom left screw hole
  translate([1.0, 2.1, 0])
    cube([73.0, 26.3, lcd_mount_t+wall_t-0.8]); // black bezel inset
  translate([5.5, 7.8, 0])
    cube([64.0, 15.4, lcd_mount_t+wall_t+2*e]); // LCD active area
  translate([4.23, -2.5, 0])
    cube([16*2.54, 5, lcd_mount_t+wall_t-0.8]); // pins cutout
}

module locklip_top_n(split) {
  translate([wall, d+wall, split+wall_t+e])
    rotate([180]) {
      locklip_n(28);
      translate([w-34,0,0]) locklip_n(34);
    }
}

module hm43() {
difference() {
  union() {
    cube_bchamfer([w+2*wall, d+2*wall, h_b+2*wall_t],
      r=body_corner_radius, top=body_chamfer_height_t,
      bottom=body_chamfer_height_b, $fn=36);
    // extra thick by Pi connectors
    if (Pi_Model != "Zero")
      translate([-pic_ex,wall,wall_t])
        pic_ex_cube();
    // TC +/-
    if (Control_Probe == "Thermocouple")
      translate([w+wall*2-e,wall+10,wall_t+18]) tc_plusminus();
  }

  // Main cutout
  translate([wall, wall, wall_t])
    cube_fillet([w, d, h_b+e], bottom=[2,2,2,2],
    top=[lcd_mount_t,lcd_mount_t,lcd_mount_t,lcd_mount_t]);
  if (Pi_Model != "Zero")
    translate([wall-pic_ex+e,wall,wall_t]) pic_ex_cube();

  // Probe jack side
  translate([w+wall*0.5,wall,wall_t]) {
    // Probe jacks
    translate([0,24.25,probe_centerline]) {
      if (Control_Probe == "Thermocouple")
        // TC jack
        translate([0,inch(-0.55)-16.5/2,-1.4]) cube([2*wall, 16.5, 6.5]);
      else
        translate([0,-17.25,0]) phole();
      translate([0,inch(0.37)*0,0]) phole();
      translate([0,inch(0.37)*1,0]) phole();
      translate([0,inch(0.37)*2,0]) phole();
    }
  }
  // Pi connector side
  translate([wall*-0.5,wall,wall_t]) {
    // Pi connectors
    translate([0,0,5]) {
      if (Pi_Model == "3B/2B/1B+") {
        // ethernet
        translate([0,81.5,-0.5]) jhole(15,13);
        translate([0,81.5,-1.5]) jhole(5,5);
        // USB 0+1
        translate([0,62.75,0]) jhole(13,14.8);
        translate([0,44.75,0]) jhole(13,14.8);
      }
      if (Pi_Model == "1A+")
        translate([0,44.75,0]) jhole(13,7.4);
    }
    // HeaterMeter connectors
    translate([0,0,0]) {
      // Blower/Servo output
      translate([0,25.25,1.1]) jhole(16.7,13);
      // HM power jack
      translate([0,5.25,3.4]) jhole(9.4,11);
    }
  }

  // lcd hole
  translate([wall+10.7, wall+52, h_b+wall_t-lcd_mount_t-e]) lcd_neg();

  // button holes
  translate([wall+48.7, wall+29.4, h_b+wall_t-e]) {
    translate([-inch(1.1)/2,0,0]) btn_rnd(7.2);  // left
    translate([inch(1.1)/2,0,0]) btn_rnd(7.2);   // right
    translate([0,inch(0.9)/2,0]) btn_rnd(7.2);   // up
    translate([0,-inch(0.9)/2,0]) btn_rnd(7.2);  // down
    // LED holes
    translate([inch(1.3), inch(-0.05), 0]) {
      led_hole();  //red
      translate([0, inch(0.35), 0]) led_hole(); //yellow
      translate([0, inch(0.70), 0]) led_hole(); //green
    }
  }
  // close screw holes
  translate([wall+inch(0.8)+1.3,wall+2.9,0]) {
    screwhole2();
    translate([inch(2.0),0,0]) screwhole2();
  }
}  // END OF DIFFERENCE

  // Pi mounting screws
  translate([wall+24,wall+d-7,wall_t]) {
    //screw_pimount();
    translate([58,0,0]) screw_pimount();
    translate([58,-49,0]) screw_pimount();
    translate([0,-49,0]) screw_pimount();
    translate([0,0,0]) screw_pimount();
  }
  // Pi right edge stop
  translate([wall+w-10, wall+d-60, wall_t]) {
    difference() {
      cube_fillet([10,60,4], vertical=[0,0,10/2], $fn=24);
      // Pi B+ microsd gap
      translate([-e,22.5,-e]) cube_fillet([6,14,4+2*e], vertical=[2,0,0,2], $fn=20);
    }
  }

  // close nut traps
  translate([wall+inch(0.8)+1.3,wall+2.9,0]) {
    nuttrap();
    translate([inch(2.0),0,0]) nuttrap();
  }

  // Top locklip (negative)
  if (Pi_Model == "3B/2B/1B+")
    locklip_top_n(case_split);
  else
    locklip_top_n(probe_centerline);

  // LCD mount
  difference() {
    union() {
      // Filled block above LCD hole
      translate([wall, wall+d-16, h_b+wall_t-lcd_mount_t]) cube([w,16,lcd_mount_t+e]);
      // LCD grab notch
      translate([wall+10.7, wall+52, h_b+wall_t-lcd_mount_t])
        translate([(77.5-20)/2,33.5-wall_t,-(1.8+wall_t)])
          // 1.8=thickness of LCD pcb
          cube_fillet([20,1.8+wall_t+wall,1.8+wall_t+e], top=[0,0,1.8+wall_t+e],
            vertical=[wall/2,wall/2]);
    }
    translate([wall+10.7, wall+52, h_b+wall_t-lcd_mount_t-e]) lcd_neg();
    translate([wall+10.7, wall+52, h_b+wall_t-e]) lcd_mount();
  }

  if (Pi_Model == "3B/2B/1B+" || Pi_Model == "1A+")
    translate([wall-pic_ex, wall, wall_t]) {
      // USB pillar reinforcements
      translate([0, (44.75+62.75)/2-1, 0]) cube([pic_ex+1, 2, h_b]);
      translate([0, 81.5-15/2-3, 0]) cube([pic_ex+1, 2.5, h_b]);
      // Near pic_ex fill
      translate([0, 33.75, 0]) cube([pic_ex, 3, h_b]);
      // Far pic_ex fill (near ethernet)
      translate([0, (33.75+59.5)-3, 0]) cube([pic_ex+1, 3, h_b]);
    }
}

module lip_guide(l) {
  guide_offset = 0.2; // how much to recess the edge guides
  guide_h = 1.2; // how tall above the edge to extend
  linear_extrude(height=l) polygon([
    [0,-e], [wall+guide_offset,-e], [0, wall+guide_offset],
    [-guide_h, wall+guide_offset], [-guide_h, guide_offset],
    [0, guide_offset]
  ]);
}

module hm43_bottom_lips(split) {
  translate([wall, wall, split+wall_t]) {
    // bottom locklip (postive)
    translate([0,d,0]) {
      locklip_p(28);
      translate([w-34,0,0]) locklip_p(34-wall+1);
    }

    // front guide lip
    translate([w/2-9, 0, 0])
      rotate([0,90]) lip_guide(30);
    // left guide lip assortment
    translate([0, 5.25+9.4/2, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(25.25-5.25-9.4/2-16.7/2);
    *translate([-pic_ex, 52, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
    *translate([-pic_ex, 70, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
  }
  // probe side guide lip
  translate([wall, wall, probe_centerline+wall_t])
    translate([w, d-45, 0])
      rotate([-90]) rotate(90) lip_guide(40);
}

module split_volume() {
  if (Pi_Model == "3B/2B/1B+") {
    difference() {
      translate([-pic_ex-e,-e,-e])
        cube([w+pic_ex+2*wall+2*e, d+2*wall+2*e, wall_t+case_split+2*e]);
      translate([w,0,wall_t+probe_centerline])
        cube([3*wall, d+2*wall+2*e, wall_t+probe_centerline+2*e]);
    }
  }
  else
    translate([-w,-d,-e])
      cube([3*w, 3*d, wall_t+probe_centerline+2*e]);
}

module hm43_split() {
  // bottom
  if (Pieces != "Top") {
    intersection() {
      hm43();
      split_volume();
    }
    if (Pi_Model == "3B/2B/1B+")
      hm43_bottom_lips(case_split);
    else
      hm43_bottom_lips(probe_centerline);
  } // if include bottom

  // top
  if (Pieces != "Bottom") {
    translate([0,-2,h_b+2*wall_t]) rotate([180]) difference() {
      hm43();
      split_volume();
    }
  }  // if include top
}

/**********************                               **********************/
/********************** END OF CASE / LIBRARY FOLLOWS **********************/
/**********************                               **********************/

module cube_bchamfer(dim, r, top=0, bottom=0, $fn=$fn) {
  // bottom beaded area
  if (bottom != 0) hull(){
    translate([r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
  }
  // center
  translate([0,0,bottom]) hull(){
    translate([r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
  }
  // top beaded area
  if (top != 0) translate([0,0,dim[2]-top]) hull(){
    translate([r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
  }
}

module fillet(radius, height=100, $fn=$fn) {
  if (radius > 0) {
    //this creates acutal fillet
    translate([-radius, -radius, -height / 2 - 0.02]) difference() {
        cube([radius * 2, radius * 2, height + 0.04]);
        if ($fn == 0 && (radius == 2 || radius == 3 || radius == 4)) {
            cylinder(r=radius, h=height + 0.04, $fn=4 * radius);
        } else {
            cylinder(r=radius, h=height + 0.04, $fn=$fn);
        }

    }
  }
}

module cube_fillet(size, radius=-1, vertical=[0,0,0,0], top=[0,0,0,0], bottom=[0,0,0,0], center=false, $fn=4){
    if (center) {
        cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    } else {
        translate([size[0]/2, size[1]/2, size[2]/2])
            cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    }
}

module cube_negative_fillet(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    j=[1,0,1,0];

    for (i=[0:3]) {
        if (radius > -1) {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(radius, size[2], $fn);
        } else {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(vertical[i], size[2], $fn);
        }
        rotate([90*i, -90, 0]) translate([size[2]/2, size[j[i]]/2, 0 ]) fillet(top[i], size[1-j[i]], $fn);
        rotate([90*(4-i), 90, 0]) translate([size[2]/2, size[j[i]]/2, 0]) fillet(bottom[i], size[1-j[i]], $fn);

    }
}

module cube_fillet_inside(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    //makes CENTERED cube with round corners
    // if you give it radius, it will fillet vertical corners.
    //othervise use vertical, top, bottom arrays
    //when viewed from top, it starts in upper right corner (+x,+y quadrant) , goes counterclockwise
    //top/bottom fillet starts in direction of Y axis and goes CCW too

    if (radius == 0) {
        cube(size, center=true);
    } else {
        difference() {
            cube(size, center=true);
            cube_negative_fillet(size, radius, vertical, top, bottom, $fn);
        }
    }
}

//cube_fillet([10,10,10]);

// preview[view:northeast, tilt:topdiagonal]

/* [Options] */
// Pit probe type
Control_Probe = "Thermocouple"; // [Thermocouple,Thermistor]
// Raspberry Pi Model
Pi_Model = "3B/2B/1B+"; // [3B/2B/1B+,Connectorless,1A+,Zero]
// Which case halves
Pieces = "Both"; // [Both,Top,Bottom]
// Corner ear height
MouseEarHeight = 0.0;

/* [Hidden] */
function inch(x) = x*25.4;

w = inch(3.75)+0.5; // overall interior case width
d = inch(3.75)-0.5; // overall interior case depth
h_b = 32; // overall interior case height

probe_centerline = 9.0; // case is split along probe centerline on the probe side
case_split = 12.4;  // and the case split on the other 3 sides

pic_ex = 2;
lcd_mount_t = 7;

wall = 2.0*1.41; // thickness of side walls (*1.41 so rounded corners are this width)
wall_t = 2; // thickness of top and bottom walls
e = 0.01;

echo("WALL is ", wall);
hm43_split();

module cube_fillet_chamfer(size,f,c,$fn=32) {
  hull() {
    translate([f,f,c]) linear_extrude(height=size[2]-2*c) minkowski() {
      square([size[0]-2*f, size[1]-2*f]);
      circle(r=f, $fn=$fn);
    }
    translate([f+c,f+c,0]) linear_extrude(height=size[2]) minkowski() {
      square([size[0]-2*(f+c), size[1]-2*(f+c)]);
      circle(r=f, $fn=$fn);
    }
  }
}

module jhole(d, h) {
  translate([0,0,h/2]) cube([2*(wall+pic_ex),d,h], center=true);
}

module phole() {
  dia=4.5;
  // Hole for thermistor probe jack
  rotate([0,90,0]) cylinder(2*wall, d=dia, $fn=16);
  // because 3d print tends to curl up slightly between the probe holes,
  // do not go right to the edge on the final layer (stop 0.25mm short on each side)
  translate([0,-(dia+0.5)/2, -0.3]) cube([2*wall, dia+0.5, 0.6]);
}

module screwhole() {
  // Screw hole for bottom of case (including nut)
  //translate([0,0,-e]) cylinder(h_b+wall_t, d=3.4, $fn=18);
  translate([0,0,-e]) {
    cylinder(0.4, d1=7.4, d2=6.6, $fn=6);
    translate([0,0,0.4]) cylinder(3, d=6.6, $fn=6);
  }
  translate([0,0,3+0.2]) cylinder(h_b+2*wall_t, d=3.4, $fn=18);
  translate([0,0,h_b+wall_t]) cylinder(3, d=5.5, $fn=18);
}

module screwhole2() {
  translate([0,0,-e]) cylinder(3, d=6, $fn=18);
  translate([0,0,3+0.4]) cylinder(h_b-3-0.4, d=3.4, $fn=18);
}

module pic_ex_cube() {
  translate([0,33.75,2])
    cube_fillet([pic_ex+e, 59.5, 20.8],
      vertical=[0, pic_ex, pic_ex, 0],
      top=[0,pic_ex,0,0],
      bottom=[0,pic_ex,0,0]);
}

module screw_pimount() {
  // 2mm height is good for screw holes
  difference() {
    cylinder(h=2.25, d=6.4, $fn=18);
    //cylinder(h=2+e, d=2.5, $fn=16);
  }
}

module btn_rnd(dia=10) {
  cylinder(wall_t+2*e, d1=dia, d2=dia+1.5*wall_t, $fn=24);
  translate([-6.5,-6.5,0]) cube([13,13,0.75+e]);
}

module btn_square(sq=13) {
  translate([-sq/2,-sq/2,0]) cube([sq,sq,wall_t+2*e]);
}

module tc_plusminus() {
  T=0.75+e;
  H=2;
  W=6;
  // Minus
  translate([0,2,0])
    cube_fillet([T, W, H], top=[0,0,0,T]);
  translate([0,-(2+W),0]) {
    cube_fillet([T, W, H], top=[0,0,0,T]);
    translate([0,(W-H)/2,(H-W)/2])
      cube_fillet([T, H, W], top=[0,0,0,T]);
  }
}

module led_hole() {
  cylinder(wall_t+2*e, d=3.4, $fn=16);
}

module nuttrap() {
  ww_w=3;
  ww_d=2.7;
  nut_h=2.8;
  nut_ingress = 5.8; //nut_d * sin(60);
  nut_d = nut_ingress / sin(60);
  oa_h=wall_t+0.4+nut_h+wall_t+6.7;

  // bottom half for M3 socket cap screw (flush)
  difference() {
    translate([-5.5/2-ww_w, -nut_ingress/2-e, 0])
      cube_fillet([5.5+2*ww_w, nut_ingress+ww_d*0.8+e, 6], vertical=[3.4,3.4], $fn=20);
    // socket cap
    translate([0,0,-e]) cylinder(3.5, d=6, $fn=18);
    // screw shaft
    translate([0,0,3.5+0.3]) cylinder(oa_h-3, d=3.4, $fn=18);
  }

  // top half M3 nut trap
  translate([0,0,h_b+wall_t-oa_h])
  difference() {
    translate([-(nut_d/2+ww_w), -nut_ingress/2-e, 0])
      cube_fillet([nut_d+2*ww_w, nut_ingress+ww_d+e, oa_h],
        vertical=[3.4,3.4], $fn=20);
    // M3 screw
    translate([0,0,-e]) cylinder(wall_t, d1=4, d2=3.4, $fn=16);
    // nut hole / M3 extra
    translate([0,0,wall_t+0.3]) {
      translate([-0.4,0,0]) // nut offset slightly deeper for easier alignment
        cylinder(nut_h*1.5+e, d=nut_d, $fn=6);  // nut
      cylinder(oa_h-wall_t-0.3, d=4, $fn=16);  // M3 with plenty of clearance
    }
    // nut ingress
    translate([0,-nut_ingress/2,wall_t+0.3])
      cube([nut_d/2+ww_w+e,nut_ingress,nut_h+e]);
  }
}

module locklip_p(l, l_offset=1,
  lip_insert_depth=2.0, // how deep V to insert
  lip_v_off=0.2, // extra height before starting insert
  lip_h_off=0.4, // back connector away from mating area
  lip_w=1.5  // thickness of attachment beam
  ) {
  translate([l_offset,0,0]) rotate([90,0,0]) rotate([0,90,0])
    linear_extrude(height=l-2*l_offset) polygon(points=[
      [0, -lip_w-lip_insert_depth-lip_h_off],
      [0, 0],
      [-lip_insert_depth-lip_h_off, 0],
      [-lip_insert_depth-lip_h_off, lip_v_off],
      [-lip_h_off, lip_v_off+lip_insert_depth],
      [-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth,],
      [-lip_w-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth],
      [-lip_w-lip_insert_depth-lip_h_off, 0]
    ]);
}

module locklip_n(l, l_offset=1,
  lip_insert_depth=2.2, // how deep V to insert
  lip_tip_clip=0.3, // how much to shave off the top tip
  ) {
  translate([l-l_offset,0,0]) rotate([90,0,0]) rotate([0,-90,0])
    linear_extrude(height=l-2*l_offset) polygon(points=[
      [0.1, -3*lip_insert_depth],  // 0.1 to add depth to keep extrusion manifold
      [0.1, -lip_tip_clip],
      [-lip_insert_depth+lip_tip_clip, -lip_tip_clip],
      [-e, -lip_insert_depth],
      [-lip_insert_depth, -2*lip_insert_depth]
    ]);
}

module lcd_screw() {
  rotate([180]) difference() {
    //cylinder(lcd_mount_t, d=2.5+3.2, $fn=16);
    cylinder(lcd_mount_t+e, d=2.5, $fn=16);
  }
}

module lcd_mount() {
  // Assuming starting at bottom left screw hole
  lcd_screw();
  //translate([75,0,0]) lcd_screw(); // bottom right hole obscured by PCB
  translate([0,31,0]) lcd_screw();
  translate([75,31,0]) lcd_screw();
}

module lcd_neg() {
  // Assuming starting at bottom left screw hole
  translate([1.0, 2.1, 0])
    cube([73.0, 26.3, lcd_mount_t+wall_t-0.8]); // black bezel inset
  translate([5.5, 7.8, 0])
    cube([64.0, 15.4, lcd_mount_t+wall_t+2*e]); // LCD active area
  translate([4.23, -2.5, 0])
    cube([16*2.54, 5, lcd_mount_t+wall_t-0.8]); // pins cutout
}

module mouseears() {
  me_h = MouseEarHeight;
  me_d = 15;
  me_outset_bottom = (me_d/4) - wall/2;
  me_outset_top = (me_d/4) - wall;

  // Bottom corners
  translate([-me_outset_bottom, -me_outset_bottom, 0])
    cylinder(me_h, d1=me_d, d2=me_d-2*me_h, $fn=24);
  translate([w+2*wall+me_outset_bottom, -me_outset_bottom, 0])
    cylinder(me_h, d1=me_d, d2=me_d-2*me_h, $fn=24);
  translate([w+2*wall+me_outset_bottom, d+2*wall+me_outset_bottom, 0])
    cylinder(me_h, d1=me_d, d2=me_d-2*me_h, $fn=24);
  translate([-me_outset_bottom, d+2*wall+me_outset_bottom, 0])
    cylinder(me_h, d1=me_d, d2=me_d-2*me_h, $fn=24);

  // top corners
  translate([0,0,h_b+2*wall_t-me_h]) {
    translate([-me_outset_top, -me_outset_top, 0])
      cylinder(me_h, d2=me_d, d1=me_d-2*me_h, $fn=24);
    translate([w+2*wall+me_outset_top, -me_outset_top, 0])
      cylinder(me_h, d2=me_d, d1=me_d-2*me_h, $fn=24);
    translate([w+2*wall+me_outset_top, d+2*wall+me_outset_top, 0])
      cylinder(me_h, d2=me_d, d1=me_d-2*me_h, $fn=24);
    translate([-me_outset_top, d+2*wall+me_outset_top, 0])
      cylinder(me_h, d2=me_d, d1=me_d-2*me_h, $fn=24);
  }
}

module locklip_top_n(split) {
  translate([wall, d+wall, split+wall_t+e])
    rotate([180]) {
      locklip_n(28);
      translate([w-34,0,0]) locklip_n(34);
    }
}

module hm43() {
difference() {
  union() {
    cube_bchamfer([w+2*wall, d+2*wall, h_b+2*wall_t],
      r=4, top=1.5, bottom=1.5, $fn=36);
    // extra thick by Pi connectors
    if (Pi_Model != "Zero")
      translate([-pic_ex,wall,wall_t])
        pic_ex_cube();
    // TC +/-
    if (Control_Probe == "Thermocouple")
      translate([w+wall*2-e,wall+10,wall_t+18]) tc_plusminus();
    if (MouseEarHeight > 0.0)
      mouseears();
  }

  // Main cutout
  translate([wall, wall, wall_t])
    cube_fillet([w, d, h_b+e], bottom=[2,2,2,2],
    top=[lcd_mount_t,lcd_mount_t,lcd_mount_t,lcd_mount_t]);
  if (Pi_Model != "Zero")
    translate([wall-pic_ex+e,wall,wall_t]) pic_ex_cube();

  // Probe jack side
  translate([w+wall*0.5,wall,wall_t]) {
    // Probe jacks
    translate([0,24.25,probe_centerline]) {
      if (Control_Probe == "Thermocouple")
        // TC jack
        translate([0,inch(-0.55)-16.5/2,-1.4]) cube([2*wall, 16.5, 6.5]);
      else
        translate([0,-17.25,0]) phole();
      translate([0,inch(0.37)*0,0]) phole();
      translate([0,inch(0.37)*1,0]) phole();
      translate([0,inch(0.37)*2,0]) phole();
    }
  }
  // Pi connector side
  translate([wall*-0.5,wall,wall_t]) {
    // Pi connectors
    translate([0,0,5]) {
      if (Pi_Model == "3B/2B/1B+") {
        // ethernet
        translate([0,81.5,-0.5]) jhole(15,13);
        translate([0,81.5,-1.5]) jhole(5,5);
        // USB 0+1
        translate([0,62.75,0]) jhole(13,14.8);
        translate([0,44.75,0]) jhole(13,14.8);
      }
      if (Pi_Model == "1A+")
        translate([0,44.75,0]) jhole(13,7.4);
    }
    // HeaterMeter connectors
    translate([0,0,0]) {
      // Blower/Servo output
      translate([0,25.25,1.1]) jhole(16.7,13);
      // HM power jack
      translate([0,5.25,3.4]) jhole(9.4,11);
    }
  }

  // lcd hole
  translate([wall+10.7, wall+52, h_b+wall_t-lcd_mount_t-e]) lcd_neg();

  // button holes
  translate([wall+48.7, wall+29.4, h_b+wall_t-e]) {
    translate([-inch(1.1)/2,0,0]) btn_rnd(7.2);  // left
    translate([inch(1.1)/2,0,0]) btn_rnd(7.2);   // right
    translate([0,inch(0.9)/2,0]) btn_rnd(7.2);   // up
    translate([0,-inch(0.9)/2,0]) btn_rnd(7.2);  // down
    // LED holes
    translate([inch(1.3), inch(-0.05), 0]) {
      led_hole();  //red
      translate([0, inch(0.35), 0]) led_hole(); //yellow
      translate([0, inch(0.70), 0]) led_hole(); //green
    }
  }
  // close screw holes
  translate([wall+inch(0.8)+1.3,wall+2.9,0]) {
    screwhole2();
    translate([inch(2.0),0,0]) screwhole2();
  }
}  // END OF DIFFERENCE

  // Pi mounting screws
  translate([wall+24,wall+d-7,wall_t]) {
    //screw_pimount();
    translate([58,0,0]) screw_pimount();
    translate([58,-49,0]) screw_pimount();
    translate([0,-49,0]) screw_pimount();
    translate([0,0,0]) screw_pimount();
  }
  // Pi right edge stop
  translate([wall+w-10, wall+d-60, wall_t]) {
    difference() {
      cube_fillet([10,60,4], vertical=[0,0,10/2], $fn=24);
      // Pi B+ microsd gap
      translate([-e,22.5,-e]) cube_fillet([6,14,4+2*e], vertical=[2,0,0,2], $fn=20);
    }
  }

  // close nut traps
  translate([wall+inch(0.8)+1.3,wall+2.9,0]) {
    nuttrap();
    translate([inch(2.0),0,0]) nuttrap();
  }

  // Top locklip (negative)
  if (Pi_Model == "3B/2B/1B+")
    locklip_top_n(case_split);
  else
    locklip_top_n(probe_centerline);

  // LCD mount
  difference() {
    union() {
      // Filled block above LCD hole
      translate([wall, wall+d-16, h_b+wall_t-lcd_mount_t]) cube([w,16,lcd_mount_t+e]);
      // LCD grab notch
      translate([wall+10.7, wall+52, h_b+wall_t-lcd_mount_t])
        translate([(77.5-20)/2,33.5-wall_t,-(1.8+wall_t)])
          // 1.8=thickness of LCD pcb
          cube_fillet([20,1.8+wall_t+wall,1.8+wall_t+e], top=[0,0,1.8+wall_t+e],
            vertical=[wall/2,wall/2]);
    }
    translate([wall+10.7, wall+52, h_b+wall_t-lcd_mount_t-e]) lcd_neg();
    translate([wall+10.7, wall+52, h_b+wall_t-e]) lcd_mount();
  }

  if (Pi_Model == "3B/2B/1B+" || Pi_Model == "1A+")
    translate([wall-pic_ex, wall, wall_t]) {
      // USB pillar reinforcements
      translate([0, (44.75+62.75)/2-1, 0]) cube([pic_ex+1, 2, h_b]);
      translate([0, 81.5-15/2-3, 0]) cube([pic_ex+1, 2.5, h_b]);
      // Near pic_ex fill
      translate([0, 33.75, 0]) cube([pic_ex, 3, h_b]);
      // Far pic_ex fill (near ethernet)
      translate([0, (33.75+59.5)-3, 0]) cube([pic_ex+1, 3, h_b]);
    }
}

module lip_guide(l) {
  guide_offset = 0.2; // how much to recess the edge guides
  guide_h = 1.2; // how tall above the edge to extend
  linear_extrude(height=l) polygon([
    [0,-e], [wall+guide_offset,-e], [0, wall+guide_offset],
    [-guide_h, wall+guide_offset], [-guide_h, guide_offset],
    [0, guide_offset]
  ]);
}

module hm43_bottom_lips(split) {
  translate([wall, wall, split+wall_t]) {
    // bottom locklip (postive)
    translate([0,d,0]) {
      locklip_p(28);
      translate([w-34,0,0]) locklip_p(34-wall+1);
    }

    // front guide lip
    translate([w/2-9, 0, 0])
      rotate([0,90]) lip_guide(30);
    // left guide lip assortment
    translate([0, 5.25+9.4/2, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(25.25-5.25-9.4/2-16.7/2);
    *translate([-pic_ex, 52, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
    *translate([-pic_ex, 70, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
  }
  // probe side guide lip
  translate([wall, wall, probe_centerline+wall_t])
    translate([w, d-45, 0])
      rotate([-90]) rotate(90) lip_guide(40);
}

module split_volume() {
  if (Pi_Model == "3B/2B/1B+") {
    difference() {
      translate([-pic_ex-e,-e,-e])
        cube([w+pic_ex+2*wall+2*e, d+2*wall+2*e, wall_t+case_split+2*e]);
      translate([w,0,wall_t+probe_centerline])
        cube([3*wall, d+2*wall+2*e, wall_t+probe_centerline+2*e]);
    }
  }
  else
    translate([-w,-d,-e])
      cube([3*w, 3*d, wall_t+probe_centerline+2*e]);
}

module hm43_split() {
  // bottom
  if (Pieces != "Top") {
    intersection() {
      hm43();
      split_volume();
    }
    if (Pi_Model == "3B/2B/1B+")
      hm43_bottom_lips(case_split);
    else
      hm43_bottom_lips(probe_centerline);
  } // if include bottom

  // top
  if (Pieces != "Bottom") {
    translate([0,-2,h_b+2*wall_t]) rotate([180]) difference() {
      hm43();
      split_volume();
    }
  }  // if include top
}

/**********************                               **********************/
/********************** END OF CASE / LIBRARY FOLLOWS **********************/
/**********************                               **********************/

module cube_bchamfer(dim, r, top=0, bottom=0, $fn=$fn) {
  // bottom beaded area
  if (bottom != 0) hull(){
    translate([r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
  }
  // center
  translate([0,0,bottom]) hull(){
    translate([r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
  }
  // top beaded area
  if (top != 0) translate([0,0,dim[2]-top]) hull(){
    translate([r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
  }
}

module fillet(radius, height=100, $fn=$fn) {
  if (radius > 0) {
    //this creates acutal fillet
    translate([-radius, -radius, -height / 2 - 0.02]) difference() {
        cube([radius * 2, radius * 2, height + 0.04]);
        if ($fn == 0 && (radius == 2 || radius == 3 || radius == 4)) {
            cylinder(r=radius, h=height + 0.04, $fn=4 * radius);
        } else {
            cylinder(r=radius, h=height + 0.04, $fn=$fn);
        }

    }
  }
}

module cube_fillet(size, radius=-1, vertical=[0,0,0,0], top=[0,0,0,0], bottom=[0,0,0,0], center=false, $fn=4){
    if (center) {
        cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    } else {
        translate([size[0]/2, size[1]/2, size[2]/2])
            cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    }
}

module cube_negative_fillet(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    j=[1,0,1,0];

    for (i=[0:3]) {
        if (radius > -1) {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(radius, size[2], $fn);
        } else {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(vertical[i], size[2], $fn);
        }
        rotate([90*i, -90, 0]) translate([size[2]/2, size[j[i]]/2, 0 ]) fillet(top[i], size[1-j[i]], $fn);
        rotate([90*(4-i), 90, 0]) translate([size[2]/2, size[j[i]]/2, 0]) fillet(bottom[i], size[1-j[i]], $fn);

    }
}

module cube_fillet_inside(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    //makes CENTERED cube with round corners
    // if you give it radius, it will fillet vertical corners.
    //othervise use vertical, top, bottom arrays
    //when viewed from top, it starts in upper right corner (+x,+y quadrant) , goes counterclockwise
    //top/bottom fillet starts in direction of Y axis and goes CCW too

    if (radius == 0) {
        cube(size, center=true);
    } else {
        difference() {
            cube(size, center=true);
            cube_negative_fillet(size, radius, vertical, top, bottom, $fn);
        }
    }
}

//cube_fillet([10,10,10]);


yaxis/idler: tweaks to pulley block

yaxis/idler: tweaks to pulley block

use <thing_libutils/triangles.scad>
include <thing_libutils/attach.scad>
include <config.scad>
include <pulley.scad>

yaxis_idler_conn = [[-extrusion_size/2, 0, 0], [-1,0,0]];

yidler_w = yaxis_pulley_d;
yaxis_idler_mount_thread_dia = lookup(ThreadSize, extrusion_thread);

yaxis_idler_mount_tightscrew_dia = lookup(ThreadSize, ThreadM4);
yaxis_idler_mount_tightscrew_hexnut_dia = lookup(MHexNutWidthMax, MHexNutM4);
yaxis_idler_mount_tightscrew_hexnut_thick = lookup(MHexNutThickness, MHexNutM4);

yidler_mount_width = yidler_w+yaxis_idler_mount_thickness*2 + yaxis_idler_mount_thread_dia*3.5*2;

module yaxis_idler()
{
    difference()
    {
        // top plate
        union()
        {
            // top mount plate
            difference()
            {
                tighten_screw_dia_outer = yaxis_idler_mount_tightscrew_dia*4;
                mount_screw_dist = (yidler_w/2+yaxis_idler_mount_thread_dia*3)*2;
                union()
                {
                    translate([0,0,extrusion_size/2])
                    {
                        cubea(
                                size=[extrusion_size+yaxis_idler_mount_thickness*2, yidler_mount_width, yaxis_idler_mount_thickness],
                                align=[0,0,1]);
                    }

                    hull()
                    {
                        translate([0,0,extrusion_size/2])
                        {
                            translate([0,0,yaxis_belt_path_offset_z])
                            fncylindera(
                                    h=extrusion_size+yaxis_idler_mount_thickness*2,
                                    d=tighten_screw_dia_outer,
                                    align=[0,0,0],
                                    orient=[1,0,0]
                                    );
                            cubea(
                                    size=[extrusion_size+yaxis_idler_mount_thickness*2, mount_screw_dist-yaxis_idler_mount_tightscrew_dia*3, yaxis_idler_mount_thickness],
                                    align=[0,0,1]);
                        }
                    }
                }

                translate([0,0,extrusion_size/2])
                {
                    for(i=[-1,1])
                        translate([0, i*mount_screw_dist/2, 0])
                            fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia, orient=[0,0,1]);

                    // cutout tighten screw
                    translate([0,0,yaxis_belt_path_offset_z])
                    fncylindera(h=extrusion_size+yaxis_idler_mount_thickness*2+1, d=yaxis_idler_mount_tightscrew_dia, orient=[1,0,0], align=[0,0,0]);

                    // cutout tighten screw
                    translate([-extrusion_size/2-yaxis_idler_mount_thickness-.1,0,yaxis_belt_path_offset_z])
                    fncylindera(h=extrusion_size,d=yaxis_idler_mount_tightscrew_dia*2, orient=[1,0,0], align=[1,0,0]);
                }

                translate([0,0,extrusion_size/2])
                cubea(size=[extrusion_size+1, yidler_mount_width, tighten_screw_dia_outer/2],
                        extrasize=[yaxis_idler_mount_thickness,0,0],
                        extrasize_align=[1,0,0],
                        align=[-1,0,-1]);
            }

            translate([-extrusion_size/2,0,0])
            difference()
            {
                cubea([yaxis_idler_mount_thickness, yidler_mount_width, extrusion_size], align=[-1,0,0]);

                for(i=[-1,1])
                    translate([0, i*(yidler_w/2+yaxis_idler_mount_thread_dia*3), 0])
                        fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia, orient=[1,0,0]);
            }

            /*difference()*/
            /*{*/
                /*cubea([yaxis_idler_mount_thickness, yidler_mount_width, extrusion_size], align=[1,0,0]);*/

                /*for(i=[-1,1])*/
                    /*translate([0, i*(yidler_w/2+yaxis_idler_mount_thread_dia*3), 0])*/
                        /*fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia, orient=[1,0,0]);*/
            /*}*/

            /*// bottom mount plate*/
            /*translate([0,0,-main_lower_dist_z])*/
            /*{*/
                /*difference()*/
                /*{*/
                    /*cubea([yaxis_idler_mount_thickness, yidler_w, extrusion_size], align=[1,0,0]);*/

                    /*for(i=[0])*/
                        /*translate([0, i*(yidler_w/2+yaxis_idler_mount_thread_dia*3), 0])*/
                            /*fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia,align=[0,0,0], orient=[1,0,0]);*/
                /*}*/
            /*}*/

        }

    }
}

yaxis_idler_pulley_thread = ThreadM5;
yaxis_idler_pulley_thread_dia = lookup(ThreadSize, yaxis_idler_pulley_thread);
yaxis_idler_pulleyblock_supportsize = yaxis_pulley_d*1.2;
yaxis_idler_pulleyblock_wallthick = 5*mm;
yaxis_idler_pulleyblock_lenfrompulley = yaxis_idler_pulleyblock_supportsize/2 + yaxis_idler_pulley_tight_len;

module yaxis_idler_pulleyblock(show_pulley=false)
{
    if(show_pulley)
    {
        %pulley_idler_2GT2_20T();
    }

    h = yaxis_idler_pulley_h + 3*mm*2;
    difference()
    {
        hull()
        {
            /*fncylindera(d=yaxis_pulley_d*1.5, h=h, orient=[0,0,1], align=[0,0,0]);*/
            cubea([yaxis_idler_pulleyblock_supportsize, yaxis_idler_pulleyblock_supportsize, h],
                    align=[0,0,0],
                    extrasize=[yaxis_idler_pulley_tight_len,0,0],
                    extrasize_align=[-1,0,0]
                 );
            /*translate([-yaxis_idler_pulley_tight_len,0,0])*/
                /*cubea([yaxis_pulley_d, yaxis_pulley_d*1.5, h]);*/
        }

        // pulley cutout
        translate([-3*mm,0,0])
            cubea(
                    size=[yaxis_pulley_d, yaxis_pulley_d*3, yaxis_idler_pulley_h+0.5],
                    align=[0,0,0],
                    extrasize=[20*mm,0,0], extrasize_align=[1,0,0]
                 );

        // pulley screw
        translate([0,0,yaxis_idler_pulley_h/2+1])
        {
            fncylindera(d=yaxis_idler_pulley_thread_dia, h=h*2, orient=[0,0,1], align=[0,0,0]);
        }

        fncylindera(d=yaxis_idler_pulley_thread_dia, h=h*2, orient=[0,0,1], align=[0,0,0]);

        translate([-15*mm+yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len-.1, 0, 0])
        {
            fncylindera(fn=6, d=yaxis_idler_mount_tightscrew_hexnut_dia*1.01, h=yaxis_idler_pulley_tight_len+.1, orient=[1,0,0], align=[1,0,0]);

            translate([yaxis_idler_mount_tightscrew_hexnut_thick,0,0])
            fncylindera(d=yaxis_idler_mount_tightscrew_hexnut_dia*1.2, h=yaxis_idler_pulley_tight_len+.1, orient=[1,0,0], align=[1,0,0]);
        }

        fncylindera(d=yaxis_idler_mount_tightscrew_dia, h=yaxis_idler_pulleyblock_lenfrompulley+.1, orient=[1,0,0], align=[-1,0,0]);
    }

}

// the pulley block mounting point (mounting point in pulley block frame)
yaxis_idler_pulleyblock_conn = [[-yaxis_idler_pulleyblock_lenfrompulley, 0, 0], [-1,0,0]];

yaxis_idler_pulleyblock_conn_print = [[-yaxis_idler_pulleyblock_lenfrompulley, yaxis_idler_pulleyblock_supportsize/2, 0], [0,1,0]];

// the idler pulley block mounting point (mounting point in idler frame)
yaxis_idler_conn_pulleyblock = [[extrusion_size/2+yaxis_idler_mount_thickness, 0, extrusion_size/2+yaxis_belt_path_offset_z], [1,0,0]];

module print_yaxis_idler()
{
    attach([[0,0,0], [0,0,-1]], yaxis_idler_conn)
    {
        yaxis_idler();
    }
}

module print_yaxis_idler_pulleyblock()
{
    attach([[0,0,0], [0,0,-1]], yaxis_idler_pulleyblock_conn_print)
    {
        yaxis_idler_pulleyblock(show_pulley=false);
    }
}

/*print_yaxis_idler();*/
/*yaxis_idler();*/
/*print_yaxis_idler_pulleyblock();*/
/*yaxis_idler_pulleyblock();*/

/*attach([[0,0,0],[-1,0,0]], yaxis_idler_conn)*/
/*{*/
    /*yaxis_idler();*/
    /*attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)*/
    /*{*/
        /*yaxis_idler_pulleyblock(show_pulley=true);*/
    /*}*/
/*}*/

use <thing_libutils/triangles.scad>
include <thing_libutils/attach.scad>
include <config.scad>
include <pulley.scad>

yaxis_idler_conn = [[-extrusion_size/2, 0, 0], [-1,0,0]];

yidler_w = yaxis_pulley_d;
yaxis_idler_mount_thread_dia = lookup(ThreadSize, extrusion_thread);

yaxis_idler_mount_tightscrew_dia = lookup(ThreadSize, ThreadM4);
yaxis_idler_mount_tightscrew_hexnut_dia = lookup(MHexNutWidthMax, MHexNutM4);
yaxis_idler_mount_tightscrew_hexnut_thick = lookup(MHexNutThickness, MHexNutM4);

yidler_mount_width = yidler_w+yaxis_idler_mount_thickness*2 + yaxis_idler_mount_thread_dia*3.5*2;

module yaxis_idler()
{
    difference()
    {
        // top plate
        union()
        {
            // top mount plate
            difference()
            {
                tighten_screw_dia_outer = yaxis_idler_mount_tightscrew_dia*4;
                mount_screw_dist = (yidler_w/2+yaxis_idler_mount_thread_dia*3)*2;
                union()
                {
                    translate([0,0,extrusion_size/2])
                    {
                        cubea(
                                size=[extrusion_size+yaxis_idler_mount_thickness*2, yidler_mount_width, yaxis_idler_mount_thickness],
                                align=[0,0,1]);
                    }

                    hull()
                    {
                        translate([0,0,extrusion_size/2])
                        {
                            translate([0,0,yaxis_belt_path_offset_z])
                            fncylindera(
                                    h=extrusion_size+yaxis_idler_mount_thickness*2,
                                    d=tighten_screw_dia_outer,
                                    align=[0,0,0],
                                    orient=[1,0,0]
                                    );
                            cubea(
                                    size=[extrusion_size+yaxis_idler_mount_thickness*2, mount_screw_dist-yaxis_idler_mount_tightscrew_dia*3, yaxis_idler_mount_thickness],
                                    align=[0,0,1]);
                        }
                    }
                }

                translate([0,0,extrusion_size/2])
                {
                    for(i=[-1,1])
                        translate([0, i*mount_screw_dist/2, 0])
                            fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia, orient=[0,0,1]);

                    // cutout tighten screw
                    translate([0,0,yaxis_belt_path_offset_z])
                    fncylindera(h=extrusion_size+yaxis_idler_mount_thickness*2+1, d=yaxis_idler_mount_tightscrew_dia, orient=[1,0,0], align=[0,0,0]);

                    // cutout tighten screw
                    translate([-extrusion_size/2-yaxis_idler_mount_thickness-.1,0,yaxis_belt_path_offset_z])
                    fncylindera(h=extrusion_size,d=yaxis_idler_mount_tightscrew_dia*2, orient=[1,0,0], align=[1,0,0]);
                }

                translate([0,0,extrusion_size/2])
                cubea(size=[extrusion_size+1, yidler_mount_width, tighten_screw_dia_outer/2],
                        extrasize=[yaxis_idler_mount_thickness,0,0],
                        extrasize_align=[1,0,0],
                        align=[-1,0,-1]);
            }

            translate([-extrusion_size/2,0,0])
            difference()
            {
                cubea([yaxis_idler_mount_thickness, yidler_mount_width, extrusion_size], align=[-1,0,0]);

                for(i=[-1,1])
                    translate([0, i*(yidler_w/2+yaxis_idler_mount_thread_dia*3), 0])
                        fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia, orient=[1,0,0]);
            }

            /*difference()*/
            /*{*/
                /*cubea([yaxis_idler_mount_thickness, yidler_mount_width, extrusion_size], align=[1,0,0]);*/

                /*for(i=[-1,1])*/
                    /*translate([0, i*(yidler_w/2+yaxis_idler_mount_thread_dia*3), 0])*/
                        /*fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia, orient=[1,0,0]);*/
            /*}*/

            /*// bottom mount plate*/
            /*translate([0,0,-main_lower_dist_z])*/
            /*{*/
                /*difference()*/
                /*{*/
                    /*cubea([yaxis_idler_mount_thickness, yidler_w, extrusion_size], align=[1,0,0]);*/

                    /*for(i=[0])*/
                        /*translate([0, i*(yidler_w/2+yaxis_idler_mount_thread_dia*3), 0])*/
                            /*fncylindera(h=yaxis_idler_mount_thickness*3,d=yaxis_idler_mount_thread_dia,align=[0,0,0], orient=[1,0,0]);*/
                /*}*/
            /*}*/

        }

    }
}

yaxis_idler_pulley_thread = ThreadM5;
yaxis_idler_pulley_thread_dia = lookup(ThreadSize, yaxis_idler_pulley_thread);
yaxis_idler_pulleyblock_supportsize = yaxis_pulley_d*1.2;
yaxis_idler_pulleyblock_wallthick = 5*mm;
yaxis_idler_pulleyblock_lenfrompulley = yaxis_idler_pulleyblock_supportsize/2 + yaxis_idler_pulley_tight_len;

module yaxis_idler_pulleyblock(show_pulley=false)
{
    if(show_pulley)
    {
        %pulley_idler_2GT2_20T();
    }

    h = yaxis_idler_pulley_h + 3*mm*2;
    difference()
    {
        hull()
        {
            /*fncylindera(d=yaxis_pulley_d*1.5, h=h, orient=[0,0,1], align=[0,0,0]);*/
            cubea([yaxis_idler_pulleyblock_supportsize, yaxis_idler_pulleyblock_supportsize, h],
                    align=[0,0,0],
                    extrasize=[yaxis_idler_pulley_tight_len,0,0],
                    extrasize_align=[-1,0,0]
                 );
            /*translate([-yaxis_idler_pulley_tight_len,0,0])*/
                /*cubea([yaxis_pulley_d, yaxis_pulley_d*1.5, h]);*/
        }

        // pulley cutout
        translate([-3*mm,0,0])
            cubea(
                    size=[yaxis_pulley_d, yaxis_pulley_d*3, yaxis_idler_pulley_h+0.5],
                    align=[0,0,0],
                    extrasize=[20*mm,0,0], extrasize_align=[1,0,0]
                 );

        // pulley screw
        translate([0,0,yaxis_idler_pulley_h/2+1])
        {
            fncylindera(d=yaxis_idler_pulley_thread_dia, h=h*2, orient=[0,0,1], align=[0,0,0]);
        }

        fncylindera(d=yaxis_idler_pulley_thread_dia, h=h*2, orient=[0,0,1], align=[0,0,0]);

        translate([8*mm-yaxis_idler_pulleyblock_supportsize/2-yaxis_idler_pulley_tight_len-.1, 0, 0])
        {
            fncylindera(fn=6, d=yaxis_idler_mount_tightscrew_hexnut_dia*1.01, h=yaxis_idler_pulley_tight_len+.1, orient=[1,0,0], align=[1,0,0]);

            fncylindera(d=yaxis_idler_mount_tightscrew_hexnut_dia*1.2, h=yaxis_idler_pulley_tight_len+.1, orient=[1,0,0], align=[1,0,0]);
        }

        fncylindera(d=yaxis_idler_mount_tightscrew_dia, h=yaxis_idler_pulleyblock_lenfrompulley+.1, orient=[1,0,0], align=[-1,0,0]);
    }

}

// the pulley block mounting point (mounting point in pulley block frame)
yaxis_idler_pulleyblock_conn = [[-yaxis_idler_pulleyblock_lenfrompulley, 0, 0], [-1,0,0]];

yaxis_idler_pulleyblock_conn_print = [[-yaxis_idler_pulleyblock_lenfrompulley, yaxis_idler_pulleyblock_supportsize/2, 0], [0,1,0]];

// the idler pulley block mounting point (mounting point in idler frame)
yaxis_idler_conn_pulleyblock = [[extrusion_size/2+yaxis_idler_mount_thickness, 0, extrusion_size/2+yaxis_belt_path_offset_z], [1,0,0]];

module print_yaxis_idler()
{
    attach([[0,0,0], [0,0,-1]], yaxis_idler_conn)
    {
        yaxis_idler();
    }
}

module print_yaxis_idler_pulleyblock()
{
    attach([[0,0,0], [0,0,-1]], yaxis_idler_pulleyblock_conn_print)
    {
        yaxis_idler_pulleyblock(show_pulley=false);
    }
}

/*print_yaxis_idler();*/
/*yaxis_idler();*/
/*print_yaxis_idler_pulleyblock();*/
/*yaxis_idler_pulleyblock();*/

/*attach([[0,0,0],[-1,0,0]], yaxis_idler_conn)*/
/*{*/
    /*yaxis_idler();*/
    /*attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)*/
    /*{*/
        /*yaxis_idler_pulleyblock(show_pulley=true);*/
    /*}*/
/*}*/


Fix typo

Fix typo

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2017 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Build box visualization.
 *
 * @package shape/context
 * @author jsconan
 */

/**
 * Computes the size of the build plate.
 *
 * @param Number|Vector [size] - The size of the build plate.
 * @param Number|Vector [cell] - The size of each cell on the build plate.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [cl] - The length of a cell.
 * @param Number [cw] - The width of cell.
 * @returns Vector - Returns the size vector.
 */
function sizeBuildPlate(size, cell, l, w, cl, cw) =
    let(
        size = apply2D(uor(size, DEFAULT_BUILD_PLATE_SIZE), l, w),
        cell = apply2D(uor(cell, DEFAULT_BUILD_PLATE_CELL), cl, cw),
        nb = [
            cell[0] ? floor(size[0] / cell[0]) : 0,
            cell[1] ? floor(size[1] / cell[1]) : 0
        ],
        count = [
            nb[0] + 1,
            nb[1] + 1
        ],
        offset = [
            cell[0] ? -nb[0] * cell[0] / 2 : 0,
            cell[1] ? -nb[1] * cell[1] / 2 : 0
        ]
    )
    [ size, cell, count, offset ]
;

/**
 * Creates a build plate visualization at the origin.
 *
 * @param Number|Vector [size] - The size of the build plate.
 * @param Number|Vector [cell] - The size of each cell on the build plate.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [cl] - The length of a cell.
 * @param Number [cw] - The width of cell.
 */
module buildPlate(size=DEFAULT_BUILD_PLATE_SIZE, cell=DEFAULT_BUILD_PLATE_CELL, l, w, cl, cw) {
    size = sizeBuildPlate(size=size, cell=cell, l=l, w=w, cl=cl, cw=cw);
    plateSize = size[0];
    cellSize = size[1];
    cellCount = size[2];
    cellOffset = size[3];

    plateHeight = 1;
    lineWidth = .5;

    %color([1, 1, 1, .2]) {
        negativeExtrude(height=-plateHeight, direction=0) {
            rectangle(plateSize);
        }
        negativeExtrude(height=-plateHeight, direction=2) {
            translateX(cellOffset[0]) {
                repeat(count=cellCount[0], intervalX=cellSize[0]) {
                    rectangle([lineWidth, plateSize[1]]);
                }
            }
            translateY(cellOffset[1]) {
                repeat(count=cellCount[1], intervalY=cellSize[1]) {
                    rectangle([plateSize[0], lineWidth]);
                }
            }
        }
    }
}

/**
 * Creates a build volume visualization at the origin.
 *
 * @param Number|Vector [size] - The size of the build box.
 * @param Number|Vector [cell] - The size of each cell on the build plate.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [cl] - The length of a cell.
 * @param Number [cw] - The width of cell.
 */
module buildVolume(size=DEFAULT_BUILD_VOLUME_SIZE, l, w, h) {
    %color([1, 1, 1, .1]) {
        box(size=size, l=l, w=w, h=w);
    }
}

/**
 * Creates a build box visualization at the origin.
 * A build box contains visualizations for a build plate and a build volume.
 * It also applies a render mode.
 * @param String [mode] - The mode to apply on the children modules.
 * @param Number|Vector [size] - The size of the build volume.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 */
module buildBox(size, cell, mode, l, w, h, cl, cw) {
    size = apply3D(uor(size, DEFAULT_BUILD_PLATE_SIZE), l, w, h);

    buildPlate(size=size, cell=cell, l=l, w=w, cl=cl, cw=cw);
    buildVolume(size=size, l=l, w=w, h=h);

    applyMode(mode) {
        children();
    }
}

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2017 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Build box visualization.
 *
 * @package shape/context
 * @author jsconan
 */

/**
 * Computes the size of the build plate.
 *
 * @param Number|Vector [size] - The size of the build plate.
 * @param Number|Vector [cell] - The size of each cell on the build plate.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [cl] - The length of a cell.
 * @param Number [cw] - The width of cell.
 * @returns Vector - Returns the size vector.
 */
function sizeBuildPlate(size, cell, l, w, cl, cw) =
    let(
        size = apply2D(uor(size, DEFAULT_BUILD_PLATE_SIZE), l, w),
        cell = apply2D(uor(cell, DEFAULT_BUILD_PLATE_CELL), cl, cw),
        nb = [
            cell[0] ? floor(size[0] / cell[0]) : 0,
            cell[1] ? floor(size[1] / cell[1]) : 0
        ],
        count = [
            nb[0] + 1,
            nb[1] + 1
        ],
        offset = [
            cell[0] ? -nb[0] * cell[0] / 2 : 0,
            cell[1] ? -nb[1] * cell[1] / 2 : 0
        ]
    )
    [ size, cell, count, offset ]
;

/**
 * Creates a build plate vizualization at the origin.
 *
 * @param Number|Vector [size] - The size of the build plate.
 * @param Number|Vector [cell] - The size of each cell on the build plate.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [cl] - The length of a cell.
 * @param Number [cw] - The width of cell.
 */
module buildPlate(size=DEFAULT_BUILD_PLATE_SIZE, cell=DEFAULT_BUILD_PLATE_CELL, l, w, cl, cw) {
    size = sizeBuildPlate(size=size, cell=cell, l=l, w=w, cl=cl, cw=cw);
    plateSize = size[0];
    cellSize = size[1];
    cellCount = size[2];
    cellOffset = size[3];

    plateHeight = 1;
    lineWidth = .5;

    %color([1, 1, 1, .2]) {
        negativeExtrude(height=-plateHeight, direction=0) {
            rectangle(plateSize);
        }
        negativeExtrude(height=-plateHeight, direction=2) {
            translateX(cellOffset[0]) {
                repeat(count=cellCount[0], intervalX=cellSize[0]) {
                    rectangle([lineWidth, plateSize[1]]);
                }
            }
            translateY(cellOffset[1]) {
                repeat(count=cellCount[1], intervalY=cellSize[1]) {
                    rectangle([plateSize[0], lineWidth]);
                }
            }
        }
    }
}

/**
 * Creates a build volume vizualization at the origin.
 *
 * @param Number|Vector [size] - The size of the build box.
 * @param Number|Vector [cell] - The size of each cell on the build plate.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [cl] - The length of a cell.
 * @param Number [cw] - The width of cell.
 */
module buildVolume(size=DEFAULT_BUILD_VOLUME_SIZE, l, w, h) {
    %color([1, 1, 1, .1]) {
        box(size=size, l=l, w=w, h=w);
    }
}

/**
 * Creates a build box vizualization at the origin.
 * A build box contains vizualizations for a build plate and a build volume.
 * It also applies a render mode.
 * @param String [mode] - The mode to apply on the children modules.
 * @param Number|Vector [size] - The size of the build volume.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 */
module buildBox(size, cell, mode, l, w, h, cl, cw) {
    size = apply3D(uor(size, DEFAULT_BUILD_PLATE_SIZE), l, w, h);

    buildPlate(size=size, cell=cell, l=l, w=w, cl=cl, cw=cw);
    buildVolume(size=size, l=l, w=w, h=h);

    applyMode(mode) {
        children();
    }
}


box draft is ready

box draft is ready