Added invert option to scad script

Added invert option to scad script

/* Case parts for Zikzak rev3
 * www.zikzak.ca
 */

// ref
// colours: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#color

// TODO:
// - add cart hole 'sides' as guides for the cart to go down nicely into edge connector
//

// render target
// - leftbacktop
// - rightfrontbottom
// - all
target = "leftbacktop";
//target = "rightfrontbottom";
//target = "all";

// scale? Use this to print out tiny versions for inspection prior to printing real ones
//scale_factor = 1;
scale_factor = 0.4;

// invert for print?
//rotate_y = 180;   // invert
rotate_y = 0;   // no invert

// fan holes?
fan_holes = 1;
//fan_holes = 0;

// DO IT
//

// facets
$fn = 50;

// board params
inner_width = 150;
inner_depth = 100;
inner_height = 40;

// calcs
sloppyness = 2;
wall_thickness = 2.5;
jack_buffer = 2; 			// amount of extra cutout space around each side of a jack

outer_width = inner_width + sloppyness + wall_thickness;
outer_depth = inner_depth + sloppyness + wall_thickness;
outer_height = inner_height + sloppyness + wall_thickness;

module leftbacktop () {
	function r_from_dia(d) = d / 2;

	module walls() {
		union() {
			// left wall
			color ( "thistle" ) {
				cube ( [ wall_thickness, outer_depth, outer_height ] );
			}
			// back wall
			color ( "cadetblue" ) {
				translate ( [ 0, inner_depth + sloppyness, 0 ] ) {
					cube ( [ outer_width, wall_thickness, outer_height ] );
				}
			}
			// top
			color ( "MediumSeaGreen" ) {
				translate ( [ 0, 0, inner_height + sloppyness ] ) {
					cube ( [ outer_width, outer_depth, wall_thickness] );
				}
			}

        } // union
	} // walls

	module cutouts() {
		// LEFT SIDE
		//

		// joy0 + headphone
		translate ( [ -10, 9 - jack_buffer, 25 - jack_buffer ] ) {
			cube( [ 20, 30 + 15 + (2*jack_buffer), 13 + (2*jack_buffer) ] );
		}

		// BACK
		//

		// USB power/serial
		translate ( [ 3 - jack_buffer, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 7 + (2*jack_buffer), 20, 4 + (2*jack_buffer) ] );
		}
		// volume potwheel
		translate ( [ 16, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 15 + (2*jack_buffer), 20, 2 + (2*jack_buffer) ] );
		}
		// PS/2 keyb
		translate ( [ 36, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 15, 20, 15 + (2*jack_buffer) ] );
		}
		// VGA
		translate ( [ 55, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 31, 20, 14 + (2*jack_buffer) ] );
		}

        // TOP
        //

   		// cart
		translate ( [ 30, 2, 35 - jack_buffer ] ) {
			cube( [ 82 + (2*jack_buffer), 25+(2*jack_buffer), 20 ] );
		}

	} // cutouts

    module reartrim() {
        translate ( [ 135, inner_depth + sloppyness + 2, 13 ] )  {
            rotate ( [ 90, 0, 180 ] ) {
                linear_extrude(slices=1,height=5) {
                    text ( text="ZZ", size=20, font="DejaVu Sans Mono:style=Bold" );
                } // extrude
            } // rotate
        } // translate
     } // rear trim

     module toptrim() {
         translate ( [ 10, 60, 39 + sloppyness  ] )  {
             linear_extrude(slices=1,height=5) {
                text ( text="/////////////////////////", size=20, font="DejaVu Sans Mono:style=Bold",spacing=.3 );
             } // ex
         } // tr
     } // top trim

    difference() {
		walls();
		cutouts();
        reartrim();
        toptrim();
	}

} // left back top

module rightfrontbottom () {

	module walls() {
		union() {
			// right wall
			color ( "thistle" ) {
                translate ( [ inner_width + sloppyness, 0, 0 ] ) {
                    cube ( [ wall_thickness, outer_depth, outer_height ] );
                }
			}
			// front wall
			color ( "cadetblue" ) {
                cube ( [ outer_width, wall_thickness, outer_height ] );
			}
			// bottom
			color ( "MediumSeaGreen" ) {
                cube ( [ outer_width, outer_depth, wall_thickness] );
			}

        } // union
	} // walls

    module trimtext() {
        translate ( [ 105, 0, 13 ] )  {
            rotate ( [ 90, 0, 0 ] ) {
                linear_extrude(slices=1,height=5) {
                    text ( text="ZZ", size=20, font="DejaVu Sans Mono:style=Bold" );
                } // extrude
            } // rotate
        } // translate
     } // trim text

    difference() {
		walls();
        trimtext();
        if ( fan_holes == 1 ) translate( [ 75, 55, 0 ] ) fanholes();
	}

} // right front bottom

