[3d] Add support for 0.36inch LED displays to MeterMonitor

// LCD type
lt = 0; // [0: 0.56inch, 1: 0.36inch]

wall = 1.3; // interior walls
wall_o = 1.9; // outer walls
wall_t = 1.45; // base thickness

/* Hidden */
lid_h = wall_t;

lcd_w = [67, 45.50][lt];
lcd_d = [28, 23.00][lt];
lcd_s_w = [60, 40.35][lt]; // width between screws
lcd_s_d = [22, 17.76][lt];
lcd_s_h = [8.5, 7.0][lt];
lcd_s_dia = [3.1, 3.1][lt];
lcd_a_w = [50, 30][lt]; // width of actual 7-segment area
lcd_a_d = [17.5, 14][lt];
lcd_ex_w = [0, 2][lt];
lcd_ex_d = [2, 4][lt];
lcd_window_offset = [2, (5.43-10.07)/2][lt];
w_extra = [2, 6][lt];
d_extra = [0, 0][lt];

oa_w = 2*lcd_w + 2*lcd_ex_w + w_extra;
oa_d = 3*lcd_d + 3*lcd_ex_d + d_extra;
oa_h = 15;
pad_right = max(2*lcd_window_offset, 0); // padding is asymetrical so not included in oa_w

main();
//translate([-oa_w/2, oa_d/2+wall_o+5, 0]) lid();

module main() {
  difference() {
    union() {
      translate([-oa_w/2-wall_o, -oa_d/2-wall_o, 0])
        cube_bchamfer([oa_w+pad_right+2*wall_o, oa_d+2*wall_o, oa_h+wall_t+lid_h+wall_t/2], r=5, bottom=1);
    } // union

    // main cutout
    translate([-oa_w/2, -oa_d/2, wall_t])
      cube_bchamfer([oa_w+pad_right, oa_d, oa_h+e], r=5-wall, bottom=1, top=lid_h);
    // lid cutout
    translate([-oa_w/2,-oa_d/2-wall_o-e,wall_t+oa_h])
      cube_fillet([oa_w+pad_right, oa_d+wall_o+e, lid_h+wall_t+e],
        vertical=[2,2], top=[lid_h,lid_h,0,lid_h], $fn=4);

    // LCD holes
    lcd_places() lcd_mount_n();

    // USB power hole
    wemos_place() translate([-5.9, -35.2/2-1.2-wall_o-e, 2.3+2-0.5])
      cube_fillet([13, 10, 6+1.5], top=[0,1,0,1]);

    //branding();
  } // diff

  lcd_places() lcd_mount_p();
  wemos_place() wemos_mount(2);
}

module lid() {
  ww = oa_w+pad_right+0.2;
  dd = oa_d+wall_o-0.2;
  difference() {
    cube_fillet([ww, dd, lid_h], bottom=[0.5, 0.5, 0, 0.5], vertical=[1.5, 1.5 ,1.5, 1.5]);
    // vent holes
    //translate([15, dd/2, 0])
    //  for (X=[0:3])
    //    translate([X*(ww-30)/3, 0, -e]) rotate(90) cylcyl(d*0.7, 2, lid_h+2*e, $fn=12);
  }
  // lock bump
  //translate([wall_o+wall_t+0.5, dd/2-4*wall, lid_h-e]) cube_fillet([2*wall, 8*wall, 0.6], top=[0.6,0,0.6,0]);
  translate([ww/4, wall_o+wall_t+0.5, lid_h-e]) cube_fillet([ww/2, 2*wall, 0.6], top=[0,0.6,0,0.6]);
}

module lcd_places() {
  // center two
  translate([lcd_w/2+lcd_ex_w,0,0])
    children();
  translate([-lcd_w/2-lcd_ex_w,0,0])
    children();
  // top/bottom
  mirror2([0,1,0]) translate([-lcd_w/2-lcd_ex_w,lcd_d+lcd_ex_d,0])
    children();
}

module lcd_mount_p() {
  mirror2([1,0,0]) mirror2([0,1,0]) translate([lcd_s_w/2, lcd_s_d/2, wall_t]) {
    difference() {
      cylinder(lcd_s_h, d=lcd_s_dia+2*wall, $fn=16);
      translate([0,0,-e]) cylinder(lcd_s_h+2*e, d=lcd_s_dia, $fn=16);
    }
  }
}

module lcd_mount_n() {
  translate([-lcd_a_w/2+lcd_window_offset-wall_t, -lcd_a_d/2-wall_t, -e])
    cube_bchamfer([lcd_a_w+2*wall_t, lcd_a_d+2*wall_t, wall_t+2*e], r=3, top=wall_t, $fn=12);
}

module wemos_place() {
  translate([oa_w/2+pad_right+wall-20, -lcd_d-lcd_ex_d, wall_t]) rotate(90) children();
}

module wemos_mount(extra_h) {
  we_w=25.9;
  we_d=35.2;
  we_h=6;
  we_rad=2.4;
  we_wall=1.2;

  difference() {
    translate([-we_w/2-we_wall, -we_d/2-we_wall, 0])
      cube_fillet([we_w+2*we_wall, we_d+2*we_wall, we_h+extra_h],
        vertical=[we_rad+we_wall*0.5855,we_rad+we_wall*0.5855]);

    translate([0,0,extra_h]) {
      // Big hole
      translate([-we_w/2, -we_d/2, 3])
        cube_fillet([we_w, we_d, we_h+2*e], vertical=[we_rad,we_rad]);
      // USB jack
      translate([-5.9, -we_d/2-we_wall-e, 2.3])
        cube([13, 10, we_h]);
      // Reset button
      translate([we_w/2-e, -we_d/2+1.8, 3.5])
        cube([we_wall+2*e, 5, we_h]);
      // Bottom small hole
      translate([-21/2, -31/2, -e])
        cube([21, 31, we_h+2*e]);
      // wifi antenna
      translate([-18/2, we_d/2-(we_d-31)/2-e, 3-1.3])
        cube([18, (we_d-31)/2+e, 1.3+e]);
    }
  } // diff

  // Grab notches
  translate([0,0,extra_h]) {
    translate([we_w/2,5/2,we_h-0.8/2]) rotate([90]) cylinder(5, d=0.8, $fn=4);
    translate([-we_w/2,5/2,we_h-0.8/2]) rotate([90]) cylinder(5, d=0.8, $fn=4);
  }
}

module branding() {
  translate([lcd_w/2-3,lcd_d+lcd_ex_d,-e]) mirror([1,0,0]) linear_extrude(0.24+e)
    text("HeaterMeter", halign="center", valign="center", font="Impact",
      spacing=1.3, size=7);
}

/********************************** LIBRARY CODE BELOW HERE **********************/

e = 0.01;

