bearing/linear/mount: use 2 zipties even if no clips in bearing

include <units.scad>
include <system.scad>

use <misc.scad>
use <transforms.scad>
use <shapes.scad>
use <screws.scad>
include <bearing-linear-data.scad>
include <thread-data.scad>

module linear_bearing(part, bearing, align=N, orient=Z, offset_flange=false)
{
    model = get(LinearBearingModel, bearing);
    width_x = fallback(get(LinearBearingFlangeCutDiameter, bearing),LinearBearingOuterDiameter);
    width_y = fallback(get(LinearBearingFlangeDiameter, bearing),LinearBearingOuterDiameter);

    clip_dist = get(LinearBearingClipsDistance, bearing);
    clip_groove = get(LinearBearingClipsGrooveDepth, bearing);
    clip_dia = get(LinearBearingClipsDiameter, bearing);

    flange_h = fallback(get(LinearBearingFlangeThickness, bearing),0);

    // for all kinds of flanges
    flange_d = get(LinearBearingFlangeDiameter,bearing);

    // only for square flange
    flange_side = get(LinearBearingFlangeSide,bearing);

    // only for cut flanges
    flange_d_cut = get(LinearBearingFlangeCutDiameter,bearing);

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

    flange_screw_len=12*mm;

    flange_offset = offset_flange ? -flange_h : 0;
    h = get(LinearBearingLength,bearing);
    d = get(LinearBearingInnerDiameter, bearing);
    D = get(LinearBearingOuterDiameter, bearing);
    s = [width_x, width_y, h];
    if(part==U)
    {
        difference()
        {
            linear_bearing(part="pos", bearing=bearing, align=align, orient=orient, offset_flange=offset_flange);
            linear_bearing(part="neg", bearing=bearing, align=align, orient=orient, offset_flange=offset_flange);
        }
        %linear_bearing(part="vit", bearing=bearing, align=align, orient=orient, offset_flange=offset_flange);
    }
    else if(part=="pos")
    size_align(size=s, align=align, orient=orient)
    translate(Z*flange_offset)
    {
        cylindera(h=h, d=D, orient=Z);

        // flange
        translate(-Z*h/2)
        {
            if(flange_side != U)
            {
                // LMK
                intersection()
                {
                    rcubea(size=[flange_side, flange_side, flange_h], orient=Z, align=Z, round_r=1);

                    rcubea(size=[flange_d, flange_d, flange_h], orient=Z, align=Z, round_r=1);
                }
            }
            else if(flange_d != U)
            {
                // LMH
                if(flange_d_cut != U)
                {
                    intersection()
                    {
                        rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                        rcubea(size=[get(LinearBearingFlangeCutDiameter, bearing), flange_d, flange_h], align=Z, round_r=1);
                    }
                }
                // LMF
                else if(flange_d != U)
                {
                    rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                }
            }
        }
    }
    else if(part=="neg")
    size_align(size=s, align=align, orient=orient)
    translate(Z*flange_offset)
    {
        translate(-Z*h/2)
        {
            // inner bore cut
            cylindera(h=h, d=d, orient=Z, align=Z, extra_h=.2);

            // clips
            if(clip_dist != U)
            {
                translate(Z*h/2)
                for(z=[-1,1])
                translate(z*Z*clip_dist/2)
                hollow_cylinder(d=D-clip_groove/2+.01, thickness=clip_groove, h=clip_groove, taper=false, orient=Z, align=-z);
            }

            // flange
            if(flange_side != U)
            {
                // LMK
                // screw cut
                for(x=[-1,1])
                for(y=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d_cut != U)
            {
                // LMH
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*get(LinearBearingFlangeCutMountHoleDist, bearing)/2)
                translate(x*X*get(LinearBearingFlangeCutMountHoleDistSide, bearing)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d != U)
            {
                // LMF
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
        }
    }
}

module linear_bearing_mount(part, bearing, extra_h=0, override_h=U, ziptie_type=[2*mm, 3*mm], ziptie_bearing_distance=3*mm, tolerance=.1*mm, align=N, orient=Z, ziptie_dist=U, with_zips=true, offset_flange=false, mount_dir_align=U, mount_style="open")
{
    assert(mount_dir_align != U, "mount_dir_align == U");

    ziptie_thickness = ziptie_type[0];
    ziptie_width = ziptie_type[1]+0.6*mm;

    clip_groove = get(LinearBearingClipsGrooveDepth, bearing);

    h = fallback(override_h, get(LinearBearingLength,bearing)) + extra_h;
    d = get(LinearBearingInnerDiameter, bearing);
    D = get(LinearBearingOuterDiameter, bearing);

    clip_dist = get(LinearBearingClipsDistance, bearing);
    ziptie_dist_ = v_fallback(ziptie_dist, [clip_dist/2, ziptie_width*2<(h/3+2*mm) ? h / 3 : U]);

    flange_h = fallback(get(LinearBearingFlangeThickness, bearing),0);

    // for all kinds of flanges
    flange_d = get(LinearBearingFlangeDiameter,bearing);

    // only for square flange
    flange_side = get(LinearBearingFlangeSide,bearing);

    // only for cut flanges
    flange_d_cut = get(LinearBearingFlangeCutDiameter,bearing);

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

    flange_screw_len=12*mm;
    flange_offset = offset_flange ? -flange_h : 0;

    support_wall_thickness = 2.5*mm;

    support_D=D+2*support_wall_thickness;
    support_h = h+flange_offset;
    if(part==U)
    {
        difference()
        {
            linear_bearing_mount(part="pos", bearing=bearing, extra_h=extra_h, override_h=override_h, ziptie_type=ziptie_type, ziptie_bearing_distance=ziptie_bearing_distance, tolerance=tolerance, align=align, orient=orient, ziptie_dist=ziptie_dist, with_zips=with_zips, offset_flange=offset_flange, mount_dir_align=mount_dir_align, mount_style=mount_style);
            linear_bearing_mount(part="neg", bearing=bearing, extra_h=extra_h, override_h=override_h, ziptie_type=ziptie_type, ziptie_bearing_distance=ziptie_bearing_distance, tolerance=tolerance, align=align, orient=orient, ziptie_dist=ziptie_dist, with_zips=with_zips, offset_flange=offset_flange, mount_dir_align=mount_dir_align, mount_style=mount_style);
        }
        %linear_bearing_mount(part="vit", bearing=bearing, extra_h=extra_h, override_h=override_h, ziptie_type=ziptie_type, ziptie_bearing_distance=ziptie_bearing_distance, tolerance=tolerance, align=align, orient=orient, ziptie_dist=ziptie_dist, with_zips=with_zips, offset_flange=offset_flange, mount_dir_align=mount_dir_align, mount_style=mount_style);
    }
    else if(part=="pos")
    size_align(size=[D,D,h], align=align, orient=orient)
    {
        translate(-Z*h/2)
        {
            // z axis bearing support
            if(mount_style=="open")
            {
                intersection()
                {
                    rcylindera(h=support_h, d=D, orient=Z, align=Z);
                    rcubea(size=[D,D,support_h], orient=Z, align=Z+mount_dir_align);
                }
            }
            else if(mount_style=="closed")
            {
                rcylindera(h=support_h, d=support_D, orient=Z, align=Z);
            }

            // support for clips
            if(ziptie_dist_ != U)
            {
                translate(Z*h/2)
                for(z=[-1,1])
                translate(z*Z*ziptie_dist_)
                hollow_cylinder(d=D-clip_groove/2+.01, thickness=clip_groove, h=clip_groove, taper=false, orient=Z, align=-z);
            }

            // support for flange mount
            if(flange_side != U)
            {
                // LMK
                // screw cut
                for(x=[-1,1])
                for(y=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                rcylindera(d=1.5*get(LinearBearingFlangeMountingSize,bearing), h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d_cut != U)
            {
                // LMH
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*get(LinearBearingFlangeCutMountHoleDist, bearing)/2)
                translate(x*X*get(LinearBearingFlangeCutMountHoleDistSide, bearing)/2)
                rcylindera(d=1.5*get(LinearBearingFlangeMountingSize,bearing), h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d != U)
            {
                // LMF
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                rcylindera(d=1.5*get(LinearBearingFlangeMountingSize,bearing), h=flange_screw_len, orient=Z, align=Z);
            }
        }
    }
    else if(part=="neg")
    size_align(size=[D,D,h], align=align, orient=orient)
    translate(Z*flange_offset)
    translate(-Z*.001)
    {
        // Main bearing cut
        cylindera(h=h+tolerance, d=D+tolerance, orient=Z);

        if(mount_style=="open")
        {
            orient(-orient)
            rcubea(size=[1000,1000,D+.2*mm], align=mount_dir_align);

            if(with_zips)
            {
                for(z=[-1,1])
                translate([0,0,z*ziptie_dist_ - z*1/2])
                hollow_cylinder(
                    d=D+ziptie_bearing_distance+ziptie_thickness,
                    thickness = ziptie_thickness*2,
                    h = ziptie_width,
                    taper=false,
                    orient=Z,
                    align=N
                    );
            }
        }

        // for linear rod
        cylindera(d=d+2*mm, h=1000, orient=Z);

        // flange
        translate(-Z*h/2)
        {
            if(flange_side != U)
            {
                // LMK
                intersection()
                {
                    rcubea(size=[flange_side, flange_side, flange_h], orient=Z, align=Z, round_r=1);

                    rcubea(size=[flange_d, flange_d, flange_h], orient=Z, align=Z, round_r=1);
                }
            }
            else if(flange_d != U)
            {
                // LMH
                if(flange_d_cut != U)
                {
                    intersection()
                    {
                        rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                        rcubea(size=[get(LinearBearingFlangeCutDiameter, bearing), flange_d, flange_h], align=Z, round_r=1);
                    }
                }
                // LMF
                else if(flange_d != U)
                {
                    rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                }
            }
        }

        translate(-Z*h/2)
        {
            // inner bore cut
            cylindera(h=h, d=d, orient=Z, align=Z, extra_h=.2);

            // clips
            if(ziptie_dist_ != U)
            {
                translate(Z*h/2)
                for(z=[-1,1])
                translate(z*Z*ziptie_dist_/2)
                hollow_cylinder(d=D-clip_groove/2+.01, thickness=clip_groove, h=clip_groove, taper=false, orient=Z, align=-z);
            }

            // flange
            if(flange_side != U)
            {
                // LMK
                // screw cut
                for(x=[-1,1])
                for(y=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d_cut != U)
            {
                // LMH
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*get(LinearBearingFlangeCutMountHoleDist, bearing)/2)
                translate(x*X*get(LinearBearingFlangeCutMountHoleDistSide, bearing)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d != U)
            {
                // LMF
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
        }

    }
    else if(part=="vit")
    size_align(size=[D,D,h], align=align, orient=orient)
    translate(Z*flange_offset)
    {
        if($show_vit)
        {
            linear_bearing(bearing=bearing);

            if(mount_style=="open")
            for(z=[-1,1])
            translate([0,0,z*ziptie_dist_])
            {
                hollow_cylinder(
                    d=D+ziptie_bearing_distance+ziptie_thickness,
                    thickness = ziptie_thickness,
                    h = ziptie_width,
                    taper=false,
                    orient=Z,
                    align=-z*Z
                    );
            }
        }
    }
}

// all
if(false)
{
    v_flangewidth = v_get(AllLinearBearing,LinearBearingFlangeDiameter);
    v_dia = v_get(AllLinearBearing,LinearBearingOuterDiameter);
    v_width = vv_fallback([v_flangewidth, v_dia]);
    dist_cumsum = v_cumsum(v_width, 0);
    for(i=[0:1:len(AllLinearBearing)-1])
    {
        bearing = AllLinearBearing[i];
        dist=dist_cumsum[i];
        translate(X*dist)
        {
            linear_bearing(bearing=bearing, align=Z);
            translate((v_width[i]/2 + 3*mm)*-Y)
            rotate(-90*Z)
            text(get(LinearBearingModel, bearing), size=v_width[i]*.8, valign="center", halign="left");

            translate((v_width[i] + 10*mm)*Y)
            linear_bearing_mount(bearing=bearing, align=Z);
        }
    }
}

if(false)
{
    stack(axis=X, dist=50*mm)
    {
        linear_bearing(bearing=LinearBearingLM6, align=Z);
        linear_bearing(bearing=LinearBearingLM6L, align=Z);
        linear_bearing(bearing=LinearBearingLMF8, align=Z);
        linear_bearing(bearing=LinearBearingLMF8L, align=Z);
        linear_bearing(bearing=LinearBearingLMK8, align=Z);
        linear_bearing(bearing=LinearBearingLMK8L, align=Z);
        linear_bearing(bearing=LinearBearingLMH12L, align=Z);
        linear_bearing(bearing=LinearBearingLMH16L, align=Z);
    }
}

include <units.scad>
include <system.scad>

use <misc.scad>
use <transforms.scad>
use <shapes.scad>
use <screws.scad>
include <bearing-linear-data.scad>
include <thread-data.scad>

module linear_bearing(part, bearing, align=N, orient=Z, offset_flange=false)
{
    model = get(LinearBearingModel, bearing);
    width_x = fallback(get(LinearBearingFlangeCutDiameter, bearing),LinearBearingOuterDiameter);
    width_y = fallback(get(LinearBearingFlangeDiameter, bearing),LinearBearingOuterDiameter);

    clip_dist = get(LinearBearingClipsDistance, bearing);
    clip_groove = get(LinearBearingClipsGrooveDepth, bearing);
    clip_dia = get(LinearBearingClipsDiameter, bearing);

    flange_h = fallback(get(LinearBearingFlangeThickness, bearing),0);

    // for all kinds of flanges
    flange_d = get(LinearBearingFlangeDiameter,bearing);

    // only for square flange
    flange_side = get(LinearBearingFlangeSide,bearing);

    // only for cut flanges
    flange_d_cut = get(LinearBearingFlangeCutDiameter,bearing);

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

    flange_screw_len=12*mm;

    flange_offset = offset_flange ? -flange_h : 0;
    h = get(LinearBearingLength,bearing);
    d = get(LinearBearingInnerDiameter, bearing);
    D = get(LinearBearingOuterDiameter, bearing);
    s = [width_x, width_y, h];
    if(part==U)
    {
        difference()
        {
            linear_bearing(part="pos", bearing=bearing, align=align, orient=orient, offset_flange=offset_flange);
            linear_bearing(part="neg", bearing=bearing, align=align, orient=orient, offset_flange=offset_flange);
        }
        %linear_bearing(part="vit", bearing=bearing, align=align, orient=orient, offset_flange=offset_flange);
    }
    else if(part=="pos")
    size_align(size=s, align=align, orient=orient)
    translate(Z*flange_offset)
    {
        cylindera(h=h, d=D, orient=Z);

        // flange
        translate(-Z*h/2)
        {
            if(flange_side != U)
            {
                // LMK
                intersection()
                {
                    rcubea(size=[flange_side, flange_side, flange_h], orient=Z, align=Z, round_r=1);

                    rcubea(size=[flange_d, flange_d, flange_h], orient=Z, align=Z, round_r=1);
                }
            }
            else if(flange_d != U)
            {
                // LMH
                if(flange_d_cut != U)
                {
                    intersection()
                    {
                        rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                        rcubea(size=[get(LinearBearingFlangeCutDiameter, bearing), flange_d, flange_h], align=Z, round_r=1);
                    }
                }
                // LMF
                else if(flange_d != U)
                {
                    rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                }
            }
        }
    }
    else if(part=="neg")
    size_align(size=s, align=align, orient=orient)
    translate(Z*flange_offset)
    {
        translate(-Z*h/2)
        {
            // inner bore cut
            cylindera(h=h, d=d, orient=Z, align=Z, extra_h=.2);

            // clips
            if(clip_dist != U)
            {
                translate(Z*h/2)
                for(z=[-1,1])
                translate(z*Z*clip_dist/2)
                hollow_cylinder(d=D-clip_groove/2+.01, thickness=clip_groove, h=clip_groove, taper=false, orient=Z, align=-z);
            }

            // flange
            if(flange_side != U)
            {
                // LMK
                // screw cut
                for(x=[-1,1])
                for(y=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d_cut != U)
            {
                // LMH
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*get(LinearBearingFlangeCutMountHoleDist, bearing)/2)
                translate(x*X*get(LinearBearingFlangeCutMountHoleDistSide, bearing)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d != U)
            {
                // LMF
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
        }
    }
}

module linear_bearing_mount(part, bearing, extra_h=0, override_h=U, ziptie_type=[2*mm, 3*mm], ziptie_bearing_distance=3*mm, tolerance=.1*mm, align=N, orient=Z, ziptie_dist=U, with_zips=true, offset_flange=false, mount_dir_align=U, mount_style="open")
{
    assert(mount_dir_align != U, "mount_dir_align == U");

    ziptie_thickness = ziptie_type[0];
    ziptie_width = ziptie_type[1]+0.6*mm;

    ziptie_dist_ = fallback(ziptie_dist, get(LinearBearingClipsDistance,bearing)/2);

    clip_dist = get(LinearBearingClipsDistance, bearing);

    h = fallback(override_h, get(LinearBearingLength,bearing)) + extra_h;
    d = get(LinearBearingInnerDiameter, bearing);
    D = get(LinearBearingOuterDiameter, bearing);

    flange_h = fallback(get(LinearBearingFlangeThickness, bearing),0);

    // for all kinds of flanges
    flange_d = get(LinearBearingFlangeDiameter,bearing);

    // only for square flange
    flange_side = get(LinearBearingFlangeSide,bearing);

    // only for cut flanges
    flange_d_cut = get(LinearBearingFlangeCutDiameter,bearing);

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

    flange_screw_len=12*mm;
    flange_offset = offset_flange ? -flange_h : 0;

    support_wall_thickness = 2.5*mm;

    support_D=D+2*support_wall_thickness;
    support_h = h+flange_offset;
    if(part==U)
    {
        difference()
        {
            linear_bearing_mount(part="pos", bearing=bearing, extra_h=extra_h, override_h=override_h, ziptie_type=ziptie_type, ziptie_bearing_distance=ziptie_bearing_distance, tolerance=tolerance, align=align, orient=orient, ziptie_dist=ziptie_dist, with_zips=with_zips, offset_flange=offset_flange, mount_dir_align=mount_dir_align, mount_style=mount_style);
            linear_bearing_mount(part="neg", bearing=bearing, extra_h=extra_h, override_h=override_h, ziptie_type=ziptie_type, ziptie_bearing_distance=ziptie_bearing_distance, tolerance=tolerance, align=align, orient=orient, ziptie_dist=ziptie_dist, with_zips=with_zips, offset_flange=offset_flange, mount_dir_align=mount_dir_align, mount_style=mount_style);
        }
        %linear_bearing_mount(part="vit", bearing=bearing, extra_h=extra_h, override_h=override_h, ziptie_type=ziptie_type, ziptie_bearing_distance=ziptie_bearing_distance, tolerance=tolerance, align=align, orient=orient, ziptie_dist=ziptie_dist, with_zips=with_zips, offset_flange=offset_flange, mount_dir_align=mount_dir_align, mount_style=mount_style);
    }
    else if(part=="pos")
    size_align(size=[D,D,h], align=align, orient=orient)
    {
        translate(-Z*h/2)
        {
            // z axis bearing support
            if(mount_style=="open")
            {
                intersection()
                {
                    rcylindera(h=support_h, d=D, orient=Z, align=Z);
                    rcubea(size=[D,D,support_h], orient=Z, align=Z+mount_dir_align);
                }
            }
            else if(mount_style=="closed")
            {
                rcylindera(h=support_h, d=support_D, orient=Z, align=Z);
            }

            // support for clips
            if(clip_dist != U)
            {
                translate(Z*h/2)
                for(z=[-1,1])
                translate(z*Z*clip_dist/2)
                hollow_cylinder(d=D-clip_groove/2+.01, thickness=clip_groove, h=clip_groove, taper=false, orient=Z, align=-z);
            }

            // support for flange mount
            if(flange_side != U)
            {
                // LMK
                // screw cut
                for(x=[-1,1])
                for(y=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                rcylindera(d=1.5*get(LinearBearingFlangeMountingSize,bearing), h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d_cut != U)
            {
                // LMH
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*get(LinearBearingFlangeCutMountHoleDist, bearing)/2)
                translate(x*X*get(LinearBearingFlangeCutMountHoleDistSide, bearing)/2)
                rcylindera(d=1.5*get(LinearBearingFlangeMountingSize,bearing), h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d != U)
            {
                // LMF
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                rcylindera(d=1.5*get(LinearBearingFlangeMountingSize,bearing), h=flange_screw_len, orient=Z, align=Z);
            }
        }
    }
    else if(part=="neg")
    size_align(size=[D,D,h], align=align, orient=orient)
    translate(Z*flange_offset)
    translate(-Z*.001)
    {
        // Main bearing cut
        cylindera(h=h+tolerance, d=D+tolerance, orient=Z);

        if(mount_style=="open")
        {
            orient(-orient)
            rcubea(size=[1000,1000,D+.2*mm], align=mount_dir_align);

            if(with_zips)
            {
                for(z=[-1,1])
                translate([0,0,z*ziptie_dist_ - z*1/2])
                hollow_cylinder(
                    d=D+ziptie_bearing_distance+ziptie_thickness,
                    thickness = ziptie_thickness*2,
                    h = ziptie_width,
                    taper=false,
                    orient=Z,
                    align=N
                    );
            }
        }

        // for linear rod
        cylindera(d=d+2*mm, h=1000, orient=Z);

        // flange
        translate(-Z*h/2)
        {
            if(flange_side != U)
            {
                // LMK
                intersection()
                {
                    rcubea(size=[flange_side, flange_side, flange_h], orient=Z, align=Z, round_r=1);

                    rcubea(size=[flange_d, flange_d, flange_h], orient=Z, align=Z, round_r=1);
                }
            }
            else if(flange_d != U)
            {
                // LMH
                if(flange_d_cut != U)
                {
                    intersection()
                    {
                        rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                        rcubea(size=[get(LinearBearingFlangeCutDiameter, bearing), flange_d, flange_h], align=Z, round_r=1);
                    }
                }
                // LMF
                else if(flange_d != U)
                {
                    rcylindera(h=flange_h, d=flange_d, orient=Z, align=Z, round_r=1);
                }
            }
        }

        translate(-Z*h/2)
        {
            // inner bore cut
            cylindera(h=h, d=d, orient=Z, align=Z, extra_h=.2);

            // clips
            if(clip_dist != U)
            {
                translate(Z*h/2)
                for(z=[-1,1])
                translate(z*Z*clip_dist/2)
                hollow_cylinder(d=D-clip_groove/2+.01, thickness=clip_groove, h=clip_groove, taper=false, orient=Z, align=-z);
            }

            // flange
            if(flange_side != U)
            {
                // LMK
                // screw cut
                for(x=[-1,1])
                for(y=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d_cut != U)
            {
                // LMH
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*get(LinearBearingFlangeCutMountHoleDist, bearing)/2)
                translate(x*X*get(LinearBearingFlangeCutMountHoleDistSide, bearing)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
            else if(flange_d != U)
            {
                // LMF
                // screw cut
                for(y=[-1,1])
                for(x=[-1,1])
                translate(y*Y*flange_pcd/2*sqrt(2)/2)
                translate(x*X*flange_pcd/2*sqrt(2)/2)
                screw_cut(thread=ThreadM4, h=flange_screw_len, orient=Z, align=Z);
            }
        }

    }
    else if(part=="vit")
    size_align(size=[D,D,h], align=align, orient=orient)
    translate(Z*flange_offset)
    {
        if($show_vit)
        {
            linear_bearing(bearing=bearing);

            if(mount_style=="open")
            for(z=[-1,1])
            translate([0,0,z*ziptie_dist_])
            {
                hollow_cylinder(
                    d=D+ziptie_bearing_distance+ziptie_thickness,
                    thickness = ziptie_thickness,
                    h = ziptie_width,
                    taper=false,
                    orient=Z,
                    align=-z*Z
                    );
            }
        }
    }
}

// all
if(false)
{
    v_flangewidth = v_get(AllLinearBearing,LinearBearingFlangeDiameter);
    v_dia = v_get(AllLinearBearing,LinearBearingOuterDiameter);
    v_width = vv_fallback([v_flangewidth, v_dia]);
    dist_cumsum = v_cumsum(v_width, 0);
    for(i=[0:1:len(AllLinearBearing)-1])
    {
        bearing = AllLinearBearing[i];
        dist=dist_cumsum[i];
        translate(X*dist)
        {
            linear_bearing(bearing=bearing, align=Z);
            translate((v_width[i]/2 + 3*mm)*-Y)
            rotate(-90*Z)
            text(get(LinearBearingModel, bearing), size=v_width[i]*.8, valign="center", halign="left");

            translate((v_width[i] + 10*mm)*Y)
            linear_bearing_mount(bearing=bearing, align=Z);
        }
    }
}

if(false)
{
    stack(axis=X, dist=50*mm)
    {
        linear_bearing(bearing=LinearBearingLM6, align=Z);
        linear_bearing(bearing=LinearBearingLM6L, align=Z);
        linear_bearing(bearing=LinearBearingLMF8, align=Z);
        linear_bearing(bearing=LinearBearingLMF8L, align=Z);
        linear_bearing(bearing=LinearBearingLMK8, align=Z);
        linear_bearing(bearing=LinearBearingLMK8L, align=Z);
        linear_bearing(bearing=LinearBearingLMH12L, align=Z);
        linear_bearing(bearing=LinearBearingLMH16L, align=Z);
    }
}


As printed

As printed

/** \file
 * Bracket to hold a 16x2 LED panel in an Octoscroller configuration.
 */

module bracket_half()
{
	render() difference()
	{
		cube([18,7,10]);

		translate([13,10,5])
		rotate([90,0,0])
		cylinder(r=2, h=20, $fs=1);
	}
}

module bracket()
{
	rotate([0,0,+45/2]) bracket_half();
	rotate([0,0,-45/2-180]) translate([0,-7,0]) bracket_half();
}

for (i = [0:1])
{
	translate([i*35,0,0]) {
		for (j = [0:7]) {
			translate([0,10*j,0]) bracket();
		}
	}
}

%translate([0,0,-1]) cube([200,200,2], center=true);

/** \file
 * Bracket to hold a 16x2 LED panel in an Octoscroller configuration.
 */

module bracket()
{
	render() difference()
	{
		cube([16,5,10]);

		translate([13,10,5])
		rotate([90,0,0])
		cylinder(r=2, h=20, $fs=1);
	}
}

rotate([0,0,+45/2]) bracket();
rotate([0,0,-45/2-180]) translate([0,-5,0]) bracket();

%translate([0,0,-1]) cube([200,200,2], center=true);


transforms: add some asserts

transforms: add some asserts

/*include <../scad-utils/transformations.scad>*/
include <system.scad>
use <misc.scad>

module t(dist)
{
    assert(dist!=U, "dist==U");
    translate(dist)
    children();
}

module tx(dist)
{
    assert(dist!=U, "dist==U");
    translate(X*dist)
    children();
}

module ty(dist)
{
    assert(dist!=U, "dist==U");
    translate(Y*dist)
    children();
}

module tz(dist)
{
    assert(dist!=U, "dist==U");
    translate(Z*dist)
    children();
}

module r(a, v)
{
    rotate(a,v)
    children();
}

module rx(degrees)
{
    rotate(X*degrees)
    children();
}

module ry(degrees)
{
    rotate(Y*degrees)
    children();
}

module rz(degrees)
{
    rotate(Z*degrees)
    children();
}

// translate children
module position(positions)
{
    assert(positions!=U, "positions==U");
    for(pos=positions)
    translate(pos)
    children();
}

// translate children
module linup(arr=U)
{
    if($children>0)
    {
        for (i = [0 : $children-1])
        translate(arr[i]) children(i);
    }
}

module stack(dist=10, distances=U, axis=Z)
{
    if($children>0)
    {
        if(dist == U && distances != U)
        {
            for (i = [0:len(distances)-1])
            {
                offset = v_sum(distances,i);
                translate(axis*offset)
                    child(i);
            }
        }
        else if(dist != U && distances == U)
        {
            for (i = [0 : $children-1])
                translate(axis*(dist*i))
                    children(i);
        }
    }
}

module orient(axis=U, axis_ref=U, roll=0, extra_roll, extra_roll_orient)
{
    rotate(extra_roll_orient==U||extra_roll==U?0:extra_roll*extra_roll_orient)

    // orient to reference axis
    /*rotate(axis_ref==U?0:_orient_angles(axis_ref))*/
    /*multmatrix(axis_ref==U?0:v_rotate(90, axis_ref))*/
    rotate(axis_ref==U?0:_orient_angles(axis_ref))

    // roll around orient axis
    rotate(axis==U?0:roll*axis)

    // orient to axis
    /*multmatrix(axis==U?0:v_rotate(90, axis))*/
    rotate(axis==U?0:_orient_angles(axis))
    children();
}

module orient_(axis=U, axis_ref=U, roll=0, extra_roll, extra_roll_orient)
{
    rotate(extra_roll_orient==U||extra_roll==U?0:extra_roll*extra_roll_orient)

    // orient to reference axis
    multmatrix(axis_ref==U?0:v_rotate(90, axis_ref))

    // roll around orient axis
    rotate(axis==U?0:roll*axis)

    // orient to axis
    multmatrix(axis_ref==U?0:v_rotate(90, axis))
    children();
}

function _orient_bounds(orient, size) =
    (_rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1]);

function _orient_t(orient, align, size) =
    let(bounds = _orient_bounds(orient, size))
    (hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]));

module size_align(size=[10,10,10], extra_size=N, align=N, extra_align=N, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    t = orient==U?N:_orient_t(orient, align, size);
    extra_t = (orient==U||extra_size==U||extra_size==[U,U,U]||extra_size==[0,0,0]||extra_align==U) ?
        N : _orient_t(orient, extra_align, extra_size);
    translate(t+extra_t)
    {
        orient(axis=orient, axis_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
        {
            children();
        }
    }
}

module hull_pairwise()
{
    for (i= [1:1:$children-1])
    {
        hull()
        {
            children(i-1);
            children(i);
        }
    }
}

module proj_extrude_axis(axis=Z, h=1, offset=0, cut=false)
{
    translate(-offset*axis)
    hull()
    {
        orient_(axis=axis, axis_ref=Z)
        {
            linear_extrude(h, center=false)
            projection(cut=cut)
            orient_(axis=Z, axis_ref=axis)
            translate(offset*axis)
            children();

            orient_(axis=Z, axis_ref=axis)
            translate(offset*axis)
            children();
        }
    }
}

module all_axes()
{
    for($axis=concat(AXES,-AXES))
    {
        $color = v_abs($axis*.3 + v_clamp(v_sign($axis),0,1)*.7);
        children();
    }
}

// test proj_extruder_axis
if(false)
{
    all_axes()
    color($color)
    translate(5*$axis)
    proj_extrude_axis(axis=$axis)
    translate(20*$axis)
    sphere(d=10);
}

if(false)
{
    translate(Y*10)
    proj_extrude_axis(axis=Y, offset=10)
    {
        sphere(d=10);
    }
}

// translate by pos, with extra (depending on the sign of pos)
// an "explode" function
module te(pos, extra=[0,0,0])
{
    assert(len(pos) == 3);
    assert(len(extra) == 3);

    t(pos + v_mul(extra , v_sign(pos)))
    children();
}

/*include <../scad-utils/transformations.scad>*/
include <system.scad>
use <misc.scad>

module t(dist)
{
    translate(dist)
    children();
}

module tx(dist)
{
    translate(X*dist)
    children();
}

module ty(dist)
{
    translate(Y*dist)
    children();
}

module tz(dist)
{
    translate(Z*dist)
    children();
}

module r(a, v)
{
    rotate(a,v)
    children();
}

module rx(degrees)
{
    rotate(X*degrees)
    children();
}

module ry(degrees)
{
    rotate(Y*degrees)
    children();
}

module rz(degrees)
{
    rotate(Z*degrees)
    children();
}

// translate children
module position(positions)
{
    assert(positions!=U, "positions==U");
    for(pos=positions)
    translate(pos)
    children();
}

// translate children
module linup(arr=U)
{
    if($children>0)
    {
        for (i = [0 : $children-1])
        translate(arr[i]) children(i);
    }
}

module stack(dist=10, distances=U, axis=Z)
{
    if($children>0)
    {
        if(dist == U && distances != U)
        {
            for (i = [0:len(distances)-1])
            {
                offset = v_sum(distances,i);
                translate(axis*offset)
                    child(i);
            }
        }
        else if(dist != U && distances == U)
        {
            for (i = [0 : $children-1])
                translate(axis*(dist*i))
                    children(i);
        }
    }
}

module orient(axis=U, axis_ref=U, roll=0, extra_roll, extra_roll_orient)
{
    rotate(extra_roll_orient==U||extra_roll==U?0:extra_roll*extra_roll_orient)

    // orient to reference axis
    /*rotate(axis_ref==U?0:_orient_angles(axis_ref))*/
    /*multmatrix(axis_ref==U?0:v_rotate(90, axis_ref))*/
    rotate(axis_ref==U?0:_orient_angles(axis_ref))

    // roll around orient axis
    rotate(axis==U?0:roll*axis)

    // orient to axis
    /*multmatrix(axis==U?0:v_rotate(90, axis))*/
    rotate(axis==U?0:_orient_angles(axis))
    children();
}

module orient_(axis=U, axis_ref=U, roll=0, extra_roll, extra_roll_orient)
{
    rotate(extra_roll_orient==U||extra_roll==U?0:extra_roll*extra_roll_orient)

    // orient to reference axis
    multmatrix(axis_ref==U?0:v_rotate(90, axis_ref))

    // roll around orient axis
    rotate(axis==U?0:roll*axis)

    // orient to axis
    multmatrix(axis_ref==U?0:v_rotate(90, axis))
    children();
}

function _orient_bounds(orient, size) =
    (_rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1]);

function _orient_t(orient, align, size) =
    let(bounds = _orient_bounds(orient, size))
    (hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]));

module size_align(size=[10,10,10], extra_size=N, align=N, extra_align=N, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    t = orient==U?N:_orient_t(orient, align, size);
    extra_t = (orient==U||extra_size==U||extra_size==[U,U,U]||extra_size==[0,0,0]||extra_align==U) ?
        N : _orient_t(orient, extra_align, extra_size);
    translate(t+extra_t)
    {
        orient(axis=orient, axis_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
        {
            children();
        }
    }
}

module hull_pairwise()
{
    for (i= [1:1:$children-1])
    {
        hull()
        {
            children(i-1);
            children(i);
        }
    }
}

module proj_extrude_axis(axis=Z, h=1, offset=0, cut=false)
{
    translate(-offset*axis)
    hull()
    {
        orient_(axis=axis, axis_ref=Z)
        {
            linear_extrude(h, center=false)
            projection(cut=cut)
            orient_(axis=Z, axis_ref=axis)
            translate(offset*axis)
            children();

            orient_(axis=Z, axis_ref=axis)
            translate(offset*axis)
            children();
        }
    }
}

module all_axes()
{
    for($axis=concat(AXES,-AXES))
    {
        $color = v_abs($axis*.3 + v_clamp(v_sign($axis),0,1)*.7);
        children();
    }
}

// test proj_extruder_axis
if(false)
{
    all_axes()
    color($color)
    translate(5*$axis)
    proj_extrude_axis(axis=$axis)
    translate(20*$axis)
    sphere(d=10);
}

if(false)
{
    translate(Y*10)
    proj_extrude_axis(axis=Y, offset=10)
    {
        sphere(d=10);
    }
}

// translate by pos, with extra (depending on the sign of pos)
// an "explode" function
module te(pos, extra=[0,0,0])
{
    assert(len(pos) == 3);
    assert(len(extra) == 3);

    t(pos + v_mul(extra , v_sign(pos)))
    children();
}


Clarifying specs, general updates.

Clarifying specs, general updates.

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.
thickness = 3;

// Interior box dimensions (from centerpoints of walls, so actual dimension is minus material thickness)
width = 400;   // x
depth = 300;   // y
height = 180;  // z

// tank base plate
base_width = width-thickness*2;
base_height = 10;

// light bar
light_bar_width = 30;
light_pos_x = 50;
light_height = height-10;

// height of side supports
side_support_height = height/2; // full side walls
//side_support_height = 20;

// amount faces extend past each other at corners
overhang = 10;

// amount horizontal support bars extend past side supports
outset = overhang/2;

// components to include (comment out unwanted)
vert_faces();
side_supports();
tank_base();
light_bar();

//////////////////////////////////////////////////////////////////
// Module definitions
//

module vert_faces() {
	difference() {
		union() {
			vert_face(x=0);
			vert_face(x=width);
		}
		side_support_base(height_scale=0.5);
		side_support_top(height_scale=0.5);
	}
}

module vert_face(x) {
	translate([x-thickness/2,-overhang,0])
		cube([thickness,depth+overhang*2,height]);
}

module tank_base() {
	translate([thickness,-outset,base_height])
	difference() {
		cube([base_width, depth+outset*2, thickness]);
		cutouts(5,base_width,outset,far_side=false);
        cutouts(5,base_width,outset,far_side=true);
	}
}

module light_bar() {
	translate([light_pos_x,-outset,light_height])
	difference() {
		cube([light_bar_width, depth+outset*2, thickness]);
		cutouts(2,light_bar_width,outset,far_side=false);
        cutouts(2,light_bar_width,outset,far_side=true);
	}
}

module cutouts(num, width, outset, far_side=False) {
    w = width / ((num-1) * 2);
    y = far_side ? depth+outset-thickness/2 : 0;
    for (i = [0 : num-1]) {
        translate([-w/2 + i*2*w,y,0])
            cube([w, outset+thickness/2, thickness]);
    }
}

module side_supports() {
	difference() {
		union() {
			side_support_base();
			side_support_top();
		}
		vert_faces();
		tank_base();
        light_bar();
	}
}

module side_support_top(height_scale=1) {
	translate([0,0,height])
        side_support_base(height_scale=-height_scale);
}

module side_support_base(height_scale=1) {
	scale([1,1,height_scale])
		union() {
			side_support(y=0);
			side_support(y=depth);
		}
}

module side_support(y) {
	translate([-overhang,y-thickness/2,0])
		cube([width+overhang*2, thickness, side_support_height]);
}

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.
thickness = 3;

// Interior box dimensions (from centerpoints of walls, so actual dimension is minus material thickness)
width = 400;   // x
depth = 300;   // y
height = 180;  // z

// tank base plate
base_width = 80;
base_height = 10;

// light bar
light_bar_width = 20;
light_pos_x = thickness+base_width-light_bar_width;
light_height = height-10;

// height of side supports
//side_support_height = height/2; // full side walls
side_support_height = 20;

// amount faces extend past each other at corners
overhang = 10;

// amount horizontal support bars extend past side supports
outset = overhang/2;

// components to include (comment out unwanted)
vert_faces();
side_supports();
tank_base();
light_bar();

//////////////////////////////////////////////////////////////////
// Module definitions
//

module vert_faces() {
	difference() {
		union() {
			vert_face(x=0);
			vert_face(x=width);
		}
		side_support_base(height_scale=0.5);
		side_support_top(height_scale=0.5);
	}
}

module vert_face(x) {
	translate([x-thickness/2,-overhang,0])
		cube([thickness,depth+overhang*2,height]);
}

module tank_base() {
	translate([thickness,-outset,base_height])
	difference() {
		cube([base_width, depth+outset*2, thickness]);
		cutouts(3,base_width,outset,far_side=false);
        cutouts(3,base_width,outset,far_side=true);
	}
}

module light_bar() {
	translate([light_pos_x,-outset,light_height])
	difference() {
		cube([light_bar_width, depth+outset*2, thickness]);
		cutouts(2,light_bar_width,outset,far_side=false);
        cutouts(2,light_bar_width,outset,far_side=true);
	}
}

module cutouts(num, width, outset, far_side=False) {
    w = width / ((num-1) * 2);
    y = far_side ? depth+outset-thickness/2 : 0;
    for (i = [0 : num-1]) {
        translate([-w/2 + i*2*w,y,0])
            cube([w, outset+thickness/2, thickness]);
    }
}

module side_supports() {
	difference() {
		union() {
			side_support_base();
			side_support_top();
		}
		vert_faces();
		tank_base();
        light_bar();
	}
}

module side_support_top(height_scale=1) {
	translate([0,0,height])
        side_support_base(height_scale=-height_scale);
}

module side_support_base(height_scale=1) {
	scale([1,1,height_scale])
		union() {
			side_support(y=0);
			side_support(y=depth);
		}
}

module side_support(y) {
	translate([-overhang,y-thickness/2,0])
		cube([width+overhang*2, thickness, side_support_height]);
}


Fix offset of camera supports for cutouts.

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.
thickness = 3;

// Interior box dimensions (from centerpoints of walls, so actual dimension is minus material thickness)
width = 400;   // x
depth = 300;   // y
height = 180;  // z

// tank base plate
base_width = width-thickness*2;
base_height = 10;

// light bar
light_bar_width = 30;
light_pos_x = 50;
light_height = height-10;

// height of side supports
side_support_height = height/2; // full side walls
//side_support_height = 20;

// amount faces extend past each other at corners
overhang = 10;

// amount horizontal support bars extend past side supports
outset = overhang/2;

// for slight offsets/tweaks
epsilon = 1;

// components to include (comment out unwanted)
vert_faces();
side_supports();
tank_base();
light_bar();
camera_supports(x=width, y=depth/2, z=height/2, spacing=20);
top_cover();

//////////////////////////////////////////////////////////////////
// Module definitions
//

module vert_faces() {
	difference() {
		union() {
			vert_face(x=0);
            difference() {
                vert_face(x=width);
                camera_opening();
                camera_supports(x=width+thickness*2, y=depth/2, z=height/2+10, spacing=20);
            }
		}
		side_support_base(height_scale=0.5);
		side_support_top(height_scale=0.5);
	}
}

module vert_face(x) {
	translate([x-thickness/2,-overhang,0])
		cube([thickness,depth+overhang*2,height]);
}

module camera_opening() {
    translate([width, depth/2, height/2])
        cube([thickness*2,10,10], center=true);
}

module camera_supports(x, y, z, spacing) {
    camera_support(x, y + spacing/2, z);
    camera_support(x, y - spacing/2, z);
}

module camera_support(x, y, z) {
    inner_w = 20;
    inner_h = 30;
    inner_offset = 5;
    translate([x,y,z])
    // shift down to center on camera opening
    translate([0,0,-inner_offset])
    // push inner opening up against vert face
    translate([inner_w/2,0,0])
    difference() {
        cube([inner_w+20, thickness, inner_h+30], center=true);
        // cutout for camera
        translate([0,0,inner_offset])
            cube([inner_w, thickness*2, inner_h], center=true);
        // cutout for passing through vertface
        translate([-10-epsilon,0,0])
            cube([inner_w, thickness*2, inner_h-10], center=true);
        // bottom cutout
        translate([-inner_w/2,0,-25])
            cube([thickness, thickness*2, 10], center=true);
    }
}

module top_cover() {
    color("Grey", alpha=0.5)
    translate([thickness/2,-outset,height-thickness])
    difference() {
        cube([width-thickness,depth+outset*2,thickness]);
		cutouts(5,width-thickness,outset,far_side=false);
		cutouts(5,width-thickness,outset,far_side=true);
    }
}

module tank_base() {
	translate([thickness,-outset,base_height])
	difference() {
		cube([base_width, depth+outset*2, thickness]);
		cutouts(5,base_width,outset,far_side=false);
        cutouts(5,base_width,outset,far_side=true);
	}
}

module light_bar() {
	translate([light_pos_x-light_bar_width/2, -outset, light_height])
	difference() {
		cube([light_bar_width, depth+outset*2, thickness]);
		cutouts(2,light_bar_width,outset,far_side=false);
        cutouts(2,light_bar_width,outset,far_side=true);
	}
}

module cutouts(num, width, outset, far_side=false) {
    w = width / ((num-1) * 2);
    y = far_side ? depth+outset-thickness/2 : 0;
    for (i = [0 : num-1]) {
        translate([-w/2 + i*2*w, y, -epsilon])
            cube([w, outset+thickness/2, thickness+epsilon*2]);
    }
}

module light_wire_opening() {
    translate([light_pos_x, 0, light_height-10])
    scale([2,1,1])
    rotate(v=[1,0,0], a=90)
        cylinder(d=10, h=thickness+epsilon, center=true);
}

module side_supports() {
	difference() {
		union() {
			side_support_base();
			side_support_top();
		}
		vert_faces();
		tank_base();
        light_bar();
        light_wire_opening();
        top_cover();
	}
}

module side_support_top(height_scale=1) {
	translate([0,0,height])
        side_support_base(height_scale=-height_scale);
}

module side_support_base(height_scale=1) {
	scale([1,1,height_scale])
		union() {
			side_support(y=0);
			side_support(y=depth);
		}
}

module side_support(y) {
	translate([-overhang,y-thickness/2,0])
		cube([width+overhang*2, thickness, side_support_height]);
}

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.
thickness = 3;

// Interior box dimensions (from centerpoints of walls, so actual dimension is minus material thickness)
width = 400;   // x
depth = 300;   // y
height = 180;  // z

// tank base plate
base_width = width-thickness*2;
base_height = 10;

// light bar
light_bar_width = 30;
light_pos_x = 50;
light_height = height-10;

// height of side supports
side_support_height = height/2; // full side walls
//side_support_height = 20;

// amount faces extend past each other at corners
overhang = 10;

// amount horizontal support bars extend past side supports
outset = overhang/2;

// for slight offsets/tweaks
epsilon = 1;

// components to include (comment out unwanted)
vert_faces();
side_supports();
tank_base();
light_bar();
camera_supports(x=width, y=depth/2, z=height/2, spacing=20);
top_cover();

//////////////////////////////////////////////////////////////////
// Module definitions
//

module vert_faces() {
	difference() {
		union() {
			vert_face(x=0);
            difference() {
                vert_face(x=width);
                camera_opening();
                camera_supports(x=width+10, y=depth/2, z=height/2+10, spacing=20);
            }
		}
		side_support_base(height_scale=0.5);
		side_support_top(height_scale=0.5);
	}
}

module vert_face(x) {
	translate([x-thickness/2,-overhang,0])
		cube([thickness,depth+overhang*2,height]);
}

module camera_opening() {
    translate([width, depth/2, height/2])
        cube([thickness*2,10,10], center=true);
}

module camera_supports(x, y, z, spacing) {
    camera_support(x, y + spacing/2, z);
    camera_support(x, y - spacing/2, z);
}

module camera_support(x, y, z) {
    inner_w = 20;
    inner_h = 30;
    inner_offset = 5;
    translate([x,y,z])
    // shift down to center on camera opening
    translate([0,0,-inner_offset])
    // push inner opening up against vert face
    translate([inner_w/2,0,0])
    difference() {
        cube([inner_w+20, thickness, inner_h+30], center=true);
        // cutout for camera
        translate([0,0,inner_offset])
            cube([inner_w, thickness*2, inner_h], center=true);
        // cutout for passing through vertface
        translate([-10-epsilon,0,0])
            cube([inner_w, thickness*2, inner_h-10], center=true);
        // bottom cutout
        translate([-inner_w/2,0,-25])
            cube([thickness, thickness*2, 10], center=true);
    }
}

module top_cover() {
    color("Grey", alpha=0.5)
    translate([thickness/2,-outset,height-thickness])
    difference() {
        cube([width-thickness,depth+outset*2,thickness]);
		cutouts(5,width-thickness,outset,far_side=false);
		cutouts(5,width-thickness,outset,far_side=true);
    }
}

module tank_base() {
	translate([thickness,-outset,base_height])
	difference() {
		cube([base_width, depth+outset*2, thickness]);
		cutouts(5,base_width,outset,far_side=false);
        cutouts(5,base_width,outset,far_side=true);
	}
}

module light_bar() {
	translate([light_pos_x-light_bar_width/2, -outset, light_height])
	difference() {
		cube([light_bar_width, depth+outset*2, thickness]);
		cutouts(2,light_bar_width,outset,far_side=false);
        cutouts(2,light_bar_width,outset,far_side=true);
	}
}

module cutouts(num, width, outset, far_side=false) {
    w = width / ((num-1) * 2);
    y = far_side ? depth+outset-thickness/2 : 0;
    for (i = [0 : num-1]) {
        translate([-w/2 + i*2*w, y, -epsilon])
            cube([w, outset+thickness/2, thickness+epsilon*2]);
    }
}

module light_wire_opening() {
    translate([light_pos_x, 0, light_height-10])
    scale([2,1,1])
    rotate(v=[1,0,0], a=90)
        cylinder(d=10, h=thickness+epsilon, center=true);
}

module side_supports() {
	difference() {
		union() {
			side_support_base();
			side_support_top();
		}
		vert_faces();
		tank_base();
        light_bar();
        light_wire_opening();
        top_cover();
	}
}

module side_support_top(height_scale=1) {
	translate([0,0,height])
        side_support_base(height_scale=-height_scale);
}

module side_support_base(height_scale=1) {
	scale([1,1,height_scale])
		union() {
			side_support(y=0);
			side_support(y=depth);
		}
}

module side_support(y) {
	translate([-overhang,y-thickness/2,0])
		cube([width+overhang*2, thickness, side_support_height]);
}


Adjust header spacer and reset button colours

/*
    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    = 0.1 * 25.4;                   // 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

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(Grey20)
    linear_extrude(spacerheight)
        square(spacerwidth, center = true);

    // Break-Away Material
    color(Grey20)
    // 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
    datumX = ArduinoPro_PCB_Width/2 - ArduinoPro_PCB_Inset;
    datumZ = ArduinoPro_PCB_Height;

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

    // Parts for Pro Mini
    if (type == ArduinoPro_Mini) {
        // Reset switch
        translate([datumX, 0.05 * 25.4, datumZ])
        {
            color("silver")
            linear_extrude(1.2)
                square([4.5, 4.5], center=true);
            color(ArduinoPro_PCB_Colour)
            translate([0, 0, 1.2])
            linear_extrude(0.5)
                circle(d=2.5);
        }

        // RX and TX LEDs
        color("white")
        translate([datumX, 0.05 * 25.4, datumZ])
        linear_extrude(1)
        {
            // Red - Power
            translate([0, 0.75 * 25.4, 0])
                square([1.2,0.7], center=true);
            // Green - Status
            translate([0.2 * 25.4, 0, 0])
                square([0.7,1.2], center=true);
        }

    }

    // Parts for Pro Micro
    if (type == ArduinoPro_Micro) {
        // Crystal
        color("silver")
        translate([datumX, 0.15 * 25.4, datumZ])
        linear_extrude(1)
            square([5, 3], center=true);

        // RX and TX LEDs
        color("white")
        translate([datumX, 0.2 * 25.4, datumZ])
        linear_extrude(1)
        {
            // RX - Yellow
            translate([-0.3 * 25.4/2, 0, 0])
                square([0.7,1.2], center=true);
            // Power - Red
            translate([-0.15 * 25.4, 0.75 * 25.4, 0])
                square([1.2,0.7], center=true);
            // TX - Green
            translate([0.3 * 25.4/2, 0, 0])
                square([0.7,1.2], center=true);
        }
    }

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

    // Other components
    color("silver")
    translate([datumX, moveY, datumZ])
    linear_extrude(1)
    {
        square([1, 2.5], center=true);
        translate([0, 3.25, 0])
            square([2.5, 1.5], center=true);
    }
}

module ArduinoPro(type = ArduinoPro_Mini, headerpins = 0, serialpins = 0)
{
    color(ArduinoPro_PCB_Colour)
    linear_extrude(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);
}

// 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    = 0.1 * 25.4;                   // 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

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
    datumX = ArduinoPro_PCB_Width/2 - ArduinoPro_PCB_Inset;
    datumZ = ArduinoPro_PCB_Height;

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

    // Parts for Pro Mini
    if (type == ArduinoPro_Mini) {
        // Reset switch
        translate([datumX, 0.05 * 25.4, datumZ])
        {
            color("silver")
            linear_extrude(1.2)
                square([4.5, 4.5], center=true);
            color("sandybrown")
            translate([0, 0, 1.2])
            linear_extrude(0.5)
                circle(d=2.5);
        }

        // RX and TX LEDs
        color("white")
        translate([datumX, 0.05 * 25.4, datumZ])
        linear_extrude(1)
        {
            // Red - Power
            translate([0, 0.75 * 25.4, 0])
                square([1.2,0.7], center=true);
            // Green - Status
            translate([0.2 * 25.4, 0, 0])
                square([0.7,1.2], center=true);
        }

    }

    // Parts for Pro Micro
    if (type == ArduinoPro_Micro) {
        // Crystal
        color("silver")
        translate([datumX, 0.15 * 25.4, datumZ])
        linear_extrude(1)
            square([5, 3], center=true);

        // RX and TX LEDs
        color("white")
        translate([datumX, 0.2 * 25.4, datumZ])
        linear_extrude(1)
        {
            // RX - Yellow
            translate([-0.3 * 25.4/2, 0, 0])
                square([0.7,1.2], center=true);
            // Power - Red
            translate([-0.15 * 25.4, 0.75 * 25.4, 0])
                square([1.2,0.7], center=true);
            // TX - Green
            translate([0.3 * 25.4/2, 0, 0])
                square([0.7,1.2], center=true);
        }
    }

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

    // Other components
    color("silver")
    translate([datumX, moveY, datumZ])
    linear_extrude(1)
    {
        square([1, 2.5], center=true);
        translate([0, 3.25, 0])
            square([2.5, 1.5], center=true);
    }
}

module ArduinoPro(type = ArduinoPro_Mini, headerpins = 0, serialpins = 0)
{
    color(ArduinoPro_PCB_Colour)
    linear_extrude(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);
}

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


adding gantry cart

adding gantry cart

include <../scad/or_gantry_plate.scad>
include <../scad/ob_wheel.scad>
use <../scad/ob_spacer.scad>
use <../scad/shim.scad>

module gantry_cart(mod = 1) {
  translate([0,0,or_gantry_plate_height/2])
    or_gantry_plate(mod);
  eccentric_spacers = [[],[2,10]];
  spacers = [[],[1,9]];
  translate([0,0,or_gantry_plate_height]) {
    for(s = eccentric_spacers[mod])
      translate(or_gantry_plate_holes[mod][s][0]) {
        ob_eccentric_spacer();
        translate([0,0,6.85]) {
          precision_shim_10x5x1();
          translate([0,0,ob_wheel_half_width])
            ob_solid_wheel();
        }
      }
    for(s = spacers[mod])
      translate(or_gantry_plate_holes[mod][s][0]) {
        ob_spacer(6.35);
        translate([0,0,6.85]) {
          precision_shim_10x5x1();
          translate([0,0,ob_wheel_half_width])
            ob_solid_wheel();
        }
      }
  }
}

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


first draft

first draft

cutW=2;
cutH=4;
width=2*1+cutW;
height=3+cutH;

difference()
{
  union()
  {
    translate([-width/2, 0, 0])
      cube([width, 51, height]);
    translate([-67/2, 31+width, 0])
      rotate([0, 0, -90])
        cube([width, 67, height]);
  }
  translate([-cutW/2, 0, 3])
    cube([cutW, 51, cutH]);
  translate([-67/2, 31+1, 3])
    cube([67, cutW, cutH]);
}


Some code tidyups

Some code tidyups

/* Pins required -

pintack(side=true, h=7.8+2+2.5, bh=2);

*/

module Bumper_STL()
{
	printedPart("printedparts/Bumper.scad", "Bumper", "Bumper_STL()") {

	    //view(t=[0, -1, -1], r=[49, 0, 25], d=336);

		if (DebugCoordinateFrames) frame();
		if (DebugConnectors) connector(Wheel_Con_Default);

	    color(Level2PlasticColor) {
            if (UseSTL) {
                import(str(STLPath, "Bumper.stl"));
            } else {
				BumperModel();
            }
        }
	}
}

module BumperModel()
{
	// Parameters
	thickness = dw;				// bumper thickness
	height = 15;				// bumper height
	offset = 5;					// distance from base to inside of bumper
	wrapAngle = 170;			// angle that bumper wraps around
	microSwitchAngle = 43.5;	// angle that microswitches are placed at

	// Calculated parameters
	outr = BaseDiameter/2 + offset + thickness;		// outside radius or the bumper

	// Bumper arc
	linear_extrude(height)
	difference() {
		circle(r = outr);

		circle(r = outr - thickness);

		// Chop off below X-axis
		translate([-outr, -outr])
			square([outr*2, outr]);

		// Trim left side of arc
		rotate([0, 0, wrapAngle/2])
		translate([-outr, 0])
			square([outr, outr * 2]);

		// Trim right side of arc
		rotate([0, 0, -wrapAngle/2])
			square([outr, outr * 2]);
	}

	// Springy bits
	for(i=[0, 1])
		mirror([i, 0, 0])
		translate([30, outr - 24, 0])
		rotate([0, 0, 90])
		linear_extrude(5)
			donutSector(17, 17 - 2*perim, 175, center=true);

	// Flanges to hit microwitch
	for(i=[0, 1])
		mirror([i, 0, 0])
		rotate([0, 0, microSwitchAngle])
		translate([0, BaseDiameter/2 - 1 , 0])
			cube([8, offset + 1 + eta, 5]);

	// Microswitch plates
	for(i=[0, 1])
		mirror([i, 0, 0])
		rotate([0, 0, microSwitchAngle])
		translate([-10, BaseDiameter/2 - 23, 0])
			MicroSwitchPlate();
}

module MicroSwitchPlate()
{
	// Parameters - todo: pickup from microswitch model?
	ms_length=12.9;
	ms_width=6.6;
	ms_height=5.8;

	base_length = ms_length + 2 * dw + 0.5;
	base_width = ms_width + 13.5;

	// Base
	translate([0, 6.5, 0])
		cube([base_length, base_width - 6.5, dw]);

	// Microswitch surround
	translate([0, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([base_length - dw, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([0, 13-dw, 0])
		cube([base_length, dw, dw + 2]);

	// Rear support lozenge with pin hole
	difference() {
		linear_extrude(dw + ms_height)
		hull() {
			translate([2.5, 7])
				circle(r=2.5);
			translate([base_length, 9.5])
				circle(r=eta);
			translate([13, 1])
				circle(r=2.5);
			translate([20, 1])
				circle(r=2.5);
		}

		// Actual hole
		translate([base_length/2 + 7, 2.65, dw + ms_height - eta])
		translate([0, 0, dw])
		mirror([0, 0, 1])
			pinhole(fixed=true);
	}
}

/* Pins required -

pintack(side=true, h=7.8+2+2.5, bh=2);

*/

module Bumper_STL()
{
	printedPart("printedparts/Bumper.scad", "Bumper", "Bumper_STL()") {

	    //view(t=[0, -1, -1], r=[49, 0, 25], d=336);

		if (DebugCoordinateFrames) frame();
		if (DebugConnectors) connector(Wheel_Con_Default);

	    color(Level2PlasticColor) {
            if (UseSTL) {
                import(str(STLPath, "Bumper.stl"));
            } else {
				BumperModel();
            }
        }
	}
}

Bumper_Pin_Width = 3;
Bumper_Pin_Length = 18;

module BumperModel()
{
	thickness = dw;
	height = 15;
	offset = 5;				// distance from base to inside of bumper
	wrapAngle = 170;		// angle that bumper wraps around
	microSwitchAngle = 43.5;	// angle that microswitches are placed at

	outr = BaseDiameter/2 + offset + thickness; // outr is the outside radius or the bumper

	// Bumper arc
	linear_extrude(height)
	difference() {
		circle(r = outr);

		circle(r = outr - thickness);

		// Chop off below X-axis
		translate([-outr, -outr])
			square([outr*2, outr]);

		// Trim left side of arc
		rotate(a=wrapAngle/2, v=[0,0,1])
		translate([-outr, 0])
			square([outr, outr * 2]);

		// Trim right side of arc
		rotate(a=-wrapAngle/2, v=[0,0,1])
			square([outr, outr * 2]);
	}

	// Springy bits
	for(i=[0,1])
		mirror([i, 0, 0])
		translate([30, outr - 24, 0])
		rotate([0,0,90])
		linear_extrude(5)
			donutSector(17, 17 - 2*perim, 175, center=true);

	// Flanges to hit microwitch
	for(i=[0,1])
	mirror([i, 0, 0])
	rotate(a=microSwitchAngle, v=[0, 0, 1]) {
		translate([0, BaseDiameter/2 - 1 , 0])
			cube([8, offset + 1 + eta, 5]);
	}

	// Microswitch plates
	for(i=[0,1])
	mirror([i, 0, 0])
	rotate([0, 0, microSwitchAngle])
	translate([-10, BaseDiameter/2 - 23, 0])
		MicroSwitchPlate();

}

module MicroSwitchPlate()
{
	ms_length=12.9;
	ms_width=6.6;
	ms_height=5.8;

	base_length = ms_length + 2 * dw + 0.5;
	base_width = ms_width + 13.5;

	// Base
	translate([0, 6.5, 0])
		cube([base_length, base_width - 6.5, dw]);

	// Microswitch surround
	translate([0, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([base_length - dw, 7, 0])
		cube([dw, base_width - 7, dw + 3]);
	translate([0, 13-dw, 0])
		cube([base_length, dw, dw + 2]);

	// Pin section
	difference() {
		linear_extrude(dw + ms_height)
		hull() {
			translate([2.5, 7])
				circle(r=2.5);
			translate([base_length, 9.5])
				circle(r=eta);
			translate([13, 1])
				circle(r=2.5);
			translate([20, 1])
				circle(r=2.5);
		}

		translate([base_length/2 + 7, 2.65, dw + ms_height - eta])
		translate([0,0,dw])
		mirror([0,0,1])
			pinhole(fixed=true);
	}
}


zaxis/motormount: use new screw_cut

zaxis/motormount: use new screw_cut

include <config.scad>

module zaxis_upper_gantry_zrod_connector()
{
    upper_width_extra = main_upper_width-main_width;
    difference()
    {
        union()
        {
            hull()
            {
                // attach to z rod
                translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
                translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
                {
                    cubea([gantry_connector_thickness, zmotor_mount_clamp_width, extrusion_size+gantry_connector_thickness], align=[-1,0,1]);
                }

                // connect upper gantry
                translate([upper_width_extra/2, 0, 0])
                    translate([0,0,extrusion_size/2])
                    cubea([gantry_connector_thickness,main_upper_dist_y+extrusion_size,extrusion_size], align=[1,0,0], extrasize=[0,0,gantry_connector_thickness], extrasize_align=[0,0,1]);
            }

            translate([upper_width_extra/2, 0, 0])
                translate([0,0,extrusion_size])
                cubea([extrusion_size*2,main_upper_dist_y+extrusion_size,gantry_connector_thickness], align=[-1,0,1]);

        }

        // cut out z rod mounting clamp nut traps and screw holes
        translate([0,0,extrusion_size/2])
        translate([upper_width_extra/2, 0, 0])
        for(i=[-1,1])
        {
            translate([-.1, i*zmotor_mount_clamp_dist/2, 0])
            {
                screw_cut(zmotor_mount_clamp_nut, h=200, orient=[1,0,0], align=[1,0,0]);
            }
        }

        translate([0,0,extrusion_size+gantry_connector_thickness])
        /*#cubea(align=[0,0,1])*/

        translate([upper_width_extra/4, 0, 0])
        for(x=[-1,1])
        for(y=[-1,1])
        {
            translate([x*extrusion_thread_dia*2, y*main_upper_dist_y/2, 0])
            {
                screw_cut(extrusion_nut, h=gantry_connector_thickness+.1, nut_offset=true, orient=[0,0,-1], align=[0,0,-1]);
            }
        }

        // cutout for z rod
        translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
        translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,extrusion_size])
        fncylindera(d=zaxis_rod_d*1.01, h=extrusion_size*3, align=[0,0,0], orient=[0,0,1]);
    }
}

/*rotate([0,180,0])*/
/*zaxis_upper_gantry_zrod_connector();*/

include <config.scad>

module zaxis_upper_gantry_zrod_connector()
{
    upper_width_extra = main_upper_width-main_width;
    difference()
    {
        union()
        {
            hull()
            {
                // attach to z rod
                translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
                translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
                {
                    cubea([gantry_connector_thickness, zmotor_mount_clamp_width, extrusion_size+gantry_connector_thickness], align=[-1,0,1]);
                }

                // connect upper gantry
                translate([upper_width_extra/2, 0, 0])
                    translate([0,0,extrusion_size/2])
                    cubea([gantry_connector_thickness,main_upper_dist_y+extrusion_size,extrusion_size], align=[1,0,0], extrasize=[0,0,gantry_connector_thickness], extrasize_align=[0,0,1]);
            }

            translate([upper_width_extra/2, 0, 0])
                translate([0,0,extrusion_size])
                cubea([extrusion_size*2,main_upper_dist_y+extrusion_size,gantry_connector_thickness], align=[-1,0,1]);

        }

        // cut out z rod mounting clamp nut traps and screw holes
        translate([0,0,extrusion_size/2])
        translate([upper_width_extra/2, 0, 0])
        for(i=[-1,1])
        {
            translate([-1, i*zmotor_mount_clamp_dist/2, 0])
            {
                fncylindera(fn=6, d=zmotor_mount_clamp_nut_dia*1.05, h=zmotor_mount_clamp_nut_thick*1.05, orient=[1,0,0], align=[1,0,0]);

                fncylindera(d=zmotor_mount_clamp_thread_dia, h=100, orient=[1,0,0], align=[1,0,0]);
            }
        }

        translate([0,0,extrusion_size/2])
        translate([upper_width_extra/4, 0, 0])
        for(x=[-1,1])
        for(y=[-1,1])
        {
            translate([x*extrusion_thread_dia*2, y*main_upper_dist_y/2, -1])
            {
                fncylindera(d=extrusion_thread_dia, h=100, orient=[0,0,1], align=[1,0,1]);
            }
        }

        // cutout for z rod
        translate([lookup(NemaSideSize,zaxis_motor)/2, 0, 0])
        translate([(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,extrusion_size])
        fncylindera(d=zaxis_rod_d*1.01, h=extrusion_size*3, align=[0,0,0], orient=[0,0,1]);
    }
}

/*rotate([0,180,0])*/
/*zaxis_upper_gantry_zrod_connector();*/


Changed calls to child() to children()

Changed calls to child() to children()

//---------------------------------------------------------------
//-- Openscad Attachment library
//-- Attach parts easily. Make your designs more reusable and clean
//---------------------------------------------------------------
//-- This is a component of the obiscad opescad tools by Obijuan
//-- (C) Juan Gonzalez-Gomez (Obijuan)
//-- Sep-2012
//---------------------------------------------------------------
//-- Released under the GPL license
//---------------------------------------------------------------

use <vector.scad>

// default connector
DefCon = [[0,0,0],[0,0,1],0,0,0];

// Connector getter functions

function connector_translation(c) 	= c[0];
function connector_axis(c) 		  	= c[1];
function connector_ang(c) 			= c[2];
function connector_thickness(c) 	= c[3];	   // the thickness of the mounting point
function connector_bore(c) 			= c[4];    // the required diameter of a fixing

//--------------------------------------------------------------------
//-- Draw a connector
//-- A connector is defined a 3-tuple that consist of a point
//--- (the attachment point), and axis (the attachment axis) and
//--- an angle the connected part should be rotate around the
//--  attachment axis
//--
//--- Input parameters:
//--
//--  Connector c = [p , v, ang] where:
//--
//--     p : The attachment point
//--     v : The attachment axis
//--   ang : the angle
//--------------------------------------------------------------------
module connector(c,clr="Gray")
{
  //-- Get the three components from the connector
  p = c[0];
  v = c[1];
  ang = c[2];

  //-- Draw the attachment poing
  color("Gray") point(p);

  //-- Draw the attachment axis vector (with a mark)

  translate(p)
    rotate(a=ang, v=v)
    color(clr) vector(unitv(v)*6, l_arrow=2, mark=true);
}

//-------------------------------------------------------------------------
//--  ATTACH OPERATOR
//--  This operator applies the necesary transformations to the
//--  child (attachable part) so that it is attached to the main part
//--
//--  Parameters
//--    a -> Connector of the main part
//--    b -> Connector of the attachable part
//-------------------------------------------------------------------------
module attach(a,b)
{
  //-- Get the data from the connectors
  pos1 = a[0];  //-- Attachment point. Main part
  v    = a[1];  //-- Attachment axis. Main part
  roll = a[2];  //-- Rolling angle

  pos2 = b[0];  //-- Attachment point. Attachable part
  vref = b[1];  //-- Atachment axis. Attachable part
                //-- The rolling angle of the attachable part is not used

  //-------- Calculations for the "orientate operator"------
  //-- Calculate the rotation axis
  //raxis = cross(vref,v);
  raxis = v[0]==vref[0] && v[1]==vref[1] ? [0,1,0] : cross(vref,v);

  //-- Calculate the angle between the vectors
  ang = anglev(vref,v);
  //--------------------------------------------------------.-

  //-- Apply the transformations to the child ---------------------------

  for (i=[0:$children-1])
  //-- Place the attachable part on the main part attachment point
  translate(pos1)
    //-- Orientate operator. Apply the orientation so that
    //-- both attachment axis are paralell. Also apply the roll angle
    rotate(a=roll, v=v)  rotate(a=ang, v=raxis)
      //-- Attachable part to the origin
      translate(-pos2)
		children(i);
}

module attachWithOffset(a,b,o) {
	// offsets attachment point on a by o

	newa = [
		[
			a[0][0] + o[0],
			a[0][1] + o[1],
			a[0][2] + o[2]
		],
		a[1],
		a[2]
	];

	for (i=[0:$children-1])
		attach(newa,b) children(i);
}

// threads along neg z axis, starting at z=0 with first part
// up to 12 children
module threadTogether(a) {
	echo($children);
	children(0);
	if ($children>1)
		translate([0,0,-a[0]])
		children(1);
	if ($children>2)
		translate([0,0,-a[0]-a[1]])
		children(2);
	if ($children>3)
		translate([0,0,-a[0]-a[1]-a[2]])
		children(3);
	if ($children>4)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]])
		children(4);
	if ($children>5)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]])
		children(5);
	if ($children>6)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]])
		children(6);
	if ($children>7)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]])
		children(7);
	if ($children>8)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]])
		children(8);
	if ($children>9)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]-a[8]])
		children(9);
	if ($children>10)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]-a[8]-a[9]])
		children(10);
	if ($children>11)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]-a[8]-a[9]-a[10]])
		children(11);
}