rotate ( [ 0, rotate_y, 0 ] ) {
    scale ( [ scale_factor, scale_factor, scale_factor ] ) {
        if ( target == "leftbacktop" ) {
            leftbacktop();
        } else if ( target == "rightfrontbottom" ) {
            rightfrontbottom();
        } else if ( target == "all" ) {
            leftbacktop();
            rightfrontbottom();
        } // render the right piece
    } // scale
} // rotate

module fanholes() {
    // How large is the fan rotor ? (mm)
RotorDiameter=70;
// How large should each hole be ? (mm)
HolesDiameter=10;
// How much space should be left between each hole, proportionally to the hole size ?
HolesRingsSpacingFraction = 0.4; // [0.1:4.0]
// The height of the generated solids (mm)
Height = 10;
// The number of faces of each hole outer perimeter
Resoultion=20;// [3:100]

// VARIABLES INITIALIZATION
echo("RotorDiameter=",RotorDiameter);
echo("HolesDiameter=",HolesDiameter);
echo("Height=",Height);
echo("Resoultion=",Resoultion);

HolesBoundingBox = HolesDiameter*(1+HolesRingsSpacingFraction);
echo("HolesBoundingBox=",HolesBoundingBox);
NumberOfRings = RotorDiameter / HolesBoundingBox;
echo("NumberOfRings=",NumberOfRings);

OuterRadius = RotorDiameter/2;
echo("OuterRadius=",OuterRadius);

RingRadiusStep = HolesBoundingBox;
echo("RingRadiusStep=",RingRadiusStep);

difference()
{
 for (i=[0:1:NumberOfRings/2])
 {
  difference()
  {
   for(j=[0:360/((i*HolesBoundingBox*6/HolesBoundingBox)):360])
   {
    translate([sin(j)*(i*HolesBoundingBox),cos(j)*(i*HolesBoundingBox),0])cylinder(h=Height,d=HolesDiameter, center = false, $fn=Resoultion);
   }
  }
 }
}

} // fanholes

/* Case parts for Zikzak rev3
 * www.zikzak.ca
 */

// ref
// colours: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#color

// TODO:
// - add cart hole 'sides' as guides for the cart to go down nicely into edge connector
//

// render target
// - leftbacktop
// - rightfrontbottom
// - all
//target = "leftbacktop";
target = "rightfrontbottom";
//target = "all";

// scale? Use this to print out tiny versions for inspection prior to printing real ones
//scale_factor = 1;
scale_factor = 0.4;

// fan holes?
fan_holes = 1;
//fan_holes = 0;

// facets
$fn = 50;

// board params
inner_width = 150;
inner_depth = 100;
inner_height = 40;

// calcs
sloppyness = 2;
wall_thickness = 2.5;
jack_buffer = 2; 			// amount of extra cutout space around each side of a jack

outer_width = inner_width + sloppyness + wall_thickness;
outer_depth = inner_depth + sloppyness + wall_thickness;
outer_height = inner_height + sloppyness + wall_thickness;

module leftbacktop () {
	function r_from_dia(d) = d / 2;

	module walls() {
		union() {
			// left wall
			color ( "thistle" ) {
				cube ( [ wall_thickness, outer_depth, outer_height ] );
			}
			// back wall
			color ( "cadetblue" ) {
				translate ( [ 0, inner_depth + sloppyness, 0 ] ) {
					cube ( [ outer_width, wall_thickness, outer_height ] );
				}
			}
			// top
			color ( "MediumSeaGreen" ) {
				translate ( [ 0, 0, inner_height + sloppyness ] ) {
					cube ( [ outer_width, outer_depth, wall_thickness] );
				}
			}

        } // union
	} // walls

	module cutouts() {
		// LEFT SIDE
		//

		// joy0 + headphone
		translate ( [ -10, 9 - jack_buffer, 25 - jack_buffer ] ) {
			cube( [ 20, 30 + 15 + (2*jack_buffer), 13 + (2*jack_buffer) ] );
		}

		// BACK
		//

		// USB power/serial
		translate ( [ 3 - jack_buffer, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 7 + (2*jack_buffer), 20, 4 + (2*jack_buffer) ] );
		}
		// volume potwheel
		translate ( [ 16, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 15 + (2*jack_buffer), 20, 2 + (2*jack_buffer) ] );
		}
		// PS/2 keyb
		translate ( [ 36, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 15, 20, 15 + (2*jack_buffer) ] );
		}
		// VGA
		translate ( [ 55, inner_depth, 25 - jack_buffer ] ) {
			cube( [ 31, 20, 14 + (2*jack_buffer) ] );
		}

        // TOP
        //

   		// cart
		translate ( [ 30, 2, 35 - jack_buffer ] ) {
			cube( [ 82 + (2*jack_buffer), 25+(2*jack_buffer), 20 ] );
		}

	} // cutouts

    module reartrim() {
        translate ( [ 135, inner_depth + sloppyness + 2, 13 ] )  {
            rotate ( [ 90, 0, 180 ] ) {
                linear_extrude(slices=1,height=5) {
                    text ( text="ZZ", size=20, font="DejaVu Sans Mono:style=Bold" );
                } // extrude
            } // rotate
        } // translate
     } // rear trim

     module toptrim() {
         translate ( [ 10, 60, 39 + sloppyness  ] )  {
             linear_extrude(slices=1,height=5) {
                text ( text="/////////////////////////", size=20, font="DejaVu Sans Mono:style=Bold",spacing=.3 );
             } // ex
         } // tr
     } // top trim

    difference() {
		walls();
		cutouts();
        reartrim();
        toptrim();
	}

} // left back top