module cube_bchamfer(dim, r, top=0, bottom=0, $fn=$fn) {
  // bottom beaded area
  if (bottom != 0) hull(){
    translate([r,r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
  }
  // center
  translate([0,0,bottom]) hull(){
    translate([r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
  }
  // top beaded area
  if (top != 0) translate([0,0,dim[2]-top-e]) hull(){
    translate([r,r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
  }
}

module mirror2(dim) {
  // Create both item and mirror of item
  children();
  mirror(dim) children();
}

module fillet(radius, height=100, $fn=$fn) {
  if (radius > 0) {
    //this creates acutal fillet
    translate([-radius, -radius, -height / 2 - 0.02]) difference() {
        cube([radius * 2, radius * 2, height + 0.04]);
        if ($fn == 0 && (radius == 2 || radius == 3 || radius == 4)) {
            cylinder(r=radius, h=height + 0.04, $fn=4 * radius);
        } else {
            cylinder(r=radius, h=height + 0.04, $fn=$fn);
        }

    }
  }
}

module cube_fillet(size, radius=-1, vertical=[0,0,0,0], top=[0,0,0,0], bottom=[0,0,0,0], center=false, $fn=4){
    if (center) {
        cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    } else {
        translate([size[0]/2, size[1]/2, size[2]/2])
            cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    }
}

module cube_negative_fillet(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    j=[1,0,1,0];

    fn_V = $fn[0] == undef ? $fn : $fn[0];
    fn_T = $fn[1] == undef ? $fn : $fn[1];
    fn_B = $fn[2] == undef ? $fn : $fn[2];

    for (i=[0:3]) {
        if (radius > -1) {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(radius, size[2], fn_V);
        } else {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(vertical[i], size[2], fn_V);
        }
        rotate([90*i, -90, 0]) translate([size[2]/2, size[j[i]]/2, 0 ]) fillet(top[i], size[1-j[i]], fn_T);
        rotate([90*(4-i), 90, 0]) translate([size[2]/2, size[j[i]]/2, 0]) fillet(bottom[i], size[1-j[i]], fn_B);

    }
}

module cube_fillet_inside(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    //makes CENTERED cube with round corners
    // if you give it radius, it will fillet vertical corners.
    //othervise use vertical, top, bottom arrays
    //when viewed from top, it starts in upper right corner (+x,+y quadrant) , goes counterclockwise
    //top/bottom fillet starts in direction of Y axis and goes CCW too

    if (radius == 0) {
        cube(size, center=true);
    } else {
        difference() {
            cube(size, center=true);
            cube_negative_fillet(size, radius, vertical, top, bottom, $fn);
        }
    }
}

//cube_fillet([10,10,10]);

wall = 1.3;
wall_o = 1.9;
wall_t = 1.45;

lid_h = wall_t;

lcd_w = 67;
lcd_d = 28;
lcd_s_w = 60; // width between screws
lcd_s_d = 22;
lcd_s_h = 8.5;
lcd_s_dia = 3.1;
lcd_a_w = 50; // width of actual 7-segment area
lcd_a_d = 17.5; //19
lcd_ex_w = 0;
lcd_ex_d = 2;
lcd_window_offset = 2;

oa_w = 2*lcd_w+2*lcd_ex_w;
oa_d = 3*lcd_d+3*lcd_ex_d;
oa_h = 15;

main();
//translate([-oa_w/2, oa_d/2+wall_o+5, 0]) lid();

module main() {
  difference() {
    union() {
      translate([-oa_w/2-wall_o, -oa_d/2-wall_o, 0])
        cube_bchamfer([oa_w+2*lcd_window_offset+2*wall_o, oa_d+2*wall_o, oa_h+wall_t+lid_h+wall_t/2], r=5, bottom=1);
    } // union

    // main cutout
    translate([-oa_w/2, -oa_d/2, wall_t])
      cube_bchamfer([oa_w+2*lcd_window_offset, oa_d, oa_h+e], r=5-wall, bottom=1, top=lid_h);
    // lid cutout
    translate([-oa_w/2,-oa_d/2-wall_o-e,wall_t+oa_h])
      cube_fillet([oa_w+2*lcd_window_offset, oa_d+wall_o+e, lid_h+wall_t+e],
        vertical=[2,2], top=[lid_h,lid_h,0,lid_h], $fn=4);

    // LCD holes
    lcd_places() lcd_mount_n();

    // USB power hole
    wemos_place() translate([-5.9, -35.2/2-1.2-wall_o-e, 2.3+2-0.5])
      cube_fillet([13, 10, 6+1.5], top=[0,1,0,1]);

    //branding();
  } // diff

  lcd_places() lcd_mount_p();
  wemos_place() wemos_mount(2);
}

module lid() {
  ww = oa_w+2*lcd_window_offset+0.2;
  dd = oa_d+wall_o-0.2;
  difference() {
    cube_fillet([ww, dd, lid_h], bottom=[0.5, 0.5, 0, 0.5], vertical=[1.5, 1.5 ,1.5, 1.5]);
    // vent holes
    //translate([15, dd/2, 0])
    //  for (X=[0:3])
    //    translate([X*(ww-30)/3, 0, -e]) rotate(90) cylcyl(d*0.7, 2, lid_h+2*e, $fn=12);
  }
  // lock bump
  //translate([wall_o+wall_t+0.5, dd/2-4*wall, lid_h-e]) cube_fillet([2*wall, 8*wall, 0.6], top=[0.6,0,0.6,0]);
  translate([ww/4, wall_o+wall_t+0.5, lid_h-e]) cube_fillet([ww/2, 2*wall, 0.6], top=[0,0.6,0,0.6]);
}

module lcd_places() {
  // center two
  translate([lcd_w/2+lcd_ex_w,0,0])
    children();
  translate([-lcd_w/2+lcd_ex_w,0,0])
    children();
  // top/bottom
  mirror2([0,1,0]) translate([-lcd_w/2,lcd_d+lcd_ex_d,0])
    children();
}

module lcd_mount_p() {
  mirror2([1,0,0]) mirror2([0,1,0]) translate([lcd_s_w/2, lcd_s_d/2, wall_t]) {
    difference() {
      cylinder(lcd_s_h, d=lcd_s_dia+2*wall, $fn=16);
      translate([0,0,-e]) cylinder(lcd_s_h+2*e, d=lcd_s_dia, $fn=16);
    }
  }
}

module lcd_mount_n() {
  translate([-lcd_a_w/2+lcd_window_offset-wall_t, -lcd_a_d/2-wall_t, -e])
    cube_bchamfer([lcd_a_w+2*wall_t, lcd_a_d+2*wall_t, wall_t+2*e], r=3, top=wall_t, $fn=12);
}

module wemos_place() {
  translate([oa_w/2+2*lcd_window_offset+wall-20, -lcd_d-lcd_ex_d, wall_t]) rotate(90) children();
}

module wemos_mount(extra_h) {
  we_w=25.9;
  we_d=35.2;
  we_h=6;
  we_rad=2.4;
  we_wall=1.2;

  difference() {
    translate([-we_w/2-we_wall, -we_d/2-we_wall, 0])
      cube_fillet([we_w+2*we_wall, we_d+2*we_wall, we_h+extra_h],
        vertical=[we_rad+we_wall*0.5855,we_rad+we_wall*0.5855]);

    translate([0,0,extra_h]) {
      // Big hole
      translate([-we_w/2, -we_d/2, 3])
        cube_fillet([we_w, we_d, we_h+2*e], vertical=[we_rad,we_rad]);
      // USB jack
      translate([-5.9, -we_d/2-we_wall-e, 2.3])
        cube([13, 10, we_h]);
      // Reset button
      translate([we_w/2-e, -we_d/2+1.8, 3.5])
        cube([we_wall+2*e, 5, we_h]);
      // Bottom small hole
      translate([-21/2, -31/2, -e])
        cube([21, 31, we_h+2*e]);
      // wifi antenna
      translate([-18/2, we_d/2-(we_d-31)/2-e, 3-1.3])
        cube([18, (we_d-31)/2+e, 1.3+e]);
    }
  } // diff

  // Grab notches
  translate([0,0,extra_h]) {
    translate([we_w/2,5/2,we_h-0.8/2]) rotate([90]) cylinder(5, d=0.8, $fn=4);
    translate([-we_w/2,5/2,we_h-0.8/2]) rotate([90]) cylinder(5, d=0.8, $fn=4);
  }
}

module branding() {
  translate([lcd_w/2-3,lcd_d+lcd_ex_d,-e]) mirror([1,0,0]) linear_extrude(0.24+e)
    text("HeaterMeter", halign="center", valign="center", font="Impact",
      spacing=1.3, size=7);
}

/********************************** LIBRARY CODE BELOW HERE **********************/

e = 0.01;

module cube_bchamfer(dim, r, top=0, bottom=0, $fn=$fn) {
  // bottom beaded area
  if (bottom != 0) hull(){
    translate([r,r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(bottom+e, r1=max(0, r-bottom), r2=r, $fn=$fn);
  }
  // center
  translate([0,0,bottom]) hull(){
    translate([r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(dim[2]-top-bottom, r=r, $fn=$fn);
  }
  // top beaded area
  if (top != 0) translate([0,0,dim[2]-top-e]) hull(){
    translate([r,r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(top+e, r2=max(0, r-top), r1=r, $fn=$fn);
  }
}

module mirror2(dim) {
  // Create both item and mirror of item
  children();
  mirror(dim) children();
}

module fillet(radius, height=100, $fn=$fn) {
  if (radius > 0) {
    //this creates acutal fillet
    translate([-radius, -radius, -height / 2 - 0.02]) difference() {
        cube([radius * 2, radius * 2, height + 0.04]);
        if ($fn == 0 && (radius == 2 || radius == 3 || radius == 4)) {
            cylinder(r=radius, h=height + 0.04, $fn=4 * radius);
        } else {
            cylinder(r=radius, h=height + 0.04, $fn=$fn);
        }

    }
  }
}

module cube_fillet(size, radius=-1, vertical=[0,0,0,0], top=[0,0,0,0], bottom=[0,0,0,0], center=false, $fn=4){
    if (center) {
        cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    } else {
        translate([size[0]/2, size[1]/2, size[2]/2])
            cube_fillet_inside(size, radius, vertical, top, bottom, $fn);
    }
}

module cube_negative_fillet(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    j=[1,0,1,0];

    fn_V = $fn[0] == undef ? $fn : $fn[0];
    fn_T = $fn[1] == undef ? $fn : $fn[1];
    fn_B = $fn[2] == undef ? $fn : $fn[2];

    for (i=[0:3]) {
        if (radius > -1) {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(radius, size[2], fn_V);
        } else {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(vertical[i], size[2], fn_V);
        }
        rotate([90*i, -90, 0]) translate([size[2]/2, size[j[i]]/2, 0 ]) fillet(top[i], size[1-j[i]], fn_T);
        rotate([90*(4-i), 90, 0]) translate([size[2]/2, size[j[i]]/2, 0]) fillet(bottom[i], size[1-j[i]], fn_B);

    }
}

module cube_fillet_inside(size, radius=-1, vertical=[3,3,3,3], top=[0,0,0,0], bottom=[0,0,0,0], $fn=$fn){
    //makes CENTERED cube with round corners
    // if you give it radius, it will fillet vertical corners.
    //othervise use vertical, top, bottom arrays
    //when viewed from top, it starts in upper right corner (+x,+y quadrant) , goes counterclockwise
    //top/bottom fillet starts in direction of Y axis and goes CCW too

    if (radius == 0) {
        cube(size, center=true);
    } else {
        difference() {
            cube(size, center=true);
            cube_negative_fillet(size, radius, vertical, top, bottom, $fn);
        }
    }
}

//cube_fillet([10,10,10]);


main: add psu's + psu extrusion brackets

include <thing_libutils/metric-thread.scad>;
include <thing_libutils/metric-hexnut.scad>;
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
include <thing_libutils/timing-belts.scad>;

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

include <config.scad>
include <misc.scad>
include <extruder-direct.scad>
include <x-carriage.scad>
include <y-axis.scad>
include <y-axis-carriage-belt-clamp.scad>
include <y-axis-idler.scad>
include <z-axis.scad>
include <psu.scad>
include <rod-clamps.scad>

use <scad-utils/trajectory.scad>
use <scad-utils/trajectory_path.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/skin.scad>

axis_pos_x = 0*mm;
axis_pos_y = 0*mm;
axis_range_z=[85,380];
axis_pos_z = axis_range_z[1]*mm/2;

module x_axis()
{
    // x axis
    translate([0,0,axis_pos_z])
    {
        if(!preview_mode)
        {
            translate([0, xaxis_zaxis_distance_y, 0])
                belt_path(500, 6, xaxis_pulley_d, orient=[1,0,0]);
        }

        translate([axis_pos_x,0,0])
        {
            // x carriage
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])
            {
                x_carriage(show_bearings=true);
            }

            if(!preview_mode)
            {
                attach([[35, -0, -0], [1,0,0]], extruder_conn_xcarriage)
                {
                    extruder();
                }
            }
        }

        // x smooth rods
        for(i=[-1,1])
            translate([0,xaxis_zaxis_distance_y,i*(xaxis_rod_distance/2)])
                fncylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);
    }
}

module y_axis()
{
    // y axis
    attach([[yaxis_belt_path_offset_x,main_depth/2,yaxis_motor_offset_z], [0,-1,0]], yaxis_motor_mount_conn)
    {
        yaxis_motor_mount(show_motor=true);
    }

    extrusion_idler_conn = [[yaxis_belt_path_offset_x, -main_depth/2-extrusion_size, -extrusion_size+yaxis_idler_offset_z], [0,-1,0]];
    attach(extrusion_idler_conn, yaxis_idler_conn)
    {
        yaxis_idler();
        attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)
        {
            yaxis_idler_pulleyblock(show_bearing=true);
        }
    }

    translate([yaxis_belt_path_offset_x,0,yaxis_belt_path_offset_z])
    {
        if(!preview_mode)
        {
            translate([0,main_depth/2-yaxis_motor_offset_x,0])
            {
                /*cubea([10,main_depth-yaxis_motor_offset_x,10], align=[0,-1,0]);*/
                belt_path(main_depth-yaxis_motor_offset_x-yaxis_idler_pulley_offset_y, 6, yaxis_pulley_d, align=[0,-1,0], orient=[0,1,0]);
            }
        }
    }

    translate([0,-axis_pos_y,yaxis_bearing[0]/2])
    attach(ycarriage_bearing_mount_conn_bearing, yaxis_belt_mount_conn)
    {
        yaxis_belt_holder();
    }

    translate([0,0,yaxis_bearing[0]/2])
    {
        for(i=[-1,1])
        for(j=[-1,1])
        {
            attach([[i*(yaxis_rod_distance/2),j*(main_depth/2+extrusion_size/2),0],[0,0,1]],mount_rod_clamp_conn_rod)
            {
                mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=zmotor_mount_clamp_thread, orient=[0,1,0]);
            }
        }

        for(i=[-1,1])
        translate([i*(yaxis_rod_distance/2), 0, 0])
        {
            fncylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=[0,1,0]);

            for(j=[-1,1])
            {
                attach([[0,j*(yaxis_bearing_distance_y/2)-axis_pos_y,0],[0,0,-1]], ycarriage_bearing_mount_conn_bearing)
                {
                    ycarriage_bearing_mount(show_bearing=true, show_zips=true);
                }
            }
        }

        attach(ycarriage_bearing_mount_conn_bearing, [[0,axis_pos_y,0],[0,0,1]])
        {
            /*translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1]-16*mm)/2, 0])*/
            // y axis plate
            for(x=[-1,1])
            for(y=[-1,1])
            hull()
            {
                translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1])/2, 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,1]);
                }
                translate([x*(ycarriage_size[0]/2-16*mm), y*(ycarriage_size[1]/2-16*mm), 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,1]);
                }
            }

            cubea([ycarriage_size[0]-16*mm*2,ycarriage_size[1]-16*mm*2, ycarriage_size[2]], align=[0,0,1]);

            translate([0,0,10*mm])
                cubea(ycarriage_size, align=[0,0,1]);
        }
    }

}

