config: x-axis rod distance to 70mm

config: x-axis rod distance to 70mm

include <bearings.scad>
include <screws.scad>
include <thing_libutils/metric-thread.scad>

e=0.01;

// resolution of any round object (segment length)
fnr                         = 0.4;

extrusion_height            = 0.4*mm;

// width of a single wall, should match your slicer settings
extrusion_width             = 0.4*mm;

// how many lines should a normal wall have (i.e. 0.6(extrusion_width)*6(normal_wall_factor)= 3.6mm wall width)
normal_wall_factor          = 3;

thick_wall_factor           = 4;

// diameter of your filament.
filament_d                  = 1.75*mm;
filament_r                  = filament_d/2;

main_width = 340*mm;
main_depth = 420*mm;
main_height = 400*mm;
main_upper_width = 420*mm;

extrusion_color = [0.5,0.5,0.5];
extrusion_size = 20*mm;
extrusion_thread = ThreadM5;

main_lower_dist_z= 80*mm;
main_upper_dist_y= 160*mm;

xaxis_rod_distance = 70*mm;
xaxis_rod_d = 9.975*mm;
xaxis_rod_l = 500*mm;
xaxis_bearing=bearing_igus_rj4jp_01_10;

yaxis_rod_distance = 170*mm;
yaxis_rod_d = 11.975*mm;
yaxis_rod_l = 500*mm;
yaxis_bearing=bearing_igus_rj4jp_01_12;
ycarriage_size=[220*mm,220*mm,5*mm];

zaxis_rod_d = 11.975*mm;
zaxis_rod_l = 500*mm;
zaxis_bearing=bearing_igus_rj4jp_01_12;

// NEMA17 motor w/340mm leadscrew
zaxis_motor = [
                [NemaModel, 17],
                [NemaLengthShort, 33*mm],
                [NemaLengthMedium, 39*mm],
                [NemaLengthLong, 47*mm],
                [NemaSideSize, 42.20*mm],
                [NemaDistanceBetweenMountingHoles, 31.04*mm],
                [NemaMountingHoleDiameter, 4*mm],
                [NemaMountingHoleDepth, 4.5*mm],
                [NemaMountingHoleLip, -1*mm],
                [NemaMountingHoleCutoutRadius, 0*mm],
                [NemaEdgeRoundingRadius, 7*mm],
                [NemaRoundExtrusionDiameter, 22*mm],
                [NemaRoundExtrusionHeight, 1.9*mm],
                [NemaAxleDiameter, 8*mm],
                // custom front axle length
                [NemaFrontAxleLength, 340*mm],
                [NemaBackAxleLength, 15*mm],
                [NemaAxleFlatDepth, 0.5*mm],
                [NemaAxleFlatLengthFront, 15*mm],
                [NemaAxleFlatLengthBack, 14*mm]
         ];

zaxis_motor_offset_z = 10*mm;

// inner_d, outer_d, thread
zaxis_nut = [20*mm, 36.5*mm, 8*mm];

zaxis_nut_mount_outer = zaxis_nut[1]/2 + zaxis_bearing[1]/2 + 3;

// place z rod on edge of motor
/*zaxis_rod_screw_distance_x = max(zaxis_nut_mount_outer, zaxis_rod_d/2 + lookup(NemaSideSize,zaxis_motor)/2);*/
zaxis_rod_screw_distance_x = zaxis_nut_mount_outer;

xaxis_zaxis_distance_y = xaxis_rod_d/2 + zaxis_bearing[1]/2;

// GT2
// there is bunch of GT2 belts with different tooth-to-tooth distance
// this one is most common in reprap world
// adjust to your needs.
belt_width = 6.5;
belt_tooth_distance = 2;
belt_tooth_ratio = 0.5;
belt_thickness = 0.8;

//T2.5
//belt_tooth_distance = 2.5;
//belt_tooth_ratio = 0.5;

//T5 (strongly discouraged)
//belt_tooth_distance = 5;
//belt_tooth_ratio = 0.75;

//HTD3
//belt_tooth_distance = 3;
//belt_tooth_ratio = 0.75;

//MXL
//belt_tooth_distance = 2.032;
//belt_tooth_ratio = 0.64;

include <bearings.scad>
include <screws.scad>
include <thing_libutils/metric-thread.scad>

e=0.01;

// resolution of any round object (segment length)
fnr                         = 0.4;

extrusion_height            = 0.4*mm;

// width of a single wall, should match your slicer settings
extrusion_width             = 0.4*mm;

// how many lines should a normal wall have (i.e. 0.6(extrusion_width)*6(normal_wall_factor)= 3.6mm wall width)
normal_wall_factor          = 3;

thick_wall_factor           = 4;

// diameter of your filament.
filament_d                  = 1.75*mm;
filament_r                  = filament_d/2;

main_width = 340*mm;
main_depth = 420*mm;
main_height = 400*mm;
main_upper_width = 420*mm;

extrusion_color = [0.5,0.5,0.5];
extrusion_size = 20*mm;
extrusion_thread = ThreadM5;

main_lower_dist_z= 80*mm;
main_upper_dist_y= 160*mm;

xaxis_rod_distance = 60*mm;
xaxis_rod_d = 9.975*mm;
xaxis_rod_l = 500*mm;
xaxis_bearing=bearing_igus_rj4jp_01_10;

yaxis_rod_distance = 170*mm;
yaxis_rod_d = 11.975*mm;
yaxis_rod_l = 500*mm;
yaxis_bearing=bearing_igus_rj4jp_01_12;
ycarriage_size=[220*mm,220*mm,5*mm];

zaxis_rod_d = 11.975*mm;
zaxis_rod_l = 500*mm;
zaxis_bearing=bearing_igus_rj4jp_01_12;

// NEMA17 motor w/340mm leadscrew
zaxis_motor = [
                [NemaModel, 17],
                [NemaLengthShort, 33*mm],
                [NemaLengthMedium, 39*mm],
                [NemaLengthLong, 47*mm],
                [NemaSideSize, 42.20*mm],
                [NemaDistanceBetweenMountingHoles, 31.04*mm],
                [NemaMountingHoleDiameter, 4*mm],
                [NemaMountingHoleDepth, 4.5*mm],
                [NemaMountingHoleLip, -1*mm],
                [NemaMountingHoleCutoutRadius, 0*mm],
                [NemaEdgeRoundingRadius, 7*mm],
                [NemaRoundExtrusionDiameter, 22*mm],
                [NemaRoundExtrusionHeight, 1.9*mm],
                [NemaAxleDiameter, 8*mm],
                // custom front axle length
                [NemaFrontAxleLength, 340*mm],
                [NemaBackAxleLength, 15*mm],
                [NemaAxleFlatDepth, 0.5*mm],
                [NemaAxleFlatLengthFront, 15*mm],
                [NemaAxleFlatLengthBack, 14*mm]
         ];

zaxis_motor_offset_z = 10*mm;

// inner_d, outer_d, thread
zaxis_nut = [20*mm, 36.5*mm, 8*mm];

zaxis_nut_mount_outer = zaxis_nut[1]/2 + zaxis_bearing[1]/2 + 3;

// place z rod on edge of motor
/*zaxis_rod_screw_distance_x = max(zaxis_nut_mount_outer, zaxis_rod_d/2 + lookup(NemaSideSize,zaxis_motor)/2);*/
zaxis_rod_screw_distance_x = zaxis_nut_mount_outer;

xaxis_zaxis_distance_y = xaxis_rod_d/2 + zaxis_bearing[1]/2;

// GT2
// there is bunch of GT2 belts with different tooth-to-tooth distance
// this one is most common in reprap world
// adjust to your needs.
belt_width = 6.5;
belt_tooth_distance = 2;
belt_tooth_ratio = 0.5;
belt_thickness = 0.8;

//T2.5
//belt_tooth_distance = 2.5;
//belt_tooth_ratio = 0.5;

//T5 (strongly discouraged)
//belt_tooth_distance = 5;
//belt_tooth_ratio = 0.75;

//HTD3
//belt_tooth_distance = 3;
//belt_tooth_ratio = 0.75;

//MXL
//belt_tooth_distance = 2.032;
//belt_tooth_ratio = 0.64;


config/ziptie: increase zip distance (wall thick)

include <MCAD/stepper.scad>
include <screws.scad>
include <pulley.scad>
include <thing_libutils/bearing_data.scad>
include <thing_libutils/metric-thread-data.scad>
include <thing_libutils/metric-hexnut-data.scad>
include <thing_libutils/misc.scad>

e=0.01;

// resolution of any round object (segment length)
fnr                         = 0.4;

extrusion_height            = 0.4*mm;

// width of a single wall, should match your slicer settings
extrusion_width             = 0.4*mm;

// how many lines should a normal wall have (i.e. 0.6(extrusion_width)*6(normal_wall_factor)= 3.6mm wall width)
normal_wall_factor          = 3;

thick_wall_factor           = 4;

// diameter of your filament.
filament_d                  = 1.75*mm;
filament_r                  = filament_d/2;

// enable preview model (faster openscad)
preview_mode=true;

main_width = 340*mm;
main_depth = 420*mm;
main_height = 400*mm;
main_upper_width = 420*mm;

extrusion_color = [0.5,0.5,0.5];
extrusion_size = 20*mm;
extrusion_thread = ThreadM5;
extrusion_thread_dia = lookup(ThreadSize, extrusion_thread);
extrusion_nut = MHexNutM5;
extrusion_nut_dia = lookup(MHexNutWidthMax, extrusion_nut);

main_lower_dist_z= 80*mm;
main_upper_dist_y= 160*mm;

gantry_connector_thickness = 5;

rod_fit_tolerance=1.01;

ziptie_type = [1.1*mm, 2.4*mm];
ziptie_thickness = ziptie_type[0];
ziptie_width = ziptie_type[1]+0.6*mm;
ziptie_bearing_distance=3*mm;

xaxis_rod_distance = 60*mm;
xaxis_rod_d = 9.975*mm;
xaxis_rod_l = 500*mm;
xaxis_rod_offset_x = 20*mm;
xaxis_bearing=bearing_igus_rj4jp_01_10;

xaxis_pulley = pulley_2GT_20T;
xaxis_pulley_inner_d = xaxis_pulley[2];
xaxis_idler_pulley = pulley_2GT_20T_idler;
xaxis_idler_pulley_inner_d = xaxis_idler_pulley[2];
xaxis_idler_pulley_outer_d = xaxis_idler_pulley[3];

xaxis_belt_width = 6*mm;

xaxis_carriage_bearing_offset_z = ziptie_thickness/2;
xaxis_carriage_beltpath_offset = xaxis_carriage_bearing_offset_z+xaxis_bearing[1]/2;

xaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);

