edged top v2

edged top v2

tol = 0.25;
screen_tol = 0.8;
pcb_x = 100;
pcb_y = 100;
pcb_z = 4;
bolt_d = 3.6;
shift_bolt = 3;
shift_bolt_x = 4;
shift_bolt_y = 7;
board_w = 1;
board_h = 1;

m3_bolt_top_r = 2.9;
m3_bolt_top_h = 1.5;

// box thickness
th = 2;

// bolts
shift_x = th + 0.5;
shift_y = th + 0.5;

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

pcb_width = 2;

socket_h = 14.7;
socket_w = 10;
socket_n = 6;
socket_all_len = 85;
socket_int = socket_w + (socket_all_len - socket_n*socket_w)/(socket_n - 1);
start_socket_x = shift_x + (pcb_x - socket_all_len) / 2;
eps = 1e-1;

bottom_box_z = socket_h + th + pcb_width;

usb_type_b_w = 12;
usb_type_b_h = 11;
start_type_b_y = shift_y + pcb_y - 36.5;
start_type_b_z = bottom_box_z - pcb_width - usb_type_b_h - tol;

usb_type_a_w = 14.4;
usb_type_a_h = 6.3;
start_type_a_y = shift_y + 25;
start_type_a_z = bottom_box_z - pcb_width - usb_type_a_h - 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;
stoiki_h = socket_h;
wide_stoiki_r = stoiki_r + 2;

dynamic_x = shift_x + 20;
dynamic_y = shift_y + 31;
dynamic_r = 16;

volume_center_y = shift_y + 50;
volume_w = 15;
volume_start_y = volume_center_y - volume_w/2;
volume_h = 4;

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

difference() {
  union() {
    difference() {
      union() {
        cube([box_x, box_y, bottom_box_z-board_h], false);
        translate([th - board_w, th - board_w, 0]) {
          cube([box_x - 2*(th - board_w), box_y - 2*(th - board_w), bottom_box_z], false);
        }
      }
      translate([th, th, th]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, bottom_box_z-th+eps], false);
      }
    }
    // under_pcb, stoiki
    for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
      for (dx = [shift_x+shift_bolt_x, shift_x+pcb_x-shift_bolt_x]) {
        translate([dx,dy,th-eps]) {
          cylinder($fn=6, r=stoiki_r, h=stoiki_h + eps);
          //cylinder($fn=6, r=wide_stoiki_r, h=gaika_h);
        }
      }
    }
   translate([start_socket_x, th - eps, th - eps]) {
     cube([socket_all_len, th/2 + eps, stoiki_h + eps]);
   }
    //translate([box_x/2, box_y/2, th-eps]) {
      //cylinder($fn=6, r=stoiki_r, h=pcb_up);
    //}
  }

  // dynamic
  translate([dynamic_x, dynamic_y, -eps]) {
      cylinder($fn=20, r=dynamic_r, h = th+2*eps);
  }

  // sockets
  for (i = [0:1:socket_n-1]) {
      translate([start_socket_x+i*socket_int - tol, -eps, bottom_box_z - socket_h - pcb_width]) {
        cube(size=[socket_w + 2*tol, socket_h, socket_h + socket_h]);
      }
  }
  // bolts
  for (dx = [shift_x+shift_bolt_x, shift_x+pcb_x-shift_bolt_x]) {
    for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=th+stoiki_h+2*eps);
        // bolt
        cylinder($fn=12, r=m3_bolt_top_r + 0.05, h=m3_bolt_top_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, bottom_box_z]);
    }

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

    // volume
    translate([-eps, volume_start_y, bottom_box_z - pcb_width - volume_h]) {
        cube(size=[th+2*eps, volume_w, volume_h + pcb_width + eps]);
    }

}
}

top_box_z = 10;
//stoiki_h = top_box_z - th;
wide_stoiki_h = 4;
pcb_room = 1;
screen_start_x = shift_x + 11.5;
screen_start_y = shift_y + 24.5;
screen_length_x = 77;
screen_length_y = 51;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 12.5;
screen_hold_y_shift = 2;
screen_hold_up_x = 15;
screen_hold_up_x_shift = 5;

master_button_y = shift_y + pcb_y - 7.5;
master_button_x = shift_x + 18.5;
master_button_int = 31.5;
master_button_r = 6.5;
top_bolt_h = 1.5;
top_bolt_r = 3.5;

!rotate(a=[180,0,0]) {
difference() {
  union() {
    // board
    translate([0, 0, -board_h]) {
        difference() {
            cube([box_x, box_y, board_h + eps], false);
            translate([board_w, board_w, -eps]) {
                cube([box_x - 2*board_w, box_y - 2*board_w, board_h + 3*eps], false);
            }
        }
    }
    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_x, shift_x+pcb_x-shift_bolt_x]) {
      for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
        translate([dx,dy,-eps]) {
          cylinder($fn=6, r=stoiki_r-0.5, 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]);
    //}
  }
  // bolts
  for (dx = [shift_x+shift_bolt_x, shift_x+pcb_x-shift_bolt_x]) {
    for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
      translate([dx,dy,-2*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]);
  }
  // master buttons
  for (i = [0:1:2]) {
    translate([master_button_x + master_button_int*i, 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.25;
screen_tol = 0.8;
pcb_x = 100;
pcb_y = 100;
pcb_z = 4;
bolt_d = 3.6;
shift_bolt = 3;
shift_bolt_x = 4;
shift_bolt_y = 7;
board_w = 1;
board_h = 1;

m3_bolt_top_r = 2.9;
m3_bolt_top_h = 1.5;

// box thickness
th = 2;

// bolts
shift_x = th;
shift_y = th;

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

pcb_width = 1.6;

socket_h = 14.7;
socket_w = 10;
socket_n = 6;
socket_all_len = 85;
socket_int = socket_w + (socket_all_len - socket_n*socket_w)/(socket_n - 1);
start_socket_x = shift_x + (pcb_x - socket_all_len) / 2;
eps = 1e-1;

bottom_box_z = socket_h + th + pcb_width;

usb_type_b_w = 11;
usb_type_b_h = 11;
start_type_b_y = shift_y + pcb_y - 36;
start_type_b_z = bottom_box_z - pcb_width - usb_type_b_h - tol;

usb_type_a_w = 14.4;
usb_type_a_h = 6.3;
start_type_a_y = shift_y + 25;
start_type_a_z = bottom_box_z - pcb_width - usb_type_a_h - 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;
stoiki_h = socket_h;
wide_stoiki_r = stoiki_r + 2;

dynamic_x = shift_x + 20;
dynamic_y = shift_y + 31.5;
dynamic_r = 15.2;

volume_center_y = shift_y + 50;
volume_w = 15;
volume_start_y = volume_center_y - volume_w/2;
volume_h = 4;

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

difference() {
  union() {
    difference() {
      union() {
        cube([box_x, box_y, bottom_box_z-board_h], false);
        translate([th - board_w, th - board_w, 0]) {
          cube([box_x - 2*(th - board_w), box_y - 2*(th - board_w), bottom_box_z], false);
        }
      }
      translate([th, th, th]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, bottom_box_z-th+eps], false);
      }
    }
    // under_pcb, stoiki
    for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
      for (dx = [shift_x+shift_bolt_x, shift_x+pcb_x-shift_bolt_x]) {
        translate([dx,dy,th-eps]) {
          cylinder($fn=6, r=stoiki_r, h=stoiki_h + eps);
          //cylinder($fn=6, r=wide_stoiki_r, h=gaika_h);
        }
      }
    }
   translate([start_socket_x, th - eps, th - eps]) {
     cube([socket_all_len, th/2 + eps, stoiki_h + eps]);
   }
    //translate([box_x/2, box_y/2, th-eps]) {
      //cylinder($fn=6, r=stoiki_r, h=pcb_up);
    //}
  }

  // dynamic
  translate([dynamic_x, dynamic_y, -eps]) {
      cylinder($fn=20, r=dynamic_r, h = th+2*eps);
  }

  // sockets
  for (i = [0:1:socket_n-1]) {
      translate([start_socket_x+i*socket_int - tol, -eps, bottom_box_z - socket_h - pcb_width]) {
        cube(size=[socket_w + 2*tol, socket_h, socket_h + socket_h]);
      }
  }
  // bolts
  for (dx = [shift_x+shift_bolt_x, shift_x+pcb_x-shift_bolt_x]) {
    for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=th+stoiki_h+2*eps);
        // bolt
        cylinder($fn=12, r=m3_bolt_top_r + 0.05, h=m3_bolt_top_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, bottom_box_z]);
    }

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

    // volume
    translate([-eps, volume_start_y, bottom_box_z - pcb_width - volume_h]) {
        cube(size=[th+2*eps, volume_w, volume_h + pcb_width + eps]);
    }

}
}