module z_axis()
{
    // z axis
    for(i=[-1,1])
    {
        translate([i*(main_width/2),0,main_height])
        {
            mirror([i==-1?1:0,0,0])
            {
                upper_gantry_zrod_connector();

                translate([zmotor_mount_rod_offset_x, 0, extrusion_size/2])
                    mount_rod_clamp_half(
                            rod_d=zaxis_rod_d,
                            screw_dist=zmotor_mount_clamp_dist,
                            thick=5,
                            base_thick=5,
                            width=zmotor_mount_thickness_h,
                            thread=zmotor_mount_clamp_thread);
            }
        }

        translate([i*(main_width/2), 0, 0])
        {
            translate([0,0,zaxis_motor_offset_z])
                mirror([i==-1?1:0,0,0])
                {
                    zaxis_motor_mount(show_motor=true);

                    translate([zmotor_mount_rod_offset_x, 0, zmotor_mount_thickness_h/2])
                    {
                        mount_rod_clamp_half(
                                rod_d=zaxis_rod_d,
                                screw_dist=zmotor_mount_clamp_dist,
                                thick=5,
                                base_thick=5,
                                width=zmotor_mount_thickness_h,
                                thread=zmotor_mount_clamp_thread);
                    }
                }

            // z smooth rods
            translate([i*(lookup(NemaSideSize,zaxis_motor)/2), 0, 0])
            translate([i*(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
            {
                // z rods
                translate([0,0,zaxis_motor_offset_z-50])
                    fncylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=[0,0,1]);

                for(j=[-1,1])
                    translate([0,0,axis_pos_z-j*xaxis_rod_distance/2])
                        bearing(zaxis_bearing);

            }

            translate([i*zmotor_mount_rod_offset_x, 0, axis_pos_z])
                #fncylindera(h=100, d=zaxis_nut[1], align=[0,0,0]);

            translate([i*zaxis_leadscrew_offset_x, 0, axis_pos_z-xaxis_rod_distance/2-10])
            {
                difference()
                {
                    #fncylindera(h=10, d=zaxis_nut[1], align=[0,0,0]);
                    union()
                    {
                        fncylindera(h=10+1, d=zaxis_nut[0], center= false);
                        translate([0, 13.5, -1]) fncylindera(h=5, r=1.6);
                        translate([0, -13.5, -1]) fncylindera(h=5, r=1.6);
                    }
                }
            }
        }
    }

}

module main()
{
    color(extrusion_color)
    gantry_lower();

    color(extrusion_color)
    translate([0,0,-main_lower_dist_z])
    gantry_lower();

    color(extrusion_color)
    for(i=[-1,1])
    translate([0,i*(main_upper_dist_y/2),0])
    gantry_upper();

    x_axis();
    y_axis();
    z_axis();

    for(x=[-1,1])
    translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
    {
        translate([-x*psu_w/2, -psu_d/2, psu_h/2])
        {
            psu();

            mirror([x==-1?1:0,0,0])
            translate([0, -psu_screw_dist_y/2, 0])
                psu_extrusion_bracket_side();

            translate([0, psu_screw_dist_y/2, 0])
                psu_extrusion_bracket_back();
        }
    }
}

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

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

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

        }

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

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

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

module gantry_upper()
{
    for(i=[-1,1])
    translate([i*(main_width/2), 0, 0])
    {
        if(preview_mode)
        {
            cubea(size=[extrusion_size, extrusion_size, main_height], align=[-i,0,1]);
        }
        else
        {
            linear_extrusion(h=main_height, align=[-i,0,1], orient=[0,0,1]);
        }
    }