yaxis_rod_distance = 170*mm;
yaxis_rod_d = 11.975*mm;
yaxis_rod_l = 500*mm;
yaxis_bearing=bearing_igus_rj4jp_01_12;
yaxis_bearing_distance_y = 7*cm;

yaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);

yaxis_pulley = pulley_2GT_20T;
yaxis_pulley_inner_d = yaxis_pulley[2];
ymotor_mount_thickness = 5;
ymotor_mount_thickness_h = 5;
yaxis_motor_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_motor_offset_z = -5*mm;
yaxis_belt_path_offset_x = -yaxis_pulley_inner_d/2;
yaxis_belt_path_offset_z = yaxis_motor_offset_z + 15*mm;

yaxis_idler_pulley = pulley_2GT_20T_idler;
yaxis_idler_pulley_inner_d = yaxis_idler_pulley[2];
yaxis_idler_pulley_outer_d = yaxis_idler_pulley[3];
yaxis_idler_pulley_h = yaxis_idler_pulley[0];
yaxis_idler_mount_thickness = 5;
yaxis_idler_pulley_tight_len = 20*mm;
yaxis_idler_pulley_offset_y = yaxis_idler_mount_thickness + yaxis_pulley_inner_d/2 + yaxis_idler_pulley_tight_len;
yaxis_idler_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_idler_offset_z = 10*mm;

yaxis_carriage_size=[220*mm,220*mm,5*mm];

zaxis_rod_d = 11.975*mm;
zaxis_rod_l = 500*mm;
zaxis_bearing=bearing_igus_rj4jp_01_12;

// Nema17 motor w/340mm long 8*mm leadscrew
zaxis_motor = dict_replace_multiple(Nema17,
        [
        [NemaAxleDiameter, 8*mm],
        [NemaFrontAxleLength, 340*mm],
        ]);

zmotor_w = lookup(NemaSideSize,zaxis_motor);
zmotor_h = lookup(NemaLengthLong,zaxis_motor);

// inner_d, outer_d, thread, outer_h, full_h
zaxis_nut = [20*mm, 36*mm, 8*mm, 5*mm, 23*mm];

zaxis_nut_mount_outer = zaxis_nut[1]/2 + zaxis_rod_d/2 + 1*mm;

// place z rod as close as possible (depends on z nut and also motor etc)
zaxis_rod_screw_distance_x = max(zaxis_nut_mount_outer, zaxis_rod_d/2 + zmotor_w/2 + 1*mm);

zaxis_motor_offset_z = 10*mm;
zmotor_mount_thickness = 5;
zmotor_mount_thickness_h = 10;
zmotor_mount_motor_offset=5;
zmotor_mount_rod_offset_x = zmotor_w/2 + zaxis_rod_screw_distance_x + zmotor_mount_motor_offset;

zmotor_w = lookup(NemaSideSize,zaxis_motor);
zmotor_h = lookup(NemaLengthLong,zaxis_motor);
zmotor_mount_thread_dia = lookup(ThreadSize, extrusion_thread);
zmotor_mount_width = zmotor_w+zmotor_mount_thickness*2 + zmotor_mount_thread_dia*8;
zmotor_mount_h = main_lower_dist_z+extrusion_size+zaxis_motor_offset_z;
zmotor_mount_rod_offset_x = zmotor_w/2+zaxis_rod_screw_distance_x+zmotor_mount_motor_offset;

zmotor_mount_clamp_dist = zaxis_rod_d*2.5;
zmotor_mount_clamp_thread = ThreadM4;
zmotor_mount_clamp_nut = MHexNutM4;
zmotor_mount_clamp_thread_dia = lookup(ThreadSize, zmotor_mount_clamp_thread);
zmotor_mount_clamp_nut_dia = lookup(MHexNutWidthMin, zmotor_mount_clamp_nut);
zmotor_mount_clamp_nut_thick = lookup(MHexNutThickness, zmotor_mount_clamp_nut);

zmotor_mount_clamp_width = zmotor_mount_clamp_dist+zmotor_mount_clamp_thread_dia*3;
xaxis_zaxis_distance_y = 0*mm + xaxis_rod_d/2 + zaxis_bearing[1]/2;

// GT2
// there is bunch of GT2 belts with different tooth-to-tooth distance
// this one is most common in reprap world
// adjust to your needs.
belt_width = 6.5;
belt_tooth_distance = 2;
belt_tooth_ratio = 0.5;
belt_thickness = 0.8;

//T2.5
//belt_tooth_distance = 2.5;
//belt_tooth_ratio = 0.5;

//T5 (strongly discouraged)
//belt_tooth_distance = 5;
//belt_tooth_ratio = 0.75;

//HTD3
//belt_tooth_distance = 3;
//belt_tooth_ratio = 0.75;

//MXL
//belt_tooth_distance = 2.032;
//belt_tooth_ratio = 0.64;

include <MCAD/stepper.scad>
include <screws.scad>
include <pulley.scad>
include <thing_libutils/bearing_data.scad>
include <thing_libutils/metric-thread-data.scad>
include <thing_libutils/metric-hexnut-data.scad>
include <thing_libutils/misc.scad>

e=0.01;

// resolution of any round object (segment length)
fnr                         = 0.4;

extrusion_height            = 0.4*mm;

// width of a single wall, should match your slicer settings
extrusion_width             = 0.4*mm;

// how many lines should a normal wall have (i.e. 0.6(extrusion_width)*6(normal_wall_factor)= 3.6mm wall width)
normal_wall_factor          = 3;

thick_wall_factor           = 4;

// diameter of your filament.
filament_d                  = 1.75*mm;
filament_r                  = filament_d/2;

// enable preview model (faster openscad)
preview_mode=true;

main_width = 340*mm;
main_depth = 420*mm;
main_height = 400*mm;
main_upper_width = 420*mm;

extrusion_color = [0.5,0.5,0.5];
extrusion_size = 20*mm;
extrusion_thread = ThreadM5;
extrusion_thread_dia = lookup(ThreadSize, extrusion_thread);
extrusion_nut = MHexNutM5;
extrusion_nut_dia = lookup(MHexNutWidthMax, extrusion_nut);

main_lower_dist_z= 80*mm;
main_upper_dist_y= 160*mm;

gantry_connector_thickness = 5;

rod_fit_tolerance=1.01;

ziptie_type = [1.1*mm, 2.4*mm];
ziptie_thickness = ziptie_type[0];
ziptie_width = ziptie_type[1]+0.6*mm;
ziptie_bearing_distance=2*mm;

xaxis_rod_distance = 60*mm;
xaxis_rod_d = 9.975*mm;
xaxis_rod_l = 500*mm;
xaxis_rod_offset_x = 0*mm;
xaxis_bearing=bearing_igus_rj4jp_01_10;

xaxis_pulley = pulley_2GT_20T;
xaxis_pulley_inner_d = xaxis_pulley[2];
xaxis_idler_pulley = pulley_2GT_20T_idler;
xaxis_idler_pulley_inner_d = xaxis_idler_pulley[2];
xaxis_idler_pulley_outer_d = xaxis_idler_pulley[3];

xaxis_belt_width = 6*mm;

xaxis_carriage_bearing_offset_z = ziptie_thickness/2;
xaxis_carriage_beltpath_offset = xaxis_carriage_bearing_offset_z+xaxis_bearing[1]/2;

xaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);

yaxis_rod_distance = 170*mm;
yaxis_rod_d = 11.975*mm;
yaxis_rod_l = 500*mm;
yaxis_bearing=bearing_igus_rj4jp_01_12;
yaxis_bearing_distance_y = 7*cm;

yaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);

yaxis_pulley = pulley_2GT_20T;
yaxis_pulley_inner_d = yaxis_pulley[2];
ymotor_mount_thickness = 5;
ymotor_mount_thickness_h = 5;
yaxis_motor_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_motor_offset_z = -5*mm;
yaxis_belt_path_offset_x = -yaxis_pulley_inner_d/2;
yaxis_belt_path_offset_z = yaxis_motor_offset_z + 15*mm;

yaxis_idler_pulley = pulley_2GT_20T_idler;
yaxis_idler_pulley_inner_d = yaxis_idler_pulley[2];
yaxis_idler_pulley_outer_d = yaxis_idler_pulley[3];
yaxis_idler_pulley_h = yaxis_idler_pulley[0];
yaxis_idler_mount_thickness = 5;
yaxis_idler_pulley_tight_len = 20*mm;
yaxis_idler_pulley_offset_y = yaxis_idler_mount_thickness + yaxis_pulley_inner_d/2 + yaxis_idler_pulley_tight_len;
yaxis_idler_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_idler_offset_z = 10*mm;

yaxis_carriage_size=[220*mm,220*mm,5*mm];

zaxis_rod_d = 11.975*mm;
zaxis_rod_l = 500*mm;
zaxis_bearing=bearing_igus_rj4jp_01_12;

// Nema17 motor w/340mm long 8*mm leadscrew
zaxis_motor = dict_replace_multiple(Nema17,
        [
        [NemaAxleDiameter, 8*mm],
        [NemaFrontAxleLength, 340*mm],
        ]);

zmotor_w = lookup(NemaSideSize,zaxis_motor);
zmotor_h = lookup(NemaLengthLong,zaxis_motor);

// inner_d, outer_d, thread, outer_h, full_h
zaxis_nut = [20*mm, 36*mm, 8*mm, 5*mm, 23*mm];

zaxis_nut_mount_outer = zaxis_nut[1]/2 + zaxis_rod_d/2 + 1*mm;

// place z rod as close as possible (depends on z nut and also motor etc)
zaxis_rod_screw_distance_x = max(zaxis_nut_mount_outer, zaxis_rod_d/2 + zmotor_w/2 + 1*mm);

zaxis_motor_offset_z = 10*mm;
zmotor_mount_thickness = 5;
zmotor_mount_thickness_h = 10;
zmotor_mount_motor_offset=5;
zmotor_mount_rod_offset_x = zmotor_w/2 + zaxis_rod_screw_distance_x + zmotor_mount_motor_offset;

zmotor_w = lookup(NemaSideSize,zaxis_motor);
zmotor_h = lookup(NemaLengthLong,zaxis_motor);
zmotor_mount_thread_dia = lookup(ThreadSize, extrusion_thread);
zmotor_mount_width = zmotor_w+zmotor_mount_thickness*2 + zmotor_mount_thread_dia*8;
zmotor_mount_h = main_lower_dist_z+extrusion_size+zaxis_motor_offset_z;
zmotor_mount_rod_offset_x = zmotor_w/2+zaxis_rod_screw_distance_x+zmotor_mount_motor_offset;