top_box_z = 10;
//stoiki_h = top_box_z - th;
wide_stoiki_h = 4;
pcb_room = 1;
screen_start_x = shift_x + 11;
screen_start_y = shift_y + 26;
screen_length_x = 78;
screen_length_y = 51;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 12.5;
screen_hold_y_shift = 2;
screen_hold_up_x = 15;
screen_hold_up_x_shift = 5;

master_button_y = shift_y + pcb_y - 7.5;
master_button_x = shift_x + 18.5;
master_button_int = 31.5;
master_button_r = 6;
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() {
    // board
    translate([0, 0, -board_h]) {
        difference() {
            cube([box_x, box_y, board_h + eps], false);
            translate([board_w, board_w, -eps]) {
                cube([box_x - 2*board_w, box_y - 2*board_w, board_h + 3*eps], false);
            }
        }
    }
    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_x, shift_x+pcb_x-shift_bolt_x]) {
      for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
        translate([dx,dy,-eps]) {
          cylinder($fn=6, r=stoiki_r-0.5, 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]);
    //}
  }
  // bolts
  for (dx = [shift_x+shift_bolt_x, shift_x+pcb_x-shift_bolt_x]) {
    for (dy = [shift_y+shift_bolt_y, shift_y+pcb_y-shift_bolt_y]) {
      translate([dx,dy,-2*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]);
  }
  // master buttons
  for (i = [0:1:2]) {
    translate([master_button_x + master_button_int*i, 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);
//        }
//    }


Rounded ends to wheel section on tibia

Rounded ends to wheel section on tibia

module tibia(sl = 23, sw = 12.5){
	difference(){
		//solid parts
		union(){
			hull(){
				//main inner square
				translate([-30,-10,0]) cube([28,20,4]);
				//lower taper
				translate([5,-1.5,0]) cube([2,3,4]);
			}

			//leg
			translate([0,-1.5,0]) cube([40,3,4]);
			//top bar
			translate([-33,-7,0]) cube([6,14,4]);
			//rounded corners
			for (i = [ [-30,7,0],[-30,-7,0] ]){
				translate(i) cylinder(r=3,h=4,$fn=50);
			}
		}
		//servo mounts
		for (i = [ [-3,0,-2],[-31,0,-2] ]){
			translate(i) cylinder(r=1,h=20,$fn=20);
		}
		//hole for servo body
		translate([-17,0,2])  cube([sl,sw,22], center=true);
	}
}

module tibia2(sl = 23, sw = 12.5) {
	wheelThickness = 6;
	or = 70;
	ir = or - wheelThickness;

	difference(){
		//solid parts
		union(){
			hull(){
				//main inner square
				translate([-30,-10,0]) cube([28,20,4]);
				//lower taper
				translate([5,-1.5,0]) cube([2,3,4]);
			}

			//top bar
			translate([-33,-7,0]) cube([6,14,4]);
			//rounded corners
			for (i = [ [-30,7,0],[-30,-7,0] ]){
				translate(i) cylinder(r=3,h=4,$fn=50);
			}

			// wheel section
			translate([-44, ir - 20,0])
			rotate([0,0,-80]) {

				// section
				sector3D(r=or, ir=ir, a=160, h=4, center = false, $fn=64);

				// add rounded tips to the wheel section
				for (i=[0,1])
					rotate([0,0,i*160])
					translate([or - wheelThickness/2,0,0])
					cylinder(r=3, h=4);
			}

		}
		//servo mounts
		for (i = [ [-3,0,-2],[-31,0,-2] ]){
			translate(i) cylinder(r=1,h=20,$fn=20);
		}
		//hole for servo body
		translate([-17,0,2])  cube([sl,sw,22], center=true);
	}
}

module tibia(sl = 23, sw = 12.5){
	difference(){
		//solid parts
		union(){
			hull(){
				//main inner square
				translate([-30,-10,0]) cube([28,20,4]);
				//lower taper
				translate([5,-1.5,0]) cube([2,3,4]);
			}

			//leg
			translate([0,-1.5,0]) cube([40,3,4]);
			//top bar
			translate([-33,-7,0]) cube([6,14,4]);
			//rounded corners
			for (i = [ [-30,7,0],[-30,-7,0] ]){
				translate(i) cylinder(r=3,h=4,$fn=50);
			}
		}
		//servo mounts
		for (i = [ [-3,0,-2],[-31,0,-2] ]){
			translate(i) cylinder(r=1,h=20,$fn=20);
		}
		//hole for servo body
		translate([-17,0,2])  cube([sl,sw,22], center=true);
	}
}

module tibia2(sl = 23, sw = 12.5){
	or = 70;
	ir = or - 6;

	difference(){
		//solid parts
		union(){
			hull(){
				//main inner square
				translate([-30,-10,0]) cube([28,20,4]);
				//lower taper
				translate([5,-1.5,0]) cube([2,3,4]);
			}

			//top bar
			translate([-33,-7,0]) cube([6,14,4]);
			//rounded corners
			for (i = [ [-30,7,0],[-30,-7,0] ]){
				translate(i) cylinder(r=3,h=4,$fn=50);
			}

			// wheel section
			translate([-44, ir - 20,0])
				rotate([0,0,-80])
				sector3D(r=or, ir=ir, a=160, h=4, center = false, $fn=64);
		}
		//servo mounts
		for (i = [ [-3,0,-2],[-31,0,-2] ]){
			translate(i) cylinder(r=1,h=20,$fn=20);
		}
		//hole for servo body
		translate([-17,0,2])  cube([sl,sw,22], center=true);
	}
}


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


reworked to use 2D CSG exclusively, plus added end pieces.

// Housings to hold hexagonal nut for a "nut drive" two nuts with
// reverse threads on a threaded rod.
use <../common/extrusions.scad>
EPSILON = 0.01;
LARGE = 100;

function poly_coords(order, r=1)  =
    let(angles=[ for (i = [0:order-1]) i*(360/order) ])
 	[ for (th=angles) [r*cos(th), r*sin(th)] ];

 module regular_polygon(order, r=1){
 	polygon(poly_coords(order, r));
 }

block_w = 30;
block_d = 30;
block_ro = 3;

hole_r = 2.05;
holes_major_dia = block_d  - hole_r;

 center_h = 10;
 end_h = 3;

// about center
module block2d(w, r) {
    offset(r = r) square([w-2*r, w-2*r], center=true);
}

// about center
module holes2d(major_dia, r) {
    hole_centers = poly_coords(4, major_dia/2);
    rotate([0, 0, 45]) for (i = [0:3]) {
                translate(hole_centers[i])
                    circle(r);
            }
}

module center_piece() {

    hex_dia = 20;

    linear_extrude(height = center_h) {
        difference() {
             block2d(block_w, block_ro);
            regular_polygon(6, hex_dia/2);
            holes2d(holes_major_dia, hole_r);
        }
    }
}

module end_piece() {
    linear_extrude(height = end_h) {
        center_hole_r = 5;
        anchor_offset = 5; // from top of block
        anchor_hole_r = hole_r;
        anchor_wall = 3; // min wall surrounding anchor
        anchor_center = [0, block_w/2 + anchor_offset];
        difference() {
                 //linear_extrude(height = block_h + 2*EPSILON)
            hull() {
                block2d(block_w, block_ro);
                translate(anchor_center)
                    circle(anchor_wall + anchor_hole_r);
            }
            holes2d(holes_major_dia, hole_r);
            circle(center_hole_r);
            translate(anchor_center)
                circle(anchor_hole_r);

        }
    }
}

$fn = 50;
center_piece();
translate([block_w + 10, 0, 0]) end_piece();
translate([0, block_w + 10, 0]) end_piece();

// Housings to hold hexagonal nut for a "nut drive" two nuts with
// reverse threads on a threaded rod.
use <../common/extrusions.scad>
EPSILON = 0.01;
LARGE = 100;

function poly_coords(order, r=1)  =
    let(angles=[ for (i = [0:order-1]) i*(360/order) ])
 	[ for (th=angles) [r*cos(th), r*sin(th)] ];

 module regular_polygon(order, r=1){
 	polygon(poly_coords(order, r));
 }

block_w = 30;
block_d = 30;
block_h = 10;
block_ro = 3;

module center_piece() {

    hex_dia = 20;
    hole_r = 2.05;
    hole_major_dia = block_d  - hole_r;
    hole_centers = poly_coords(4, hole_major_dia/2);
    punch_h = block_h + 2*EPSILON;

    difference() {
        oblong(block_w, block_d, block_ro, block_h);
        translate([block_w/2, block_d/2, -EPSILON]) {
            linear_extrude(height = block_h + 2*EPSILON) regular_polygon(6, hex_dia/2);
            rotate([0, 0, 45]) for (i = [0:3]) {
                translate(hole_centers[i])
                    cylinder(r=hole_r, h = punch_h);
            }
        }
    }
}

$fn = 50;
center_piece();


oozing test tower is narrowed at the top now


back to low poly

back to low poly

use <dummies.scad>;
use <grip.scad>;

phi_sphere = 38;
e_sphere = 3.;
phi_sphere_in = phi_sphere - e_sphere;
phi_sphere_out = phi_sphere + e_sphere;

phi_knob_in = phi_sphere_in;
phi_knob_out = phi_knob_in + 6;
w_knob = (phi_knob_out - phi_knob_in)/2;
e_knob = 4;
hh = e_knob/3-0.1;
clear = 2;
$fn = 36;

module turret_base(){
     union(){
          ring(e_knob, phi_knob_in, phi_knob_out);
          // SM1Z specific
          translate([0, 0, -2.2]) ring(2, 28.5, phi_knob_out);
          translate([0, 0, -3]) ring(3, 28.5, 31.5);
     }
}

module turret(){
     difference(){
          union(){
               movement_sphere(phi_sphere_in, phi_sphere_out);
               turret_base();
          }
          sphere_hole(e=e_sphere,
                      phi_sphere=phi_sphere,
                      clear=clear,
                      aperture=175);
     }
}

module half_turret(){
     difference(){
          turret();
          translate([-25, -0.05, -25]) cube([50, 50, 50]);
     }
}

module left_turret(){
     union(){
          difference(){
               half_turret();
               translate([phi_knob_in/2+w_knob/2, -0.5, -1.5])
                    rotate(90, [1, 0, 0])
                    magnet();
               translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.5])
                    cube([w_knob+0.2, w_knob+0.2, hh+0.3], center=true);

          }
          translate([-phi_knob_in/2-w_knob/2, 0, -hh/2])
                    cylinder(d=w_knob, h=hh, $fn=36, center=true);
          translate([-phi_knob_in/2-w_knob/2, 0, -e_knob+hh/2])
                    cylinder(d=w_knob, h=hh, $fn=36, center=true);
          translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.5])
                    cylinder(d=1., h=e_knob, $fn=36, center=true);

     }
}