    translate([0, 0, main_height])
    {
        if(preview_mode)
        {
            cubea(size=[main_upper_width, extrusion_size, extrusion_size], align=[0,0,1]);
        }
        else
        {
            linear_extrusion(h=main_upper_width, align=[0,0,1], orient=[1,0,0]);
        }
    }
}

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

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

module enclosure()
{
    w=60*cm;
    h=60*cm;
    d=60*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

    translate([0, 0, h/2])
    {
        // left/right walls
        for(i=[-1,1])
            translate([i*w/2,0,0])
                cubea([wallthick,d,h], align=[-i, 0, 0]);

        // back plate
        translate([0,d/2,0])
            cubea([w,backthick,h], align=[0,-1, 0]);

        // top/bottom plate
        for(i=[-1,1])
        translate([0,0,i*h/2])
            cubea([w-wallthick*2,d,wallthick], align=[0,0, -i]);
    }
}

translate([0, 0, main_lower_dist_z+extrusion_size*2])
main();

/*psu();*/

/*%enclosure();*/

include <thing_libutils/metric-thread.scad>;
include <thing_libutils/metric-hexnut.scad>;
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/triangles.scad>
use <thing_libutils/linear-extrusion.scad>;
include <thing_libutils/timing-belts.scad>;

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

include <config.scad>
include <misc.scad>
include <extruder-direct.scad>
include <x-carriage.scad>
include <y-axis.scad>
include <y-axis-carriage-belt-clamp.scad>
include <y-axis-idler.scad>
include <z-axis.scad>
include <psu.scad>
include <rod-clamps.scad>

use <scad-utils/trajectory.scad>
use <scad-utils/trajectory_path.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>
use <list-comprehension-demos/skin.scad>

axis_pos_x = 0*mm;
axis_pos_y = 0*mm;
axis_range_z=[85,380];
axis_pos_z = axis_range_z[1]*mm/2;

module x_axis()
{
    // x axis
    translate([0,0,axis_pos_z])
    {
        if(!preview_mode)
        {
            translate([0, xaxis_zaxis_distance_y, 0])
                belt_path(500, 6, xaxis_pulley_d, orient=[1,0,0]);
        }

        translate([axis_pos_x,0,0])
        {
            // x carriage
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])
            {
                x_carriage(show_bearings=true);
            }

            if(!preview_mode)
            {
                attach([[35, -0, -0], [1,0,0]], extruder_conn_xcarriage)
                {
                    extruder();
                }
            }
        }

        // x smooth rods
        for(i=[-1,1])
            translate([0,xaxis_zaxis_distance_y,i*(xaxis_rod_distance/2)])
                fncylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);
    }
}

module y_axis()
{
    // y axis
    attach([[yaxis_belt_path_offset_x,main_depth/2,yaxis_motor_offset_z], [0,-1,0]], yaxis_motor_mount_conn)
    {
        yaxis_motor_mount(show_motor=true);
    }