module rightfrontbottom () {

	module walls() {
		union() {
			// right wall
			color ( "thistle" ) {
                translate ( [ inner_width + sloppyness, 0, 0 ] ) {
                    cube ( [ wall_thickness, outer_depth, outer_height ] );
                }
			}
			// front wall
			color ( "cadetblue" ) {
                cube ( [ outer_width, wall_thickness, outer_height ] );
			}
			// bottom
			color ( "MediumSeaGreen" ) {
                cube ( [ outer_width, outer_depth, wall_thickness] );
			}

        } // union
	} // walls

    module trimtext() {
        translate ( [ 105, 0, 13 ] )  {
            rotate ( [ 90, 0, 0 ] ) {
                linear_extrude(slices=1,height=5) {
                    text ( text="ZZ", size=20, font="DejaVu Sans Mono:style=Bold" );
                } // extrude
            } // rotate
        } // translate
     } // trim text

    difference() {
		walls();
        trimtext();
        if ( fan_holes == 1 ) translate( [ 75, 55, 0 ] ) fanholes();
	}

} // right front bottom

scale ( [ scale_factor, scale_factor, scale_factor ] ) {
	if ( target == "leftbacktop" ) {
		leftbacktop();
	} else if ( target == "rightfrontbottom" ) {
		rightfrontbottom();
	} else if ( target == "all" ) {
        leftbacktop();
        rightfrontbottom();
	}
}

module fanholes() {
    // How large is the fan rotor ? (mm)
RotorDiameter=70;
// How large should each hole be ? (mm)
HolesDiameter=10;
// How much space should be left between each hole, proportionally to the hole size ?
HolesRingsSpacingFraction = 0.4; // [0.1:4.0]
// The height of the generated solids (mm)
Height = 10;
// The number of faces of each hole outer perimeter
Resoultion=20;// [3:100]

// VARIABLES INITIALIZATION
echo("RotorDiameter=",RotorDiameter);
echo("HolesDiameter=",HolesDiameter);
echo("Height=",Height);
echo("Resoultion=",Resoultion);

HolesBoundingBox = HolesDiameter*(1+HolesRingsSpacingFraction);
echo("HolesBoundingBox=",HolesBoundingBox);
NumberOfRings = RotorDiameter / HolesBoundingBox;
echo("NumberOfRings=",NumberOfRings);

OuterRadius = RotorDiameter/2;
echo("OuterRadius=",OuterRadius);

RingRadiusStep = HolesBoundingBox;
echo("RingRadiusStep=",RingRadiusStep);

difference()
{
 for (i=[0:1:NumberOfRings/2])
 {
  difference()
  {
   for(j=[0:360/((i*HolesBoundingBox*6/HolesBoundingBox)):360])
   {
    translate([sin(j)*(i*HolesBoundingBox),cos(j)*(i*HolesBoundingBox),0])cylinder(h=Height,d=HolesDiameter, center = false, $fn=Resoultion);
   }
  }
 }
}

} // fanholes


adding x pegs.  check in before altering a bit

// 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,0,9]) lid();

//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();
  }
}

dh=3.1;
c30=cos(30);   dx=3*dh;  dy=2*c30*dh;
module hexGrid() {
  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,s=[1,1,1]) translate([x,y,0]) scale(s)
   cylinder(r1=2,r2=2.7,h=6,$fn=6,center=true);

module lid() {
  difference() {
    union() {
      for (i=[-1,1]) {
        for (j=[-1,1]) translate([2*dx*i,5*dy*j,0]) {
           hull() {
             translate([0,  0 ,1.7]) cylinder(r=2.2,h=1.4,$fn=6);
             translate([0,1.5*j,3]) cylinder(r=.1 ,h=5,$fn=6); }
                              hex(0,0,[.9,.9,1]); }
        hull() {                hex(5*dx*i,  0   ,[.9,.9,1]);
           translate([(5*dx-0.6)*i,0,8]) sphere(0.1); }
      }
      difference() {
        lidShell();
        translate([0,0,0.3]) scale([.982,.976,.97]) lidShell();

        //trim off thin edges of shell
        translate([0,0,2.4]) cube([89,53,2],center=true);
      }
    }

    // trim off severe overhanging parts of tabs
    *hull() {
       translate([0,0,3.5]) cube([70,55,.1],center=true);
       cube([70,50,7],center=true);
    }

    // trim off part of tab in partial hex hole
    for(x=[-1,1]) translate([49.7*x,0,0]) rotate([0,10*x,0])
       cube([6,6,20],center=true);

    // pass through for cable ties to attach platform to sides
    for(x=[-1,1]) translate([x*28,0,2.7]) rotate([90,0,0])
       scale([3,2,1]) cylinder(r=1,h=77,$fn=16,center=true);

    //translate([0,0,-99]) cube([200,200,200]);
  }

}