module right_turret(){
     difference(){
          union(){
               difference(){
                    rotate(180, [0, 0, 1]) half_turret();
                    translate([phi_knob_in/2+w_knob/2, 0.5, -1.5])
                         rotate(90, [1, 0, 0])
                         magnet();
                    translate([-phi_knob_in/2-w_knob/2, 0, 0.])
                         cube([w_knob+0.4, w_knob+0.4, hh+1.5], center=true);
                    translate([-phi_knob_in/2-w_knob/2, 0, -e_knob+hh/2-0.05])
                         cube([w_knob+0.4, w_knob+0.2, hh+0.5], center=true);
               }
               translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.5])
                    cylinder(d=w_knob, h=hh, center=true, $fn=30);
          }
          translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.6])
               cylinder(d=1.2, h=hh+0.6, center=true, $fn=30);
     }
}

right_turret();
/* right_grip(e=e_sphere, */
/*            phi_sphere=phi_sphere, */
/*            shift=clear/2); */

translate([-phi_knob_in/2-w_knob/2, 0, 0])
rotate([0, 0, -30])
translate([phi_knob_in/2+w_knob/2, 0, 0])
union(){
     left_turret();
     /* left_grip(e=e_sphere, */
     /*           phi_sphere=phi_sphere, */
     /*           shift=clear/2); */
}

use <dummies.scad>;
use <grip.scad>;

phi_sphere = 38;
e_sphere = 3.;
phi_sphere_in = phi_sphere - e_sphere;
phi_sphere_out = phi_sphere + e_sphere;

phi_knob_in = phi_sphere_in;
phi_knob_out = phi_knob_in + 6;
w_knob = (phi_knob_out - phi_knob_in)/2;
e_knob = 4;
hh = e_knob/3-0.1;
clear = 2;
$fn = 256;

module turret_base(){
     union(){
          ring(e_knob, phi_knob_in, phi_knob_out);
          // SM1Z specific
          translate([0, 0, -2.2]) ring(2, 28.5, phi_knob_out);
          translate([0, 0, -3]) ring(3, 28.5, 31.5);
     }
}

module turret(){
     difference(){
          union(){
               movement_sphere(phi_sphere_in, phi_sphere_out);
               turret_base();
          }
          sphere_hole(e=e_sphere,
                      phi_sphere=phi_sphere,
                      clear=clear,
                      aperture=175);
     }
}

module half_turret(){
     difference(){
          turret();
          translate([-25, -0.05, -25]) cube([50, 50, 50]);
     }
}

module left_turret(){
     union(){
          difference(){
               half_turret();
               translate([phi_knob_in/2+w_knob/2, -0.5, -1.5])
                    rotate(90, [1, 0, 0])
                    magnet();
               translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.5])
                    cube([w_knob+0.2, w_knob+0.2, hh+0.3], center=true);

          }
          translate([-phi_knob_in/2-w_knob/2, 0, -hh/2])
                    cylinder(d=w_knob, h=hh, $fn=36, center=true);
          translate([-phi_knob_in/2-w_knob/2, 0, -e_knob+hh/2])
                    cylinder(d=w_knob, h=hh, $fn=36, center=true);
          translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.5])
                    cylinder(d=1., h=e_knob, $fn=36, center=true);

     }
}

module right_turret(){
     difference(){
          union(){
               difference(){
                    rotate(180, [0, 0, 1]) half_turret();
                    translate([phi_knob_in/2+w_knob/2, 0.5, -1.5])
                         rotate(90, [1, 0, 0])
                         magnet();
                    translate([-phi_knob_in/2-w_knob/2, 0, 0.])
                         cube([w_knob+0.4, w_knob+0.4, hh+1.5], center=true);
                    translate([-phi_knob_in/2-w_knob/2, 0, -e_knob+hh/2-0.05])
                         cube([w_knob+0.4, w_knob+0.2, hh+0.5], center=true);
               }
               translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.5])
                    cylinder(d=w_knob, h=hh, center=true, $fn=30);
          }
          translate([-phi_knob_in/2-w_knob/2, 0., -2*hh+0.6])
               cylinder(d=1.2, h=hh+0.6, center=true, $fn=30);
     }
}

right_turret();
/* right_grip(e=e_sphere, */
/*            phi_sphere=phi_sphere, */
/*            shift=clear/2); */

translate([-phi_knob_in/2-w_knob/2, 0, 0])
rotate([0, 0, -30])
translate([phi_knob_in/2+w_knob/2, 0, 0])
union(){
     left_turret();
     /* left_grip(e=e_sphere, */
     /*           phi_sphere=phi_sphere, */
     /*           shift=clear/2); */
}


screws: remove debug echo

screws: remove debug echo

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

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

// for proper threads
use <naca_sweep.scad>

// naive, assume head height is same as thread size (generally true for cap heads)
function get_screw_head_h(head, thread) =
(head=="socket" || head == "button") ?
    get(ThreadSize, thread)
:
head == "set" ? 0
:
0;

function get_screw_head_d(head, thread) =
(head=="socket" || head == "button") ?
    2 * get(ThreadSize, thread)
