Small radius mods

Small radius mods


shapes: rename rcylinder to rcylindera

shapes: rename rcylinder to rcylindera

include <system.scad>
include <units.scad>
use <misc.scad>
use <transforms.scad>

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

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

/*cubea(size=[10,20,30], align=[0,-1,0], orient=[0,0,1], roll=10, extra_roll=-30, extra_roll_orient=[1,0,0]);*/

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

module cylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        round_radius=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, [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=[0,0,1], align=align, extra_align=extra_align)
    {
        if(round_radius>0)
        {
            rcylindera(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, round_radius=round_radius);
        }
        else
        {
            cylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, center=true);
        }
    }
}

/*translate([10,0,0])*/
/*rotate_extrude()*/
        /*translate([10-2,2,0])*/
/*$fa = 5.6;*/
/*$fs = 0.3;*/
/*circle(r = 100);*/
/*torus(10, 2, align=[0,0,0], orient=[0,0,1]);*/

module torus(radius, radial_width, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[radius*2+radial_width*2, radius*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate([radius, 0, 0])
    circle(radial_width);
}

module rcylindera(d, d1, d2, r, r1, r2, h=10, round_radius=2, align=[0,0,0], orient=[0,0,1])
{
    if($preview_mode || round_radius == 0 || true)
    {
        cylindera(d=d, d1=d1, d2=d2, r=r, r1=r1, r2=r2, h=h, align=align, orient=orient);
    }
    else
    {
        d1_ = v_fallback(d1, [r*2, r1*2]);
        d2_ = v_fallback(d2, [r*2, r2*2]);

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

        r_ = [r1_,r2_];

        size_align(align=align, orient=orient)
            hull()
            {
                for(z=[-1,1])
                    translate([0, 0, z*(-h/2)])
                    {
                        r__=z!=-1?r_[0]:r_[1];
                        torus(radius=r__-round_radius/2, radial_width=round_radius/2, align=[0,0,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=[0,0,1], align=[0,0,0])
{
    size_align(size=[r*2, r*2, h], orient=orient, orient_ref=[0,0,1], 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=undef, orient=[0,0,1], align=[0,0,0])
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    taper_h = taper_h == undef ? 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=[0,0,1], align=[0,0,0]);
            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=[0,0,1]);
            }
        }
        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=[0,0,1]);

            // 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=[0,0,1], align=[0,0,0], $fn=fn);
        }
        else
        {
            cylindera(h=h+.2, d=inner_d, orient=[0,0,1], align=[0,0,0]);
        }
    }
}

/**
 * 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=[0,0,0], orient=[0,0,1])
{
    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, rounding_radius=2, align=[0,0,0], orient=[0,0,1])
{
    size = [a_len-rounding_radius, depth-rounding_radius, o_len-rounding_radius];
    r_x = rounding_radius;
    r_y = rounding_radius;
    r_z = -rounding_radius;

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

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

    /*translate([size[0]+4,0,0])*/
    /*color([1,0,0])*/
    /*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)+rounding_radius,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+rounding_radius,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+rounding_radius,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=rounding_radius);
}

module teardrop(r, d, h=10, truncate=1, align=[0,0,0], orient=[0,1,0], 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=[0,0,1], 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;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        teardrop(r=r, h=20, orient=axis, align=axis);
    }
}

// test cubea
if(false)
{
    w=5*mm;
    h=2*mm;
    for(axis=concat(AXES,-AXES))
    /*translate(axis)*/
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        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=[0,0,-1]);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,1]);*/

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

/**
 * 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=XAXIS, dist=15)
    {
        hollow_cylinder(thickness=5, h=10, taper=false, orient=[0,0,1], align=[0,0,1]);
        hollow_cylinder(thickness=5, h=10, taper=true, orient=[0,0,1], align=[0,0,1]);
    }

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

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

    /*cubea([10,10,10],[1,0,0]);*/
    /*%cubea([10,10,10],[1,0,0],[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=[1,0,0], extra_d=10);*/

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

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

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

    cylindera(h=20, r=5*mm, align=[0,1,0], orient=[0,0,1], $fn=100);

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

/*cylindera(d=10, h=10, orient=[0,1,0], align=[0,0,1]);*/
}