module lidShell()
  hull() {
    for (x=[-1,1]) for(y=[-1,1]) {
      translate([44*x,26*y,4.6]) sphere(3,$fn=24);
      translate([40*x,23  *y,30 ]) sphere(3,$fn=24);
    }
}

// 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+0.3,tabZ])
         rotate([90,0,0]) rotate([0,0,30]) tab(PCBhole);
    }
}

// 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,0,9]) lid();

//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();
  }
}

dh=3.1;
c30=cos(30);   dx=3*dh;  dy=2*c30*dh;
module hexGrid() {
  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,s=[1,1,1]) translate([x,y,0]) scale(s)
   cylinder(r1=2,r2=2.7,h=6,$fn=6,center=true);

module lid() {
  difference() {
    union() {
      for (i=[-1,1]) for (j=[-1,1])
        hex(3*dx*i,5*dy*j,[.9,.9,1]);
      difference() {
        lidShell();
        translate([0,0,0.3]) scale([.987,.98,.97]) lidShell();
      }
    }
    hull() {
       translate([0,0,3.5]) cube([89,57.5,.1],center=true);
       cube([86,52,7],center=true);
    }

    for(x=[-1,1]) translate([x*23,0,2.2]) rotate([90,0,0])
       scale([2.5,1.5,1]) cylinder(r=1,h=77,$fn=16,center=true);

    //translate([0,0,-99]) cube([200,200,200]);
  }

}

module lidShell()
  hull() {
    for (x=[-1,1]) for(y=[-1,1]) {
      translate([44*x,27.5*y,4.6]) sphere(3,$fn=24);
      translate([40*x,23  *y,30 ]) sphere(3,$fn=24);
    }
}

// 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+0.3,tabZ])
         rotate([90,0,0]) rotate([0,0,30]) tab(PCBhole);
    }
}


updated placements

updated placements

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

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

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

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


fixed diameter and wall thinckness of the rod-holder

eps = 0.01;
rod_d = 5+0.7;
mount_h = 40;

module rod_mount()
{
  base_h = 4;
  base_d = 35;
  // base
  difference()
  {
    cylinder(d=base_d, h=base_h);
    n=5;
    for(i=[0:n-1])
      rotate([0, 0, 1]*(i/n*360))
        translate([base_d/2-5, 0, -eps])
          cylinder(d=3.5, h=base_h+2*eps, $fn=30);
  }
  // rod holder
  translate([0, 0, base_h])
    difference()
    {
      cylinder(d=rod_d+2.5, h=mount_h, $fn=30);
      cylinder(d=rod_d, h=mount_h+eps, $fn=100);
    }
}

rod_mount();

eps = 0.01;
rod_d = 5;
mount_h = 40;

module rod_mount()
{
  base_h = 4;
  base_d = 35;
  // base
  difference()
  {
    cylinder(d=base_d, h=base_h);
    n=5;
    for(i=[0:n-1])
      rotate([0, 0, 1]*(i/n*360))
        translate([base_d/2-5, 0, -eps])
          cylinder(d=3.5, h=base_h+2*eps, $fn=30);
  }
  // main block
  translate([0, 0, base_h])
    difference()
    {
      cylinder(d=rod_d+1.5, h=mount_h, $fn=30);
      cylinder(d=rod_d, h=mount_h+eps, $fn=100);
    }
}

rod_mount();


remove the jetpuf version from the preivew

outerRadius = 12;

squareLength = 28;

xScale = 0.4;

yScale = 1.9;

bottomOuterRadius = 20;

use <../christmas-story-lamp-shade.scad>

// translate([-120, 0, 0])
// import("/home/roberto/Versioning/world/betoland/household/lamps/christmas-story-leg-lamp/jetpuf/files/LegLamp_Shade130.stl");

legLampShade(bottomOuterRadius = bottomOuterRadius,
             outerRadius = outerRadius,
             squareLength = squareLength,
             xScale = xScale,
             yScale = yScale);

outerRadius = 12;

squareLength = 28;

xScale = 0.4;

yScale = 1.9;

bottomOuterRadius = 20;

use <../christmas-story-lamp-shade.scad>

translate([-120, 0, 0])
import("/home/roberto/Versioning/world/betoland/household/lamps/christmas-story-leg-lamp/jetpuf/files/LegLamp_Shade130.stl");

legLampShade(bottomOuterRadius = bottomOuterRadius,
             outerRadius = outerRadius,
             squareLength = squareLength,
             xScale = xScale,
             yScale = yScale);


