porch checkpoint

porch checkpoint

// OpenSCAD for a "porch" extension for a Turtlebot3 burger
//           It includes a lampholder.
thickness = 4;
lampholder_thickness = 3; // Must be smaller than distance between nubs
bulb_width = 25;
porch_center_y = 36;  // The length of the rectangular portion
porch_x  = 96;
rivet_radius = 2.5;   // Hole radius for rivet attachment
round_radius = 2;     // Radius of the corner arcs
tab_x = 78;           // center-center
tab_y = 7;            // edge to center of holes
tabr_x = 22.25;       // center-to-center of relay board
tabr_y = -19;         // center to center of relay board
rim = 3;              // Width of rim
hex_offset = 12;      // Center-to-center of hex connection
hex_radius = 2.5;     // Radius for hex nuts
post_offset = 24;     // Center-to-center of post cutout

// This is the basic plate. Y argument is the protrusion (2/3 of the
// porch extent). This object cannot be translated once created.
module base(x,y,z) {
    $fn=100;
    linear_extrude(height=z,center=false,convexity=10) {
        hull() {
        // place 6 circles in the corners, with the rounding radius
        translate([(-x/2)+(round_radius/2), -y+(round_radius/2), 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2), -y+(round_radius/2), 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2), 0-(round_radius/2), 0])
        circle(r=round_radius);

        translate([x/2-y+(round_radius/2), y/2-(round_radius/2), 0])
        circle(r=round_radius);

        translate([(-x/2)+y-(round_radius/2),y/2-(round_radius/2), 0])
        circle(r=round_radius);

        translate([(-x/2)+(round_radius/2), 0+(round_radius/2), 0])
        circle(r=round_radius);
        }
    }
}

// This is the basic plate less a rim width all around. This is meant to
// be subtracted from the standard plate.
module base_cutout(x,y,z,rwidth) {
    $fn=100;
    linear_extrude(height=z,center=false,convexity=10) {
        hull() {
        // place 6 circles in the corners, with the rounding radius
        translate([(-x/2)+(round_radius/2)+rwidth, -y+(round_radius/2)+rwidth, 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2)-rwidth, -y+(round_radius/2)+rwidth, 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2)-rwidth, 0-(round_radius/2)-rwidth/2, 0])
        circle(r=round_radius);

        translate([x/2-y+(round_radius/2), y/2-(round_radius/2)-rwidth, 0])
        circle(r=round_radius);

        translate([(-x/2)+y-(round_radius/2),y/2-(round_radius/2)-rwidth, 0])
        circle(r=round_radius);

        translate([(-x/2)+(round_radius/2)+rwidth, 0+(round_radius/2)-rwidth/2, 0])
        circle(r=round_radius);
        }
    }
}

// x - center to between holes
// y - baseline to center of hole
// z - thickness
module holes(x,y,z) {
    pad = 0.5;
    // These are rivet holes for the tab pieces
    for(i=[[x+rivet_radius+pad,y],[x-rivet_radius-pad,y],
           [-x+rivet_radius+pad,y],[-x-rivet_radius-pad,y]]) {
        translate(i)
        cylinder(r=rivet_radius,h=z);
    }
}

// x - center of board
// y - center of board
// z - thickness
module relay_holes(x,y,z) {
    dx = 14;   // center of board to center of hole
    dy = 10;   // center of board to center of hole
    // These are rivet holes for the relay board
    for(i=[[x+dx,y+dy],[x-dx,y-dy],
           [x+dx,y-dy],[x-dx,y+dy]]) {
        translate(i)
        cylinder(r=rivet_radius,h=z);
    }
}

// Protrusions to allow screws to main platform
module connector(z) {
    difference() {
        rotate(22.5,0,0)
        cylinder(h=z,r1=5,r2=5,$fn=8,center=true);
        cylinder(h=z,r1=2,r2=2,center=true);
        translate([0,0,z/2])
          cylinder(height=z/2,r1=2.5,r2=2.5,$fn=8);
    }
}
// Subtract this from the base platform
// These are the cutouts for the fastening nuts
module connector_housing(z) {
    linear_extrude(height=z,center=true) {
        rotate(22.5,0,0)
        circle(r=5,$fn=8);
    }
}
// Subtract this from the base platform
// This also works for the cutout for posts.
module post_housing(z) {
    linear_extrude(height=z,center=true) {
        rotate(22.5,0,0)
        circle(r=6,$fn=8);
    }
}
// width - radius of the bulb opening
// z - thickness of the holder
module lampholder(width,z) {
    bulb_tail_radius = 8;
    notch_radius = 1;
    difference() {
        union() {
            translate([0,-width/4,0])
                cube([width,width/2,z],center=true);
            translate([0,-width/2,-z/2])
                cylinder(r=width/2,h=z);
           }
           translate([0,-width/2,-z/2])
            cylinder(r=bulb_tail_radius,h=z);
           translate([0,-width/2-bulb_tail_radius-notch_radius/2,-z/2])
            cylinder(r=notch_radius,h=z);
    }
}
// Cutout to account for flare of lamp. 15mm->28mm in 5mm
module lamp_flare() {
    cylinder(h=6,r1=14,r2=7.5,center=true);
}

// Support between the lampholders.
module support(x,y,z) {
    height=6;
    cube([x,y,height],center=true);
}

// --------------------- Final Assembly ----------------------
// Baseplate
translate([0,0,thickness/2])
difference() {
    base(porch_x,porch_center_y,thickness);
    translate([0,-porch_center_y,0])
        holes(tab_x/2,tab_y,thickness);
        relay_holes(tabr_x,tabr_y,thickness);
    translate([-hex_offset,-porch_center_y-(hex_radius/2),thickness/2])
        connector_housing(2*thickness);
    translate([hex_offset,-porch_center_y-(hex_radius/2),thickness/2])
        connector_housing(2*thickness);
    translate([post_offset,-porch_center_y-(round_radius/2),thickness/2])
        post_housing(2*thickness);
     translate([-post_offset,-porch_center_y-(round_radius/2),thickness])
         post_housing(2*thickness);
}
// Rim
translate([0,0,-thickness/2]) {
    difference() {
        base(porch_x,porch_center_y,thickness);
        base_cutout(porch_x,porch_center_y,thickness,rim);
        translate([hex_offset,-porch_center_y-(hex_radius/2),thickness/2])
            connector_housing(2*thickness);
        translate([-hex_offset,-porch_center_y-(hex_radius/2),thickness/2])
            connector_housing(2*thickness);
        translate([post_offset,-porch_center_y-(round_radius/2),thickness/2])
            post_housing(2*thickness);
        translate([-post_offset,-porch_center_y-(round_radius/2),thickness])
            post_housing(2*thickness);
    }
}
// Lampholders
// Inner distance between holders = 6mm
translate([0,0,thickness/2])
    rotate(90,[1,0,0])
        lampholder(bulb_width,lampholder_thickness);
translate([0,6+lampholder_thickness+thickness/2,thickness/2])
    rotate(90,[1,0,0])
      lampholder(bulb_width,thickness);

translate([bulb_width/2-rim/2,porch_center_y/4,0])
    support(rim,porch_center_y/2,6);
translate([-bulb_width/2+rim/2,porch_center_y/4,0])
    support(rim,porch_center_y/2,6);
// These are the two protrusions for fastening to the robot.
translate([hex_offset,-porch_center_y-hex_radius/2,thickness])
    rotate(180,[0,1,0])
        connector(thickness);
translate([-hex_offset,-porch_center_y-hex_radius/2,0])
    connector(thickness);
 intersection() {
    translate([0,6+2*lampholder_thickness+thickness,-bulb_width/2+3])
    rotate(90,[1,0,0])
      lamp_flare();
 }

// OpenSCAD for a "porch" extension for a Turtlebot3 burger
//           It includes a lampholder.
thickness = 4;
lampholder_thickness = 3; // Must be smaller than distance between nubs
bulb_width = 25;
porch_center_y = 36;  // The length of the rectangular portion
porch_x  = 90;
rivet_radius = 2.5;   // Hole radius for rivet attachment
round_radius = 2;     // Radius of the corner arcs
tab_x = 66;           // center-center
tab_y = 9;            // edge to center of holes
tabr_x = 22.25;       // center-to-center of relay board
tabr_y = -17;         // center to center of relay board
rim = 3;              // Width of rim
hex_offset = 12;      // Center-to-center of hex connection
post_offset = 24;     // Center-to-center of post cutout

// This is the basic plate. Y argument is the protrusion (2/3 of the
// porch extent). This object cannot be translated once created.
module base(x,y,z) {
    $fn=100;
    linear_extrude(height=z,center=false,convexity=10) {
        hull() {
        // place 6 circles in the corners, with the rounding radius
        translate([(-x/2)+(round_radius/2), -y+(round_radius/2), 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2), -y+(round_radius/2), 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2), 0-(round_radius/2), 0])
        circle(r=round_radius);

        translate([x/2-y+(round_radius/2), y/2-(round_radius/2), 0])
        circle(r=round_radius);

        translate([(-x/2)+y-(round_radius/2),y/2-(round_radius/2), 0])
        circle(r=round_radius);

        translate([(-x/2)+(round_radius/2), 0+(round_radius/2), 0])
        circle(r=round_radius);
        }
    }
}

// This is the basic plate less a rim width all around. This is meant to
// be subtracted from the standard plate.
module base_cutout(x,y,z,rwidth) {
    $fn=100;
    linear_extrude(height=z,center=false,convexity=10) {
        hull() {
        // place 6 circles in the corners, with the rounding radius
        translate([(-x/2)+(round_radius/2)+rwidth, -y+(round_radius/2)+rwidth, 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2)-rwidth, -y+(round_radius/2)+rwidth, 0])
        circle(r=round_radius);

        translate([(x/2)-(round_radius/2)-rwidth, 0-(round_radius/2)-rwidth/2, 0])
        circle(r=round_radius);

        translate([x/2-y+(round_radius/2), y/2-(round_radius/2)-rwidth, 0])
        circle(r=round_radius);

        translate([(-x/2)+y-(round_radius/2),y/2-(round_radius/2)-rwidth, 0])
        circle(r=round_radius);

        translate([(-x/2)+(round_radius/2)+rwidth, 0+(round_radius/2)-rwidth/2, 0])
        circle(r=round_radius);
        }
    }
}

// x - center to between holes
// y - baseline to center of hole
// z - thickness
module holes(x,y,z) {
    pad = 0.5;
    // These are rivet holes for the tab pieces
    for(i=[[x+rivet_radius+pad,y],[x-rivet_radius-pad,y],
           [-x+rivet_radius+pad,y],[-x-rivet_radius-pad,y]]) {
        translate(i)
        cylinder(r=rivet_radius,h=z);
    }
}

// x - center of board
// y - center of board
// z - thickness
module relay_holes(x,y,z) {
    dx = 14;   // center of board to center of hole
    dy = 10;   // center of board to center of hole
    // These are rivet holes for the relay board
    for(i=[[x+dx,y+dy],[x-dx,y-dy],
           [x+dx,y-dy],[x-dx,y+dy]]) {
        translate(i)
        cylinder(r=rivet_radius,h=z);
    }
}