:
head == "set" ? 0
:
0;

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

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

    s = threadsize*tolerance;
    total_h = h;

    if(part==U)
    {
        difference()
        {
            screw(part="pos", nut=nut, thread=thread, head=head, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
            screw(part="neg", nut=nut, thread=thread, head=head, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
        }
        if($show_vit)
        %screw(part="vit", nut=nut, thread=thread, head=head, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
    }
    else if(part=="pos")
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, align=align)
    tz(head_embed?-head_h:0)
    {
        if(with_head)
        {
            tz(h/2+.01)
            screw_head(part=part, head=head, thread=thread_, orient=Z, align=Z);
        }

        tz(-h/2+.01)
        screw_thread(thread=thread_, h=h+.1, tolerance=tolerance, orient=Z, align=N);

        if(with_nut && nut != U)
        {
            tz(-h/2+nut_h+nut_offset+(head_embed?head_h:0))
            screw_nut(nut=nut, tolerance=tolerance, orient=Z, align=-Z);
        }
    }
    else if(part=="neg")
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, align=align)
    tz(head_embed?-head_h:0)
    {
        if(with_head)
        tz(h/2+.01)
        screw_head(part=part, head=head, thread=thread_, orient=Z, align=Z);
    }
    else if(part=="vit")
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, align=align)
    {
        if(with_nut && nut != U)
        {
            tz(-h/2+nut_h+nut_offset+(head_embed?head_h:0))
            %screw_nut(nut=nut, align=-Z);
        }
    }
}

module screw_cut(nut, thread, head="socket", h=10, tolerance=1.05, head_embed=false, with_nut=true, with_nut_cut=true, with_nut_access=true, nut_cut_h=1000, with_head=true, head_cut_h=1000, nut_offset=0, cut_access=true, orient=Z, align=N)
{
    assert(h>0);

    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "screw_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && nut_thread != thread_, "screw_cut: Mismatched nut and thread");*/

    nut_h = get(NutThickness,nut)*tolerance;
    assert(head != U, "screw_cut: head == U");

    head_h = get_screw_head_h(head=head, thread=thread_);
    assert(head_h != U, "screw_cut: head_h is U!");

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

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

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

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

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

module screw_thread(thread, h=10, tolerance=1.00, orient=Z, align=N)
{
    assert(thread!=U, "screw_thread: thread is undef");
    threadsize = get(ThreadSize, thread);
    d = get(ThreadSize, thread);
    pitch = get(ThreadPitchMm, thread);
    windings = ceil(h/pitch);

    size_align(size=[d,d,h], orient=orient, align=align)
    material(Mat_Steel)
    {
        if($preview_mode)
        {
            cylindera(d=d, h=h, align=Z);
        }
        else
        {
            intersection()
            {
                cylindera(d=d, h=h, align=Z);
                tz(-pitch)
                threading(angle=60, pitch=pitch, d=d, windings=windings, full=true);
            }
            /*inner_d = (get(ThreadInternalMinorDiaMin, thread) + get(ThreadInternalMinorDiaMin, thread))/2;*/
            /*cylindera(d=inner_d, h=h, align=Z);*/
        }
    }
}

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

module screw_head(part, head="socket", drive="hex", thread, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(head != U, "screw_head: head == U");
    assert(thread!=U, "screw_head: thread == undef");

    threadsize = get(ThreadSize, thread);
    head_h = fallback(override_h, get_screw_head_h(head=head, thread=thread));
    head_d = get_screw_head_d(head=head, thread=thread);

    if(part==U)
    {
        difference()
        {
            screw_head(part="pos", head=head, drive=drive, thread=thread, tolerance=tolerance, override_h=override_h, orient=orient, align=align);
            screw_head(part="neg", head=head, drive=drive, thread=thread, tolerance=tolerance, override_h=override_h, orient=orient, align=align);
        }
    }
    else if(part=="pos")
    material(Mat_Steel)
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket")
        {
            tz(-head_h/2)
            cylindera(d=head_d, h = head_h, align=Z);
        }
        else if(head=="button")
        {
            c = head_d;
            f = head_h*1.25;
            r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

            d = r - f; // displacement to move sphere

            intersection()
            {
                tz(-head_h/2)
                scale([1,1,.5])
                spherea(r = head_h, align=N);

                tz(-head_h/2)
                cylindera(d=head_d, h = head_h/2, align=Z);
            }
        }
    }
    else if(part=="neg")
    material(Mat_Steel)
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        tz(-head_h/2)
        if(drive=="hex")
        {
            threadsize_cut = threadsize-head_drive_threadsize_minus(head);
            inset = head_drive_inset(head, head_h);
            tz(inset)
            cylindera(d = fn_radius(threadsize_cut, 6), h = head_h, $fn = 6, align=Z);
        }
        else if(part=="neg")
        {
            if(head=="socket")
            {
                difference()
                {
                    tz(-head_h/2)
                    cylindera(d=head_d, h = fallback(override_h,head_h), align=Z);

                    if(drive == "hex")
                    {
                        cylindera(d = fn_radius(threadsize, 6), h = 1000, $fn = 6, align=Z);
                    }
                }
            }
            else if(head=="button")
            {
                c = head_d;
                f = head_h*1.25;
                r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

                d = r - f; // displacement to move sphere

                difference()
                {
                    intersection()
                    {
                        tz(-head_h/2)
                        scale([1,1,.5])
                        spherea(r = head_h, align=N);

                        tz(-head_h/2)
                        cylindera(d=head_d, h = fallback(override_h,head_h)/2, align=Z);
                    }

                    if(drive == "hex")
                    {
                        // button head uses -0.5*mm smaller hex
                        tz(-head_h/2)
                        cylindera(d = fn_radius(threadsize-.5, 6), h = 1000, $fn = 6, align=Z);
                    }
                }
            }
            else if(head=="set")
            {
            }
        }
    }
}

function head_drive_threadsize_minus(head) =
head=="socket"?  0:
head=="button"?  0.5:
head=="set"?     1.5:
0;

function head_drive_inset(head, head_h) =
head=="socket"?  1*mm:
head=="button"?  0.5*mm:
head=="set"?     -head_h/2:
0;

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

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(head=head, thread=thread);
    head_d = get_screw_head_d(head=head, thread=thread)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket" || head=="button")
        {
            tz(-head_h/2)
            cylindera(d=head_d, h=fallback(override_h, head_h), align=Z);
        }
        else if(head=="set")
        {
            tz(-head_h/2)
            cylindera(d=threadsize, h=fallback(override_h, head_h), align=Z);
        }
        else
        {
            assert("head: not implemented");
        }
    }
}

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    assert(nut_facets>=4, "screw_nut: nut_facets < 4 is not supported");
    nut_dia = nut_dia(nut);
    nut_thread = fallback(thread, get(NutThread, nut));
    h_ = fallback(override_h, nut_thick);
    material(Mat_Steel)
    size_align([nut_dia, nut_dia, h_], orient=orient, align=align)
    {
        difference()
        {
            if(nut_facets==4)
            {
                cubea([nut_dia,nut_dia,h_]);
            }
            else
            {
                cylindera($fn=nut_facets, d=nut_dia, h=h_);
            }
            tz(-h_/2-.2)
            screw_thread(thread=nut_thread, h=h_+.1);
        }
    }
}

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    nut_facets = get(NutFacets, nut);
    assert(nut_facets>=4, "screw_nut: nut_facets < 4 is not supported");
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        tz(nut_thick/2)
        {
            tz(-.1)
            screw_nut(nut=nut, tolerance=tolerance, orient=Z, align=-Z);

            if(with_access)
            tz(-nut_thick-.01)
            {
                if(nut_facets==4)
                {
                    cubea([nut_dia+2*mm,nut_dia+2*mm, h], align=-Z);
                }
                else
                {
                    cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
                }
            }
        }
    }
}

