fix the top yet again

fix the top yet again

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

// box thickness
th = 2;

shift_x = 4;
shift_y = th + 1;

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

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

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

usb_type_b_w = 12;
usb_type_b_h = 11;
start_type_b_y = shift_y + 81.5;
//start_type_b_z = th + pcb_z + tol;

usb_type_a_w = 14.4;
usb_type_a_h = 7.8;
start_type_a_y = shift_y + 46;
//start_type_a_z = th + pcb_z + tol;

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

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

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

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

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

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

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

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

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

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

top_box_z = 15 + th;
stoiki_h = top_box_z - th;
wide_stoiki_h = 4;
pcb_room = 1;
screen_start_x = shift_x + 29;
screen_start_y = shift_y + 38.9;
screen_length_x = 71.2;
screen_length_y = 24.2;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 12;
screen_hold_y_shift = 2;
screen_hold_up_x = 15;
screen_hold_up_x_shift = 5;

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

!difference() {
  union() {
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room]) {
          cylinder($fn=6, r=stoiki_r, h=top_box_z-th+eps);
        }
        translate([dx,dy,top_box_z-th-wide_stoiki_h+eps]) {
          cylinder($fn=6, r=wide_stoiki_r, h=wide_stoiki_h+th-2*eps);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y - screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
    translate([screen_start_x + screen_length_x - screen_hold_up_x - screen_hold_up_x_shift, screen_start_y + screen_length_y + screen_hold_y_shift, screen_hold_start_z]) {
	cube([screen_hold_up_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker na stoikah
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // speaker_hole
  for (dy = [shift_y + speaker_shift - speaker_hole_int - speaker_hole_w*3/2,
             shift_y + speaker_shift - speaker_hole_w/2,
             shift_y + speaker_shift + speaker_hole_int + speaker_hole_w/2]) {
    translate([shift_x + pcb_x - speaker_shift - speaker_hole_d, dy, top_box_z-th-eps]) {
      cube(size=[speaker_hole_d, speaker_hole_w, th + 2*eps]);
    }
  }

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

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

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

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

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

// box thickness
th = 2;

shift_x = 4;
shift_y = th + 1;

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

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

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

usb_type_b_w = 12;
usb_type_b_h = 11;
start_type_b_y = shift_y + 81.5;
//start_type_b_z = th + pcb_z + tol;

usb_type_a_w = 13.4;
usb_type_a_h = 7.3;
start_type_a_y = shift_y + 47;
//start_type_a_z = th + pcb_z + tol;

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

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

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

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

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

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

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

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

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

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

top_box_z = 15 + th;
stoiki_h = top_box_z - th;
wide_stoiki_h = 2;
pcb_room = 0.5;
screen_start_x = shift_x + 29.15;
screen_start_y = shift_y + 39.1;
screen_length_x = 72;
screen_length_y = 24.2;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 12;
screen_hold_y_shift = 2;
screen_hold_up_x = 15;
screen_hold_up_x_shift = 5;

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

!difference() {
  union() {
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room]) {
	  cylinder($fn=6, r=stoiki_r, h=top_box_z-th+eps);
        }
        translate([dx,dy,top_box_z-th-wide_stoiki_h+eps]) {
	  cylinder($fn=6, r=wide_stoiki_r, h=wide_stoiki_h+th-2*eps);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y - screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
    translate([screen_start_x + screen_length_x - screen_hold_up_x - screen_hold_up_x_shift, screen_start_y + screen_length_y + screen_hold_y_shift, screen_hold_start_z]) {
	cube([screen_hold_up_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker na stoikah
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // speaker_hole
  for (dy = [shift_y + speaker_shift - speaker_hole_int - speaker_hole_w*3/2,
             shift_y + speaker_shift - speaker_hole_w/2,
             shift_y + speaker_shift + speaker_hole_int + speaker_hole_w/2]) {
    translate([shift_x + pcb_x - speaker_shift - speaker_hole_d, dy, top_box_z-th-eps]) {
      cube(size=[speaker_hole_d, speaker_hole_w, th + 2*eps]);
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=top_box_z+2*eps);
      }
      translate([dx, dy, top_box_z - top_bolt_h]) {
        cylinder($fn=6, r=top_bolt_r, h=top_bolt_h + eps);
      }
    }
  }

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

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

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


cone made way lower - it should be enough as bearings will keep it in tact any way

difference()
{
  cylinder(h=20, r1=120/2, r2=40/2); // main hull
  cylinder(h=20, r=(22+1)/2);        // center rod & bearings holding
}

difference()
{
  cylinder(h=40, r1=120/2, r2=40/2); // main hull
  cylinder(h=40, r=(22+1)/2);        // center rod & bearings holding
}


[3d] Adjust interior fillet to round, make Pi ethernet hole tighter, USB pillar wider

-- USB pillar width 2.0mm -> 2.2mm
-- Interior fillet from 1mm chamfer to body_corner_radius/2 round
-- Don't cut out pic_ex and then rebuild it, just cut less (makes Pi ethernet jack area smaller)

// preview[view:northeast, tilt:topdiagonal]

/* [Options] */
// Pit probe type
Control_Probe = "Thermocouple"; // [Thermocouple,Thermistor,None]
// Raspberry Pi Model
Pi_Model = "3B/2B/1B+"; // [3B/2B/1B+,Connectorless,1A+,Zero,3A+]
// Which case halves
Pieces = "Both"; // [Both,Top,Bottom]
// Include cutouts and mounts for LCD/Buttons
LCD = 1; // [0:None,1:2-line]
// Thickness of side walls (mm) - Set to trace width multiple
wall = 2.5;
/* [Advanced] */
// Thickness of top and bottom faces (mm)
wall_t = 2;
// Height of the body edge bead chamfer (mm)
body_chamfer_height = 1.5;
// Corner ear height (mm) - 0 to disable
MouseEarHeight = 0;

/* [Hidden] */
// External corner radius on the body (mm)
body_corner_radius = wall*2-1/2;
d_off = 1.0; // offset the heatermeter origin from the front edge
w = inch(3.725)+1.2; // overall interior case width
d = inch(3.75)+1.0+d_off; // overall interior case depth
// 19.1+ headless Zero
// 22.4 headless Pi3 (limited by nuttrapps interfering with PCB to -6.7)
// 32 standard
h_b = [32.5-6.7, 32.5][LCD];  // overall interior case height

probe_centerline = 9.3; // case is split along probe centerline on the probe side
case_split = 12.4;  // and the case split on the other 3 sides

pic_ex = 1.7;
lcd_mount_t = 8.2 - (wall_t - 0.8);
pi_screw_t = 2.3;

body_chamfer_height_t = body_chamfer_height;
body_chamfer_height_b = body_chamfer_height;

e = 0.01;
is_jig = 0; // generate a jig for soldering LEDs

function inch(x) = x*25.4;

main();

module main()
{
  if (is_jig) {
    intersection() {
      hm43_split();
      translate([wall+6,-d-wall+3,-e]) cube([w-12,d-8,15]);
    }

    difference() {
      cube([w-12,d-8,8 - wall_t]);
      translate([wall,wall,-e]) cube([w-12-2*wall, d-8-2*wall, 8 - wall_t +2*e]);
    }
  } /* is_jig */
  else
    hm43_split();
}

module cube_fillet_chamfer(size,f,c,$fn=32) {
  hull() {
    translate([f,f,c]) linear_extrude(height=size[2]-2*c) minkowski() {
      square([size[0]-2*f, size[1]-2*f]);
      circle(r=f, $fn=$fn);
    }
    translate([f+c,f+c,0]) linear_extrude(height=size[2]) minkowski() {
      square([size[0]-2*(f+c), size[1]-2*(f+c)]);
      circle(r=f, $fn=$fn);
    }
  }
}

module jhole(d, h) {
  translate([0,0,h/2]) cube([2*(wall+pic_ex),d,h], center=true);
}

module phole() {
  dia=4.5;
  // Hole for thermistor probe jack
  rotate([0,90,0]) cylinder(2*wall, d=dia, $fn=16);
  // because 3d print tends to curl up slightly between the probe holes,
  // do not go right to the edge on the final layer (stop 0.25mm short on each side)
  translate([0,-(dia+0.5)/2, -0.3]) cube([2*wall, dia+0.5, 0.6]);
}

module screwhole() {
  translate([0,0,-e]) cylinder(3.5, d=6, $fn=18);
  translate([0,0,3+0.4]) cylinder(h_b-3.5-0.4+wall_t, d=3.4, $fn=18);
  translate([0.0,0,h_b+wall_t-lcd_mount_t/2-e])
    cylinder(lcd_mount_t/2+e, d=(2.9*2)/sin(60), $fn=6);
}

module pic_ex_cube(interior) {
  translate([0,33.75+interior*(pic_ex+1.3),2])
    cube_fillet([pic_ex+e, 59.8-interior*(pic_ex*2+1.3+2.0), 20.8],
      vertical=[0, (1-interior)*pic_ex, (1-interior)*pic_ex, 0],
      top=[0,pic_ex,0,0],
      bottom=[0,pic_ex,0,0]);
}

module screw_pimount() {
  cylinder(wall_t+pi_screw_t, d=6.4, $fn=18);
  // alignment nubbies
  cylinder(wall_t+pi_screw_t+1.4, d=2.4, $fn=12);
}

module screw_keyhole() {
  d=6.2;
  d2=3.5;
  off=4.15; // ideally would be D but runs into edge of case
  h=3;

  cylinder(wall_t+2*e, d=d, $fn=18);
  translate([-d2/2,0,0]) cube([d2,off,wall_t+2*e]);
  translate([0,off,0]) {
    cylinder(wall_t+2*e, d=d2, $fn=18);
    translate([0,0,wall_t+e]) cylinder(h+e, d=d, $fn=18);
  }
}

module screw_keyhole_p() {
  d=6.2+wall;
  h=2.3;

  difference() {
    cylinder(wall_t+h, d=d, $fn=18);
    translate([0,0,-e]) cylinder(wall_t+h+2*e, d=d-wall, $fn=18);
    translate([-d,0,-e]) cube([d*2, d/2, wall_t+h+2*e]);
  }
}

module btn_rnd() {
  dia = is_jig ? 6.0 : 7.2;
  cylinder(wall_t+2*e, d1=dia, d2=dia+1.5*wall_t, $fn=24);
  translate([-6.5,-6.5,0]) cube([13,13,0.5+e]);
}

module tc_plusminus() {
  T=0.75+e;
  H=2;
  W=6;
  // Minus
  translate([0,2,0])
    cube_fillet([T, W, H], top=[0,0,0,T]);
  translate([0,-(2+W),0]) {
    cube_fillet([T, W, H], top=[0,0,0,T]);
    translate([0,(W-H)/2,(H-W)/2])
      cube_fillet([T, H, W], top=[0,0,0,T]);
  }
}

module led_hole() {
  dia = is_jig ? 3.2 : 3.4;
  cylinder(wall_t+2*e, d1=dia, d2=dia, $fn=16);
}

module nuttrap() {
  ww_w=3;
  ww_d=wall;
  nut_h=3.2;
  nut_ingress = 5.7;
  nut_d = nut_ingress / sin(60);
  nut_ingress_off = nut_ingress/sqrt(3)/2;
  oa_h=wall_t+0.4+nut_h+wall_t+[0,6.7][LCD];

  // bottom half for M3 socket cap screw (flush)
  difference() {
    translate([-5.5/2-ww_w, -nut_ingress/2-d_off-e, 0])
      cube_fillet([5.5+2*ww_w, nut_ingress+d_off+ww_d, 6], vertical=[3.4,3.4], $fn=20);
    // socket cap
    translate([0,0,-e]) cylinder(3.5, d=6, $fn=18);
    // screw shaft
    translate([0,0,3.5+0.3]) cylinder(oa_h-3, d=3.4, $fn=18);
  }

  // top half M3 nut trap
  translate([0,0,h_b+wall_t-oa_h])
  difference() {
    translate([-(nut_d/2+ww_w), -nut_ingress/2-d_off, 0])
      cube_fillet([nut_d+2*ww_w, nut_ingress+d_off+ww_d, oa_h+e],
        vertical=[ww_d/2,3.4], $fn=20);
    // M3 screw
    translate([0,0,-e]) cylinder(wall_t, d1=4, d2=3.4, $fn=16);
    // nut hole / M3 extra
    translate([0,0,wall_t+0.3]) {
      // nut 2x for an elongated trap
      translate([-0.2,0,0]) cylinder(nut_h*1.5+e, d=nut_d, $fn=6);
      translate([+0.2,0,0]) cylinder(nut_h*1.5+e, d=nut_d, $fn=6);
      cylinder(oa_h-wall_t-0.3, d=4, $fn=16);  // M3 with plenty of clearance
      //translate([-50,-50,-100]) cube([100,100,100+e]); // cutaway top
    }
    // nut ingress (sideways trapezoid with wider side at ingress)
    translate([nut_ingress_off,-nut_ingress/2,wall_t+0.3])
       linear_extrude(nut_h+e) polygon([[0,0],
         [nut_d/2+ww_w-nut_ingress_off+0.4+e, -0.8],
         [nut_d/2+ww_w-nut_ingress_off+0.4+e, nut_ingress+0.8],
         [0,nut_ingress]]);
  }
}

module locklip_p(l, l_offset=0,
  lip_insert_depth=2.0, // how deep V to insert
  lip_v_off=0.2, // extra height before starting insert
  lip_h_off=0.4, // back connector away from mating area
  lip_w=2.5,  // thickness of attachment beam
  insert_inset=[0,0] // inset the insert inside mating area
  ) {
  translate([l_offset,0,0]) rotate([90,0,0]) rotate([0,90,0])
    difference() {
      linear_extrude(height=l-2*l_offset) polygon(points=[
        [0.1, -lip_w-lip_insert_depth-lip_h_off],  // 0.1 to add depth to keep extrusion manifold
        [0.1, 0],
        [-lip_insert_depth-lip_h_off, 0],
        [-lip_insert_depth-lip_h_off, lip_v_off],
        [-lip_h_off, lip_v_off+lip_insert_depth],
        [-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth,],
        [-lip_w-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth],
        [-lip_w-lip_insert_depth-lip_h_off, 0]
      ]);
      translate([-lip_w-lip_insert_depth-lip_h_off-e, 0, 0]) {
        if (insert_inset[0] > 0)
          translate([0,0,-e])
            cube([lip_w+lip_insert_depth+lip_h_off+2*e,
              lip_v_off+2*lip_insert_depth+e, insert_inset[0]+e]);
        if (insert_inset[1] > 0)
          translate([0, 0, l-2*l_offset-insert_inset[1]])
            cube([lip_w+lip_insert_depth+lip_h_off+2*e,
              lip_v_off+2*lip_insert_depth+e, insert_inset[1]+e]);
      }
    }
}

module locklip_n(l, l_offset=0,
  lip_insert_depth=2.2, // how deep V to insert
  lip_tip_clip=0.3, // how much to shave off the top tip
  ) {
  translate([l-l_offset,0,0]) rotate([90,0,0]) rotate([0,-90,0])
    linear_extrude(height=l-2*l_offset) polygon(points=[
      [0.1, -3*lip_insert_depth],  // 0.1 to add depth to keep extrusion manifold
      [0.1, -lip_tip_clip],
      [-lip_insert_depth+lip_tip_clip, -lip_tip_clip],
      [-e, -lip_insert_depth],
      [-lip_insert_depth, -2*lip_insert_depth]
    ]);
}

module lcd_screw() {
  rotate([180]) difference() {
    //cylinder(lcd_mount_t, d=2.5+3.2, $fn=16);
    cylinder(lcd_mount_t+e, d=2.5, $fn=16);
  }
}

module lcd_mount() {
  // Assuming starting at bottom left screw hole
  //lcd_screw();
  //translate([75,0,0]) lcd_screw(); // bottom right hole obscured by PCB
  translate([0,31,0]) lcd_screw();
  translate([75,31,0]) lcd_screw();
}

module lcd_neg() {
  // Assuming starting at bottom left screw hole
  // (Note LCD is not centered vertically on PCB, top is 5.15, bottom is 4.55mm)
  translate([1.0, 1.55, 0])
    cube([73.0, 27.3, lcd_mount_t+wall_t-0.8]); // black bezel inset
  translate([5.5, 7.5, 0])
    cube([64.0, 15.4, lcd_mount_t+wall_t+2*e]); // LCD active area
  //translate([4.23, -2.5, 0])
  //  cube([16*2.54, 5, lcd_mount_t+wall_t-0.8]); // pins cutout
}

module locklip_top_n(split) {
  translate([wall, d+wall, split+wall_t+e])
    rotate([180]) {
      locklip_n(28);
      translate([w-34,0,0]) locklip_n(34);
    }
}

module hm_base() {
  cube_bchamfer([w+2*wall, d+2*wall, h_b+2*wall_t],
    r=body_corner_radius, top=body_chamfer_height_t,
    bottom=body_chamfer_height_b, $fn=36);
  // extra thick by Pi connectors
  if (Pi_Model != "Zero" && Pi_Model != "1A+" && Pi_Model != "3A+")
    translate([-pic_ex,wall+d_off,wall_t])
      pic_ex_cube(0);
  // TC +/-
  if (Control_Probe == "Thermocouple")
    translate([w+wall*2-e,wall+d_off+10,wall_t+19]) tc_plusminus();
}

module hm43() {
difference() {
  hm_base();

  // Main cutout
  translate([wall, wall, wall_t])
    cube_fillet([w, d, h_b],
      bottom=[pi_screw_t,pi_screw_t,pi_screw_t,pi_screw_t],
      top=[pi_screw_t,pi_screw_t,pi_screw_t,pi_screw_t],
      vertical=[body_corner_radius/2,body_corner_radius/2,body_corner_radius/2,body_corner_radius/2],
      $fn=[36,4,4]);
  if (Pi_Model != "Zero" && Pi_Model != "1A+" && Pi_Model != "3A+")
    translate([wall-pic_ex+e,wall+d_off,wall_t]) pic_ex_cube(1);

  // Probe jack side
  translate([w+wall*0.5, wall+d_off, wall_t+probe_centerline]) {
    // Probe jacks
    if (Control_Probe == "Thermocouple")
      // TC jack
      translate([0,inch(0.4)-16.5/2,-1.1]) cube([2*wall, 16.5, 6.5]);
    else if (Control_Probe == "Thermistor")
      translate([0,inch(0.28),0]) phole();
    if (Control_Probe != "None") {
      translate([0,inch(0.95)+inch(0.37)*0,0]) phole();
      translate([0,inch(0.95)+inch(0.37)*1,0]) phole();
      translate([0,inch(0.95)+inch(0.37)*2,0]) phole();
    }
  }
  // Pi connector side
  translate([0,wall+d_off,wall_t]) {
    // Pi connectors
    translate([0,0,5]) {
      if (Pi_Model == "3B/2B/1B+") {
        // ethernet
        translate([0,81.5,-0.8]) jhole(15,13);
        translate([0,81.5,-1.8]) jhole(5,5);
        // USB 0+1
        translate([0,62.75,0]) jhole(13,14.8);
        translate([0,44.75,0]) jhole(13,14.8);
      }
    }
    // HeaterMeter connectors
    translate([0,0,0]) {
      // Blower/Servo output
      translate([0,25,1.7]) jhole(16.4,13);
      // HM power jack
      translate([0,inch(0.2),4.2]) jhole(9.4,11);
    }
  }

  // lcd hole
  if (LCD)
    translate([wall+10.7, wall+d_off+inch(2), h_b+wall_t-lcd_mount_t-e]) lcd_neg();

  // button holes
  if (LCD) translate([wall+48.7, wall+d_off+inch(1.15), h_b+wall_t-e]) {
    translate([-inch(1.1)/2,0,0]) btn_rnd();  // left
    translate([inch(1.1)/2,0,0]) btn_rnd();   // right
    translate([0,inch(0.9)/2,0]) btn_rnd();   // up
    translate([0,-inch(0.9)/2,0]) btn_rnd();  // down
    // LED holes
    translate([inch(1.3), inch(-0.05), 0]) {
      led_hole();  //red
      translate([0, inch(0.35), 0]) led_hole(); //yellow
      translate([0, inch(0.70), 0]) led_hole(); //green
    }
  }
  // close screw holes
  translate([wall+inch(0.825)+0.5,wall+d_off+inch(0.1),0]) {
    screwhole();
    translate([inch(2.0),0,0]) screwhole();
  }
  // keyholes
  //translate([wall+24,wall+d_off+39,-e]) {
  //    translate([0,49,0]) screw_keyhole();
  //    translate([58,49,0]) screw_keyhole();
  //}
}  // END OF DIFFERENCE

  // Pi mounting screws
  translate([wall+24,wall+d_off+39,0]) {
    translate([0,0,0]) screw_pimount();
    translate([58,0,0]) screw_pimount();
    if (Pi_Model == "Zero") {
      translate([0,23,0]) screw_pimount();
      translate([58,23,0]) screw_pimount();
    }
    else {
      translate([0,49,0]) screw_pimount();
      translate([58,49,0]) screw_pimount();
      //translate([0,49,0]) screw_keyhole_p();
      //translate([58,49,0]) screw_keyhole_p();
    }
  }

  if (Pi_Model != "Zero") {
    // Pi right edge stop
    translate([wall+w-9.5, wall+d_off+35, wall_t])
      difference() {
        cube_fillet([9.5,d-d_off-35,4], vertical=[0,0,10/2], $fn=24);
        // Pi B+ microsd gap
        translate([-e,22,-e]) cube_fillet([5.5,14.5,4+2*e], vertical=[2,0,0,2], $fn=20);
      }
  } // if !Zero

  // close nut traps
  if (!is_jig) translate([wall+inch(0.825)+0.5,wall+d_off+inch(0.1),0]) {
      nuttrap();
      translate([inch(2.0),0,0]) nuttrap();
    }

  // Top locklip (negative)
  if (Pi_Model == "3B/2B/1B+")
    locklip_top_n(case_split);
  else
    locklip_top_n(probe_centerline);

  // LCD mount
  if (LCD) difference() {
    union() {
      // Filled block above LCD hole
      translate([wall, wall+d_off+78, h_b+wall_t-lcd_mount_t])
        cube([w,d-d_off-78,lcd_mount_t+e],
          bottom=[lcd_mount_t/2,lcd_mount_t/2,0,lcd_mount_t/2]);
      // LCD grab notch
      translate([wall+10.7, wall+d_off+inch(2), h_b+wall_t-lcd_mount_t])
        translate([(77.5-20)/2,34.0-wall_t,-(1.8+wall_t)])
          // 1.8=thickness of LCD pcb
          cube_fillet([20,1.8+wall_t+wall,1.8+wall_t+e], top=[0,0,1.8+wall_t+e],
            vertical=[wall/2,wall/2]);
    }
    translate([wall+10.7, wall+d_off+inch(2), h_b+wall_t-e]) {
      translate([0, 0, -lcd_mount_t]) lcd_neg();
      // vv Keep screw holes where they have been since the beginning
      translate([0, 0.5, 0]) lcd_mount();
    }
  }

  if (Pi_Model == "3B/2B/1B+")
    translate([-pic_ex, wall+d_off, wall_t+2]) {
      // USB pillar reinforcements
      translate([0, (44.75+62.75)/2-2.2/2, 1.5])
        cube_fillet([pic_ex+wall, 2.2, 20.8-1.5], bottom=[0,pic_ex,0,2], top=[0,pic_ex]);
      translate([0, 81.5-15/2-3, 1.5])
        cube_fillet([pic_ex+wall, 2.5, 20.8-1.5], bottom=[0,pic_ex,0,2], top=[0,pic_ex]);
    }
}

module lip_guide(l) {
  guide_offset = 0.2; // how much to recess the edge guides
  guide_h = 1.2; // how tall above the edge to extend
  linear_extrude(height=l) polygon([
    [0,-e], [wall+guide_offset,-e], [0, wall+guide_offset],
    [-guide_h, wall+guide_offset], [-guide_h, guide_offset],
    [0, guide_offset]
  ]);
}

module hm43_bottom_lips(split) {
  translate([wall, wall, split+wall_t]) {
    // bottom locklip (positive)
    translate([0,d,0]) {
      locklip_p(28, insert_inset=[2,0]);
      translate([w-34,0,0]) locklip_p(34-wall, insert_inset=[0,1]);
    }

    // front guide lip
    translate([w/2-9, 0, 0])
      rotate([0,90]) lip_guide(25);
    // left guide lip assortment
    translate([0, d_off+5.25+9.4/2, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(25.25-5.25-9.4/2-16.7/2);
    *translate([-pic_ex, d_off+52, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
    *translate([-pic_ex, d_off+70, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
  }
  // probe side guide lip
  translate([wall+w, wall+d-45, probe_centerline+wall_t])
    rotate([-90]) rotate(90) lip_guide(40);
}

module mouseears() {
  me_h = MouseEarHeight;
  me_d = 20;
  me_overlap = wall;
  me_outset_bottom = (me_d/2 - body_corner_radius/4 - body_chamfer_height_b - me_overlap) * 0.707;
  me_outset_top = (me_d/2 - body_corner_radius/4 - body_chamfer_height_t - me_overlap) * 0.707;

  // Bottom outside corners
  if (Pieces != "Top") {
    translate([-me_outset_bottom, d+2*wall+me_outset_bottom, 0])
      cylinder(me_h, d=me_d, $fn=24);
    translate([w+2*wall+me_outset_bottom, d+2*wall+me_outset_bottom, 0])
      cylinder(me_h, d=me_d, $fn=24);
  }

  // top outside corners
  if (Pieces != "Bottom") {
    translate([0,-1,me_h]) rotate([180]) {
      translate([w+2*wall+me_outset_top, d+2*wall+me_outset_top, 0])
        cylinder(me_h, d=me_d, $fn=24);
      translate([-me_outset_top, d+2*wall+me_outset_top, 0])
        cylinder(me_h, d=me_d, $fn=24);
    }
  }

  // common corner area
  translate([-me_outset_bottom/0.707, 0, 0])
    cylinder(me_h, d=me_d, $fn=24);
  translate([w+2*wall+me_outset_bottom/0.707, 0, 0])
    cylinder(me_h, d=me_d, $fn=24);
}

module split_volume() {
  if (Pi_Model == "3B/2B/1B+") {
    difference() {
      translate([-pic_ex-e,-e,-e])
        cube([w+pic_ex+2*wall+2*e, d+2*wall+2*e, wall_t+case_split+2*e]);
      translate([w,0,wall_t+probe_centerline])
        cube([3*wall, d+2*wall+2*e, wall_t+probe_centerline+2*e]);
    }
  }
  else
    translate([-w,-d,-e])
      cube([3*w, 3*d, wall_t+probe_centerline+2*e]);
}

module hm43_split() {
  // bottom
  if (Pieces != "Top") translate([0,1,0]) {
    intersection() {
      hm43();
      split_volume();
    }
    if (Pi_Model == "3B/2B/1B+")
      hm43_bottom_lips(case_split);
    else
      hm43_bottom_lips(probe_centerline);
  } // if include bottom

  // top
  if (Pieces != "Bottom") {
    translate([0,-1,h_b+2*wall_t]) rotate([180]) {
      difference() {
        hm43();
        //translate([11,5,h_b+2*wall_t-0.24]) linear_extrude(0.5)
        //  text("HeaterMeter", font = "Liberation Sans:style=Bold Italic");
        split_volume();
      }
    }
  }  // if include top
  if (MouseEarHeight > 0.0)
    color("silver") mouseears();
}

/**********************                               **********************/
/********************** END OF CASE / LIBRARY FOLLOWS **********************/
/**********************                               **********************/

module cube_bchamfer(dim, r, top=0, bottom=0, $fn=$fn) {
  // bottom beaded area
  if (bottom != 0) hull(){
    translate([r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(bottom, r1=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]) hull(){
    translate([r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
  }
}

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

// preview[view:northeast, tilt:topdiagonal]

/* [Options] */
// Pit probe type
Control_Probe = "Thermocouple"; // [Thermocouple,Thermistor,None]
// Raspberry Pi Model
Pi_Model = "3B/2B/1B+"; // [3B/2B/1B+,Connectorless,1A+,Zero,3A+]
// Which case halves
Pieces = "Both"; // [Both,Top,Bottom]
// Include cutouts and mounts for LCD/Buttons
LCD = 1; // [0:None,1:2-line]
// Thickness of side walls (mm) - Set to trace width multiple
wall = 2.5;
/* [Advanced] */
// Thickness of top and bottom faces (mm)
wall_t = 2;
// Height of the body edge bead chamfer (mm)
body_chamfer_height = 1.5;
// Corner ear height (mm) - 0 to disable
MouseEarHeight = 0;

/* [Hidden] */
// External corner radius on the body (mm)
body_corner_radius = wall*2-1/2;
d_off = 1.0; // offset the heatermeter origin from the front edge
w = inch(3.725)+1.2; // overall interior case width
d = inch(3.75)+1.0+d_off; // overall interior case depth
// 19.1+ headless Zero
// 22.4 headless Pi3 (limited by nuttrapps interfering with PCB to -6.7)
// 32 standard
h_b = [32.5-6.7, 32.5][LCD];  // overall interior case height

probe_centerline = 9.3; // case is split along probe centerline on the probe side
case_split = 12.4;  // and the case split on the other 3 sides

pic_ex = 1.7;
lcd_mount_t = 8.2 - (wall_t - 0.8);
pi_screw_t = 2.3;

body_chamfer_height_t = body_chamfer_height;
body_chamfer_height_b = body_chamfer_height;

e = 0.01;
is_jig = 0; // generate a jig for soldering LEDs

function inch(x) = x*25.4;

main();

module main()
{
  if (is_jig) {
    intersection() {
      hm43_split();
      translate([wall+6,-d-wall+3,-e]) cube([w-12,d-8,15]);
    }

    difference() {
      cube([w-12,d-8,8 - wall_t]);
      translate([wall,wall,-e]) cube([w-12-2*wall, d-8-2*wall, 8 - wall_t +2*e]);
    }
  } /* is_jig */
  else
    hm43_split();
}

module cube_fillet_chamfer(size,f,c,$fn=32) {
  hull() {
    translate([f,f,c]) linear_extrude(height=size[2]-2*c) minkowski() {
      square([size[0]-2*f, size[1]-2*f]);
      circle(r=f, $fn=$fn);
    }
    translate([f+c,f+c,0]) linear_extrude(height=size[2]) minkowski() {
      square([size[0]-2*(f+c), size[1]-2*(f+c)]);
      circle(r=f, $fn=$fn);
    }
  }
}

module jhole(d, h) {
  translate([0,0,h/2]) cube([2*(wall+pic_ex),d,h], center=true);
}

module phole() {
  dia=4.5;
  // Hole for thermistor probe jack
  rotate([0,90,0]) cylinder(2*wall, d=dia, $fn=16);
  // because 3d print tends to curl up slightly between the probe holes,
  // do not go right to the edge on the final layer (stop 0.25mm short on each side)
  translate([0,-(dia+0.5)/2, -0.3]) cube([2*wall, dia+0.5, 0.6]);
}

module screwhole() {
  translate([0,0,-e]) cylinder(3.5, d=6, $fn=18);
  translate([0,0,3+0.4]) cylinder(h_b-3.5-0.4+wall_t, d=3.4, $fn=18);
  translate([0.0,0,h_b+wall_t-lcd_mount_t/2-e])
    cylinder(lcd_mount_t/2+e, d=(2.9*2)/sin(60), $fn=6);
}

module pic_ex_cube() {
  translate([0,33.75,2])
    cube_fillet([pic_ex+e, 59.5, 20.8],
      vertical=[0, pic_ex, pic_ex, 0],
      top=[0,pic_ex,0,0],
      bottom=[0,pic_ex,0,0]);
}

module screw_pimount() {
  cylinder(wall_t+pi_screw_t, d=6.4, $fn=18);
  // alignment nubbies
  cylinder(wall_t+pi_screw_t+1.4, d=2.4, $fn=12);
}

module screw_keyhole() {
  d=6.2;
  d2=3.5;
  off=4.15; // ideally would be D but runs into edge of case
  h=3;

  cylinder(wall_t+2*e, d=d, $fn=18);
  translate([-d2/2,0,0]) cube([d2,off,wall_t+2*e]);
  translate([0,off,0]) {
    cylinder(wall_t+2*e, d=d2, $fn=18);
    translate([0,0,wall_t+e]) cylinder(h+e, d=d, $fn=18);
  }
}

module screw_keyhole_p() {
  d=6.2+wall;
  h=2.3;

  difference() {
    cylinder(wall_t+h, d=d, $fn=18);
    translate([0,0,-e]) cylinder(wall_t+h+2*e, d=d-wall, $fn=18);
    translate([-d,0,-e]) cube([d*2, d/2, wall_t+h+2*e]);
  }
}

module btn_rnd() {
  dia = is_jig ? 6.0 : 7.2;
  cylinder(wall_t+2*e, d1=dia, d2=dia+1.5*wall_t, $fn=24);
  translate([-6.5,-6.5,0]) cube([13,13,0.5+e]);
}

module tc_plusminus() {
  T=0.75+e;
  H=2;
  W=6;
  // Minus
  translate([0,2,0])
    cube_fillet([T, W, H], top=[0,0,0,T]);
  translate([0,-(2+W),0]) {
    cube_fillet([T, W, H], top=[0,0,0,T]);
    translate([0,(W-H)/2,(H-W)/2])
      cube_fillet([T, H, W], top=[0,0,0,T]);
  }
}

module led_hole() {
  dia = is_jig ? 3.2 : 3.4;
  cylinder(wall_t+2*e, d1=dia, d2=dia, $fn=16);
}

module nuttrap() {
  ww_w=3;
  ww_d=wall;
  nut_h=3.2;
  nut_ingress = 5.7;
  nut_d = nut_ingress / sin(60);
  nut_ingress_off = nut_ingress/sqrt(3)/2;
  oa_h=wall_t+0.4+nut_h+wall_t+[0,6.7][LCD];

  // bottom half for M3 socket cap screw (flush)
  difference() {
    translate([-5.5/2-ww_w, -nut_ingress/2-d_off-e, 0])
      cube_fillet([5.5+2*ww_w, nut_ingress+d_off+ww_d, 6], vertical=[3.4,3.4], $fn=20);
    // socket cap
    translate([0,0,-e]) cylinder(3.5, d=6, $fn=18);
    // screw shaft
    translate([0,0,3.5+0.3]) cylinder(oa_h-3, d=3.4, $fn=18);
  }

  // top half M3 nut trap
  translate([0,0,h_b+wall_t-oa_h])
  difference() {
    translate([-(nut_d/2+ww_w), -nut_ingress/2-d_off, 0])
      cube_fillet([nut_d+2*ww_w, nut_ingress+d_off+ww_d, oa_h+e],
        vertical=[ww_d/2,3.4], $fn=20);
    // M3 screw
    translate([0,0,-e]) cylinder(wall_t, d1=4, d2=3.4, $fn=16);
    // nut hole / M3 extra
    translate([0,0,wall_t+0.3]) {
      // nut 2x for an elongated trap
      translate([-0.2,0,0]) cylinder(nut_h*1.5+e, d=nut_d, $fn=6);
      translate([+0.2,0,0]) cylinder(nut_h*1.5+e, d=nut_d, $fn=6);
      cylinder(oa_h-wall_t-0.3, d=4, $fn=16);  // M3 with plenty of clearance
      //translate([-50,-50,-100]) cube([100,100,100+e]); // cutaway top
    }
    // nut ingress (sideways trapezoid with wider side at ingress)
    translate([nut_ingress_off,-nut_ingress/2,wall_t+0.3])
       linear_extrude(nut_h+e) polygon([[0,0],
         [nut_d/2+ww_w-nut_ingress_off+0.4+e, -0.8],
         [nut_d/2+ww_w-nut_ingress_off+0.4+e, nut_ingress+0.8],
         [0,nut_ingress]]);
  }
}

module locklip_p(l, l_offset=0,
  lip_insert_depth=2.0, // how deep V to insert
  lip_v_off=0.2, // extra height before starting insert
  lip_h_off=0.4, // back connector away from mating area
  lip_w=2.5,  // thickness of attachment beam
  insert_inset=[0,0] // inset the insert inside mating area
  ) {
  translate([l_offset,0,0]) rotate([90,0,0]) rotate([0,90,0])
    difference() {
      linear_extrude(height=l-2*l_offset) polygon(points=[
        [0.1, -lip_w-lip_insert_depth-lip_h_off],  // 0.1 to add depth to keep extrusion manifold
        [0.1, 0],
        [-lip_insert_depth-lip_h_off, 0],
        [-lip_insert_depth-lip_h_off, lip_v_off],
        [-lip_h_off, lip_v_off+lip_insert_depth],
        [-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth,],
        [-lip_w-lip_insert_depth-lip_h_off, lip_v_off+2*lip_insert_depth],
        [-lip_w-lip_insert_depth-lip_h_off, 0]
      ]);
      translate([-lip_w-lip_insert_depth-lip_h_off-e, 0, 0]) {
        if (insert_inset[0] > 0)
          translate([0,0,-e])
            cube([lip_w+lip_insert_depth+lip_h_off+2*e,
              lip_v_off+2*lip_insert_depth+e, insert_inset[0]+e]);
        if (insert_inset[1] > 0)
          translate([0, 0, l-2*l_offset-insert_inset[1]])
            cube([lip_w+lip_insert_depth+lip_h_off+2*e,
              lip_v_off+2*lip_insert_depth+e, insert_inset[1]+e]);
      }
    }
}

module locklip_n(l, l_offset=0,
  lip_insert_depth=2.2, // how deep V to insert
  lip_tip_clip=0.3, // how much to shave off the top tip
  ) {
  translate([l-l_offset,0,0]) rotate([90,0,0]) rotate([0,-90,0])
    linear_extrude(height=l-2*l_offset) polygon(points=[
      [0.1, -3*lip_insert_depth],  // 0.1 to add depth to keep extrusion manifold
      [0.1, -lip_tip_clip],
      [-lip_insert_depth+lip_tip_clip, -lip_tip_clip],
      [-e, -lip_insert_depth],
      [-lip_insert_depth, -2*lip_insert_depth]
    ]);
}

module lcd_screw() {
  rotate([180]) difference() {
    //cylinder(lcd_mount_t, d=2.5+3.2, $fn=16);
    cylinder(lcd_mount_t+e, d=2.5, $fn=16);
  }
}

module lcd_mount() {
  // Assuming starting at bottom left screw hole
  //lcd_screw();
  //translate([75,0,0]) lcd_screw(); // bottom right hole obscured by PCB
  translate([0,31,0]) lcd_screw();
  translate([75,31,0]) lcd_screw();
}

module lcd_neg() {
  // Assuming starting at bottom left screw hole
  // (Note LCD is not centered vertically on PCB, top is 5.15, bottom is 4.55mm)
  translate([1.0, 1.55, 0])
    cube([73.0, 27.3, lcd_mount_t+wall_t-0.8]); // black bezel inset
  translate([5.5, 7.5, 0])
    cube([64.0, 15.4, lcd_mount_t+wall_t+2*e]); // LCD active area
  //translate([4.23, -2.5, 0])
  //  cube([16*2.54, 5, lcd_mount_t+wall_t-0.8]); // pins cutout
}

module locklip_top_n(split) {
  translate([wall, d+wall, split+wall_t+e])
    rotate([180]) {
      locklip_n(28);
      translate([w-34,0,0]) locklip_n(34);
    }
}

module hm_base() {
  cube_bchamfer([w+2*wall, d+2*wall, h_b+2*wall_t],
    r=body_corner_radius, top=body_chamfer_height_t,
    bottom=body_chamfer_height_b, $fn=36);
  // extra thick by Pi connectors
  if (Pi_Model != "Zero" && Pi_Model != "1A+" && Pi_Model != "3A+")
    translate([-pic_ex,wall+d_off,wall_t])
      pic_ex_cube();
  // TC +/-
  if (Control_Probe == "Thermocouple")
    translate([w+wall*2-e,wall+d_off+10,wall_t+19]) tc_plusminus();
}

module hm43() {
difference() {
  hm_base();

  // Main cutout
  translate([wall, wall, wall_t])
    cube_fillet([w, d, h_b],
      bottom=[pi_screw_t,pi_screw_t,pi_screw_t,pi_screw_t],
      top=[pi_screw_t,pi_screw_t,pi_screw_t,pi_screw_t],
      vertical=[1,1,1,1]);
  if (Pi_Model != "Zero" && Pi_Model != "1A+" && Pi_Model != "3A+")
    translate([wall-pic_ex+e,wall+d_off,wall_t]) pic_ex_cube();

  // Probe jack side
  translate([w+wall*0.5, wall+d_off, wall_t+probe_centerline]) {
    // Probe jacks
    if (Control_Probe == "Thermocouple")
      // TC jack
      translate([0,inch(0.4)-16.5/2,-1.1]) cube([2*wall, 16.5, 6.5]);
    else if (Control_Probe == "Thermistor")
      translate([0,inch(0.28),0]) phole();
    if (Control_Probe != "None") {
      translate([0,inch(0.95)+inch(0.37)*0,0]) phole();
      translate([0,inch(0.95)+inch(0.37)*1,0]) phole();
      translate([0,inch(0.95)+inch(0.37)*2,0]) phole();
    }
  }
  // Pi connector side
  translate([0,wall+d_off,wall_t]) {
    // Pi connectors
    translate([0,0,5]) {
      if (Pi_Model == "3B/2B/1B+") {
        // ethernet
        translate([0,81.5,-0.8]) jhole(15,13);
        translate([0,81.5,-1.8]) jhole(5,5);
        // USB 0+1
        translate([0,62.75,0]) jhole(13,14.8);
        translate([0,44.75,0]) jhole(13,14.8);
      }
    }
    // HeaterMeter connectors
    translate([0,0,0]) {
      // Blower/Servo output
      translate([0,25,1.7]) jhole(16.4,13);
      // HM power jack
      translate([0,inch(0.2),4.2]) jhole(9.4,11);
    }
  }

  // lcd hole
  if (LCD)
    translate([wall+10.7, wall+d_off+inch(2), h_b+wall_t-lcd_mount_t-e]) lcd_neg();

  // button holes
  if (LCD) translate([wall+48.7, wall+d_off+inch(1.15), h_b+wall_t-e]) {
    translate([-inch(1.1)/2,0,0]) btn_rnd();  // left
    translate([inch(1.1)/2,0,0]) btn_rnd();   // right
    translate([0,inch(0.9)/2,0]) btn_rnd();   // up
    translate([0,-inch(0.9)/2,0]) btn_rnd();  // down
    // LED holes
    translate([inch(1.3), inch(-0.05), 0]) {
      led_hole();  //red
      translate([0, inch(0.35), 0]) led_hole(); //yellow
      translate([0, inch(0.70), 0]) led_hole(); //green
    }
  }
  // close screw holes
  translate([wall+inch(0.825)+0.5,wall+d_off+inch(0.1),0]) {
    screwhole();
    translate([inch(2.0),0,0]) screwhole();
  }
  // keyholes
  //translate([wall+24,wall+d_off+39,-e]) {
  //    translate([0,49,0]) screw_keyhole();
  //    translate([58,49,0]) screw_keyhole();
  //}
}  // END OF DIFFERENCE

  // Pi mounting screws
  translate([wall+24,wall+d_off+39,0]) {
    translate([0,0,0]) screw_pimount();
    translate([58,0,0]) screw_pimount();
    if (Pi_Model == "Zero") {
      translate([0,23,0]) screw_pimount();
      translate([58,23,0]) screw_pimount();
    }
    else {
      translate([0,49,0]) screw_pimount();
      translate([58,49,0]) screw_pimount();
      //translate([0,49,0]) screw_keyhole_p();
      //translate([58,49,0]) screw_keyhole_p();
    }
  }

  if (Pi_Model != "Zero") {
    // Pi right edge stop
    translate([wall+w-9.5, wall+d_off+35, wall_t])
      difference() {
        cube_fillet([9.5,d-d_off-35,4], vertical=[0,0,10/2], $fn=24);
        // Pi B+ microsd gap
        translate([-e,22,-e]) cube_fillet([5.5,14.5,4+2*e], vertical=[2,0,0,2], $fn=20);
      }
  } // if !Zero

  // close nut traps
  if (!is_jig) translate([wall+inch(0.825)+0.5,wall+d_off+inch(0.1),0]) {
      nuttrap();
      translate([inch(2.0),0,0]) nuttrap();
    }

  // Top locklip (negative)
  if (Pi_Model == "3B/2B/1B+")
    locklip_top_n(case_split);
  else
    locklip_top_n(probe_centerline);

  // LCD mount
  if (LCD) difference() {
    union() {
      // Filled block above LCD hole
      translate([wall, wall+d_off+78, h_b+wall_t-lcd_mount_t])
        cube([w,d-d_off-78,lcd_mount_t+e],
          bottom=[lcd_mount_t/2,lcd_mount_t/2,0,lcd_mount_t/2]);
      // LCD grab notch
      translate([wall+10.7, wall+d_off+inch(2), h_b+wall_t-lcd_mount_t])
        translate([(77.5-20)/2,34.0-wall_t,-(1.8+wall_t)])
          // 1.8=thickness of LCD pcb
          cube_fillet([20,1.8+wall_t+wall,1.8+wall_t+e], top=[0,0,1.8+wall_t+e],
            vertical=[wall/2,wall/2]);
    }
    translate([wall+10.7, wall+d_off+inch(2), h_b+wall_t-e]) {
      translate([0, 0, -lcd_mount_t]) lcd_neg();
      // vv Keep screw holes where they have been since the beginning
      translate([0, 0.5, 0]) lcd_mount();
    }
  }

  if (Pi_Model == "3B/2B/1B+")
    translate([-pic_ex, wall+d_off, wall_t+2]) {
      // USB pillar reinforcements
      translate([0, (44.75+62.75)/2-1, 1.5])
        cube_fillet([pic_ex+wall, 2, 20.8-1.5], bottom=[0,pic_ex,0,2], top=[0,pic_ex]);
      translate([0, 81.5-15/2-3, 1.5])
        cube_fillet([pic_ex+wall, 2.5, 20.8-1.5], bottom=[0,pic_ex,0,2], top=[0,pic_ex]);
      // Near pic_ex fill
      translate([0, 33.75, 0])
        cube_fillet([pic_ex+wall, 3, 20.8], bottom=[0,pic_ex,0,0], top=[0,pic_ex],
        vertical=[0,0,pic_ex]);
      // Far pic_ex fill (near ethernet)
      translate([wall, 33.75+59.5-pic_ex, 1.5])
       cube_fillet([pic_ex, pic_ex+e, 20.8-1.5], bottom=[0,0,0,2], vertical=[0,pic_ex]);
    }
}

module lip_guide(l) {
  guide_offset = 0.2; // how much to recess the edge guides
  guide_h = 1.2; // how tall above the edge to extend
  linear_extrude(height=l) polygon([
    [0,-e], [wall+guide_offset,-e], [0, wall+guide_offset],
    [-guide_h, wall+guide_offset], [-guide_h, guide_offset],
    [0, guide_offset]
  ]);
}

module hm43_bottom_lips(split) {
  translate([wall, wall, split+wall_t]) {
    // bottom locklip (positive)
    translate([0,d,0]) {
      locklip_p(28, insert_inset=[2,0]);
      translate([w-34,0,0]) locklip_p(34-wall, insert_inset=[0,1]);
    }

    // front guide lip
    translate([w/2-9, 0, 0])
      rotate([0,90]) lip_guide(25);
    // left guide lip assortment
    translate([0, d_off+5.25+9.4/2, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(25.25-5.25-9.4/2-16.7/2);
    *translate([-pic_ex, d_off+52, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
    *translate([-pic_ex, d_off+70, 0])
      rotate([-90]) rotate(90) mirror([0,1,0]) lip_guide(3.5);
  }
  // probe side guide lip
  translate([wall+w, wall+d-45, probe_centerline+wall_t])
    rotate([-90]) rotate(90) lip_guide(40);
}

module mouseears() {
  me_h = MouseEarHeight;
  me_d = 20;
  me_overlap = wall;
  me_outset_bottom = (me_d/2 - body_corner_radius/4 - body_chamfer_height_b - me_overlap) * 0.707;
  me_outset_top = (me_d/2 - body_corner_radius/4 - body_chamfer_height_t - me_overlap) * 0.707;

  // Bottom outside corners
  if (Pieces != "Top") {
    translate([-me_outset_bottom, d+2*wall+me_outset_bottom, 0])
      cylinder(me_h, d=me_d, $fn=24);
    translate([w+2*wall+me_outset_bottom, d+2*wall+me_outset_bottom, 0])
      cylinder(me_h, d=me_d, $fn=24);
  }

  // top outside corners
  if (Pieces != "Bottom") {
    translate([0,-1,me_h]) rotate([180]) {
      translate([w+2*wall+me_outset_top, d+2*wall+me_outset_top, 0])
        cylinder(me_h, d=me_d, $fn=24);
      translate([-me_outset_top, d+2*wall+me_outset_top, 0])
        cylinder(me_h, d=me_d, $fn=24);
    }
  }

  // common corner area
  translate([-me_outset_bottom/0.707, 0, 0])
    cylinder(me_h, d=me_d, $fn=24);
  translate([w+2*wall+me_outset_bottom/0.707, 0, 0])
    cylinder(me_h, d=me_d, $fn=24);
}

module split_volume() {
  if (Pi_Model == "3B/2B/1B+") {
    difference() {
      translate([-pic_ex-e,-e,-e])
        cube([w+pic_ex+2*wall+2*e, d+2*wall+2*e, wall_t+case_split+2*e]);
      translate([w,0,wall_t+probe_centerline])
        cube([3*wall, d+2*wall+2*e, wall_t+probe_centerline+2*e]);
    }
  }
  else
    translate([-w,-d,-e])
      cube([3*w, 3*d, wall_t+probe_centerline+2*e]);
}

module hm43_split() {
  // bottom
  if (Pieces != "Top") translate([0,1,0]) {
    intersection() {
      hm43();
      split_volume();
    }
    if (Pi_Model == "3B/2B/1B+")
      hm43_bottom_lips(case_split);
    else
      hm43_bottom_lips(probe_centerline);
  } // if include bottom

  // top
  if (Pieces != "Bottom") {
    translate([0,-1,h_b+2*wall_t]) rotate([180]) difference() {
      hm43();
      //translate([11,5,h_b+2*wall_t-0.24]) linear_extrude(0.5)
      //  text("HeaterMeter", font = "Liberation Sans:style=Bold Italic");
      split_volume();
    }
  }  // if include top
  if (MouseEarHeight > 0.0)
    color("silver") mouseears();
}

/**********************                               **********************/
/********************** END OF CASE / LIBRARY FOLLOWS **********************/
/**********************                               **********************/

module cube_bchamfer(dim, r, top=0, bottom=0, $fn=$fn) {
  // bottom beaded area
  if (bottom != 0) hull(){
    translate([r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(bottom, r1=r-bottom, r2=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(bottom, r1=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]) hull(){
    translate([r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
    translate([dim[0]-r,dim[1]-r,0]) cylinder(top, r2=r-top, r1=r, $fn=$fn);
  }
}

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];

    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);
        } else {
            rotate([0, 0, 90*i]) translate([size[1-j[i]]/2, size[j[i]]/2, 0]) fillet(vertical[i], size[2], $fn);
        }
        rotate([90*i, -90, 0]) translate([size[2]/2, size[j[i]]/2, 0 ]) fillet(top[i], size[1-j[i]], $fn);
        rotate([90*(4-i), 90, 0]) translate([size[2]/2, size[j[i]]/2, 0]) fillet(bottom[i], size[1-j[i]], $fn);

    }
}

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


Adding hole_template

Adding hole_template

loose_fitting = 0;
timber_w = 47;
timber_h = 75;

timber_construct_w = timber_w+loose_fitting;
timber_construct_h = timber_h+loose_fitting;

hole_size = 5;
parameter = 2.5;
$fn=60;

difference()
{
    cube([timber_construct_w+1*parameter,timber_construct_h+1*parameter,+2*parameter]);
    translate([parameter,parameter,parameter]) cube([timber_construct_w+2*parameter,timber_construct_h+2*parameter,+2*parameter]);
    translate([parameter,parameter,-parameter])
    {
        translate([timber_construct_w*1/4,timber_construct_h*1/4,0]) cylinder(5*parameter, d=hole_size);
        translate([timber_construct_w*1/4,timber_construct_h*3/4,0]) cylinder(5*parameter, d=hole_size);
        translate([timber_construct_w*3/4,timber_construct_h*1/4,0]) cylinder(5*parameter, d=hole_size);
        translate([timber_construct_w*3/4,timber_construct_h*3/4,0]) cylinder(5*parameter, d=hole_size);
        translate([timber_construct_w*2/4,timber_construct_h*2/4,0]) cylinder(5*parameter, d=hole_size);
    }
    translate([timber_w/2+parameter*2,timber_h/2+parameter,parameter*3/4]) rotate([0,0,90]) linear_extrude(parameter) text(str(timber_w,"x",timber_h), size=timber_w/4, halign = "center");
}

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


/ ‘Impression 3D/2016 - Trocar/trocar-test1.scad’


resized

resized

use <projector_plate.scad>;
include <projector.scad>;
use <plate.scad>;
include <profile.scad>;
use <../scad/ob_wheel.scad>
use <../scad/ob_spacer.scad>
include <gantry_cart.scad>
use <../scad/brackets.scad>
use <../scad/geom.scad>
use <support_projector_beam.scad>
include <materials.scad>
use <basin_support.scad>
use <big_screw.scad>

module printer(projector_position = 0) {
  offset_depth = 50;

  middle_sections = 2;

  height = 500;
  width = 560;
  base_depth = 440;
  display_projection = false;
  base_sections = 3;

  projector_movement = height / 2 - acer_projector_distances[projector_position] + middle_sections * 20;

  // projector
  translate([0, 0, -offset_depth]) {
    translate([0, projector_movement, 0]) {
      center_projector() {
        Acer_Plate(160, 120, 85, 100);
        Acer_H6510BD(display_projection);
      }
    }
  }
  beam_offset = 10;
  beam_width = width - 2 * beam_offset;

  carriage_tower_sections = 3;

  translate([0, projector_movement, -offset_depth]) {
    translate([-beam_width/2,-20 * base_sections,-10])
      rotate([90,90,90])
        profile(base_sections, beam_width);
  /*
    translate([beam_width/2,-60,-10])
      rotate([90,0,90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
    translate([-beam_width/2,-60,-10])
      rotate([90,0,-90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
  */
  }

  // projector towers
  translate([0, 0, -offset_depth]) {
    translate([-width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
    translate([width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
  }

  // supports for horizontal beam
  translate([0, middle_sections * 20, -offset_depth])
  for(d = acer_projector_distances) {
    translate([0,d-height/2+10,0])
      support_projector_beam(width-60);
  }
  //height / 2 - d

  // base
  module base(width, depth, sections = 2) {
    translate([-width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    translate([width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    lateral_beam_width = width - 20;
    translate([-lateral_beam_width/2,0,-base_depth/2+10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);

    translate([-lateral_beam_width/2,0,base_depth/2-10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);
  }

  module baser(width, depth, sections = 2) {
    translate([(- width + sections * 20) / 2 - 10, -10, -base_depth/2])
      rotate([0,0,90])
        profile(sections, base_depth);

    translate([(  width - sections * 20) / 2 + 10, -10, -base_depth/2])
      rotate([0,0,90])
        profile(sections, base_depth);

    lateral_beam_width = width - 30 * sections;
    translate([-lateral_beam_width/2, -10, -base_depth/2+30])
      rotate([90,0,90])
        profile(sections, lateral_beam_width);
    translate([-lateral_beam_width/2, -10, base_depth/2-30])
      rotate([90,0,90])
        profile(sections, lateral_beam_width);
  }

  bottom_sections = 3;
  translate([0,-(height+bottom_sections*20)/2,0])
    base(width, base_depth, bottom_sections);

  translate([0,(height+middle_sections*20)/2,0])
    baser(width, base_depth, 3);

  // support towers
  tower_pos = base_depth / 2 - 10;
  translate([-width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);
  translate([width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);

  rotate([0,180,0]) {

    offset = 16;
    plate_width = width - 20 - offset * 2;
    plate_depth = base_depth - 60 * 2;
    cut_width = 440;
    cut_offset = 7.5;
    translate([
      -plate_width/2,
      height/2 + 20,
      -plate_depth / 2 + 20 - offset])
      basin_support(plate_width, plate_depth, cut_width, cut_offset);

    translate([0, height/2 + 20 * middle_sections, base_depth / 2 + 20])
      big_screw();

    // TODO review
    screw_height = 640;
    rail_sections = 2;
    rotate([-90, 0, 0]) {
      translate([65, -base_depth / 2 - 20, -height / 2 - 20 * (bottom_sections)]) {
        profile(rail_sections, screw_height + height + 20 * (bottom_sections + middle_sections));
      }
      translate([-65, -base_depth / 2 - 20, -height / 2 - 20 * (bottom_sections)]) {
        profile(rail_sections, screw_height + height + 20 * (bottom_sections + middle_sections));
      }
    }
    translate([0,0,30]) {
      translate([40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
        rotate([0, 180, 0])
          profile(4, width / 2 + rail_sections * 2 - 5);
      translate([-40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
        rotate([0, 180, 0])
          profile(4, width / 2 + rail_sections * 2 - 5);
      translate([-50, height / 2 + 20 * middle_sections + 300, base_depth / 2 -60])
        plate(100, 4, 80);
      translate([-50, height / 2 + 20 * middle_sections + 216, base_depth / 2 -60])
        plate(100, 4, 80);
      translate([0, height / 2 + 20 * middle_sections + 300, base_depth / 2 - width / 2 + 30])
        rotate([90,90,0])
          profile(3, 140);

      translate([65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();

      translate([-65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([-65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([-65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
    }
  }
}

use <projector_plate.scad>;
include <projector.scad>;
use <plate.scad>;
include <profile.scad>;
use <../scad/ob_wheel.scad>
use <../scad/ob_spacer.scad>
include <gantry_cart.scad>
use <../scad/brackets.scad>
use <../scad/geom.scad>
use <support_projector_beam.scad>
include <materials.scad>
use <basin_support.scad>
use <big_screw.scad>

module printer(projector_position = 0) {
  offset_depth = 50;

  middle_sections = 2;

  height = 500;
  width = 560;
  base_depth = 400;
  display_projection = false;
  base_sections = 3;

  projector_movement = height / 2 - acer_projector_distances[projector_position] + middle_sections * 20;

  // projector
  translate([0, 0, -offset_depth]) {
    translate([0, projector_movement, 0]) {
      center_projector() {
        Acer_Plate(160, 120, 85, 100);
        Acer_H6510BD(display_projection);
      }
    }
  }
  beam_offset = 10;
  beam_width = width - 2 * beam_offset;

  carriage_tower_sections = 3;

  translate([0, projector_movement, -offset_depth]) {
    translate([-beam_width/2,-20 * base_sections,-10])
      rotate([90,90,90])
        profile(base_sections, beam_width);
  /*
    translate([beam_width/2,-60,-10])
      rotate([90,0,90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
    translate([-beam_width/2,-60,-10])
      rotate([90,0,-90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
  */
  }

  // projector towers
  translate([0, 0, -offset_depth]) {
    translate([-width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
    translate([width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
  }

  // supports for horizontal beam
  translate([0, middle_sections * 20, -offset_depth])
  for(d = acer_projector_distances) {
    translate([0,d-height/2+10,0])
      support_projector_beam(width-60);
  }
  //height / 2 - d

  // base
  module base(width, depth, sections = 2) {
    translate([-width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    translate([width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    lateral_beam_width = width - 20;
    translate([-lateral_beam_width/2,0,-base_depth/2+10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);

    translate([-lateral_beam_width/2,0,base_depth/2-10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);
  }

  module baser(width, depth, sections = 2) {
    translate([(- width + sections * 20) / 2 - 10, -10, -base_depth/2])
      rotate([0,0,90])
        profile(sections, base_depth);

    translate([(  width - sections * 20) / 2 + 10, -10, -base_depth/2])
      rotate([0,0,90])
        profile(sections, base_depth);

    lateral_beam_width = width - 30 * sections;
    translate([-lateral_beam_width/2, -10, -base_depth/2+30])
      rotate([90,0,90])
        profile(sections, lateral_beam_width);
    translate([-lateral_beam_width/2, -10, base_depth/2-30])
      rotate([90,0,90])
        profile(sections, lateral_beam_width);
  }

  bottom_sections = 3;
  translate([0,-(height+bottom_sections*20)/2,0])
    base(width, base_depth, bottom_sections);

  translate([0,(height+middle_sections*20)/2,0])
    baser(width, base_depth, 3);

  // support towers
  tower_pos = base_depth / 2 - 10;
  translate([-width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);
  translate([width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);

  rotate([0,180,0]) {

    offset = 16;
    plate_width = width - 20 - offset * 2;
    plate_depth = base_depth - 60 * 2;
    cut_width = 440;
    cut_offset = 7.5;
    translate([
      -plate_width/2,
      height/2 + 20,
      -plate_depth / 2 + 20 - offset])
      basin_support(plate_width, plate_depth, cut_width, cut_offset);

    translate([0, height/2 + 20 * middle_sections, base_depth / 2 + 20])
      big_screw();

    // TODO review
    screw_height = 640;
    rail_sections = 2;
    rotate([-90, 0, 0]) {
      translate([65, -base_depth / 2 - 20, -height / 2 - 20 * (bottom_sections)]) {
        profile(rail_sections, screw_height + height + 20 * (bottom_sections + middle_sections));
      }
      translate([-65, -base_depth / 2 - 20, -height / 2 - 20 * (bottom_sections)]) {
        profile(rail_sections, screw_height + height + 20 * (bottom_sections + middle_sections));
      }
    }
    translate([0,0,30]) {
      translate([40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
        rotate([0, 180, 0])
          profile(4, 240);
      translate([-40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
        rotate([0, 180, 0])
          profile(4, 240);
      translate([-50, height / 2 + 20 * middle_sections + 300, base_depth / 2 -60])
        plate(100, 4, 80);
      translate([-50, height / 2 + 20 * middle_sections + 216, base_depth / 2 -60])
        plate(100, 4, 80);
      translate([0, height / 2 + 20 * middle_sections + 300, base_depth / 2 - 210])
        rotate([90,90,0])
          profile(3, 140);

      translate([65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();

      translate([-65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([-65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([-65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
    }
  }
}


bearing: add extra_h param

bearing: add extra_h param

use <transforms.scad>;
use <shapes.scad>
include <bearing_data.scad>
include <units.scad>

module bearing(bearing_type, extra_h=0, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    h = (override_h==undef ? bearing_type[2] : override_h) + extra_h;
    size_align(size=[bearing_type[1],bearing_type[1],h], align=align ,orient=orient)
    difference()
    {
        // outer
        cylindera(h=h, d=bearing_type[1], align=[0,0,0]);
        // inner
        cylindera(h=h+.1, d=bearing_type[0], align=[0,0,0]);
        // clips
        if(len(bearing_type) > 3)
        {
            clip_depth=.5;
            for(z=[-1,1])
            translate([0,0,z*bearing_type[3]/2])
            difference()
            {
                cylindera(h=1*mm, d=bearing_type[2]+1, align=[0,0,-z]);
                cylindera(h=1*mm+.1, d=bearing_type[4]-clip_depth, align=[0,0,-z]);
            }

        }
    }
}

module bearing_mount_holes(bearing_type, ziptie_type=[2*mm, 3*mm], ziptie_bearing_distance=3*mm, tolerance=1.01, orient=[1,0,0], ziptie_dist=undef, show_zips=false)
{
    ziptie_thickness = ziptie_type[0];
    ziptie_width = ziptie_type[1]+0.6*mm;

    ziptie_dist_ = (ziptie_dist==undef?bearing_type[3]/2:ziptie_dist);

    orient(orient)
    {
        // Main bearing cut
        cylindera(h=bearing_type[2]*tolerance, d=bearing_type[1]*tolerance, orient=[0,0,1]);

        for(z=[-1,1])
        translate([0,0,z*ziptie_dist_ - z*1/2])
        hollow_cylinder(
                d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                thickness = ziptie_thickness*2,
                h = ziptie_width,
                taper=true,
                orient=[0,0,1],
                align=[0,0,0]
                );

        // for linear rod
        cylindera(d=bearing_type[0]*1.3, h=100, orient=[0,0,1]);

        if(show_zips)
        {
            for(z=[-1,1])
            translate([0,0,z*ziptie_dist_])
            {
                %hollow_cylinder(
                        d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                        thickness = ziptie_thickness,
                        h = ziptie_width,
                        orient=[0,0,1],
                        align=[0,0,-z]
                        );
            }
        }
    }
}

if(false)
{
    b=bearing_igus_rj4jp_01_12;
    bearing_mount_holes(b, orient=[0,0,1]);
    translate([30,0,0])
    bearing(b, orient=[0,0,1]);
}

use <transforms.scad>;
use <shapes.scad>
include <bearing_data.scad>
include <units.scad>

module bearing(bearing_type, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    h = override_h==undef ? bearing_type[2] : override_h;
    size_align(size=[bearing_type[1],bearing_type[1],h], align=align ,orient=orient)
    difference()
    {
        // outer
        cylindera(h=h, d=bearing_type[1], align=[0,0,0]);
        // inner
        cylindera(h=h+.1, d=bearing_type[0], align=[0,0,0]);
        // clips
        if(len(bearing_type) > 3)
        {
            clip_depth=.5;
            for(z=[-1,1])
            translate([0,0,z*bearing_type[3]/2])
            difference()
            {
                cylindera(h=1*mm, d=bearing_type[2]+1, align=[0,0,-z]);
                cylindera(h=1*mm+.1, d=bearing_type[4]-clip_depth, align=[0,0,-z]);
            }

        }
    }
}

module bearing_mount_holes(bearing_type, ziptie_type=[2*mm, 3*mm], ziptie_bearing_distance=3*mm, tolerance=1.01, orient=[1,0,0], ziptie_dist=undef, show_zips=false)
{
    ziptie_thickness = ziptie_type[0];
    ziptie_width = ziptie_type[1]+0.6*mm;

    ziptie_dist_ = (ziptie_dist==undef?bearing_type[3]/2:ziptie_dist);

    orient(orient)
    {
        // Main bearing cut
        cylindera(h=bearing_type[2]*tolerance, d=bearing_type[1]*tolerance, orient=[0,0,1]);

        for(z=[-1,1])
        translate([0,0,z*ziptie_dist_ - z*1/2])
        hollow_cylinder(
                d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                thickness = ziptie_thickness*2,
                h = ziptie_width,
                taper=true,
                orient=[0,0,1],
                align=[0,0,0]
                );

        // for linear rod
        cylindera(d=bearing_type[0]*1.3, h=100, orient=[0,0,1]);

        if(show_zips)
        {
            for(z=[-1,1])
            translate([0,0,z*ziptie_dist_])
            {
                %hollow_cylinder(
                        d=bearing_type[1]+ziptie_bearing_distance+ziptie_thickness,
                        thickness = ziptie_thickness,
                        h = ziptie_width,
                        orient=[0,0,1],
                        align=[0,0,-z]
                        );
            }
        }
    }
}

if(false)
{
    b=bearing_igus_rj4jp_01_12;
    bearing_mount_holes(b, orient=[0,0,1]);
    translate([30,0,0])
    bearing(b, orient=[0,0,1]);
}


prototype of an element

prototype of an element

eps = 0.01;

module element()
{
  difference()
  {
    union()
    {
      // center guideing element
      intersection()
      {
        cylinder(d=35, h=42-4, $fn=200);
        translate([-100/2, -4/2, 0])
          cube([100, 4, 50]);
      }
      // core cylinder
      cylinder(d=32, h=42-4, $fn=200);
    }
    // center side cut
    translate([0, 50/2, 26/2+7])
      rotate([90, 0, 0])
        cylinder(d=26, h=50, $fn=200);
    // bottom cut
    translate([0, 0, -eps])
      cylinder(d=17, h=2.5);
    // screw hole
    translate([0, 0, -eps])
      cylinder(d=3.5, h=50, $fn=30);
    // screw head
    translate([0, 0, -eps])
      cylinder(d=9.5, h=42-4-5+2.5, $fn=30);
  }
}

rotate([180, 0, 0])
  element();

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


New motor size and finish

New motor size and finish

Finish layout code for motor retention rings

MOTOR_DIST_X = 37.5;
MOTOR_DIST_Y = 37.5;
MOTOR_DIAMETER = 8.5;

WIRING_HOLE_OFFSET = 0.7;
WIRING_HOLE_DIAMETER = 2;

ARM_WIDTH = 13.5;
PLATE_DIMENSIONS = [30, 45];

ZIP_TIE_HOLE_OFFSETS = [0.15, 0.4, 0.6, 0.85];
ZIP_TIE_HOLE_DIAM = 3;

module MainPlate()
{
  motor_positions = [
    [MOTOR_DIST_X, MOTOR_DIST_Y],
    [-MOTOR_DIST_X, MOTOR_DIST_Y],
    [MOTOR_DIST_X, -MOTOR_DIST_Y],
    [-MOTOR_DIST_X, -MOTOR_DIST_Y]
  ];

  module Plate()
  {
    square(PLATE_DIMENSIONS, center=true);
  }

  module MotorCross()
  {
    for(p=motor_positions)
    {
      hull()
      {
        circle(d=ARM_WIDTH);
        translate(p)
          circle(d=ARM_WIDTH);
      }
    }
  }

  module MotorMountingHoles()
  {
    for(p=motor_positions)
    {
      translate(p)
        circle(d=MOTOR_DIAMETER);

      translate(p * WIRING_HOLE_OFFSET)
        circle(d=WIRING_HOLE_DIAMETER);
    }
  }

  module Cutouts()
  {
    half_dim = PLATE_DIMENSIONS / 2;
    translate(-half_dim)
    {
      for(i=ZIP_TIE_HOLE_OFFSETS)
      {
        translate([PLATE_DIMENSIONS[0] * 0.85, PLATE_DIMENSIONS[1] * i])
          circle(d=ZIP_TIE_HOLE_DIAM);
        translate([PLATE_DIMENSIONS[0] * 0.15, PLATE_DIMENSIONS[1] * i])
          circle(d=ZIP_TIE_HOLE_DIAM);
      }
    }
  }

  difference()
  {
    union()
    {
      Plate();
      MotorCross();
    }

    union()
    {
      MotorMountingHoles();
      Cutouts();
    }
  }
}

module MotorRetentionClips()
{
  difference()
  {
    circle(d=ARM_WIDTH);
    circle(d=MOTOR_DIAMETER);
  }
}

$fs = 2;

MainPlate();

for(a = [0 : 90 : 360])
  rotate([0, 0, a])
    translate([0, (max(PLATE_DIMENSIONS) / 2) + ARM_WIDTH])
      MotorRetentionClips();

MOTOR_DIST_X = 37.5;
MOTOR_DIST_Y = 37.5;
MOTOR_DIAMETER = 6.9;

WIRING_HOLE_OFFSET = 0.7;
WIRING_HOLE_DIAMETER = 2;

ARM_WIDTH = 11;
PLATE_DIMENSIONS = [30, 45];

ZIP_TIE_HOLE_OFFSETS = [0.15, 0.4, 0.6, 0.85];
ZIP_TIE_HOLE_DIAM = 3;

module MainPlate()
{
  motor_positions = [
    [MOTOR_DIST_X, MOTOR_DIST_Y],
    [-MOTOR_DIST_X, MOTOR_DIST_Y],
    [MOTOR_DIST_X, -MOTOR_DIST_Y],
    [-MOTOR_DIST_X, -MOTOR_DIST_Y]
  ];

  module Plate()
  {
    square(PLATE_DIMENSIONS, center=true);
  }

  module MotorCross()
  {
    for(p=motor_positions)
    {
      hull()
      {
        circle(d=ARM_WIDTH);
        translate(p)
          circle(d=ARM_WIDTH);
      }
    }
  }

  module MotorMountingHoles()
  {
    for(p=motor_positions)
    {
      translate(p)
        circle(d=MOTOR_DIAMETER);

      translate(p * WIRING_HOLE_OFFSET)
        circle(d=WIRING_HOLE_DIAMETER);
    }
  }

  module Cutouts()
  {
    half_dim = PLATE_DIMENSIONS / 2;
    translate(-half_dim)
    {
      for(i=ZIP_TIE_HOLE_OFFSETS)
      {
        translate([PLATE_DIMENSIONS[0] * 0.85, PLATE_DIMENSIONS[1] * i])
          circle(d=ZIP_TIE_HOLE_DIAM);
        translate([PLATE_DIMENSIONS[0] * 0.15, PLATE_DIMENSIONS[1] * i])
          circle(d=ZIP_TIE_HOLE_DIAM);
      }
    }
  }

  difference()
  {
    union()
    {
      Plate();
      MotorCross();
    }

    union()
    {
      MotorMountingHoles();
      Cutouts();
    }
  }
}

module MotorRetentionClips()
{
  difference()
  {
    circle(d=ARM_WIDTH);
    circle(d=MOTOR_DIAMETER);
  }
}

$fs = 2;
MainPlate();
translate([0, (PLATE_DIMENSIONS[1] / 2) + 10])
  MotorRetentionClips();


decreased spacing between coins

decreased spacing between coins

eps = 0.01;
N = 4;
M = 4;

module qiagen_logo()
{
  translate([-10.5, -9, 0])
    translate([0,0,1+1])
      linear_extrude(1)
        scale(.42*[1,1])
          import("qiagen_logo.svg");
}

module qiabasz()
{
  difference()
  {
    cylinder(d=30, h=1+1, $fn=100);
    translate([0,0,-eps])
      linear_extrude(1+eps)
        text("#!", size=18, halign="center", valign="center");
  }
  qiagen_logo();
}

for(i=[0:N-1])
  for(j=[0:M-1])
    translate([i*32, j*32, 0])
      qiabasz();

eps = 0.01;
N = 4;
M = 4;

module qiagen_logo()
{
  translate([-10.5, -9, 0])
    translate([0,0,1+1])
      linear_extrude(1)
        scale(.42*[1,1])
          import("qiagen_logo.svg");
}

module qiabasz()
{
  difference()
  {
    cylinder(d=30, h=1+1, $fn=100);
    translate([0,0,-eps])
      linear_extrude(1+eps)
        text("#!", size=18, halign="center", valign="center");
  }
  qiagen_logo();
}

for(i=[0:N-1])
  for(j=[0:M-1])
    translate([i*35, j*35, 0])
      qiabasz();


psu/mount: define parts

psu/mount: define parts

use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
include <thing_libutils/metric-thread-data.scad>;
include <thing_libutils/metric-hexnut-data.scad>;

include <config.scad>

psu_a_w=11.5*cm;
psu_a_d=21.5*cm;
psu_a_h=5*cm;
psu_a_screw_side_dist_z = 2.5*cm;
psu_a_screw_dist_y = 15*cm;
psu_a_screw_bottom_dist_x = 5*cm;

psu_a_screw_thread = ThreadM4;
psu_a_screw_thread_dia = lookup(ThreadSize, psu_a_screw_thread);

psu_b_w=98*mm;
psu_b_d=19.5*cm;
psu_b_h=42*mm;
psu_b_screw_offset_y = 37.5*mm-18*mm;
psu_b_screw_dist_y = 12*cm;
psu_b_screw_bottom_dist_x = 8*cm;

psu_b_screw_thread = ThreadM3;
psu_b_screw_thread_dia = lookup(ThreadSize, psu_b_screw_thread);

psu_mount_bottom_height = 4*mm;

module psu_a(align=[0,0,0], detailed_model=true)
{
    if(detailed_model)
    {
        size_align([psu_a_w,psu_a_d,psu_a_h], align)
            translate([-24.5,105,-25])
            rotate([0,0,90])
            import("stl/ledpowersupply.stl");
    }
    else
    {
        size_align([psu_a_w,psu_a_d,psu_a_h], align)
        difference()
        {
            cubea([psu_a_w,psu_a_d,psu_a_h]);

            // screw holes, sides
            for(x=[-1,1])
                for(y=[-1,1])
                    for(z=[-1,1])
                        translate([x*(psu_a_w/2+1), y*(psu_a_screw_dist_y/2), z*psu_a_screw_side_dist_z/2])
                            cylindera(d=psu_a_screw_thread_dia, h=0.5*cm, orient=[1,0,0], align=[-x,0,0]);

            // screw holes, bottom
            for(x=[-1,1])
                for(y=[-1,1])
                    translate([x*(psu_a_screw_bottom_dist_x/2), y*(psu_a_screw_dist_y/2), -psu_a_h/2-1])
                        cylindera(d=psu_a_screw_thread_dia, h=1*cm, orient=[0,0,1], align=[0,0,1]);
        }
    }
}

module psu_a_extrusion_bracket_side()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2])
                    cylindera(d=psu_a_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(y=[-1,1])
                translate([psu_a_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_a_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2+1])
                cylindera(d=psu_a_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(y=[-1,1])
            translate([psu_a_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_a_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

module psu_a_extrusion_bracket_back()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2])
                    cylindera(d=psu_a_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(x=[-1,1])
                translate([x*psu_a_screw_bottom_dist_x/2, -psu_a_screw_dist_y/2+psu_a_d/2+extrusion_size/2, -psu_a_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2+1])
                cylindera(d=psu_a_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(x=[-1,1])
            translate([x*psu_a_screw_bottom_dist_x/2, -psu_a_screw_dist_y/2+psu_a_d/2+extrusion_size/2, -psu_a_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

module psu_b(align=[0,0,0])
{
    {
        size_align([psu_b_w,psu_b_d,psu_b_h], align)
        difference()
        {
            cubea([psu_b_w,psu_b_d,psu_b_h]);

            // screw holes, sides
            /*for(x=[-1,1])*/
                /*for(y=[-1,1])*/
                    /*for(z=[-1,1])*/
                        /*translate([x*(psu_b_w/2+1), y*(psu_b_screw_dist_y/2), z*psu_b_screw_side_dist_z/2])*/
                            /*cylindera(d=psu_b_screw_thread_dia, h=0.5*cm, orient=[1,0,0], align=[-x,0,0]);*/

            // screw holes, bottom
            for(x=[-1,1])
                for(y=[-1,1])
                    translate([x*(psu_b_screw_bottom_dist_x/2), psu_b_screw_offset_y+y*(psu_b_screw_dist_y/2), -psu_b_h/2-1])
                        cylindera(d=psu_b_screw_thread_dia, h=1*cm, orient=[0,0,1], align=[0,0,1]);
        }
    }
}

module psu_b_extrusion_bracket_side()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_b_screw_bottom_dist_x/2), 0, -psu_b_h/2])
                    cylindera(d=psu_b_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(y=[-1,1])
                translate([psu_b_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_b_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_b_screw_bottom_dist_x/2), 0, -psu_b_h/2+1])
                cylindera(d=psu_b_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(y=[-1,1])
            translate([psu_b_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_b_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

module psu_b_extrusion_bracket_back()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_b_screw_bottom_dist_x/2), psu_b_screw_offset_y, -psu_b_h/2])
                    cylindera(d=psu_b_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(x=[-1,1])
                translate([x*psu_b_screw_bottom_dist_x/2, -psu_b_screw_dist_y/2+psu_b_d/2+extrusion_size/2, -psu_b_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_b_screw_bottom_dist_x/2), psu_b_screw_offset_y, -psu_b_h/2+1])
                cylindera(d=psu_b_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(x=[-1,1])
            translate([x*psu_b_screw_bottom_dist_x/2, -psu_b_screw_dist_y/2+psu_b_d/2+extrusion_size/2, -psu_b_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

module part_psu_a_extrusion_bracket_side()
{
    psu_a_extrusion_bracket_side();
}

module part_psu_a_extrusion_bracket_back()
{
    psu_a_extrusion_bracket_back();
}

module part_psu_b_extrusion_bracket_side()
{
    psu_b_extrusion_bracket_side();
}

module part_psu_b_extrusion_bracket_back()
{
    psu_b_extrusion_bracket_back();
}

/*psu_a();*/

/*translate([0, -psu_a_screw_dist_y/2, 0])*/
/*psu_a_extrusion_bracket_side();*/

/*translate([0, psu_a_screw_dist_y/2, 0])*/
/*psu_a_extrusion_bracket_back();*/

/*psu_b();*/

/*translate([0, psu_b_screw_offset_y-psu_b_screw_dist_y/2, 0])*/
/*psu_b_extrusion_bracket_side();*/

/*translate([0, psu_b_screw_dist_y/2, 0])*/
/*psu_b_extrusion_bracket_back();*/

use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
include <thing_libutils/metric-thread-data.scad>;
include <thing_libutils/metric-hexnut-data.scad>;

include <config.scad>

psu_a_w=11.5*cm;
psu_a_d=21.5*cm;
psu_a_h=5*cm;
psu_a_screw_side_dist_z = 2.5*cm;
psu_a_screw_dist_y = 15*cm;
psu_a_screw_bottom_dist_x = 5*cm;

psu_a_screw_thread = ThreadM4;
psu_a_screw_thread_dia = lookup(ThreadSize, psu_a_screw_thread);

psu_b_w=98*mm;
psu_b_d=19.5*cm;
psu_b_h=42*mm;
psu_b_screw_offset_y = 37.5*mm-18*mm;
psu_b_screw_dist_y = 12*cm;
psu_b_screw_bottom_dist_x = 8*cm;

psu_b_screw_thread = ThreadM3;
psu_b_screw_thread_dia = lookup(ThreadSize, psu_b_screw_thread);

psu_mount_bottom_height = 4*mm;

module psu_a(align=[0,0,0], detailed_model=true)
{
    if(detailed_model)
    {
        size_align([psu_a_w,psu_a_d,psu_a_h], align)
            translate([-24.5,105,-25])
            rotate([0,0,90])
            import("stl/ledpowersupply.stl");
    }
    else
    {
        size_align([psu_a_w,psu_a_d,psu_a_h], align)
        difference()
        {
            cubea([psu_a_w,psu_a_d,psu_a_h]);

            // screw holes, sides
            for(x=[-1,1])
                for(y=[-1,1])
                    for(z=[-1,1])
                        translate([x*(psu_a_w/2+1), y*(psu_a_screw_dist_y/2), z*psu_a_screw_side_dist_z/2])
                            cylindera(d=psu_a_screw_thread_dia, h=0.5*cm, orient=[1,0,0], align=[-x,0,0]);

            // screw holes, bottom
            for(x=[-1,1])
                for(y=[-1,1])
                    translate([x*(psu_a_screw_bottom_dist_x/2), y*(psu_a_screw_dist_y/2), -psu_a_h/2-1])
                        cylindera(d=psu_a_screw_thread_dia, h=1*cm, orient=[0,0,1], align=[0,0,1]);
        }
    }
}

module psu_a_extrusion_bracket_side()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2])
                    cylindera(d=psu_a_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(y=[-1,1])
                translate([psu_a_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_a_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2+1])
                cylindera(d=psu_a_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(y=[-1,1])
            translate([psu_a_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_a_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

module psu_a_extrusion_bracket_back()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2])
                    cylindera(d=psu_a_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(x=[-1,1])
                translate([x*psu_a_screw_bottom_dist_x/2, -psu_a_screw_dist_y/2+psu_a_d/2+extrusion_size/2, -psu_a_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_a_screw_bottom_dist_x/2), 0, -psu_a_h/2+1])
                cylindera(d=psu_a_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(x=[-1,1])
            translate([x*psu_a_screw_bottom_dist_x/2, -psu_a_screw_dist_y/2+psu_a_d/2+extrusion_size/2, -psu_a_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

/*psu_a();*/

/*translate([0, -psu_a_screw_dist_y/2, 0])*/
/*psu_a_extrusion_bracket_side();*/

/*translate([0, psu_a_screw_dist_y/2, 0])*/
/*psu_a_extrusion_bracket_back();*/

module psu_b(align=[0,0,0])
{
    {
        size_align([psu_b_w,psu_b_d,psu_b_h], align)
        difference()
        {
            cubea([psu_b_w,psu_b_d,psu_b_h]);

            // screw holes, sides
            /*for(x=[-1,1])*/
                /*for(y=[-1,1])*/
                    /*for(z=[-1,1])*/
                        /*translate([x*(psu_b_w/2+1), y*(psu_b_screw_dist_y/2), z*psu_b_screw_side_dist_z/2])*/
                            /*cylindera(d=psu_b_screw_thread_dia, h=0.5*cm, orient=[1,0,0], align=[-x,0,0]);*/

            // screw holes, bottom
            for(x=[-1,1])
                for(y=[-1,1])
                    translate([x*(psu_b_screw_bottom_dist_x/2), psu_b_screw_offset_y+y*(psu_b_screw_dist_y/2), -psu_b_h/2-1])
                        cylindera(d=psu_b_screw_thread_dia, h=1*cm, orient=[0,0,1], align=[0,0,1]);
        }
    }
}

module psu_b_extrusion_bracket_side()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_b_screw_bottom_dist_x/2), 0, -psu_b_h/2])
                    cylindera(d=psu_b_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(y=[-1,1])
                translate([psu_b_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_b_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_b_screw_bottom_dist_x/2), 0, -psu_b_h/2+1])
                cylindera(d=psu_b_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(y=[-1,1])
            translate([psu_b_w/2+extrusion_size/2, y*extrusion_side_screw_dist/2, -psu_b_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

module psu_b_extrusion_bracket_back()
{
    extrusion_side_screw_dist = 3*cm;
    difference()
    {
        hull()
        {
            for(x=[-1,1])
                translate([x*(psu_b_screw_bottom_dist_x/2), psu_b_screw_offset_y, -psu_b_h/2])
                    cylindera(d=psu_b_screw_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);

            for(x=[-1,1])
                translate([x*psu_b_screw_bottom_dist_x/2, -psu_b_screw_dist_y/2+psu_b_d/2+extrusion_size/2, -psu_b_h/2])
                    cylindera(d=extrusion_thread_dia*3, h=psu_mount_bottom_height, align=[0,0,-1]);
        }

        for(x=[-1,1])
            translate([x*(psu_b_screw_bottom_dist_x/2), psu_b_screw_offset_y, -psu_b_h/2+1])
                cylindera(d=psu_b_screw_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);

        for(x=[-1,1])
            translate([x*psu_b_screw_bottom_dist_x/2, -psu_b_screw_dist_y/2+psu_b_d/2+extrusion_size/2, -psu_b_h/2+1])
                cylindera(d=extrusion_thread_dia, h=psu_mount_bottom_height*2, align=[0,0,-1]);
    }
}

/*psu_b();*/

/*translate([0, psu_b_screw_offset_y-psu_b_screw_dist_y/2, 0])*/
/*psu_b_extrusion_bracket_side();*/

/*translate([0, psu_b_screw_dist_y/2, 0])*/
/*psu_b_extrusion_bracket_back();*/