// This allows screws to main platform
module connector(z) {
    difference() {
        cylinder(h=z,r1=5,r2=5,$fn=6,center=true);
        cylinder(h=z,r1=2,r2=2,center=true);
        translate([0,0,z/2])
          cylinder(height=z/2,r1=2.5,r2=2.5,$fn=6);
    }
}
// Subtract this from the base platform
// This also works for the cutout for posts.
module connector_housing(z) {
    linear_extrude(height=z,center=true) {
        circle(r=5,$fn=6);
    }
}
// width - radius of the bulb opening
// z - thickness of the holder
module lampholder(width,z) {
    bulb_tail_radius = 8;
    notch_radius = 1;
    difference() {
        union() {
            translate([0,-width/4,0])
                cube([width,width/2,z],center=true);
            translate([0,-width/2,-z/2])
                cylinder(r=width/2,h=z);
           }
           translate([0,-width/2,-z/2])
            cylinder(r=bulb_tail_radius,h=z);
           translate([0,-width/2-bulb_tail_radius-notch_radius/2,-z/2])
            cylinder(r=notch_radius,h=z);
    }
}

// Support between the lampholders.
module support(x,y,z) {
    height=6;
    cube([x,y,height],center=true);
}

// --------------------- Final Assembly ----------------------
// Baseplate
translate([0,0,thickness/2])
difference() {
    base(porch_x,porch_center_y,thickness);
    translate([0,-porch_center_y,0])
        holes(tab_x/2,tab_y,thickness);
        relay_holes(tabr_x,tabr_y,thickness);
    translate([-hex_offset,-porch_center_y-(round_radius/2),thickness/2])
        connector_housing(2*thickness);
    translate([hex_offset,-porch_center_y-(round_radius/2),thickness/2])
        connector_housing(2*thickness);
    translate([post_offset,-porch_center_y-(round_radius/2),thickness/2])
        connector_housing(2*thickness);
     translate([-post_offset,-porch_center_y-(round_radius/2),thickness])
         connector_housing(2*thickness);
}
// Rim
translate([0,0,-thickness/2]) {
    difference() {
        base(porch_x,porch_center_y,thickness);
        base_cutout(porch_x,porch_center_y,thickness,rim);
        translate([hex_offset,-porch_center_y-(round_radius/2),thickness/2])
            connector_housing(2*thickness);
        translate([-hex_offset,-porch_center_y-(round_radius/2),thickness/2])
            connector_housing(2*thickness);
        translate([post_offset,-porch_center_y-(round_radius/2),thickness/2])
            connector_housing(2*thickness);
        translate([-post_offset,-porch_center_y-(round_radius/2),thickness])
            connector_housing(2*thickness);
    }
}
// Lampholders
// Inner distance between holders = 6mm
translate([0,0,thickness/2])
    rotate(90,[1,0,0])
        lampholder(bulb_width,lampholder_thickness);
translate([0,6+lampholder_thickness+thickness/2,thickness/2])
    rotate(90,[1,0,0])
      lampholder(bulb_width,thickness);

translate([bulb_width/2-rim/2,porch_center_y/4,0])
    support(rim,porch_center_y/2,6);
translate([-bulb_width/2+rim/2,porch_center_y/4,0])
    support(rim,porch_center_y/2,6);
translate([hex_offset,-porch_center_y,thickness])
    rotate(180,[0,1,0])
        connector(thickness);
translate([-hex_offset,-porch_center_y,0])
    connector(thickness);


c&p AAA version

c&p AAA version

use <battery.scad>

surround        = 15;
height          = 150;
wall            = 2;
batteryDiameter = 15;
batteryLength   = 49;

module channel(h)
{
  // side
  cube([2*wall+batteryDiameter, h, wall]);
  // back wall
  cube([wall, h, batteryLength/2]);
  // front holding
  translate([wall+batteryDiameter, 0, 0])
    cube([wall, h, surround]);
}

module wing()
{
  difference()
  {
    // main channel part
    union()
    {
      channel(height);
      rotate([0,0,60])
        translate([0, -2*batteryDiameter, 0])
          channel(2*batteryDiameter);
    }
    // removal of unnecessary elements
    translate([wall, 0, wall])
      cube([batteryDiameter, 2*batteryDiameter, surround]);
    rotate([0,0,60])
      translate([wall, -2*batteryDiameter, wall])
        cube([batteryDiameter, 2*batteryDiameter, surround]);
    // removal of part from which battery will be extracted
    rotate([0,0,60])
      translate([3*wall, -2*batteryDiameter+wall, wall])
        cube([batteryDiameter, batteryDiameter, surround]);
  }
  rotate([0,0,60])
    translate([0, -2*batteryDiameter, 0])
      cube([2*wall+batteryDiameter, wall, surround]);
}

for(m = [0,1])
{
  mirror([m,0,0])
  {
    translate([5,0,0])
      wing();
    %translate([28, -3, wall+1])
      batteryAAA();
  }
}

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


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


deleting orginal file

deleting orginal file

motor_shaft_r=5;
motor_shaft_h=8;
motor_flange_h = 1;
motor_flange_r = 9.20;
Motor_body_r = 28.00;
Motor_body_h = 19.30;

	///rotate object around to Y access
	rotate([90,0,0]){
	// shaft
		color("grey")
	cylinder(r=motor_shaft_r, h=motor_shaft_h, center=true);
		//flange
		translate([0,0,motor_shaft_h/2])
			color("yellow")
			cylinder(r=motor_flange_r, h=motor_flange_h, center=true);
			// Main Body
				translate([0,-15,14])///don't understand this
					color("silver")
			cylinder(r=Motor_body_r, h=Motor_body_h, center=true);
				//Flanges
					translate([35,-15,4.5]){///don't understand this

					cylinder(r=7, h=1);
							translate([-14,-7,0]){
								cube([14.5,14,1]);
							}
					color("white")
					cylinder(r=4, h=1);

					}
					translate([-35,-15,4.5]){///don't understand this

					cylinder(r=7, h=1);
						translate([0,-7,0]){
								cube([14.5,14,1]);
							}

								color("white")
					cylinder(r=4, h=1);

							}
				  //bottom
				color("blue")
				 translate([0-7,-46,4])
					  cube([14.5,5.5,Motor_body_h]);

}


helper modlues for visualization purposes

use <support.scad>
use <wallMount.scad>

module bothElements()
{
  support();
  wallMount();
}

module closedPosition()
{
  wallMount();
  translate([150, 0, 14.5])
    rotate([0, 180, 0])
      support();
}

module openPosition()
{
  wallMount();
  translate([150, -4, 4])
    rotate([-90, 180, 0])
      support();
}

//%closedPosition();
%openPosition();

//bothElements();

use <support.scad>
use <wallMount.scad>

//support();
//wallMount();

%wallMount();
%translate([150, 0, 14.5])
  rotate([0, 180, 0])
    support();


added scad library

added scad library

/*This helper library was originally created by davidIvann and
can be found in his Parametric Space Truss http://www.thingiverse.com/thing:10642
It allows you to join two points on a plane and add rounded corners
*/
module tube(x1, y1, z1, x2, y2, z2, diameter, faces, thickness_over_width)
{

	length = sqrt( pow(x1 - x2, 2) + pow(y1 - y2, 2) + pow(z1 - z2, 2) );
	alpha = ( (y2 - y1 != 0) ? atan( (z2 - z1) / (y2 - y1) ) : 0 );
	beta = 90 - ( (x2 - x1 != 0) ? atan( (z2 - z1) / (x2 - x1) ) :  0 );
	gamma =  ( (x2 - x1 != 0) ? atan( (y2 - y1) / (x2 - x1) ) : ( (y2 - y1 >= 0) ? 90 : -90 ) ) + ( (x2 - x1 >= 0) ? 0 : -180 );
	// echo(Length = length, Alpha = alpha, Beta = beta, Gamma = gamma);
	translate([x1, y1, z1])
	rotate([ 0, beta, gamma])
		scale([thickness_over_width,1,1])
			rotate([0,0,90]) cylinder(h = length, r = diameter/2, center = false, $fn = faces );
}

module corner(x, y, z, diameter){
	translate([x, y, z])
	sphere( r = diameter/2 );
}
d = 0.35; // tube diameter
f = 6;
t = 0.6;
tube(0,0,0,1,0,0, d,f,t);

error: pathspec 'test_cases/modelReaderTestCase/output/tube.scad' did not match any file(s) known to git


removed dead code and simplified orunder_*surface_() helpers

module rounded_surface_(size, r)
{
  assert(len(size)==2);
  hull()
    for(dx=[r, size[0]-r])
      for(dy=[r, size[1]-r])
        translate([dx, dy, r])
          sphere(r=r, $fn=r*3); // TODO: r*10!
}

module rounded_half_surface_(size, r)
{
  assert(len(size)==2);
  translate([0, 0, -r])
    difference()
    {
      rounded_surface_(size, r);
      cube([size[0], size[1], r]);
    }
}

// element for holding a single brush
module holder(size)
{
  cube([size[0], 7, size[2]]);
  translate([1.5, 7, size[2]-3])
    rotate([-90,0,0])
    {
      cylinder(r=(8-1.5)/2, h=7+2);
      cylinder(r=(3-1)/2, h=14+2);
    }
}

module whole_holder(names)
{
  translate([0, 5+1, -5])
    rotate([90, 0, 0])
      difference()
      {
        rounded_surface_([36, 35], 3);
        cube([36, 5, 3*2]);
      }
  rounded_half_surface_([36, 50], 5);
  translate(1/2*[36, 50, 0]) // TODO: temporary
  {
  for(dx=[-1, +1])
    translate([dx*20/2-1, -1, 2])
      holder([3,25,18]);
  }
}

whole_holder(["John", "Jane"]);
//rounded_surface_([36, 5, 30], 3/2);

//rounded_surface_([30, 20], 3);
//rounded_half_surface_([30, 20], 5);

names=["John", "Jane"];

module rounded_surface_(size)
{
  r=size[2]/2;
  translate([0, 0, r])
    hull()
      for(dx=[r, size[0]-r])
        for(dy=[r, size[1]-r])
          translate([dx, dy, 0])
            sphere(r=r, $fn=r*10); // TODO: r*20!
}

module rounded_half_surface_(size)
{
  translate([0, 0, -size[2]/2])
    difference()
    {
      rounded_surface_(size);
      translate(size[2]/2*[0,0,-1])
        cube(size);
    }
}

corrners = [ [-1,-1,0], [-1,+1,0], [+1,-1,0], [+1,+1,0] ];

// wall-mounted part
module wall(size)
{
  hull()
    difference()
    {
      #for(t = corrners)
      {
        off = [size[0]/2*t[0], size[1]/2*t[1], 0*t[2]];
          translate(off)
            sphere(size[2]);
      };
      translate([0,0,-size[2]]) cube(2*size, center=true);
    }
}

// water drops catching plane
module plane(size)
{
  translate([0, 0, size[1]/2])
    rotate([90,0,0])
      hull()
        for(t = corrners)
        {
          off = [size[0]/2*t[0], size[1]/2*t[1], 0*t[2]];
            translate(off)
              sphere(size[2]);
        };
}

// element for holding a single brush
module holder(size)
{
  cube([size[0], 7, size[2]]);
  translate([1.5, 7, size[2]-3])
    rotate([-90,0,0])
    {
      cylinder(r=(8-1.5)/2, h=7+2);
      cylinder(r=(3-1)/2, h=14+2);
    }
}

module brush_holder()
{
  translate([0, -23.25, 0])
    rotate([90, 0, 0])
      rounded_surface_([36-2*2, 29, 2]);
  translate(1/2*[36, 50, 0]) // TODO: temporary
  {
  translate(-1/2*[36,50, 0])    // TODO: to be removed
    rounded_half_surface_([36, 50, 5]);

  for(dx=[-1, +1])
    translate([dx*20/2-1, -1, 2])
      holder([3,25,18]);
  }
}

brush_holder();

//rounded_surface_([20,30,5]);
//rounded_half_surface_([20,30,5]);