function nut_radius(nut) = outradius(get(NutWidthMin, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = get(NutFacets, nut) > 4 ?
                2*nut_radius(nut) :
                get(NutWidthMax, nut);

module nut_trap_cut(nut, thread, head="socket", trap_offset=10, screw_l=10*mm, screw_offset=0*mm, cut_screw=false, cut_screw_close=false, trap_h=10, trap_axis=-Y, orient=Z, align=N)
{
    screw_min_nut_dist = 2*mm;
    assert(screw_l+screw_offset >= trap_offset, "nut_trap_cut: screw_l+screw_offset < trap_offset");
    assert(screw_offset-trap_offset <= -screw_min_nut_dist, "nut_trap_cut: screw_offset-trap_offset > -screw_min_nut_dist");

    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "nut_trap_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && nut_thread != thread_, "nut_trap_cut: Mismatched nut and thread");*/

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

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

        tz(trap_offset)
        hull()
        {
            orient(axis=Z, axis_ref=orient)
            translate(-.15*mm*trap_axis)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(axis=orient, axis_ref=Z)
                {
                    if(nut_facets==4)
                    {
                        cubea([nut_dia,nut_dia,h_]);
                    }
                    else
                    {
                        rz(30)
                        cylindera($fn=nut_facets, d=nut_dia, h=nut_h, align=N);
                    }
                }

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

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

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

    }
}

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

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

// From ParkinBots threading library
// https://www.thingiverse.com/thing:1659079
/*module Threading(D = 0, pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40)*/
/*{*/
    /*R = D==0?d/2+2*pitch/PI:D/2; */
    /*translate([0,0,-pitch])*/
    /*difference()*/
    /*{*/
        /*translate([0,0,pitch])*/
        /*cylinder (r=R, h =pitch*(windings-helices));*/
        /*threading(pitch, d, windings, helices, angle, steps, true); */
    /*}*/
/*}*/

// From ParkinBots threading library
// https://www.thingiverse.com/thing:1659079
module threading(pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40, full = false)
{
    // tricky: glue two 180° pieces together to get a proper manifold
    r = d/2;
    Steps = steps/2;
    Pitch = pitch*helices;
    if(full)
    {
        cylinder(r = r-.5-pitch/PI, h=pitch*(windings+helices), $fn=steps);
    }

    sweep(gen_dat(), planar_caps=true);   // half screw
    rz(180)
    tz(Pitch/2)
    sweep(gen_dat(), planar_caps=true);   // half screw

    function gen_dat() =
        let(ang = 180, bar = R_(180, -90, 0, Ty_(-r+.5, vec3D(pitch/PI*Rack(windings, angle)))))
        [for (i=[0:Steps]) Tz_(i/2/Steps*Pitch, -Rz_(i*ang/Steps, bar))];

    function Rack(w, angle) =
        concat([[0, 2]],
            [for (i=[0:w-1], j=[0:3])
            let(t = [ [0, 1], [2*tan(angle/2), -1], [PI/2, -1], [2*tan(angle/2)+PI/2, 1]])
            [t[j][0]+i*PI, t[j][1]]], [[w*PI, 1], [w*PI, 2]
            ]);
}

if(false)
{
    $fn=32;
    all_heads=
    [
        "socket",
        "button",
        "set"
    ];
    for(i=[0:len(all_heads)-1])
    {
        head=all_heads[i];
        tx(i*8*mm)
        screw(nut=NutHexM3, head=head, h=25, orient=-Z);
    }

}

if(false)
{
    $fn=128;
    nut1 = NutHexM3;
    stack(axis=X, dist = 20)
    {
        screw(nut=NutHexM8, head="socket", h=25, orient=-Z);
        screw(nut=NutHexM8, head="button", h=25, orient=-Z);
        screw(nut=NutHexM8, head="button", h=25, with_head=1, with_nut=0, orient=-Z);
        screw(nut=NutHexM8, head="button", h=25, with_head=0, with_nut=0, orient=-Z);
        screw(nut=NutHexM8, head="set", h=25, with_nut=0, orient=-Z);

        threading(pitch = 1.25, d=8, windings=10, full=true);
    }
}

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

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

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

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

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

}

if(false)
{
    nut1 = NutHexM5;
    stack(dist=10,axis=X)
    {
        $show_vit=true;
        $preview_mode=true;
        #screw(nut=nut1, h=10, orient=-Z, align=-Z);
        #screw_cut(nut=nut1, h=10, orient=-Z, align=-Z);
        #screw_cut(nut=nut1, h=10, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=10, cut_screw=false, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=10, cut_screw=true, orient=-Z, align=-Z);
        #screw(nut=nut1, h=20, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=20, cut_screw=true, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=20, trap_offset=20, cut_screw=true, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=25, screw_offset=-5, trap_offset=20, cut_screw=true, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=20, cut_screw=true, cut_screw_close=true, orient=-Z, align=-Z);
    }
}

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

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

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

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

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

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

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

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

// for proper threads
use <naca_sweep.scad>

// naive, assume head height is same as thread size (generally true for cap heads)
function get_screw_head_h(head, thread) =
(head=="socket" || head == "button") ?
    get(ThreadSize, thread)
:
head == "set" ? 0
:
0;

function get_screw_head_d(head, thread) =
(head=="socket" || head == "button") ?
    2 * get(ThreadSize, thread)
:
head == "set" ? 0
:
0;

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

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

    s = threadsize*tolerance;
    total_h = h;

    if(part==U)
    {
        difference()
        {
            screw(part="pos", nut=nut, thread=thread, head=head, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
            screw(part="neg", nut=nut, thread=thread, head=head, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
        }
        if($show_vit)
        %screw(part="vit", nut=nut, thread=thread, head=head, h=h, tolerance=tolerance, head_embed=head_embed, with_nut=with_nut, with_head=with_head, nut_offset=nut_offset, orient=orient, align=align);
    }
    else if(part=="pos")
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, align=align)
    tz(head_embed?-head_h:0)
    {
        if(with_head)
        {
            tz(h/2+.01)
            screw_head(part=part, head=head, thread=thread_, orient=Z, align=Z);
        }

        tz(-h/2+.01)
        screw_thread(thread=thread_, h=h+.1, tolerance=tolerance, orient=Z, align=N);

        if(with_nut && nut != U)
        {
            tz(-h/2+nut_h+nut_offset+(head_embed?head_h:0))
            screw_nut(nut=nut, tolerance=tolerance, orient=Z, align=-Z);
        }
    }
    else if(part=="neg")
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, align=align)
    tz(head_embed?-head_h:0)
    {
        if(with_head)
        tz(h/2+.01)
        screw_head(part=part, head=head, thread=thread_, orient=Z, align=Z);
    }
    else if(part=="vit")
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=Z, align=align)
    {
        if(with_nut && nut != U)
        {
            tz(-h/2+nut_h+nut_offset+(head_embed?head_h:0))
            %screw_nut(nut=nut, align=-Z);
        }
    }
}

module screw_cut(nut, thread, head="socket", h=10, tolerance=1.05, head_embed=false, with_nut=true, with_nut_cut=true, with_nut_access=true, nut_cut_h=1000, with_head=true, head_cut_h=1000, nut_offset=0, cut_access=true, orient=Z, align=N)
{
    assert(h>0);

    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "screw_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && nut_thread != thread_, "screw_cut: Mismatched nut and thread");*/

    nut_h = get(NutThickness,nut)*tolerance;
    assert(head != U, "screw_cut: head == U");

    head_h = get_screw_head_h(head=head, thread=thread_);
    assert(head_h != U, "screw_cut: head_h is U!");

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

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

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

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

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

module screw_thread(thread, h=10, tolerance=1.00, orient=Z, align=N)
{
    assert(thread!=U, "screw_thread: thread is undef");
    threadsize = get(ThreadSize, thread);
    d = get(ThreadSize, thread);
    pitch = get(ThreadPitchMm, thread);
    windings = ceil(h/pitch);

    size_align(size=[d,d,h], orient=orient, align=align)
    material(Mat_Steel)
    {
        if($preview_mode)
        {
            cylindera(d=d, h=h, align=Z);
        }
        else
        {
            intersection()
            {
                cylindera(d=d, h=h, align=Z);
                tz(-pitch)
                threading(angle=60, pitch=pitch, d=d, windings=windings, full=true);
            }
            /*inner_d = (get(ThreadInternalMinorDiaMin, thread) + get(ThreadInternalMinorDiaMin, thread))/2;*/
            /*cylindera(d=inner_d, h=h, align=Z);*/
        }
    }
}

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

module screw_head(part, head="socket", drive="hex", thread, tolerance=1.00, override_h=U, orient=Z, align=N)
{
    assert(head != U, "screw_head: head == U");
    assert(thread!=U, "screw_head: thread == undef");

    threadsize = get(ThreadSize, thread);
    head_h = fallback(override_h, get_screw_head_h(head=head, thread=thread));
    head_d = get_screw_head_d(head=head, thread=thread);