if(false)
{
    r=5*mm;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        /*cylindera(h=20, r=r, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=100);*/
        cylindera(h=20, r1=r, r2=r/2, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=16, round_radius=2);
    }
}

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

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

include <system.scad>
include <units.scad>
use <misc.scad>
use <transforms.scad>

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

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

/*cubea(size=[10,20,30], align=[0,-1,0], orient=[0,0,1], roll=10, extra_roll=-30, extra_roll_orient=[1,0,0]);*/

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

module cylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        round_radius=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, [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=[0,0,1], align=align, extra_align=extra_align)
    {
        if(round_radius>0)
        {
            rcylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, round_radius=round_radius);
        }
        else
        {
            cylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, center=true);
        }
    }
}

/*translate([10,0,0])*/
/*rotate_extrude()*/
        /*translate([10-2,2,0])*/
/*$fa = 5.6;*/
/*$fs = 0.3;*/
/*circle(r = 100);*/
/*torus(10, 2, align=[0,0,0], orient=[0,0,1]);*/

module torus(radius, radial_width, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[radius*2+radial_width*2, radius*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate([radius, 0, 0])
    circle(radial_width);
}

module rcylinder(d, d1, d2, r, r1, r2, h=10, round_radius=2, align=[0,0,0], orient=[0,0,1])
{
    if($preview_mode || round_radius == 0 || true)
    {
        cylindera(d=d, d1=d1, d2=d2, r=r, r1=r1, r2=r2, h=h, align=align, orient=orient);
    }
    else
    {
        d1_ = v_fallback(d1, [r*2, r1*2]);
        d2_ = v_fallback(d2, [r*2, r2*2]);

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

        r_ = [r1_,r2_];

        size_align(align=align, orient=orient)
            hull()
            {
                for(z=[-1,1])
                    translate([0, 0, z*(-h/2)])
                    {
                        r__=z!=-1?r_[0]:r_[1];
                        torus(radius=r__-round_radius/2, radial_width=round_radius/2, align=[0,0,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=[0,0,1], align=[0,0,0])
{
    size_align(size=[r*2, r*2, h], orient=orient, orient_ref=[0,0,1], 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=undef, orient=[0,0,1], align=[0,0,0])
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    taper_h = taper_h == undef ? 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=[0,0,1], align=[0,0,0]);
            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=[0,0,1]);
            }
        }
        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=[0,0,1]);

            // 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=[0,0,1], align=[0,0,0], $fn=fn);
        }
        else
        {
            cylindera(h=h+.2, d=inner_d, orient=[0,0,1], align=[0,0,0]);
        }
    }
}

/**
 * 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=[0,0,0], orient=[0,0,1])
{
    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, rounding_radius=2, align=[0,0,0], orient=[0,0,1])
{
    size = [a_len-rounding_radius, depth-rounding_radius, o_len-rounding_radius];
    r_x = rounding_radius;
    r_y = rounding_radius;
    r_z = -rounding_radius;

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

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

    /*translate([size[0]+4,0,0])*/
    /*color([1,0,0])*/
    /*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)+rounding_radius,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+rounding_radius,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+rounding_radius,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=rounding_radius);
}

module teardrop(r, d, h=10, truncate=1, align=[0,0,0], orient=[0,1,0], 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=[0,0,1], 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;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        teardrop(r=r, h=20, orient=axis, align=axis);
    }
}

// test cubea
if(false)
{
    w=5*mm;
    h=2*mm;
    for(axis=concat(AXES,-AXES))
    /*translate(axis)*/
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        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=[0,0,-1]);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,1]);*/

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

/**
 * 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=XAXIS, dist=15)
    {
        hollow_cylinder(thickness=5, h=10, taper=false, orient=[0,0,1], align=[0,0,1]);
        hollow_cylinder(thickness=5, h=10, taper=true, orient=[0,0,1], align=[0,0,1]);
    }

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

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

    /*cubea([10,10,10],[1,0,0]);*/
    /*%cubea([10,10,10],[1,0,0],[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=[1,0,0], extra_d=10);*/

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

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

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

    cylindera(h=20, r=5*mm, align=[0,1,0], orient=[0,0,1], $fn=100);

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

/*cylindera(d=10, h=10, orient=[0,1,0], align=[0,0,1]);*/
}