//---------------------------------------------------------------
//-- Openscad Attachment library
//-- Attach parts easily. Make your designs more reusable and clean
//---------------------------------------------------------------
//-- This is a component of the obiscad opescad tools by Obijuan
//-- (C) Juan Gonzalez-Gomez (Obijuan)
//-- Sep-2012
//---------------------------------------------------------------
//-- Released under the GPL license
//---------------------------------------------------------------

use <vector.scad>

// default connector
DefCon = [[0,0,0],[0,0,1],0,0,0];

// Connector getter functions

function connector_translation(c) 	= c[0];
function connector_axis(c) 		  	= c[1];
function connector_ang(c) 			= c[2];
function connector_thickness(c) 	= c[3];	   // the thickness of the mounting point
function connector_bore(c) 			= c[4];    // the required diameter of a fixing

//--------------------------------------------------------------------
//-- Draw a connector
//-- A connector is defined a 3-tuple that consist of a point
//--- (the attachment point), and axis (the attachment axis) and
//--- an angle the connected part should be rotate around the
//--  attachment axis
//--
//--- Input parameters:
//--
//--  Connector c = [p , v, ang] where:
//--
//--     p : The attachment point
//--     v : The attachment axis
//--   ang : the angle
//--------------------------------------------------------------------
module connector(c,clr="Gray")
{
  //-- Get the three components from the connector
  p = c[0];
  v = c[1];
  ang = c[2];