Fixes and improvements to hanging supports.

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014 - Jan, 2015
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.
thickness = 1.8;  // 1.8mm = 0.07" (looks good based on cut test piece)

// Interior box dimensions (from centerpoints of walls, so actual dimension is minus material thickness)
width = 290;    // x = 29cm wall-to-wall
depth = 350;    // y = 35cm to accomodate 34.5cm tank length
i_height = 180+thickness;
                // z = 18cm to accomodate 16cm tank height plus light holder, plus cover
                // (i_height because 'height' is used for height of entire box)

// amount faces extend past each other at corners
overhang = 20;

// amount horizontal support bars extend past side supports
outset = overhang/2;

// tank base plate
base_depth = depth-thickness*2;
base_height = overhang;

// create height var to account for raised base
height = i_height + base_height;

// light bar
light_bar_width = 30;
light_pos_x = 50;
light_height = height-thickness*2-10;

// for slight offsets/tweaks
epsilon = 1;

// vars to control projection for DXF export (see makefile)
if (DXF_TOP) {
    projection() top_cover();
} else if (DXF_BOTTOM) {
    projection() tank_base();
} else if (DXF_SIDE1) {
    projection() rotate(a=[90,0,0]) side(y=0);
} else if (DXF_SIDE2) {
    projection() rotate(a=[90,0,0]) side(y=depth);
} else if (DXF_END1) {
    projection() rotate(a=[0,90,0]) vert_face(x=0);
} else if (DXF_END2) {
    projection() rotate(a=[0,90,0]) vert_face(x=width);
} else if (DXF_LIGHT_BAR) {
    projection() light_bar();
}
else {
    // 3D model
    // components to include (comment out unwanted)
    vert_face(x=0);
    vert_face(x=width);
    side(y=0);
    side(y=depth);
    tank_base();
    light_bar();
    // camera supports (z -5 to center on camera opening)
    hanging_supports(x=width, y=depth/2, z=height/2-5, out=20, up=30, spacing=20);
    // rpi support
    hanging_support(x=width, y=depth/4+9, z=height/2, out=3, up=85);
    mock_rpi(x=width, y=depth/4, z=height/2);
    top_cover();
}

//////////////////////////////////////////////////////////////////
// Module definitions
//

module vert_face(x=0) {
    difference() {
        vert_face_base(x);
        camera_opening();
        // camera supports (z -5 to center on camera opening)
        hanging_supports(x=width+thickness, y=depth/2, z=height/2-5+10, out=20, up=30, spacing=20);
        // rpi supports
        hanging_support(x=width+thickness, y=depth/4+9, z=height/2+10, out=3, up=85);
        side(y=0);
        side(y=depth);
        tank_base();
    }
}

module vert_face_base(x) {
    translate([x-thickness/2,-overhang, 0])
        cube([thickness,depth+overhang*2,height]);
}

module camera_opening() {
    translate([width, depth/2, height/2])
        cube([thickness*2,10,10], center=true);
}

module hanging_supports(x, y, z, out, up, spacing) {
    hanging_support(x, y + spacing/2, z, out, up);
    hanging_support(x, y - spacing/2, z, out, up);
}

module hanging_support(x, y, z, out, up) {
    inner_w = out+thickness;
    inner_h = up;
    cutout_w = 10;
    translate([x,y,z])
    // push inner opening up against vert face
    translate([inner_w/2,0,0])
    difference() {
        cube([inner_w+cutout_w*2, thickness, inner_h+cutout_w*3], center=true);
        // cutout for object
        cube([inner_w, thickness*2, inner_h], center=true);
        // cutout for passing through vertface
        translate([-(inner_w/2+cutout_w/2),0,-cutout_w/2])
            cube([cutout_w+2*epsilon, thickness*2, inner_h-10], center=true);
        // bottom cutout
        translate([-inner_w/2,0,-(inner_h/2+cutout_w)])
            cube([thickness, thickness*2, cutout_w], center=true);
    }
}

module top_cover() {
    color("Grey", alpha=0.5)
    translate([-outset,-outset,height-thickness])
    difference() {
        cube([width+outset*2,depth+outset*2,thickness]);
        cutouts(5,width-thickness,outset,rot=0,trans=[width/2+outset,0,0]);
        cutouts(5,width-thickness,outset,rot=180,trans=[width/2+outset,depth+outset*2,0]);
        cutouts(5,depth-thickness,outset,rot=-90,trans=[0,depth/2+outset,0]);
        cutouts(5,depth-thickness,outset,rot=90,trans=[width+outset*2,depth/2+outset,0]);
    }
}

module tank_base() {
    translate([-outset,thickness,base_height])
    difference() {
        cube([width+outset*2, base_depth, thickness]);
        cutouts(5,depth,outset,rot=-90,trans=[0,base_depth/2,0]);
        cutouts(5,depth,outset,rot=90,trans=[width+outset*2,base_depth/2,0]);
    }
}