if(false)
{
    r=5*mm;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        /*cylindera(h=20, r=r, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=100);*/
        cylindera(h=20, r1=r, r2=r/2, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=16, round_radius=2);
    }
}

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

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


fixup! main/yaxis: better belt placement logic

include <MCAD/stepper.scad>
include <MCAD/motors.scad>

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

ycarriage_bearing_mount_bottom_thick = 3;
ycarriage_bearing_mount_conn_bottom = [[0,0,0], [0,0,1]];
ycarriage_bearing_mount_conn_bearing = [[0,0,ycarriage_bearing_mount_bottom_thick+yaxis_bearing[1]/2], [0,0,1]];

module ycarriage_bearing_mount(show_bearing=false, show_zips=false)
{
    // x distance of holes
    screw_dx=28;
    // y distance of holes
    screw_dy=21;

    carriage_plate_thread=ThreadM4;
    carriage_plate_thread_d=lookup(ThreadSize, carriage_plate_thread);

    width = screw_dx+carriage_plate_thread_d*2;
    depth = max(yaxis_bearing[1], screw_dx+carriage_plate_thread_d*2);
    /*height = yaxis_bearing[1]/2+ycarriage_bearing_mount_bottom_thick;*/
    height = 5+ycarriage_bearing_mount_bottom_thick;