  //-- Draw the attachment poing
  color("Gray") point(p);

  //-- Draw the attachment axis vector (with a mark)

  translate(p)
    rotate(a=ang, v=v)
    color(clr) vector(unitv(v)*6, l_arrow=2, mark=true);
}

//-------------------------------------------------------------------------
//--  ATTACH OPERATOR
//--  This operator applies the necesary transformations to the
//--  child (attachable part) so that it is attached to the main part
//--
//--  Parameters
//--    a -> Connector of the main part
//--    b -> Connector of the attachable part
//-------------------------------------------------------------------------
module attach(a,b)
{
  //-- Get the data from the connectors
  pos1 = a[0];  //-- Attachment point. Main part
  v    = a[1];  //-- Attachment axis. Main part
  roll = a[2];  //-- Rolling angle

  pos2 = b[0];  //-- Attachment point. Attachable part
  vref = b[1];  //-- Atachment axis. Attachable part
                //-- The rolling angle of the attachable part is not used

  //-------- Calculations for the "orientate operator"------
  //-- Calculate the rotation axis
  //raxis = cross(vref,v);
  raxis = v[0]==vref[0] && v[1]==vref[1] ? [0,1,0] : cross(vref,v);

  //-- Calculate the angle between the vectors
  ang = anglev(vref,v);
  //--------------------------------------------------------.-