zmotor_mount_clamp_dist = zaxis_rod_d*2.5;
zmotor_mount_clamp_thread = ThreadM4;
zmotor_mount_clamp_nut = MHexNutM4;
zmotor_mount_clamp_thread_dia = lookup(ThreadSize, zmotor_mount_clamp_thread);
zmotor_mount_clamp_nut_dia = lookup(MHexNutWidthMin, zmotor_mount_clamp_nut);
zmotor_mount_clamp_nut_thick = lookup(MHexNutThickness, zmotor_mount_clamp_nut);

zmotor_mount_clamp_width = zmotor_mount_clamp_dist+zmotor_mount_clamp_thread_dia*3;
xaxis_zaxis_distance_y = 0*mm + xaxis_rod_d/2 + zaxis_bearing[1]/2;

// GT2
// there is bunch of GT2 belts with different tooth-to-tooth distance
// this one is most common in reprap world
// adjust to your needs.
belt_width = 6.5;
belt_tooth_distance = 2;
belt_tooth_ratio = 0.5;
belt_thickness = 0.8;

//T2.5
//belt_tooth_distance = 2.5;
//belt_tooth_ratio = 0.5;

//T5 (strongly discouraged)
//belt_tooth_distance = 5;
//belt_tooth_ratio = 0.75;

//HTD3
//belt_tooth_distance = 3;
//belt_tooth_ratio = 0.75;

//MXL
//belt_tooth_distance = 2.032;
//belt_tooth_ratio = 0.64;


screws/nut_trap: fix trap_axis

screws/nut_trap: fix trap_axis

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

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

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

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

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

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

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

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

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

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

    nut_h = get(NutThickness,nut)*tolerance;
    head_h = get_screw_head_h(thread_);
    assert(head_h != U, "screw_cut: head_h is U!");

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

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

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

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

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

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

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

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

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

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

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

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    cylindera($fn=nut_facets, d=nut_dia, h=fallback(override_h, nut_thick), orient=orient, align=align);
}

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        translate([0,0,nut_thick/2])
        {
            screw_nut(nut, tolerance, orient=Z, align=-Z);
            translate([0,0,-nut_thick+.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
            }
        }
    }
}

// distance from center to flat on a polygon (taking in the diagonal distance)
function apothem(radius, facets) = radius/cos(180/facets);

function nut_radius(nut) = apothem(get(NutWidthMax, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = 2*nut_radius(nut);

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

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

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

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

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

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

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

    }
}

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    nut_h = get(NutThickness,nut)*tolerance;
    head_h = get_screw_head_h(thread_);
    assert(head_h != U, "screw_cut: head_h is U!");

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

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

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

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

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

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

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

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

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

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

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

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    nut_dia = nut_dia(nut);
    cylindera($fn=nut_facets, d=nut_dia, h=fallback(override_h, nut_thick), orient=orient, align=align);
}

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        translate([0,0,nut_thick/2])
        {
            screw_nut(nut, tolerance, orient=Z, align=-Z);
            translate([0,0,-nut_thick+.01])
            {
                cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
            }
        }
    }
}

// distance from center to flat on a polygon (taking in the diagonal distance)
function apothem(radius, facets) = radius/cos(180/facets);

function nut_radius(nut) = apothem(get(NutWidthMax, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = 2*nut_radius(nut);

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

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

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

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

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

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

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

    }
}

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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


shapes: cubea,rcubea: rename extrasize param to extra_size

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

module cubea(size=[10,10,10], align=N, extra_size=N, extra_align=N, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extra_size, align=align, extra_align=extra_align, orient=orient, orient_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        cube(size+extra_size, center=true);
    }
}

module rcubea(size=[10,10,10], round_r=1, align=N, extra_size=N, extra_align=N, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extra_size, align=align, extra_align=extra_align, orient=orient, orient_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        rcube(size=size+extra_size, round_r=round_r);
    }
}

module rcube(size=[20,20,20], round_r=1)
{
    if($preview_mode || round_r == 0)
    {
        cubea(size);
    }
    else
    {
        hull()
        for(x=[-(size[0]/2-round_r),(size[0]/2-round_r)])
        for(y=[-(size[1]/2-round_r),(size[1]/2-round_r)])
        for(z=[-(size[2]/2-round_r),(size[2]/2-round_r)])
        translate([x,y,z])
        {
            sphere(r=round_r);
        }
    }
}

module spherea(r, d, align=N, extra_r, extra_d, extra_align, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    d_ = v_fallback(d, [r*2]);
    assert(d_ != U);

    extra_d_ = v_fallback(extra_d, [extra_r*2, 0]);

    size=[d_,d_,d_];
    extra_size=[extra_d_,extra_d_,extra_d_];
    size_align(size=size, extra_size=extra_size, align=align, extra_align=extra_align, orient=orient, orient_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        /*cube(size=size, center=true);*/
        sphere(d=d_+extra_d_, center=true);
    }
}

module cylindera(
        h=10,
        r=U,
        r1=U,
        r2=U,
        d=U,
        d1=U,
        d2=U,
        align=N,
        orient=Z,
        extra_h=0,
        extra_r=U,
        extra_d=U,
        extra_align=N,
        round_r=0,
        debug=false
        )
{
    pi=3.1415926536;

    d1_ = v_fallback(d1, [r*2, r1*2]);
    d2_ = v_fallback(d2, [r*2, r2*2]);

    r1_ = v_fallback(r1, [d1_/2, d/2, r]);
    r2_ = v_fallback(r2, [d2_/2, d/2, r]);

    r_max = v_fallback(r, [max(r1_,r2_)]);

    extra_r_ = v_fallback(extra_r, [extra_d/2, 0]);

    if(debug)
    {
        echo(useDia, h, r_, r1_, r2_, extra_r_, align);
    }

    size_align(size=[r_max*2,r_max*2,h], extra_size=[extra_r_*2, extra_r_*2, extra_h], orient=orient, orient_ref=Z, align=align, extra_align=extra_align)
    {
        if(round_r>0)
        {
            rcylindera(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, round_r=round_r);
        }
        else
        {
            cylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, center=true);
        }
    }
}