    difference()
    {
        union()
        {
            cubea ([width, depth, height], align=[0,0,1]);
        }

        translate ([+screw_dx/2, +screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);
        translate ([+screw_dx/2, -screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);
        translate ([-screw_dx/2, +screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);
        translate ([-screw_dx/2, -screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);

        translate([0,0,yaxis_bearing[1]/2+ycarriage_bearing_mount_bottom_thick])
        bearing_mount_holes(yaxis_bearing, orient=[0,1,0], ziptie_dist=5, show_zips=show_zips);
    }

    %if(show_bearing)
    {
        translate([0,0,yaxis_bearing[1]/2+ycarriage_bearing_mount_bottom_thick])
        bearing(yaxis_bearing, orient=[0,1,0]);
    }
}

/*c1=[[0,0,0],[0,0,-1]];*/
/*attach(c1,ycarriage_bearing_mount_conn)*/
/*{*/
    /*ycarriage_bearing_mount();*/
    /*#connector(ycarriage_bearing_mount_conn);*/
/*}*/

yaxis_motor_mount_conn = [[0,0,+extrusion_size/2+yaxis_motor_offset_z],[1,0,0]];
yaxis_motor_mount_conn_motor = [[+yaxis_motor_offset_x, 0,+extrusion_size/2+yaxis_motor_offset_z],[0,0,1]];

ymotor_w = lookup(NemaSideSize, yaxis_motor);
ymotor_h = lookup(NemaLengthLong, yaxis_motor);
ymotor_mount_thread_dia = lookup(ThreadSize, extrusion_thread);
ymotor_mount_h = main_lower_dist_z+extrusion_size+yaxis_motor_offset_z;
ymotor_mount_width = ymotor_w+ymotor_mount_thickness*2 + ymotor_mount_thread_dia*8;

yaxis_motor_pulley_h = 17.5*mm;
yaxis_motor_mount_bearing_clamp_offset_z = yaxis_motor_pulley_h;

module yaxis_motor_mount_bearing_clamp(align=[0,0,0])
{
    bearing_d = bearing_625[1];
    bearing_h = bearing_625[2];
    width=ymotor_w+ymotor_mount_thickness;
    depth=ymotor_w+ymotor_mount_thickness*2;
    height=yaxis_motor_mount_bearing_clamp_offset_z;

    /*size_align(size=[width,depth,height], align=align);*/
    difference()
    {
        cubea([width, depth, height], align=[0,0,-1]);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        translate([0,0,.1])
            fncylindera(h=bearing_h*2, d=bearing_d*rod_fit_tolerance, orient=[0,0,1], align=[0,0,-1]);

        // cutout for belt path
        fncylindera(d=bearing_d, h=height*2, orient=[0,0,1], align=[0,0,-1]);
        translate([depth/2, 0, -bearing_h])
            cubea([depth, ymotor_round_d, height-bearing_h+1], align=[0,0,-1]);

        // cut out motor mount holes etc
        screw_dist = lookup(NemaDistanceBetweenMountingHoles, yaxis_motor);
        for(x=[-1,1])
        for(y=[-1,1])
        translate([x*screw_dist/2, y*screw_dist/2, 1])
        fncylindera(h=height, d=3*mm, orient=[0,0,1], align=[0,0,-1]);
    }

    // debug bearing
    %fncylindera(h=bearing_h, d=bearing_d*rod_fit_tolerance, align=[0,0,-1], orient=[0,0,1]);
}

module motor_mount_top(width, depth, height, belt_cutout=true, belt_cutout_orient=[1,0,0], align=[0,0,0])
{
    size_align(size=[width, depth, height], align=align);
    difference()
    {
        cubea([width, depth, height], align=[0,0,1]);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        // cutout for belt path
        fncylindera(d=ymotor_round_d, h=height*2, orient=[0,0,1], align=[0,0,0]);
        translate([0, 0,-1])
            cubea([depth/2, ymotor_round_d, height*2], align=[1,0,1]);

        // cut out motor mount holes etc
        translate([0,0,-1])
            linear_extrude(height+2)
            stepper_motor_mount(17, slide_distance=0, mochup=false);
    }
}

module yaxis_motor_mount(show_motor=false)
{
    difference()
    {
        // top plate
        union()
        {
            translate([0,0,yaxis_motor_offset_z])
            {
                // top plate
                translate([ymotor_mount_thickness,0,extrusion_size/2])
                {
                    /*translate([ymotor_w/2,0,ymotor_mount_thickness_h+yaxis_motor_mount_bearing_clamp_offset_z+1])*/
                        /*yaxis_motor_mount_bearing_clamp(align=[0,0,-1]);*/

                    translate([ymotor_w/2,0,0])
                        motor_mount_top(width=ymotor_w+ymotor_mount_thickness,
                        depth=ymotor_w+ymotor_mount_thickness*2,
                        height=ymotor_mount_thickness_h,
                        belt_cutout=true,
                        belt_cutout_orient=[1,0,0]);
                }

                translate([0,0,extrusion_size/2])
                {
                    difference()
                    {
                        // reinforcement plate between motor and extrusion
                        cubea([ymotor_mount_thickness, ymotor_w+ymotor_mount_thickness*2, ymotor_h], align=[1,0,-1], extrasize=[0,0,ymotor_mount_thickness_h], extrasize_align=[0,0,1]);

                        // cutout for motor cables
                        translate([0,0,-20*mm])
                            cubea([ymotor_mount_thickness*3, 20*mm, ymotor_h], align=[0,0,-1]);
                    }
                }

                // side triangles
                for(i=[-1,1])
                {
                    translate([ymotor_mount_thickness, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        rotate([90,90,0])
                        Right_Angled_Triangle(a=ymotor_w+ymotor_mount_thickness/2, b=main_lower_dist_z+extrusion_size+yaxis_motor_offset_z, height=ymotor_mount_thickness, centerXYZ=[0,0,1]);

                    translate([0, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        cubea([ymotor_mount_thickness, ymotor_mount_thickness, ymotor_mount_h], align=[1,0,-1]);
                }
            }

            // top mount plate
            difference()
            {
                cubea([ymotor_mount_thickness, ymotor_mount_width, extrusion_size], align=[1,0,0]);

                for(i=[-1,1])
                    translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                        fncylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia, orient=[1,0,0]);
            }

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

                    for(i=[0])
                        translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                            fncylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia,align=[0,0,0], orient=[1,0,0]);
                }
            }

        }

    }

    if(show_motor)
    {
        attach(yaxis_motor_mount_conn_motor,[[0,0,0],[0,0,0]])
        {
            motor(yaxis_motor, NemaMedium, dualAxis=false, orientation=[0,180,0]);

            translate([0,0,5*mm])
            fncylindera(d=yaxis_pulley_d, h=yaxis_motor_pulley_h, orient=[0,0,1]);
        }
    }
}

/*yaxis_motor_mount(show_motor=true);*/

include <MCAD/stepper.scad>
include <MCAD/motors.scad>

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

ycarriage_bearing_mount_bottom_thick = 3;
ycarriage_bearing_mount_conn_bottom = [[0,0,0], [0,0,1]];
ycarriage_bearing_mount_conn_bearing = [[0,0,ycarriage_bearing_mount_bottom_thick+yaxis_bearing[1]/2], [0,0,1]];

module ycarriage_bearing_mount(show_bearing=false, show_zips=false)
{
    // x distance of holes
    screw_dx=28;
    // y distance of holes
    screw_dy=21;

    carriage_plate_thread=ThreadM4;
    carriage_plate_thread_d=lookup(ThreadSize, carriage_plate_thread);

    width = screw_dx+carriage_plate_thread_d*2;
    depth = max(yaxis_bearing[1], screw_dx+carriage_plate_thread_d*2);
    /*height = yaxis_bearing[1]/2+ycarriage_bearing_mount_bottom_thick;*/
    height = 5+ycarriage_bearing_mount_bottom_thick;

    difference()
    {
        union()
        {
            cubea ([width, depth, height], align=[0,0,1]);
        }

        translate ([+screw_dx/2, +screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);
        translate ([+screw_dx/2, -screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);
        translate ([-screw_dx/2, +screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);
        translate ([-screw_dx/2, -screw_dy/2, -1]) fncylindera(d=carriage_plate_thread_d, h=height+2, align=[0,0,1]);

        translate([0,0,yaxis_bearing[1]/2+ycarriage_bearing_mount_bottom_thick])
        bearing_mount_holes(yaxis_bearing, orient=[0,1,0], ziptie_dist=5, show_zips=show_zips);
    }

    %if(show_bearing)
    {
        translate([0,0,yaxis_bearing[1]/2+ycarriage_bearing_mount_bottom_thick])
        bearing(yaxis_bearing, orient=[0,1,0]);
    }
}

/*c1=[[0,0,0],[0,0,-1]];*/
/*attach(c1,ycarriage_bearing_mount_conn)*/
/*{*/
    /*ycarriage_bearing_mount();*/
    /*#connector(ycarriage_bearing_mount_conn);*/
/*}*/

yaxis_motor_mount_conn = [[0,0,+extrusion_size/2+yaxis_motor_offset_z],[1,0,0]];
yaxis_motor_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_motor_mount_conn_motor = [[+yaxis_motor_offset_x, 0,+extrusion_size/2+yaxis_motor_offset_z],[0,0,1]];

ymotor_w = lookup(NemaSideSize, yaxis_motor);
ymotor_h = lookup(NemaLengthLong, yaxis_motor);
ymotor_mount_thread_dia = lookup(ThreadSize, extrusion_thread);
ymotor_mount_h = main_lower_dist_z+extrusion_size+yaxis_motor_offset_z;
ymotor_mount_width = ymotor_w+ymotor_mount_thickness*2 + ymotor_mount_thread_dia*8;

yaxis_motor_pulley_h = 17.5*mm;
yaxis_motor_mount_bearing_clamp_offset_z = yaxis_motor_pulley_h;

module yaxis_motor_mount_bearing_clamp(align=[0,0,0])
{
    bearing_d = bearing_625[1];
    bearing_h = bearing_625[2];
    width=ymotor_w+ymotor_mount_thickness;
    depth=ymotor_w+ymotor_mount_thickness*2;
    height=yaxis_motor_mount_bearing_clamp_offset_z;

    /*size_align(size=[width,depth,height], align=align);*/
    difference()
    {
        cubea([width, depth, height], align=[0,0,-1]);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        translate([0,0,.1])
            fncylindera(h=bearing_h*2, d=bearing_d*rod_fit_tolerance, orient=[0,0,1], align=[0,0,-1]);

        // cutout for belt path
        fncylindera(d=bearing_d, h=height*2, orient=[0,0,1], align=[0,0,-1]);
        translate([depth/2, 0, -bearing_h])
            cubea([depth, ymotor_round_d, height-bearing_h+1], align=[0,0,-1]);

        // cut out motor mount holes etc
        screw_dist = lookup(NemaDistanceBetweenMountingHoles, yaxis_motor);
        for(x=[-1,1])
        for(y=[-1,1])
        translate([x*screw_dist/2, y*screw_dist/2, 1])
        fncylindera(h=height, d=3*mm, orient=[0,0,1], align=[0,0,-1]);
    }

    // debug bearing
    %fncylindera(h=bearing_h, d=bearing_d*rod_fit_tolerance, align=[0,0,-1], orient=[0,0,1]);
}

module motor_mount_top(width, depth, height, belt_cutout=true, belt_cutout_orient=[1,0,0], align=[0,0,0])
{
    size_align(size=[width, depth, height], align=align);
    difference()
    {
        cubea([width, depth, height], align=[0,0,1]);

        ymotor_round_d = lookup(NemaRoundExtrusionDiameter, yaxis_motor);

        // cutout for belt path
        fncylindera(d=ymotor_round_d, h=height*2, orient=[0,0,1], align=[0,0,0]);
        translate([0, 0,-1])
            cubea([depth/2, ymotor_round_d, height*2], align=[1,0,1]);

        // cut out motor mount holes etc
        translate([0,0,-1])
            linear_extrude(height+2)
            stepper_motor_mount(17, slide_distance=0, mochup=false);
    }
}

module yaxis_motor_mount(show_motor=false)
{
    difference()
    {
        // top plate
        union()
        {
            translate([0,0,yaxis_motor_offset_z])
            {
                // top plate
                translate([ymotor_mount_thickness,0,extrusion_size/2])
                {
                    /*translate([ymotor_w/2,0,ymotor_mount_thickness_h+yaxis_motor_mount_bearing_clamp_offset_z+1])*/
                        /*yaxis_motor_mount_bearing_clamp(align=[0,0,-1]);*/

                    translate([ymotor_w/2,0,0])
                        motor_mount_top(width=ymotor_w+ymotor_mount_thickness,
                        depth=ymotor_w+ymotor_mount_thickness*2,
                        height=ymotor_mount_thickness_h,
                        belt_cutout=true,
                        belt_cutout_orient=[1,0,0]);
                }

                translate([0,0,extrusion_size/2])
                {
                    difference()
                    {
                        // reinforcement plate between motor and extrusion
                        cubea([ymotor_mount_thickness, ymotor_w+ymotor_mount_thickness*2, ymotor_h], align=[1,0,-1], extrasize=[0,0,ymotor_mount_thickness_h], extrasize_align=[0,0,1]);

                        // cutout for motor cables
                        translate([0,0,-20*mm])
                            cubea([ymotor_mount_thickness*3, 20*mm, ymotor_h], align=[0,0,-1]);
                    }
                }

                // side triangles
                for(i=[-1,1])
                {
                    translate([ymotor_mount_thickness, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        rotate([90,90,0])
                        Right_Angled_Triangle(a=ymotor_w+ymotor_mount_thickness/2, b=main_lower_dist_z+extrusion_size+yaxis_motor_offset_z, height=ymotor_mount_thickness, centerXYZ=[0,0,1]);

                    translate([0, i*((ymotor_w/2)+ymotor_mount_thickness/2), extrusion_size/2])
                        cubea([ymotor_mount_thickness, ymotor_mount_thickness, ymotor_mount_h], align=[1,0,-1]);
                }
            }

            // top mount plate
            difference()
            {
                cubea([ymotor_mount_thickness, ymotor_mount_width, extrusion_size], align=[1,0,0]);

                for(i=[-1,1])
                    translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                        fncylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia, orient=[1,0,0]);
            }

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

                    for(i=[0])
                        translate([0, i*(ymotor_w/2+ymotor_mount_thread_dia*3), 0])
                            fncylindera(h=ymotor_mount_thickness*3,d=ymotor_mount_thread_dia,align=[0,0,0], orient=[1,0,0]);
                }
            }

        }

    }

    if(show_motor)
    {
        attach(yaxis_motor_mount_conn_motor,[[0,0,0],[0,0,0]])
        {
            motor(yaxis_motor, NemaMedium, dualAxis=false, orientation=[0,180,0]);

            translate([0,0,5*mm])
            fncylindera(d=yaxis_pulley_d, h=yaxis_motor_pulley_h, orient=[0,0,1]);
        }
    }
}

/*yaxis_motor_mount(show_motor=true);*/


shapes: fix profile functions

shapes: fix profile functions

/*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 pyramid(size=[10,10,10], orient, align)
{
    let(s=size)
    size_align(size=s, align=align, orient=orient)
    polyhedron(
        points=[
            // the four points at base
            [s.x/2,s.y/2,-s.z/2],[s.x/2,-s.y/2,-s.z/2],[-s.x/2,-s.y/2,-s.z/2],[-s.x/2,s.y/2,-s.z/2],
            // the apex point
            [0,0,s.z/2]
        ],
        faces=[
            // each triangle side
            [0,1,4],[1,2,4],[2,3,4],[3,0,4],
            // two triangles for square base
            [1,0,3],[2,1,3]
        ]
        );
}

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)
    sphere(d=d_+extra_d_);
}

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

function circle_profile(r=10, fn=$fn) = [for (i=[0:fn-1]) [r*sin(i*360/fn), r*cos(i*360/fn)]];

function rounded_rectangle_profile(size=[10,10],r=[1,1],fn=32) = [
let(r_ = is_array(r) ? r : [r,r])
for (index = [0:fn-1])
let(a = index/fn*360)
[cos(a)*r.x, sin(a)*r.y]
+ sign_x(index, fn) * X * (size.x/2-r.x)
+ sign_y(index, fn) * Y * (size.y/2-r.y)
];

function sign_x(i,n) =
i < n/4 || i > n-n/4  ?  1 :
i > n/4 && i < n-n/4  ? -1 :
    0;

function sign_y(i,n) =
i > 0 && i < n/2  ?  1 :
i > n/2 ? -1 :
    0;

// From Obiscad
//----------------------------------------------------------
//--  Draw a point in the position given by the vector p
//----------------------------------------------------------
module point(p, r=0.7, fn)
{
    translate(p)
    sphere(r=r);
}

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

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

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

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

    //-- Draw the body
    cylindera(r=1/2, h=lb, align=-Z);
  }

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

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

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

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

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

  vref = Z;
  raxis = v_cross(vref,v);

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

  raxis_=ang==180&&raxis==N?X:raxis;

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

}

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

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

  //-- Draw the attachment axis vector (with a mark)
  translate(p)
    rotate(a=ang, v=v)
    color("Gray") vector(v=v_unitv(v)*6, l_arrow=2, mark=true);
}

// 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, 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 pyramid(size=[10,10,10], orient, align)
{
    let(s=size)
    size_align(size=s, align=align, orient=orient)
    polyhedron(
        points=[
            // the four points at base
            [s.x/2,s.y/2,-s.z/2],[s.x/2,-s.y/2,-s.z/2],[-s.x/2,-s.y/2,-s.z/2],[-s.x/2,s.y/2,-s.z/2],
            // the apex point
            [0,0,s.z/2]
        ],
        faces=[
            // each triangle side
            [0,1,4],[1,2,4],[2,3,4],[3,0,4],
            // two triangles for square base
            [1,0,3],[2,1,3]
        ]
        );
}

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)
    sphere(d=d_+extra_d_);
}

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

function rounded_rectangle_profile(size=[1,1],r=[1,1],fn=$fn) = [
for (index = [0:fn-1])
let(a = index/fn*360)
[cos(a)*r.x, sin(a)*r.y]
+ sign_x(index, fn) * X*(size.x/2-r.x)
+ sign_y(index, fn) * Y*(size.y/2-r.y)
];

function sign_x(i,n) =
i < n/4 || i > n-n/4  ?  1 :
i > n/4 && i < n-n/4  ? -1 :
    0;

function sign_y(i,n) =
i > 0 && i < n/2  ?  1 :
i > n/2 ? -1 :
    0;

function circle_profile(r=10, fn=$fn) = [for (i=[0:fn-1]) [r*sin(i*360/fn), r*cos(i*360/fn)]];

// From Obiscad
//----------------------------------------------------------
//--  Draw a point in the position given by the vector p
//----------------------------------------------------------
module point(p, r=0.7, fn)
{
    translate(p)
    sphere(r=r);
}

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

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

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

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

    //-- Draw the body
    cylindera(r=1/2, h=lb, align=-Z);
  }

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

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

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

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

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

  vref = Z;
  raxis = v_cross(vref,v);

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

  raxis_=ang==180&&raxis==N?X:raxis;

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

}

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

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

  //-- Draw the attachment axis vector (with a mark)
  translate(p)
    rotate(a=ang, v=v)
    color("Gray") vector(v=v_unitv(v)*6, l_arrow=2, mark=true);
}

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