shapes/fncylindera: fix extra_align

shapes/fncylindera: fix extra_align

use <misc.scad>

// translate children
module lineup(arr=undef)
{
    /*echo(arr);*/
    /*echo($children);*/
    if($children>0)
    {
        for (i = [0 : $children-1])
            translate(arr[i]) children(i);
    }
}

module stack(separations)
{
    union()
    {
        for (i = [0:len(separations)-1])
        {
            offset = v_sum(separations,i);
            /*echo("i",i,"offset",offset);*/
            translate ([0,0,offset])
            {
                child(i);
            }
        }
    }
}

module orient(zaxes, roll=0)
{
    zaxes = len(zaxes.x) == undef && zaxes.x != undef? [zaxes] : zaxes;
    for(zaxis=zaxes)
    {
        rotate(_orient_angles(zaxis))
        /*rotate(roll*z)*/
            children();
    }
}

module size_align(size=[10,10,10], align=[0,0,0], orient=[0,0,1])
{
    bounds = _rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1];
    t=hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]);
    translate(t)
    {
        orient(orient)
        {
            children();
        }
    }
}

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module cylindera(h=10, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, align=[0,0,0], extra_h=0,extra_r=undef,extra_d=undef,extra_align=[0,0,0])
{
    extra_r_=(extra_r==undef?0:extra_r);
    extra_d_=(extra_d==undef?0:extra_d);
    extra_sizexy=extra_r_*2 + extra_d_;
    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {
        r_=(r==undef?0:r);
        d_=(d==undef?0:d);
        sizexy=r_*2 + d_;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r+extra_r_, r1=r1, r2=r2, d=d+extra_d_, d1=d1, d2=d2, center=true);
        }
    }
}

module fncylinder(r, r2, d, d2, h, fn, center=false, enlarge=0, fnr=0.8){
    translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
        if (fn==undef) {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            }
        } else {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
            }
        }
    }
}

// specify segment length with fnr, $fn not needed but if desired use fn instead but if desired use fn instead
module fncylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,1],
        fn,
        fnr=0.8,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r_= useDia?d/2:(r==undef?0:r);
    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    sizexy=r_*2;
    extra_sizexy=extra_r_*2;

    // some orient hax here to properly support extra_align
    orient(-orient)
    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align, orient=orient)
    orient(orient)
    {
        fn_=fn==undef?(floor(2*(r_+extra_r_)*pi/fnr)):fn;

        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align, fn_);
        }

        // some orient hax here to properly support extra_align
        orient(-orient)
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true, $fn=fn_);
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

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

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/
/*fncylindera(h=10, r=5, extra_r=2, align=[0,0,1], orient=[1,0,0]);*/

/*fncylindera(h=10, d=5, extra_r=2, align=[0,0,-1], orient=[0,0,1]);*/
/*translate([0,-10,0])*/
/*fncylindera(h=10, d=5, extra_r=2, align=[0,0,1], orient=[0,0,1]);*/
/*translate([0,-20,0])*/
/*fncylindera(h=10, d=10, extra_h=5, orient=[1,0,0], align=[1,0,0], extra_align=[1,0,0]);*/
/*translate([0,-30,0])*/
/*fncylindera(h=10, d=7.5, extra_h=5, orient=[1,0,0], align=[-1,0,0], extra_align=[1,0,0]);*/

use <misc.scad>

// translate children
module lineup(arr=undef)
{
    /*echo(arr);*/
    /*echo($children);*/
    if($children>0)
    {
        for (i = [0 : $children-1])
            translate(arr[i]) children(i);
    }
}

module stack(separations)
{
    union()
    {
        for (i = [0:len(separations)-1])
        {
            offset = v_sum(separations,i);
            /*echo("i",i,"offset",offset);*/
            translate ([0,0,offset])
            {
                child(i);
            }
        }
    }
}

module orient(zaxes, roll=0)
{
    zaxes = len(zaxes.x) == undef && zaxes.x != undef? [zaxes] : zaxes;
    for(zaxis=zaxes)
    {
        rotate(_orient_angles(zaxis))
        /*rotate(roll*z)*/
            children();
    }
}

module size_align(size=[10,10,10], align=[0,0,0], orient=[0,0,1])
{
    bounds = _rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1];
    t=hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]);
    translate(t)
    {
        orient(orient)
        {
            children();
        }
    }
}

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module cylindera(h=10, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, align=[0,0,0], extra_h=0,extra_r=undef,extra_d=undef,extra_align=[0,0,0])
{
    extra_r_=(extra_r==undef?0:extra_r);
    extra_d_=(extra_d==undef?0:extra_d);
    extra_sizexy=extra_r_*2 + extra_d_;
    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {
        r_=(r==undef?0:r);
        d_=(d==undef?0:d);
        sizexy=r_*2 + d_;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r+extra_r_, r1=r1, r2=r2, d=d+extra_d_, d1=d1, d2=d2, center=true);
        }
    }
}

module fncylinder(r, r2, d, d2, h, fn, center=false, enlarge=0, fnr=0.8){
    translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
        if (fn==undef) {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            }
        } else {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
            }
        }
    }
}

// specify segment length with fnr, $fn not needed but if desired use fn instead but if desired use fn instead
module fncylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        fn,
        fnr=0.8,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r_= useDia?d/2:(r==undef?0:r);
    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    extra_sizexy=extra_r_*2;

    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align)
    {
        fn_=fn==undef?(floor(2*(r_+extra_r_)*pi/fnr)):fn;

        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align, fn_);
        }

        sizexy=r_*2;
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true, $fn=fn_);
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

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

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/
/*fncylindera(h=10, r=5, extra_r=2, align=[0,0,1], orient=[1,0,0]);*/


ADENIN

ADENIN


furniture support element

furniture support element

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


liked snap-on upper platform so much, changed lower to use a similar platform

// unified payload electronics mount

Bhole=2.38+.3;  // for brass tube
PCBhole = (25.4*3/32)/2;//1;  // found that 3/32" drill made good pilot for #4 self-piloting screw
include <JansenDefs.scad>;  // Bx
PCBholeSep=37;  // hole pattern for L298 module is a square this wide
PCBholeInset=15;  // from hole center to side of mount

thinWall=.35;//0.41;  // width of thinnest wall which will not get culled by slicer

//translate([0,20,0]) L298mount();

%translate([0,0,  7.8])                 payloadPlatform();
%translate([0,0,-31.5]) rotate([180,0,0]) lowerPlatform();

braceSep = PCBholeInset+PCBholeSep/2;
for(a=[0,180]) rotate([0,0,a]) translate([0,braceSep,0]) rotate([90,0,0])
      payloadBrace();

//translate([0,100,0]) payloadBrace();

//%translate([0,0,-29]) cylinder(r=4,h=31,$fn=4);

// -----------------------------------------------------

module payloadBrace() difference() {
   payloadMount(Bx,Bhole);

   #for(x=[-1,1]) translate([x*Bx,0,-1]) cylinder(r=Bhole,h=44,$fn=25);
   translate([0,0,-4]) cube([200,200,8],center=true);
}

// dovetail tabs for platform
tabZ=4.2;  // offset for tab
module tab(pilotHoleRad=0) difference() {
  cylinder(r1=7,r2=5.5,h=6,$fn=3);

  if (pilotHoleRad > 0.2) {
     translate([0,0,1]) // pilot hole for plastic screw
        #cylinder(r1=pilotHoleRad-.4,r2=pilotHoleRad+.2,h=6,$fn=13);
  }
}
tabCutoutScale = .4/6 + 1;  // want .2 mm space
tabShellScale  =  4/6 + 1;  // want  2 mm space
tabSepUpper=40;
tabSepLower=23;

module payloadPlatform() {
platWidth=100;
  difference() {
    payloadPlatformShell(  platWidth,tabSepUpper); // width, tab seperation
    payloadPlatformCutouts(platWidth,tabSepUpper);
  }
}
module lowerPlatform() {
platWidth=70;
hc=PCBholeSep/2;  // dist for L298N module sqare hole pattern
  difference() {
    payloadPlatformShell(  platWidth,tabSepLower); // width, tab seperation
    difference() {
      payloadPlatformCutouts(platWidth,tabSepLower);
      for(x=[-1,1]) for(y=[-1,1]) translate([x*hc,y*hc,0])
         cylinder(r1=4,r2=3,h=6,$fn=12,center=true);
    }

    // pilot holes for L298N module mount screws
    for(x=[-1,1]) for(y=[-1,1]) translate([x*hc,y*hc,-1])
       cylinder(r1=PCBhole+.3,r2=PCBhole-.2,h=4,$fn=12,center=true);
  }
}

module payloadPlatformCutouts(width=100,tabSep=40) {
  intersection() {
    difference() {
      hull() for(x=[-1,1]) for(y=[-1,1])
         translate([x*(width/2-5),y*(braceSep-5),0])
            cylinder(r1=2,r2=3,h=6,$fn=16,center=true);

      // cutouts for dovetail tabs
      for(a=[0,180]) rotate([0,0,a])
         for(x=[-tabSep,0,tabSep]) translate([x,braceSep-tabZ,-3])
            rotate([0,0,-30]) scale(tabShellScale) tab();
    }
    hexGrid();
  }
}

module hexGrid() {
dh=3.1;
c30=cos(30);  $fn=6;   dx=3*dh;  dy=2*c30*dh;
  translate([3*dh/2,-c30*dh,0])
    for(j=[-5:6]) for(i=[-5:4]) hex(i*dx,j*dy);
    for(j=[-6:6]) for(i=[-5:5]) hex(i*dx,j*dy);
}
module hex(x,y) translate([x,y,0])
   cylinder(r1=2,r2=2.7,h=6,$fn=6,center=true);

// width of platform along axes  (Y width fixed)
// tabSep  -- seperation between tab centers
module payloadPlatformShell(width=100,tabSep=40) {
  intersection() {
    difference() {
      cube([width,2*braceSep,5],center=true);

      // slots for dovetail tabs
      for(a=[0,180]) rotate([0,0,a])
         for(x=[-tabSep,0,tabSep]) translate([x,braceSep-tabZ,-3])
            rotate([0,0,-30]) scale(tabCutoutScale) tab();
    }

    // round off corners
    hull()for(x=[-1,1])for(y=[-1,1])translate([x*(width/2-4),y*(braceSep-4),0])
       scale([4.5,4.5,3.5])sphere(1,$fn=36);
  }
}

module L298mount() intersection() { cube([59,99,4],center=true);

  difference() {
    hull() for(x=[-1,1]) for(y=[-1,PCBholeInset-0.5])
       translate([x*(30-4),y,0])
          scale([4,4,3]) sphere(1,$fn=24);

    hull() {
       translate([0,12,0]) scale([ 9,4,6]) sphere(1,$fn=48);
       translate([0,22,0]) scale([18,1,8]) sphere(1,$fn=48);
    }

    difference() {
      union() {
        translate([0,4,0]) scale([ 5,2.5,5]) sphere(1,$fn=24);

        for(x=[-1,1]) {
          translate([x*PCBholeSep/2,PCBholeInset,-4])
            #cylinder(r=PCBhole,h=9,$fn=15);

          for (y=[6,14]) translate([x*26,y,-4]) cylinder(r=1.6,h=9,$fn=15);

          hull() {
            translate([x*21,7,0]) rotate([0,0,40*x])
                scale([5,1,5]) sphere(1,$fn=36);
            translate([x*22,13,0]) scale([1,2,5]) sphere(1,$fn=16);
          }
          hull() {
            translate([x*11,5,0]) rotate([0,0,30*x])
               scale([4,2,5]) sphere(1,$fn=36);
            translate([x*16,12,0]) scale([2,1,5]) sphere(1,$fn=12);
          }

        }
      }

      cube([99,99,thinWall],center=true); // leave support wall
    }
  }
}