    if(part==U)
    {
        difference()
        {
            screw_head(part="pos", head=head, drive=drive, thread=thread, tolerance=tolerance, override_h=override_h, orient=orient, align=align);
            screw_head(part="neg", head=head, drive=drive, thread=thread, tolerance=tolerance, override_h=override_h, orient=orient, align=align);
        }
    }
    else if(part=="pos")
    material(Mat_Steel)
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket")
        {
            tz(-head_h/2)
            cylindera(d=head_d, h = head_h, align=Z);
        }
        else if(head=="button")
        {
            c = head_d;
            f = head_h*1.25;
            r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

            d = r - f; // displacement to move sphere

            intersection()
            {
                tz(-head_h/2)
                scale([1,1,.5])
                spherea(r = head_h, align=N);

                tz(-head_h/2)
                cylindera(d=head_d, h = head_h/2, align=Z);
            }
        }
    }
    else if(part=="neg")
    material(Mat_Steel)
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        tz(-head_h/2)
        if(drive=="hex")
        {
            threadsize_cut = threadsize-head_drive_threadsize_minus(head);
            inset = head_drive_inset(head, head_h);
            tz(inset)
            cylindera(d = fn_radius(threadsize_cut, 6), h = head_h, $fn = 6, align=Z);
        }
        else if(part=="neg")
        {
            if(head=="socket")
            {
                difference()
                {
                    tz(-head_h/2)
                    cylindera(d=head_d, h = fallback(override_h,head_h), align=Z);

                    if(drive == "hex")
                    {
                        cylindera(d = fn_radius(threadsize, 6), h = 1000, $fn = 6, align=Z);
                    }
                }
            }
            else if(head=="button")
            {
                c = head_d;
                f = head_h*1.25;
                r = ( pow(c,2)/4 + pow(f,2) )/(2*f);

                d = r - f; // displacement to move sphere

                difference()
                {
                    intersection()
                    {
                        tz(-head_h/2)
                        scale([1,1,.5])
                        spherea(r = head_h, align=N);

                        tz(-head_h/2)
                        cylindera(d=head_d, h = fallback(override_h,head_h)/2, align=Z);
                    }

                    if(drive == "hex")
                    {
                        // button head uses -0.5*mm smaller hex
                        tz(-head_h/2)
                        cylindera(d = fn_radius(threadsize-.5, 6), h = 1000, $fn = 6, align=Z);
                    }
                }
            }
            else if(head=="set")
            {
            }
        }
    }
}

function head_drive_threadsize_minus(head) =
head=="socket"?  0:
head=="button"?  0.5:
head=="set"?     1.5:
0;

function head_drive_inset(head, head_h) =
head=="socket"?  1*mm:
head=="button"?  0.5*mm:
head=="set"?     -head_h/2:
0;

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

    threadsize = get(ThreadSize, thread);
    head_h = get_screw_head_h(head=head, thread=thread);
    head_d = get_screw_head_d(head=head, thread=thread)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    {
        if(head=="socket" || head=="button")
        {
            tz(-head_h/2)
            cylindera(d=head_d, h=fallback(override_h, head_h), align=Z);
        }
        else if(head=="set")
        {
            tz(-head_h/2)
            cylindera(d=threadsize, h=fallback(override_h, head_h), align=Z);
        }
        else
        {
            assert("head: not implemented");
        }
    }
}

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_facets = get(NutFacets, nut);
    assert(nut_facets>=4, "screw_nut: nut_facets < 4 is not supported");
    nut_dia = nut_dia(nut);
    nut_thread = fallback(thread, get(NutThread, nut));
    h_ = fallback(override_h, nut_thick);
    material(Mat_Steel)
    size_align([nut_dia, nut_dia, h_], orient=orient, align=align)
    {
        difference()
        {
            echo(nut_facets);
            if(nut_facets==4)
            {
                cubea([nut_dia,nut_dia,h_]);
            }
            else
            {
                cylindera($fn=nut_facets, d=nut_dia, h=h_);
            }
            tz(-h_/2-.2)
            screw_thread(thread=nut_thread, h=h_+.1);
        }
    }
}

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

    nut_thick = get(NutThickness,nut)*tolerance;
    nut_dia = nut_dia(nut);
    nut_facets = get(NutFacets, nut);
    assert(nut_facets>=4, "screw_nut: nut_facets < 4 is not supported");
    size_align(size=[nut_dia, nut_dia, nut_thick], orient=orient, align=align)
    {
        tz(nut_thick/2)
        {
            tz(-.1)
            screw_nut(nut=nut, tolerance=tolerance, orient=Z, align=-Z);

            if(with_access)
            tz(-nut_thick-.01)
            {
                if(nut_facets==4)
                {
                    cubea([nut_dia+2*mm,nut_dia+2*mm, h], align=-Z);
                }
                else
                {
                    cylindera(d=nut_dia+2*mm, h=h, orient=Z, align=-Z);
                }
            }
        }
    }
}

function nut_radius(nut) = outradius(get(NutWidthMin, nut)/2, get(NutFacets, nut));
function nut_dia(nut) = get(NutFacets, nut) > 4 ?
                2*nut_radius(nut) :
                get(NutWidthMax, nut);

module nut_trap_cut(nut, thread, head="socket", trap_offset=10, screw_l=10*mm, screw_offset=0*mm, cut_screw=false, cut_screw_close=false, trap_h=10, trap_axis=-Y, orient=Z, align=N)
{
    screw_min_nut_dist = 2*mm;
    assert(screw_l+screw_offset >= trap_offset, "nut_trap_cut: screw_l+screw_offset < trap_offset");
    assert(screw_offset-trap_offset <= -screw_min_nut_dist, "nut_trap_cut: screw_offset-trap_offset > -screw_min_nut_dist");

    nut_thread = get(NutThread, nut);
    thread_ = fallback(thread, nut_thread);
    assert(thread_ != U, "nut_trap_cut: No nut or thread given");
    /*assert(nut!=U && thread!=U && nut_thread != thread_, "nut_trap_cut: Mismatched nut and thread");*/

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

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

        tz(trap_offset)
        hull()
        {
            orient(axis=Z, axis_ref=orient)
            translate(-.15*mm*trap_axis)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(axis=orient, axis_ref=Z)
                {
                    if(nut_facets==4)
                    {
                        cubea([nut_dia,nut_dia,h_]);
                    }
                    else
                    {
                        rz(30)
                        cylindera($fn=nut_facets, d=nut_dia, h=nut_h, align=N);
                    }
                }

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

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

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

    }
}

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

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

// From ParkinBots threading library
// https://www.thingiverse.com/thing:1659079
/*module Threading(D = 0, pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40)*/
/*{*/
    /*R = D==0?d/2+2*pitch/PI:D/2; */
    /*translate([0,0,-pitch])*/
    /*difference()*/
    /*{*/
        /*translate([0,0,pitch])*/
        /*cylinder (r=R, h =pitch*(windings-helices));*/
        /*threading(pitch, d, windings, helices, angle, steps, true); */
    /*}*/
/*}*/

// From ParkinBots threading library
// https://www.thingiverse.com/thing:1659079
module threading(pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40, full = false)
{
    // tricky: glue two 180° pieces together to get a proper manifold
    r = d/2;
    Steps = steps/2;
    Pitch = pitch*helices;
    if(full)
    {
        cylinder(r = r-.5-pitch/PI, h=pitch*(windings+helices), $fn=steps);
    }

    sweep(gen_dat(), planar_caps=true);   // half screw
    rz(180)
    tz(Pitch/2)
    sweep(gen_dat(), planar_caps=true);   // half screw

    function gen_dat() =
        let(ang = 180, bar = R_(180, -90, 0, Ty_(-r+.5, vec3D(pitch/PI*Rack(windings, angle)))))
        [for (i=[0:Steps]) Tz_(i/2/Steps*Pitch, -Rz_(i*ang/Steps, bar))];

    function Rack(w, angle) =
        concat([[0, 2]],
            [for (i=[0:w-1], j=[0:3])
            let(t = [ [0, 1], [2*tan(angle/2), -1], [PI/2, -1], [2*tan(angle/2)+PI/2, 1]])
            [t[j][0]+i*PI, t[j][1]]], [[w*PI, 1], [w*PI, 2]
            ]);
}

if(false)
{
    $fn=32;
    all_heads=
    [
        "socket",
        "button",
        "set"
    ];
    for(i=[0:len(all_heads)-1])
    {
        head=all_heads[i];
        tx(i*8*mm)
        screw(nut=NutHexM3, head=head, h=25, orient=-Z);
    }

}

