Edited header, and removed module call up.

// MicroSwitch v1.0 by Gyrobot
// http://www.gyrobot.co.uk
//
// Default values based upon :
// Farnell P/N : 2352329
// Omron Electronic Components P/N : SS-01GLT
//
// Datum X is centre of mounting hole with X pointing away from mounting slot.
// Datum Y is pointing away from terminals towards the lever.
// Datum Z is in on base of model.
//
// Parameters :
//
// ms_length 			= Length of body in X.
// ms_width 			= Width of body in Y.
// ms_height 			= Height (thickness) of body in Z.
// ms_datxoffset		= X Position of lower left corner of body from Datum hole.
// ms_datyoffset 		= Y Position of lower left corner of body from Datum hole.
// ms_orientation		= Defines whether the switch is mounted left or right (0:1).
// ms_hole_diam		= Size of Datum mounting hole and slot width of second hole.
// ms_xholepitch		= Mounting hole X pitch.
// ms_yholepitch		= Mounting hole Y pitch.
// ms_hole_slot_length	= Slot length of second mounting hole.
// ms_lever_length		= Length of lever.
// ms_lever_width		= Width of lever.
// ms_lever_thickness	= Thickness of lever.
// ms_lever_height		= Height of lever (OP) from Datum hole.
// ms_tab_length		= Length of terminal tab from Datum hole.
// ms_tab_width		= Width of terminal tab.
// ms_tab_thickness	= Thickness of terminal tab.
// ms_tab_hole_diam	= Diameter of terminal tab hole.
//

module microswitch(ms_length = 19.8, ms_width = 10.2, ms_height = 6.4, ms_datxoffset = -14.6, ms_datyoffset = -2.5, ms_orientation = 0, ms_hole_diam = 2.35, ms_xholepitch = 9.5, ms_yholepitch = 0, ms_hole_slot_length = 0.15, ms_lever_length = 14.5, ms_lever_width = 3.6, ms_lever_thickness = 0.3, ms_lever_height = 8.8, ms_tab_length = 6.4, ms_tab_width = 3.2, ms_tab_thickness = 0.3, ms_tab_hole_diam = 1.6){

	cutout_offset = 0.7;
	foot_offset = ms_datyoffset - 0.4;

	mirror ([ms_orientation, 0, 0]){
		// Mirror to provide a left or right mounted switch.
		//
		translate ([ms_datxoffset, ms_datyoffset, ms_height / 2]){
			//Move datum position.
			//
			color("DarkSlateGray")
			linear_extrude(ms_height, center=true){
				//
				// Body
				//
				difference(){
					union(){
						//Add all Additive profiles together, place any extras here.
						//
						square ([ms_length, ms_width]); //Main body cuboid.
						translate ([-ms_datxoffset, -ms_datyoffset])
							square ([ms_hole_diam, foot_offset * -2], center=true);
						translate ([-ms_datxoffset - ms_xholepitch - ms_hole_slot_length / 2, -ms_datyoffset + ms_yholepitch])
							square ([ms_hole_diam, foot_offset * -2], center=true);

					}
					union(){
						//Add all Subtractive profiles together, place any extras here.
						//
						translate ([ms_length / 2, ms_width - cutout_offset]) // Move corner cutout.
							square ([ms_length, ms_width]); // Corner cutout.
						translate ([-ms_datxoffset, -ms_datyoffset]) // Move datum hole.
							circle (d = ms_hole_diam, $fn = 32); // Remove datum hole.
						translate ([-ms_datxoffset - ms_xholepitch - ms_hole_slot_length / 2, -ms_datyoffset + ms_yholepitch]){ // Move second mounting hole (slot)
							// Second mounting hole (slot)
							hull(){
								circle (d = ms_hole_diam, $fn = 32);
								translate ([ms_hole_slot_length, 0]) // Move circle to create slot.
									circle (d = ms_hole_diam, $fn = 32);
							}
						}
					}
				}
			}
			color("Silver")
			linear_extrude(ms_lever_width, center=true){
				//
				// Lever
				//
				translate([2.5 ,+ ms_lever_height - ms_datyoffset,0]) // Move lever to position
					mirror([0, 1, 0]) // Mirror lever to invert shape
						union (){
							//Add all Additive profiles together, place any extras here.
							//
							square ([ms_lever_length + 2.5 , ms_lever_thickness]);
							square ([ms_lever_thickness,ms_width / 2]);
						}
			}
			for ( x = [1.6, 10.4, 17.7]){
				color ("Silver")
				translate ([x, -ms_tab_length - ms_datyoffset, 0])
					terminal(ms_tab_length, ms_tab_width, ms_tab_thickness, ms_tab_hole_diam);
			}
		}
	}
}

//
// Terminal module for solder pad. Other terminal types are available.
//

module terminal (ms_tab_length, ms_tab_width, ms_tab_thickness, ms_tab_hole_diam){
	rotate ([0,90,0]){
		translate ([ms_tab_width / -2,0,0]) {
			linear_extrude(ms_tab_thickness, center=true){
				difference (){
					square ([ms_tab_width , ms_tab_length]);
					translate ([ms_tab_width / 2, ms_tab_width / 2, 0])
						circle (d = ms_tab_hole_diam, $fn = 32);
				}
			}
		}
	}
}

microswitch(ms_orientation=0);


cable protection board

cable protection board

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


fanduct: only show controls in debug_mode

include <config.scad>
include <fanduct.h>

use <scad-utils/transformations.scad>
use <scad-utils/lists.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/sweep.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/skin.scad>
use <thing_libutils/misc.scad>
use <thing_libutils/splines.scad>
use <thing_libutils/sweep.scad>
use <thing_libutils/transforms.scad>
use <thing_libutils/shapes.scad>
use <thing_libutils/attach.scad>
use <thing_libutils/naca_sweep.scad>
include <fan_5015S.scad>

// helper functions to work on headered-arrays (where first entry is column headers)
function nSpline_header(S, N) =
let(slice = v_slice(S,start=1))
concat(
    [S[0]],
    nSpline(slice, N)
    );

// data for duct geometry
// ss parameter is initial size of duct (e.g. for fan throat/output)
// returned data has a header row
// warning, don't set r to 0 or rendering breaks!
function gen_data(ss) = [
    [       "Tx","Ty","Tz",     "Sx",   "Sy", "Rx", "Ry",  "r"],
    [     ss.x/4, -27,  55,   ss.x/2,   ss.y,   13,    0,  .01],
    [ 2.5+ss.x/4, -25,  49, 5+ss.x/2, 1+ss.y,   13,    0,  .1 ],
    [         15, -18,  40,       11,     20,   13,    0,  .4 ],
    [         17,  -8,  20,       11,     17,   11,  -10,  .5 ],
    [         14,  -3,  10,        8,     15,    8,  -25,  .7 ],
    [         11,   0,   4,        6,     13,    0,  -45,  .8 ],
];

fanduct_data = gen_data(fanduct_throat_size_withwall);

module duct(A, fanduct_wallthick=2, N=100, d=2)
{
    // rounded bugs out when rendering if r value is 0 :/
    function shape_profile(size,r) = rounded_rectangle_profile(size=size,r=r);
    /*function shape_profile(size,r) = rectangle_profile(size);*/

    module showcontrols(V)
    {
        function gen_T(V) =
        [
           for (i=[0:len(V)-2])
           let(R = vec3(geth(V,["Rx","Ry"],i)))
           let(T = geth(V,["Tx","Ty","Tz"],i))
           translation(T)*rotation(v_mul(R,[1,-1,1]))
        ];

        T = gen_T(A);
        for (i=[0:len(T)-1])
        let(t=T[i])
        multmatrix(t)
        color("red")
        let(S = [geth(A,"Sx",i),geth(A,"Sy",i)])
        let(r = geth(A,"r",i))
        let(r_ = [.5*r*S.x, .5*r*S.y])
        let(h=.5)
        difference()
        {
            linear_extrude(height=h,center=true)
            polygon(shape_profile(size=S+[1,1], r=r_));

            linear_extrude(height=h+.1,center=true)
            polygon(shape_profile(size=S, r=r_));

            /*torus(r=a[3], radial_width=1.5);*/
        }

        function gen_dat(V) =
           [
           for (i=[0:len(V)-2])
               let(S = geth(V,["Sx","Sy"],i))
               let(R = vec3(geth(V,["Rx","Ry"],i)))
               let(T = geth(V,["Tx","Ty","Tz"],i))
               let(dat = R_(R.x, R.y, R.z, v=to_3d(circle_profile(r=.5))))
               T_(T.x,T.y,T.z, dat)
           ];
        outer = gen_dat(nSpline_header(A,N));    // outer skin
        skin(outer, close = true, slices = true);
    }