module payloadMount(axisSep,axisRad) {
platOff=-30+2;  // L286 module mount platform offset
    union() {

      for (x=[-1,1]) translate([x*axisSep,0,0])    // axle hubs
           cylinder(r1=axisRad+3,r2=axisRad+2,h=12,$fn=36);

      hull() { // top bar
        translate([0,4.7,4]) cube([2*axisSep,.7,8],center=true);
        translate([0,1.5,0]) cube([2*axisSep,1 ,1],center=true);
      }
      hull() for(x=[-1,1]) translate([axisSep*x,1.1,0.5])
            scale([1,4,1.5]) sphere(1,$fn=16);

      hull() { // lower bar
        translate([0,platOff-.7,4]) cube([60,.6,8],center=true);
        translate([0,platOff+1 ,0]) cube([60,1 ,1],center=true);
      }
      hull() for(x=[-1,1]) translate([31*x,platOff+3,0.3])
            rotate([0,0,-x*40]) scale([1,3.5,1.5]) sphere(1,$fn=16);

      //%translate([0,platOff,0]) rotate([90,0,0]) L298mount();

      for(x=[-1,1]) {  // main side braces
        hull() {
          translate([x*(axisSep+2),-2,2]) scale([1.5,1,9]) sphere(1,$fn=16);
          translate([x*29,platOff ,3]) scale([.5,1,4]) sphere(1,$fn=16);
        }
        hull() {
          translate([x*(axisSep-1),0 ,0.3]) scale([4,1,1.5]) sphere(1,$fn=16);
          translate([x*26,platOff,0.3]) scale([3,1,1.5]) sphere(1,$fn=16);
        }
      }

      // upper platform tabs
      for(x=[-tabSepUpper,0,tabSepUpper]) translate([x,5-1,tabZ])
         rotate([-90,0,0]) rotate([0,0,-30]) tab(PCBhole);

      // lower platform tabs
      for(x=[-tabSepLower,0,tabSepLower]) translate([x,platOff,tabZ])
         rotate([90,0,0]) rotate([0,0,30]) tab(PCBhole);
    }
}

// unified payload electronics mount

Bhole=2.38+.2;  // for brass tube
PCBhole = (25.4*3/32)/2;//1;  // found that 3/32" drill made good pilot for #4 self-piloting screw
include <JansenDefs.scad>;  // Bx
PCBholeSep=37;  // hole pattern for L298 module is a square this wide
PCBholeInset=15;  // from hole center to side of mount

thinWall=.35;//0.41;  // width of thinnest wall which will not get culled by slicer

//translate([0,20,0]) L298mount();

translate([0,0,7.8]) payloadPlatform();

braceSep = PCBholeInset+PCBholeSep/2;
%for(a=[0,180]) rotate([0,0,a]) translate([0,braceSep,0]) rotate([90,0,0])
      payloadBrace();

// -----------------------------------------------------

module payloadBrace() difference() {
   payloadMount(Bx,Bhole);

   #for(x=[-1,1]) translate([x*Bx,0,-1]) cylinder(r=Bhole,h=44,$fn=25);
   translate([0,0,-4]) cube([200,200,8],center=true);
}

// dovetail tabs for platform
tabZ=4.2;  // offset for tab
tabSep=40; // distance between tab centers
module tab() cylinder(r1=7,r2=5.5,h=6,$fn=3);

module payloadPlatform() difference() {
  payloadPlatformShell();
  payloadPlatformCutouts();
}

module payloadPlatformCutouts() {
  intersection() {
    difference() {
      hull() for(x=[-1,1]) for(y=[-1,1]) translate([x*45,y*(braceSep-5),0])
         cylinder(r1=2,r2=3,h=6,$fn=16,center=true);

      // cutouts for dovetail tabs
      for(a=[0,180]) rotate([0,0,a])
         for(x=[-tabSep,0,tabSep]) translate([x,braceSep-tabZ,-3])
            rotate([0,0,-30]) scale(1.8) tab();
    }
    hexGrid();
  }
}

module hexGrid() {
dh=3.1;
c30=cos(30);  $fn=6;   dx=3*dh;  dy=2*c30*dh;
  translate([3*dh/2,-c30*dh,0])
    for(j=[-5:6]) for(i=[-5:4]) hex(i*dx,j*dy);
    for(j=[-6:6]) for(i=[-5:5]) hex(i*dx,j*dy);
}
module hex(x,y) translate([x,y,0])
   cylinder(r1=2,r2=2.6,h=6,$fn=6,center=true);

module payloadPlatformShell() {
  intersection() {
    difference() {
      cube([100,2*braceSep,5],center=true);

      // slots for dovetail tabs
      for(a=[0,180]) rotate([0,0,a])
         for(x=[-tabSep,0,tabSep]) translate([x,braceSep-tabZ,-3])
            rotate([0,0,-30]) scale(1.07) tab();
    }

    // round off corners
    hull()for(x=[-1,1])for(y=[-1,1])translate([x*46,y*(braceSep-4),0])
       scale([4.5,4.5,3.5])sphere(1,$fn=36);
  }
}

module L298mount() intersection() { cube([59,99,4],center=true);

  difference() {
    hull() for(x=[-1,1]) for(y=[-1,PCBholeInset-0.5])
       translate([x*(30-4),y,0])
          scale([4,4,3]) sphere(1,$fn=24);

    hull() {
       translate([0,12,0]) scale([ 9,4,6]) sphere(1,$fn=48);
       translate([0,22,0]) scale([18,1,8]) sphere(1,$fn=48);
    }

    difference() {
      union() {
        translate([0,4,0]) scale([ 5,2.5,5]) sphere(1,$fn=24);

        for(x=[-1,1]) {
          translate([x*PCBholeSep/2,PCBholeInset,-4])
            #cylinder(r=PCBhole,h=9,$fn=15);

          for (y=[6,14]) translate([x*26,y,-4]) cylinder(r=1.6,h=9,$fn=15);

          hull() {
            translate([x*21,7,0]) rotate([0,0,40*x])
                scale([5,1,5]) sphere(1,$fn=36);
            translate([x*22,13,0]) scale([1,2,5]) sphere(1,$fn=16);
          }
          hull() {
            translate([x*11,5,0]) rotate([0,0,30*x])
               scale([4,2,5]) sphere(1,$fn=36);
            translate([x*16,12,0]) scale([2,1,5]) sphere(1,$fn=12);
          }

        }
      }

      cube([99,99,thinWall],center=true); // leave support wall
    }
  }
}

module payloadMount(axisSep,axisRad) {
platOff=-34;  // L286 module mount platform offset
    union() {
      for (x=[-1,1]) //hull() {
        translate([x*axisSep,0,0])
           cylinder(r1=axisRad+3,r2=axisRad+2,h=12,$fn=36);
        //translate([x*(axisSep-14),0,0]) cylinder(r=0.4,h=1,$fn=4); }

      hull() { // top bar
        translate([0,4.7,4]) cube([2*axisSep,.7,8],center=true);
        translate([0,1.5,0]) cube([2*axisSep,1 ,1],center=true);
      }
      hull() for(x=[-1,1]) translate([axisSep*x,1.1,0.5])
            scale([1,4,1.5]) sphere(1,$fn=16);

      translate([0,platOff,0]) rotate([90,0,0]) L298mount();

      for(x=[-1,1]) {  // main side braces
        hull() {
          translate([x*axisSep,0,2]) scale([1.5,1,9]) sphere(1,$fn=16);
          translate([x*28,platOff,2]) scale([1,2,4]) sphere(1,$fn=16);
        }
        hull() {
          translate([x*axisSep,0 ,0.3]) scale([4,1,1.5]) sphere(1,$fn=16);
          translate([x*25,platOff,0.3]) scale([4,1,1.5]) sphere(1,$fn=16);
        }
      }

      for(x=[-tabSep,0,tabSep]) translate([x,5-1,tabZ])
         rotate([-90,0,0]) rotate([0,0,-30]) difference() {
            tab();
            #translate([0,0,1]) // pilot hole for plastic screw
               cylinder(r1=PCBhole-.4,r2=PCBhole+.2,h=6,$fn=13);
         }
    }
}


misc: add v_cumsum

misc: add v_cumsum

use <scad-utils/linalg.scad>
use <scad-utils/lists.scad>

function posvec(path_vec) = [for(v=path_vec) translation_part(v)];
function posvec_x(path_vec) = [for(v=path_vec) translation_part(v)[0]];
function posvec_y(path_vec) = [for(v=path_vec) translation_part(v)[1]];
function posvec_z(path_vec) = [for(v=path_vec) translation_part(v)[2]];

function vec_i(v3,i) = [for(v=v3) v[i]];
function vec_0(v3) = vec_i(v3,0);
function vec_1(v3) = vec_i(v3,1);
function vec_2(v3) = vec_i(v3,2);

function vec_add(vec,v) = [for(vv=vec) vv+v];

function v_itrlen(vec) = [0:1:len(vec)-1];

function range1(v1) = [min(v1), max(v1)];
function range3(v3) = [range1(vec_0(v3)), range1(vec_1(v3)), range1(vec_2(v3))];
function bbox(r) = [ [r[0][0],r[1][0],r[2][0]], [r[0][1],r[1][1],r[2][1]] ];
function transform_pp(vec_m, t_pre, t_post) = [for(m=vec_m) (t_pre*m)*t_post];
function transform_pre(vec_m, t) = [for(m=vec_m) t*m];
function transform_post(vec_m, t) = [for(m=vec_m) m*t];

// sum a vector up to position i
function v_sum(v, i) = i >= 0 ? v[i] + sum_vec(v, i - 1) : 0;

// cumulative sum of vector [1,2,3] = [1,3,6]
function v_cumsum(v, start=0) = [for(i=[start:1:len(v)-1]) sum_vec(v,i)];

// filter/remove a val from a vec
function filter(vec,val=undef) = [for(v=vec) if(v!=val) v];

function vec_pair_double_transform_post(vec,t1,t2)=
    flatten(
        [for(v=vec)
            [transform_post(v,t1),transform_post(v,t2)]
        ]);

function vec_pair_double(vec)=flatten([for(v=vec) [v,v] ]);

use <scad-utils/linalg.scad>
use <scad-utils/lists.scad>

function posvec(path_vec) = [for(v=path_vec) translation_part(v)];
function posvec_x(path_vec) = [for(v=path_vec) translation_part(v)[0]];
function posvec_y(path_vec) = [for(v=path_vec) translation_part(v)[1]];
function posvec_z(path_vec) = [for(v=path_vec) translation_part(v)[2]];

function vec_i(v3,i) = [for(v=v3) v[i]];
function vec_0(v3) = vec_i(v3,0);
function vec_1(v3) = vec_i(v3,1);
function vec_2(v3) = vec_i(v3,2);

function vec_add(vec,v) = [for(vv=vec) vv+v];

function v_itrlen(vec) = [0:1:len(vec)-1];

function range1(v1) = [min(v1), max(v1)];
function range3(v3) = [range1(vec_0(v3)), range1(vec_1(v3)), range1(vec_2(v3))];
function bbox(r) = [ [r[0][0],r[1][0],r[2][0]], [r[0][1],r[1][1],r[2][1]] ];
function transform_pp(vec_m, t_pre, t_post) = [for(m=vec_m) (t_pre*m)*t_post];
function transform_pre(vec_m, t) = [for(m=vec_m) t*m];
function transform_post(vec_m, t) = [for(m=vec_m) m*t];