module torus(r=U, radius=5, radial_width, align=N, orient=Z)
{
    r_ = fallback(r, radius);
    size_align(size=[r_*2+radial_width*2, r_*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate(r_*X)
    circle(radial_width);
}

module rcylindera(
        h=10,
        r=U,
        r1=U,
        r2=U,
        d=U,
        d1=U,
        d2=U,
        align=N,
        orient=Z,
        extra_h=0,
        extra_r=U,
        extra_d=U,
        extra_align=N,
        round_r=1,
        debug=false
        )
{
    d1_ = v_fallback(d1, [r*2, r1*2]);
    d2_ = v_fallback(d2, [r*2, r2*2]);

    r1_ = v_fallback(r1, [d1_/2, d/2, r]);
    r2_ = v_fallback(r2, [d2_/2, d/2, r]);

    r_max = v_fallback(r, [max(r1_,r2_)]);

    h_ = h+extra_h;

    extra_r_ = v_fallback(extra_r, [extra_d/2, 0]);

    assert(r1_ != U);
    assert(r2_ != U);
    assert(extra_r_ != U);

    if(debug)
    {
        echo(useDia, h, r_, r1_, r2_, extra_r_, align);
    }

    size_align(size=[r_max*2,r_max*2,h], extra_size=[extra_r_*2, extra_r_*2, extra_h], orient=orient, orient_ref=Z, align=align, extra_align=extra_align)
    {
        if($preview_mode || round_r == 0)
        {
            cylindera(h=h_, r1=r1_+extra_r_, r2=r2_+extra_r_);
        }
        else
        {
            r_ = [r1_+extra_r_/2,r2_+extra_r_/2];

            hull()
            {
                for(z=[-1,1])
                translate([0, 0, z*(-h_/2)])
                {
                    r__=z!=-1?r_[0]:r_[1];
                    torus(radius=r__-round_r, radial_width=round_r, align=z*Z);
                }
            }
        }
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    intersection() {
        circle(r);
        polygon([
                [0,0],
                [R * cos(a0), R * sin(a0)],
                [R * cos(a1), R * sin(a1)],
                [R * cos(a2), R * sin(a2)],
                [R * cos(a3), R * sin(a3)],
                [R * cos(a4), R * sin(a4)],
                [0,0]
        ]);
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice(r, start_angle, end_angle, h, orient=Z, align=N)
{
    size_align(size=[r*2, r*2, h], orient=orient, orient_ref=Z, align=align)
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

module hollow_cylinder(d=10, thickness=1, h=10, taper=false, taper_h=U, orient=Z, align=N)
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    taper_h = taper_h == U ? min(h/4, (outer_d-inner_d)/2) : max(taper_h,h/2);
    taper_ = taper && taper_h > 0;
    size_align(size=[outer_d, outer_d, h], orient=orient, align=align);
    difference()
    {
        union()
        {
            cylindera(h=h-(taper_?taper_h*2:0), d=outer_d, orient=Z, align=N);
            if(taper_)
            {
                for(z=[-1,1])
                translate([0,0,z*(h/2-taper_h)])
                mirror([0,0,z==-1?1:0])
                cylindera(d1=outer_d, d2=outer_d-inner_d/4, h=taper_h, align=Z);
            }
        }
        if(taper_)
        {
            for(z=[-1,1])
            translate([0,0,z*(h/2-taper_h)])
            mirror([0,0,z==-1?1:0])
            cylindera(d1=inner_d, d2=outer_d, h=taper_h+.1, align=Z, extra_h=.2);

            // override fn for inner cylinder cut, to ensure same fragments as taper
            // this ensures cleaner mesh
            fn = fn_from_d(d=outer_d);
            cylindera(h=h+.2+taper_h, d=inner_d, orient=Z, align=N, $fn=fn);
        }
        else
        {
            cylindera(h=h, d=inner_d, orient=Z, align=N, extra_h=.4);
        }
    }
}

/**
 * Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module triangle(o_len, a_len, depth, align=N, orient=Z)
{
    size_align(size=[a_len, depth, o_len], align=align, orient=orient)
    rotate([90,0,0])
    translate([-a_len/2, -o_len/2, -depth/2])
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]);
    }
}

/**
 * Rounded Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module rtriangle(o_len, a_len, depth, round_r=2, align=N, orient=Z)
{
    size = [a_len-round_r, depth-round_r, o_len-round_r];
    r_x = round_r;
    r_y = round_r;
    r_z = -round_r;

    hyp = pythag_hyp(o_len,a_len);
    a_z = atan(a_len/o_len);

    translate([0,0,size[2]+2])
    color(X)
    rotate([90,90,0])
    pie_slice(r=2, start_angle=0, end_angle=a_z, h=depth);

    /*translate([size[0]+4,0,0])*/
    /*color(X)*/
    /*rotate([90,90,0])*/
    /*pie_slice(r=2, start_angle=90, end_angle=90+a_z, h=depth);*/

    size_align(size=size, align=align, orient=orient)
    /*hull()*/
    for(x=[-(size[0]/2)+round_r,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+round_r,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+round_r,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=round_r);
}

module teardrop(r, d, h=10, truncate=1, align=N, orient=Y, roll=0)
{
    r_= v_fallback(r, [d/2]);

    sx1 = r_ * sin(-45);
    sx2 = r_ * -sin(-45);
    sy = r_ * -cos(-45);
    ex = 0;
    ey = (sin(-135) + cos(-135)) * r_;

    dx= ex-sx1;
    dy = ey-sy;

    eys = lerp(-r_,ey,1-truncate);

    dys = eys-sy;
    ex1 = sy+dys*dx/dy;
    ex2 = -ex1;

    size_align(size=[d,d,h], align=align, orient=orient, orient_ref=Z, roll=roll)
    union()
    {
        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        circle(r = r_, center = true);

        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        polygon(points = [
                [sy, sx1],
                [sy, sx2],
                [eys, ex2],
                [eys, ex1]],
                paths = [[0, 1, 2, 3]]);
    }
}

// test teardrop
if(false)
{
    r=5*mm;
    all_axes()
    translate($axis*r*2)
    color($color)
    teardrop(r=r, h=20, orient=$axis, align=$axis);
}

// test cubea
if(false)
{
    w=5*mm;
    h=2*mm;
    all_axes()
    color($color)
    cubea([w,w,h], orient=$axis, align=$axis*3);
}
/**
/*debug();*/

module debug()
{
    $fs = 0.1;
    $fa = 1;

    /*triangle_a(45, 5, 5);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=-Z);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=Z);*/

    triangle(10, 30, 5, align=[1,1,1], orient=Z);
    translate([0,-10,0])
    rtriangle(10, 30, 5, align=[1,1,1], orient=Z);
}

/**
 * Standard right-angled triangle (tangent version)
 *
 * @param number angle of adjacent to hypotenuse (ie tangent)
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 */
module triangle_a(tan_angle, a_len, depth)
{
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]);
    }
}

// Tests:
module test_triangles()
{
    // Generate a bunch of triangles by sizes
    for (i = [1:10])
    {
        translate([i*7, -30, i*7])
        {
            triangle(i*5, sqrt(i*5+pow(i,2)), 5);
        }
    }

    // Generate a bunch of triangles by angle
    for (i = [1:85/5])
    {
        translate([i*7, 22, i*7])
        {
            triangle_a(i*5, 10, 5);
        }
    }
}

if(false)
{
    stack(axis=X, dist=15)
    {
        hollow_cylinder(thickness=5, h=10, taper=false, orient=Z, align=Z);
        hollow_cylinder(thickness=5, h=10, taper=true, orient=Z, align=Z);
    }

    /*cylindera(d=10, h=10, orient=Z, align=Z);*/
    /*translate([10,0,0])*/
    /*{*/
    /*hollow_cylinder(d=10, thickness=4, h=10, taper=true, taper_h=.5, orient=Z, align=Z);*/
    /*cylindera(d=8, h=10, orient=Z, align=Z);*/
    /*}*/

    /*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

    /*cubea([10,10,10],X);*/
    /*%cubea([10,10,10],X,[5,5,5],[1,1,1]);*/

    /*%cubea([10,10,10],[-1,0,1]);*/
    /*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
    /*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=X, extra_d=10);*/

    /*hull_pairwise()*/
    /*sphere(30/2);*/

    /*translate([30,0,0])*/
    /*rcubea(s=[35,35,35], round_r=10);*/
    /*rcubea(s=[35,35,35], align=-Y);*/

    /*translate([60,0,0])*/
    /*sphere(30/2);*/

    cylindera(h=20, r=5*mm, align=Y, orient=Z, $fn=100);

/*size_align(size=[5,5,20], orient=Y, orient_ref=Z)*/
/*size_align(size=[5,5,20], orient=Y, orient_ref=Y, align=Y)*/
/*size_align(size=[5,20,5], orient=Z, orient_ref=Y, align=N)*/
/*rotate([90,0,0])*/
/*cylinder(d=5, h=20, center=true);*/

/*cylindera(d=10, h=10, orient=Y, align=Z);*/
}

if(false)
{
    /*cubea();*/
    /*rcubea(size=[10,10,10]);*/

    is_build = true;
    $fs = is_build ? 0.5 : 2;
    $fa = is_build ? 4 : 12;

    stack(axis=X, dist=15)
    {
        cylindera(h=10,r=5);

        rcylindera(h=10,r=5);

        rcubea([10,10,10]);
    }
}

if(false)
{
    r=5*mm;
    all_axes()
    translate($axis*r*2)
    color($color)
    /*orient(axis=$axis, axis_ref=Z)*/
    /*translate(Z*10)*/
    /*rcylindera(r1=5, r2=3, h=10);*/
    {
        rcylindera(h=20, extra_d = 1*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16); /*cylindera(h=20, round_r=1, extra_r = 2*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16);*/
        cylindera(h=20, extra_d = 1*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16); /*cylindera(h=20, round_r=1, extra_r = 2*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16);*/
    }

}

if(false)
{
    all_axes()
    translate($axis*r*2)
    color($color)
    {
        orient(axis=$axis, axis_ref=Z)
        hull()
        {
            cubea(size=[5,8,7]);
            translate(5*Z)
            cubea(size=[2,2,2]);
        }
    }
}

if(false)
{
    stack(dist=50, axis=Y)
    {
        stack(dist=10, axis=-Z)
        {
            /*cylindera(orient=-Z, align=-Z);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=Z, align=-Z);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=-Z, align=Z);
            /*pie_slice(r=30, h=5, start_angle=-90, end_angle=180, align=-Z);*/
            /*pie_slice(r=30, h=5, start_angle=90, end_angle=270, align=-Z);*/
            /*pie_slice(r=30, h=5, start_angle=0, end_angle=270, align=-Z);*/
        }

        stack(dist=10, axis=Y)
        {
            /*cylindera(orient=Y, align=Y);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=-Y, align=Y);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=Y, align=Y);
            pie_slice(r=30, h=5, start_angle=-90, end_angle=180, orient=Y, align=Y);
            pie_slice(r=30, h=5, start_angle=90, end_angle=270, orient=Y, align=Y);
            pie_slice(r=30, h=5, start_angle=0, end_angle=270, orient=Y, align=Y);
        }
    }
}

if(false)
{
    /*$fs = 0.5;*/
    /*$fa = 4;*/

    r=5;
    hull()
    {
        stack(dist=10, axis=-Z)
        {
            rcylindera(r=r, h=r*2, orient=Y, align=Y);
            rcylindera(r=r, h=r*2, orient=Y, align=Y);
        }

        rcylindera(r=5, h=r, orient=X, align=Y+X+Z);
    }
}

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

module cubea(size=[10,10,10], align=N, extrasize=N, extrasize_align=N, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extrasize, align=align, extra_align=extrasize_align, orient=orient, orient_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        cube(size+extrasize, center=true);
    }
}

module rcubea(size=[10,10,10], round_r=1, align=N, extrasize=N, extrasize_align=N, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extrasize, align=align, extra_align=extrasize_align, orient=orient, orient_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        rcube(size=size+extrasize, round_r=round_r);
    }
}

module rcube(size=[20,20,20], round_r=1)
{
    if($preview_mode || round_r == 0)
    {
        cubea(size);
    }
    else
    {
        hull()
        for(x=[-(size[0]/2-round_r),(size[0]/2-round_r)])
        for(y=[-(size[1]/2-round_r),(size[1]/2-round_r)])
        for(z=[-(size[2]/2-round_r),(size[2]/2-round_r)])
        translate([x,y,z])
        {
            sphere(r=round_r);
        }
    }
}

module spherea(r, d, align=N, extra_r, extra_d, extra_align, orient=Z, orient_ref=Z, roll=0, extra_roll, extra_roll_orient)
{
    d_ = v_fallback(d, [r*2]);
    assert(d_ != U);

    extra_d_ = v_fallback(extra_d, [extra_r*2, 0]);

    size=[d_,d_,d_];
    extra_size=[extra_d_,extra_d_,extra_d_];
    size_align(size=size, extra_size=extra_size, align=align, extra_align=extra_align, orient=orient, orient_ref=orient_ref, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        /*cube(size=size, center=true);*/
        sphere(d=d_+extra_d_, center=true);
    }
}

module cylindera(
        h=10,
        r=U,
        r1=U,
        r2=U,
        d=U,
        d1=U,
        d2=U,
        align=N,
        orient=Z,
        extra_h=0,
        extra_r=U,
        extra_d=U,
        extra_align=N,
        round_r=0,
        debug=false
        )
{
    pi=3.1415926536;

    d1_ = v_fallback(d1, [r*2, r1*2]);
    d2_ = v_fallback(d2, [r*2, r2*2]);

    r1_ = v_fallback(r1, [d1_/2, d/2, r]);
    r2_ = v_fallback(r2, [d2_/2, d/2, r]);

    r_max = v_fallback(r, [max(r1_,r2_)]);

    extra_r_ = v_fallback(extra_r, [extra_d/2, 0]);

    if(debug)
    {
        echo(useDia, h, r_, r1_, r2_, extra_r_, align);
    }

    size_align(size=[r_max*2,r_max*2,h], extra_size=[extra_r_*2, extra_r_*2, extra_h], orient=orient, orient_ref=Z, align=align, extra_align=extra_align)
    {
        if(round_r>0)
        {
            rcylindera(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, round_r=round_r);
        }
        else
        {
            cylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, center=true);
        }
    }
}

module torus(r=U, radius=5, radial_width, align=N, orient=Z)
{
    r_ = fallback(r, radius);
    size_align(size=[r_*2+radial_width*2, r_*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate(r_*X)
    circle(radial_width);
}

module rcylindera(
        h=10,
        r=U,
        r1=U,
        r2=U,
        d=U,
        d1=U,
        d2=U,
        align=N,
        orient=Z,
        extra_h=0,
        extra_r=U,
        extra_d=U,
        extra_align=N,
        round_r=1,
        debug=false
        )
{
    d1_ = v_fallback(d1, [r*2, r1*2]);
    d2_ = v_fallback(d2, [r*2, r2*2]);

    r1_ = v_fallback(r1, [d1_/2, d/2, r]);
    r2_ = v_fallback(r2, [d2_/2, d/2, r]);

    r_max = v_fallback(r, [max(r1_,r2_)]);

    h_ = h+extra_h;

    extra_r_ = v_fallback(extra_r, [extra_d/2, 0]);

    assert(r1_ != U);
    assert(r2_ != U);
    assert(extra_r_ != U);

    if(debug)
    {
        echo(useDia, h, r_, r1_, r2_, extra_r_, align);
    }

    size_align(size=[r_max*2,r_max*2,h], extra_size=[extra_r_*2, extra_r_*2, extra_h], orient=orient, orient_ref=Z, align=align, extra_align=extra_align)
    {
        if($preview_mode || round_r == 0)
        {
            cylindera(h=h_, r1=r1_+extra_r_, r2=r2_+extra_r_);
        }
        else
        {
            r_ = [r1_+extra_r_/2,r2_+extra_r_/2];

            hull()
            {
                for(z=[-1,1])
                translate([0, 0, z*(-h_/2)])
                {
                    r__=z!=-1?r_[0]:r_[1];
                    torus(radius=r__-round_r, radial_width=round_r, align=z*Z);
                }
            }
        }
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    intersection() {
        circle(r);
        polygon([
                [0,0],
                [R * cos(a0), R * sin(a0)],
                [R * cos(a1), R * sin(a1)],
                [R * cos(a2), R * sin(a2)],
                [R * cos(a3), R * sin(a3)],
                [R * cos(a4), R * sin(a4)],
                [0,0]
        ]);
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice(r, start_angle, end_angle, h, orient=Z, align=N)
{
    size_align(size=[r*2, r*2, h], orient=orient, orient_ref=Z, align=align)
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

module hollow_cylinder(d=10, thickness=1, h=10, taper=false, taper_h=U, orient=Z, align=N)
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    taper_h = taper_h == U ? min(h/4, (outer_d-inner_d)/2) : max(taper_h,h/2);
    taper_ = taper && taper_h > 0;
    size_align(size=[outer_d, outer_d, h], orient=orient, align=align);
    difference()
    {
        union()
        {
            cylindera(h=h-(taper_?taper_h*2:0), d=outer_d, orient=Z, align=N);
            if(taper_)
            {
                for(z=[-1,1])
                translate([0,0,z*(h/2-taper_h)])
                mirror([0,0,z==-1?1:0])
                cylindera(d1=outer_d, d2=outer_d-inner_d/4, h=taper_h, align=Z);
            }
        }
        if(taper_)
        {
            for(z=[-1,1])
            translate([0,0,z*(h/2-taper_h)])
            mirror([0,0,z==-1?1:0])
            cylindera(d1=inner_d, d2=outer_d, h=taper_h+.1, align=Z, extra_h=.2);

            // override fn for inner cylinder cut, to ensure same fragments as taper
            // this ensures cleaner mesh
            fn = fn_from_d(d=outer_d);
            cylindera(h=h+.2+taper_h, d=inner_d, orient=Z, align=N, $fn=fn);
        }
        else
        {
            cylindera(h=h, d=inner_d, orient=Z, align=N, extra_h=.4);
        }
    }
}

/**
 * Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module triangle(o_len, a_len, depth, align=N, orient=Z)
{
    size_align(size=[a_len, depth, o_len], align=align, orient=orient)
    rotate([90,0,0])
    translate([-a_len/2, -o_len/2, -depth/2])
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]);
    }
}

/**
 * Rounded Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module rtriangle(o_len, a_len, depth, round_r=2, align=N, orient=Z)
{
    size = [a_len-round_r, depth-round_r, o_len-round_r];
    r_x = round_r;
    r_y = round_r;
    r_z = -round_r;

    hyp = pythag_hyp(o_len,a_len);
    a_z = atan(a_len/o_len);

    translate([0,0,size[2]+2])
    color(X)
    rotate([90,90,0])
    pie_slice(r=2, start_angle=0, end_angle=a_z, h=depth);

    /*translate([size[0]+4,0,0])*/
    /*color(X)*/
    /*rotate([90,90,0])*/
    /*pie_slice(r=2, start_angle=90, end_angle=90+a_z, h=depth);*/

    size_align(size=size, align=align, orient=orient)
    /*hull()*/
    for(x=[-(size[0]/2)+round_r,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+round_r,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+round_r,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=round_r);
}

module teardrop(r, d, h=10, truncate=1, align=N, orient=Y, roll=0)
{
    r_= v_fallback(r, [d/2]);

    sx1 = r_ * sin(-45);
    sx2 = r_ * -sin(-45);
    sy = r_ * -cos(-45);
    ex = 0;
    ey = (sin(-135) + cos(-135)) * r_;

    dx= ex-sx1;
    dy = ey-sy;

    eys = lerp(-r_,ey,1-truncate);

    dys = eys-sy;
    ex1 = sy+dys*dx/dy;
    ex2 = -ex1;

    size_align(size=[d,d,h], align=align, orient=orient, orient_ref=Z, roll=roll)
    union()
    {
        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        circle(r = r_, center = true);

        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        polygon(points = [
                [sy, sx1],
                [sy, sx2],
                [eys, ex2],
                [eys, ex1]],
                paths = [[0, 1, 2, 3]]);
    }
}

// test teardrop
if(false)
{
    r=5*mm;
    all_axes()
    translate($axis*r*2)
    color($color)
    teardrop(r=r, h=20, orient=$axis, align=$axis);
}

// test cubea
if(false)
{
    w=5*mm;
    h=2*mm;
    all_axes()
    color($color)
    cubea([w,w,h], orient=$axis, align=$axis*3);
}
/**
/*debug();*/

module debug()
{
    $fs = 0.1;
    $fa = 1;

    /*triangle_a(45, 5, 5);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=-Z);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=Z);*/

    triangle(10, 30, 5, align=[1,1,1], orient=Z);
    translate([0,-10,0])
    rtriangle(10, 30, 5, align=[1,1,1], orient=Z);
}

/**
 * Standard right-angled triangle (tangent version)
 *
 * @param number angle of adjacent to hypotenuse (ie tangent)
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 */
module triangle_a(tan_angle, a_len, depth)
{
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]);
    }
}

// Tests:
module test_triangles()
{
    // Generate a bunch of triangles by sizes
    for (i = [1:10])
    {
        translate([i*7, -30, i*7])
        {
            triangle(i*5, sqrt(i*5+pow(i,2)), 5);
        }
    }

    // Generate a bunch of triangles by angle
    for (i = [1:85/5])
    {
        translate([i*7, 22, i*7])
        {
            triangle_a(i*5, 10, 5);
        }
    }
}

if(false)
{
    stack(axis=X, dist=15)
    {
        hollow_cylinder(thickness=5, h=10, taper=false, orient=Z, align=Z);
        hollow_cylinder(thickness=5, h=10, taper=true, orient=Z, align=Z);
    }

    /*cylindera(d=10, h=10, orient=Z, align=Z);*/
    /*translate([10,0,0])*/
    /*{*/
    /*hollow_cylinder(d=10, thickness=4, h=10, taper=true, taper_h=.5, orient=Z, align=Z);*/
    /*cylindera(d=8, h=10, orient=Z, align=Z);*/
    /*}*/

    /*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

    /*cubea([10,10,10],X);*/
    /*%cubea([10,10,10],X,[5,5,5],[1,1,1]);*/

    /*%cubea([10,10,10],[-1,0,1]);*/
    /*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
    /*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=X, extra_d=10);*/

    /*hull_pairwise()*/
    /*sphere(30/2);*/

    /*translate([30,0,0])*/
    /*rcubea(s=[35,35,35], round_r=10);*/
    /*rcubea(s=[35,35,35], align=-Y);*/

    /*translate([60,0,0])*/
    /*sphere(30/2);*/

    cylindera(h=20, r=5*mm, align=Y, orient=Z, $fn=100);

/*size_align(size=[5,5,20], orient=Y, orient_ref=Z)*/
/*size_align(size=[5,5,20], orient=Y, orient_ref=Y, align=Y)*/
/*size_align(size=[5,20,5], orient=Z, orient_ref=Y, align=N)*/
/*rotate([90,0,0])*/
/*cylinder(d=5, h=20, center=true);*/

/*cylindera(d=10, h=10, orient=Y, align=Z);*/
}

if(false)
{
    /*cubea();*/
    /*rcubea(size=[10,10,10]);*/

    is_build = true;
    $fs = is_build ? 0.5 : 2;
    $fa = is_build ? 4 : 12;

    stack(axis=X, dist=15)
    {
        cylindera(h=10,r=5);

        rcylindera(h=10,r=5);

        rcubea([10,10,10]);
    }
}

if(false)
{
    r=5*mm;
    all_axes()
    translate($axis*r*2)
    color($color)
    /*orient(axis=$axis, axis_ref=Z)*/
    /*translate(Z*10)*/
    /*rcylindera(r1=5, r2=3, h=10);*/
    {
        rcylindera(h=20, extra_d = 1*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16); /*cylindera(h=20, round_r=1, extra_r = 2*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16);*/
        cylindera(h=20, extra_d = 1*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16); /*cylindera(h=20, round_r=1, extra_r = 2*mm, r1=r, r2=r/2, align=$axis, orient=$axis, extra_h=r, extra_align=-$axis, $fn=16);*/
    }

}

if(false)
{
    all_axes()
    translate($axis*r*2)
    color($color)
    {
        orient(axis=$axis, axis_ref=Z)
        hull()
        {
            cubea(size=[5,8,7]);
            translate(5*Z)
            cubea(size=[2,2,2]);
        }
    }
}

if(false)
{
    stack(dist=50, axis=Y)
    {
        stack(dist=10, axis=-Z)
        {
            /*cylindera(orient=-Z, align=-Z);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=Z, align=-Z);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=-Z, align=Z);
            /*pie_slice(r=30, h=5, start_angle=-90, end_angle=180, align=-Z);*/
            /*pie_slice(r=30, h=5, start_angle=90, end_angle=270, align=-Z);*/
            /*pie_slice(r=30, h=5, start_angle=0, end_angle=270, align=-Z);*/
        }

        stack(dist=10, axis=Y)
        {
            /*cylindera(orient=Y, align=Y);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=-Y, align=Y);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=Y, align=Y);
            pie_slice(r=30, h=5, start_angle=-90, end_angle=180, orient=Y, align=Y);
            pie_slice(r=30, h=5, start_angle=90, end_angle=270, orient=Y, align=Y);
            pie_slice(r=30, h=5, start_angle=0, end_angle=270, orient=Y, align=Y);
        }
    }
}

if(false)
{
    /*$fs = 0.5;*/
    /*$fa = 4;*/

    r=5;
    hull()
    {
        stack(dist=10, axis=-Z)
        {
            rcylindera(r=r, h=r*2, orient=Y, align=Y);
            rcylindera(r=r, h=r*2, orient=Y, align=Y);
        }

        rcylindera(r=5, h=r, orient=X, align=Y+X+Z);
    }
}


Wheel: thinner spokes and slightly larger centre hole for motor

module Wheel_STL() {

	printedPart("printedparts/Wheel.scad", "Wheel", "Wheel_STL()") {

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

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

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

module WheelModel()
{
	rimThickness = 4;
	spokeThickness = 5;
	hubDiameter = 10;

    // Outer Rim
    rotate_extrude($fn=100)
    translate ([(WheelDiameter / 2) - rimThickness, 0, 0])
    difference()
    {
        square([rimThickness, WheelThickness]);

        translate([rimThickness + 0.5 , WheelThickness / 2])
            circle(r = WheelThickness / 4);
    }

	// Spokes
	linear_extrude(2)
	difference() {
		union() {
			// Cool, curvey spokes
			for (i = [0, 120, 240])
				rotate(i)
				translate([WheelDiameter / 4 - 1, 0 ])
				difference() {
					circle(r=WheelDiameter / 4 - 2);
					circle(r=WheelDiameter / 4 - 2 - spokeThickness/2);
				}

			// Boring straight spokes
			*for (i = [0, 90, 180, 270])
				rotate(i)
				translate([hubDiameter / 2 - 1, -spokeThickness / 2, 0 ])
					square([(WheelDiameter / 2) - (hubDiameter / 2 - 1) - (rimThickness - 1), spokeThickness]);
		}

		// Chop out center where hub will go
		translate([0,0,-eta])
			circle(r=hubDiameter/2 - eta);
	}

	// Hub
	render()
	difference() {
		linear_extrude(6) // = motor_shaft_h - a bit?
		difference() {
			// Center Hub
			circle(r=hubDiameter / 2);

			MotorShaftSlot();
		}

		// Grub screw hole
		translate([0, 0, 3.5])
		rotate(a=90, v=[0, 1, 0])
			cylinder(r=1.5, h=hubDiameter/2 + eta);

	}
}

module MotorShaftSlot()
{
	difference() {
		circle(r = 5/2 + 0.2); // = motor_shaft_r / 2

		for(i = [0:1])
			mirror([i, 0, 0])
			translate([MotorShaftFlatThickness / 2 + 0.1, -MotorShaftDiameter / 2, 0])
				square([MotorShaftDiameter / 2, MotorShaftDiameter]);
	}
}

module Tyre_STL()
{
	tyreThickness = 1.5;
	stretchAmount = 2; // Make tyre dia this much less than wheel so it is stretch to fit

	color(Grey80)
	rotate_extrude($fn=100)
	translate ([(WheelDiameter - stretchAmount) / 2, 0, 0]) {
        square([tyreThickness, WheelThickness]);

        translate([0 , WheelThickness / 2])
            circle(r = WheelThickness / 4);
	}
}

module Wheel_STL() {

	printedPart("printedparts/Wheel.scad", "Wheel", "Wheel_STL()") {

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

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

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

module WheelModel()
{
	rimThickness = 4;
	spokeThickness = 5;
	hubDiameter = 10;

    // Outer Rim
    rotate_extrude($fn=100)
    translate ([(WheelDiameter / 2) - rimThickness, 0, 0])
    difference()
    {
        square([rimThickness, WheelThickness]);

        translate([rimThickness + 0.5 , WheelThickness / 2])
            circle(r = WheelThickness / 4);
    }

	// Spokes
	linear_extrude(WheelThickness)
	difference() {
		union() {
			// Cool, curvey spokes
			for (i = [0, 120, 240])
				rotate(i)
				translate([WheelDiameter / 4 - 1, 0 ])
				difference() {
					circle(r=WheelDiameter / 4 - 2);
					circle(r=WheelDiameter / 4 - 2 - spokeThickness/2);
				}

			// Boring straight spokes
			*for (i = [0, 90, 180, 270])
				rotate(i)
				translate([hubDiameter / 2 - 1, -spokeThickness / 2, 0 ])
					square([(WheelDiameter / 2) - (hubDiameter / 2 - 1) - (rimThickness - 1), spokeThickness]);
		}

		// Chop out center where hub will go
		translate([0,0,-eta])
			circle(r=hubDiameter/2 - eta);
	}

	// Hub
	render()
	difference() {
		linear_extrude(6) // = motor_shaft_h - a bit?
		difference() {
			// Center Hub
			circle(r=hubDiameter / 2);

			MotorShaftSlot();
		}

		// Grub screw hole
		translate([0, 0, 3.5])
		rotate(a=90, v=[0, 1, 0])
			cylinder(r=1.5, h=hubDiameter/2 + eta);

	}
}

module MotorShaftSlot()
{
	difference() {
		circle(r = 5/2); // = motor_shaft_r / 2

		for(i = [0:1])
			mirror([i, 0, 0])
			translate([MotorShaftFlatThickness / 2, -MotorShaftDiameter / 2, 0])
				square([MotorShaftDiameter / 2, MotorShaftDiameter]);
	}
}

module Tyre_STL()
{
	tyreThickness = 1.5;
	stretchAmount = 2; // Make tyre dia this much less than wheel so it is stretch to fit

	color(Grey80)
	rotate_extrude($fn=100)
	translate ([(WheelDiameter - stretchAmount) / 2, 0, 0]) {
        square([tyreThickness, WheelThickness]);

        translate([0 , WheelThickness / 2])
            circle(r = WheelThickness / 4);
	}
}


Citosine

Citosine

$fn=128;
x=55;
y=19;
z=9; // по этой переменной можно менять толщину всей модели
z2=2.5;
//Цитозин
$fn=270;
difference(){

difference (){
color("MediumPurple") translate ([0,0,0]) cube ([x,y,z-2], center=true);
color("Red") translate ([-30,y/200000,-4]) cylinder (z,y/2,y/2);

 }
#rotate([0,90,0]) translate([0,0,-22]) cylinder(5,2.3,2.3);
translate([-10,-10.5,-1]) cube([50,21,5]);
}

rotate([90,0,0]) translate([-10.5,0,-9.5]) cylinder(19,3.5,3.5);


Fix for 2 mm

Fix for 2 mm

tol = 0.5;
pcb_x = 130;
pcb_y = 110;
pcb_z = 4;
bolt_d = 3.6;
shift_bolt = 5;

// box thickness
th = 2;

//TODO
shift_x = 4;
shift_y = th + 1;

//TODO
box_x = pcb_x + shift_x + 4;
box_y = pcb_y + shift_y + th;

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

socket_h = 15;
socket_w = 10;
socket_n = 5;
socket_int = 20;
start_socket_x = 20 + shift_x;
start_socket_z = th + pcb_z + tol;
eps = 1e-1;

// TODO
usb_type_b_w = 15.2;
usb_type_b_h = 11.5;
start_type_b_y = shift_y + pcb_y - 30.1;
//start_type_b_z = th + pcb_z + tol;

// TODO
usb_type_a_w = 17.3;
usb_type_a_h = 8;
start_type_a_y = shift_y + 44.7;
//start_type_a_z = th + pcb_z + tol;

// programmator
micro_x = 10;
micro_y = 21.1;
micro_start_x = shift_x + 4.75;
micro_start_y = shift_y + pcb_y - 23.3 - micro_y;

contrast_start_x = shift_x + 38.4;
contrast_start_y = shift_y + 25.7;
volume_start_x = shift_x + pcb_x - 39.2;
volume_start_y = contrast_start_y;
pot_d = 7;
under_pcb = 13;
fn = 10;
gaika_h = 6;
gaika_w = 5.6;
stoiki_r = 4;

translate([0,0,-50]) {

difference() {
  union() {
    difference() {
      cube([box_x,box_y,box_z], false);
      translate([th, th, th]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, box_z-th+eps], false);
      }
    }
    // under_pcb, stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
//        translate([dx,dy,pcb_up/2+th-eps]) {
//          cube(size=[under_pcb,under_pcb,pcb_up], center=true);
//        }
        translate([dx,dy,th-eps+pcb_up/2]) {
          cylinder(r=stoiki_r, h=pcb_up, center=true);
        }
      }
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=th+pcb_up+2*eps);
        // gaika
        cylinder($fn=6, r=gaika_w / 2 / cos(30) + 0.05, h=gaika_h);
      }
    }
  }

//    for (i = [0:1:socket_n-1]) {
//        translate([start_socket_x+i*socket_int-tol, box_y-th-eps, start_socket_z]) {
//            cube(size=[socket_w+2*tol, th+2*eps, box_z]);
//        }
//    }

//    // usb_in1 type b
//    translate([box_x-th-eps, start_type_b_y-tol, start_type_b_z]) {
//        cube(size=[th+2*eps, usb_type_b_w+2*tol, box_z]);
//    }

//    // usb_out1 type a
//    translate([-eps, start_type_a_y - tol, start_type_a_z]) {
//        cube(size=[th+2*eps, usb_type_a_w + 2*tol, box_z]);
//    }

    // programmator
    translate([micro_start_x-tol,micro_start_y-tol, -eps]) {
      cube(size=[micro_x+2*tol, micro_y+2*tol, th+2*eps]);
    }

    // contrast
    translate([contrast_start_x, contrast_start_y, -eps]) {
      cylinder($fn=fn, r=pot_d/2, h=th+2*eps);
    }

    // volume
//    translate([volume_start_x, volume_start_y, -eps]) {
//      cylinder($fn=20, r=pot_d/2, h=th+2*eps);
//    }
}
}

top_box_z = 17 + th;
stoiki_h = top_box_z - th;
pcb_room = 0.5;
screen_start_x = shift_x + 28;
screen_start_y = shift_y + 40;
screen_length_x = 72;
screen_length_y = 24;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 14;
screen_hold_y_shift = -2;

master_button_y = shift_y + 10;
master_button_x = shift_x + 43;
master_button_int = 21.8;
master_button_r = 3;
top_bolt_h = 2.5;
top_bolt_r = 3.5;
speaker_shift = 18;
speaker_r = 15;
speaker_h = 15;

!difference() {
  union() {
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room]) {
	       cylinder($fn=6, r=stoiki_r, h=top_box_z-th+eps);
          //cube(size=[under_pcb, under_pcb, stoiki_h + eps], center=true);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y + screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=top_box_z+2*eps);
      }
      translate([dx, dy, top_box_z - top_bolt_h]) {
        cylinder($fn=6, r=top_bolt_r, h=top_bolt_h + eps);
      }
    }
  }