  //-- Apply the transformations to the child ---------------------------

  for (i=[0:$children-1])
  //-- Place the attachable part on the main part attachment point
  translate(pos1)
    //-- Orientate operator. Apply the orientation so that
    //-- both attachment axis are paralell. Also apply the roll angle
    rotate(a=roll, v=v)  rotate(a=ang, v=raxis)
      //-- Attachable part to the origin
      translate(-pos2)
		child(i);
}

module attachWithOffset(a,b,o) {
	// offsets attachment point on a by o

	newa = [
		[
			a[0][0] + o[0],
			a[0][1] + o[1],
			a[0][2] + o[2]
		],
		a[1],
		a[2]
	];

	for (i=[0:$children-1])
		attach(newa,b) child(i);
}

// threads along neg z axis, starting at z=0 with first part
// up to 12 children
module threadTogether(a) {
	echo($children);
	child(0);
	if ($children>1)
		translate([0,0,-a[0]])
		child(1);
	if ($children>2)
		translate([0,0,-a[0]-a[1]])
		child(2);
	if ($children>3)
		translate([0,0,-a[0]-a[1]-a[2]])
		child(3);
	if ($children>4)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]])
		child(4);
	if ($children>5)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]])
		child(5);
	if ($children>6)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]])
		child(6);
	if ($children>7)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]])
		child(7);
	if ($children>8)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]])
		child(8);
	if ($children>9)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]-a[8]])
		child(9);
	if ($children>10)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]-a[8]-a[9]])
		child(10);
	if ($children>11)
		translate([0,0,-a[0]-a[1]-a[2]-a[3]-a[4]-a[5]-a[6]-a[7]-a[8]-a[9]-a[10]])
		child(11);
}