// sum a vector up to position i
function v_sum(v, i) = i >= 0 ? v[i] + sum_vec(v, i - 1) : 0;

// filter/remove a val from a vec
function filter(vec,val=undef) = [for(v=vec) if(v!=val) v];

function vec_pair_double_transform_post(vec,t1,t2)=
    flatten(
        [for(v=vec)
            [transform_post(v,t1),transform_post(v,t2)]
        ]);

function vec_pair_double(vec)=flatten([for(v=vec) [v,v] ]);


mods to make it a little more useful once full size

el = 46.1; // edge length at max radius
ft = 2; // flake thickness
cmt = el / 4; // crystal max thickness
xw = 3; // extrude width
nc = 18; // number of crystals
bw = 4; // backbone width

pn = "Test"; // person name

make_2d = true; // set to true for 2d output (e.g. DXF)

//rs = floor(rands(0,pow(10,6),1)[0]); // random number seed.
//rs = 1416261; // Uncomment to get a consistent snowflake
rs = 78278400;

echo("Random number seed: ", rs);
echo("Name: ", pn);
echo("Edge length: ", el);

cit = xw; // crystal min thickness
th = sqrt(3) * el/2; // triangle height

// random vector (x, y, length, direction, thickness)
rv = rands(0,1,nc*5, seed_value = rs);

// the idea on how to do this is loosely based on origami snowflakes as at:
// http://www.marthastewart.com/276331/how-to-make-paper-snowflakes
// combined with Wilson Bentley's observations of snowflakes
// http://en.wikipedia.org/wiki/Wilson_Bentley

module flake_part(){
	rotate([0,0,30]) translate([0,-el/2,0])
		square([bw,el], center = true);
	for(i = [0:nc-1]){
		assign(yr = sqrt(rv[i*4]),
		   xr = rv[i*4+1] * sqrt(rv[i*4]),
		   rt = (rv[i*4+2]<(1/3))?0:(rv[i*4+2]<(2/3))?60:120,
		   sl = rv[i*4+3],
		   ct = (rv[i*4+4])*(rv[i*4+4])){
			if(((rt != 120) || (yr + sl/2 < 1)) && (sl*el/2 > xw)){
				translate([xr*el/2, -yr*th,0]) rotate(rt)
					square([sl*el/2, cit + max(0,cmt*ct/2-cit)],
					   center = true, $fa = 60);
			}
		}
	}
}

if(make_2d){
    translate([el, el]) {
        for(ri = [0:60:300]){
            rotate([0,0,ri]) flake_part();
            rotate([0,180,ri]) flake_part();
        }
        translate ([el, el]) {
            text(pn, size=1.5);
        }
    }
} else {
	linear_extrude(height=ft){
		for(ri = [0:60:300]){
			rotate([0,0,ri]) flake_part();
			rotate([0,180,ri]) flake_part();
		}
	}
}

echo("Done!");

el = 46.1; // edge length at max radius
ft = 2; // flake thickness
cmt = el / 5; // crystal max thickness
xw = 2; // extrude width
nc = 18; // number of crystals
bw = 2; // backbone width

pn = "Test"; // person name

make_2d = true; // set to true for 2d output (e.g. DXF)

//rs = floor(rands(0,pow(10,6),1)[0]); // random number seed.
//rs = 1416261; // Uncomment to get a consistent snowflake
rs = 16120121;

echo("Random number seed: ", rs);
echo("Name: ", pn);
echo("Edge length: ", el);

cit = xw; // crystal min thickness
th = sqrt(3) * el/2; // triangle height

// random vector (x, y, length, direction, thickness)
rv = rands(0,1,nc*5, seed_value = rs);

// the idea on how to do this is loosely based on origami snowflakes as at:
// http://www.marthastewart.com/276331/how-to-make-paper-snowflakes
// combined with Wilson Bentley's observations of snowflakes
// http://en.wikipedia.org/wiki/Wilson_Bentley

module flake_part(){
	rotate([0,0,30]) translate([0,-el/2,0])
		square([bw,el], center = true);
	for(i = [0:nc-1]){
		assign(yr = sqrt(rv[i*4]),
		   xr = rv[i*4+1] * sqrt(rv[i*4]),
		   rt = (rv[i*4+2]<(1/3))?0:(rv[i*4+2]<(2/3))?60:120,
		   sl = rv[i*4+3],
		   ct = (rv[i*4+4])*(rv[i*4+4])){
			if(((rt != 120) || (yr + sl/2 < 1)) && (sl*el/2 > xw)){
				translate([xr*el/2, -yr*th,0]) rotate(rt)
					square([sl*el/2, cit + max(0,cmt*ct/2-cit)],
					   center = true, $fa = 60);
			}
		}
	}
}

if(make_2d){
    translate([el, el]) {
        for(ri = [0:60:300]){
            rotate([0,0,ri]) flake_part();
            rotate([0,180,ri]) flake_part();
        }
        translate ([el, el]) {
            text(pn, size=1.5);
        }
    }
} else {
	linear_extrude(height=ft){
		for(ri = [0:60:300]){
			rotate([0,0,ri]) flake_part();
			rotate([0,180,ri]) flake_part();
		}
	}
}

echo("Done!");


added mounting panels on sides

added mounting panels on sides


xaxis/ends: fix bug, used wrong bearing

xaxis/ends: fix bug, used wrong bearing

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

include <config.scad>
include <thing_libutils/misc.scad>
include <thing_libutils/bearing.scad>
use <thing_libutils/metric-screw.scad>

motor_mount_wall_thick = xaxis_pulley[1] - xaxis_pulley[0]/2 + 4*mm;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+9*mm,motor_mount_wall_thick-2*mm,0];
xaxis_end_wz = xaxis_rod_distance+zaxis_bearing[2]+5*mm;

module xaxis_end_body(with_motor, nut_top=false)
{
    x_side = with_motor?1:-1;
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;

    /*%rcubea([wx_, xaxis_rod_d*2, xaxis_end_wz], rounding_radius=3, align=[with_motor?1:-1,0,0]);*/

    if(with_motor)
    translate(xaxis_end_motor_offset)
    rcubea([xaxis_end_motorsize, motor_mount_wall_thick, xaxis_end_motorsize], rounding_radius=3, align=[0,-1,0]);

    // nut mount
    mirror([0,0,nut_top?1:0])
    translate([x_side*zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
    {
        union()
        {
            cylindera(h=zaxis_nut[4], d=zaxis_nut[1], align=[0,0,1]);

            // lead screw
            // ensure some support for the leadscrew cutout all the way to the top
            /*cylindera(h=xaxis_end_wz, d=zaxis_nut[2]*2, align=[0,0,1]);*/
        }
    }

    // x axis rod holders
    for(z=[-1,1])
    translate([0,0,z*(xaxis_rod_distance/2)])
        cylindera(h=wx_,d=xaxis_rod_d+5*mm, orient=[1,0,0], align=[x_side,0,0]);

    // support around z axis bearings
    translate([0, -xaxis_zaxis_distance_y, 0])
    {
        difference()
        {
            sizey= zaxis_bearing[1]+10*mm;
            cylindera(h=xaxis_end_wz,d=sizey, orient=[0,0,1], align=[0,0,0]);
            translate([0,0,.1])
            cubea([sizey/2+.1, sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[-x_side,0,0]);
        }
    }
}

module xaxis_end(with_motor=false, show_motor=false, nut_top=false, show_nut=false, show_rods=false)
{
    x_side = with_motor?1:-1;
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;
    difference()
    {
        extrasize = with_motor?0*mm:0*mm;
        extrasize_align = with_motor?-1:1;

        hull()
        {
            xaxis_end_body(with_motor, nut_top);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(with_motor);
        }

        xaxis_end_beltpath();

        // z smooth bearing mounts
        for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
                translate([0, -xaxis_zaxis_distance_y, 0])
                bearing_mount_holes(
                        zaxis_bearing,
                        ziptie_type,
                        ziptie_bearing_distance,
                        orient=[0,0,1],
                        show_zips=false
                );

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

        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);

            // axle
            translate(xaxis_end_motor_offset)
            {
                round_d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor);
                translate([0, .1, 0])
                translate([0,1,0])

                cylindera(d=round_d, h=motor_mount_wall_thick, orient=[0,1,0], align=[0,1,0]);
                rotate([0,45,0])
                difference()
                {
                    cubea([round_d, motor_mount_wall_thick, round_d], align=[0,-1,0]);

                    cubea([round_d, motor_mount_wall_thick, round_d/2], align=[0,-1,-1]);
                    cubea([round_d/2, motor_mount_wall_thick, round_d], align=[1,-1,0]);
                }

                // motor axle
                translate([0, .1, 0])
                cylindera(d=1.2*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor)+3*mm, orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -2.5*mm-xaxis_pulley[1]-.1, 0])
                scale(1.03)
                bearing(bearing_MR105, override_h=6*mm, orient=[0,1,0], align=[0,-1,0]);

                xaxis_motor_thread=ThreadM3;
                xaxis_motor_nut=MHexNutM3;
                for(x=[-1,1])
                for(z=[-1,1])
                translate([x*screw_dist/2, -motor_mount_wall_thick, z*screw_dist/2])
                {
                    screw_cut(xaxis_motor_nut, h=motor_mount_wall_thick, with_nut=false, orient=[0,1,0], align=[0,1,0]);
                }
            }

        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([x_side*zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            union()
            {
                translate([0,0,-.1])
                {
                    // nut
                    cylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    cylindera(h=xaxis_end_wz+1, d=zaxis_nut[2]*1.5, align=[0,0,1]);

                    for(i=[-1,1])
                        translate([i*13.5, 0, 0])
                            cylindera(h=5, r=1.6, align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_motor)
    {
            /*translate([0,5,0])*/
        translate(xaxis_end_motor_offset)
        {
            /*translate([0,-motor_mount_wall_thick,0])*/
            /*translate([0,-5,0])*/
            /*translate([0,-xaxis_pulley[0]/2,0])*/

            // 1mm due to motor offset
            translate([0,-1*mm,0])
            {
                // 1mm between pulley and motor
                /*translate([0,-1*mm,0])*/
                    /*pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);*/
                /*motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);*/
            }
        }
    }

    %if(show_nut)
    {
        mirror([0,0,nut_top?1:0])
        translate([x_side*zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2-zaxis_nut[3]])
        xaxis_end_znut();
    }

    %if(show_rods)
    {
        for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            cylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
    }
}

module xaxis_end_beltpath(xaxis_end_beltpath_length=1000)
{
    diag = pythag_hyp(xaxis_beltpath_width,xaxis_beltpath_width)/2;

    /*cubea([xaxis_end_beltpath_length, xaxis_beltpath_width, xaxis_beltpath_height+diag/2]);*/

    hull()
    for(z=[-1,1])
    translate([0,0,z*xaxis_beltpath_height/2])
    translate([-diag/2,0,0])
    translate([diag/2,0,0])
    rotate([z*-45,0,0])
    cubea([xaxis_end_beltpath_length, diag, diag]);
}

module xaxis_end_idlerholder(xaxis_end_beltpath_length=10)
{
    diag = pythag_hyp(xaxis_beltpath_width,xaxis_beltpath_width)/2;

    difference()
    {
        union()
        {
            cubea([10*mm, xaxis_beltpath_width/sqrt(2), xaxis_rod_distance], align=[1,0,0]);

            translate([10*mm, 0,0])
                cubea([15*mm, xaxis_idler_pulley[0]+8*mm, xaxis_rod_distance+xaxis_rod_d*2], align=[1,0,0]);
        }

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

        translate([20,0,0])
            pulley(xaxis_idler_pulley, orient=[0,1,0]);

        translate([10*mm+15*mm/2,0,0])
        cylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

        xaxis_end_beltpath();
    }
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            cylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }
        translate([0,0,-.1])
            cylindera(d=zaxis_nut[2], h=zaxis_nut[4]+.2, orient=[0,0,1], align=[0,0,1]);
    }
}

if(false)
{
    // x smooth rods
    for(z=[-1,1])
        translate([0,0,z*(xaxis_rod_distance/2)])
            %cylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);

    xaxis_end(with_motor=true, show_motor=false, nut_top=false, show_nut=true, show_rods=true);

    translate([150,0,0])
    {
        xaxis_end(with_motor=false, show_motor=true, nut_top=false, show_nut=true, show_rods=true);
        xaxis_end_idlerholder();
    }
}

if(false)
{
    /*translate([0,0,xaxis_end_wz/2])*/
    /*xaxis_end(with_motor=true, show_motor=true, show_nut=false);*/

    translate([100,0,xaxis_end_wz/2])
    xaxis_end(with_motor=false, show_nut=false);

    /*translate([50,30,25])*/
        /*rotate([0,90,0])*/
        /*xaxis_end_idlerholder();*/
}

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

include <config.scad>
include <thing_libutils/misc.scad>
include <thing_libutils/bearing.scad>
use <thing_libutils/metric-screw.scad>

motor_mount_wall_thick = xaxis_pulley[1] - xaxis_pulley[0]/2 + 4*mm;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+9*mm,motor_mount_wall_thick-2*mm,0];
xaxis_end_wz = xaxis_rod_distance+xaxis_bearing[2]+5*mm;