  // screen
  translate([screen_start_x-tol, screen_start_y-tol, top_box_z - th - eps]) {
      cube([screen_length_x + 2*tol, screen_length_y + 2*tol, th + 2*eps]);
  }
  // sockets
  for (i = [0:1:socket_n-1]) {
      translate([start_socket_x+i*socket_int-tol, box_y-th-eps, -eps]) {
	  cube(size=[socket_w+2*tol, th+2*eps, socket_h+tol]);
      }
  }
  // type_b
  translate([box_x - th - eps, start_type_b_y - tol, -tol]) {
      cube([th + 2*eps, usb_type_b_w + 2*tol, usb_type_b_h + 2*tol]);
  }
  // type_a
  translate([-eps, start_type_a_y - tol, -tol]) {
      cube([th + 2*eps, usb_type_a_w + 2*tol, usb_type_a_h + 2*tol]);
  }
  // master buttons
  for (dx = [master_button_x, master_button_x + master_button_int*2])
      translate([dx, master_button_y, top_box_z - th - eps]) {
	  cylinder($fn=fn, r=master_button_r+tol, h=th+2*eps);
      }
}

//// bolts
//for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
//  for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
//    difference() {
//      translate([dx,dy,pcb_up/2+th]) {
//        cube(size=[a,a,pcb_up], center=true);
//      }
//      translate([dx,dy,-eps]) {
//        cylinder($fn=20, r=bolt_d/2, h=th+pcb_up+2*eps);
//      }
//    }
//  }
//}