hut version draft

hut version draft

use <closet_hinge.scad>

module shell(extra_size)
{
  cube_size=100;

  difference()
  {
    resize([60, 60, 70] + extra_size*[1,1,1])
      sphere(r=25);
    // front cut
    translate(cube_size*[-1/2, -1, -1/2] + [0, -20, 0])
      cube(cube_size*[1,1,1]);
    // bottom cut
    translate(cube_size*[-1/2, -1/2, -1])
      cube(cube_size*[1,1,1]);
  }
}

module cover()
{
  difference()
  {
    shell(3);
    shell(0);
  }
}

%translate([-21/2, -41/2, 0])
  closet_hinge();
cover();


The holes for the resistor leads were made larger.

resisitorStand();

module resisitorStand()
{
    resistorHolder();
}

module resistorHolder(baseLengthX = 24,
                      baseLengthY = 15,
                      baseLengthZ = 5,

                      towerLengthX = 6,
                      towerLengthY = 15,
                      towerLengthZ = 21)
{
    difference()
    {
        resistorHolderUnion(baseLengthX,
                      baseLengthY ,
                      baseLengthZ ,

                      towerLengthX,
                      towerLengthY,
                      towerLengthZ);

          shafts();
    }

}

module resistorHolderUnion(baseLengthX,
                      baseLengthY ,
                      baseLengthZ ,

                      towerLengthX,
                      towerLengthY,
                      towerLengthZ)
{
    union()
    {
        base(xLength=baseLengthX,
             yLength=baseLengthY,
             zLength=baseLengthZ);

        for ( i = [0 : 1] )
        {
            xIncrement = (towerLengthX/4.0) + 10;
            xTranslate = i * xIncrement;
            translate([xTranslate, 0, 0])
            tower(xLength=towerLengthX,
                  yLength=towerLengthY,
                  zLength=towerLengthZ);
        }
    }
}