    // generate transformed shapes
    function gen_dat(V) =
       [
       for (i=[0:len(V)-2])
           let(S = geth(V,["Sx","Sy"],i))
           let(r = [S.x*.5*geth(V,"r",i), S.y*.5*geth(V,"r",i)])
           let(R = vec3(geth(V,["Rx","Ry"],i)))
           let(T = geth(V,["Tx","Ty","Tz"],i))
           let(dat = R_(R.x, R.y, R.z, v=to_3d(shape_profile(size=S,r=r))))
           T_(T.x,T.y,T.z, dat)
       ];

    // inner skin data: modify tube diameter
    function modify_inner(S, subtract) = array_header_col_subtract(S, ["Sx", "Sy"], subtract);

    module sweepshape(V_outer,interp=true)
    {
        // inner skin is outer, but smaller size and reversed (so it will go back to start and join)
        V_inner = modify_inner(reverse_header(V_outer), fanduct_wallthick);
        if(interp)
        {
            outer = gen_dat(nSpline_header(V_outer,N));    // outer skin
            inner = gen_dat(nSpline_header(V_inner,N));    // inner skin
            sweep(concat(outer, inner), close = true, showslices = false);
            /*sweep(outer, close = true, showslices = false);*/
            /*skin(concat(outer, inner), loop=true);*/
        }
        else
        {
            outer = gen_dat(V_outer);    // outer skin
            inner = gen_dat(V_inner);    // inner skin
            sweep(concat(outer, inner), close = true, showslices = true);
        }
    }

    function mirrorshape(S, size) =
    let(cols = header_col_index(S,["Tx","Rx","Ry"]))
    concat([S[0]],
    [
        for(i=[1:len(S)-1])
        [
        for(j=[0:len(S[0])-1])
            v_contains(cols,j) ? -S[i][j] :
            S[i][j]
        ]
    ]);

    // debug experiment, mirror + join path for both duct arms
    /*A_ = mirrorshape(A);*/
    /*A__ = reverse_header(A_);*/
    /*A___ = concat_header(A__,A);*/
    /*sweepshape(A___,true);*/

    if($debug_mode)
    {
        /*tx(15)*/
        /*sweep(gen_dat(A), close = false, slices = true);*/

        /*tx(-15)*/
        /*showcontrols(A);*/
    }

    material(Mat_Plastic)
    sweepshape(A,true);
}

module mirrorcopy(axis)
{
    children();
    mirror(axis)
    children();
}

module fanduct_throat(throat_seal_h)
{
    difference()
    {
        union()
        {
            hull()
            {
                ty((fanduct_throat_size_withwall.y)/2)
                cubea([fanduct_throat_size.x,fanduct_throat_size.y,throat_seal_h]+XY*fanduct_wallthick,align=Z-Y);

                tz(seal_height)
                ty(fanduct_throat_size.y/2 - 47)
                tz(11.34/2)
                cylindera(h=fanduct_throat_size_withwall.x, d=7, orient=X);
            }

        }

        tz(-.1)
        cubea([fanduct_throat_size.x,fanduct_throat_size.y,1000],align=Z);

        seal_height = 4;
        tz(seal_height)
        {
            ty((fanduct_throat_size.y)/2)
            cubea([fanduct_throat_size.x,1000,1000],align=Z-Y, extra_size=.1*Y, extra_align=-Z);

            ty(-(fanduct_throat_size_withwall.y)/2)
            tz(-5)
            cubea([fanduct_throat_size.x,1000,1000],align=Z-Y, extra_size=.1*Y, extra_align=-Z);

            tz(-seal_height+2*mm)
            cubea([3.8,1000,1000],align=Z+Y);

            ty(fanduct_throat_size.y/2 - 47)
            tz(11.34/2)
            cylindera(h=1000, d=3.65, orient=X);
        }
    }

    ry(45)
    cubea([fanduct_wallthick/sqrt(2),fanduct_throat_size_withwall.y,fanduct_wallthick/sqrt(2)]);
}

module fanduct(part)
{
    $fn=is_build?$fn:48;

    A = fanduct_data;

    mirrorcopy(X)
    {
        duct(A=A, fanduct_wallthick=fanduct_wallthick, N=$fn, debug=true);
    }

    tx(-geth(A,"Tx",0))
    t(geth(A,["Tx","Ty","Tz"],0))
    r(geth(A,["Rx","Ry","Rz"],0))
    {
        throat_seal_h = 13*mm;

        material(Mat_Plastic)
        fanduct_throat(throat_seal_h);

        fanduct_conn_fan = [N,-Z];
        tz(2)
        attach(fanduct_conn_fan, fan_5015S_conn_flowoutput, 0)
        fan_5015S();
    }
}

module part_fanduct()
{
    ry(180)
    t(-13)
    t(-geth(fanduct_data,["Tx","Ty","Tz"],0))
    r(-geth(fanduct_data,["Rx","Ry","Rz"],0))
    difference()
    fanduct();
}

if(false)
{
   $debug_mode=true;
   fanduct();
}

include <config.scad>
include <fanduct.h>

use <scad-utils/transformations.scad>
use <scad-utils/lists.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/sweep.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/skin.scad>
use <thing_libutils/misc.scad>
use <thing_libutils/splines.scad>
use <thing_libutils/sweep.scad>
use <thing_libutils/transforms.scad>
use <thing_libutils/shapes.scad>
use <thing_libutils/attach.scad>
use <thing_libutils/naca_sweep.scad>
include <fan_5015S.scad>

// helper functions to work on headered-arrays (where first entry is column headers)
function nSpline_header(S, N) =
let(slice = v_slice(S,start=1))
concat(
    [S[0]],
    nSpline(slice, N)
    );

// data for duct geometry
// ss parameter is initial size of duct (e.g. for fan throat/output)
// returned data has a header row
// warning, don't set r to 0 or rendering breaks!
function gen_data(ss) = [
    [       "Tx","Ty","Tz",     "Sx",   "Sy", "Rx", "Ry",  "r"],
    [     ss.x/4, -27,  55,   ss.x/2,   ss.y,   13,    0,  .01],
    [ 2.5+ss.x/4, -25,  49, 5+ss.x/2, 1+ss.y,   13,    0,  .1 ],
    [         15, -18,  40,       11,     20,   13,    0,  .4 ],
    [         17,  -8,  20,       11,     17,   11,  -10,  .5 ],
    [         14,  -3,  10,        8,     15,    8,  -25,  .7 ],
    [         11,   0,   4,        6,     13,    0,  -45,  .8 ],
];

fanduct_data = gen_data(fanduct_throat_size_withwall);

module duct(A, fanduct_wallthick=2, N=100, d=2)
{
    // rounded bugs out when rendering if r value is 0 :/
    function shape_profile(size,r) = rounded_rectangle_profile(size=size,r=r);
    /*function shape_profile(size,r) = rectangle_profile(size);*/

    module showcontrols(V)
    {
        function gen_T(V) =
        [
           for (i=[0:len(V)-2])
           let(R = vec3(geth(V,["Rx","Ry"],i)))
           let(T = geth(V,["Tx","Ty","Tz"],i))
           translation(T)*rotation(v_mul(R,[1,-1,1]))
        ];

        T = gen_T(A);
        for (i=[0:len(T)-1])
        let(t=T[i])
        multmatrix(t)
        color("red")
        let(S = [geth(A,"Sx",i),geth(A,"Sy",i)])
        let(r = geth(A,"r",i))
        let(r_ = [.5*r*S.x, .5*r*S.y])
        let(h=.5)
        difference()
        {
            linear_extrude(height=h,center=true)
            polygon(shape_profile(size=S+[1,1], r=r_));

            linear_extrude(height=h+.1,center=true)
            polygon(shape_profile(size=S, r=r_));

            /*torus(r=a[3], radial_width=1.5);*/
        }

        function gen_dat(V) =
           [
           for (i=[0:len(V)-2])
               let(S = geth(V,["Sx","Sy"],i))
               let(R = vec3(geth(V,["Rx","Ry"],i)))
               let(T = geth(V,["Tx","Ty","Tz"],i))
               let(dat = R_(R.x, R.y, R.z, v=to_3d(circle_profile(r=.5))))
               T_(T.x,T.y,T.z, dat)
           ];
        outer = gen_dat(nSpline_header(A,N));    // outer skin
        skin(outer, close = true, slices = true);
    }

    // generate transformed shapes
    function gen_dat(V) =
       [
       for (i=[0:len(V)-2])
           let(S = geth(V,["Sx","Sy"],i))
           let(r = [S.x*.5*geth(V,"r",i), S.y*.5*geth(V,"r",i)])
           let(R = vec3(geth(V,["Rx","Ry"],i)))
           let(T = geth(V,["Tx","Ty","Tz"],i))
           let(dat = R_(R.x, R.y, R.z, v=to_3d(shape_profile(size=S,r=r))))
           T_(T.x,T.y,T.z, dat)
       ];

    // inner skin data: modify tube diameter
    function modify_inner(S, subtract) = array_header_col_subtract(S, ["Sx", "Sy"], subtract);