//leg_r = t;
//shift = t/2+leg_r;
//for (dx = [shift, a-shift])
//    for (dy = [shift, b-shift]) {
//        translate([dx, dy, 0]) {
//            cylinder(h=c, r=leg_r, $fn=40);
//        }
//    }

tol = 0.5;
pcb_x = 130;
pcb_y = 110;
pcb_z = 4;
bolt_d = 3.6;
shift_bolt = 5;

// box thickness
th = 2;

shift_x = th + 1;
shift_y = th + 1;

box_x = pcb_x + shift_x + th + 1;
box_y = pcb_y + 2*th + 1;

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

socket_h = 15;
socket_w = 10;
socket_n = 5;
socket_int = 20;
start_socket_x = 20 + shift_x;
start_socket_z = th + pcb_z + tol;
eps = 1e-1;

usb_type_b_w = 15.2;
usb_type_b_h = 11.5;
start_type_b_y = shift_y + pcb_y - 30.1;
//start_type_b_z = th + pcb_z + tol;

usb_type_a_w = 17.3;
usb_type_a_h = 8;
//usb_type_a_h = 0.5;
start_type_a_y = shift_y + 44.7;
//start_type_a_z = th + pcb_z + tol;

// programmator
micro_x = 10;
micro_y = 21.1;
micro_start_x = shift_x + 4.75;
micro_start_y = shift_y + pcb_y - 23.3 - micro_y;

