update for full test print of platform()

//$fs = 0.1;
//$fa = 5;
$fs = 0.25;
$fa = 8;

use <hcsr04.scad>

module wheel() {
    color("black") rotate([90, 90, 0]) difference() {
        #cylinder(d=47, h=23, center=true);
        cylinder(d=30, h=26, center=true);
    }
}

module base() {

    // 4 wheels
    translate([77.5, 60, 47/2]) wheel();
    translate([-77.5, 60, 47/2]) wheel();
    translate([77.5, -60, 47/2]) wheel();
    translate([-77.5, -60, 47/2]) wheel();

    // front axe assemby - slightly longer
    translate([77.5-5, 0, 47/2]) color("gray") cube(size=[25, 103, 26], center=true);
    // rear axe assemby
    translate([-77.5, 0, 47/2]) color("gray") cube(size=[26, 97, 26], center=true);

    color("gray") translate ([0, 0, 12]) {

        // base plate
        linear_extrude(height = 2) base_plate();
        linear_extrude(height = 7) difference() {
            base_plate();
            offset(-2) base_plate();
        }

        // shaft
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        //shaft ribs
        translate ([14, 4, 23]) cube(size=[67, 2, 4], center=false);
        translate ([14, -6, 23]) cube(size=[67, 2, 4], center=false);
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        translate ([-81, 4, 23]) cube(size=[45, 2, 6], center=false);
        translate ([-81, -6, 23]) cube(size=[45, 2, 6], center=false);
        // servo
        linear_extrude(height = 15)  polygon([
            [29,0], [79,0],
            [79,-23], [70,-23],[49,-40],[29,-40]
        ]);

        // motor
        translate ([-79+30, -16, 23/2+2]) rotate([0, 90, 0]) cylinder(d=23, h=32, center=false);

        // gear
        translate ([-79+23, 0, 34/2]) rotate([0, 90, 0]) cylinder(d=34, h=6, center=false);

        // battery
        translate ([-5/2, 30/2+7, 16/2+2]) cube(size=[84, 30, 16], center=true);

        // battery holder
        translate ([-79+23, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([79-29, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([-5/2, 20, 22]) cube(size=[110, 13, 2], center=true);

        // front shocks
        translate ([162/2, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[23,44],[18,48],[5,41],[-5,41],[-18,48],[-23,44], [-38,0],[38,0]]);

        // rear shocks
        translate ([-162/2-16, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[25,48],[20,48],[5,38],[-5,38],[-20,48],[-25,48], [-38,0],[38,0]]);
    }
}

module base_plate() {
    polygon([
        [-79,25], [-70,25],[-54,40],[49,40],[70,23], [79,23],
        [79,-23], [70,-23],[49,-40],[-54,-40],[-70,-25], [-79,-25]
    ]);
}

module platform() {

    difference() {
    color("black") translate ([0, 0, 12+32+4]) difference() {
        union() {
            #linear_extrude(height = 3) intersection() {
                difference() {
                    offset(-10) offset(30) offset(-20)
                       polygon([
                         [-200,25], [-70,25],[-44,60],[44,60],[70,23], [200,23],
                         [200,-23], [70,-23],[44,-60],[-44,-60],[-70,-25], [-200,-25]
                       ]);

                    offset(5) offset(-5) translate ([-2.5, 0, 0]) difference() {
                        polygon([
                         [-50,-35], [50,-35],
                           [50,-30], [60,-15],[60,15], [50,30],
                         [50,35], [-50,35],
                           [-50,30], [-55,20],[-55,-20], [-50,-30]
                        ])

                        square(size=[90,70], center=true);
                        translate ([-45, -35, 0]) circle(r=7.5, center=true);
                        translate ([ 45, -35, 0]) circle(r=7.5, center=true);
                        translate ([-45,  35, 0]) circle(r=7.5, center=true);
                        translate ([ 45,  35, 0]) circle(r=7.5, center=true);
                    }

                }
                square(size=[162,120], center=true);
            }

            intersection() { translate ([0, 0, 100]) cube(size=[200,200,200], center=true); union() {
            // shock tower mount points
            // rear
            #translate ([-81, -25, 0]) { hull() {
                cube(size=[4, 7, 12-3.5], center=false);
                translate ([4/2, 3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            translate ([8/2, 3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            #translate ([-81, 25-7, 0]) { hull() {
                cube(size=[4, 7, 12-3.5], center=false);
                translate ([4/2, 7-3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            translate ([8/2, 7-3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            // front
            #translate ([81-4, -46/2, 0]) hull() {
                cube(size=[4, 7, 8-3.5], center=false);
                translate ([4/2, 3.5, 8-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            #translate ([81-4, 46/2-7, 0]) hull() {
                cube(size=[4, 7, 8-3.5], center=false);
                translate ([4/2, 7-3.5, 8-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            }}
        }

        // board mount holes
        translate ([-(45-2.5)-2.5,  (35-2.5), 2.5]) screw2x6bore(); // cylinder(d=2.2, h=10, center=true);
        translate ([-(45-2.5)-2.5, -(35-2.5), 2.5]) screw2x6bore(); //cylinder(d=2.2, h=10, center=true);
        translate ([ (45-2.5)-2.5,  (35-2.5), 2.5]) screw2x6bore(); //cylinder(d=2.2, h=10, center=true);
        translate ([ (45-2.5)-2.5, -(35-2.5), 2.5]) screw2x6bore(); //cylinder(d=2.2, h=10, center=true);

        // servo wire hole
        //translate ([55, -20, 0]) cylinder(d=10, h=10, center=true);
        //translate ([55,  20, 0]) cylinder(d=10, h=10, center=true);

        // mount holes
        // front
        #translate ([81, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81, 42.5/2-3/2, 8-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        #translate ([81,-42.5/2+3/2, 8-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);

        #translate ([81-4-5/2, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=6.1, h=5, center=true);
        #translate ([81-4-5/2,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=6.1, h=5, center=true);

        // rear
        #translate ([-81, 46.5/2-3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81, 46.5/2-3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
    }
    arrangebottom(30)
    {
        hbaseholes(center=true, right=1, left=1);
        hbaseholes(center=true, right=0, left=1);
        hbaseholes(center=true, right=1, left=0);
        hbaseholes(center=true, right=1, left=0);
        hbaseholes(center=true, right=0, left=1);
    }
    //arrangebottom(45) hbaseholes();
    }
}

module board() {

    // base
    color("yellow") translate ([-2.5, 0, 47]) cube(size=[90, 70, 1.2], center=true);

    // teensy
    color("green") translate ([-25, 0, 47+5]) cube(size=[20, 63, 10], center=true);

    // MPU-9250
    color("red") translate ([0, 15, 47+5]) cube(size=[20, 20, 10], center=true);
}

module esc() {
    color("green") cube(size=[36, 26, 2], center=true);
    color("black") translate ([36/2, 0, 0]) rotate([0, 90, 0]) cylinder(d=8, h=16, center=false);

    // esc support box ?
    // hcolor("black") translate ([0, 0, -11]) cube(size=[30, 20, 20], center=true);
}

module vsonar() {

    // vertical sonar
    translate ([0, -10, 45]) rotate([0, 90, 0]) hcsr04();

    // mount plate
    color("gray") translate ([1.5, -10, -6]) cube(size=[3, 20, 51], center=false);
    color("gray") translate ([-8.5, -10, -6]) cube(size=[10, 20, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 22.5]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module hbaseholes(center = true, left = 2, right = 2)
{
    if (center) translate ([-5,    0, -15]) cylinder(d=3.2, h=15, center=false);

    if (left >= 1) translate ([-5,  9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (left >= 2) translate ([-5,  19, -15]) cylinder(d=3.2, h=15, center=false);

    if (right >= 1) translate ([-5, -9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (right >= 2) translate ([-5, -19, -15]) cylinder(d=3.2, h=15, center=false);
}

module hmount() {
    // mount plate
    color ("gray") {

        // front
        difference() {
            translate ([1.5, -48/2, -6]) #hull() {
                cube(size=[3, 48, 25], center=false);
                translate ([0, 48-3, 25]) rotate([90, 0, 90]) cylinder(r=3, h=3, center=false);
                translate ([0, 3, 25]) rotate([90, 0, 90]) cylinder(r=3, h=3, center=false);
            }

            translate ([0, -45/2, 0]) rotate([90, 0, 90]) {

                // sonar
                translate([45/2-(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);
                translate([45/2+(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);

                //xtal(s)
                hull () {
                    translate([45/2-3.25,20-3.5,1.3])
                    {
                        translate([0,0,0]) cylinder(d=6, h=5);
                        translate([6.5,0,0]) cylinder(d=6, h=5);
                    }
                    translate([45/2-3.25, 4,1.3]) hull()
                    {
                        //translate([0,0,0]) cylinder(d=6, h=5);
                        //translate([6.5,0,0]) cylinder(d=6, h=5);
                        translate([0,-2,0]) cylinder(d=6, h=5);
                        translate([6.5,-2,0]) cylinder(d=6, h=5);
                    }
                }

                // screws
                translate([   1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([45-1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
                translate([45-1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([   1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
            }

            translate ([3, 0, 10])
                cube(size=[5, 20, 11], center=true);
        }

        //base
        difference() {
            hull() {
                translate ([-3.5, -48/2, -6]) cube(size=[5, 48, 5], center=false);
                translate ([-3.5, -48/2+5, -6]) cylinder(r=5, h=5, center=false);
                translate ([-3.5, 48/2-5, -6]) cylinder(r=5, h=5, center=false);
            }
            hbaseholes();
        }
    }
}

module screw2x6bore() {
    rotate([180, 0, 0]) {
        cylinder(d=2.2, h=6);
        translate ([0, 0, -1.3])
            cylinder(d1=2*3.6, d2=0, h=2*1.3);
    }
}

module hsonar() {

    // horizontal sonar
    translate ([0, -45/2, 0]) rotate([90, 0, 90]) hcsr04();

    hmount();

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 10]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module car()
{
    base();
    platform();
    board();

    translate ([10, -23, 35]) esc();
//    translate ([-10, 0, 40]) rotate([0, 0, 180]) esc();
}

// full model - vertical sonars
module fullv() {
    car();

    translate ([68, 0, 55]) vsonar();
    translate ([60, 25, 55]) rotate([0, 0, 30]) vsonar();
    translate ([60, -25, 55]) rotate([0, 0, -30]) vsonar();
    translate ([35, 35, 55]) rotate([0, 0, 60]) vsonar();
    translate ([35, -35, 55]) rotate([0, 0, -60]) vsonar();
}

// full model - horizontal sonars
module fullh() {
    car();

    translate ([68, 0, 55]) hsonar();
    translate ([40, 35, 55]) rotate([0, 0, 30]) hsonar();
    translate ([40, -35, 55]) rotate([0, 0, -30]) hsonar();
    translate ([-10, 35, 55]) rotate([0, 0, 60]) hsonar();
    translate ([-10, -35, 55]) rotate([0, 0, -60]) hsonar();
}

module arrangebottom(a) {
    translate ([68, 0, 57]) if ($children == 1) children(); else children(0);

    translate ([45, 45, 57]) rotate([0, 0, a]) if ($children == 1) children(); else children(1);
    translate ([0, 52.5, 42]) rotate([180, 0, 2*a]) if ($children == 1) children(); else children(2);

    translate ([45, -45, 57]) rotate([0, 0, -a]) if ($children == 1) children(); else children(3);
    translate ([0, -52.5, 42]) rotate([180, 0, -2*a]) if ($children == 1) children(); else children(4);
}

module fullb() {
    car();
    arrangebottom(30) hsonar();
}

//car();

platform();

/*
intersection() {
platform();
#translate ([80, 0, 0]) cube(size=[20, 200, 400], center=true);
}*/

/*
intersection() {
platform();
#translate ([-80, 0, 0]) cube(size=[20, 200, 400], center=true);
}*/

/*
intersection() {
platform();
#translate ([45-2.5, 30, 0]) cube(size=[20, 20, 400], center=true);
}
*/

//fullb();

//translate ([0, 0, 4.5]) rotate([0, 90, 0]) hmount();

//screw2x6bore();

//projection(cut=true) translate ([0, 0, -47]) platform();

//$fs = 0.1;
//$fa = 5;
$fs = 0.25;
$fa = 8;

use <hcsr04.scad>

module wheel() {
    color("black") rotate([90, 90, 0]) difference() {
        #cylinder(d=47, h=23, center=true);
        cylinder(d=30, h=26, center=true);
    }
}

module base() {

    // 4 wheels
    translate([77.5, 60, 47/2]) wheel();
    translate([-77.5, 60, 47/2]) wheel();
    translate([77.5, -60, 47/2]) wheel();
    translate([-77.5, -60, 47/2]) wheel();

    // front axe assemby - slightly longer
    translate([77.5-5, 0, 47/2]) color("gray") cube(size=[25, 103, 26], center=true);
    // rear axe assemby
    translate([-77.5, 0, 47/2]) color("gray") cube(size=[26, 97, 26], center=true);

    color("gray") translate ([0, 0, 12]) {

        // base plate
        linear_extrude(height = 2) base_plate();
        linear_extrude(height = 7) difference() {
            base_plate();
            offset(-2) base_plate();
        }

        // shaft
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        //shaft ribs
        translate ([14, 4, 23]) cube(size=[67, 2, 4], center=false);
        translate ([14, -6, 23]) cube(size=[67, 2, 4], center=false);
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        translate ([-81, 4, 23]) cube(size=[45, 2, 6], center=false);
        translate ([-81, -6, 23]) cube(size=[45, 2, 6], center=false);
        // servo
        linear_extrude(height = 15)  polygon([
            [29,0], [79,0],
            [79,-23], [70,-23],[49,-40],[29,-40]
        ]);

        // motor
        translate ([-79+30, -16, 23/2+2]) rotate([0, 90, 0]) cylinder(d=23, h=32, center=false);

        // gear
        translate ([-79+23, 0, 34/2]) rotate([0, 90, 0]) cylinder(d=34, h=6, center=false);

        // battery
        translate ([-5/2, 30/2+7, 16/2+2]) cube(size=[84, 30, 16], center=true);

        // battery holder
        translate ([-79+23, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([79-29, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([-5/2, 20, 22]) cube(size=[110, 13, 2], center=true);

        // front shocks
        translate ([162/2, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[23,44],[18,48],[5,41],[-5,41],[-18,48],[-23,44], [-38,0],[38,0]]);

        // rear shocks
        translate ([-162/2-16, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[25,48],[20,48],[5,38],[-5,38],[-20,48],[-25,48], [-38,0],[38,0]]);
    }
}

module base_plate() {
    polygon([
        [-79,25], [-70,25],[-54,40],[49,40],[70,23], [79,23],
        [79,-23], [70,-23],[49,-40],[-54,-40],[-70,-25], [-79,-25]
    ]);
}

module platform() {

    difference() {
    color("black") translate ([0, 0, 12+32+4]) difference() {
        union() {
            #linear_extrude(height = 3) intersection() {
                difference() {
                    offset(-10) offset(30) offset(-20)
                       polygon([
                         [-200,25], [-70,25],[-44,60],[44,60],[70,23], [200,23],
                         [200,-23], [70,-23],[44,-60],[-44,-60],[-70,-25], [-200,-25]
                       ]);

                    offset(5) offset(-5) translate ([-2.5, 0, 0]) difference() {
                        polygon([
                         [-50,-35], [50,-35],
                           [50,-30], [60,-15],[60,15], [50,30],
                         [50,35], [-50,35],
                           [-50,30], [-55,20],[-55,-20], [-50,-30]
                        ])

                        square(size=[90,70], center=true);
                        translate ([-45, -35, 0]) circle(r=7.5, center=true);
                        translate ([ 45, -35, 0]) circle(r=7.5, center=true);
                        translate ([-45,  35, 0]) circle(r=7.5, center=true);
                        translate ([ 45,  35, 0]) circle(r=7.5, center=true);
                    }

                }
                square(size=[162,120], center=true);
            }

            intersection() { translate ([0, 0, 100]) cube(size=[200,200,200], center=true); union() {
            // shock tower mount points
            // rear
            #translate ([-81, -25, 0]) { hull() {
                cube(size=[4, 7, 12-3.5], center=false);
                translate ([4/2, 3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            translate ([8/2, 3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            #translate ([-81, 25-7, 0]) { hull() {
                cube(size=[4, 7, 12-3.5], center=false);
                translate ([4/2, 7-3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            translate ([8/2, 7-3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            // front
            #translate ([81-4, -46/2, 0]) hull() {
                cube(size=[4, 7, 8-3.5], center=false);
                translate ([4/2, 3.5, 8-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            #translate ([81-4, 46/2-7, 0]) hull() {
                cube(size=[4, 7, 8-3.5], center=false);
                translate ([4/2, 7-3.5, 8-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
            }
            }}
        }

        // board mount holes
        translate ([-(45-2.5)-2.5,  (35-2.5), 2.5]) screw2x6bore(); // cylinder(d=2.2, h=10, center=true);
        translate ([-(45-2.5)-2.5, -(35-2.5), 2.5]) screw2x6bore(); //cylinder(d=2.2, h=10, center=true);
        translate ([ (45-2.5)-2.5,  (35-2.5), 2.5]) screw2x6bore(); //cylinder(d=2.2, h=10, center=true);
        translate ([ (45-2.5)-2.5, -(35-2.5), 2.5]) screw2x6bore(); //cylinder(d=2.2, h=10, center=true);

        // servo wire hole
        //translate ([55, -20, 0]) cylinder(d=10, h=10, center=true);
        //translate ([55,  20, 0]) cylinder(d=10, h=10, center=true);

        // mount holes
        // front
        #translate ([81, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81, 42.5/2-3/2, 8-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        #translate ([81,-42.5/2+3/2, 8-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);

        #translate ([81-4-5/2, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=6.1, h=5, center=true);
        #translate ([81-4-5/2,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=6.1, h=5, center=true);

        // rear
        #translate ([-81, 46.5/2-3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81, 46.5/2-3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
    }
    arrangebottom(30) hbaseholes(center=true);
    //arrangebottom(45) hbaseholes();
    }
}

module board() {

    // base
    color("yellow") translate ([-2.5, 0, 47]) cube(size=[90, 70, 1.2], center=true);

    // teensy
    color("green") translate ([-25, 0, 47+5]) cube(size=[20, 63, 10], center=true);

    // MPU-9250
    color("red") translate ([0, 15, 47+5]) cube(size=[20, 20, 10], center=true);
}

module esc() {
    color("green") cube(size=[36, 26, 2], center=true);
    color("black") translate ([36/2, 0, 0]) rotate([0, 90, 0]) cylinder(d=8, h=16, center=false);

    // esc support box ?
    // hcolor("black") translate ([0, 0, -11]) cube(size=[30, 20, 20], center=true);
}

module vsonar() {

    // vertical sonar
    translate ([0, -10, 45]) rotate([0, 90, 0]) hcsr04();

    // mount plate
    color("gray") translate ([1.5, -10, -6]) cube(size=[3, 20, 51], center=false);
    color("gray") translate ([-8.5, -10, -6]) cube(size=[10, 20, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 22.5]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module hbaseholes(center = false)
{
    translate ([-5,    0, -15]) cylinder(d=3.2, h=15, center=false);
    translate ([-5,  9.5, -15]) cylinder(d=3.2, h=15, center=false);
    translate ([-5, -9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (!center) {
        translate ([-5,  19, -15]) cylinder(d=3.2, h=15, center=false);
        translate ([-5, -19, -15]) cylinder(d=3.2, h=15, center=false);
    }
}

module hmount() {
    // mount plate
    color ("gray") {

        // front
        difference() {
            translate ([1.5, -48/2, -6]) #hull() {
                cube(size=[3, 48, 25], center=false);
                translate ([0, 48-3, 25]) rotate([90, 0, 90]) cylinder(r=3, h=3, center=false);
                translate ([0, 3, 25]) rotate([90, 0, 90]) cylinder(r=3, h=3, center=false);
            }

            translate ([0, -45/2, 0]) rotate([90, 0, 90]) {

                // sonar
                translate([45/2-(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);
                translate([45/2+(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);

                //xtal(s)
                hull () {
                    translate([45/2-3.25,20-3.5,1.3])
                    {
                        translate([0,0,0]) cylinder(d=6, h=5);
                        translate([6.5,0,0]) cylinder(d=6, h=5);
                    }
                    translate([45/2-3.25, 4,1.3]) hull()
                    {
                        //translate([0,0,0]) cylinder(d=6, h=5);
                        //translate([6.5,0,0]) cylinder(d=6, h=5);
                        translate([0,-2,0]) cylinder(d=6, h=5);
                        translate([6.5,-2,0]) cylinder(d=6, h=5);
                    }
                }

                // screws
                translate([   1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([45-1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
                translate([45-1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([   1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
            }

            translate ([3, 0, 10])
                cube(size=[5, 20, 11], center=true);
        }

        //base
        difference() {
            hull() {
                translate ([-3.5, -48/2, -6]) cube(size=[5, 48, 5], center=false);
                translate ([-3.5, -48/2+5, -6]) cylinder(r=5, h=5, center=false);
                translate ([-3.5, 48/2-5, -6]) cylinder(r=5, h=5, center=false);
            }
            hbaseholes();
        }
    }
}

module screw2x6bore() {
    rotate([180, 0, 0]) {
        cylinder(d=2.2, h=6);
        translate ([0, 0, -1.3])
            cylinder(d1=2*3.6, d2=0, h=2*1.3);
    }
}

module hsonar() {

    // horizontal sonar
    translate ([0, -45/2, 0]) rotate([90, 0, 90]) hcsr04();

    hmount();

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 10]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module car()
{
    base();
    platform();
    board();

    translate ([10, -23, 35]) esc();
//    translate ([-10, 0, 40]) rotate([0, 0, 180]) esc();
}

// full model - vertical sonars
module fullv() {
    car();

    translate ([68, 0, 55]) vsonar();
    translate ([60, 25, 55]) rotate([0, 0, 30]) vsonar();
    translate ([60, -25, 55]) rotate([0, 0, -30]) vsonar();
    translate ([35, 35, 55]) rotate([0, 0, 60]) vsonar();
    translate ([35, -35, 55]) rotate([0, 0, -60]) vsonar();
}

// full model - horizontal sonars
module fullh() {
    car();

    translate ([68, 0, 55]) hsonar();
    translate ([40, 35, 55]) rotate([0, 0, 30]) hsonar();
    translate ([40, -35, 55]) rotate([0, 0, -30]) hsonar();
    translate ([-10, 35, 55]) rotate([0, 0, 60]) hsonar();
    translate ([-10, -35, 55]) rotate([0, 0, -60]) hsonar();
}

module arrangebottom(a) {
    translate ([68, 0, 57]) children();
    translate ([45, 45, 57]) rotate([0, 0, a]) children();
    translate ([45, -45, 57]) rotate([0, 0, -a]) children();

    translate ([0, 52.5, 42]) rotate([180, 0, 2*a]) children();
    translate ([0, -52.5, 42]) rotate([180, 0, -2*a]) children();
}

module fullb() {
    car();
    arrangebottom(30) hsonar();
}

//car();

//platform();

/*
intersection() {
platform();
#translate ([80, 0, 0]) cube(size=[20, 200, 400], center=true);
}*/

/*
intersection() {
platform();
#translate ([-80, 0, 0]) cube(size=[20, 200, 400], center=true);
}*/

/*
intersection() {
platform();
#translate ([45-2.5, 30, 0]) cube(size=[20, 20, 400], center=true);
}
*/

//fullb();

translate ([0, 0, 4.5]) rotate([0, 90, 0]) hmount();

//screw2x6bore();

//projection(cut=true) translate ([0, 0, -47]) platform();


bearing/linear: fix cut for linear rods in open mount style

include <system.scad>
include <materials.scad>

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

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

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

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

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

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

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

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

    flange_screw_len=12*mm;

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

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

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

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

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

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

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

    clip_groove = get(LinearBearingClipsGrooveDepth, bearing);

    h = fallback(override_h, get(LinearBearingLength,bearing)) + extra_h;

    assert(h>0);

    d = get(LinearBearingInnerDiameter, bearing);
    D = get(LinearBearingOuterDiameter, bearing);

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

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

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

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

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

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

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

    support_wall_thickness = 2.5*mm;

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

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

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

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

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

        // for linear rod
        if(mount_style=="open")
        {
            hull()
            {
                cylindera(d=d+2*mm, h=1000, orient=Z);
                ty(1000)
                cylindera(d=d+2*mm, h=1000, orient=Z);
            }
        }
        else
        {
            cylindera(d=d+2*mm, h=1000, orient=Z);
        }

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

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

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

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

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

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

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

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

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

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

include <system.scad>
include <materials.scad>

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

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

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

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

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

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

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

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

    flange_screw_len=12*mm;

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

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

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

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

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

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

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

    clip_groove = get(LinearBearingClipsGrooveDepth, bearing);

    h = fallback(override_h, get(LinearBearingLength,bearing)) + extra_h;

    assert(h>0);

    d = get(LinearBearingInnerDiameter, bearing);
    D = get(LinearBearingOuterDiameter, bearing);

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

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

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

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

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

    flange_pcd = get(LinearBearingFlangePitchCircleDiameter,bearing);

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

    support_wall_thickness = 2.5*mm;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


lcd2004: simplify gantry/test code

lcd2004: simplify gantry/test code

include <thing_libutils/system.scad>
include <thing_libutils/units.scad>

include <config.scad>

use <thing_libutils/linear-extrusion.scad>
use <thing_libutils/screws.scad>
use <thing_libutils/transforms.scad>

// wall thickness
lcd2004_wall_thick=4;
lcd2004_width=151+2*lcd2004_wall_thick;
lcd2004_depth=63.5+2*lcd2004_wall_thick;
mount_lcd2004_mount_angle=45;

module mount_lcd2004_parts(
    eps=[0.1,0.1,0], // gap for cavities
    part=undef,
    height=16*mm,
    align, orient, roll, extra_roll, extra_roll_orient
    )
{

    size_align(size=[lcd2004_width,lcd2004_depth,height], align=align, orient=orient, orient_ref=Z, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    if(part==undef)
    {
        difference()
        {
            mount_lcd2004_parts(lcd2004_wall_thick=lcd2004_wall_thick, eps=eps, part="pos", height=height);
            mount_lcd2004_parts(lcd2004_wall_thick=lcd2004_wall_thick, eps=eps, part="neg", height=height);
        }
    }
    else if(part=="pos")
    {
        translate([-lcd2004_width/2,-lcd2004_depth/2,-height/2])
        rcubea(size=[lcd2004_width,lcd2004_depth,height], rounding_radius=3, align=[1,1,1]);
    }
    else if(part=="neg")
    mirror(Y)
    translate([-lcd2004_width/2,-lcd2004_depth/2,-height/2])
    translate([lcd2004_wall_thick,lcd2004_wall_thick,0])
    {
        // LCD cutout
        translate([14.5,10,-2])
        cubea([97,40,19], align=[1,1,1]);

        // LCD PCB
        translate([14,-0.25,4])
        cubea([98.5,60.5,9+10], align=[1,1,1]);

        // Main PCB
        translate([0,7.75,8])
        cubea([151,56,5+22], align=[1,1,1]);

        // Switch axis
        translate([137,35,-2])
        cylindera(r=8/2, h=19, align=Z);

        // buzzer
        translate([130+13.5/2,8+39+12.5/2,-2])
        cylindera(r=12.5/2, h=19, align=Z);

        // reset switch
        translate([137,16,-2])
        cylindera(r=2, h=19, align=Z);

        // buzzer/switch/reset
        translate([116,8,2])
        cubea([29,55.5,10], align=[1,1,1]);

        // buzzer/switch/reset
        translate([118,18,2])
        cubea([33,35.5,10], align=[1,1,1]);

        // buzzer/switch/reset
        translate([0,18,2])
        cubea([11,35.5,10], align=[1,1,1]);

        // SD slot
        translate([-lcd2004_wall_thick-1,17,9])
        cubea([lcd2004_wall_thick+2,27,10], align=[1,1,1]);

        // Screw hole for PCB
        translate([0+2.9,8+2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // Screw hole for PCB
        translate([151-2.7,8+2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // Screw hole for PCB
        translate([0+2.9,8+55.5-2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // Screw hole for PCB
        translate([151-2.7,8+55.5-2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // LCD pin header
        translate([14.5+8,60-5,2])
        cubea([42,8.5,9], align=[1,1,1]);

        // Anti-Warping
        translate([50,-lcd2004_wall_thick/2,2])
        cubea([2,55.5+8+lcd2004_wall_thick,11], align=[1,1,1]);

        // Anti-Warping
        translate([90,-lcd2004_wall_thick/2,2])
        cubea([2,55.5+8+lcd2004_wall_thick,11], align=[1,1,1]);
    }
}

module gantry_lower()
{
    for(z=[-1,1])
    translate([0,0,z*-main_lower_dist_z/2])
    {
        for(y=[-1,1])
        translate([0, y*(main_depth/2), 0])
        linear_extrusion(h=main_width, align=[0,y,-1], orient=X);

        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        linear_extrusion(h=main_depth, align=-x*X-Z, orient=Y);
    }
}

lcd2004_mount_thickness = 5*mm;
module lcd2004_extrusion_conn(part, orient=Z, align=N)
{
    s = [extrusion_size, extrusion_size, lcd2004_mount_thickness];
    size_align(size=s, orient=orient, orient_ref=Z, align=align)
    if(part==undef)
    {
        difference()
        {
            lcd2004_extrusion_conn(part="pos");
            lcd2004_extrusion_conn(part="neg");
        }
    }
    else if(part=="pos")
    {
        rcubea(size=s, rounding_radius=3);
    }
    else if(part=="neg")
    {
        translate([0,0,-lcd2004_mount_thickness/2])
        screw_cut(nut=extrusion_nut, with_nut=true, nut_cut_h=30, with_head=true, head_cut_h=30, length=12*mm, align=Z, orient=Z);
    }
}

lcd2004_offset = [0, -34.2*mm,-5*mm];

module mount_lcd2004(part, show_gantry=false)
{
    if(part==undef)
    {
        difference()
        {
            mount_lcd2004(part="pos", show_gantry=show_gantry);
            mount_lcd2004(part="neg", show_gantry=show_gantry);
        }
    }
    else if(part == "pos")
    {
        hull()
        {
            for(x=[-1,1])
            translate([x*(lcd2004_width/2+extrusion_size),0,0])
            {
                translate([0,0,main_lower_dist_z/2-extrusion_size])
                lcd2004_extrusion_conn(part=part, orient=Z, align=[-x,0,-1]);
            }

            for(x=[-1,1])
            translate([x*(lcd2004_width/2+extrusion_size),0,0])
            {
                translate([0,0,-main_lower_dist_z/2])
                lcd2004_extrusion_conn(part=part, orient=[0,0,-1], align=[-x,0,1]);
            }

            translate(lcd2004_offset)
            rotate([-mount_lcd2004_mount_angle,0,0])
            mount_lcd2004_parts(part=part, orient=Y, align=Y);

        }
        if(show_gantry)
        {
            translate([0,main_depth/2,0])
            translate([0,extrusion_size/2,0])
            gantry_lower();
        }

    }
    else if(part == "neg")
    {
        for(x=[-1,1])
        translate([x*(lcd2004_width/2+extrusion_size),0,0])
        {
            translate([0,0,main_lower_dist_z/2-extrusion_size])
            lcd2004_extrusion_conn(part=part, orient=Z, align=[-x,0,-1]);

            translate([0,0,-main_lower_dist_z/2])
            {
                lcd2004_extrusion_conn(part=part, orient=[0,0,-1], align=[-x,0,1]);
            }
        }

        translate([0,10*mm,-extrusion_size/2])
        /*#rcubea([lcd2004_width+30*mm, extrusion_size+.2, main_lower_dist_z-extrusion_size-lcd2004_mount_thickness*2]);*/
        rcubea([1000, extrusion_size+.2, main_lower_dist_z-extrusion_size-lcd2004_mount_thickness*2]);

        /*translate([0,0,-extrusion_size/2])*/
        /*rcubea([lcd2004_width, extrusion_size+.2, main_lower_dist_z-extrusion_size-lcd2004_mount_thickness*1]);*/

        translate(lcd2004_offset)
        rotate([-mount_lcd2004_mount_angle,0,0])
        {
            mount_lcd2004_parts(part=part, orient=Y, align=Y);

            translate([0,1000+5,0])
            rotate([90,0,0])
            linear_extrude(height=1000)
            projection(cut=false)
            rotate([-90,0,0])
            mount_lcd2004_parts(part=part, orient=Y, align=Y);
        }

        translate(lcd2004_offset)
        translate([0,27,-13])
        translate([0,1000,0])
        rotate([90,0,0])
        linear_extrude(height=1000)
        projection(cut=false)
        rotate([-90,0,0])
        mount_lcd2004_parts(part=part, orient=Y, align=Y);

        translate([0,main_depth/2,0])
        translate([0,extrusion_size/2,0])
        gantry_lower();
    }

}

module part_lcd2004_mount()
{
    rotate([90+mount_lcd2004_mount_angle,0,0])
    translate(-lcd2004_offset)
    mount_lcd2004();
}

if(false)
{
    mount_lcd2004(show_gantry=true);
}

include <thing_libutils/system.scad>
include <thing_libutils/units.scad>

include <config.scad>

use <thing_libutils/linear-extrusion.scad>
use <thing_libutils/screws.scad>
use <thing_libutils/transforms.scad>

// wall thickness
lcd2004_wall_thick=4;
lcd2004_width=151+2*lcd2004_wall_thick;
lcd2004_depth=63.5+2*lcd2004_wall_thick;
mount_lcd2004_mount_angle=45;

module mount_lcd2004_parts(
    eps=[0.1,0.1,0], // gap for cavities
    part=undef,
    height=16*mm,
    align, orient, roll, extra_roll, extra_roll_orient
    )
{

    size_align(size=[lcd2004_width,lcd2004_depth,height], align=align, orient=orient, orient_ref=Z, roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    if(part==undef)
    {
        difference()
        {
            mount_lcd2004_parts(lcd2004_wall_thick=lcd2004_wall_thick, eps=eps, part="pos", height=height);
            mount_lcd2004_parts(lcd2004_wall_thick=lcd2004_wall_thick, eps=eps, part="neg", height=height);
        }
    }
    else if(part=="pos")
    {
        translate([-lcd2004_width/2,-lcd2004_depth/2,-height/2])
        rcubea(size=[lcd2004_width,lcd2004_depth,height], rounding_radius=3, align=[1,1,1]);
    }
    else if(part=="neg")
    mirror(Y)
    translate([-lcd2004_width/2,-lcd2004_depth/2,-height/2])
    translate([lcd2004_wall_thick,lcd2004_wall_thick,0])
    {
        // LCD cutout
        translate([14.5,10,-2])
        cubea([97,40,19], align=[1,1,1]);

        // LCD PCB
        translate([14,-0.25,4])
        cubea([98.5,60.5,9+10], align=[1,1,1]);

        // Main PCB
        translate([0,7.75,8])
        cubea([151,56,5+22], align=[1,1,1]);

        // Switch axis
        translate([137,35,-2])
        cylindera(r=8/2, h=19, align=Z);

        // buzzer
        translate([130+13.5/2,8+39+12.5/2,-2])
        cylindera(r=12.5/2, h=19, align=Z);

        // reset switch
        translate([137,16,-2])
        cylindera(r=2, h=19, align=Z);

        // buzzer/switch/reset
        translate([116,8,2])
        cubea([29,55.5,10], align=[1,1,1]);

        // buzzer/switch/reset
        translate([118,18,2])
        cubea([33,35.5,10], align=[1,1,1]);

        // buzzer/switch/reset
        translate([0,18,2])
        cubea([11,35.5,10], align=[1,1,1]);

        // SD slot
        translate([-lcd2004_wall_thick-1,17,9])
        cubea([lcd2004_wall_thick+2,27,10], align=[1,1,1]);

        // Screw hole for PCB
        translate([0+2.9,8+2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // Screw hole for PCB
        translate([151-2.7,8+2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // Screw hole for PCB
        translate([0+2.9,8+55.5-2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // Screw hole for PCB
        translate([151-2.7,8+55.5-2.5,3])
        cylindera(r=2.5/2, h=6, align=Z);

        // LCD pin header
        translate([14.5+8,60-5,2])
        cubea([42,8.5,9], align=[1,1,1]);

        // Anti-Warping
        translate([50,-lcd2004_wall_thick/2,2])
        cubea([2,55.5+8+lcd2004_wall_thick,11], align=[1,1,1]);

        // Anti-Warping
        translate([90,-lcd2004_wall_thick/2,2])
        cubea([2,55.5+8+lcd2004_wall_thick,11], align=[1,1,1]);
    }
}

module gantry_lower()
{
    color(color_extrusion)
    for(z=[-1,1])
    {
        translate([0,0,z*-main_lower_dist_z/2])
        {
            for(y=[-1,1])
            translate([0, y*(main_depth/2), 0])
            {
                if($preview_mode)
                {
                    cubea([main_width, extrusion_size, extrusion_size], align=[0,y,-1]);
                }
                else
                {
                    linear_extrusion(h=main_width, align=[0,y,-1], orient=X);
                }
            }

            for(x=[-1,1])
            translate([x*(main_width/2), 0, 0])
            {
                if($preview_mode)
                {
                    cubea([extrusion_size, main_depth, extrusion_size], align=[-x,0,-1]);
                }
                else
                {
                    linear_extrusion(h=main_depth, align=[-x,0,-1], orient=Y);
                }
            }
        }
    }
}

lcd2004_mount_thickness = 5*mm;
module lcd2004_extrusion_conn(part, orient=Z, align=N)
{
    s = [extrusion_size, extrusion_size, lcd2004_mount_thickness];
    size_align(size=s, orient=orient, orient_ref=Z, align=align)
    if(part==undef)
    {
        difference()
        {
            lcd2004_extrusion_conn(part="pos");
            lcd2004_extrusion_conn(part="neg");
        }
    }
    else if(part=="pos")
    {
        rcubea(size=s, rounding_radius=3);
    }
    else if(part=="neg")
    {
        translate([0,0,-lcd2004_mount_thickness/2])
        screw_cut(nut=extrusion_nut, with_nut=true, nut_cut_h=30, with_head=true, head_cut_h=30, length=12*mm, align=Z, orient=Z);
    }
}

lcd2004_offset = [0, -34.2*mm,-5*mm];

module mount_lcd2004(part, show_gantry=false)
{
    if(part==undef)
    {
        difference()
        {
            mount_lcd2004(part="pos", show_gantry=show_gantry);
            mount_lcd2004(part="neg", show_gantry=show_gantry);
        }
    }
    else if(part == "pos")
    {
        hull()
        {
            for(x=[-1,1])
            translate([x*(lcd2004_width/2+extrusion_size),0,0])
            {
                translate([0,0,main_lower_dist_z/2-extrusion_size])
                lcd2004_extrusion_conn(part=part, orient=Z, align=[-x,0,-1]);
            }

            for(x=[-1,1])
            translate([x*(lcd2004_width/2+extrusion_size),0,0])
            {
                translate([0,0,-main_lower_dist_z/2])
                lcd2004_extrusion_conn(part=part, orient=[0,0,-1], align=[-x,0,1]);
            }

            translate(lcd2004_offset)
            rotate([-mount_lcd2004_mount_angle,0,0])
            mount_lcd2004_parts(part=part, orient=Y, align=Y);

        }
        if(show_gantry)
        {
            translate([0,main_depth/2,0])
            translate([0,extrusion_size/2,0])
            gantry_lower();
        }

    }
    else if(part == "neg")
    {
        for(x=[-1,1])
        translate([x*(lcd2004_width/2+extrusion_size),0,0])
        {
            translate([0,0,main_lower_dist_z/2-extrusion_size])
            lcd2004_extrusion_conn(part=part, orient=Z, align=[-x,0,-1]);

            translate([0,0,-main_lower_dist_z/2])
            {
                lcd2004_extrusion_conn(part=part, orient=[0,0,-1], align=[-x,0,1]);
            }
        }

        translate([0,10*mm,-extrusion_size/2])
        /*#rcubea([lcd2004_width+30*mm, extrusion_size+.2, main_lower_dist_z-extrusion_size-lcd2004_mount_thickness*2]);*/
        rcubea([1000, extrusion_size+.2, main_lower_dist_z-extrusion_size-lcd2004_mount_thickness*2]);

        /*translate([0,0,-extrusion_size/2])*/
        /*rcubea([lcd2004_width, extrusion_size+.2, main_lower_dist_z-extrusion_size-lcd2004_mount_thickness*1]);*/

        translate(lcd2004_offset)
        rotate([-mount_lcd2004_mount_angle,0,0])
        {
            mount_lcd2004_parts(part=part, orient=Y, align=Y);

            translate([0,1000+5,0])
            rotate([90,0,0])
            linear_extrude(height=1000)
            projection(cut=false)
            rotate([-90,0,0])
            mount_lcd2004_parts(part=part, orient=Y, align=Y);
        }

        translate(lcd2004_offset)
        translate([0,27,-13])
        translate([0,1000,0])
        rotate([90,0,0])
        linear_extrude(height=1000)
        projection(cut=false)
        rotate([-90,0,0])
        mount_lcd2004_parts(part=part, orient=Y, align=Y);

        translate([0,main_depth/2,0])
        translate([0,extrusion_size/2,0])
        gantry_lower();
    }

}

module part_lcd2004_mount()
{
    rotate([90+mount_lcd2004_mount_angle,0,0])
    translate(-lcd2004_offset)
    mount_lcd2004();
}

if(false)
{
    mount_lcd2004(show_gantry=true);
}