module xaxis_end_body(with_motor, nut_top=false)
{
    x_side = with_motor?1:-1;
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;

    /*%rcubea([wx_, xaxis_rod_d*2, xaxis_end_wz], rounding_radius=3, align=[with_motor?1:-1,0,0]);*/

    if(with_motor)
    translate(xaxis_end_motor_offset)
    rcubea([xaxis_end_motorsize, motor_mount_wall_thick, xaxis_end_motorsize], rounding_radius=3, align=[0,-1,0]);

    // nut mount
    mirror([0,0,nut_top?1:0])
    translate([x_side*zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
    {
        union()
        {
            cylindera(h=zaxis_nut[4], d=zaxis_nut[1], align=[0,0,1]);

            // lead screw
            // ensure some support for the leadscrew cutout all the way to the top
            /*cylindera(h=xaxis_end_wz, d=zaxis_nut[2]*2, align=[0,0,1]);*/
        }
    }

    // x axis rod holders
    for(z=[-1,1])
    translate([0,0,z*(xaxis_rod_distance/2)])
        cylindera(h=wx_,d=xaxis_rod_d+5*mm, orient=[1,0,0], align=[x_side,0,0]);

    // support around z axis bearings
    translate([0, -xaxis_zaxis_distance_y, 0])
    {
        difference()
        {
            sizey= zaxis_bearing[1]+10*mm;
            cylindera(h=xaxis_end_wz,d=sizey, orient=[0,0,1], align=[0,0,0]);
            translate([0,0,.1])
            cubea([sizey/2+.1, sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[-x_side,0,0]);
        }
    }
}

module xaxis_end(with_motor=false, show_motor=false, nut_top=false, show_nut=false, show_rods=false)
{
    x_side = with_motor?1:-1;
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;
    xaxis_end_wz = xaxis_rod_distance+xaxis_bearing[2]+5*mm;
    difference()
    {
        extrasize = with_motor?0*mm:0*mm;
        extrasize_align = with_motor?-1:1;

        hull()
        {
            xaxis_end_body(with_motor, nut_top);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(with_motor);
        }

        xaxis_end_beltpath();

        // z smooth bearing mounts
        for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
                translate([0, -xaxis_zaxis_distance_y, 0])
                bearing_mount_holes(
                        zaxis_bearing,
                        ziptie_type,
                        ziptie_bearing_distance,
                        orient=[0,0,1],
                        show_zips=false
                );

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

        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);

            // axle
            translate(xaxis_end_motor_offset)
            {
                round_d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor);
                translate([0, .1, 0])
                translate([0,1,0])

                cylindera(d=round_d, h=motor_mount_wall_thick, orient=[0,1,0], align=[0,1,0]);
                rotate([0,45,0])
                difference()
                {
                    cubea([round_d, motor_mount_wall_thick, round_d], align=[0,-1,0]);

                    cubea([round_d, motor_mount_wall_thick, round_d/2], align=[0,-1,-1]);
                    cubea([round_d/2, motor_mount_wall_thick, round_d], align=[1,-1,0]);
                }

                // motor axle
                translate([0, .1, 0])
                cylindera(d=1.2*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor)+3*mm, orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -2.5*mm-xaxis_pulley[1]-.1, 0])
                scale(1.03)
                bearing(bearing_MR105, override_h=6*mm, orient=[0,1,0], align=[0,-1,0]);

                xaxis_motor_thread=ThreadM3;
                xaxis_motor_nut=MHexNutM3;
                for(x=[-1,1])
                for(z=[-1,1])
                translate([x*screw_dist/2, -motor_mount_wall_thick, z*screw_dist/2])
                {
                    screw_cut(xaxis_motor_nut, h=motor_mount_wall_thick, with_nut=false, orient=[0,1,0], align=[0,1,0]);
                }
            }

        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([x_side*zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            union()
            {
                translate([0,0,-.1])
                {
                    // nut
                    cylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    cylindera(h=xaxis_end_wz+1, d=zaxis_nut[2]*1.5, align=[0,0,1]);

                    for(i=[-1,1])
                        translate([i*13.5, 0, 0])
                            cylindera(h=5, r=1.6, align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_motor)
    {
            /*translate([0,5,0])*/
        translate(xaxis_end_motor_offset)
        {
            /*translate([0,-motor_mount_wall_thick,0])*/
            /*translate([0,-5,0])*/
            /*translate([0,-xaxis_pulley[0]/2,0])*/

            // 1mm due to motor offset
            translate([0,-1*mm,0])
            {
                // 1mm between pulley and motor
                /*translate([0,-1*mm,0])*/
                    /*pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);*/
                /*motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);*/
            }
        }
    }

    %if(show_nut)
    {
        mirror([0,0,nut_top?1:0])
        translate([x_side*zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2-zaxis_nut[3]])
        xaxis_end_znut();
    }

    %if(show_rods)
    {
        for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            cylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
    }
}

module xaxis_end_beltpath(xaxis_end_beltpath_length=1000)
{
    diag = pythag_hyp(xaxis_beltpath_width,xaxis_beltpath_width)/2;

    /*cubea([xaxis_end_beltpath_length, xaxis_beltpath_width, xaxis_beltpath_height+diag/2]);*/

    hull()
    for(z=[-1,1])
    translate([0,0,z*xaxis_beltpath_height/2])
    translate([-diag/2,0,0])
    translate([diag/2,0,0])
    rotate([z*-45,0,0])
    cubea([xaxis_end_beltpath_length, diag, diag]);
}

module xaxis_end_idlerholder(xaxis_end_beltpath_length=10)
{
    diag = pythag_hyp(xaxis_beltpath_width,xaxis_beltpath_width)/2;

    difference()
    {
        union()
        {
            cubea([10*mm, xaxis_beltpath_width/sqrt(2), xaxis_rod_distance], align=[1,0,0]);

            translate([10*mm, 0,0])
                cubea([15*mm, xaxis_idler_pulley[0]+8*mm, xaxis_rod_distance+xaxis_rod_d*2], align=[1,0,0]);
        }

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

        translate([20,0,0])
            pulley(xaxis_idler_pulley, orient=[0,1,0]);

        translate([10*mm+15*mm/2,0,0])
        cylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

        xaxis_end_beltpath();
    }
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            cylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }
        translate([0,0,-.1])
            cylindera(d=zaxis_nut[2], h=zaxis_nut[4]+.2, orient=[0,0,1], align=[0,0,1]);
    }
}

if(false)
{
    // x smooth rods
    for(z=[-1,1])
        translate([0,0,z*(xaxis_rod_distance/2)])
            %cylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);

    xaxis_end(with_motor=true, show_motor=false, nut_top=false, show_nut=true, show_rods=true);

    translate([150,0,0])
    {
        xaxis_end(with_motor=false, show_motor=true, nut_top=false, show_nut=true, show_rods=true);
        xaxis_end_idlerholder();
    }
}

if(false)
{
    /*translate([0,0,xaxis_end_wz/2])*/
    /*xaxis_end(with_motor=true, show_motor=true, show_nut=false);*/

    translate([100,0,xaxis_end_wz/2])
    xaxis_end(with_motor=false, show_nut=false);

    /*translate([50,30,25])*/
        /*rotate([0,90,0])*/
        /*xaxis_end_idlerholder();*/
}


xaxis/ends/debug: fix idlerholder position

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

include <config.scad>
include <thing_libutils/misc.scad>
include <thing_libutils/bearing.scad>
use <thing_libutils/metric-screw.scad>
use <thing_libutils/timing-belts.scad>

motor_mount_wall_thick = xaxis_pulley[1] - xaxis_pulley[0]/2 + 4*mm;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+7*mm,motor_mount_wall_thick-2*mm,0];
xaxis_end_wz = xaxis_rod_distance+zaxis_bearing[2]+5*mm;

// overlap of the X and Z rods
xaxis_end_xz_rod_overlap = 4*mm;

// how much "stop" for the x rods
xaxis_end_rod_stop = 10*mm;

xaxis_endstop_size = [10.3*mm, 20*mm, 6.3*mm];
xaxis_endstop_screw_offset = [-1.8*mm, 0*mm, 0*mm];