if(false)
{
    $fn=128;
    nut1 = NutHexM3;
    stack(axis=X, dist = 20)
    {
        screw(nut=NutHexM8, head="socket", h=25, orient=-Z);
        screw(nut=NutHexM8, head="button", h=25, orient=-Z);
        screw(nut=NutHexM8, head="button", h=25, with_head=1, with_nut=0, orient=-Z);
        screw(nut=NutHexM8, head="button", h=25, with_head=0, with_nut=0, orient=-Z);
        screw(nut=NutHexM8, head="set", h=25, with_nut=0, orient=-Z);

        threading(pitch = 1.25, d=8, windings=10, full=true);
    }
}

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

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

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

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

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

}

if(false)
{
    nut1 = NutHexM5;
    stack(dist=10,axis=X)
    {
        $show_vit=true;
        $preview_mode=true;
        #screw(nut=nut1, h=10, orient=-Z, align=-Z);
        #screw_cut(nut=nut1, h=10, orient=-Z, align=-Z);
        #screw_cut(nut=nut1, h=10, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=10, cut_screw=false, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=10, cut_screw=true, orient=-Z, align=-Z);
        #screw(nut=nut1, h=20, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=20, cut_screw=true, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=20, trap_offset=20, cut_screw=true, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=25, screw_offset=-5, trap_offset=20, cut_screw=true, orient=-Z, align=-Z);
        #nut_trap_cut(nut=nut1, screw_l=20, cut_screw=true, cut_screw_close=true, orient=-Z, align=-Z);
    }
}

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

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

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

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

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

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


added support shape (needs measures)

added support shape (needs measures)

inch = 25.4;
width = 400;
height = 300;
thickness = inch / 4;
tollerance = 0.2;

cut_thickness = 2;
cut_width = 250;
cut_height = 150;
cut_support = inch / 8;
hole_diameter = 6;
holes_per_side = 5;
holes_coverage = 200;
holes_distance = 350;

module support(width, height, thickness) {
  color([0,0,0,0.75]) {
    difference() {
      cube([width, height, thickness], center=true);

      translate([0,0,thickness-cut_thickness])
        cube([cut_width + tollerance * 2, cut_height + tollerance * 2, thickness], center=true);
      cube([cut_width - cut_support * 2, cut_height - cut_support * 2, thickness * 2], center=true);

      $fn = 32;
      dist = holes_coverage / (holes_per_side - 1);
      for(y = [0 : holes_per_side - 1]) {
        translate([0, -holes_coverage / 2 + y * dist, 0]) {
          translate([  holes_distance / 2, 0, 0])
            cylinder(h = thickness * 2, r = hole_diameter / 2, center = true);
          translate([- holes_distance / 2, 0, 0])
            cylinder(h = thickness * 2, r = hole_diameter / 2, center = true);
        }
      }
    }
  }
}

translate([0,0,thickness/2])
  support(width, height, thickness);

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


adding resin tank

adding resin tank

module glass(w,d,h) {
  color([1,1,1,0.25])
  cube([w,d,h]);
}

width  = 120;
depth  = 80;
height = 4;

glass(width, depth, height);

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


sensor holes added to fanholder

sensor holes added to fanholder

// two fan powered picker
use <flatsine.scad>;
//motorbox();
//fancut();
fanbracket();

fansize = 50;
curve = 5;
fanh=15.15;
boarder=3;
sensor_bottom_x = 4;
sensor_bottom_y = 4;
sensor_bottom_z = 1.7;
sensor_bot = [sensor_bottom_x,sensor_bottom_y,sensor_bottom_z];
sensor_top = [6,4,3.5];
totalsensor_ht = sensor_top[2] + sensor_bottom_z;
echo(totalsensor_ht);
screwdistance = fansize - curve*2;

module elbi (){
	for (i=[0,1]){
		mirror([0,i,0]){
		    translate([0,43,0])
		        elbow();
		translate([0,55,0])
			elbow(tr=3*(6.67+2), thk=5.2);
		}
	}
}

module lifter(s=fanh){
    difference(){
        cube([s,s,s], center=true);
        translate([0,0,-s/2-1-0.1])
            rotate([90,0,0])
                translate([3, 0, -s/2+1.5-0.1])
                linear_extrude(convexity=10, height=s-3)
                    sinewave(portion=180, normto=s/2-1);
        translate([0,0,-0.25*s-0.1])
            cube([s+.1, s+.1, s/2], center=true);
    }
}

module elbow(tr=6.67+2, thk=5, nutthk=2.5){
    translate([0,0,thk/2])
    difference(){
        union(){
            cube([tr, thk, thk], center=true);
            translate([tr/2,tr/2,0]){
                //cube([thk,tr, thk], center=true);
                translate([0,-tr/2,0])
                    cylinder(r=thk, h=thk, center=true);
                translate([-4.3, .5, 0])
                    #cylinder(r=thk/2, h=thk, center=true, $fn=24);
            }
            translate([-tr/2,0,0])
            cylinder(r=thk, h=thk, center=true);
        }
        for (i=[tr/2, -tr/2]){
            translate([i,0,0]){
                cylinder(r=1.7, h=thk+.1, center=true);
                translate([0,0,thk/2-nutthk/2])
                    cylinder(r=6.67/2, h=nutthk+.1, center=true, $fn=6);
            }

        }
    }
}

module motorbox(){
	difference(){
		union(){
			cube([12,10,25.4], center=true);
			cylinder(r=2, h=26.5, $fn=14, center=true);
			translate([0,0,(33.3+26.5)/4])
				cylinder(r=1.7, h=33.3-26.5, $fn=14, center=true);
		}
		translate([0,1.45,(33.3+26.5)/4+1.7])
				cube([3.4, .6, 33.3-26.5], center=true);
	}
}

module fancut(xy=fansize, h=fanh, curve=curve, screwhole_space=screwdistance, screwhole_OD=3.3){
	minkowski(){
		cube([xy-curve, xy-curve, h-.1], center=true);
		cylinder(r=curve/2, h=.1, $fn=curve*6, center=true);
	}
	cylinder(r=(xy-0.8)/2, h=h+20, center=true, $fn=48);
	for (i=[screwhole_space/2, -screwhole_space/2], j=[screwhole_space/2, -screwhole_space/2]){
        echo("from fancut(), screwhole_OD: ", screwhole_OD);
		translate([i,j,0])
			cylinder(r=screwhole_OD/2, h=h*2, $fn=screwhole_OD*4, center=true);
	}
}

module fanblock(x=fansize*2+boarder*2, y=fansize+boarder*5, h=fanh+1, scl=1.03){
    minkowski(){
	    cube([x-curve, y-curve, h-0.1], center=true);
	    cylinder(r=curve/2, h=0.1, $fn=curve*6, center=true);
    }

}

module fanbracket(x=fansize*2+boarder*2, y=fansize+boarder*5, h=fanh+1, scl=1.011, screwhole_OD=5){
    translate([0,0,h/2])
	 difference(){
        fanblock();

        // two fan cut-outs
        for (i=[fansize/2*scl, -fansize/2*scl]){
                translate([i,0,1])
                scale([scl,scl,1])
                        fancut(screwhole_OD=screwhole_OD);
        }

        // holes on the sides with captured nuts
        for (i=[-2,-1,1,2], j=[-1,1]){
            translate([fansize/2.5*i, 0, 0]){
		        translate([0,0,-1]) rotate([90,0,0])
			        cylinder(r=1.7,h=100, center=true, $fn=12);
		        translate([0,0,-1]) rotate([90,0,0])
			        cylinder(r=3,h=57, center=true, $fn=18);
		        translate([0, j*(y/2-1.14), -1]) rotate([90,0,0])
			        cylinder(r=3.35,h=2.3, center=true, $fn=6);
            }
	    }

        // holes
        for (i=[-1,0,1,], j=[1,-1]){
        translate([j*x/2, i*(y/2-boarder*1.5), 0]) rotate([0,90,0])
            #cylinder(r=1.5, h=boarder*6, center=true, $fn=10);
        }

        // IR sensor ( ods687 )
        for (j=[-1,1]){
            translate([0, j*(y/2 - sensor_bottom_y/2), -8.25]){
                translate([0,0,sensor_bottom_z/2])
                    #cube(sensor_bot, center=true);
                translate([0,0,totalsensor_ht/2 + sensor_bottom_z/2- 0.1])
                    #cube(sensor_top, center=true);
            cube([sensor_bottom_x, sensor_bottom_y, 16], center=true);
            cylinder(r=sensor_bottom_x/2-0.25, h=17, center=false);
            }
        }
    }
}