module light_bar_opening() {
    // A wider opening, so the bar can slide out of the way of placing or removing the fish tank
    translate([light_pos_x, -outset, light_height])
        cube([light_bar_width*2, depth+outset*2, thickness]);
}

module light_bar() {
    translate([light_pos_x-light_bar_width/2, -outset, light_height])
    difference() {
        cube([light_bar_width, depth+outset*2, thickness]);
        cutouts(2,light_bar_width,outset,rot=0,trans=[light_bar_width/2,0,0]);
        cutouts(2,light_bar_width,outset,rot=180,trans=[light_bar_width/2,depth+outset*2,0]);
    }
}

module cutouts(num, width, outset, rot, trans) {
    w = width / ((num-1) * 2);
    translate(trans)
    rotate([0,0,1], a=rot)
    for (i = [0 : num-1]) {
        translate([-width/2 - w/2 + i*2*w, -thickness/2, -epsilon])
            cube([w, outset+thickness, thickness+epsilon*2]);
    }
}

module light_wire_opening() {
    translate([light_pos_x, 0, light_height-10])
    scale([2,1,1])
    rotate(v=[1,0,0], a=90)
        cylinder(d=10, h=thickness+epsilon, center=true);
}

module side(y=0) {
    difference() {
        side_base(y);
        scale([1,1,0.5])
            vert_face_base(x=0);
        scale([1,1,0.5])
            vert_face_base(x=width);
        light_bar_opening();
        light_wire_opening();
        top_cover();
    }
}

module side_base(y) {
    translate([-overhang,y-thickness/2,overhang/2])
        cube([width+overhang*2, thickness, height-overhang/2]);
}

module mock_rpi(x, y, z) {
    translate([x+thickness, y, z])
        rotate(v=[0,1,0], a=90)
            translate([-85/2, -56/2, 0])
                union() {
                    cube([85, 56, 2]);
                    // USB1
                    translate([67, 41, 2])
                        cube([20, 12, 12]);
                    // USB2
                    translate([67, 23, 2])
                        cube([20, 12, 12]);
                }
}

// fishbox.scad
//  - Enclosure design for zebrafish Skinner box
//
//  Author: Mark Liffiton
//  Date: Oct, 2014 - Jan, 2015
//
//  Units are mm

// Set thickness to account for thickness of material
// PLUS needed clearance for cuts into which material should fit.
thickness = 1.8;  // 1.8mm = 0.07" (looks good based on cut test piece)

// Interior box dimensions (from centerpoints of walls, so actual dimension is minus material thickness)
width = 290;    // x = 29cm wall-to-wall
depth = 350;    // y = 35cm to accomodate 34.5cm tank length
i_height = 180+thickness;
                // z = 18cm to accomodate 16cm tank height plus light holder, plus cover
                // (i_height because 'height' is used for height of entire box)

// amount faces extend past each other at corners
overhang = 20;

// amount horizontal support bars extend past side supports
outset = overhang/2;

// tank base plate
base_depth = depth-thickness*2;
base_height = overhang;

// create height var to account for raised base
height = i_height + base_height;

// light bar
light_bar_width = 30;
light_pos_x = 50;
light_height = height-thickness*2-10;

// for slight offsets/tweaks
epsilon = 1;

// vars to control projection for DXF export (see makefile)
if (DXF_TOP) {
    projection() top_cover();
} else if (DXF_BOTTOM) {
    projection() tank_base();
} else if (DXF_SIDE1) {
    projection() rotate(a=[90,0,0]) side(y=0);
} else if (DXF_SIDE2) {
    projection() rotate(a=[90,0,0]) side(y=depth);
} else if (DXF_END1) {
    projection() rotate(a=[0,90,0]) vert_face(x=0);
} else if (DXF_END2) {
    projection() rotate(a=[0,90,0]) vert_face(x=width);
} else if (DXF_LIGHT_BAR) {
    projection() light_bar();
}
else {
    // 3D model
    // components to include (comment out unwanted)
    vert_face(x=0);
    vert_face(x=width);
    side(y=0);
    side(y=depth);
    tank_base();
    light_bar();
    // camera supports
    hanging_supports(x=width, y=depth/2, z=height/2, out=20, up=30, spacing=20);
    // rpi support
    hanging_support(x=width, y=depth/4+9, z=height/2, out=3, up=85);
    mock_rpi(x=width, y=depth/4, z=height/2);
    top_cover();
}

//////////////////////////////////////////////////////////////////
// Module definitions
//

module vert_face(x=0) {
    difference() {
        vert_face_base(x);
        camera_opening();
        // camera supports
        hanging_supports(x=width+thickness, y=depth/2, z=height/2+10, out=20, up=30, spacing=20);
        // rpi supports
        hanging_support(x=width+thickness, y=depth/4+9, z=height/2+10, out=3, up=85);
        side(y=0);
        side(y=depth);
        tank_base();
    }
}

module vert_face_base(x) {
    translate([x-thickness/2,-overhang, 0])
        cube([thickness,depth+overhang*2,height]);
}