module xaxis_end_body(with_motor, beltpath_index=0, nut_top=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;

    /*%rcubea([wx_, xaxis_rod_d*2, xaxis_end_wz], rounding_radius=3, align=[with_motor?1:-1,0,0]);*/

    if(with_motor)
    translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
    translate(xaxis_end_motor_offset)
    rcubea([xaxis_end_motorsize, motor_mount_wall_thick, xaxis_end_motorsize], rounding_radius=3, align=[0,-1,0]);

    // nut mount
    mirror([0,0,nut_top?1:0])
    translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
    {
        union()
        {
            difference()
            {
                cylindera(h=zaxis_nut[4], d=zaxis_nut[1], align=[0,0,1]);
                translate([0,-zaxis_nut[0]/2-1*mm,0])
                cubea([zaxis_nut[4]*2,zaxis_nut[4]+.2,zaxis_nut[4]+.2], align=[0,-1,1]);
            }

            // lead screw
            // ensure some support for the leadscrew cutout all the way to the top
            /*cylindera(h=xaxis_end_wz, d=zaxis_nut[2]*2, align=[0,0,1]);*/
        }
    }

    // x axis rod holders
    xaxis_rod_d_support = xaxis_rod_d+5*mm;
    for(z=[-1,1])
    translate([-xaxis_end_xz_rod_overlap,0,z*(xaxis_rod_distance/2)])
    cylindera(h=wx_+xaxis_end_xz_rod_overlap, d=xaxis_rod_d_support, orient=[1,0,0], align=[1,0,0]);

    translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
    {
        rcubea(xaxis_endstop_size, align=[-1,0,-1]);
    }

    // support around z axis bearings
    translate([0, -xaxis_zaxis_distance_y, 0])
    {
        difference()
        {
            sizey= zaxis_bearing[1]+10*mm;
            cylindera(h=xaxis_end_wz,d=sizey, orient=[0,0,1], align=[0,0,0]);
            translate([0,0,.1])
            cubea([sizey/2+.1, sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[-1,0,0]);
            /*#cubea([sizey+.1, sizey/2+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[0,-1,0]);*/
        }
    }
}

module xaxis_end(with_motor=false, stop_x_rods=false, beltpath_index=0, show_motor=false, nut_top=false, show_nut=false, show_rods=false, show_bearings=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;
    difference()
    {
        extrasize = with_motor?0*mm:0*mm;
        extrasize_align = 1;

        hull()
        {
            xaxis_end_body(with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(with_motor);
        }

        //endstop mount screw cuts
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        translate(xaxis_endstop_screw_offset)
        for(y=[-1,1])
        translate([-5*mm,y*9.5*mm/2,-2*mm])
        nut_trap_cut(nut=MHexNutM3, screw_l=6*mm, screw_l_extra=0*mm, trap_axis=[-1,0,0], orient=[0,0,1], align=[0,0,-1]);

        xaxis_end_beltpath(height=xaxis_beltpath_height_body);

        // z smooth bearing mounts
        for(z=[-1,1])
        {
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            {
                bearing_mount_holes(
                        zaxis_bearing,
                        ziptie_type,
                        ziptie_bearing_distance,
                        orient=[0,0,1],
                        with_zips=true,
                        show_zips=false
                        );
                /*hull()*/
                /*{*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/

                    /*translate([-5*cm,0,0])*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/
                /*}*/
            }
        }

        // x smooth rods
        x_rod_stop = stop_x_rods ? xaxis_end_rod_stop : 0;
        for(z=[-1,1])
        translate([-xaxis_end_xz_rod_overlap-.1+x_rod_stop,0,z*(xaxis_rod_distance/2)])
        cylindera(h=wx_+xaxis_end_xz_rod_overlap-x_rod_stop+.2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);

            // axle
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                round_d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor);
                translate([0, .1, 0])
                translate([0,1,0])
                teardrop(d=round_d,h=motor_mount_wall_thick, tear_orient=[0,0,1], orient=[0,1,0], align=[0,-1,0], roll=90, truncate=0);

                // motor axle
                translate([0, .1, 0])
                cylindera(d=1.2*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor)+3*mm, orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -2.5*mm-xaxis_pulley[1]-.1, 0])
                scale(1.03)
                cylindera(d=bearing_MR105[1], h=6*mm, orient=[0,1,0], align=[0,-1,0]);

                xaxis_motor_thread=ThreadM3;
                xaxis_motor_nut=MHexNutM3;
                for(x=[-1,1])
                for(z=[-1,1])
                translate([0,-xaxis_end_motor_offset[1],0])
                translate([x*screw_dist/2, -(xaxis_beltpath_width/2+4*mm), z*screw_dist/2])
                {
                    screw_cut(xaxis_motor_nut, h=25, with_nut=false, orient=[0,1,0], align=[0,1,0]);
                }
            }

        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            union()
            {
                translate([0,0,-.1])
                {
                    // nut
                    cylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    cylindera(h=lookup(NemaFrontAxleLength,zaxis_motor), d=zaxis_nut[2]*1.5, align=[0,0,1]);

                    for(i=[-1,1])
                    translate([i*13.5*mm, 0, -zaxis_nut[3]])
                    screw_cut(thread=ThreadM3, h=16*mm, with_nut=false, orient=[0,0,1], align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_motor)
    {
        translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
        translate(xaxis_end_motor_offset)
        {
            // 1mm due to motor offset
            translate([0,-1*mm,0])
            {
                // 1mm between pulley and motor
                translate([0,-1*mm,0])
                    pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);
                motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
            }
        }
    }

    //endstop
    %if($show_vit)
    {
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        {
            difference()
            {
                rcubea(xaxis_endstop_size, align=[-1,0,1]);

                translate(xaxis_endstop_screw_offset)
                for(y=[-1,1])
                translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size[2]])
                screw_cut(nut=MHexNutM3, h=10*mm, orient=[0,0,-1], align=[0,0,-1]);
            }
        }
    }

    %if(show_nut)
    {
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2-zaxis_nut[3]])
        xaxis_end_znut();
    }

    %if(show_rods)
    {
        for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            cylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
    }

    %if(show_bearings)
    {
        for(z=[-1,1])
        translate([0,0,z*xaxis_rod_distance/2])
        translate([0, -xaxis_zaxis_distance_y, 0])
        bearing(zaxis_bearing);
    }
}

module xaxis_end_beltpath(height, width=xaxis_beltpath_width, length = 1000)
{
    hull()
    for(z=[-1,1])
    translate([0,0,z*height/2])
    teardrop(h=length, d=width, orient=[1,0,0], roll=-180*min(0,z), truncate=.5);
}

module xaxis_end_idlerholder(part, width=xaxis_beltpath_width, length=10, beltpath_index=0)
{
    width = 20*mm;

    if(part==undef)
    {
        difference()
        {
            xaxis_end_idlerholder(part="pos", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
            xaxis_end_idlerholder(part="neg", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
        }
    }
    else if(part=="pos")
    {
        union()
        {
            /*translate([10*mm, 0,0])*/
            rcubea([width, xaxis_idler_pulley[0]+8*mm, xaxis_rod_distance+xaxis_rod_d*2], align=[1,0,0]);
        }
    }
    else if(part=="neg")
    {
        for(z=[-1,1])
        {
            translate([0,0,z*(xaxis_rod_distance/2)])
            {
                // x smooth rods
                translate([width/2+.1,0,0])
                cylindera(h=width/2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

                screw_cut(nut=MHexNutM4, h=16*mm, with_nut=false, orient=[1,0,0], align=[1,0,0]);

                translate([6*mm,0,0])
                nut_trap_cut(nut=MHexNutM4, screw_l=16*mm, trap_axis=[0,-1,0], orient=[1,0,0], $show_vit=false);
            }
        }

        translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([width/2,0,0])
                pulley(xaxis_idler_pulley, orient=[0,1,0]);

            translate([width/2,0,0])
                cylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

            xaxis_end_beltpath(height=xaxis_beltpath_height_holders);
        }
    }
    else if(part=="vit")
    {
    }
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            cylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }

        translate([0,0,-.1])
        cylindera(d=zaxis_nut[2], h=zaxis_nut[4]+.2, orient=[0,0,1], align=[0,0,1]);
    }
}

include <thing_libutils/misc.scad>;
if(false)
{
    // x axis
    /*translate([0,0,axis_pos_z])*/
    {
        /*if(!preview_mode)*/
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(z=[-1,1])
            for(z=xaxis_beltpath_z_offsets)
            translate([-z*3*mm, xaxis_zaxis_distance_y, z])
            belt_path(5*mm+main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[0,0,0]);
        }

        /*translate([axis_pos_x,0,0])*/
        /*{*/
            // x carriage
            /*attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])*/
            /*{*/
                /*x_carriage_full();*/
            /*}*/
        /*}*/

        // x smooth rods
        color(color_rods)
        for(z=[-1,1])
            translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
                cylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);

        for(x=[-1,1])
        {
            translate([x*(main_width/2), 0, 0])
            {
                translate([0, xaxis_zaxis_distance_y, 0])
                translate([x*zmotor_mount_rod_offset_x, 0, 0])
                mirror([max(0,x),0,0])
                xaxis_end(with_motor=true, beltpath_index=max(0,x), show_nut=true, show_motor=true, show_nut=true);

                translate([x*95, xaxis_zaxis_distance_y, 0])
                mirror([0,0,max(0,x)])
                mirror([max(0,x),0,0])
                xaxis_end_idlerholder();
            }
        }
    }

}

if(false)
{
    zrod_offset = zmotor_mount_rod_offset_x;
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    translate([0,0,xaxis_end_wz/2])
    translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
    belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);

    translate([0, xaxis_zaxis_distance_y, 0])
    {
        for(x=[-1,1])
        translate([x*55,0,xaxis_end_wz/2])
        mirror([max(0,x),0,0])
        xaxis_end(with_motor=true, beltpath_index=max(0,x), show_motor=false, show_nut=false, show_bearings=false);

        for(x=[-1,1])
        translate([0,0,xaxis_end_wz/2])
        translate([x*45,25,0])
        translate([x*105,0,0])
        mirror([max(0,x),0,0])
        rotate([0,-90,0])
        xaxis_end_idlerholder(beltpath_index=max(0,x));
    }
}

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

include <config.scad>
include <thing_libutils/misc.scad>
include <thing_libutils/bearing.scad>
use <thing_libutils/metric-screw.scad>
use <thing_libutils/timing-belts.scad>

motor_mount_wall_thick = xaxis_pulley[1] - xaxis_pulley[0]/2 + 4*mm;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+7*mm,motor_mount_wall_thick-2*mm,0];
xaxis_end_wz = xaxis_rod_distance+zaxis_bearing[2]+5*mm;

// overlap of the X and Z rods
xaxis_end_xz_rod_overlap = 4*mm;

// how much "stop" for the x rods
xaxis_end_rod_stop = 10*mm;

xaxis_endstop_size = [10.3*mm, 20*mm, 6.3*mm];
xaxis_endstop_screw_offset = [-1.8*mm, 0*mm, 0*mm];