contrast_start_x = shift_x + 38.4;
contrast_start_y = shift_y + 25.7;
volume_start_x = shift_x + pcb_x - 39.2;
volume_start_y = contrast_start_y;
pot_d = 7;
under_pcb = 12.5;
fn = 10;
gaika_h = 6;
gaika_w = 5.6;

translate([0,0,-50]) {

difference() {
  union() {
    difference() {
      cube([box_x,box_y,box_z], false);
      translate([th, th, th]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, box_z-th+eps], false);
      }
    }
    // under_pcb
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_up/2+th-eps]) {
          cube(size=[under_pcb,under_pcb,pcb_up], center=true);
        }
      }
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=th+pcb_up+2*eps);
        // gaika
        cylinder($fn=6, r=gaika_w / 2 / cos(30) + 0.05, h=gaika_h);
      }
    }
  }

//    for (i = [0:1:socket_n-1]) {
//        translate([start_socket_x+i*socket_int-tol, box_y-th-eps, start_socket_z]) {
//            cube(size=[socket_w+2*tol, th+2*eps, box_z]);
//        }
//    }

//    // usb_in1 type b
//    translate([box_x-th-eps, start_type_b_y-tol, start_type_b_z]) {
//        cube(size=[th+2*eps, usb_type_b_w+2*tol, box_z]);
//    }

//    // usb_out1 type a
//    translate([-eps, start_type_a_y - tol, start_type_a_z]) {
//        cube(size=[th+2*eps, usb_type_a_w + 2*tol, box_z]);
//    }

    // programmator
    translate([micro_start_x-tol,micro_start_y-tol, -eps]) {
      cube(size=[micro_x+2*tol, micro_y+2*tol, th+2*eps]);
    }

    // contrast
    translate([contrast_start_x, contrast_start_y, -eps]) {
      cylinder($fn=fn, r=pot_d/2, h=th+2*eps);
    }

    // volume
//    translate([volume_start_x, volume_start_y, -eps]) {
//      cylinder($fn=20, r=pot_d/2, h=th+2*eps);
//    }
}
}

top_box_z = 17 + th;
stoiki_r = bolt_d/2 + 2;
stoiki_h = top_box_z - th;
pcb_room = 0.5;
screen_start_x = shift_x + 28;
screen_start_y = shift_y + 40;
screen_length_x = 72;
screen_length_y = 24;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 14;
screen_hold_y_shift = -2;

master_button_y = shift_y + 10;
master_button_x = shift_x + 43;
master_button_int = 21.8;
master_button_r = 3;
top_bolt_h = 2.5;
top_bolt_r = 3.5;
speaker_shift = 18;
speaker_r = 15;
speaker_h = 15;

difference() {
  union() {
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room+stoiki_h/2]) {
	       //cylinder($fn=fn, r=stoiki_r, h=top_box_z-th+eps);
           cube(size=[under_pcb, under_pcb, stoiki_h + eps], center=true);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y + screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=top_box_z+2*eps);
      }
      translate([dx, dy, top_box_z - top_bolt_h]) {
        cylinder($fn=fn, r=top_bolt_r, h=top_bolt_h + eps);
      }
    }
  }

  // screen
  translate([screen_start_x-tol, screen_start_y-tol, top_box_z - th - eps]) {
      cube([screen_length_x + 2*tol, screen_length_y + 2*tol, th + 2*eps]);
  }
  // sockets
  for (i = [0:1:socket_n-1]) {
      translate([start_socket_x+i*socket_int-tol, box_y-th-eps, -eps]) {
	  cube(size=[socket_w+2*tol, th+2*eps, socket_h+tol]);
      }
  }
  // type_b
  translate([box_x - th - eps, start_type_b_y - tol, -tol]) {
      cube([th + 2*eps, usb_type_b_w + 2*tol, usb_type_b_h + 2*tol]);
  }
  // type_a
  translate([-eps, start_type_a_y - tol, -tol]) {
      cube([th + 2*eps, usb_type_a_w + 2*tol, usb_type_a_h + 2*tol]);
  }
  // master buttons
  for (dx = [master_button_x, master_button_x + master_button_int*2])
      translate([dx, master_button_y, top_box_z - th - eps]) {
	  cylinder($fn=fn, r=master_button_r+tol, h=th+2*eps);
      }
}

//// bolts
//for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
//  for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
//    difference() {
//      translate([dx,dy,pcb_up/2+th]) {
//        cube(size=[a,a,pcb_up], center=true);
//      }
//      translate([dx,dy,-eps]) {
//        cylinder($fn=20, r=bolt_d/2, h=th+pcb_up+2*eps);
//      }
//    }
//  }
//}

//leg_r = t;
//shift = t/2+leg_r;
//for (dx = [shift, a-shift])
//    for (dy = [shift, b-shift]) {
//        translate([dx, dy, 0]) {
//            cylinder(h=c, r=leg_r, $fn=40);
//        }
//    }


helper object that guides the rod, to make sure rocket starts in a proper orientation

eps = 0.01;
rod_d = 5+1.2;

module rod_guide()
{
  intersection()
  {
    // main block
    difference()
    {
      cylinder(d=rod_d+1.5, h=20, $fn=30);
      translate([0, 0, -eps])
        cylinder(d=rod_d, h=20+2*eps, $fn=100);
    }
    // cut at the top, to minimize drag
    translate([-50/2, -50/2, -30+1.2])
      rotate([45, 0, 0])
    cube([50, 50, 50]);
  }
}

for(i=[0:1])
  translate([0, i*(rod_d+3), 0])
    rod_guide();

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


Debug print statements were commented out of execution.

/*
 * knurledFinishLib_v2.scad
 *
 * Written by aubenc @ Thingiverse
 *
 * This script is licensed under the Public Domain license.
 *
 * http://www.thingiverse.com/thing:31122
 *
 * Derived from knurledFinishLib.scad (also Public Domain license) available at
 *
 * http://www.thingiverse.com/thing:9095
 *
 * Usage:
 *
 *	 Drop this script somewhere where OpenSCAD can find it (your current project's
 *	 working directory/folder or your OpenSCAD libraries directory/folder).
 *
 *	 Add the line:
 *
 *		use <knurledFinishLib_v2.scad>
 *
 *	 in your OpenSCAD script and call either...
 *
 *    knurled_cyl( Knurled cylinder height,
 *                 Knurled cylinder outer diameter,
 *                 Knurl polyhedron width,
 *                 Knurl polyhedron height,
 *                 Knurl polyhedron depth,
 *                 Cylinder ends smoothed height,
 *                 Knurled surface smoothing amount );
 *
 *  ...or...
 *
 *    knurl();
 *
 *	If you use knurled_cyl() module, you need to specify the values for all and
 *
 *  Call the module ' help(); ' for a little bit more of detail
 *  and/or take a look to the PDF available at http://www.thingiverse.com/thing:9095
 *  for a in depth descrition of the knurl properties.
 */

module knurl(	k_cyl_hg	= 12,
					k_cyl_od	= 25,
					knurl_wd =  3,
					knurl_hg =  4,
					knurl_dp =  1.5,
					e_smooth =  2,
					s_smooth =  0)
{
    knurled_cyl(k_cyl_hg, k_cyl_od,
                knurl_wd, knurl_hg, knurl_dp,
                e_smooth, s_smooth);
}

module knurled_cyl(chg, cod, cwd, csh, cdp, fsh, smt)
{
    cord=(cod+cdp+cdp*smt/100)/2;
    cird=cord-cdp;
    cfn=round(2*cird*PI/cwd);
    clf=360/cfn;
    crn=ceil(chg/csh);

//    echo("knurled cylinder max diameter: ", 2*cord);
//    echo("knurled cylinder min diameter: ", 2*cird);

	 if( fsh < 0 )
    {
        union()
        {
            shape(fsh, cird+cdp*smt/100, cord, cfn*4, chg);

            translate([0,0,-(crn*csh-chg)/2])
              knurled_finish(cord, cird, clf, csh, cfn, crn);
        }
    }
    else if ( fsh == 0 )
    {
        intersection()
        {
            cylinder(h=chg, r=cord-cdp*smt/100, $fn=2*cfn, center=false);

            translate([0,0,-(crn*csh-chg)/2])
              knurled_finish(cord, cird, clf, csh, cfn, crn);
        }
    }
    else
    {
        intersection()
        {
            shape(fsh, cird, cord-cdp*smt/100, cfn*4, chg);

            translate([0,0,-(crn*csh-chg)/2])
              knurled_finish(cord, cird, clf, csh, cfn, crn);
        }
    }
}