module camera_opening() {
    translate([width, depth/2, height/2])
        cube([thickness*2,10,10], center=true);
}

module hanging_supports(x, y, z, out, up, spacing) {
    hanging_support(x, y + spacing/2, z, out, up);
    hanging_support(x, y - spacing/2, z, out, up);
}

module hanging_support(x, y, z, out, up) {
    inner_w = out+thickness;
    inner_h = up;
    inner_offset = 5;
    translate([x,y,z])
    // shift down to center on camera opening
    translate([0,0,-inner_offset])
    // push inner opening up against vert face
    translate([inner_w/2,0,0])
    difference() {
        cube([inner_w+20, thickness, inner_h+30], center=true);
        // cutout for camera
        translate([0,0,inner_offset])
            cube([inner_w, thickness*2, inner_h], center=true);
        // cutout for passing through vertface
        translate([-10-epsilon,0,0])
            cube([inner_w, thickness*2, inner_h-10], center=true);
        // bottom cutout
        translate([-inner_w/2,0,-25])
            cube([thickness, thickness*2, 10], center=true);
    }
}

module top_cover() {
    color("Grey", alpha=0.5)
    translate([-outset,-outset,height-thickness])
    difference() {
        cube([width+outset*2,depth+outset*2,thickness]);
        cutouts(5,width-thickness,outset,rot=0,trans=[width/2+outset,0,0]);
        cutouts(5,width-thickness,outset,rot=180,trans=[width/2+outset,depth+outset*2,0]);
        cutouts(5,depth-thickness,outset,rot=-90,trans=[0,depth/2+outset,0]);
        cutouts(5,depth-thickness,outset,rot=90,trans=[width+outset*2,depth/2+outset,0]);
    }
}

module tank_base() {
    translate([-outset,thickness,base_height])
    difference() {
        cube([width+outset*2, base_depth, thickness]);
        cutouts(5,depth,outset,rot=-90,trans=[0,base_depth/2,0]);
        cutouts(5,depth,outset,rot=90,trans=[width+outset*2,base_depth/2,0]);
    }
}

module light_bar_opening() {
    // A wider opening, so the bar can slide out of the way of placing or removing the fish tank
    translate([light_pos_x, -outset, light_height])
        cube([light_bar_width*2, depth+outset*2, thickness]);
}

module light_bar() {
    translate([light_pos_x-light_bar_width/2, -outset, light_height])
    difference() {
        cube([light_bar_width, depth+outset*2, thickness]);
        cutouts(2,light_bar_width,outset,rot=0,trans=[light_bar_width/2,0,0]);
        cutouts(2,light_bar_width,outset,rot=180,trans=[light_bar_width/2,depth+outset*2,0]);
    }
}

module cutouts(num, width, outset, rot, trans) {
    w = width / ((num-1) * 2);
    translate(trans)
    rotate([0,0,1], a=rot)
    for (i = [0 : num-1]) {
        translate([-width/2 - w/2 + i*2*w, -thickness/2, -epsilon])
            cube([w, outset+thickness, thickness+epsilon*2]);
    }
}

module light_wire_opening() {
    translate([light_pos_x, 0, light_height-10])
    scale([2,1,1])
    rotate(v=[1,0,0], a=90)
        cylinder(d=10, h=thickness+epsilon, center=true);
}

module side(y=0) {
    difference() {
        side_base(y);
        scale([1,1,0.5])
            vert_face_base(x=0);
        scale([1,1,0.5])
            vert_face_base(x=width);
        light_bar_opening();
        light_wire_opening();
        top_cover();
    }
}

module side_base(y) {
    translate([-overhang,y-thickness/2,overhang/2])
        cube([width+overhang*2, thickness, height-overhang/2]);
}

module mock_rpi(x, y, z) {
    translate([x+thickness, y, z])
        rotate(v=[0,1,0], a=90)
            translate([-85/2, -56/2, 0])
                union() {
                    cube([85, 56, 2]);
                    // USB1
                    translate([67, 41, 2])
                        cube([20, 12, 12]);
                    // USB2
                    translate([67, 23, 2])
                        cube([20, 12, 12]);
                }
}


xaxis/ends: misc tweaks