    module sweepshape(V_outer,interp=true)
    {
        // inner skin is outer, but smaller size and reversed (so it will go back to start and join)
        V_inner = modify_inner(reverse_header(V_outer), fanduct_wallthick);
        if(interp)
        {
            outer = gen_dat(nSpline_header(V_outer,N));    // outer skin
            inner = gen_dat(nSpline_header(V_inner,N));    // inner skin
            sweep(concat(outer, inner), close = true, showslices = false);
            /*sweep(outer, close = true, showslices = false);*/
            /*skin(concat(outer, inner), loop=true);*/
        }
        else
        {
            outer = gen_dat(V_outer);    // outer skin
            inner = gen_dat(V_inner);    // inner skin
            sweep(concat(outer, inner), close = true, showslices = true);
        }
    }

    function mirrorshape(S, size) =
    let(cols = header_col_index(S,["Tx","Rx","Ry"]))
    concat([S[0]],
    [
        for(i=[1:len(S)-1])
        [
        for(j=[0:len(S[0])-1])
            v_contains(cols,j) ? -S[i][j] :
            S[i][j]
        ]
    ]);

    // debug experiment, mirror + join path for both duct arms
    /*A_ = mirrorshape(A);*/
    /*A__ = reverse_header(A_);*/
    /*A___ = concat_header(A__,A);*/
    /*sweepshape(A___,true);*/

    if($preview_mode)
    {
        /*tx(15)*/
        /*sweep(gen_dat(A), close = false, slices = true);*/

        /*tx(-15)*/
        showcontrols(A);
    }

    material(Mat_Plastic)
    sweepshape(A,true);
}

module mirrorcopy(axis)
{
    children();
    mirror(axis)
    children();
}

module fanduct_throat(throat_seal_h)
{
    difference()
    {
        union()
        {
            hull()
            {
                ty((fanduct_throat_size_withwall.y)/2)
                cubea([fanduct_throat_size.x,fanduct_throat_size.y,throat_seal_h]+XY*fanduct_wallthick,align=Z-Y);

                tz(seal_height)
                ty(fanduct_throat_size.y/2 - 47)
                tz(11.34/2)
                cylindera(h=fanduct_throat_size_withwall.x, d=7, orient=X);
            }

        }

        tz(-.1)
        cubea([fanduct_throat_size.x,fanduct_throat_size.y,1000],align=Z);

        seal_height = 4;
        tz(seal_height)
        {
            ty((fanduct_throat_size.y)/2)
            cubea([fanduct_throat_size.x,1000,1000],align=Z-Y, extra_size=.1*Y, extra_align=-Z);

            ty(-(fanduct_throat_size_withwall.y)/2)
            tz(-5)
            cubea([fanduct_throat_size.x,1000,1000],align=Z-Y, extra_size=.1*Y, extra_align=-Z);

            tz(-seal_height+2*mm)
            cubea([3.8,1000,1000],align=Z+Y);

            ty(fanduct_throat_size.y/2 - 47)
            tz(11.34/2)
            cylindera(h=1000, d=3.65, orient=X);
        }
    }

    ry(45)
    cubea([fanduct_wallthick/sqrt(2),fanduct_throat_size_withwall.y,fanduct_wallthick/sqrt(2)]);
}

module fanduct(part)
{
    $fn=is_build?$fn:48;

    A = fanduct_data;

    mirrorcopy(X)
    {
        duct(A=A, fanduct_wallthick=fanduct_wallthick, N=$fn, debug=true);
    }

    tx(-geth(A,"Tx",0))
    t(geth(A,["Tx","Ty","Tz"],0))
    r(geth(A,["Rx","Ry","Rz"],0))
    {
        throat_seal_h = 13*mm;

        material(Mat_Plastic)
        fanduct_throat(throat_seal_h);

        fanduct_conn_fan = [N,-Z];
        tz(2)
        attach(fanduct_conn_fan, fan_5015S_conn_flowoutput, 0)
        fan_5015S();
    }
}

module part_fanduct()
{
    ry(180)
    t(-13)
    t(-geth(fanduct_data,["Tx","Ty","Tz"],0))
    r(-geth(fanduct_data,["Rx","Ry","Rz"],0))
    difference()
    fanduct();
}

fanduct();
/*part_fanduct();*/


xcarriage: More work

xcarriage: More work

use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
use <bearings.scad>

include <config.scad>

xaxis_carriage_bearing_distance = 8;
xaxis_carriage_padding = 2;
xaxis_carriage_mount_distance = 23;
xaxis_carriage_mount_offset_z = 0;
xaxis_carriage_teeth_height=xaxis_belt_width*1.5;
xaxis_carriage_mount_screws = ThreadM4;

xaxis_carriage_conn = [[0, -xaxis_bearing[1]/2 - xaxis_carriage_bearing_offset_z,0], [0,0,0]];