module shaft(xLength, zLength)
{
    cylinder (h = 130,
              r=1.6,
              $fn=100
    );
}

module shafts()
{

}

module tower(xLength, yLength, zLength)
{
    difference()
    {
        cube([xLength, yLength, zLength]);

        color("blue")
        rotate([-20, 0, 0])
        translate([xLength,//xLength/2.0,
                   -1,
                   -10])
        shaft(xLength, zLength);
    }
}

module base(xLength, yLength, zLength)
{
    cube([xLength, yLength, zLength]);
}

resisitorStand();

module resisitorStand(baseLengthX = 24,
                      baseLengthY = 15,
                      baseLengthZ = 5,

                      towerLengthX = 6,
                      towerLengthY = 15,
                      towerLengthZ = 25)
{
    union()
    {
        base(xLength=baseLengthX,
             yLength=baseLengthY,
             zLength=baseLengthZ);

        for ( i = [0 : 1] )
        {
            xIncrement = (towerLengthX/4.0) + 10;
            xTranslate = i * xIncrement;
            translate([xTranslate, 0, 0])
            tower(xLength=towerLengthX,
                  yLength=towerLengthY,
                  zLength=towerLengthZ);
        }
    }
}

module shaft(xLength, zLength)
{
    cylinder (h = 130,
              r=0.8,
              $fn=100
    );
}

module tower(xLength, yLength, zLength)
{
    difference()
    {
        cube([xLength, yLength, zLength]);

        color("blue")

        rotate([-25, 0, 0])

        translate([xLength/2.0,
                   -2,
                   0])

        shaft(xLength, zLength);
    }
}

module base(xLength, yLength, zLength)
{
    cube([xLength, yLength, zLength]);
}


model of the element for holding string to troley

eps = 0.01;
spacing = 0.5;
d = 13;
dh = 8;

x_raw = 30.9;
y_raw = 22.9;
z_raw = 8.2;
x = x_raw - 2*spacing;
y = y_raw + dh + dh/2;
z = z_raw - 2*spacing;

cut = (x - d)/2;
echo(cut);

difference()
{
  cube([x, y, z]);
  for(dx=[0, x-cut])
    translate([dx, y_raw, -eps])
      #cube([cut, dh, z + 2*eps]);
}

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