    extrusion_idler_conn = [[yaxis_belt_path_offset_x, -main_depth/2-extrusion_size, -extrusion_size+yaxis_idler_offset_z], [0,-1,0]];
    attach(extrusion_idler_conn, yaxis_idler_conn)
    {
        yaxis_idler();
        attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)
        {
            yaxis_idler_pulleyblock(show_bearing=true);
        }
    }

    translate([yaxis_belt_path_offset_x,0,yaxis_belt_path_offset_z])
    {
        if(!preview_mode)
        {
            translate([0,main_depth/2-yaxis_motor_offset_x,0])
            {
                /*cubea([10,main_depth-yaxis_motor_offset_x,10], align=[0,-1,0]);*/
                belt_path(main_depth-yaxis_motor_offset_x-yaxis_idler_pulley_offset_y, 6, yaxis_pulley_d, align=[0,-1,0], orient=[0,1,0]);
            }
        }
    }

    translate([0,-axis_pos_y,yaxis_bearing[0]/2])
    attach(ycarriage_bearing_mount_conn_bearing, yaxis_belt_mount_conn)
    {
        yaxis_belt_holder();
    }

    translate([0,0,yaxis_bearing[0]/2])
    {
        for(i=[-1,1])
        for(j=[-1,1])
        {
            attach([[i*(yaxis_rod_distance/2),j*(main_depth/2+extrusion_size/2),0],[0,0,1]],mount_rod_clamp_conn_rod)
            {
                mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=zmotor_mount_clamp_thread, orient=[0,1,0]);
            }
        }

        for(i=[-1,1])
        translate([i*(yaxis_rod_distance/2), 0, 0])
        {
            fncylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=[0,1,0]);

            for(j=[-1,1])
            {
                attach([[0,j*(yaxis_bearing_distance_y/2)-axis_pos_y,0],[0,0,-1]], ycarriage_bearing_mount_conn_bearing)
                {
                    ycarriage_bearing_mount(show_bearing=true, show_zips=true);
                }
            }
        }

        attach(ycarriage_bearing_mount_conn_bearing, [[0,axis_pos_y,0],[0,0,1]])
        {
            /*translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1]-16*mm)/2, 0])*/
            // y axis plate
            for(x=[-1,1])
            for(y=[-1,1])
            hull()
            {
                translate([x*ycarriage_size[0]/2, y*(ycarriage_size[1])/2, 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,1]);
                }
                translate([x*(ycarriage_size[0]/2-16*mm), y*(ycarriage_size[1]/2-16*mm), 0])
                {
                    fncylindera(d=10*mm, h=ycarriage_size[2], align=[-x,-y,1]);
                }
            }

            cubea([ycarriage_size[0]-16*mm*2,ycarriage_size[1]-16*mm*2, ycarriage_size[2]], align=[0,0,1]);

            translate([0,0,10*mm])
                cubea(ycarriage_size, align=[0,0,1]);
        }
    }

}

module z_axis()
{
    // z axis
    for(i=[-1,1])
    {
        translate([i*(main_width/2),0,main_height])
        {
            mirror([i==-1?1:0,0,0])
            {
                upper_gantry_zrod_connector();

                translate([zmotor_mount_rod_offset_x, 0, extrusion_size/2])
                    mount_rod_clamp_half(
                            rod_d=zaxis_rod_d,
                            screw_dist=zmotor_mount_clamp_dist,
                            thick=5,
                            base_thick=5,
                            width=zmotor_mount_thickness_h,
                            thread=zmotor_mount_clamp_thread);
            }
        }

        translate([i*(main_width/2), 0, 0])
        {
            translate([0,0,zaxis_motor_offset_z])
                mirror([i==-1?1:0,0,0])
                {
                    zaxis_motor_mount(show_motor=true);

                    translate([zmotor_mount_rod_offset_x, 0, zmotor_mount_thickness_h/2])
                    {
                        mount_rod_clamp_half(
                                rod_d=zaxis_rod_d,
                                screw_dist=zmotor_mount_clamp_dist,
                                thick=5,
                                base_thick=5,
                                width=zmotor_mount_thickness_h,
                                thread=zmotor_mount_clamp_thread);
                    }
                }

            // z smooth rods
            translate([i*(lookup(NemaSideSize,zaxis_motor)/2), 0, 0])
            translate([i*(zaxis_rod_screw_distance_x+zmotor_mount_motor_offset),0,0])
            {
                // z rods
                translate([0,0,zaxis_motor_offset_z-50])
                    fncylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=[0,0,1]);

                for(j=[-1,1])
                    translate([0,0,axis_pos_z-j*xaxis_rod_distance/2])
                        bearing(zaxis_bearing);

            }

            translate([i*zmotor_mount_rod_offset_x, 0, axis_pos_z])
                #fncylindera(h=100, d=zaxis_nut[1], align=[0,0,0]);

            translate([i*zaxis_leadscrew_offset_x, 0, axis_pos_z-xaxis_rod_distance/2-10])
            {
                difference()
                {
                    #fncylindera(h=10, d=zaxis_nut[1], align=[0,0,0]);
                    union()
                    {
                        fncylindera(h=10+1, d=zaxis_nut[0], center= false);
                        translate([0, 13.5, -1]) fncylindera(h=5, r=1.6);
                        translate([0, -13.5, -1]) fncylindera(h=5, r=1.6);
                    }
                }
            }
        }
    }

}

module main()
{
    color(extrusion_color)
    gantry_lower();

    color(extrusion_color)
    translate([0,0,-main_lower_dist_z])
    gantry_lower();

    color(extrusion_color)
    for(i=[-1,1])
    translate([0,i*(main_upper_dist_y/2),0])
    gantry_upper();

    x_axis();
    y_axis();
    z_axis();
}

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

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

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

        }

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

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

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

module gantry_upper()
{
    for(i=[-1,1])
    translate([i*(main_width/2), 0, 0])
    {
        if(preview_mode)
        {
            cubea(size=[extrusion_size, extrusion_size, main_height], align=[-i,0,1]);
        }
        else
        {
            linear_extrusion(h=main_height, align=[-i,0,1], orient=[0,0,1]);
        }
    }

    translate([0, 0, main_height])
    {
        if(preview_mode)
        {
            cubea(size=[main_upper_width, extrusion_size, extrusion_size], align=[0,0,1]);
        }
        else
        {
            linear_extrusion(h=main_upper_width, align=[0,0,1], orient=[1,0,0]);
        }
    }
}

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

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

module enclosure()
{
    w=60*cm;
    h=60*cm;
    d=60*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

    translate([0, 0, h/2])
    {
        // left/right walls
        for(i=[-1,1])
            translate([i*w/2,0,0])
                cubea([wallthick,d,h], align=[-i, 0, 0]);

        // back plate
        translate([0,d/2,0])
            cubea([w,backthick,h], align=[0,-1, 0]);

        // top/bottom plate
        for(i=[-1,1])
        translate([0,0,i*h/2])
            cubea([w-wallthick*2,d,wallthick], align=[0,0, -i]);
    }
}

translate([0, 0, main_lower_dist_z+extrusion_size*2])
main();

/*psu();*/

/*%enclosure();*/


updated size

updated size

module solarPanel()
{
    translate([0,0,1.5]) color("blue") cube([51,51,4]);
    translate([4,4,0]) color("red") cube([43,43,5]);
    translate([0,21.5,0]) color("orange") cube([51,8,5]);
}

difference()
{
    cube([140,75,5]);
    translate([17,12.25,0]) solarPanel();
    translate([70,12.25,0]) solarPanel();
}


Added leeway for the board and cutouts for the lid

//
// This is the iotsa board itself, including the important connectors and
// holes. You can define here if you have shortened the board, which will
// not only change the board itself, but also the box we are going to create around it.
//
numberOfRowsRemoved = 0;
extraMMRemoved = 0; // 0 if nothing removed, 2.2 if any rows removed.
numberOfMMRemoved = extraMMRemoved + (numberOfRowsRemoved*2.54);