xaxis/ends: misc tweaks

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;

    /*%cuberounda([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)
    cuberounda([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()
        {
            fncylindera(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
            /*fncylindera(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)])
        fncylindera(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;
            fncylindera(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)])
                fncylindera(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)
            {
                translate([0, .1, 0])
                translate([0,1,0])
                fncylindera(d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor), h=motor_mount_wall_thick, orient=[0,1,0], align=[0,1,0]);

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

                // bearing for offloading force on motor shaft
                translate([0, -1*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
                    fncylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    fncylindera(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])
                            fncylindera(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])
            fncylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
    }
}

xaxis_end_beltpath_height = xaxis_pulley_inner_d+5*mm;
xaxis_end_beltpath_width = max(belt_width+3*mm, xaxis_pulley[0]+3*mm);

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

    hull()
    for(z=[-1,1])
    translate([0,0,z*xaxis_end_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_end_beltpath_width,xaxis_end_beltpath_width)/2;

    difference()
    {
        union()
        {
            cubea([10*mm, xaxis_end_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)])
                fncylindera(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])
        fncylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

        xaxis_end_beltpath();
    }
}

module xaxis_end_znut()
{
    difference()
    {
        union()
        {
            fncylindera(d=zaxis_nut[1], h=zaxis_nut[3], orient=[0,0,1], align=[0,0,1]);
            fncylindera(d=zaxis_nut[0], h=zaxis_nut[4], orient=[0,0,1], align=[0,0,1]);
        }
        translate([0,0,-.1])
            fncylindera(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)])
            %fncylindera(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]+0*mm-xaxis_pulley[0]/2;
xaxis_end_motorsize = lookup(NemaSideSize,xaxis_motor);
xaxis_end_motor_offset=[xaxis_end_motorsize/2+9*mm,motor_mount_wall_thick,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;
    wy = xaxis_bearing[1]*2+xaxis_zaxis_distance_y;

    /*%cuberounda([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)
    cuberounda([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()
        {
            fncylindera(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
            fncylindera(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)])
        fncylindera(h=wx_,d=xaxis_rod_d*2, 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]*2;
            fncylindera(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;
    wy = xaxis_bearing[1]*2+xaxis_zaxis_distance_y;
    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)])
                fncylindera(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)
            {
                translate([0, .1, 0])
                translate([0,1,0])
                fncylindera(d=1.1*lookup(NemaRoundExtrusionDiameter, xaxis_motor), h=motor_mount_wall_thick, orient=[0,1,0], align=[0,1,0]);

                // motor axle
                translate([0, .1, 0])
                fncylindera(d=1.1*lookup(NemaAxleDiameter, xaxis_motor), h=lookup(NemaFrontAxleLength, xaxis_motor), orient=[0,1,0], align=[0,1,0]);

                // bearing for offloading force on motor shaft
                translate([0, -xaxis_pulley[1]-0*mm+.1, 0])
                scale(1.03)
                bearing(bearing_MR105, 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
                    fncylindera(h=nut_h+1, d=zaxis_nut[0]*1.05, align=[0,0,1]);

                    // lead screw
                    translate([0,0,-.1])
                    fncylindera(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])
                            fncylindera(h=5, r=1.6, align=[0,0,1]);
                }
            }
        }
    }

    if(with_motor && show_motor)
    {
        translate(xaxis_end_motor_offset)
        {
            /*translate([0,-motor_mount_wall_thick,0])*/
            /*translate([0,-5,0])*/
            /*translate([0,-xaxis_pulley[0]/2,0])*/
            pulley(xaxis_pulley, flip=false, orient=[0,1,0], align=[0,-1,0]);
            translate([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])
            fncylindera(d=zaxis_rod_d, h=zaxis_rod_l, orient=[0,0,1]);
    }
}

xaxis_end_beltpath_height = xaxis_pulley_inner_d+5*mm;
xaxis_end_beltpath_width = max(belt_width+3*mm, xaxis_pulley[0]+3*mm);

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

    hull()
    for(z=[-1,1])
    translate([0,0,z*xaxis_end_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_end_beltpath_width,xaxis_end_beltpath_width)/2;

    difference()
    {
        union()
        {
            cubea([10*mm, xaxis_end_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)])
                fncylindera(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])
        fncylindera(d=lookup(ThreadSize, ThreadM5), h=100, orient=[0,1,0]);

        xaxis_end_beltpath();
    }
}

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

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

    /*xaxis_end(with_motor=true, show_motor=true, 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();*/
    /*}*/
/*}*/

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

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

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


xaxis/ends: use teardrop module for motor mount

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+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+v_sum(v_abs(xaxis_beltpath_z_offsets)));

        // 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)
                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([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=xaxis_beltpath_height, width=xaxis_beltpath_width, length = 1000)
{
    diag = pythag_hyp(width,width)/2;

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

module xaxis_end_idlerholder(height=xaxis_beltpath_height, width=xaxis_beltpath_width, length=10, beltpath_index=0)
{
    diag = pythag_hyp(width, width)/2;
    width = 20*mm;

    difference()
    {
        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]);
        }

        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();
        }
    }
}

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)
{
    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>

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+v_sum(v_abs(xaxis_beltpath_z_offsets)));

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

                union()
                {
                    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([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=xaxis_beltpath_height, width=xaxis_beltpath_width, length = 1000)
{
    diag = pythag_hyp(width,width)/2;

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

module xaxis_end_idlerholder(height=xaxis_beltpath_height, width=xaxis_beltpath_width, length=10, beltpath_index=0)
{
    diag = pythag_hyp(width, width)/2;
    width = 20*mm;

    difference()
    {
        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]);
        }

        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();
        }
    }
}

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)
{
    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));
    }
}