// two fan powered picker
use <flatsine.scad>;
//motorbox();
//fancut();
fanbracket();

fansize = 50;
curve = 5;
fanh=15.15;
boarder=3;

screwdistance = fansize - curve*2;

module elbi (){
	for (i=[0,1]){
		mirror([0,i,0]){
		    translate([0,43,0])
		        elbow();
		translate([0,55,0])
			elbow(tr=3*(6.67+2), thk=5.2);
		}
	}
}

module lifter(s=fanh){
    difference(){
        cube([s,s,s], center=true);
        translate([0,0,-s/2-1-0.1])
            rotate([90,0,0])
                translate([3, 0, -s/2+1.5-0.1])
                linear_extrude(convexity=10, height=s-3)
                    sinewave(portion=180, normto=s/2-1);
        translate([0,0,-0.25*s-0.1])
            cube([s+.1, s+.1, s/2], center=true);
    }
}

module elbow(tr=6.67+2, thk=5, nutthk=2.5){
    translate([0,0,thk/2])
    difference(){
        union(){
            cube([tr, thk, thk], center=true);
            translate([tr/2,tr/2,0]){
                //cube([thk,tr, thk], center=true);
                translate([0,-tr/2,0])
                    cylinder(r=thk, h=thk, center=true);
                translate([-4.3, .5, 0])
                    #cylinder(r=thk/2, h=thk, center=true, $fn=24);
            }
            translate([-tr/2,0,0])
            cylinder(r=thk, h=thk, center=true);
        }
        for (i=[tr/2, -tr/2]){
            translate([i,0,0]){
                cylinder(r=1.7, h=thk+.1, center=true);
                translate([0,0,thk/2-nutthk/2])
                    cylinder(r=6.67/2, h=nutthk+.1, center=true, $fn=6);
            }

        }
    }
}

module motorbox(){
	difference(){
		union(){
			cube([12,10,25.4], center=true);
			cylinder(r=2, h=26.5, $fn=14, center=true);
			translate([0,0,(33.3+26.5)/4])
				cylinder(r=1.7, h=33.3-26.5, $fn=14, center=true);
		}
		translate([0,1.45,(33.3+26.5)/4+1.7])
				cube([3.4, .6, 33.3-26.5], center=true);
	}
}

module fancut(xy=fansize, h=fanh, curve=curve, screwhole_space=screwdistance, screwhole_OD=3.3){
	minkowski(){
		cube([xy-curve, xy-curve, h-.1], center=true);
		cylinder(r=curve/2, h=.1, $fn=curve*6, center=true);
	}
	cylinder(r=(xy-0.8)/2, h=h+20, center=true, $fn=48);
	for (i=[screwhole_space/2, -screwhole_space/2], j=[screwhole_space/2, -screwhole_space/2]){
        echo("from fancut(), screwhole_OD: ", screwhole_OD);
		translate([i,j,0])
			cylinder(r=screwhole_OD/2, h=h*2, $fn=screwhole_OD*4, center=true);
	}
}

module fanblock(x=fansize*2+boarder*2, y=fansize+boarder*5, h=fanh+1, scl=1.03){
    minkowski(){
	    cube([x-curve, y-curve, h-0.1], center=true);
	    cylinder(r=curve/2, h=0.1, $fn=curve*6, center=true);
    }

}

module fanbracket(x=fansize*2+boarder*2, y=fansize+boarder*5, h=fanh+1, scl=1.011, screwhole_OD=5){
    translate([0,0,h/2])
	 difference(){
        fanblock();
		for (i=[fansize/2*scl, -fansize/2*scl]){
			translate([i,0,1])
			scale([scl,scl,1])
				fancut(screwhole_OD=screwhole_OD);
		}
        for (i=[-2,-1,0,1,2], j=[-1,1]){
            translate([fansize/2.5*i, 0, 0]){
		        translate([0,0,-1]) rotate([90,0,0])
			        cylinder(r=1.7,h=100, center=true, $fn=12);
		        translate([0,0,-1]) rotate([90,0,0])
			        cylinder(r=3,h=57, center=true, $fn=18);
		        translate([0, j*(y/2-1.14), -1]) rotate([90,0,0])
			        cylinder(r=3.35,h=2.3, center=true, $fn=6);
            }
	    }
	    for (i=[-1,0,1,], j=[1,-1]){
            translate([j*x/2, i*(y/2-boarder*1.5), 0]) rotate([0,90,0])
                #cylinder(r=1.5, h=boarder*6, center=true, $fn=10);
        }
    }
}


stuff

stuff

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


Update ADENIN.scad

Update ADENIN.scad

//Азотистое основание: Аденин

x=50;
y=19;
z=9;
dx=9; //Длина разъема магнита
d=2.67; //Диаметр гнезда магнита
p=6;  //Перемещине буквы А по плоскости
difference() {
union() {
 translate([0, 0, 0]) cube ([x-2, y, z-0.3], center=true);

  translate([-24, 0, 0]) rotate([0, 0, 45]) cube ([13.5, 13.5, z-0.3], center=true);

   translate([30.1, 0, 0]) cube ([13.1, 19, z-0.3], center=true);

}
  translate([6, 0, 3]) cube ([x-10, y+2, z/1.5], center=true); //Пространство для изменения объема поля с буквой

   translate([-34.8, 0, 0]) cube ([10.5, 10.5, z+2], center=true); //Для вырезки с переди

    rotate([0, 90, 0]) translate([0, 0, -34.8]) cylinder(dx, d, d);

// #rotate([0, 90, 0]) translate([0, -4.5, 33.1]) cylinder(dx, d,  d);
}

rotate([90, 0, 0]) translate([-13, 0, -9.5]) cylinder(19, 4.4, 4.4);

rotate([90, 0, 0]) translate([26.3, 0, -9.5]) cylinder(19, 4.4, 4.4);

//Буква А
difference() {
union () {
 translate([p, -7.55, 0]) rotate ([0, 0, 22]) cube ([2, 16, 2]);
  translate([p, -6.8, 2]) rotate ([45, 90, 22]) cube ([2, 16, 2]);
   translate([p-3.8, 2, 0]) cube ([9, 2, 2]);
}
 translate([p-6, -9, -2]) cube ([15, 2, 4]);
   translate([p-6, 7.1, -2]) cube ([15, 2, 4]);
}
#translate ([24.63,-11,-2])cube([12,22,4.2]);

//Азотистое основание: Аденин

x=50;
y=19;
z=9;
dx=9; //Длина разъема магнита
d=2.67; //Диаметр гнезда магнита
p=6;  //Перемещине буквы А по плоскости
difference() {
union() {
 translate([0, 0, 0]) cube ([x-2, y, z-0.3], center=true);

  translate([-24, 0, 0]) rotate([0, 0, 45]) cube ([13.5, 13.5, z-0.3], center=true);

   translate([30.1, 0, 0]) cube ([13.1, 19, z-0.3], center=true);

}
  translate([6, 0, 3]) cube ([x-10, y+2, z/1.5], center=true); //Пространство для изменения объема поля с буквой

   translate([-34.8, 0, 0]) cube ([10.5, 10.5, z+2], center=true); //Для вырезки с переди

    rotate([0, 90, 0]) translate([0, 0, -34.8]) cylinder(dx, d, d);

     rotate([0, 90, 0]) translate([0, 0, 33.1]) cylinder(dx, d,  d);

// #rotate([0, 90, 0]) translate([0, -4.5, 33.1]) cylinder(dx, d,  d);
}

rotate([90, 0, 0]) translate([-13, 0, -9.5]) cylinder(19, 4.4, 4.4);

rotate([90, 0, 0]) translate([26.3, 0, -9.5]) cylinder(19, 4.4, 4.4);

//Буква А
difference() {
union () {
 translate([p, -7.55, 0]) rotate ([0, 0, 22]) cube ([2, 16, 2]);
  translate([p, -6.8, 2]) rotate ([45, 90, 22]) cube ([2, 16, 2]);
   translate([p-3.8, 2, 0]) cube ([9, 2, 2]);
}
 translate([p-6, -9, -2]) cube ([15, 2, 4]);
   translate([p-6, 7.1, -2]) cube ([15, 2, 4]);
}
#translate ([24.63,-11,-2])cube([12,22,4.2]);