module xaxis_end_body(with_motor, beltpath_index=0, nut_top=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;

    /*%rcubea([wx_, xaxis_rod_d*2, xaxis_end_wz], rounding_radius=3, align=[with_motor?1:-1,0,0]);*/

    if(with_motor)
    translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
    translate(xaxis_end_motor_offset)
    rcubea([xaxis_end_motorsize, motor_mount_wall_thick, xaxis_end_motorsize], rounding_radius=3, align=[0,-1,0]);

    // nut mount
    mirror([0,0,nut_top?1:0])
    translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
    {
        union()
        {
            difference()
            {
                cylindera(h=zaxis_nut[4], d=zaxis_nut[1], align=[0,0,1]);
                translate([0,-zaxis_nut[0]/2-1*mm,0])
                cubea([zaxis_nut[4]*2,zaxis_nut[4]+.2,zaxis_nut[4]+.2], align=[0,-1,1]);
            }

            // lead screw
            // ensure some support for the leadscrew cutout all the way to the top
            /*cylindera(h=xaxis_end_wz, d=zaxis_nut[2]*2, align=[0,0,1]);*/
        }
    }

    // x axis rod holders
    xaxis_rod_d_support = xaxis_rod_d+5*mm;
    for(z=[-1,1])
    translate([-xaxis_end_xz_rod_overlap,0,z*(xaxis_rod_distance/2)])
    cylindera(h=wx_+xaxis_end_xz_rod_overlap, d=xaxis_rod_d_support, orient=[1,0,0], align=[1,0,0]);

    translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
    {
        rcubea(xaxis_endstop_size, align=[-1,0,-1]);
    }

    // support around z axis bearings
    translate([0, -xaxis_zaxis_distance_y, 0])
    {
        difference()
        {
            sizey= zaxis_bearing[1]+10*mm;
            cylindera(h=xaxis_end_wz,d=sizey, orient=[0,0,1], align=[0,0,0]);
            translate([0,0,.1])
            cubea([sizey/2+.1, sizey+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[-1,0,0]);
            /*#cubea([sizey+.1, sizey/2+.2, xaxis_end_wz+.4], orient=[0,0,1], align=[0,-1,0]);*/
        }
    }
}

module xaxis_end(with_motor=false, stop_x_rods=false, beltpath_index=0, show_motor=false, nut_top=false, show_nut=false, show_rods=false, show_bearings=false)
{
    nut_h = zaxis_nut[4];
    wx = zaxis_bearing[1]/2+zaxis_nut[1];
    wx_ = with_motor? xaxis_end_motorsize+xaxis_end_motor_offset[0] - xaxis_end_motorsize/2 : wx;
    difference()
    {
        extrasize = with_motor?0*mm:0*mm;
        extrasize_align = 1;

        hull()
        {
            xaxis_end_body(with_motor=with_motor, beltpath_index=beltpath_index, nut_top=nut_top);

            // projection against z, ensure easy print
            translate([0,0,-xaxis_end_wz/2])
                linear_extrude(1)
                projection(cut=false)
                xaxis_end_body(with_motor);
        }

        //endstop mount screw cuts
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        translate(xaxis_endstop_screw_offset)
        for(y=[-1,1])
        translate([-5*mm,y*9.5*mm/2,-2*mm])
        nut_trap_cut(nut=MHexNutM3, screw_l=6*mm, screw_l_extra=0*mm, trap_axis=[-1,0,0], orient=[0,0,1], align=[0,0,-1]);

        xaxis_end_beltpath(height=xaxis_beltpath_height_body);

        // z smooth bearing mounts
        for(z=[-1,1])
        {
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            {
                bearing_mount_holes(
                        zaxis_bearing,
                        ziptie_type,
                        ziptie_bearing_distance,
                        orient=[0,0,1],
                        with_zips=true,
                        show_zips=false
                        );
                /*hull()*/
                /*{*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/

                    /*translate([-5*cm,0,0])*/
                    /*cylindera(d=zaxis_bearing[1],h=xaxis_end_wz);*/
                /*}*/
            }
        }

        // x smooth rods
        x_rod_stop = stop_x_rods ? xaxis_end_rod_stop : 0;
        for(z=[-1,1])
        translate([-xaxis_end_xz_rod_overlap-.1+x_rod_stop,0,z*(xaxis_rod_distance/2)])
        cylindera(h=wx_+xaxis_end_xz_rod_overlap-x_rod_stop+.2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

        if(with_motor)
        {
            screw_dist = lookup(NemaDistanceBetweenMountingHoles, xaxis_motor);

            // axle
            translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
            translate(xaxis_end_motor_offset)
            {
                round_d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor);
                translate([0, .1, 0])
                translate([0,1,0])
                teardrop(d=round_d,h=motor_mount_wall_thick, tear_orient=[0,0,1], orient=[0,1,0], align=[0,-1,0], roll=90, truncate=0);

                // motor axle
                translate([0, .1, 0])
                cylindera(d=1.2*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor)+3*mm, orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -2.5*mm-xaxis_pulley[1]-.1, 0])
                scale(1.03)
                cylindera(d=bearing_MR105[1], h=6*mm, orient=[0,1,0], align=[0,-1,0]);

                xaxis_motor_thread=ThreadM3;
                xaxis_motor_nut=MHexNutM3;
                for(x=[-1,1])
                for(z=[-1,1])
                translate([0,-xaxis_end_motor_offset[1],0])
                translate([x*screw_dist/2, -(xaxis_beltpath_width/2+4*mm), z*screw_dist/2])
                {
                    screw_cut(xaxis_motor_nut, h=25, with_nut=false, orient=[0,1,0], align=[0,1,0]);
                }
            }

        }

        // nut mount
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2])
        {
            union()
            {
                translate([0,0,-.1])
                {
                    // nut
                    cylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    cylindera(h=lookup(NemaFrontAxleLength,zaxis_motor), d=zaxis_nut[2]*1.5, align=[0,0,1]);

                    for(i=[-1,1])
                    translate([i*13.5*mm, 0, -zaxis_nut[3]])
                    screw_cut(thread=ThreadM3, h=16*mm, with_nut=false, orient=[0,0,1], align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_motor)
    {
        translate([0,0,xaxis_beltpath_z_offsets[beltpath_index]])
        translate(xaxis_end_motor_offset)
        {
            // 1mm due to motor offset
            translate([0,-1*mm,0])
            {
                // 1mm between pulley and motor
                translate([0,-1*mm,0])
                    pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);
                motor(xaxis_motor, NemaMedium, dualAxis=false, orientation=[-90,0,0]);
            }
        }
    }

    //endstop
    %if($show_vit)
    {
        translate([wx_,0,(xaxis_rod_distance/2)+xaxis_rod_d])
        {
            difference()
            {
                rcubea(xaxis_endstop_size, align=[-1,0,1]);

                translate(xaxis_endstop_screw_offset)
                for(y=[-1,1])
                translate([-5*mm,y*9.5*mm/2,xaxis_endstop_size[2]])
                screw_cut(nut=MHexNutM3, h=10*mm, orient=[0,0,-1], align=[0,0,-1]);
            }
        }
    }

    %if(show_nut)
    {
        mirror([0,0,nut_top?1:0])
        translate([zaxis_rod_screw_distance_x, -xaxis_zaxis_distance_y, -xaxis_end_wz/2-zaxis_nut[3]])
        xaxis_end_znut();
    }

    %if(show_rods)
    {
        for(z=[-1,1])
            translate([0,0,z*xaxis_rod_distance/2])
            translate([0, -xaxis_zaxis_distance_y, 0])
            cylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
    }

    %if(show_bearings)
    {
        for(z=[-1,1])
        translate([0,0,z*xaxis_rod_distance/2])
        translate([0, -xaxis_zaxis_distance_y, 0])
        bearing(zaxis_bearing);
    }
}

module xaxis_end_beltpath(height, width=xaxis_beltpath_width, length = 1000)
{
    hull()
    for(z=[-1,1])
    translate([0,0,z*height/2])
    teardrop(h=length, d=width, orient=[1,0,0], roll=-180*min(0,z), truncate=.5);
}

module xaxis_end_idlerholder(part, width=xaxis_beltpath_width, length=10, beltpath_index=0)
{
    width = 20*mm;

    if(part==undef)
    {
        difference()
        {
            xaxis_end_idlerholder(part="pos", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
            xaxis_end_idlerholder(part="neg", width=xaxis_beltpath_width, length=length, beltpath_index=beltpath_index);
        }
    }
    else if(part=="pos")
    {
        union()
        {
            /*translate([10*mm, 0,0])*/
            rcubea([width, xaxis_idler_pulley[0]+8*mm, xaxis_rod_distance+xaxis_rod_d*2], align=[1,0,0]);
        }
    }
    else if(part=="neg")
    {
        for(z=[-1,1])
        {
            translate([0,0,z*(xaxis_rod_distance/2)])
            {
                // x smooth rods
                translate([width/2+.1,0,0])
                cylindera(h=width/2,d=xaxis_rod_d+.2*mm, orient=[1,0,0], align=[1,0,0]);

                screw_cut(nut=MHexNutM4, h=16*mm, with_nut=false, orient=[1,0,0], align=[1,0,0]);

                translate([6*mm,0,0])
                nut_trap_cut(nut=MHexNutM4, screw_l=16*mm, trap_axis=[0,-1,0], orient=[1,0,0], $show_vit=false);
            }
        }

        translate([0,0,-xaxis_beltpath_z_offsets[max(0,beltpath_index)]])
        {
            translate([width/2,0,0])
                pulley(xaxis_idler_pulley, orient=[0,1,0]);

            translate([width/2,0,0])
                cylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

            xaxis_end_beltpath(height=xaxis_beltpath_height_holders);
        }
    }
    else if(part=="vit")
    {
    }
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            cylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            cylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }

        translate([0,0,-.1])
        cylindera(d=zaxis_nut[2], h=zaxis_nut[4]+.2, orient=[0,0,1], align=[0,0,1]);
    }
}

include <thing_libutils/misc.scad>;
if(false)
{
    // x axis
    /*translate([0,0,axis_pos_z])*/
    {
        /*if(!preview_mode)*/
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(z=[-1,1])
            for(z=xaxis_beltpath_z_offsets)
            translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
            belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);
        }

        /*translate([axis_pos_x,0,0])*/
        /*{*/
            // x carriage
            /*attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])*/
            /*{*/
                /*x_carriage_full();*/
            /*}*/
        /*}*/

        // x smooth rods
        color(color_rods)
        for(z=[-1,1])
            translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
                cylindera(h=xaxis_rod_l,d=xaxis_rod_d, orient=[1,0,0]);

        for(x=[-1,1])
        {
            translate([x*(main_width/2), 0, 0])
            {
                translate([0, xaxis_zaxis_distance_y, 0])
                translate([x*zmotor_mount_rod_offset_x, 0, 0])
                mirror([max(0,x),0,0])
                xaxis_end(with_motor=true, beltpath_index=max(0,x), show_nut=true, show_motor=true, show_nut=true);

                translate([x*110, 0, 0])
                mirror([max(0,x),0,0])
                xaxis_end_idlerholder();
            }
        }
    }

}

if(false)
{
    zrod_offset = zmotor_mount_rod_offset_x;
    for(z=[-1,1])
    for(z=xaxis_beltpath_z_offsets)
    translate([0,0,xaxis_end_wz/2])
    translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
    belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);

    translate([0, xaxis_zaxis_distance_y, 0])
    {
        for(x=[-1,1])
        translate([x*55,0,xaxis_end_wz/2])
        mirror([max(0,x),0,0])
        xaxis_end(with_motor=true, beltpath_index=max(0,x), show_motor=false, show_nut=false, show_bearings=false);

        for(x=[-1,1])
        translate([0,0,xaxis_end_wz/2])
        translate([x*45,25,0])
        translate([x*105,0,0])
        mirror([max(0,x),0,0])
        rotate([0,-90,0])
        xaxis_end_idlerholder(beltpath_index=max(0,x));
    }
}


new frame scoop

new frame scoop

cardthick= 41.18/134;
echo("one card thickness (mm) =", cardthick);
cardsize=	[88.05, 63.19, cardthick];
cardcorner= 5;
scoopheight=29;
cardcenter=	cardsize/2;
cardedge=	[cardsize[0]-cardcorner, cardsize[1]-cardcorner];
echo("cardedge =",cardedge);

module singlecard(){
	minkowski(){
		square(cardedge, center=true);
		circle(cardcorner/2, $fn=36);
	}
}

module squaremm(size, border=3, ht=scoopheight){
	difference(){
		cube([size, size*cardsize[1]/cardsize[0], ht], center=true);
		cube([size-border, size*cardsize[1]/cardsize[0]-border, ht+.1], center=true);
		echo("measurement frame outside is = ",[size,size]);
		echo("thickness of walls of frame: ", border/2);
		echo("measurement frame inside is = ",[size-border, size-border]);
		echo("height is = ", ht);
	}
}

module tray(floorthk=0, scaledif=.05, sideslope=1.4, scooph=scoopheight){
	translate([0,0,0])
	difference(){
		union(){
			linear_extrude (height=scooph, center=true, convexity=10, twist=0, scale=sideslope){
				scale([1+scaledif,1+scaledif,1])
					singlecard();
			}
			for (i=[-cardedge[0]/2, cardedge[0]/2]){
				translate([i,0,0])
					cube([scooph*(sideslope+scaledif) - scooph*sideslope,
						sideslope*cardsize[1]*(1+scaledif),
						scooph], center=true);
			}
		}
		translate([0,0,floorthk])
			linear_extrude (height=scooph*(1+scaledif)+.01,
							center=true,
							convexity=10,
							twist=0, scale=sideslope){
				scale([1,1,1])
					singlecard();
			}
		//singlecard();
	}
}

translate([0,0,-scoopheight/2]) squaremm(cardsize[0]);
tray();

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