boardThickness = 1.8; // The thickness of the PCB board
regulatorAngle = 35; // 0, or higher if you've bent the regulator over backwards.

module iotsaBoard() {
    module esp12() {
        union() {
            cube([24, 16, 2]); // the esp-12 board
            translate([8, 1.5, 2]) cube([15, 13, 2.5]); // the metal cap
        }
    }
    module regulator() {
        rotate([-regulatorAngle, 0, 0])
        translate([0, 0, 5])
        union() {
            translate([0, 4.5, 0]) cube([10.2, 1.3, 15]);
            translate([0, 0, 0]) cube([10.2, 4.5, 8.5]);
        }
    }
    module powerjack() {
        difference() {
            cube([9, 15, 11]);
            translate([4.5, -1, 7]) rotate([-90, 0, 0]) cylinder(14, d=6);
        }
    }
    translate([0, 0, -1.8])
    union() {
        // The board
        difference() {
            cube([63-numberOfMMRemoved,43,1.8]);
            translate([2, 2, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([2, 41, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([36.5, 2, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([36.5, 41, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([60.5, 2, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([60.5, 41, -0.1]) cylinder(2, d=2, center=false, $fn=12);
        }
        // The components
        translate([-5, 13.5, 1.8]) esp12();
        translate([20, 15, 1.8]) regulator();
        translate([22, -3, 1.8]) powerjack();
    }
}

//
// Box parameters. We are going to compute the size from the parameters.
//
iotsaComponentHeight = 20;  // Make sure this is high enough
iotsaSolderingHeight = 3;   // How far the soldering extends below the board.
boxThickness = 3;
boxBottomThickness = boxThickness;
boxFrontThickness = boxThickness;   // This is where the power connector is
boxLeftThickness = boxThickness;
boxRightThickness = boxThickness;
boxBackThickness = boxThickness;
boxTopThickness = boxThickness;

leeWay = 0.3;   // gap we want between board and box (on all sides, individually)

module box() {
    innerXSize = (63-numberOfMMRemoved) + 5 + 2*leeWay; // Add 5 for how far the esp12 antenna extends
    innerYSize = 43 + 2*leeWay;
    innerZSize = boardThickness + iotsaComponentHeight + iotsaSolderingHeight + 2*leeWay;

    outerXSize = innerXSize + boxLeftThickness + boxRightThickness;
    outerYSize = innerYSize + boxFrontThickness + boxBackThickness;
    outerZSize = innerZSize + boxBottomThickness + boxTopThickness;

    strutThickness = 2;
    retainerWidth = 3;
    retainerLength = 6;

    module basicBox() {
         difference() {
            cube([outerXSize, outerYSize, outerZSize-boxTopThickness]);
            translate([boxLeftThickness, boxFrontThickness, boxBottomThickness])
                cube([innerXSize, innerYSize, innerZSize+1]);
        }
    }
    module frontHoles() {
        // Holes in the front. X and Z relative to iotsa frontleft corner, Y should be 2*frontThickness.
        translate([22-leeWay, 0, 0-leeWay]) cube([9+2*leeWay, 2*boxFrontThickness, 11+2*leeWay]);
    }
    union() {
        difference() {
            translate([-5-boxLeftThickness-leeWay, -boxFrontThickness-leeWay, -(boardThickness+iotsaSolderingHeight+boxBottomThickness+leeWay)])
                union() {
                    // The box itself, with the cutouts for the lid
                    difference() {
                        basicBox();
                        // Front cutout
                        translate([boxLeftThickness, -boxFrontThickness, outerZSize-boxTopThickness-boxBottomThickness])
                            cube([innerXSize, 2*boxFrontThickness, 2*boxTopThickness]);
                        // back cutout
                        translate([boxLeftThickness, innerYSize+boxFrontThickness-0.5*leeWay, outerZSize-boxTopThickness-boxBottomThickness])
                            cube([innerXSize, 0.5*boxBackThickness+leeWay, 0.5*boxTopThickness]);
                        // left retainer hole
                        # translate([boxLeftThickness,-0.5*boxFrontThickness, outerZSize-boxTopThickness-boxBottomThickness-retainerLength])
                            cube([retainerWidth, 2*boxFrontThickness, retainerWidth]);
                        // right retainer hole
                        # translate([outerXSize-boxRightThickness-retainerWidth, -0.5*boxFrontThickness, outerZSize-boxTopThickness-boxBottomThickness-retainerLength])
                            cube([retainerWidth, 2*boxFrontThickness, retainerWidth]);
                    }
                    // The front support for the iotsa board
                    cube([outerXSize, boxFrontThickness+strutThickness, boxBottomThickness+iotsaSolderingHeight]);
                    // The back support for the outsa board
                    translate([0, innerYSize, 0])
                        cube([outerXSize, boxFrontThickness+strutThickness, boxBottomThickness+iotsaSolderingHeight]);
                }
                translate([0, -1.5*boxFrontThickness-leeWay, 0]) frontHoles();
            }
        % iotsaBoard();
    }
}
box();

//
// This is the iotsa board itself, including the important connectors and
// holes. You can define here if you have shortened the board, which will
// not only change the board itself, but also the box we are going to create around it.
//
numberOfRowsRemoved = 0;
extraMMRemoved = 0; // 0 if nothing removed, 2.2 if any rows removed.
numberOfMMRemoved = extraMMRemoved + (numberOfRowsRemoved*2.54);

boardThickness = 1.8; // The thickness of the PCB board
regulatorAngle = 35; // 0, or higher if you've bent the regulator over backwards.

module iotsaBoard() {
    module esp12() {
        union() {
            cube([24, 16, 2]); // the esp-12 board
            translate([8, 1.5, 2]) cube([15, 13, 2.5]); // the metal cap
        }
    }
    module regulator() {
        rotate([-regulatorAngle, 0, 0])
        translate([0, 0, 5])
        union() {
            translate([0, 4.5, 0]) cube([10.2, 1.3, 15]);
            translate([0, 0, 0]) cube([10.2, 4.5, 8.5]);
        }
    }
    module powerjack() {
        difference() {
            cube([9, 15, 11]);
            translate([4.5, -1, 7]) rotate([-90, 0, 0]) cylinder(14, d=6);
        }
    }
    translate([0, 0, -1.8])
    union() {
        // The board
        difference() {
            cube([63-numberOfMMRemoved,43,1.8]);
            translate([2, 2, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([2, 41, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([36.5, 2, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([36.5, 41, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([60.5, 2, -0.1]) cylinder(2, d=2, center=false, $fn=12);
            translate([60.5, 41, -0.1]) cylinder(2, d=2, center=false, $fn=12);
        }
        // The components
        translate([-5, 13.5, 1.8]) esp12();
        translate([20, 15, 1.8]) regulator();
        translate([22, -3, 1.8]) powerjack();
    }
}

//
// Box parameters. We are going to compute the size from the parameters.
//
iotsaComponentHeight = 20;  // Make sure this is high enough
iotsaSolderingHeight = 3;   // How far the soldering extends below the board.
boxThickness = 3;
boxBottomThickness = boxThickness;
boxFrontThickness = boxThickness;   // This is where the power connector is
boxLeftThickness = boxThickness;
boxRightThickness = boxThickness;
boxBackThickness = boxThickness;
boxTopThickness = boxThickness;

module box() {
    innerXSize = (63-numberOfMMRemoved) + 5; // Add 5 for how far the esp12 antenna extends
    innerYSize = 43;
    innerZSize = boardThickness + iotsaComponentHeight + iotsaSolderingHeight;

    outerXSize = innerXSize + boxLeftThickness + boxRightThickness;
    outerYSize = innerYSize + boxFrontThickness + boxBackThickness;
    outerZSize = innerZSize + boxBottomThickness + boxTopThickness;

    strutThickness = 2;
    module basicBox() {
         difference() {
            cube([outerXSize, outerYSize, outerZSize-boxTopThickness]);
            translate([boxLeftThickness, boxFrontThickness, boxBottomThickness])
                cube([innerXSize, innerYSize, innerZSize+1]);
        }
    }
    module frontHoles() {
        // Holes in the front. X and Z relative to iotsa frontleft corner, Y should be 2*frontThickness.
        translate([22, 0, 0]) cube([9, 2*boxFrontThickness, 11]);
    }
    union() {
        difference() {
            translate([-5-boxLeftThickness, -boxFrontThickness, -(boardThickness+iotsaSolderingHeight+boxBottomThickness)])
                union() {
                    basicBox();
                    cube([outerXSize, boxFrontThickness+strutThickness, boxBottomThickness+iotsaSolderingHeight]);
                    translate([0, innerYSize, 0])
                        cube([outerXSize, boxFrontThickness+strutThickness, boxBottomThickness+iotsaSolderingHeight]);
                }
                translate([0, -boxFrontThickness, 0]) frontHoles();
            }
        % iotsaBoard();
    }
}
box();


z/motor-mount: rewrite to part system, use screw_cut

include <z-motor-mount.h>
include <thing_libutils/materials.scad>
include <MCAD/motors.scad>

use <thing_libutils/attach.scad>
use <thing_libutils/shapes.scad>
use <thing_libutils/screws.scad>
use <thing_libutils/transforms.scad>

use <rod-clamps.scad>

module zaxis_motor_mount(part)
{
    if(part==U)
    {
        difference()
        {
            zaxis_motor_mount(part="pos");
            zaxis_motor_mount(part="neg");
        }
        %zaxis_motor_mount(part="vit");
    }
    else if(part=="pos")
    material(Mat_Plastic)
    {
        // top plate
        rcubea([zmotor_mount_rod_offset_x-zmotor_mount_thickness, zmotor_w+zmotor_mount_thickness*2, zmotor_mount_thickness_h], align=[1,0,1]);
        translate([zmotor_mount_rod_offset_x, 0, 0])
        {
            rcubea([gantry_connector_thickness+5, zmotor_w+zmotor_mount_thickness*2, zmotor_mount_thickness_h], align=[-1,0,1]);
        }

        // reinforcement plate between motor and extrusion
        rcubea([zmotor_mount_thickness, zmotor_w+2, zmotor_h], align=[1,0,-1], extra_size=[0,0,2], extra_align=Z);

        // top extrusion mount plate
        translate([0, 0,-extrusion_size-zaxis_motor_offset_z])
        rcubea([zmotor_mount_thickness, zmotor_mount_width, extrusion_size], align=[1,0,1]);

        // bottom extrusion mount plate
        translate([0, 0, -main_lower_dist_z-extrusion_size-zaxis_motor_offset_z])
        rcubea([zmotor_mount_thickness, zmotor_w+2, extrusion_size], align=[1,0,1]);

        // side triangles
        for(i=[-1,1])
        {
            translate([zmotor_mount_thickness, i*((zmotor_w/2)+zmotor_mount_thickness/2), 2])
            triangle(
                zmotor_mount_rod_offset_x-zmotor_mount_thickness,
                main_lower_dist_z+extrusion_size+zaxis_motor_offset_z+2,
                depth=zmotor_mount_thickness,
                align=[1,0,-1],
                orient=X
                );

            translate([0, i*((zmotor_w/2)+zmotor_mount_thickness/2), 2])
            cubea([zmotor_mount_thickness, zmotor_mount_thickness, zmotor_mount_h+2], align=[1,0,-1]);
        }
    }
    else if(part=="neg")
    {
        // cutout for motor cables
        translate([0,0,-30*mm])
        cubea([zmotor_mount_thickness*3, 20*mm, zmotor_h], align=[0,0,-1]);

        // screw holes top
        for(y=[-1,1])
        tx(zmotor_mount_thickness)
        ty(y*(zmotor_w/2+zmotor_mount_thread_dia*3))
        tz(-extrusion_size)
        screw_cut(nut=extrusion_nut, head="button", h=12*mm, orient=-X, align=-X);

        // screw hole bottom
        for(y=[0])
        tx(zmotor_mount_thickness)
        ty(y*(zmotor_w/2+zmotor_mount_thread_dia*3))
        tz(-extrusion_size-main_lower_dist_z)
        screw_cut(nut=extrusion_nut, head="button", h=12*mm, orient=-X, align=-X);

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

        // cut out z rod
        translate([zmotor_mount_rod_offset_x, 0, 0])
        cylindera(d=zaxis_rod_d*rod_fit_tolerance, h=100, orient=Z);

        // cut out z rod mounting clamp nut traps
        for(i=[-1,1])
        {
            translate([zmotor_mount_rod_offset_x-5, i*zmotor_mount_clamp_dist/2, zmotor_mount_thickness_h/2])
            {
                nut_trap_cut(nut=zmotor_mount_clamp_nut, h=10, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=-Z, orient=X, align=N);
            }
        }

    }
    else if(part=="vit")
    {
        attach([[lookup(NemaSideSize,zaxis_motor)/2,0,0],N],zmotor_mount_conn_motor)
        {
            // z motor/leadscrews
            motor(zaxis_motor, NemaMedium, dualAxis=false, orientation=[0,180,0]);
        }
    }
}

module part_z_motor_mount()
{
    rotate([0,-90,0])
    zaxis_motor_mount();
}

module part_z_motor_mount_clamp()
{
    translate([0,0,zmotor_mount_thickness_h/2])
    mount_rod_clamp_half(
            rod_d=zaxis_rod_d,
            screw_dist=zmotor_mount_clamp_dist,
            thick=5,
            base_thick=5,
            width=zmotor_mount_thickness_h,
            thread=zmotor_mount_clamp_thread);
}

include <z-motor-mount.h>
include <thing_libutils/materials.scad>
include <MCAD/motors.scad>

use <thing_libutils/attach.scad>
use <thing_libutils/shapes.scad>
use <thing_libutils/screws.scad>

use <rod-clamps.scad>

module zaxis_motor_mount(show_motor=false)
{
    difference()
    {
        // top plate
        union()
        {

            difference()
            {
                material(Mat_Plastic)
                union()
                {
                    // top plate
                    rcubea([zmotor_mount_rod_offset_x-zmotor_mount_thickness, zmotor_w+zmotor_mount_thickness*2, zmotor_mount_thickness_h], align=[1,0,1]);
                    translate([zmotor_mount_rod_offset_x, 0, 0])
                    {
                        rcubea([gantry_connector_thickness+5, zmotor_w+zmotor_mount_thickness*2, zmotor_mount_thickness_h], align=[-1,0,1]);
                    }

                    // reinforcement plate between motor and extrusion
                    rcubea([zmotor_mount_thickness, zmotor_w+2, zmotor_h], align=[1,0,-1], extra_size=[0,0,2], extra_align=Z);

                    // top extrusion mount plate
                    translate([0, 0,-extrusion_size-zaxis_motor_offset_z])
                        rcubea([zmotor_mount_thickness, zmotor_mount_width, extrusion_size], align=[1,0,1]);

                    // bottom extrusion mount plate
                    translate([0, 0, -main_lower_dist_z-extrusion_size-zaxis_motor_offset_z])
                        rcubea([zmotor_mount_thickness, zmotor_w+2, extrusion_size], align=[1,0,1]);

                    // side triangles
                    for(i=[-1,1])
                    {
                        translate([zmotor_mount_thickness, i*((zmotor_w/2)+zmotor_mount_thickness/2), 2])
                            triangle(
                                    zmotor_mount_rod_offset_x-zmotor_mount_thickness,
                                    main_lower_dist_z+extrusion_size+zaxis_motor_offset_z+2,
                                    depth=zmotor_mount_thickness,
                                    align=[1,0,-1],
                                    orient=X
                                    );

                        translate([0, i*((zmotor_w/2)+zmotor_mount_thickness/2), 2])
                            cubea([zmotor_mount_thickness, zmotor_mount_thickness, zmotor_mount_h+2], align=[1,0,-1]);
                    }

                }

                // cutout for motor cables
                translate([0,0,-30*mm])
                cubea([zmotor_mount_thickness*3, 20*mm, zmotor_h], align=[0,0,-1]);

                // screw holes top
                for(i=[-1,1])
                    translate([0, i*(zmotor_w/2+zmotor_mount_thread_dia*3), -extrusion_size])
                        cylindera(h=zmotor_mount_thickness*3,d=zmotor_mount_thread_dia, orient=X);

                // screw hole bottom
                for(i=[0])
                    translate([0, i*(zmotor_w/2+zmotor_mount_thread_dia*3), -extrusion_size-main_lower_dist_z])
                        cylindera(h=zmotor_mount_thickness*3,d=zmotor_mount_thread_dia,align=N, orient=X);
            }

        }

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

        // cut out z rod
        translate([zmotor_mount_rod_offset_x, 0, 0])
            cylindera(d=zaxis_rod_d*rod_fit_tolerance, h=100, orient=Z);

        // cut out z rod mounting clamp nut traps
        for(i=[-1,1])
        {
            translate([zmotor_mount_rod_offset_x-5, i*zmotor_mount_clamp_dist/2, zmotor_mount_thickness_h/2])
            {
                nut_trap_cut(nut=zmotor_mount_clamp_nut, h=10, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=Z, orient=X, align=N);
            }
        }

        %if(show_motor)
        {
            attach([[lookup(NemaSideSize,zaxis_motor)/2,0,0],N],zmotor_mount_conn_motor)
            {
                // z motor/leadscrews
                motor(zaxis_motor, NemaMedium, dualAxis=false, orientation=[0,180,0]);
            }
        }
    }
}

module part_z_motor_mount()
{
    rotate([0,-90,0])
    zaxis_motor_mount();
}

module part_z_motor_mount_clamp()
{
    translate([0,0,zmotor_mount_thickness_h/2])
    mount_rod_clamp_half(
            rod_d=zaxis_rod_d,
            screw_dist=zmotor_mount_clamp_dist,
            thick=5,
            base_thick=5,
            width=zmotor_mount_thickness_h,
            thread=zmotor_mount_clamp_thread);
}


curve: fix eol

curve: fix eol

include <system.scad>
use <shapes.scad>
use <scad-utils/lists.scad>
use <scad-utils/trajectory.scad>
use <scad-utils/trajectory_path.scad>
use <scad-utils/transformations.scad>
use <scad-utils/shapes.scad>
use <scad-utils/linalg.scad>
use <scad-utils/se3.scad>
use <scad-utils/so3.scad>
use <list-comprehension-demos/skin.scad>
use <list-comprehension-demos/sweep.scad>

module draw_path(path, r=1) {
    for (i=[0:len(path)-2]) {
        hull() {
            translate(path[i]) sphere(r);
            translate(path[i+1]) sphere(r);
        }
    }
}

module draw_transform(transform, r=1) {
    multmatrix(transform) scale(r/3) frame(10);
}

module draw_transforms(transforms, r=1) {
    for (t=transforms) {
        draw_transform(t,r);
    }
}

function vec_trans(path_t) = [for(t=path_t) translation_part(t)];

function to_delta_trans(path)=
[
    let(l=len(path))
    for (i=[0:l-1-1])
        trajectory(translation=path[i+1]-path[i])
];

function quantize_path(path, step, includestartoffset=1) = let (
    // construct vector of delta translations
    path_traj = to_delta_trans(path)
    // quantize evenly along path
    , path_q_f = quantize_trajectories(path_traj, step=step, loop=false, start_position=0)
    )
    includestartoffset == 1 ?
        [for(v=path_q_f) path[0]+translation_part(v)]
        :
        [for(v=path_q_f) translation_part(v)]
;

function step_vec(vec, step, start_offset=0, end_offset=0) =
    [start_offset:step:len(vec)-1-end_offset];

function iterate_step_vec(vec, step, start_offset=0, end_offset=0, even=0) =
    even==1?
    //remainder
    let(r = (len(vec)-1) % step)
    [for(k=[r/2+start_offset:step:len(vec)-1-end_offset]) vec[k]]
    :
    [for(k=[start_offset:step:len(vec)-1-end_offset]) vec[k]]
;

module place(vec_t, debug=0)
{
    for(t=vec_t)
    {
        multmatrix(t)
        {
            if(debug>=1)
            {
                {
                    draw_transforms(t);
                }
            }
            children();
        }
    }
}

module placealong(vec_t, step, start_offset=0, end_offset=0, even=0, debug=0)
{
    vec = iterate_step_vec(vec_t,step,start_offset,end_offset, even);
    place(vec, debug)
    {
        children();
    }
}

function c(t, r=[20,20], degrees=360) = [
    r[0]*(cos((degrees)*t)),
    0,
    r[1]*(sin((degrees)*t)),
];
function c_(t, r=[20,20], degrees=360) = [
    r[0]*-degrees*(sin((degrees)*t)),
    0,
    r[1]*-degrees*(cos((degrees)*t)),
];

function f(t,r,d)=c(t,r,d)-c(0,r,d);

/*s = degrees/4;*/
s = 10;

degrees = s*10;

// one step per degree
degstep = 1;
path_e = [for (t=[0:degstep/degrees:1-degstep/degrees]) vec3(f(t,[80,50],degrees)) ];

// normal transform path (not evenly distributed points)
path_t = construct_transform_path(path_e);

// evenly distributed points, "acc" steps per degree
acc = 2;
path_e_q = quantize_path(path_e, step=1/acc);
path_t_q = construct_transform_path(path_e_q);
/*accstep = acc * len(path_t)/len(path_t_q);*/

function path_sweepalong(path) = [for(k=path) place_mat()*k];
function path_placealong(path) = [for(k=path) place_mat()*k*rotation([180,90,0])];

function place_mat() =
    translation(N)
    *
    rotation(N)
    ;

shape_debug = rectangle_profile([0.5,0.5]);

// non-interpolated
translate(N)
{
    color("black")
    {
        sweep(shape_debug, path_sweepalong(path_t), false);
    }
    placealong(path_placealong(path_t), s, even=0, debug=1)
    {
        color("red")
        {
            cube([s,5,0.1], true);
        }
    }
}

// interpolated
translate([0,10,0])
{
    color("black")
    {
        sweep(shape_debug, path_sweepalong(path_t_q), false);
    }
    placealong(path_placealong(path_t_q), s*acc, even=0, debug=1)
    {
        color("blue")
        {
            cube([s,5,0.1], true);
        }
    }
}