module shape(hsh, ird, ord, fn4, hg)
{
	x0= 0;	x1 = hsh > 0 ? ird : ord;		x2 = hsh > 0 ? ord : ird;
	y0=-0.1;	y1=0;	y2=abs(hsh);	y3=hg-abs(hsh);	y4=hg;	y5=hg+0.1;

	if ( hsh >= 0 )
	{
		rotate_extrude(convexity=10, $fn=fn4)
		polygon(points=[	[x0,y1],[x1,y1],[x2,y2],[x2,y3],[x1,y4],[x0,y4]	],
					paths=[	[0,1,2,3,4,5]	]);
	}
	else
	{
		rotate_extrude(convexity=10, $fn=fn4)
		polygon(points=[	[x0,y0],[x1,y0],[x1,y1],[x2,y2],
								[x2,y3],[x1,y4],[x1,y5],[x0,y5]	],
					paths=[	[0,1,2,3,4,5,6,7]	]);
	}
}

module knurled_finish(ord, ird, lf, sh, fn, rn)
{
    for(j=[0:rn-1])
    assign(h0=sh*j, h1=sh*(j+1/2), h2=sh*(j+1))
    {
        for(i=[0:fn-1])
        assign(lf0=lf*i, lf1=lf*(i+1/2), lf2=lf*(i+1))
        {
            polyhedron(
                points=[
                     [ 0,0,h0],
                     [ ord*cos(lf0), ord*sin(lf0), h0],
                     [ ird*cos(lf1), ird*sin(lf1), h0],
                     [ ord*cos(lf2), ord*sin(lf2), h0],

                     [ ird*cos(lf0), ird*sin(lf0), h1],
                     [ ord*cos(lf1), ord*sin(lf1), h1],
                     [ ird*cos(lf2), ird*sin(lf2), h1],

                     [ 0,0,h2],
                     [ ord*cos(lf0), ord*sin(lf0), h2],
                     [ ird*cos(lf1), ird*sin(lf1), h2],
                     [ ord*cos(lf2), ord*sin(lf2), h2]
                    ],
                triangles=[
                     [0,1,2],[2,3,0],
                     [1,0,4],[4,0,7],[7,8,4],
                     [8,7,9],[10,9,7],
                     [10,7,6],[6,7,0],[3,6,0],
                     [2,1,4],[3,2,6],[10,6,9],[8,9,4],
                     [4,5,2],[2,5,6],[6,5,9],[9,5,4]
                    ],
                convexity=5);
         }
    }
}

module knurl_help()
{
	echo();
	echo("    Knurled Surface Library  v2  ");
   echo("");
	echo("      Modules:    ");
	echo("");
	echo("        knurled_cyl(parameters... );    -    Requires a value for each an every expected parameter (see bellow)    ");
	echo("");
	echo("        knurl();    -    Call to the previous module with a set of default parameters,    ");
	echo("                                  values may be changed by adding 'parameter_name=value'        i.e.     knurl(s_smooth=40);    ");
	echo("");
	echo("      Parameters, all of them in mm but the last one.    ");
	echo("");
	echo("        k_cyl_hg       -   [ 12   ]  ,,  Height for the knurled cylinder    ");
	echo("        k_cyl_od      -   [ 25   ]  ,,  Cylinder's Outer Diameter before applying the knurled surfacefinishing.    ");
	echo("        knurl_wd     -   [   3   ]  ,,  Knurl's Width.    ");
	echo("        knurl_hg      -   [   4   ]  ,,  Knurl's Height.    ");
	echo("        knurl_dp     -   [  1.5 ]  ,,  Knurl's Depth.    ");
	echo("        e_smooth   -    [  2   ]  ,,  Bevel's Height at the bottom and the top of the cylinder    ");
	echo("        s_smooth   -    [  0   ]  ,,  Knurl's Surface Smoothing :  File donwn the top of the knurl this value, i.e. 40 will snooth it a 40%.    ");
	echo("");
}

/*
 * knurledFinishLib_v2.scad
 *
 * Written by aubenc @ Thingiverse
 *
 * This script is licensed under the Public Domain license.
 *
 * http://www.thingiverse.com/thing:31122
 *
 * Derived from knurledFinishLib.scad (also Public Domain license) available at
 *
 * http://www.thingiverse.com/thing:9095
 *
 * Usage:
 *
 *	 Drop this script somewhere where OpenSCAD can find it (your current project's
 *	 working directory/folder or your OpenSCAD libraries directory/folder).
 *
 *	 Add the line:
 *
 *		use <knurledFinishLib_v2.scad>
 *
 *	 in your OpenSCAD script and call either...
 *
 *    knurled_cyl( Knurled cylinder height,
 *                 Knurled cylinder outer diameter,
 *                 Knurl polyhedron width,
 *                 Knurl polyhedron height,
 *                 Knurl polyhedron depth,
 *                 Cylinder ends smoothed height,
 *                 Knurled surface smoothing amount );
 *
 *  ...or...
 *
 *    knurl();
 *
 *	If you use knurled_cyl() module, you need to specify the values for all and
 *
 *  Call the module ' help(); ' for a little bit more of detail
 *  and/or take a look to the PDF available at http://www.thingiverse.com/thing:9095
 *  for a in depth descrition of the knurl properties.
 */

module knurl(	k_cyl_hg	= 12,
					k_cyl_od	= 25,
					knurl_wd =  3,
					knurl_hg =  4,
					knurl_dp =  1.5,
					e_smooth =  2,
					s_smooth =  0)
{
    knurled_cyl(k_cyl_hg, k_cyl_od,
                knurl_wd, knurl_hg, knurl_dp,
                e_smooth, s_smooth);
}

module knurled_cyl(chg, cod, cwd, csh, cdp, fsh, smt)
{
    cord=(cod+cdp+cdp*smt/100)/2;
    cird=cord-cdp;
    cfn=round(2*cird*PI/cwd);
    clf=360/cfn;
    crn=ceil(chg/csh);

    echo("knurled cylinder max diameter: ", 2*cord);
    echo("knurled cylinder min diameter: ", 2*cird);

	 if( fsh < 0 )
    {
        union()
        {
            shape(fsh, cird+cdp*smt/100, cord, cfn*4, chg);

            translate([0,0,-(crn*csh-chg)/2])
              knurled_finish(cord, cird, clf, csh, cfn, crn);
        }
    }
    else if ( fsh == 0 )
    {
        intersection()
        {
            cylinder(h=chg, r=cord-cdp*smt/100, $fn=2*cfn, center=false);

            translate([0,0,-(crn*csh-chg)/2])
              knurled_finish(cord, cird, clf, csh, cfn, crn);
        }
    }
    else
    {
        intersection()
        {
            shape(fsh, cird, cord-cdp*smt/100, cfn*4, chg);

            translate([0,0,-(crn*csh-chg)/2])
              knurled_finish(cord, cird, clf, csh, cfn, crn);
        }
    }
}

module shape(hsh, ird, ord, fn4, hg)
{
	x0= 0;	x1 = hsh > 0 ? ird : ord;		x2 = hsh > 0 ? ord : ird;
	y0=-0.1;	y1=0;	y2=abs(hsh);	y3=hg-abs(hsh);	y4=hg;	y5=hg+0.1;

	if ( hsh >= 0 )
	{
		rotate_extrude(convexity=10, $fn=fn4)
		polygon(points=[	[x0,y1],[x1,y1],[x2,y2],[x2,y3],[x1,y4],[x0,y4]	],
					paths=[	[0,1,2,3,4,5]	]);
	}
	else
	{
		rotate_extrude(convexity=10, $fn=fn4)
		polygon(points=[	[x0,y0],[x1,y0],[x1,y1],[x2,y2],
								[x2,y3],[x1,y4],[x1,y5],[x0,y5]	],
					paths=[	[0,1,2,3,4,5,6,7]	]);
	}
}

module knurled_finish(ord, ird, lf, sh, fn, rn)
{
    for(j=[0:rn-1])
    assign(h0=sh*j, h1=sh*(j+1/2), h2=sh*(j+1))
    {
        for(i=[0:fn-1])
        assign(lf0=lf*i, lf1=lf*(i+1/2), lf2=lf*(i+1))
        {
            polyhedron(
                points=[
                     [ 0,0,h0],
                     [ ord*cos(lf0), ord*sin(lf0), h0],
                     [ ird*cos(lf1), ird*sin(lf1), h0],
                     [ ord*cos(lf2), ord*sin(lf2), h0],

                     [ ird*cos(lf0), ird*sin(lf0), h1],
                     [ ord*cos(lf1), ord*sin(lf1), h1],
                     [ ird*cos(lf2), ird*sin(lf2), h1],

                     [ 0,0,h2],
                     [ ord*cos(lf0), ord*sin(lf0), h2],
                     [ ird*cos(lf1), ird*sin(lf1), h2],
                     [ ord*cos(lf2), ord*sin(lf2), h2]
                    ],
                triangles=[
                     [0,1,2],[2,3,0],
                     [1,0,4],[4,0,7],[7,8,4],
                     [8,7,9],[10,9,7],
                     [10,7,6],[6,7,0],[3,6,0],
                     [2,1,4],[3,2,6],[10,6,9],[8,9,4],
                     [4,5,2],[2,5,6],[6,5,9],[9,5,4]
                    ],
                convexity=5);
         }
    }
}

module knurl_help()
{
	echo();
	echo("    Knurled Surface Library  v2  ");
   echo("");
	echo("      Modules:    ");
	echo("");
	echo("        knurled_cyl(parameters... );    -    Requires a value for each an every expected parameter (see bellow)    ");
	echo("");
	echo("        knurl();    -    Call to the previous module with a set of default parameters,    ");
	echo("                                  values may be changed by adding 'parameter_name=value'        i.e.     knurl(s_smooth=40);    ");
	echo("");
	echo("      Parameters, all of them in mm but the last one.    ");
	echo("");
	echo("        k_cyl_hg       -   [ 12   ]  ,,  Height for the knurled cylinder    ");
	echo("        k_cyl_od      -   [ 25   ]  ,,  Cylinder's Outer Diameter before applying the knurled surfacefinishing.    ");
	echo("        knurl_wd     -   [   3   ]  ,,  Knurl's Width.    ");
	echo("        knurl_hg      -   [   4   ]  ,,  Knurl's Height.    ");
	echo("        knurl_dp     -   [  1.5 ]  ,,  Knurl's Depth.    ");
	echo("        e_smooth   -    [  2   ]  ,,  Bevel's Height at the bottom and the top of the cylinder    ");
	echo("        s_smooth   -    [  0   ]  ,,  Knurl's Surface Smoothing :  File donwn the top of the knurl this value, i.e. 40 will snooth it a 40%.    ");
	echo("");
}