module horizontal_bearing_holes(bearing_type)
{
    translate([0,bearing_type[1]/2 + xaxis_carriage_bearing_offset_z,0])
    {
        // Main bearing cut
        difference()
        {
            fncylindera(h=bearing_type[2], d=bearing_type[1], orient=[1,0,0]);
        }

        difference()
        {
            union()
            {
                for(i=[-1,1])
                    translate([i*bearing_type[3]/2,0,0])
                        fncylindera(h=ziptie_width, d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness, orient=[1,0,0]);
            }
            fncylindera(h=bearing_type[2], d=bearing_type[1]+ziptie_bearing_distance, orient=[1,0,0]);
        }

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

module x_carriage_base()
{
    bottom_width = xaxis_bearing[2] + 2*xaxis_carriage_padding;
    top_width = xaxis_bearing[2]*2 + xaxis_carriage_bearing_distance + 2*xaxis_carriage_padding;
    thickness = xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z;

    difference()
    {
        union()
        {
            hull()
            {
                // top bearings
                translate([0,0,xaxis_rod_distance/2])
                    cubea([top_width, thickness, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2], align=[0,1,0]);

                /*#cubea([top_width,xaxis_carriage_bearing_offset_z,xaxis_rod_distance/2], align=[0,1,0]);*/

                // bottom bearing
                translate([0,0,-xaxis_rod_distance/2])
                    cubea([bottom_width, thickness, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2], align=[0,1,0]);

            }

            translate([0,xaxis_carriage_beltpath_offset,0])
            {
                difference()
                {
                    translate([0,0,xaxis_pulley_d/2])
                        cubea([50, xaxis_carriage_teeth_height, 10], align=[0,0,-1]);
                }
            }
        }

        translate([0,xaxis_carriage_beltpath_offset+.1,0])
        {
            // Cut clearing space for the belt
            translate([0,0,-xaxis_pulley_d/2])
                cubea([500,xaxis_carriage_teeth_height,5], align=[0,0,0], extrasize=[0,0,4], extrasize_align=[0,0,1]);

            belt_thickness=1.5;
            for(i=[-1,1])
                translate([i*30,0,0])
                    cubea([15,xaxis_carriage_teeth_height,15-belt_thickness], align=[0,0,0]);

            // Cut in the middle for belt
            cubea([7,xaxis_carriage_teeth_height+.1,15], align=[0,0,0]);

            translate([0,0,xaxis_pulley_d/2])
            {
                // Belt slit
                cubea([500,xaxis_carriage_teeth_height,belt_thickness], align=[0,0,0]);

                // Teeth cuts
                teeth = 50;
                teeth_height = 2;
                translate([-belt_tooth_distance/2*teeth-.5,0,0])
                for(i=[0:teeth])
                {
                    translate([i*belt_tooth_distance,0,0])
                        cubea([belt_tooth_distance*belt_tooth_ratio,xaxis_carriage_teeth_height,teeth_height], align=[0,0,-1]);
                }
            }

            for(i=[-1,1])
            translate([i*50,0,0])
            %fncylindera(d=xaxis_pulley_d, h=xaxis_belt_width*1.2, orient=[0,1,0], align=[0,0,0]);
        }

    }
}

module x_carriage_holes()
{
    for(i=[-1,1])
    translate([i*(xaxis_bearing[2]/2+xaxis_carriage_bearing_distance/2),0,0])
    translate([0,0,xaxis_rod_distance/2])
    horizontal_bearing_holes(xaxis_bearing);

    translate([0,0,-xaxis_rod_distance/2])
    horizontal_bearing_holes(xaxis_bearing);

    // Extruder mounting holes
    translate([0,0,xaxis_carriage_mount_offset_z])
    for(j=[-1,1])
    for(i=[-1,1])
    {
        translate([i*xaxis_carriage_mount_distance/2,0,j*xaxis_carriage_mount_distance/2])
        {
            screw_dia = lookup(ThreadSize, xaxis_carriage_mount_screws);
            fncylindera(d=screw_dia, h=100, orient=[0,1,0]);
        }
    }
}

// Final part
module x_carriage(show_bearings=true)
{
    difference()
    {
        x_carriage_base();
        x_carriage_holes();
    }

    %if(show_bearings)
    {
        for(j=[-1,1])
        translate([0,xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z,0])
        translate([j*(xaxis_carriage_bearing_distance+xaxis_bearing[2])/2,0,0])
        translate([0, 0, xaxis_rod_distance/2])
                bearing(xaxis_bearing, orient=[1,0,0]);

        translate([0,xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z,0])
        translate([0, 0, -xaxis_rod_distance/2])
            bearing(xaxis_bearing, orient=[1,0,0]);
    }
}

/*x_carriage();*/

use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
use <bearings.scad>

include <config.scad>

xaxis_carriage_bearing_distance = 6;
xaxis_carriage_padding = 3;
xaxis_carriage_mount_distance = 30;
xaxis_carriage_mount_offset_z = 15;
xaxis_carriage_teeth_height=xaxis_belt_width*1.5;
xaxis_carriage_conn = [[0, -xaxis_bearing[1]/2 - xaxis_carriage_bearing_offset_z, 0],[0,1,0]];

module horizontal_bearing_holes(bearing_type)
{
    translate([0,0,bearing_type[1]/2 + xaxis_carriage_bearing_offset_z])
    {
        // Main bearing cut
        difference()
        {
            fncylindera(h=bearing_type[2], d=bearing_type[1], orient=[1,0,0]);
        }

        difference()
        {
            union()
            {
                for(i=[-1,1])
                    translate(v=[i*bearing_type[3]/2,0,0])
                        fncylindera(h=ziptie_width, d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness, orient=[1,0,0]);
            }
            fncylindera(h=bearing_type[2], d=bearing_type[1]+ziptie_bearing_distance, orient=[1,0,0]);
        }

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

module x_carriage_base()
{
    bottom_width = xaxis_bearing[2] + 2*xaxis_carriage_padding;
    top_width = xaxis_bearing[2]*2 + xaxis_carriage_bearing_distance + 2*xaxis_carriage_padding;
    thickness = xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z;

    hull()
    {
        // top bearings
        translate([0,xaxis_rod_distance/2,0])
            cubea(size = [top_width, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2, thickness], align=[0,0,1]);

        cubea([top_width,xaxis_rod_distance/2,xaxis_carriage_bearing_offset_z], align=[0,0,1]);

        translate([0,0,xaxis_carriage_beltpath_offset])
            cubea([top_width,xaxis_rod_distance/2,xaxis_carriage_teeth_height], align=[0,0,0]);

        // bottom bearing
        translate([0,-xaxis_rod_distance/2,0])
            cubea(size = [bottom_width, xaxis_bearing[1]+xaxis_carriage_padding+ziptie_bearing_distance*2, thickness], align=[0,0,1]);

    }
}

module x_carriage_beltcut()
{
    translate([0,0,xaxis_carriage_beltpath_offset+.1])
    {
        // Cut in the middle for belt
        cubea([4.5,13,xaxis_carriage_teeth_height], align=[0,0,0]);

        // Cut clearing space for the belt
        translate([0,-xaxis_pulley_d/2,0]) cubea([500,10,xaxis_carriage_teeth_height], align=[0,0,0]);

        //xaxis pulleys
        /*translate([0,0,xaxis_carriage_beltpath_offset])*/
        for(i=[-1,1])
        translate([i*50,0,0])
            %fncylindera(d=xaxis_pulley_d, h=xaxis_belt_width*1.2, orient=[0,0,1], align=[0,0,0]);

        translate([0,xaxis_pulley_d/2,0])
        {
            // Belt slit
            cubea([500,1,xaxis_carriage_teeth_height], align=[0,1,0]);

            // Teeth cuts
            teeth = 50;
            teeth_height = 3;
            translate([-belt_tooth_distance/2*teeth-.5,0,0])
            for(i=[0:teeth])
            {
                translate([i*belt_tooth_distance,0,0])
                cubea([belt_tooth_distance*belt_tooth_ratio,teeth_height,xaxis_carriage_teeth_height], align=[0,-1,0]);
            }
        }
    }
}

module x_carriage_holes(bearing_type){

    for ( i = [-1,1] )
        translate([i*(bearing_type[2]/2+xaxis_bearing_distance/2),0,0])
            translate([0,xaxis_rod_distance/2,0])
            horizontal_bearing_holes(xaxis_bearing);

    translate([0,-xaxis_rod_distance/2,0])
        horizontal_bearing_holes(xaxis_bearing);

    // Extruder mounting holes
    translate([0,xaxis_carriage_mount_offset_z,0])
        for ( i = [-1,1] )
        {
            translate([i*xaxis_carriage_mount_distance/2,0,0])
            {
                fncylindera(r=1.7, h=100);
                /*fncylindera(r=3.3, h=20, fn=6, align=[0,0,1]);*/
            }
        }
}

// Final part
module x_carriage(show_bearings=true)
{
    difference()
    {
        x_carriage_base();
        x_carriage_beltcut();
        x_carriage_holes(xaxis_bearing);
    }

    %if(show_bearings)
    {
        for(j=[-1,1])
        translate([0,0,xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z])
        translate([j*(xaxis_bearing_distance+xaxis_bearing[2])/2,0,0])
        translate([0, xaxis_rod_distance/2, 0])
                bearing(xaxis_bearing, orient=[1,0,0]);

        translate([0,0,xaxis_bearing[1]/2 + xaxis_carriage_bearing_offset_z])
        translate([0, -xaxis_rod_distance/2, 0])
            bearing(xaxis_bearing, orient=[1,0,0]);
    }
}

x_carriage();


Add operator repeatRotateMap()

Add operator repeatRotateMap()

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

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

/**
 * Repeats and rotates the children modules `count` times with the provided `interval`.
 *
 * @param Number [count] - The number of times the children must be repeated.
 * @param Number [angle] - The angle interval in which rotate the children.
 * @param Vector [axis] - The rotation axis around which rotate the children.
 * @param Vector [interval] - The interval between each repeated children.
 * @param Vector [origin] - The rotate origin.
 * @param Number [intervalX] - The X interval between each repeated children
 *                             (will overwrite the X coordinate in the `interval` vector).
 * @param Number [intervalY] - The Y interval between each repeated children
 *                             (will overwrite the Y coordinate in the `interval` vector).
 * @param Number [intervalZ] - The Z interval between each repeated children
 *                             (will overwrite the Z coordinate in the `interval` vector).
 * @param Number [axisX] - The X axis factor (will overwrite the X coordinate in the `axis` vector).
 * @param Number [axisY] - The Y axis factor (will overwrite the Y coordinate in the `axis` vector).
 * @param Number [axisZ] - The Z axis factor (will overwrite the Z coordinate in the `axis` vector).
 * @param Number [originX] - The X origin (will overwrite the X coordinate in the `origin` vector).
 * @param Number [originY] - The Y origin (will overwrite the Y coordinate in the `origin` vector).
 * @param Number [originZ] - The Z origin (will overwrite the Z coordinate in the `origin` vector).
 */
module repeatRotate(count    = 2,
                    angle    = DEGREES,
                    axis     = [0, 0, 1],
                    interval = [0, 0, 0],
                    origin   = [0, 0, 0],
                    center   = false,
                    intervalX, intervalY, intervalZ,
                    axisX, axisY, axisZ,
                    originX, originY, originZ) {

    interval = apply3D(interval, intervalX, intervalY, intervalZ);
    origin = apply3D(origin, originX, originY, originZ);
    angle = deg(angle);
    partAngle = angle / (angle % DEGREES ? count - 1 : count);
    axis = apply3D(axis, axisX, axisY, axisZ) * partAngle;
    offset = center ? -interval * (count - 1) / 2 : [0, 0, 0];

    for (i = [0 : count - 1]) {
        translate(offset + interval * i) {
            rotateOrigin(a=axis * i, o=origin) {
                children();
            }
        }
    }
}

/**
 * Repeats and rotates the children modules in two directions `count` times with the provided `interval`.
 *
 * @param Number [countX] - The number of times the children must be repeated along the X axis.
 * @param Number [countY] - The number of times the children must be repeated along the Y axis.
 * @param Number [angleX] - The angle interval in which rotate the children along the X axis.
 * @param Number [angleY] - The angle interval in which rotate the children along the Y axis.
 * @param Vector [axisX] - The rotation axis around which rotate the children along the X axis.
 * @param Vector [axisY] - The rotation axis around which rotate the children along the Y axis.
 * @param Vector [intervalX] - The interval between each repeated children along the X axis.
 * @param Vector [intervalY] - The interval between each repeated children along the Y axis.
 * @param Vector [originX] - The rotate origin along the X axis.
 * @param Vector [originY] - The rotate origin along the Y axis.
 * @param Boolean [center] - Whether or not center the repeated shapes.
 */
module repeatRotate2D(countX    = 2,
                      countY    = 2,
                      angleX    = DEGREES,
                      angleY    = DEGREES,
                      axisX     = [0, 0, 1],
                      axisY     = [0, 1, 0],
                      intervalX = [0, 0, 0],
                      intervalY = [0, 0, 0],
                      originX   = [0, 0, 0],
                      originY   = [0, 0, 0],
                      center    = false) {

    repeatRotate(count=countY, interval=vector3D(intervalY), angle=angleY, axis=vector3D(axisY), origin=originY, center=center) {
        repeatRotate(count=countX, interval=vector3D(intervalX), angle=angleX, axis=vector3D(axisX), origin=originX, center=center) {
            children();
        }
    }
}

/**
 * Repeats and rotates the children modules in three directions `count` times with the provided `interval`.
 *
 * @param Number [countX] - The number of times the children must be repeated along the X axis.
 * @param Number [countY] - The number of times the children must be repeated along the Y axis.
 * @param Number [countZ] - The number of times the children must be repeated along the Z axis.
 * @param Number [angleX] - The angle interval in which rotate the children along the X axis.
 * @param Number [angleY] - The angle interval in which rotate the children along the Y axis.
 * @param Number [angleZ] - The angle interval in which rotate the children along the Z axis.
 * @param Vector [axisX] - The rotation axis around which rotate the children along the X axis.
 * @param Vector [axisY] - The rotation axis around which rotate the children along the Y axis.
 * @param Vector [axisZ] - The rotation axis around which rotate the children along the Z axis.
 * @param Vector [intervalX] - The interval between each repeated children along the X axis.
 * @param Vector [intervalY] - The interval between each repeated children along the Y axis.
 * @param Vector [intervalZ] - The interval between each repeated children along the Z axis.
 * @param Vector [originX] - The rotate origin along the X axis.
 * @param Vector [originY] - The rotate origin along the Y axis.
 * @param Vector [originZ] - The rotate origin along the Z axis.
 * @param Boolean [center] - Whether or not center the repeated shapes.
 */
module repeatRotate3D(countX    = 2,
                      countY    = 2,
                      countZ    = 2,
                      angleX    = DEGREES,
                      angleY    = DEGREES,
                      angleZ    = DEGREES,
                      axisX     = [0, 0, 1],
                      axisY     = [0, 1, 0],
                      axisZ     = [1, 0, 0],
                      intervalX = [0, 0, 0],
                      intervalY = [0, 0, 0],
                      intervalZ = [0, 0, 0],
                      originX   = [0, 0, 0],
                      originY   = [0, 0, 0],
                      originZ   = [0, 0, 0],
                      center    = false) {

    repeatRotate(count=countZ, interval=vector3D(intervalZ), angle=angleZ, axis=vector3D(axisZ), origin=originZ, center=center) {
        repeatRotate(count=countY, interval=vector3D(intervalY), angle=angleY, axis=vector3D(axisY), origin=originY, center=center) {
            repeatRotate(count=countX, interval=vector3D(intervalX), angle=angleX, axis=vector3D(axisX), origin=originX, center=center) {
                children();
            }
        }
    }
}

/**
 * Repeats the children modules on every angle given in the `map`.
 *
 * @param Vector[] map - The list of angles at which place the children.
 * @param Vector [offset] - An offset to add before the ratation is applied.
 * @param Number [x] - The X-coordinate to apply on the offset.
 * @param Number [y] - The Y-coordinate to apply on the offset.
 * @param Number [z] - The Z-coordinate to apply on the offset.
 */
module repeatRotateMap(map, offset, x, y, z) {
    offset = apply3D(offset, x, y, z);

    for (at = map) {
        rotate(vector3D(at)) {
            translate(offset) {
                children();
            }
        }
    }
}

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

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

/**
 * Repeats and rotates the children modules `count` times with the provided `interval`.
 *
 * @param Number [count] - The number of times the children must be repeated.
 * @param Number [angle] - The angle interval in which rotate the children.
 * @param Vector [axis] - The rotation axis around which rotate the children.
 * @param Vector [interval] - The interval between each repeated children.
 * @param Vector [origin] - The rotate origin.
 * @param Number [intervalX] - The X interval between each repeated children
 *                             (will overwrite the X coordinate in the `interval` vector).
 * @param Number [intervalY] - The Y interval between each repeated children
 *                             (will overwrite the Y coordinate in the `interval` vector).
 * @param Number [intervalZ] - The Z interval between each repeated children
 *                             (will overwrite the Z coordinate in the `interval` vector).
 * @param Number [axisX] - The X axis factor (will overwrite the X coordinate in the `axis` vector).
 * @param Number [axisY] - The Y axis factor (will overwrite the Y coordinate in the `axis` vector).
 * @param Number [axisZ] - The Z axis factor (will overwrite the Z coordinate in the `axis` vector).
 * @param Number [originX] - The X origin (will overwrite the X coordinate in the `origin` vector).
 * @param Number [originY] - The Y origin (will overwrite the Y coordinate in the `origin` vector).
 * @param Number [originZ] - The Z origin (will overwrite the Z coordinate in the `origin` vector).
 */
module repeatRotate(count    = 2,
                    angle    = DEGREES,
                    axis     = [0, 0, 1],
                    interval = [0, 0, 0],
                    origin   = [0, 0, 0],
                    center   = false,
                    intervalX, intervalY, intervalZ,
                    axisX, axisY, axisZ,
                    originX, originY, originZ) {

    interval = apply3D(interval, intervalX, intervalY, intervalZ);
    origin = apply3D(origin, originX, originY, originZ);
    angle = deg(angle);
    partAngle = angle / (angle % DEGREES ? count - 1 : count);
    axis = apply3D(axis, axisX, axisY, axisZ) * partAngle;
    offset = center ? -interval * (count - 1) / 2 : [0, 0, 0];

    for (i = [0 : count - 1]) {
        translate(offset + interval * i) {
            rotateOrigin(a=axis * i, o=origin) {
                children();
            }
        }
    }
}

/**
 * Repeats and rotates the children modules in two directions `count` times with the provided `interval`.
 *
 * @param Number [countX] - The number of times the children must be repeated along the X axis.
 * @param Number [countY] - The number of times the children must be repeated along the Y axis.
 * @param Number [angleX] - The angle interval in which rotate the children along the X axis.
 * @param Number [angleY] - The angle interval in which rotate the children along the Y axis.
 * @param Vector [axisX] - The rotation axis around which rotate the children along the X axis.
 * @param Vector [axisY] - The rotation axis around which rotate the children along the Y axis.
 * @param Vector [intervalX] - The interval between each repeated children along the X axis.
 * @param Vector [intervalY] - The interval between each repeated children along the Y axis.
 * @param Vector [originX] - The rotate origin along the X axis.
 * @param Vector [originY] - The rotate origin along the Y axis.
 * @param Boolean [center] - Whether or not center the repeated shapes.
 */
module repeatRotate2D(countX    = 2,
                      countY    = 2,
                      angleX    = DEGREES,
                      angleY    = DEGREES,
                      axisX     = [0, 0, 1],
                      axisY     = [0, 1, 0],
                      intervalX = [0, 0, 0],
                      intervalY = [0, 0, 0],
                      originX   = [0, 0, 0],
                      originY   = [0, 0, 0],
                      center    = false) {

    repeatRotate(count=countY, interval=vector3D(intervalY), angle=angleY, axis=vector3D(axisY), origin=originY, center=center) {
        repeatRotate(count=countX, interval=vector3D(intervalX), angle=angleX, axis=vector3D(axisX), origin=originX, center=center) {
            children();
        }
    }
}

/**
 * Repeats and rotates the children modules in three directions `count` times with the provided `interval`.
 *
 * @param Number [countX] - The number of times the children must be repeated along the X axis.
 * @param Number [countY] - The number of times the children must be repeated along the Y axis.
 * @param Number [countZ] - The number of times the children must be repeated along the Z axis.
 * @param Number [angleX] - The angle interval in which rotate the children along the X axis.
 * @param Number [angleY] - The angle interval in which rotate the children along the Y axis.
 * @param Number [angleZ] - The angle interval in which rotate the children along the Z axis.
 * @param Vector [axisX] - The rotation axis around which rotate the children along the X axis.
 * @param Vector [axisY] - The rotation axis around which rotate the children along the Y axis.
 * @param Vector [axisZ] - The rotation axis around which rotate the children along the Z axis.
 * @param Vector [intervalX] - The interval between each repeated children along the X axis.
 * @param Vector [intervalY] - The interval between each repeated children along the Y axis.
 * @param Vector [intervalZ] - The interval between each repeated children along the Z axis.
 * @param Vector [originX] - The rotate origin along the X axis.
 * @param Vector [originY] - The rotate origin along the Y axis.
 * @param Vector [originZ] - The rotate origin along the Z axis.
 * @param Boolean [center] - Whether or not center the repeated shapes.
 */
module repeatRotate3D(countX    = 2,
                      countY    = 2,
                      countZ    = 2,
                      angleX    = DEGREES,
                      angleY    = DEGREES,
                      angleZ    = DEGREES,
                      axisX     = [0, 0, 1],
                      axisY     = [0, 1, 0],
                      axisZ     = [1, 0, 0],
                      intervalX = [0, 0, 0],
                      intervalY = [0, 0, 0],
                      intervalZ = [0, 0, 0],
                      originX   = [0, 0, 0],
                      originY   = [0, 0, 0],
                      originZ   = [0, 0, 0],
                      center    = false) {

    repeatRotate(count=countZ, interval=vector3D(intervalZ), angle=angleZ, axis=vector3D(axisZ), origin=originZ, center=center) {
        repeatRotate(count=countY, interval=vector3D(intervalY), angle=angleY, axis=vector3D(axisY), origin=originY, center=center) {
            repeatRotate(count=countX, interval=vector3D(intervalX), angle=angleX, axis=vector3D(axisX), origin=originX, center=center) {
                children();
            }
        }
    }
}


screws: tweak tolerances

screws: tweak tolerances

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

module screw_thread(thread, h=10, tolerance=1.00, orient=Z, align=N)
{
    assert(thread!=U, "screw_thread: thread is undef");
    // TODO render thread
    threadsize = get(ThreadSize, thread);

    material(Mat_Steel)
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

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

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

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(head=head, thread=thread);
    head_d = get_screw_head_d(head=head, thread=thread);
    material(Mat_Steel)
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket")
        {
            difference()
            {
                tz(-head_h/2)
                cylindera(d=head_d, h = fallback(override_h,head_h), align=Z);

                if(drive == "hex")
                {
                    cylindera(d = fn_radius(threadsize, 6), h = 1000, $fn = 6, align=Z);
                }
            }
        }
        else if(head=="button")
        {
            c = head_d;
            f = head_h*1.25;
            r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

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

            difference()
            {
                intersection()
                {
                    tz(-head_h/2)
                    scale([1,1,.5])
                    spherea(r = head_h, align=N);

                    tz(-head_h/2)
                    cylindera(d=head_d, h = fallback(override_h,head_h)/2, align=Z);
                }

                if(drive == "hex")
                {
                    // button head uses -0.5*mm smaller hex
                    tz(-head_h/2)
                    cylindera(d = fn_radius(threadsize-.5, 6), h = 1000, $fn = 6, align=Z);
                }
            }

        }
    }
}

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

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

module screw_nut(nut, thread, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(nut!=U, "screw_nut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    nut_thread = fallback(thread, get(NutThread, nut));
    h_ = fallback(override_h, nut_thick);
    material(Mat_Steel)
    size_align([nut_dia, nut_dia, h_], orient=orient, align=align)
    {
        difference()
        {
            cylindera($fn=nut_facets, d=nut_dia, h=h_);
            screw_thread(thread=nut_thread, h=h_+.2);
        }
    }
}

module screw_nut_cut(nut, tolerance=1.05, h=1000, orient=Z, align=N)
{
    assert(nut!=U, "screw_nut_cut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        translate([0,0,nut_thick/2])
        {
            tz(-.1)
            screw_nut(nut=nut, tolerance=tolerance, orient=Z, align=-Z);

            translate([0,0,-nut_thick-.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
            }
        }
    }
}

function nut_radius(nut) = outradius(get(NutWidthMin, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = 2*nut_radius(nut);

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

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

    tolerance = -.2*mm;
    nut_width_min = get(NutWidthMin, nut)+tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut)+tolerance;
    total_h = nut_h;
    size_align(size=[nut_dia, nut_dia, total_h], orient=orient, orient_ref=Z, align=align)
    {
        if(cut_screw)
        {
            translate(-nut_h/2*Z)
            translate(screw_offset*Z)
            screw_cut($show_vit=false, nut=nut, thread=thread_, with_nut=false, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }
        else
        {
            translate([0,0,nut_h/2+screw_offset])
            screw_thread_cut($show_vit=false, thread=thread_, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }

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

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

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

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

    }
}

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

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

if(false)
{
    nut1 = NutHexM3;
    stack(axis=X, dist = 10)
    {
        screw(nut=nut1, head="button", h=10, orient=-Z);
        screw(nut=nut1, head="socket", h=10, orient=-Z);
    }
}

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

module screw_thread(thread, h=10, tolerance=1.00, orient=Z, align=N)
{
    assert(thread!=U, "screw_thread: thread is undef");
    // TODO render thread
    threadsize = get(ThreadSize, thread);

    material(Mat_Steel)
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

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

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

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(head=head, thread=thread);
    head_d = get_screw_head_d(head=head, thread=thread);
    material(Mat_Steel)
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket")
        {
            difference()
            {
                tz(-head_h/2)
                cylindera(d=head_d, h = fallback(override_h,head_h), align=Z);

                if(drive == "hex")
                {
                    cylindera(d = fn_radius(threadsize, 6), h = 1000, $fn = 6, align=Z);
                }
            }
        }
        else if(head=="button")
        {
            c = head_d;
            f = head_h*1.25;
            r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

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

            difference()
            {
                intersection()
                {
                    tz(-head_h/2)
                    scale([1,1,.5])
                    spherea(r = head_h, align=N);

                    tz(-head_h/2)
                    cylindera(d=head_d, h = fallback(override_h,head_h)/2, align=Z);
                }

                if(drive == "hex")
                {
                    // button head uses -0.5*mm smaller hex
                    tz(-head_h/2)
                    cylindera(d = fn_radius(threadsize-.5, 6), h = 1000, $fn = 6, align=Z);
                }
            }

        }
    }
}

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

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

module screw_nut(nut, thread, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(nut!=U, "screw_nut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    nut_thread = fallback(thread, get(NutThread, nut));
    h_ = fallback(override_h, nut_thick);
    material(Mat_Steel)
    size_align([nut_dia, nut_dia, h_], orient=orient, align=align)
    {
        difference()
        {
            cylindera($fn=nut_facets, d=nut_dia, h=h_);
            screw_thread(thread=nut_thread, h=h_+.2);
        }
    }
}

module screw_nut_cut(nut, tolerance=1.05, h=1000, orient=Z, align=N)
{
    assert(nut!=U, "screw_nut_cut: nut is undef");

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        translate([0,0,nut_thick/2])
        {
            tz(-.1)
            screw_nut(nut=nut, tolerance=tolerance, orient=Z, align=-Z);

            translate([0,0,-nut_thick-.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
            }
        }
    }
}

function nut_radius(nut) = outradius(get(NutWidthMin, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = 2*nut_radius(nut);

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

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

    nut_width_min = get(NutWidthMin, nut);
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    total_h = nut_h;
    size_align(size=[nut_dia, nut_dia, total_h], orient=orient, orient_ref=Z, align=align)
    {
        if(cut_screw)
        {
            translate(-nut_h/2*Z)
            translate(screw_offset*Z)
            screw_cut($show_vit=false, nut=nut, thread=thread_, with_nut=false, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }
        else
        {
            translate([0,0,nut_h/2+screw_offset])
            screw_thread_cut($show_vit=false, thread=thread_, tolerance=1.1, h=screw_l, orient=-Z, align=Z);
        }

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

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

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

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

    }
}

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

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

if(false)
{
    nut1 = NutHexM3;
    stack(axis=X, dist = 10)
    {
        screw(nut=nut1, head="button", h=10, orient=-Z);
        screw(nut=nut1, head="socket", h=10, orient=-Z);
    }
}

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

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

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

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

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

}

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

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

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

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

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

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


attach: Attempt bugfix for the attach 1,-1 case (vector cross = 0, no rotation)

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

// From Obiscad
//----------------------------------------------------------
//--  Draw a point in the position given by the vector p
//----------------------------------------------------------
module point(p, r=0.7, fn, fnr=0.4)
{
    fn_= fn==undef ? (floor(2*(r)*PI/fnr)) : fn;
    translate(p)
    sphere(r=r,$fn=fn_);
}

//------------------------------------------------------------------
//-- Draw a vector poiting to the z axis
//-- This is an auxiliary module for implementing the vector module
//--
//-- Parameters:
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//--  mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//------------------------------------------------------------------
module vectorz(l=10, l_arrow=4, mark=false, fnr)
{
  //-- vector body length (not including the arrow)
  lb = l - l_arrow;

  //-- The vector is locatead at 0,0,0
  translate([0,0,lb/2])
  union() {

    //-- Draw the arrow
    translate([0,0,lb/2])
      fncylindera(r1=2/2, r2=0.2, h=l_arrow, fnr=fnr);

    //-- Draw the mark
    if (mark) {
      translate([0,0,lb/2+l_arrow/2])
      translate([1,0,0])
        cubea([2,0.3,l_arrow*0.8]);
    }

    //-- Draw the body
    fncylindera(r=1/2, h=lb, center=true, fnr=fnr);
  }

  //-- Draw a sphere in the vector base
  sphere(r=1/2, fnr);
}

//-----------------------------------------------------------------
//-- ORIENTATE OPERATOR
//--
//--  Orientate an object to the direction given by the vector v
//--  Parameters:
//--    v : Target orientation
//--    vref: Vector reference. It is the vector of the local frame
//--          of the object that want to be poiting in the direction
//--          of v
//--    roll: Rotation of the object around the v axis
//-------------------------------------------------------------------
module orientate(v,vref=[0,0,1], roll=0)
{
  //-- Calculate the rotation axis
  raxis = v_cross(vref,v);
  //-- Calculate the angle between the vectors
  ang = v_anglev(vref,v);

  raxis_=ang==180&&raxis==[0,0,0]?[1,0,0]:raxis;

  //-- Rotate the child!
  rotate(a=roll, v=v)
    rotate(a=ang, v=raxis_)
    orient(v)
      child(0);
}

// From Obiscad,
//---------------------------------------------------------------------------
//-- Draw a vector
//--
//-- There are two modes of drawing the vector
//-- * Mode 1: Given by a cartesian point(x,y,z). A vector from the origin
//--           to the end (x,y,z) is drawn. The l parameter (length) must
//--           be 0  (l=0)
//-- * Mode 2: Give by direction and length
//--           A vector of length l pointing to the direction given by
//--           v is drawn
//---------------------------------------------------------------------------
//-- Parameters:
//--  v: Vector cartesian coordinates
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//    mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//---------------------------------------------------------------------------

module vector(v,l=0, l_arrow=4, mark=false)
{
  //-- Get the vector length from the coordinates
  mod = v_mod(v);

  //-- The vector is very easy implemented by means of the orientate
  //-- operator:
  //--  orientate(v) vectorz(l=mod, l_arrow=l_arrow)
  //--  BUT... in OPENSCAD 2012.02.22 the recursion does not
  //--    not work, so that if the user use the orientate operator
  //--    on a vector, openscad will ignore it..
  //-- The solution at the moment (I hope the openscad developers
  //--  implement the recursion in the near future...)
  //--  is to repite the orientate operation in this module

  //---- SAME CALCULATIONS THAN THE ORIENTATE OPERATOR!
  //-- Calculate the rotation axis

  vref = [0,0,1];
  raxis = v_cross(vref,v);

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

  raxis_=ang==180&&raxis==[0,0,0]?[1,0,0]:raxis;

  //-- orientate the vector
  //-- Draw the vector. The vector length is given either
  //--- by the mod variable (when l=0) or by l (when l!=0)
  if (l==0)
    rotate(a=ang, v=raxis_)
      vectorz(l=mod, l_arrow=l_arrow, mark=mark);
  else
    rotate(a=ang, v=raxis_)
      vectorz(l=l, l_arrow=l_arrow, mark=mark);

}

// From Obiscad,
//--------------------------------------------------------------------
//-- 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 , n, ang] where:
//--
//--     p : The attachment point
//--     v : The attachment axis
//--   ang : the angle
//--------------------------------------------------------------------
module connector(c)
{
  //-- 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("Gray") vector(v=v_unitv(v)*6, l_arrow=2, mark=true);
}

// From Obiscad,
// modified to take roll parameter as param in module instead of attachment points
//-------------------------------------------------------------------------
//--  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, roll=0)
{
    //-- Get the data from the connectors
    pos1 = a[0];  //-- Attachment point. Main part
    v    = a[1];  //-- Attachment axis. Main part

    pos2 = b[0];  //-- Attachment point. Attachable part
    vref = b[1];  //-- Atachment axis. Attachable part

    //-------- Calculations for the "orientate operator"------
    //-- Calculate the rotation axis
    raxis = v_cross(vref,v);

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

    raxis_=ang==180&&raxis==[0,0,0]?[1,0,0]:raxis;

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

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

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

// From Obiscad
//----------------------------------------------------------
//--  Draw a point in the position given by the vector p
//----------------------------------------------------------
module point(p, r=0.7, fn, fnr=0.4)
{
    fn_= fn==undef ? (floor(2*(r)*PI/fnr)) : fn;
    translate(p)
    sphere(r=r,$fn=fn_);
}

//------------------------------------------------------------------
//-- Draw a vector poiting to the z axis
//-- This is an auxiliary module for implementing the vector module
//--
//-- Parameters:
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//--  mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//------------------------------------------------------------------
module vectorz(l=10, l_arrow=4, mark=false, fnr)
{
  //-- vector body length (not including the arrow)
  lb = l - l_arrow;

  //-- The vector is locatead at 0,0,0
  translate([0,0,lb/2])
  union() {

    //-- Draw the arrow
    translate([0,0,lb/2])
      fncylindera(r1=2/2, r2=0.2, h=l_arrow, fnr=fnr);

    //-- Draw the mark
    if (mark) {
      translate([0,0,lb/2+l_arrow/2])
      translate([1,0,0])
        cubea([2,0.3,l_arrow*0.8]);
    }

    //-- Draw the body
    fncylindera(r=1/2, h=lb, center=true, fnr=fnr);
  }

  //-- Draw a sphere in the vector base
  sphere(r=1/2, fnr);
}

//-----------------------------------------------------------------
//-- ORIENTATE OPERATOR
//--
//--  Orientate an object to the direction given by the vector v
//--  Parameters:
//--    v : Target orientation
//--    vref: Vector reference. It is the vector of the local frame
//--          of the object that want to be poiting in the direction
//--          of v
//--    roll: Rotation of the object around the v axis
//-------------------------------------------------------------------
module orientate(v,vref=[0,0,1], roll=0)
{
  //-- Calculate the rotation axis
  raxis = v_cross(vref,v);

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

  //-- Rotate the child!
  rotate(a=roll, v=v)
    rotate(a=ang, v=raxis)
      child(0);
}

// From Obiscad,
//---------------------------------------------------------------------------
//-- Draw a vector
//--
//-- There are two modes of drawing the vector
//-- * Mode 1: Given by a cartesian point(x,y,z). A vector from the origin
//--           to the end (x,y,z) is drawn. The l parameter (length) must
//--           be 0  (l=0)
//-- * Mode 2: Give by direction and length
//--           A vector of length l pointing to the direction given by
//--           v is drawn
//---------------------------------------------------------------------------
//-- Parameters:
//--  v: Vector cartesian coordinates
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//    mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//---------------------------------------------------------------------------

module vector(v,l=0, l_arrow=4, mark=false)
{
  //-- Get the vector length from the coordinates
  mod = v_mod(v);

  //-- The vector is very easy implemented by means of the orientate
  //-- operator:
  //--  orientate(v) vectorz(l=mod, l_arrow=l_arrow)
  //--  BUT... in OPENSCAD 2012.02.22 the recursion does not
  //--    not work, so that if the user use the orientate operator
  //--    on a vector, openscad will ignore it..
  //-- The solution at the moment (I hope the openscad developers
  //--  implement the recursion in the near future...)
  //--  is to repite the orientate operation in this module

  //---- SAME CALCULATIONS THAN THE ORIENTATE OPERATOR!
  //-- Calculate the rotation axis

  vref = [0,0,1];
  raxis = v_cross(vref,v);

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

  //-- orientate the vector
  //-- Draw the vector. The vector length is given either
  //--- by the mod variable (when l=0) or by l (when l!=0)
  if (l==0)
    rotate(a=ang, v=raxis)
      vectorz(l=mod, l_arrow=l_arrow, mark=mark);
  else
    rotate(a=ang, v=raxis)
      vectorz(l=l, l_arrow=l_arrow, mark=mark);

}

// From Obiscad,
//--------------------------------------------------------------------
//-- 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 , n, ang] where:
//--
//--     p : The attachment point
//--     v : The attachment axis
//--   ang : the angle
//--------------------------------------------------------------------
module connector(c)
{
  //-- 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("Gray") vector(v_unitv(v)*6, l_arrow=2, mark=true);
}

// From Obiscad,
// modified to take roll parameter as param in module instead of attachment points
//-------------------------------------------------------------------------
//--  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, roll=0)
{
    //-- Get the data from the connectors
    pos1 = a[0];  //-- Attachment point. Main part
    v    = a[1];  //-- Attachment axis. Main part

    pos2 = b[0];  //-- Attachment point. Attachable part
    vref = b[1];  //-- Atachment axis. Attachable part

    //-------- Calculations for the "orientate operator"------
    //-- Calculate the rotation axis
    raxis = v_cross(vref,v);

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

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

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


belt_fastener: fix nut trap axis

belt_fastener: fix nut trap axis

include <belt_fastener.h>

use <thing_libutils/screws.scad>
use <thing_libutils/timing-belts.scad>

module belt_fastener(part, belt=TimingBelt_GT2_2, belt_width=6*mm, belt_dist=pulley_2GT_20T[2], width=55*mm, with_tensioner=true, align=U, orient=X)
{
    belt_t2 = belt_t2_thickness(belt) + .2*mm;
    tension_screw_nut = NutHexM3;
    tension_screw_thread = ThreadM3;
    tension_screw_dia = lookup(ThreadSize, tension_screw_thread);
    angle_screw_thread = ThreadM4;
    angle_screw_dia = 3.25*mm;
    height = belt_dist + belt_t2 + angle_screw_dia + 3*mm;
    slide_width=20*mm;
    depth = belt_width + 10*mm;

    s= [width, depth, height];
    size_align(size=s, orient=orient, align=align, orient_ref=-X)
    {
        if(part==undef)
        {
            difference()
            {
                belt_fastener("pos", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
                belt_fastener("neg", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
            }
            %belt_fastener("vit", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
        }
        else if(part=="pos")
        {
            hull()
            {
                translate(-belt_dist/2*Z)
                {
                    // support for belt path
                    rcubea([width, belt_width, belt_t2*2 + angle_screw_dia]);

                    translate(-belt_width*Y)
                    translate(-angle_screw_dia/2*Y)
                    rcubea([width, angle_screw_dia+2*mm, belt_t2*2 + angle_screw_dia]);
                }
            }
        }
        else if(part=="neg")
        {
            translate(-belt_dist/2*Z)
            if(with_tensioner)
            {
                translate([0,0,belt_t2/4])
                cubea(size=[1000, belt_width+.1, belt_t2], extrasize=1000*Y, extrasize_align=Y);

                /*translate([0,0,angle_screw_dia/2])*/
                {
                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*11*mm*X)
                        cylindera(d=angle_screw_dia+belt_t2, h=belt_width+.1, extra_h=1000, extra_align=Y, orient=Y);
                    }

                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*slide_width/2*X)
                        translate(-belt_width*Y)
                        translate(-angle_screw_dia*Y)
                        translate(-.1*Y)
                        cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=Y, align=Y);
                    }

                    translate(-belt_width*Y)
                    {
                        // cut for angle screw
                        translate(-1*mm*Y)
                        translate(-12*mm*X)
                        {
                            cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=X, align=X);
                            nut_trap_cut(nut=tension_screw_nut, screw_l=6*mm, cut_screw=true, orient=-X, trap_axis=Y);
                        }
                    }
                }

            }
            else
            {
                cubea([1000, belt_width+3*mm, belt_t2*1.8], extrasize=[0,1000,1*mm], extrasize_align=Y+Z);
            }

            translate(belt_dist/2*Z)
            cubea([1000, belt_width+3*mm, belt_t2*2], extrasize=1000*Y, extrasize_align=Y);
        }
        else if(part=="vit")
        {
            if(with_tensioner)
            {
                /*translate(-belt_dist/2*Z)*/
                /*translate(-belt_width*Y)*/
                /*translate(screw_offset_x*X)*/
                /*screw(nut=tension_screw_nut, h=25*mm, with_head=true, with_nut=false, head_embed=true, with_nut=false, orient=X, align=X);*/

                // 90 angle metal screw
                /*translate(screw_offset_x*X)*/
                translate(-belt_dist/2*Z)
                translate(-belt_width*Y)
                translate(-angle_screw_dia/2*Y)
                {
                    cylindera(d=angle_screw_dia+.2*mm, h=20*mm, orient=X, align=X);
                    cylindera(d=angle_screw_dia+.2*mm, h=11*mm, orient=Y, align=Y+X);
                }
            }
        }
    }
}

if(false)
{
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    {
        translate([0, 0, z])
        {
            translate([0, xaxis_carriage_beltpath_offset_y, 0])
            translate([-main_width/2, 0, 0])
            rotate([90,0,0])
            belt_path(main_width, xaxis_belt_width, xaxis_pulley_inner_d, orient=X, align=X);

            proj_extrude_axis(axis=-Y)
            translate([0, xaxis_carriage_beltpath_offset_y, 0])
            mirror([0,0,sign(z)>1?1:0])
            /*mirror(X)*/
            belt_fastener();
        }
    }
}

include <belt_fastener.h>

use <thing_libutils/screws.scad>
use <thing_libutils/timing-belts.scad>

module belt_fastener(part, belt=TimingBelt_GT2_2, belt_width=6*mm, belt_dist=pulley_2GT_20T[2], width=55*mm, with_tensioner=true, align=U, orient=X)
{
    belt_t2 = belt_t2_thickness(belt) + .2*mm;
    tension_screw_nut = NutHexM3;
    tension_screw_thread = ThreadM3;
    tension_screw_dia = lookup(ThreadSize, tension_screw_thread);
    angle_screw_thread = ThreadM4;
    angle_screw_dia = 3.25*mm;
    height = belt_dist + belt_t2 + angle_screw_dia + 3*mm;
    slide_width=20*mm;
    depth = belt_width + 10*mm;

    s= [width, depth, height];
    size_align(size=s, orient=orient, align=align, orient_ref=-X)
    {
        if(part==undef)
        {
            difference()
            {
                belt_fastener("pos", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
                belt_fastener("neg", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
            }
            %belt_fastener("vit", belt=belt, belt_width=belt_width, belt_dist=belt_dist, width=width, with_tensioner=with_tensioner, align=align, orient=orient);
        }
        else if(part=="pos")
        {
            hull()
            {
                translate(-belt_dist/2*Z)
                {
                    // support for belt path
                    rcubea([width, belt_width, belt_t2*2 + angle_screw_dia]);

                    translate(-belt_width*Y)
                    translate(-angle_screw_dia/2*Y)
                    rcubea([width, angle_screw_dia+2*mm, belt_t2*2 + angle_screw_dia]);
                }
            }
        }
        else if(part=="neg")
        {
            translate(-belt_dist/2*Z)
            if(with_tensioner)
            {
                translate([0,0,belt_t2/4])
                cubea(size=[1000, belt_width+.1, belt_t2], extrasize=1000*Y, extrasize_align=Y);

                /*translate([0,0,angle_screw_dia/2])*/
                {
                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*11*mm*X)
                        cylindera(d=angle_screw_dia+belt_t2, h=belt_width+.1, extra_h=1000, extra_align=Y, orient=Y);
                    }

                    hull()
                    {
                        for(i=[-1,1])
                        translate(i*slide_width/2*X)
                        translate(-belt_width*Y)
                        translate(-angle_screw_dia*Y)
                        translate(-.1*Y)
                        cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=Y, align=Y);
                    }

                    translate(-belt_width*Y)
                    {
                        // cut for angle screw
                        translate(-1*mm*Y)
                        translate(-12*mm*X)
                        {
                            cylindera(d=angle_screw_dia+.3*mm, h=1000, orient=X, align=X);
                            nut_trap_cut(nut=tension_screw_nut, screw_l=6*mm, cut_screw=true, orient=-X, trap_axis=-Y);
                        }
                    }
                }

            }
            else
            {
                cubea([1000, belt_width+3*mm, belt_t2*1.8], extrasize=[0,1000,1*mm], extrasize_align=Y+Z);
            }

            translate(belt_dist/2*Z)
            cubea([1000, belt_width+3*mm, belt_t2*2], extrasize=1000*Y, extrasize_align=Y);
        }
        else if(part=="vit")
        {
            if(with_tensioner)
            {
                /*translate(-belt_dist/2*Z)*/
                /*translate(-belt_width*Y)*/
                /*translate(screw_offset_x*X)*/
                /*screw(nut=tension_screw_nut, h=25*mm, with_head=true, with_nut=false, head_embed=true, with_nut=false, orient=X, align=X);*/

                // 90 angle metal screw
                /*translate(screw_offset_x*X)*/
                translate(-belt_dist/2*Z)
                translate(-belt_width*Y)
                translate(-angle_screw_dia/2*Y)
                {
                    cylindera(d=angle_screw_dia+.2*mm, h=20*mm, orient=X, align=X);
                    cylindera(d=angle_screw_dia+.2*mm, h=11*mm, orient=Y, align=Y+X);
                }
            }
        }
    }
}

if(false)
{
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    {
        translate([0, 0, z])
        {
            translate([0, xaxis_carriage_beltpath_offset_y, 0])
            translate([-main_width/2, 0, 0])
            rotate([90,0,0])
            belt_path(main_width, xaxis_belt_width, xaxis_pulley_inner_d, orient=X, align=X);

            proj_extrude_axis(axis=-Y)
            translate([0, xaxis_carriage_beltpath_offset_y, 0])
            mirror([0,0,sign(z)>1?1:0])
            /*mirror(X)*/
            belt_fastener();
        }
    }
}


chassis created

chassis created

/**
 * rally.scad
 *
 * Created by Diego Viejo
 *
 * 11/Dic/2015
 *
 * This is my attemp on creating a chassis for a rally slot car
 *
 */

//guide arm's holder
//work in progress: check for all the sizes is still needed
numSlots = 3;
guideWidth = 40;
guideInternalWidth = 30;
guideHeight = 6;
guideHoleHeight = 3;
guideSupportLength = 7;
guideLength = guideSupportLength + 2 + numSlots*4;

module guide()
difference()
{
    cube([guideWidth, guideLength, guideHeight], center=true);

    translate([0, guideSupportLength, 0]) cube([guideInternalWidth, guideLength, guideHeight+2], center=true);
    translate([0, 0, guideHeight/2]) cube([guideInternalWidth, guideLength+2, guideHeight], center=true);

    for(i=[1:10])
    {
        translate([-guideWidth/2-1, -guideLength/2 + guideSupportLength +i*4, -guideHeight/2+guideHoleHeight])
            rotate([0, 90, 0]) cylinder(d=2, h=guideWidth+2);
    }
}

guide();

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