attach: add rollaxis param

attach: add rollaxis param

include <system.scad>
use <misc.scad>
use <transforms.scad>;
use <shapes.scad>

// From Obiscad
//----------------------------------------------------------
//--  Draw a point in the position given by the vector p
//----------------------------------------------------------
module point(p, r=0.7, fn)
{
    translate(p)
    sphere(r=r);
}

//------------------------------------------------------------------
//-- Draw a vector poiting to the z axis
//-- This is an auxiliary module for implementing the vector module
//--
//-- Parameters:
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//--  mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//------------------------------------------------------------------
module vectorz(l=10, l_arrow=4, mark=false)
{
  //-- vector body length (not including the arrow)
  lb = l - l_arrow;

  //-- The vector is locatead at 0,0,0
  translate([0,0,lb/2])
  union() {

    //-- Draw the arrow
    translate([0,0,lb/2])
      cylindera(r1=2/2, r2=0.2, h=l_arrow);

    //-- Draw the mark
    if (mark) {
      translate([0,0,lb/2+l_arrow/2])
      translate(X)
        cubea([2,0.3,l_arrow*0.8]);
    }

    //-- Draw the body
    cylindera(r=1/2, h=lb, center=true);
  }

  //-- Draw a sphere in the vector base
  sphere(r=1/2);
}

// From Obiscad,
//---------------------------------------------------------------------------
//-- Draw a vector
//--
//-- There are two modes of drawing the vector
//-- * Mode 1: Given by a cartesian point(x,y,z). A vector from the origin
//--           to the end (x,y,z) is drawn. The l parameter (length) must
//--           be 0  (l=0)
//-- * Mode 2: Give by direction and length
//--           A vector of length l pointing to the direction given by
//--           v is drawn
//---------------------------------------------------------------------------
//-- Parameters:
//--  v: Vector cartesian coordinates
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//    mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//---------------------------------------------------------------------------

module vector(v,l=0, l_arrow=4, mark=false)
{
  //-- Get the vector length from the coordinates
  mod = v_mod(v);

  //-- The vector is very easy implemented by means of the orientate
  //-- operator:
  //--  orientate(v) vectorz(l=mod, l_arrow=l_arrow)
  //--  BUT... in OPENSCAD 2012.02.22 the recursion does not
  //--    not work, so that if the user use the orientate operator
  //--    on a vector, openscad will ignore it..
  //-- The solution at the moment (I hope the openscad developers
  //--  implement the recursion in the near future...)
  //--  is to repite the orientate operation in this module

  //---- SAME CALCULATIONS THAN THE ORIENTATE OPERATOR!
  //-- Calculate the rotation axis

  vref = Z;
  raxis = v_cross(vref,v);

  //-- Calculate the angle between the vectors
  ang = v_anglev(vref,v);

  raxis_=ang==180&&raxis==N?X:raxis;

  //-- orientate the vector
  //-- Draw the vector. The vector length is given either
  //--- by the mod variable (when l=0) or by l (when l!=0)
  if (l==0)
    rotate(a=ang, v=raxis_)
      vectorz(l=mod, l_arrow=l_arrow, mark=mark);
  else
    rotate(a=ang, v=raxis_)
      vectorz(l=l, l_arrow=l_arrow, mark=mark);

}

// From Obiscad,
//--------------------------------------------------------------------
//-- Draw a connector
//-- A connector is defined a 3-tuple that consist of a point
//--- (the attachment point), and axis (the attachment axis) and
//--- an angle the connected part should be rotate around the
//--  attachment axis
//--
//--- Input parameters:
//--
//--  Connector c = [p , n, ang] where:
//--
//--     p : The attachment point
//--     v : The attachment axis
//--   ang : the angle
//--------------------------------------------------------------------
module connector(c)
{
  //-- Get the three components from the connector
  p = c[0];
  v = c[1];
  ang = c[2];

  //-- Draw the attachment poing
  color("Gray") point(p);

  //-- Draw the attachment axis vector (with a mark)
  translate(p)
    rotate(a=ang, v=v)
    color("Gray") vector(v=v_unitv(v)*6, l_arrow=2, mark=true);
}

// From Obiscad,
// modified to take roll parameter as param in module instead of attachment points
//-------------------------------------------------------------------------
//--  ATTACH OPERATOR
//--  This operator applies the necesary transformations to the
//--  child (attachable part) so that it is attached to the main part
//--
//--  Parameters
//--    a -> Connector of the main part
//--    b -> Connector of the attachable part
//-------------------------------------------------------------------------
module attach(a, b, roll=0, rollaxis)
{
    //-- Get the data from the connectors
    pos1 = a[0];  //-- Attachment point. Main part
    v    = a[1];  //-- Attachment axis. Main part

    pos2 = b[0];  //-- Attachment point. Attachable part
    vref = b[1];  //-- Atachment axis. Attachable part

    //-------- Calculations for the "orientate operator"------
    //-- Calculate the rotation axis
    raxis = v_cross(vref,v);

    //-- Calculate the angle between the vectors
    ang = v_anglev(vref,v);
    //--------------------------------------------------------.-

    raxis_=ang==180&&raxis==N?X:raxis;

    //-- Apply the transformations to the child ---------------------------

    //-- Place the attachable part on the main part attachment point
    translate(pos1)
        //-- Orientate operator. Apply the orientation so that
        //-- both attachment axis are paralell. Also apply the roll angle
        rotate(a=roll, v=rollaxis==U?v:rollaxis)  rotate(a=ang, v=raxis_)
        //-- Attachable part to the origin
        translate(-pos2)
        children();
}

include <system.scad>
use <misc.scad>
use <transforms.scad>;
use <shapes.scad>

// From Obiscad
//----------------------------------------------------------
//--  Draw a point in the position given by the vector p
//----------------------------------------------------------
module point(p, r=0.7, fn)
{
    translate(p)
    sphere(r=r);
}

//------------------------------------------------------------------
//-- Draw a vector poiting to the z axis
//-- This is an auxiliary module for implementing the vector module
//--
//-- Parameters:
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//--  mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//------------------------------------------------------------------
module vectorz(l=10, l_arrow=4, mark=false)
{
  //-- vector body length (not including the arrow)
  lb = l - l_arrow;

  //-- The vector is locatead at 0,0,0
  translate([0,0,lb/2])
  union() {

    //-- Draw the arrow
    translate([0,0,lb/2])
      cylindera(r1=2/2, r2=0.2, h=l_arrow);

    //-- Draw the mark
    if (mark) {
      translate([0,0,lb/2+l_arrow/2])
      translate(X)
        cubea([2,0.3,l_arrow*0.8]);
    }

    //-- Draw the body
    cylindera(r=1/2, h=lb, center=true);
  }

  //-- Draw a sphere in the vector base
  sphere(r=1/2);
}

// From Obiscad,
//---------------------------------------------------------------------------
//-- Draw a vector
//--
//-- There are two modes of drawing the vector
//-- * Mode 1: Given by a cartesian point(x,y,z). A vector from the origin
//--           to the end (x,y,z) is drawn. The l parameter (length) must
//--           be 0  (l=0)
//-- * Mode 2: Give by direction and length
//--           A vector of length l pointing to the direction given by
//--           v is drawn
//---------------------------------------------------------------------------
//-- Parameters:
//--  v: Vector cartesian coordinates
//--  l: total vector length (line + arrow)
//--  l_arrow: Vector arrow length
//    mark: If true, a mark is draw in the vector head, for having
//--    a visual reference of the rolling angle
//---------------------------------------------------------------------------

module vector(v,l=0, l_arrow=4, mark=false)
{
  //-- Get the vector length from the coordinates
  mod = v_mod(v);

  //-- The vector is very easy implemented by means of the orientate
  //-- operator:
  //--  orientate(v) vectorz(l=mod, l_arrow=l_arrow)
  //--  BUT... in OPENSCAD 2012.02.22 the recursion does not
  //--    not work, so that if the user use the orientate operator
  //--    on a vector, openscad will ignore it..
  //-- The solution at the moment (I hope the openscad developers
  //--  implement the recursion in the near future...)
  //--  is to repite the orientate operation in this module

  //---- SAME CALCULATIONS THAN THE ORIENTATE OPERATOR!
  //-- Calculate the rotation axis

  vref = Z;
  raxis = v_cross(vref,v);

  //-- Calculate the angle between the vectors
  ang = v_anglev(vref,v);

  raxis_=ang==180&&raxis==N?X:raxis;

  //-- orientate the vector
  //-- Draw the vector. The vector length is given either
  //--- by the mod variable (when l=0) or by l (when l!=0)
  if (l==0)
    rotate(a=ang, v=raxis_)
      vectorz(l=mod, l_arrow=l_arrow, mark=mark);
  else
    rotate(a=ang, v=raxis_)
      vectorz(l=l, l_arrow=l_arrow, mark=mark);

}

// From Obiscad,
//--------------------------------------------------------------------
//-- Draw a connector
//-- A connector is defined a 3-tuple that consist of a point
//--- (the attachment point), and axis (the attachment axis) and
//--- an angle the connected part should be rotate around the
//--  attachment axis
//--
//--- Input parameters:
//--
//--  Connector c = [p , n, ang] where:
//--
//--     p : The attachment point
//--     v : The attachment axis
//--   ang : the angle
//--------------------------------------------------------------------
module connector(c)
{
  //-- Get the three components from the connector
  p = c[0];
  v = c[1];
  ang = c[2];

  //-- Draw the attachment poing
  color("Gray") point(p);

  //-- Draw the attachment axis vector (with a mark)
  translate(p)
    rotate(a=ang, v=v)
    color("Gray") vector(v=v_unitv(v)*6, l_arrow=2, mark=true);
}

// From Obiscad,
// modified to take roll parameter as param in module instead of attachment points
//-------------------------------------------------------------------------
//--  ATTACH OPERATOR
//--  This operator applies the necesary transformations to the
//--  child (attachable part) so that it is attached to the main part
//--
//--  Parameters
//--    a -> Connector of the main part
//--    b -> Connector of the attachable part
//-------------------------------------------------------------------------
module attach(a, b, roll=0)
{
    //-- Get the data from the connectors
    pos1 = a[0];  //-- Attachment point. Main part
    v    = a[1];  //-- Attachment axis. Main part

    pos2 = b[0];  //-- Attachment point. Attachable part
    vref = b[1];  //-- Atachment axis. Attachable part

    //-------- Calculations for the "orientate operator"------
    //-- Calculate the rotation axis
    raxis = v_cross(vref,v);

    //-- Calculate the angle between the vectors
    ang = v_anglev(vref,v);
    //--------------------------------------------------------.-

    raxis_=ang==180&&raxis==N?X:raxis;

    //-- Apply the transformations to the child ---------------------------

    //-- Place the attachable part on the main part attachment point
    translate(pos1)
        //-- Orientate operator. Apply the orientation so that
        //-- both attachment axis are paralell. Also apply the roll angle
        rotate(a=roll, v=v)  rotate(a=ang, v=raxis_)
        //-- Attachable part to the origin
        translate(-pos2)
        children();
}


correct the inner cutout

correct the inner cutout


add a narrow heart sample

add a narrow heart sample

/* [Hidden] */

use <../../../half-circle-phone-stand.scad>

halfCirclePhoneStand(base_xTranslate = -1.0,
                     base_yTranslate = -1.0,
                     iconType = "Heart",
                     iconColor = "blue",
                     icon_xOffset = -9,
                     icon_yOffset = 34,
                     icon_zOffset = 9.8,
                     iconXyScale = 0.64,
                     bed_cutout_zLength = 10,
//                     height = 40,
                     stand_connectorBar_xLength = 8,
                     stand_top_xTranslate = 9.105,
                     stand_top_yTranslate = 9.85);

error: pathspec 'openscad/models/src/main/openscad/electronics/phone-stands/half-circle/samples/narrow/heart/narrow-heart-half-circle-phone-stand.scad' did not match any file(s) known to git


added elements for print and moved visualization aside

use <bottom_aa.scad>
use <top_aa.scad>
use <batteriesPack.scad>
include <config.inc>

// actual elements
bottomAA();
translate([0, sizeOY+5, 0])
  topAA();

// visualization only:
%translate([0, -sizeOY-40, 0])
{
  bottomAA();
  translate([sizeOX, 0, sizeOZ])
    mirror([1,0,0])
      mirror([0,0,1])
        topAA();
  %translate([0, 1, 0])
    batteriesPack();
}

use <bottom_aa.scad>
use <top_aa.scad>
use <batteriesPack.scad>
include <config.inc>

// actual elements
//bottomAA();
//translate()
//  topAA();

// visualization only:
bottomAA();
translate([sizeOX, 0, sizeOZ])
  mirror([1,0,0])
    mirror([0,0,1])
      topAA();
%batteriesPack();


correct the stand offsets

correct the stand offsets

base_xTranslate = -1;  // [-10: 0.1 :10]

base_yTranslate = -1;  // [-10: 0.1 :10]

stand_connectorBar_xLength = 8; // [-10: 0.1 :10]

stand_top_xTranslate = 9.105;  // [-10: 0.1 :10]

stand_top_yTranslate = 9.85;  // [-10: 0.1 :10]

iconType = "Mario";   // [Aqua Dude, Bass Clef, Cat, Creeper, Fan, Fish, Heart, Light Bulb, Luigi, Mario, Moon, Rebel, Spur, Sun, Thundercat, Treble Clef, Trooper]

iconColor = "blue"; // [pink, red, black, white, yellow, blue, green]

icon_xOffset = -9;  // [-30:30]

icon_yOffset = 34;  // [-10:200]

icon_zOffset = 19;  // [-30:30]

iconXyScale = 1.0;  // [-1: 0.1 :10]

bed_cutout_zLength = 10; // [4.2 : 15]

height = 40; // [19.125 : 60]

/* [Hidden] */

use <../../half-circle-phone-stand.scad>

halfCirclePhoneStand(base_xTranslate = base_xTranslate,
                     base_yTranslate = base_yTranslate,
                     bed_cutout_zLength = bed_cutout_zLength,
                     height = height,
                     iconColor = iconColor,
                     icon_xOffset = icon_xOffset,
                     icon_yOffset = icon_yOffset,
                     icon_zOffset = icon_zOffset,
                     iconXyScale = iconXyScale,
                     iconType = iconType,
                     stand_connectorBar_xLength = stand_connectorBar_xLength,
                     stand_top_xTranslate = stand_top_xTranslate,
                     stand_top_yTranslate = stand_top_yTranslate);

base_xTranslate = 0;  // [-10: 0.1 :10]

base_yTranslate = 0;  // [-10: 0.1 :10]

stand_connectorBar_xLength = 8; // [-10: 0.1 :10]

stand_top_xTranslate = 8.105;  // [-10: 0.1 :10]

stand_top_yTranslate = 8.85;  // [-10: 0.1 :10]

iconType = "Mario";   // [Aqua Dude, Bass Clef, Cat, Creeper, Fan, Fish, Heart, Light Bulb, Luigi, Mario, Moon, Rebel, Spur, Sun, Thundercat, Treble Clef, Trooper]

iconColor = "blue"; // [pink, red, black, white, yellow, blue, green]

icon_xOffset = -9;  // [-30:30]

icon_yOffset = 34;  // [-10:200]

icon_zOffset = 19;  // [-30:30]

iconXyScale = 1.0;  // [-1: 0.1 :10]

bed_cutout_zLength = 10; // [4.2 : 15]

height = 40; // [19.125 : 60]

/* [Hidden] */

use <../../half-circle-phone-stand.scad>

halfCirclePhoneStand(base_xTranslate = base_xTranslate,
                     base_yTranslate = base_yTranslate,
                     bed_cutout_zLength = bed_cutout_zLength,
                     height = height,
                     iconColor = iconColor,
                     icon_xOffset = icon_xOffset,
                     icon_yOffset = icon_yOffset,
                     icon_zOffset = icon_zOffset,
                     iconXyScale = iconXyScale,
                     iconType = iconType,
                     stand_connectorBar_xLength = stand_connectorBar_xLength,
                     stand_top_xTranslate = stand_top_xTranslate,
                     stand_top_yTranslate = stand_top_yTranslate);


box implemented

box implemented

use <m3d/rounded_cube.scad>

eps = 0.01;
wall = 2*0.4;
box_size = [60, 25, 20];
roundings = 2;
split_h = 5;
int_size = box_size - 2*wall*[1,1,1];

module box_main()
{
  difference()
  {

    rounded_cube(box_size, roundings, $fn=30);
    // empty interior
    translate(wall*[1,1,1])
      rounded_cube(int_size, roundings-wall, $fn=30);
    // holes for cable
    translate([-eps, box_size[1]/2, 3.25/2+roundings])
    rotate([0, 90, 0])
      hull()
        for(dy=[-1, +1])
          translate([0, dy*(5.5-2*3.5/2)/2, 0])
            cylinder(d=3.5, h=box_size[0]+2*eps, $fn=20);
  }
}

module box_bottom()
{
  intersection()
  {
    box_main();
    cube(box_size - [0, 0, split_h]);
  }
}

module box_top()
{
  // cover
  intersection()
  {
    translate([0, box_size[1], box_size[2]])
      rotate([180, 0 , 0])
        box_main();
    cube([box_size[0], box_size[1], split_h]);
  }
  // side walls for glueing
  translate(wall*[1,1,1])
  {
    difference()
    {
      cube([int_size[0], int_size[1], split_h+3]);
      // just keep walls
      translate(0.5*[1,1,0])
        cube(int_size-2*0.5*[1,1,1]);
      // corners removed for more flexibility
      for(dx=[0,1])
        for(dy=[0,1])
          translate([dx*int_size[0], dy*int_size[1], 0])
            translate(-10/2*[1,1,0])
              cube([10, 10, int_size[2]]);
      // minimize size of side walls
      translate([box_size[0]/2 - int_size[0]/3/2 - wall, -eps, 0])
        cube([int_size[0]/3, box_size[1], int_size[2]]);
    }
  }
}

box_top();
translate([0, -28, 0])
  box_bottom();

use <m3d/rounded_cube.scad>

wall = 2*0.4;
box_size = [60, 25, 20];
roundings = 2;

module box_main()
{
  difference()
  {

    rounded_cube(box_size, roundings, $fn=30);
    translate(wall*[1,1,1])
      rounded_cube(box_size - 2*wall*[1,1,1], roundings-wall, $fn=30);
  }
}

intersection()
{
  box_main();
  cube([30, 30, 30]);
}


add modules

add modules

use <../../../../shapes/open-cylinder/open-cylinder.scad>

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

outerRadius = 10;

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

union()
{
    legLamp_shade_top();

    legLamp_shade_bottom();
}

module legLamp_shade_bottom()
{
    openCylinder(height = 100,
                 outerRadius = outerRadius);
}

module legLamp_shade_top()
{
    translate([0, 0, 25])
    rotate([180, 0, 0])
    lampShade(outerRadius = 36,
            squareLength = 28,
            xScale = 0.3,
            yScale = 0.7);
}

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

lampShade(outerRadius = 36,
          squareLength = 28,
          xScale = 0.3,
          yScale = 0.7);


toda todo

toda todo

echo("a box with holes in it for Simon");
// todo: get rid of hard-coded '28' in walls_of_box

bigbox = 80;						// old box was 70?
bigboxht = 55;						// up from 50
fatten_for_lid_cut=.0;				// test fit lids: if more than .6 needed, bad geometry or print
sides = 2;							// skinny, assumes some further light-stopping material/paint
ledhole=15;
holeside=ledhole + sides*2 + 10;	// accomodate lense assembly
cornerad=4;						// used with minkowski(), cornerad*2 + 4-flat-sides = perimeter
small_chamber = 1/3;				// total of chambers' ratios should == 1
big_chamber = 2/3;				// chambers can be swapped
slit_width = 5;						// mm
cuvtt_inside = 12;					// put cuvette into a lid, slide detector around it, put other lid on.
lid_lad = 7;						// basic lid thickness
lid_puff = 4;						// rounded-ness for lid

module walls_of_box(
			fattener=fatten_for_lid_cut,
			longside=bigbox,
			bigboxht=bigboxht,
			wallthick=sides,
			ledhole=ledhole,
			cornerad=cornerad,
			holeside=holeside,
			insiders_x=bigbox - sides*3 - cornerad*2,
			insiders_y=ledhole - cornerad,		// inner-wall corner radius is hard-coded at 1/2 of outer
			){
	echo("longside = ", longside);
	echo("insiders_x = ", insiders_x);
	echo("insiders_y = ", insiders_y);
	difference(){
		minkowski(){
			square([longside - cornerad*2, holeside - cornerad*2], center=true);
			circle(r=cornerad-fattener, $fn=36);
		}
		for(block=[[small_chamber*insiders_x - fattener*2, fattener/2],
					[big_chamber*insiders_x - fattener*2, 28-fattener/2]]){
			echo("block[0] = ", block[0]);
			translate([-longside/2+(wallthick+fattener/2)*2+block[0]/2 + block[1], 0, 0]){
				minkowski(){
					square([block[0], holeside - cornerad - sides*2 - fattener*2], center=true);
					circle(r=cornerad/2, $fn=36);
				}
				// this square is just here to show the light-path
				#square([block[0], slit_width], center=true);
			}
		}
	}
}

module growbox(to_height=bigboxht, slit_width=slit_width, fatboy=0){
	difference(){
		linear_extrude(height = to_height, center = true, convexity = 10, twist = 0, slices = to_height*2, scale = 1){
			walls_of_box(fattener=fatboy);
		}
		cube([bigbox-sides*2-cornerad, slit_width, to_height - 10], center=true);
		for (i=[-bigbox/2, bigbox/2]){
			translate([i,0,0]) rotate([0,90,0])
			#cylinder(r=ledhole/2, h=sides*3, center=true, $fn=128);
		}
	}
}

module lids_on_it (overhang=lid_puff, basethick=lid_lad, with_cuvt=1){
	difference(){
		minkowski(){
			cube([bigbox, holeside, basethick], center=true);
			sphere(r=overhang/2, center=true, $fn=64);
		}
		// imprint the base of the walls and cuvette on a lid-like-structure
		translate([0,0,bigboxht/2])
			growbox(fatboy=.2);
		translate([0,0,bigboxht/2])
			cube([cuvtt_inside+.5, cuvtt_inside+.5, bigboxht], center=true);
		// an extra cut to ensure the lid doesn't obscure the cuvett:
		translate([0,0,bigboxht/2])
			cube([bigbox-sides*4, slit_width-.1, bigboxht], center=true);
	}
}

translate([0,holeside+lid_puff+2,(lid_lad+lid_puff)/2])
	lids_on_it(with_cuvt=1);
translate([0,-(holeside+lid_puff+2),(lid_lad+lid_puff)/2])
	lids_on_it(with_cuvt=0);
translate([0,0,bigboxht/2])
	growbox();

bigbox = 80;						// old box was 70?
bigboxht = 55;						// up from 50
fatten_for_lid_cut=.0;				// test fit lids: if more than .6 needed, bad geometry or print
sides = 2;							// skinny, assumes some further light-stopping material/paint
ledhole=15;
holeside=ledhole + sides*2 + 10;	// accomodate lense assembly
cornerad=4;						// used with minkowski(), cornerad*2 + 4-flat-sides = perimeter
small_chamber = 1/3;				// total of chambers' ratios should == 1
big_chamber = 2/3;				// chambers can be swapped
slit_width = 5;						// mm
cuvtt_inside = 12;
lid_lad = 7;
lid_puff = 4;

module walls_of_box(
			fattener=fatten_for_lid_cut,
			longside=bigbox,
			bigboxht=bigboxht,
			wallthick=sides,
			ledhole=ledhole,
			cornerad=cornerad,
			holeside=holeside,
			insiders_x=bigbox - sides*3 - cornerad*2,
			insiders_y=ledhole - cornerad,		// inner-wall corner radius is hard-coded at 1/2 of outer
			){
	echo("longside = ", longside);
	echo("insiders_x = ", insiders_x);
	echo("insiders_y = ", insiders_y);
	difference(){
		minkowski(){
			square([longside - cornerad*2, holeside - cornerad*2], center=true);
			circle(r=cornerad-fattener, $fn=36);
		}
		for(block=[[small_chamber*insiders_x - fattener*2, fattener/2],
					[big_chamber*insiders_x - fattener*2, 28-fattener/2]]){
			echo("block[0] = ", block[0]);
			translate([-longside/2+(wallthick+fattener/2)*2+block[0]/2 + block[1], 0, 0]){
				minkowski(){
					square([block[0], holeside - cornerad - sides*2 - fattener*2], center=true);
					circle(r=cornerad/2, $fn=36);
				}
				// this square is just here to show the light-path
				#square([block[0], slit_width], center=true);
			}
		}
	}
}

module growbox(to_height=bigboxht, slit_width=slit_width, fatboy=0){
	difference(){
		linear_extrude(height = to_height, center = true, convexity = 10, twist = 0, slices = to_height*2, scale = 1){
			walls_of_box(fattener=fatboy);
		}
		cube([bigbox-sides*2-cornerad, slit_width, to_height - 10], center=true);
		for (i=[-bigbox/2, bigbox/2]){
			translate([i,0,0]) rotate([0,90,0])
			#cylinder(r=ledhole/2, h=sides*3, center=true, $fn=128);
		}
	}
}

module lids_on_it (overhang=lid_puff, basethick=lid_lad, with_cuvt=1){
	difference(){
		minkowski(){
			cube([bigbox, holeside, basethick], center=true);
			sphere(r=overhang/2, center=true, $fn=64);
		}
		// imprint the base of the walls and cuvette on a lid-like-structure
		translate([0,0,bigboxht/2])
			growbox(fatboy=.2);
		translate([0,0,bigboxht/2])
			cube([cuvtt_inside+.5, cuvtt_inside+.5, bigboxht], center=true);
		// an extra cut to ensure the lid doesn't obscure the cuvett:
		translate([0,0,bigboxht/2])
			cube([bigbox-sides*4, slit_width-.1, bigboxht], center=true);
	}
}

translate([0,holeside+lid_puff+2,(lid_lad+lid_puff)/2])
	lids_on_it(with_cuvt=1);
translate([0,-(holeside+lid_puff+2),(lid_lad+lid_puff)/2])
	lids_on_it(with_cuvt=0);
translate([0,0,bigboxht/2])
	growbox();


added edge to kite roller, so that string does not snap on edges of fins

use <../m3d/screw_head_hex.scad>

eps = 0.01;

module screw_head()          { screw_head_hex_m8(); }
module screw_head_slot(dh=0) { screw_head_hex_m8(0.5, 2*0.2+dh); }

module side_block(left)
{
  module fin()
  {
    translate(-0.5*[1, 2, 0])
    hull()
    {
      cube([1, 2, 5]);
      for(dx=[-1,+1])
        translate(dx*(120/2-1/2)*[1,0,0])
          cube([1, 2, 2]);
    }
  }

  direction = left ? -1 : +1;
  dx_offset = direction * 80/2;
  module core_body()
  {
    // bottom part + edge around it
    difference()
    {
      $fn=360;
      cylinder(d=120+0.1, h=5+3);
      translate([0,0,5])
        cylinder(d=120-1.5, h=5);
    }
    cylinder(d=30, h=5+25, $fn=100);
    // spherical slot around screw head
    translate([dx_offset, 0, 5])
      intersection()
      {
        scale([1,1,0.5])
          sphere(d=30, $fn=100);
        translate([-20, -20, 0])
          cube([40, 40, 6]);
      }
    // fins
    translate([0,0,5])
      for(r=[0:20:180])
        rotate([0, 0, r])
          fin();
  }

  difference()
  {
    core_body();
    // screw slot
    translate([dx_offset, 0, -eps])
    {
      translate([0,0,5])
      {
        screw_head_slot(0.5);
        %screw_head();
      }
      // rod
      cylinder(d=8+0.55, h=100, $fn=50);
    }
    // screw holes in the center block part
    {
      offset = 7;
      h = 10;
      // top
      translate([0, offset, -eps])
      {
        cylinder(d1=10, d2=7, h=h);
        cylinder(d=3+0.7, h=50, $fn=50);
      }
      // bottom
      translate([0, -offset, -eps])
      {
        screw_head_hex_m3(0.5, h);
        cylinder(d=3+0.7, h=50, $fn=50);
      }
    }

    // asymetric cut, to connect 2 parts with friction
    translate([-20, 0, 5+25-10+eps])
      cube([40, 40, 10]);
  }
}

side_block(left=false);

use <../m3d/screw_head_hex.scad>

eps = 0.01;

module screw_head()          { screw_head_hex_m8(); }
module screw_head_slot(dh=0) { screw_head_hex_m8(0.5, 2*0.2+dh); }

module side_block(left)
{
  module fin()
  {
    translate(-0.5*[1, 2, 0])
    hull()
    {
      cube([1, 2, 5]);
      for(dx=[-1,+1])
        translate(dx*(120/2-1/2)*[1,0,0])
          cube([1, 2, 2]);
    }
  }

  direction = left ? -1 : +1;
  dx_offset = direction * 80/2;
  module core_body()
  {
    cylinder(d=120, h=5, $fn=360);
    cylinder(d=30, h=5+25, $fn=100);
    // spherical slot around screw head
    translate([dx_offset, 0, 5])
      intersection()
      {
        scale([1,1,0.5])
          sphere(d=30, $fn=100);
        translate([-20, -20, 0])
          cube([40, 40, 6]);
      }
    // fins
    translate([0,0,5])
      for(r=[0:20:180])
        rotate([0, 0, r])
          fin();
  }

  difference()
  {
    core_body();
    // screw slot
    translate([dx_offset, 0, -eps])
    {
      translate([0,0,5])
      {
        screw_head_slot(0.5);
        %screw_head();
      }
      // rod
      cylinder(d=8+0.55, h=100, $fn=50);
    }
    // screw holes in the center block part
    {
      offset = 7;
      h = 10;
      // top
      translate([0, offset, -eps])
      {
        cylinder(d1=10, d2=7, h=h);
        cylinder(d=3+0.7, h=50, $fn=50);
      }
      // bottom
      translate([0, -offset, -eps])
      {
        screw_head_hex_m3(0.5, h);
        cylinder(d=3+0.7, h=50, $fn=50);
      }
    }

    // asymetric cut, to connect 2 parts with friction
    translate([-20, 0, 5+25-10+eps])
      cube([40, 40, 10]);
  }
}

side_block(left=false);


Updating the new effector for better integration of blowing fans and heat sink fans

//use <roundedBox.scad>
//use <microswitch.scad>

$fn = 50;
sqrt3 = 1.7321;
roundness = 4;
longEdge = 62;
shortEdge = longEdge * .4;

m25ScrewRadius = 1.25;
m25ScrewHeadRadius= 2.5;

m4ScrewRadius = 2.0; //for M4 bolt
m4ScrewHeadRadius = 4.0;
m4NutRadius = 4.3;

m5NutRadius = 8/sqrt3+0.2;

m3ScrewRadius = 1.5; //for M3 bolt
m3ScrewHeadRadius = 3.0;
m3NutRadius = 3.5; //

m2ScrewRadius = 1.0; //for M4 bolt
m2ScrewHeadRadius = 2.0;
m2NutRadius = 2.3;

cylinderMaxRadius = 7; // enough
cylinderMinRadius = 3;
cylinderHeight = 7.0;

ballSeperateDistance = 48.0;
mountingHoleDistance = ballSeperateDistance - 30;
ballScrewRadius = 2.0;
ballJointAngle = 30;
ballJointRadius = 5;
ballBaseRadius = 3.5;

baseShapeRadius =(2*shortEdge + longEdge)/3*sqrt3-roundness*2;

upperScaleFactor=0.8;
underScaleFactor = 0.9;
upperHeight = (1-upperScaleFactor)*longEdge/sqrt3;
downHeight = (1-underScaleFactor)*longEdge/sqrt(2);
middleHeight = 2;

grooveHoleRadius = 18.5;
grooveMountScrewRadius = 13;

microSwitchHolesDistance = 9.5;

pivotRadius = 7.5;
pivotFarback = -20;
innerPivotWidth = 0.3 * longEdge;
outerPivotWidth = 0.15 * longEdge;

err = 0.4;

module triangleShape (){
    minkowski(){
	intersection(){
	    circle(r= baseShapeRadius,$fn=3); //small one, 2/3 shortEdge, 1/3 longEdge
	    rotate([0,0,180]) circle(r=(2*longEdge + shortEdge)/3*sqrt3-roundness*2, $fn=3);
	}
	circle( r= roundness);
    }
}

module pillar(){
    hull(){
	translate([0,0,5])cylinder(r= ballBaseRadius, h=1, center = true, $fn=20);
	cylinder (r=ballBaseRadius+1,h=1,center =true, $fn=20);
    }
}

module grooveShape(){
    difference(){
	cylinder(r=grooveHoleRadius, h=40, center = true);
	translate([-grooveHoleRadius+4-5, 0,0]) cube([10,grooveHoleRadius*2,40], center=true);}
}

RadiatorRadius = 20;
RadiatorHeight = 30;
GrooveMountRadius = 8;

V6SinkHeight = 25;
V6SinkRadius = 22.3/2;
proxSensor_x = 17.5;
proxSensor_y = 17.5;
proxSensor_z = 35;

module V6Profile()
{
    cylinder(r= V6SinkRadius+3, h=26);
    cylinder(r= 8, h= 34);
    cylinder(r= 6-0.1, h= 40);
    translate([0,0,39])cylinder(r= 8, h=6);

}

module lowerLayerShape(){
    difference(){
	union(){
	    //lower Shape
	    union(){
		// Draw the basic profile
		linear_extrude(height= upperHeight,center = false,convexity=10,scale=upperScaleFactor/1.05)
		scale([1.07,1.07,1])triangleShape();

		translate([0,0,-middleHeight]) linear_extrude(height= middleHeight,center = false)
		scale([1.07,1.07,1])	triangleShape();

		translate([0,0,-middleHeight]) rotate([180,0,0])
		linear_extrude(height=downHeight, center = false, scale=underScaleFactor*1.05)
		scale([1.07,1.07,1])	triangleShape();

	    }

	    // Draw Pillars for Ball Joints
	    for (i=[30:120:270])
	    for (j=[-1,1])
	    translate ([j*cos(i)*ballSeperateDistance/2, j*sin(i)*ballSeperateDistance/2,0])
	    translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
	    rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0]) pillar();

	}
	// screw holes

	for (i=[30:120:270])
	for (j=[-1,1])
	translate ([j*cos(i)*ballSeperateDistance/2, j*sin(i)*ballSeperateDistance/2,0])
	translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
	rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0])
	{
	    cylinder(r=m4ScrewRadius, h=20, center = true);
	    translate([0,0,-6]) cylinder(r=m4ScrewHeadRadius, h=12, center=true);
	}

	// Central Hole
	translate([0,0,-20 ])linear_extrude(height= 30) scale([0.67,0.67,1]) triangleShape();

    }

}

module upperPart_v2(){

    //basic shape
    difference(){
	union(){
	    hull(){
		linear_extrude(height= 2) scale([0.76, 0.76, 1])triangleShape();
		minkowski(){
		    intersection(){
			translate([0,0, V6SinkHeight-5]) linear_extrude(height=3)
			scale([0.25, 0.25,1]) triangleShape();
		    }
		    cylinder(r=4, h=1,center=true);
		}
		// front screw support for holding the upper part
		// using two m2 screws
		for(i=[-1,1])
		translate([25,i*14,0]) cylinder(r1=2, r2=1.6, h=5);
	    }
	    // print fans holding supports
	    // print fans holding screws (m2)

	    for(i=[-1])
	    translate([3,-i*13.2,-5])
	    rotate([0,0,i*8])
	    rotate([i*5,0,0])
	    translate([15,0,15])rotate([i*90,0,0])cylinder(r1=3, r2=2,h=5,center=true);

	}

	// prox sensor mount
	translate([V6SinkRadius + 3 + proxSensor_x/2, 0, -10])
	minkowski(){
	    cube([proxSensor_x, proxSensor_y, proxSensor_z], center=true);
	    //cylinder(r=2,h=5,center=true);
	    sphere(r=1.5);
	}

	// Heat sink cooling fan
	translate([-18,0,12])
	//rotate([0,90,0])
	minkowski(){
	    hull(){
		cube([21,21,1],center=true);
		translate([-10,0,-20]) cube([35,31,1],center=true);
	    }
	    sphere(r=2);
	}

	// Print fans
	for(i=[-1,1])
	translate([3,-i*19,-8])
	rotate([0,0,i*8])
	rotate([i*5,0,0])
	minkowski(){
	    hull(){
		cube([32,1,40],center=true);
		translate([-4,-i*15,0]) cube([40,1,40], center=true);
	    }
	    sphere(r=3);
	}

	// Heat sink mount
	translate([0,0,-15])	V6Profile();

	// m3 Screws
	// rare hold screw
	translate([-10, 0, 19])rotate([90,0,0])cylinder(r=m3ScrewRadius, h=40, center=true);
	translate([-10,16.5, 19])rotate([90,0,0])cylinder(r=m3NutRadius, h=5, center=true, $fn=6);
	translate([-10,-16.5,19])rotate([90,0,0])cylinder(r=m3ScrewHeadRadius, h=5,center=true);

	// front hold screw
	translate([11, 0, 19])rotate([90,0,0])cylinder(r=m3ScrewRadius, h=40, center=true);
	translate([11,12, 19])rotate([90,0,0])cylinder(r=m3NutRadius, h=5, center=true, $fn=6);
	translate([11,-12,19])rotate([90,0,0])cylinder(r=m3ScrewHeadRadius, h=5,center=true);

	// m2Screws to mount upper part to lower Basement
	// rare
	for(i=[-1,1])
	translate([-20,i*20,0])
	{
	    cylinder(r=m2ScrewRadius, h=40,center=true);
	    translate([0,0,12])cylinder(r=m2ScrewHeadRadius, h=10, center=true);
	}

	// front
	for(i=[-1,1])
	translate([25,i*14,0])
	{
	    cylinder(r=m2ScrewRadius, h=40,center=true);
	    translate([0,0,10])cylinder(r=m2ScrewHeadRadius, h=10, center=true);
	}

	// print fans holding screws (m2)
	for(i=[-1,1])
	translate([3,-i*15,-5])
	rotate([0,0,i*8])
	rotate([i*5,0,0])
	for(j=[-1,1])
	translate([15*j,0,15])rotate([90,0,0])cylinder(r=m2ScrewRadius,h=30,center=true);

    }

    // Sink cooling fan holding supports
    for(i=[-1,1])
    difference(){
	translate([-9,i*11,11])
	rotate([0,90,0])
	// support thing
	minkowski(){
	    cube([6,5,8],center=true);
	    cylinder(r=2,h=2,center=true);
	}
	// screw holes
	translate([-15, i*10, 10])
	rotate([0,90,0])
	cylinder(r=m2ScrewRadius, h= 20, center=true);

	// avoid the m2 screw for printing fans
	for(j=[-1,1])
	translate([3,j*(-15),-5])
	rotate([0,0,j*8])
	rotate([j*5,0,0])
	translate([-15,0,15])rotate([90,0,0])cylinder(r=m2ScrewRadius,h=20, center=true);

	// avoid the heat sink
	translate([0,0,-15])	V6Profile();

    }

    // Heat sink fan

    %translate([-20,0,0])
    minkowski(){
	cube([8,21,21],center=true);
	rotate([0,90,0])
	cylinder(r=2, h=1, center=true);
    }

    // print fans

    %for(i=[-1,1])
    translate([3,-i*21,-5])
    rotate([0,0,i*8])
    rotate([i*5,0,0])
    minkowski(){
	cube([31,8,31], center= true);
	rotate([90,0,0]) cylinder(r=2, h=1, center=true);
    }

    // for better adhesion
    for(i=[-1,1])
    translate([32,-i*10,0])cylinder(r=5,h=0.4);

}

module lowerPart_v2(){
    difference(){
	union(){
	    difference(){
		union(){
		    lowerLayerShape();

		    // wind hole cover
		    hull(){
			for(i=[-1,2])
			translate([-25,i*8-4.5,1.5])
			translate([0,0,0])rotate([0,90,0])cylinder(r=4.5,h=17,center=true);
			//    translate([0,0,-3.5])rotate([0,90,0])cylinder(r=2,h=20,center=true);
		    }

		    // side wind hole
		    for(j=[-1,1])
		    translate([10,0,0])
		    intersection(){
			hull(){
			    for(i=[-2,1])
			    translate([i*6,j*25,3])
			    translate([0,0,-2.5])rotate([0,0,-j*15])rotate([90,0,0])
			    cylinder(r=4.5,h=40,center=true);
			}
			cylinder(r1=62,r2=55, h=20,center=true, $fn=3);
			cylinder(r1=55,r2=62, h=20,center=true, $fn=3);

		    }

		}

		// Central Hole
		translate([0,0,-20 ])linear_extrude(height= 30) scale([0.67,0.67,1]) triangleShape();

		// Heat sink fan

		translate([-20,0,0])
		minkowski(){
		    cube([8,21,21],center=true);
		    rotate([0,90,0])
		    cylinder(r=3, h=3, center=true);
		}

		// print fans

		for(i=[-1,1])
		translate([3,-i*18,-5])
		rotate([0,0,i*8])
		rotate([i*5,0,0])
		minkowski(){
		    cube([33,12,31], center= true);
		    //rotate([90,0,0]) cylinder(r=3, h=3, center=true);
		    sphere(r=2);
		}

		// prox sensor
		translate([V6SinkRadius + 4 + proxSensor_x/2, 0, -10])
		minkowski(){
		    cube([proxSensor_x, proxSensor_y, proxSensor_z], center=true);
		    //cylinder(r=2,h=5,center=true);
		    sphere(r=1);
		}

		// wind holes
		hull(){
		    for(i=[-1,2])
		    translate([-25,i*8-4.5,1.5])
		    translate([0,0,0])rotate([0,90,0])cylinder(r=3,h=20,center=true);
		//    translate([0,0,-3.5])rotate([0,90,0])cylinder(r=2,h=20,center=true);
		}

		// side holes
		for(j=[-1,1])
		translate([10,0,0])
		hull(){
		    for(i=[-2,1])
		    translate([i*6,j*25,3])
		    translate([0,0,-2.5])rotate([0,0,-j*15])rotate([90,0,0])cylinder(r=3,h=35,center=true);
//		    translate([0,0,-3.5])rotate([90,0,-j*5])cylinder(r=1.5,h=35,center=true);
		}

	    }

	    // rare screw places for holding the upper part
	    // use m2 screws
	    for(i=[-1,1])
	    translate([-20,i*20,4.565])
	    cylinder(r1=2.5, r2=4, h=upperHeight-2, center=true);
	}

	// rare screw places for holding the upper part
	// use m2 screws
	for(i=[-1,1])
	translate([-20,i*20,0])
	{
	    cylinder(r=m2ScrewRadius, h=20, center=true);
	    translate([0,0,-3])cylinder(r=m2NutRadius, h=10, center=true, $fn=6);
	}

	// front screw places for holding the upper part
	// use m2 screws
	for(i=[-1,1])
	translate([25,i*14,0])
	{
	    cylinder(r=m2ScrewRadius, h=40,center=true);
	    translate([0,0,-3])cylinder(r=m2NutRadius, h=10, center=true, $fn=6);
	}

    }
}

module body()
{
    difference(){
	union(){
	    lowerPart_v2();
            translate([0,0,upperHeight])   upperPart_v2();
	}
    }
}

module l_upperPart_v2(){
    intersection(){
	upperPart_v2();
	translate([0,40,0])cube([80,80,60],center=true);
    }
}

module r_upperPart_v2(){
    intersection(){
	upperPart_v2();
	translate([0,-40,0])cube([80,80,60],center=true);
    }
}

//body();
//lowerPart_v2();
//translate([0,0,7])upperPart_v2();

//l_upperPart_v2();

r_upperPart_v2();

//color("silver") translate([-2,0,-27]) rotate([0,0,0])import("./e3d-v6.stl");

//use <roundedBox.scad>
//use <microswitch.scad>

$fn = 50;
sqrt3 = 1.7321;
roundness = 4;
longEdge = 62;
shortEdge = longEdge * .4;

m25ScrewRadius = 1.25;

m4ScrewRadius = 2.0; //for M4 bolt
m4ScrewHeadRadius = 4.0;
m4NutRadius = 4.3;

m5NutRadius = 8/sqrt3+0.2;

m3ScrewRadius = 1.5; //for M3 bolt
m3ScrewHeadRadius = 3.0;
m3NutRadius = 3.5; //
cylinderMaxRadius = 7; // enough
cylinderMinRadius = 3;
cylinderHeight = 7.0;

ballSeperateDistance = 48.0;
mountingHoleDistance = ballSeperateDistance - 30;
ballScrewRadius = 2.0;
ballJointAngle = 30;
ballJointRadius = 5;
ballBaseRadius = 3.5;

baseShapeRadius =(2*shortEdge + longEdge)/3*sqrt3-roundness*2;

upperScaleFactor=0.8;
underScaleFactor = 0.9;
upperHeight = (1-upperScaleFactor)*longEdge/sqrt3;
downHeight = (1-underScaleFactor)*longEdge/sqrt(2);
middleHeight = 2;

grooveHoleRadius = 18.5;
grooveMountScrewRadius = 13;

microSwitchHolesDistance = 9.5;

pivotRadius = 7.5;
pivotFarback = -20;
innerPivotWidth = 0.3 * longEdge;
outerPivotWidth = 0.15 * longEdge;

err = 0.4;

module triangleShape (){
    minkowski(){
	intersection(){
	    circle(r= baseShapeRadius,$fn=3); //small one, 2/3 shortEdge, 1/3 longEdge
	    rotate([0,0,180]) circle(r=(2*longEdge + shortEdge)/3*sqrt3-roundness*2, $fn=3);
	}
	circle( r= roundness);
    }
}

module pillar(){
    hull(){
	translate([0,0,5])cylinder(r= ballBaseRadius, h=1, center = true, $fn=20);
	cylinder (r=ballBaseRadius+1,h=1,center =true, $fn=20);
    }
}

module grooveShape(){
    difference(){
	cylinder(r=grooveHoleRadius, h=40, center = true);
	translate([-grooveHoleRadius+4-5, 0,0]) cube([10,grooveHoleRadius*2,40], center=true);}
}

// ----------------------------deprecated------------------------------------------
module baseShape(){
    difference(){
	union(){
	    difference(){
		union(){
		    // Draw the basic profile
		    linear_extrude(height= upperHeight,center = false,convexity=10,scale=upperScaleFactor) triangleShape();
		    translate([0,0,-middleHeight]) linear_extrude(height= middleHeight,center = false) triangleShape();
		    translate([0,0,-middleHeight]) rotate([180,0,0])
		    linear_extrude(height=downHeight, center = false, scale=underScaleFactor) triangleShape();
		}
		// then dig a shallow channel for pivot
		translate([-18,0,upperHeight+ pivotRadius -1])
		rotate([90,0,0]) cylinder(r=pivotRadius+2, h=innerPivotWidth+2*outerPivotWidth + 5, center=true);

	    }
	    // Draw the base pivots:
	    translate([pivotFarback, -innerPivotWidth/2, upperHeight+ pivotRadius-1])
	    rotate([90,0,0])
	    difference()	{
		hull(){
		    cylinder(r= pivotRadius, h=outerPivotWidth, center=true);
		    translate([-2,-pivotRadius-2,0])
		    cube([pivotRadius*2,2, outerPivotWidth], center = true);
		}
		// dig a m4 screw hole in the center
		cylinder(r= m3ScrewRadius, h=30, center = true);
	    };

	    translate([pivotFarback,innerPivotWidth/2,upperHeight+ pivotRadius-1])
	    rotate([90,0,0])
	    difference()	{
		hull(){
		    cylinder(r= pivotRadius, h=outerPivotWidth, center=true);
		    translate([-2,-pivotRadius-2,0])
		    cube([pivotRadius*2,2, outerPivotWidth], center = true);
		}
		// dig a m4 screw hole in the center
		cylinder(r= m3ScrewRadius, h=30, center = true);
	    };

	    // Draw the pillar
	    for (i=[30:120:270]) {
		translate ([cos(i)*ballSeperateDistance/2, sin(i)*ballSeperateDistance/2,0])
		translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
		rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0]) pillar();

		translate ([-cos(i)*ballSeperateDistance/2, -sin(i)*ballSeperateDistance/2,0])
		translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
		rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0]) pillar();
	    }

	}
	// Minus screw holes

	for (i=[30:120:270]) {
	    translate ([cos(i)*ballSeperateDistance/2, sin(i)*ballSeperateDistance/2,0])
	    translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
	    rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0])
	    union() {
		cylinder(r=m4ScrewRadius, h=20, center = true);
		translate([0,0,-6]) cylinder(r=m4ScrewHeadRadius, h=12, center=true);
	    }

	    translate ([-cos(i)*ballSeperateDistance/2, -sin(i)*ballSeperateDistance/2,0])
	    translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
	    rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0])
	    union() {
		cylinder(r=m4ScrewRadius, h=20, center = true);
		translate([0,0,-6]) cylinder(r=m4ScrewHeadRadius, h=12, center=true);
	    }
	}

	// Minus groove HOLES
	scale([1.1,1.1,1])grooveShape();

	// Minus micro switch mount place

	translate([grooveHoleRadius +2,0, 0]) cube([8,24,upperHeight+middleHeight+downHeight+3],center=true);
	// Minus two holes for m2.5 screws
	translate([grooveHoleRadius +2, -microSwitchHolesDistance/2, -2.3]) rotate([0,90,0]) cylinder(r=m25ScrewRadius, h=30,center=true);
	translate([grooveHoleRadius +2, microSwitchHolesDistance/2, -2.3]) rotate([0,90,0]) cylinder(r=m25ScrewRadius, h=30,center=true);
	translate([grooveHoleRadius + 3, 0, -3.3]) rotate([0,0,90]) %microswitch();

	// Minus a pulling screw hole
	translate([longEdge*sqrt3/3-7,0,-4]) cylinder(r=3.5, h=4,center=true);
	translate([longEdge*sqrt3/3-7,0,0])  roundedBox([m3ScrewRadius*4, m3ScrewRadius*2.5,100], m3ScrewRadius, center=true);

	// Minus some preset holes for wires pass through
	translate([-longEdge*sqrt3/3+10,0,0]) rotate([0,35,0]) roundedBox([m3ScrewRadius*3+1, m3ScrewRadius*5.5+1,  100], m3ScrewRadius, center=true);

	// Minus an inner channel to let the wire pass through for microSwitch
	translate([-2,0,-1]) difference() {
	    cylinder(r=grooveHoleRadius + 7.5, h= 4,center=true);
	    cylinder(r=grooveHoleRadius + 5, h=4, center=true);
	    translate([50,0,0]) cube([100,20,5],center=true);
	}
	translate([-2,0,-2]) for (i=[45:45:315]) {
	    rotate([0,0,-i]) translate([grooveHoleRadius+6.5,0,0]) cube([m3ScrewRadius*2.5, m3ScrewRadius*3, 6], center=true);}

	// Leave fans Mounting holes

	for (i=[30:120:260]) {
	    translate ([cos(i)*mountingHoleDistance/2, sin(i)*mountingHoleDistance/2,0])
	    translate ([sin(i)*(ballSeperateDistance/2+3), -cos(i)*(ballSeperateDistance/2+3),0])
	    rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0]) cylinder(r=m25ScrewRadius, h=30,center=true);

	    translate ([-cos(i)*mountingHoleDistance/2, -sin(i)*mountingHoleDistance/2,0])
	    translate ([sin(i)*(ballSeperateDistance/2+3), -cos(i)*(ballSeperateDistance/2+3),0])
	    rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0]) cylinder(r=m25ScrewRadius, h=30,center=true);

	}

    }
    echo ("Base Height =", upperHeight+middleHeight+downHeight);
}

module fanCone(){
    difference(){
	// outer profile
	hull(){
	    minkowski(){
		cube([25-roundness*2,25-roundness*2,5],center=true);
		cylinder(r=roundness,h=1,center=true);
	    }
	    translate([0,10,-25])
	    rotate([5,0,0])
	    minkowski(){
		cube([24-roundness,15-roundness,1],center=true);
		cylinder(r=roundness/2,h=1,center=true);
	    }
	}
    }
}

module fanConeInner(){
    // inner profile
    hull(){
	minkowski(){
	    cube([20-roundness*2,20-roundness*2,6],center=true);
	    cylinder(r=roundness,h=1,center=true);
	}
	translate([0,10,-26])
	rotate([5,0,0])
	minkowski(){
	    cube([18-roundness,10-roundness,1],center=true);
	    cylinder(r=roundness/2,h=1,center=true);
	}
    }
}

//**************************************** New **************************************************
RadiatorRadius = 20;
RadiatorHeight = 30;
GrooveMountRadius = 8;

V6SinkHeight = 25;
V6SinkRadius = 22.3/2;
proxSensor_x = 17.5;
proxSensor_y = 17.5;
proxSensor_z = 35;

module lowerLayerShape()
{
    union(){
	// Draw the basic profile
	linear_extrude(height= upperHeight,center = false,convexity=10,scale=upperScaleFactor)
	triangleShape();

	translate([0,0,-middleHeight]) linear_extrude(height= middleHeight,center = false)
	triangleShape();

	translate([0,0,-middleHeight]) rotate([180,0,0])
	linear_extrude(height=downHeight, center = false, scale=underScaleFactor)
	triangleShape();

    }

}

module lowerLayer(){
    difference(){
	union(){
	    //hull(){
		lowerLayerShape();
		//for(i=[0,1])mirror([0,i,0])rotate([0,0,-30])translate([0,baseShapeRadius*sqrt3/3-10,0])rotate([70,0,0])
		//cube([25,10,25],center=true);
	    //}

	    // Draw Pillars for Ball Joints
	    for (i=[30:120:270])
	    for (j=[-1,1])
	    translate ([j*cos(i)*ballSeperateDistance/2, j*sin(i)*ballSeperateDistance/2,0])
	    translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
	    rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0]) pillar();

	}
	// screw holes

	for (i=[30:120:270])
	for (j=[-1,1])
	translate ([j*cos(i)*ballSeperateDistance/2, j*sin(i)*ballSeperateDistance/2,0])
	translate ([sin(i)*(baseShapeRadius/2-roundness/2), -cos(i)*(baseShapeRadius/2-roundness/2),0])
	rotate([cos(i)*ballJointAngle, sin(i)*ballJointAngle,0])
	{
	    cylinder(r=m4ScrewRadius, h=20, center = true);
	    translate([0,0,-6]) cylinder(r=m4ScrewHeadRadius, h=12, center=true);
	}

	// Central Hole
	translate([0,0,-20 ])linear_extrude(height= 30) scale([0.67,0.67,1]) triangleShape();

    }

}

module V6Profile()
{
    cylinder(r= V6SinkRadius+1.5, h=26);
    cylinder(r= 8, h= 34);
    cylinder(r= 6, h= 40);
    translate([0,0,39])cylinder(r= 8, h=6);

}

module upperLayer()
{
    difference(){
	// Basic shape
	minkowski(){
	    union(){
		// Heat Sink mount
		translate([0,0,8])
		rotate([0,0,0])
		linear_extrude(height=V6SinkHeight-10, scale=0.6) scale([0.35, 0.35, 1]) triangleShape();

		for(i=[0:120:240])
		rotate([0,0,i])
		translate([V6SinkRadius,0,0])
		{
		    translate([0,0, V6SinkHeight/3-2])cube([V6SinkRadius, V6SinkRadius*.7, V6SinkHeight/3],center=true);
		    hull(){
			translate([V6SinkRadius*0.5,0, V6SinkHeight/3-2])cube([1, V6SinkRadius*.7, V6SinkHeight/3],center=true);
			translate([18,0,.5]) cube([2, V6SinkRadius*.8, 1],center=true);
		    }
		}

	    }

	    // smooth the profile
	    cylinder( r=3.5, h=3);
	}
	translate([0,0,-14]) V6Profile();

	// Heat sink cooling fan

    }

}

module upperPart(){

    // prox sensor mount
    #translate([V6SinkRadius + proxSensor_x/2, 0, -13])
    cube([proxSensor_x, proxSensor_y, proxSensor_z], center=true);

    difference(){
	import("./upperLayer.stl");
	// Heat sink cooling fan
	#translate([-16,0,-1])
	rotate([0,90,0])
	minkowski(){
	    cube([21,21,8],center=true);
	    cylinder(r=2, h=1, center=true);
	}

	// Print fans
	for(i=[-1,1])
	#rotate([0,0,i*120])
	translate([-30,0,-5])
	rotate([0,75,0])//-i*15])
	minkowski(){
	    cube([31,31,8], center=true);
	    cylinder(r=2, h=1, center=true);
	}
    }

}

module body()
{
    difference(){
	union(){
	    lowerLayer();
            translate([0,0,upperHeight-4]) upperPart();

//	    for(i=[0,1])mirror([0,i,0])rotate([0,0,30])
//	    translate([0,-(baseShapeRadius+4)*sqrt3/3,3])
//	    rotate([10,0,0])
//	    fanCone();
	}

	//translate([0,0,-27.5])cylinder(r=grooveHoleRadius+5, h= 70, center=true);
	//%translate([0,0,5])cylinder(r=10, h= 70, center=true);

//	translate([-35,0,12])rotate([0,0,0]) //fanCone();
//	minkowski(){
//	    cube([50,25-roundness*2,25-roundness*2],center=true);
//	    rotate([0,90,0])cylinder(r=roundness, h=1,center=true);
//	}
	// wind holes
	//translate([18,0,25])
//	for(i=[-10:5:10])
//	translate([25,i,12])
//	hull(){
//	    rotate([0,90,0])cylinder(r=1.1, h=40,center=true);
//	    translate([0,0,8-i*i*.03]) rotate([0,90,0])cylinder(r=1.1, h=40, center=true);
//	}

//	for(i=[0,1])mirror([0,i,0])rotate([0,0,30])
//	translate([0,-(baseShapeRadius+4)*sqrt3/3,3])
//	rotate([10,0,0])
//	fanConeInner();

    }
}

//color("grey")
 body();
!upperLayer();

color("silver") translate([-2,0,-29]) rotate([0,0,0])import("./e3d-v6.stl");

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


cleanup and mount extension by 1mm

cleanup and mount extension by 1mm

//$fs = 0.1;
//$fa = 5;
$fs = 0.25;
$fa = 8;

use <hcsr04.scad>

// size is the XY plane size, height in Z
module hexagon(size, height) {
  boxWidth = size/1.75;
  for (r = [-60, 0, 60]) rotate([0,0,r]) cube([boxWidth, size, height], true);
}

module screw2x6bore() {
    rotate([180, 0, 0]) {
        cylinder(d=2.2, h=6);
        translate ([0, 0, -1.3])
            cylinder(d1=2*3.6, d2=0, h=2*1.3);
    }
}

// model wheel
module wheel() {
    color("black") rotate([90, 90, 0]) difference() {
        #cylinder(d=47, h=23, center=true);
        cylinder(d=30, h=26, center=true);
    }
}

// car base plate outline
module base_plate() {
    polygon([
        [-79,25], [-70,25],[-54,40],[49,40],[70,23], [79,23],
        [79,-23], [70,-23],[49,-40],[-54,-40],[-70,-25], [-79,-25]
    ]);
}

// base car
module base() {

    // 4 wheels
    translate([77.5, 60, 47/2]) wheel();
    translate([-77.5, 60, 47/2]) wheel();
    translate([77.5, -60, 47/2]) wheel();
    translate([-77.5, -60, 47/2]) wheel();

    // front axe assemby - slightly longer than rear
    translate([77.5-5, 0, 47/2]) color("gray") cube(size=[25, 103, 26], center=true);

    // rear axe assemby
    translate([-77.5, 0, 47/2]) color("gray") cube(size=[26, 97, 26], center=true);

    color("gray") translate ([0, 0, 12]) {

        // base plate
        linear_extrude(height = 2) base_plate();
        linear_extrude(height = 7) // extra lip around base
            difference() {
                base_plate();
                offset(-2) base_plate();
            }

        // shaft assembly
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);

        //shaft ribs
        translate ([14, 4, 23]) cube(size=[67, 2, 4], center=false);
        translate ([14, -6, 23]) cube(size=[67, 2, 4], center=false);
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        translate ([-81, 4, 23]) cube(size=[45, 2, 6], center=false);
        translate ([-81, -6, 23]) cube(size=[45, 2, 6], center=false);

        // servo
        linear_extrude(height = 15)  polygon([
            [29,0], [79,0],
            [79,-23], [70,-23],[49,-40],[29,-40]
        ]);

        // motor
        translate ([-79+30, -16, 23/2+2]) rotate([0, 90, 0]) cylinder(d=23, h=32, center=false);

        // main gear
        translate ([-79+23, 0, 34/2]) rotate([0, 90, 0]) cylinder(d=34, h=6, center=false);

        // battery
        translate ([-5/2, 30/2+7, 16/2+2]) cube(size=[84, 30, 16], center=true);

        // battery holder
        translate ([-79+23, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([79-29, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([-5/2, 20, 22]) cube(size=[110, 13, 2], center=true);

        // front shocks and tower
        translate ([162/2, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[23,44],[18,48],[5,41],[-5,41],[-18,48],[-23,44], [-38,0],[38,0]]);

        // rear shocks and tower
        translate ([-162/2-16, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[25,48],[20,48],[5,38],[-5,38],[-20,48],[-25,48], [-38,0],[38,0]]);
    }
}

// 3d printed platform to be attached to shock towers
module platform() {

    color("black") difference()
    {
        translate ([0, 0, 12+32+4])
            difference()
            {
                union()
                {

                    // basic plate
                    #linear_extrude(height = 3)
                        difference()
                        {
                            intersection()
                            {
                                offset(-10) offset(30) offset(-20) // rounded corners
                                   polygon([
                                     [-200,25], [-70,25],[-44,60],[34,60],[70,25], [200,25], // extra wide front
                                     [200,-25], [70,-25],[34,-60],[-44,-60],[-70,-25], [-200,-25]
                                   ]);
                               square(size=[162,200], center=true); // cut off extra length
                            }

                            // central hole
                            translate ([-12.5, 0, 0])
                                offset(-5) offset(10) offset(-5) // rounded corners
                                    polygon([
                                     // left
                                     [-45,-20], [-31,-37], // bevel around [-45,-35],
                                     [ 32,-37], [ 45,-27], // bevel around [45,-35],

                                     [48,-27], [48,27],

                                     // right
                                     [ 45, 27], [ 32, 37], // bevel around [45,35],
                                     [-31, 37], [-45, 20]  // bevel around [-45,35]
                                    ]);

                            // wire tie holes
                            #translate ([-45, -45, 0]) circle(d=5);
                            #translate ([-45,  45, 0]) circle(d=5);
                            #translate ([-35, -45, 0]) circle(d=5);
                            #translate ([-35,  45, 0]) circle(d=5);
                        }

                    intersection()
                    {
                        #union()
                        { // shock tower mount points

                            // rear
                            translate ([-81, -25, 0]) {
                                hull() {
                                    cube(size=[4, 7, 12-3.5], center=false);
                                    translate ([4/2, 3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
                                }
                                translate ([8/2, 3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
                            }

                            translate ([-81, 25-7, 0]) {
                                hull() {
                                    cube(size=[4, 7, 12-3.5], center=false);
                                    translate ([4/2, 7-3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
                                }
                                translate ([8/2, 7-3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
                            }

                            // front
                            translate ([81-6.5, -25, 0]) {
                                cube(size=[6.5, 11, 4], center=false);
                                translate ([6.5/2, 5.5, 4]) rotate([90, 0, 90]) cylinder(d=11, h=6.5, center=true);
                            }

                            translate ([81-6.5, 25-11, 0]) {
                                cube(size=[6.5, 11, 4], center=false);
                                translate ([6.5/2, 5.5, 4]) rotate([90, 0, 90]) cylinder(d=11, h=6.5, center=true);
                            }
                        }
                        translate ([0, 0, 100]) cube(size=[200,200,200], center=true);  // cut off bottom parts from all cylynders
                    }
                }

                // local positioned cutouts

                // esc power wires
                #hull()
                {
                    translate ([48-12.5-5, 23, 0]) cylinder(d=6, h=20, center=true);
                    translate ([54-12.5,   23, 0]) cylinder(d=6, h=20, center=true);
                }

                // esc motor wires
                #hull()
                {
                    translate ([48-12.5-5, -23,   0]) cylinder(d=6, h=20, center=true);
                    translate ([54-12.5,   -23+4, 0]) cylinder(d=6, h=20, center=true);
                    translate ([54-12.5,   -23,   0]) cylinder(d=6, h=20, center=true);
                    translate ([48-12.5,   -23+4, 0]) cylinder(d=6, h=20, center=true);
                }

                // space save
                #hull() {
                    translate ([52, -10, 0]) cylinder(d=5, h=20, center=true);
                    translate ([42, -10, 0]) cylinder(d=5, h=20, center=true);
                    translate ([42,  10, 0]) cylinder(d=5, h=20, center=true);
                    translate ([52,  10, 0]) cylinder(d=5, h=20, center=true);
                }

                // space save
                #hull()
                {
                    translate ([-72, -10, 0]) cylinder(d=5, h=20, center=true);
                    translate ([-67, -10, 0]) cylinder(d=5, h=20, center=true);
                    translate ([-67,  10, 0]) cylinder(d=5, h=20, center=true);
                    translate ([-72,  10, 0]) cylinder(d=5, h=20, center=true);
                }

                // board mount holes
                #translate ([-(45-2.5)-10,  (35-2.5), 2.5]) screw2x6bore();
                #translate ([-(45-2.5)-10, -(35-2.5), 2.5]) screw2x6bore();
                #translate ([ (45-2.5)-10,  (35-2.5), 2.5]) screw2x6bore();
                #translate ([ (45-2.5)-10, -(35-2.5), 2.5]) screw2x6bore();

                // mount holes
                // front
                // M3 hex nut in front H=2.4, Dmin = 5.4
                // left
                #translate ([81, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
                #translate ([81-4-5/2, 42.5/2-3/2, 8-2-3/2]) rotate([90, 90, 90]) hexagon(5.5, 6);
                // right
                #translate ([81,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
                #translate ([81-4-5/2,-42.5/2+3/2, 8-2-3/2]) rotate([90, 90, 90]) hexagon(5.5, 6);

                // rear
                // left
                #translate ([-81, 46.5/2-3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true); // top thru hole
                #translate ([-81,-46.5/2+3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true); // bottom hole for pins? or unused
                // right
                #translate ([-81,-46.5/2+3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true); // top thru hole
                #translate ([-81, 46.5/2-3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true); // bottom hole for pins? or unused
            }

        // global positioned coutouts

        // sonar mount hole cutouts
        #arrange(30)
        {
            mount_holes(center=true, right=1, left=1);
            mount_holes(center=true, right=0, left=1);
            mount_holes(center=true, right=0, left=1);
            mount_holes(center=true, right=1, left=0);
            mount_holes(center=true, right=1, left=0);
        }

        // cage hole cutout
        #cage(mode=1/*cut*/);

    }
}

module board() {

    translate ([-12.5, 0, 47]) {
        // base
        color("yellow") cube(size=[90, 70, 1.2], center=true);

        // teensy
        color("green") translate ([-12, 0, 5]) cube(size=[63, 18, 10], center=true);

        // MPU-9250
        color("red") translate ([-24, 21, 5]) cube(size=[18.5, 19, 10], center=true);

        // servo conn
        color("black") translate ([27, -21, 1.5]) cube(size=[10, 7.5, 3], center=true);
    }
}

module esc() {
    color("green") cube(size=[36, 26, 2], center=true);
    color("black") translate ([36/2, 0, 0]) rotate([0, 90, 0]) cylinder(d=8, h=16, center=false);
}

// horizontal sonar mounting holes
module mount_holes(center = true, left = 2, right = 2)
{
    if (center) translate ([-5,    0, -15]) cylinder(d=3.2, h=15, center=false);

    if (left >= 1) translate ([-5,  9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (left >= 2) translate ([-5,  19, -15]) cylinder(d=3.2, h=15, center=false);

    if (right >= 1) translate ([-5, -9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (right >= 2) translate ([-5, -19, -15]) cylinder(d=3.2, h=15, center=false);
}

// sonar mount bracket
module mount() {

    extra = 7;
    top_r = 3;
    bottom_r = 5;

    // mount plate
    color ("gray") {

        // front
        difference() {

            // front plate
            translate ([1.5, -48/2, -extra])
                #union() {
                    cube(size=[3, 48, 19+extra], center=false);
                    translate ([0, top_r, 0]) cube(size=[3, 48-2*top_r, 19+extra+top_r], center=false);
                    translate ([0, 48-top_r, 19+extra]) rotate([90, 0, 90]) cylinder(r=top_r, h=3, center=false);
                    translate ([0, top_r, 19+extra]) rotate([90, 0, 90]) cylinder(r=top_r, h=3, center=false);
                }

            // hc-sr04 cutouts
            translate ([0, -45/2, 0]) rotate([90, 0, 90]) {

                // sonar holes
                translate([45/2-(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);
                translate([45/2+(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);

                //xtals holes - bot upside and downwards
                hull () {
                    translate([45/2-3.25,20-3.5,1.3])
                    {
                        translate([0,0,0]) cylinder(d=6, h=5);
                        translate([6.5,0,0]) cylinder(d=6, h=5);
                    }
                    translate([45/2-3.25, 4,1.3]) hull()
                    {
                        translate([0,-2,0]) cylinder(d=6, h=5);
                        translate([6.5,-2,0]) cylinder(d=6, h=5);
                    }
                }

                // screws
                translate([   1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([45-1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
                translate([45-1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([   1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
            }

            // center cleanup
            translate ([3, 0, 10]) cube(size=[5, 20, 11], center=true);
        }

        //base
        difference() {
            #union() {
                translate ([-3.5, -48/2, -extra]) cube(size=[10-bottom_r, 48, 5], center=false);
                translate ([-3.5-bottom_r, -48/2+5, -extra]) cube(size=[10, 48-2*bottom_r, 5], center=false);
                translate ([-3.5, -48/2+5, -extra]) cylinder(r=bottom_r, h=5, center=false);
                translate ([-3.5, 48/2-5, -extra]) cylinder(r=bottom_r, h=5, center=false);
            }
            mount_holes();
        }
    }
}

// horizantaly mounted sonar
module horizontal_sonar() {

    // horizontal sonar
    translate ([0, -45/2, 0]) rotate([90, 0, 90]) hcsr04();

    mount();

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 10]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

// horizantaly mounted sonar - mockup
module vertical_sonar() {

    // vertical sonar
    translate ([0, -10, 45]) rotate([0, 90, 0]) hcsr04();

    // mount bracket outline
    color("gray") translate ([1.5, -10, -6]) cube(size=[3, 20, 51], center=false);
    color("gray") translate ([-8.5, -10, -6]) cube(size=[10, 20, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 22.5]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

// rounded box from p1 to p2, size (~diameter) s, rounding radius r
module rounded_box(p1, p2, s=1, r=1) {

    a = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]];
    l = norm(a);
    b = [a[0]/l, a[1]/l, a[2]/l];

    l1 = l+s-2*r;

    c = cross([0,0,1], b);

    az = atan2(c[0], c[1]);
    ax = acos(b[2]);

    o = s/2-r;
    s1 = s-2*r;

    translate(p1)
        rotate([0, 0, -az])
           rotate([0, ax, 0])
               translate([0, 0, l/2]) {
                    cube(size=[s1, s, l1], center=true);
                    cube(size=[s, s1, l1], center=true);

                    for (x=[o, -o])
                        for (y=[o, -o]) {
                            translate([x,y,0]) cylinder(r=r, h=l1, center=true);
                            for (z=[l1/2, -l1/2]) {
                                translate([x,y,z]) sphere(r=r, center=true);
                            }
                        }

                    for (z=[l1/2, -l1/2]) {
                        translate([0,0,z]) cube(size=[s1, s1, 2*r], center=true);

                        translate([ 0, o, z]) rotate([0,90,0]) cylinder(r=r, h=s1, center=true);
                        translate([ 0,-o, z]) rotate([0,90,0]) cylinder(r=r, h=s1, center=true);
                        translate([ o, 0, z]) rotate([90,0,0]) cylinder(r=r, h=s1, center=true);
                        translate([-o, 0, z]) rotate([90,0,0]) cylinder(r=r, h=s1, center=true);
                    }

               }
}

// rounded cylindrical rod p1 to p2, diameter s
module rod(p1, p2, s=1) {

    a = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]];
    l = norm(a);
    b = [a[0]/l, a[1]/l, a[2]/l];

    c = cross([0,0,1], b);

    az = atan2(c[0], c[1]);
    ax = acos(b[2]);

    translate(p1) sphere(d=s, center=true);
    translate(p2) sphere(d=s, center=true);

    translate(p1)
        rotate([0, 0, -az])
           rotate([0, ax, 0])
               cylinder(d=s, h=l, center=false);
}

// 8 balls of radius r, arranged in bounding box for rounded cybe of size s centered on p
module ball8(p, s=1, r=1) {

    o = s/2-r;

    translate(p)
        for (x=[o, -o])
            for (y=[o, -o])
                for (z=[o, -o])
                    translate([x,y,z])
                        sphere(r=r, center=true);
}

// cage leg, from base p1 to top p2, size s, base size base_s, rounding radius s, mode - simple=2 or full otherwise
module cage_leg(p1, p2, s, base_s, r, mode)
{
    if (mode == 2 /*simple*/) {
        rod(p1, p2, s);
    }
    else {
        hull() {
            ball8(p2, s, r);
            translate([0, 0, -d/2]) translate(p1) difference() { // halfsphere of d = base_s
                sphere(d=base_s, center=true);
                translate([0, 0, -base_s/2]) cube(size=[base_s, base_s, base_s], center=true);
            }
        }
    }
}

// cage mount pin, from base p1 to below p1, size d (bit larger for cuts), pin diameter pd, pin heigh ph, mode - 1 for cutout
module cage_pin(p1, p2, d, pd, ph, mode)
{
    if (mode == 1 /*cut*/)
    {
        rod(p1, p2, d+0.5); // extra spacing
    }
    else // full or simple mode
    difference() {
        rod(p1, p2, d);

        #translate ([0,0,-ph])
            translate (p1)
                rotate([0,90,0])
                    cylinder(d=pd, h=2*d, center=true); // pin hole
    }
}

// lcd mount bracket for cage
module lcd_mount(p, x1, x2)
{
    translate(p) difference() {
        #translate([(x1-x2)/2,0,-1-0.5/2]) cube(size=[x1+x2, 6, 2.5], center=true);
        #translate([0,0,-0.5]) screw2x6bore();
    }
}

// cage
module cage(mode = 0)
{
    // mode 0 - full, mode 1 - cutout for platform, 2 - simple full

    d = 4;
    r1 = 1;
    n = 4;
    db = 6;
    hb = d;
    pd = 1;
    ph = d/2 + 3 /*platform*/+ 1/*freespace*/;

    // measurements
    top = 82;

    top_side = 30;

    top_front = 20;
    top_rear = -40;

    top_esc = top_front+26/*esc size*/;
    top_lcd = top_rear+27/*lcd size*/+d+1;

    bottom = 51/*platform top*/+d/2;

    bottom_front = 27;
    bottom_rear = -50;

    bottom_front_side = 40;
    bottom_rear_side = 40;

    pin = 8;
    pin_base = bottom - pin;

    mid = (top+bottom)/2;
    mid_side = 15;
    mid_front = top_esc+10;

    // points
    top_front_left = [top_front, top_side, top];
    top_front_right = [top_front, -top_side, top];

    top_esc_left = [top_esc, top_side, top];
    top_esc_right = [top_esc, -top_side, top];

    top_lcd_left = [top_lcd, top_side, top];
    top_lcd_right = [top_lcd, -top_side, top];

    top_rear_left = [top_rear, top_side, top];
    top_rear_right = [top_rear, -top_side, top];

    mid_front_left = [mid_front, mid_side, mid];
    mid_front_right = [mid_front_left[0], -mid_front_left[1], mid_front_left[2]];

    bottom_front_left = [bottom_front, bottom_front_side, bottom];
    bottom_front_right = [bottom_front, -bottom_front_side, bottom];

    bottom_rear_left = [bottom_rear, bottom_rear_side, bottom];
    bottom_rear_right = [bottom_rear, -bottom_rear_side, bottom];

    pin_front_left = [bottom_front, bottom_front_side, pin_base];
    pin_front_right = [bottom_front, -bottom_front_side, pin_base];

    pin_rear_left = [bottom_rear, bottom_rear_side, pin_base];
    pin_rear_right = [bottom_rear, -bottom_rear_side, pin_base];

    // cage bars
    if (mode != 1 /*cut*/)
    {
        rounded_box(top_front_left, top_front_right, d, r1);
        rounded_box(top_rear_left, top_rear_right, d, r1);
        rounded_box(top_esc_left, top_rear_left, d, r1);
        rounded_box(top_esc_right, top_rear_right, d, r1);

        rounded_box(top_esc_left, top_esc_right, d, r1);
        rounded_box(top_lcd_left, top_lcd_right, d, r1);

        rod(mid_front_left, top_esc_left, d);
        rod(mid_front_right, top_esc_right, d);

        lcd_mount([top_rear+d/2+2.5+23+0.5,  23.5/2, top+d/2], 4, 2);
        lcd_mount([top_rear+d/2+2.5+23+0.5, -23.5/2, top+d/2], 4, 2);
        lcd_mount([top_rear+d/2+2.5-0.5,     23.5/2, top+d/2], 2, 4);
        lcd_mount([top_rear+d/2+2.5-0.5,    -23.5/2, top+d/2], 2, 4);

        cage_leg(bottom_front_left, top_front_left, d, db, r1, mode);
        cage_leg(bottom_front_right, top_front_right, d, db, r1, mode);
        cage_leg(bottom_rear_left, top_rear_left, d, db, r1, mode);
        cage_leg(bottom_rear_right, top_rear_right, d, db, r1, mode);

        // lcd lead protector
        translate([top_lcd+1,0,top-3]) cube(size=[2, 12, 6], center=true);
        translate([top_lcd+1,0,top-5]) cube(size=[2, 16, 2], center=true);
    }

    cage_pin(bottom_front_left, pin_front_left, d, pd, ph, mode);
    cage_pin(bottom_front_right, pin_front_right, d, pd, ph, mode);
    cage_pin(bottom_rear_left, pin_rear_left, d, pd, ph, mode);
    cage_pin(bottom_rear_right, pin_rear_right, d, pd, ph, mode);
}

module lcd() {
    color("blue") translate([-40+2+27.5/2+0.5,0,81]) cube(size=[27.5, 27.5, 2], center=true);
}

// arange sonars (or mount holes)
module arrange(a) {
    translate ([68, 0, 58]) if ($children == 1) children(); else children(0);

    translate ([45, 42, 58]) rotate([0, 0, a]) if ($children == 1) children(); else children(1);
    translate ([-5, 45, 58]) rotate([0, 0, 2*a]) if ($children == 1) children(); else children(2);

    translate ([45, -42, 58]) rotate([0, 0, -a]) if ($children == 1) children(); else children(3);
    translate ([-5, -45, 58]) rotate([0, 0, -2*a]) if ($children == 1) children(); else children(4);
}

// whole car
module car()
{
    base();
    platform();
    board();
    arrange(30) horizontal_sonar();
    color("white") cage(mode=2/*simple*/);
    translate ([33, -8, 79]) rotate([0, 0, 90]) esc();
    lcd();
}

//car();
//cage();
//board();
//platform();
//translate ([0, 0, 4.5]) rotate([0, 90, 0]) mount();
//rotate([0,0,180]) projection(cut=true) translate ([0, 0, -49]) platform();
//translate([0,0,90]) rotate([180,0,0]) cage();

//$fs = 0.1;
//$fa = 5;
$fs = 0.25;
$fa = 8;

use <hcsr04.scad>

module wheel() {
    color("black") rotate([90, 90, 0]) difference() {
        #cylinder(d=47, h=23, center=true);
        cylinder(d=30, h=26, center=true);
    }
}

module base() {

    // 4 wheels
    translate([77.5, 60, 47/2]) wheel();
    translate([-77.5, 60, 47/2]) wheel();
    translate([77.5, -60, 47/2]) wheel();
    translate([-77.5, -60, 47/2]) wheel();

    // front axe assemby - slightly longer
    translate([77.5-5, 0, 47/2]) color("gray") cube(size=[25, 103, 26], center=true);
    // rear axe assemby
    translate([-77.5, 0, 47/2]) color("gray") cube(size=[26, 97, 26], center=true);

    color("gray") translate ([0, 0, 12]) {

        // base plate
        linear_extrude(height = 2) base_plate();
        linear_extrude(height = 7) difference() {
            base_plate();
            offset(-2) base_plate();
        }

        // shaft
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        //shaft ribs
        translate ([14, 4, 23]) cube(size=[67, 2, 4], center=false);
        translate ([14, -6, 23]) cube(size=[67, 2, 4], center=false);
        translate ([0, 0, 23/2]) cube(size=[158, 12, 23], center=true);
        translate ([-81, 4, 23]) cube(size=[45, 2, 6], center=false);
        translate ([-81, -6, 23]) cube(size=[45, 2, 6], center=false);
        // servo
        linear_extrude(height = 15)  polygon([
            [29,0], [79,0],
            [79,-23], [70,-23],[49,-40],[29,-40]
        ]);

        // motor
        translate ([-79+30, -16, 23/2+2]) rotate([0, 90, 0]) cylinder(d=23, h=32, center=false);

        // gear
        translate ([-79+23, 0, 34/2]) rotate([0, 90, 0]) cylinder(d=34, h=6, center=false);

        // battery
        translate ([-5/2, 30/2+7, 16/2+2]) cube(size=[84, 30, 16], center=true);

        // battery holder
        translate ([-79+23, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([79-29, 20, 0]) cylinder(d=7, h=26, center=false);
        translate ([-5/2, 20, 22]) cube(size=[110, 13, 2], center=true);

        // front shocks
        translate ([162/2, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[23,44],[18,48],[5,41],[-5,41],[-18,48],[-23,44], [-38,0],[38,0]]);

        // rear shocks
        translate ([-162/2-16, 0, 0]) rotate([90, 0, 90]) linear_extrude(height = 16)
            polygon([[25,48],[20,48],[5,38],[-5,38],[-20,48],[-25,48], [-38,0],[38,0]]);
    }
}

module base_plate() {
    polygon([
        [-79,25], [-70,25],[-54,40],[49,40],[70,23], [79,23],
        [79,-23], [70,-23],[49,-40],[-54,-40],[-70,-25], [-79,-25]
    ]);
}

// size is the XY plane size, height in Z
module hexagon(size, height) {
  boxWidth = size/1.75;
  for (r = [-60, 0, 60]) rotate([0,0,r]) cube([boxWidth, size, height], true);
}

module platform() {

    difference() {
    color("black") translate ([0, 0, 12+32+4]) difference() {
        union() {
            #linear_extrude(height = 3) intersection() {
                difference() {
                    offset(-10) offset(30) offset(-20)
                       polygon([
                         [-200,25], [-70,25],[-44,60],[34,60],[70,25], [200,25], // extra wide front
                         [200,-25], [70,-25],[34,-60],[-44,-60],[-70,-25], [-200,-25]
                       ]);

                    // central hole
                    translate ([-12.5, 0, 0])
                    offset(-5) offset(10) offset(-5) difference() {

                        polygon([
                         // left
                         [-45,-20], [-31,-37], // bevel [-45,-35],
                         [ 32,-37], [ 45,-27], // bevel [45,-35],

                         [48,-27], [48,27],

                         // right
                         [ 45, 27], [ 32, 37], // bevel [45,35],
                         [-31, 37], [-45, 20]  // bevel [-45,35]
                        ]);

                        //translate ([-45, -35, 0]) circle(r=7.5, center=true);
                        //translate ([-45,  35, 0]) circle(r=7.5, center=true);
                        //translate ([ 45, -35, 0]) circle(r=7.5, center=true);
                        //translate ([ 45,  35, 0]) circle(r=7.5, center=true);
                   }

                }
                square(size=[162,120], center=true); // cut off extra length
            }

            intersection() { translate ([0, 0, 100]) cube(size=[200,200,200], center=true); union() {
            // shock tower mount points
            // rear
            #translate ([-81, -25, 0]) {
                hull() {
                    cube(size=[4, 7, 12-3.5], center=false);
                    translate ([4/2, 3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
                }
                translate ([8/2, 3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }
            #translate ([-81, 25-7, 0]) {
                hull() {
                    cube(size=[4, 7, 12-3.5], center=false);
                    translate ([4/2, 7-3.5, 12-3.5]) rotate([90, 0, 90]) cylinder(d=7, h=4, center=true);
                }
                translate ([8/2, 7-3.5, 12-3.5-6]) rotate([90, 0, 90]) cylinder(d=6, h=8, center=true);
            }

            // front
            #translate ([81-6.5, -25, 0]) {
                cube(size=[6.5, 11, 4], center=false);
                translate ([6.5/2, 5.5, 4]) rotate([90, 0, 90]) cylinder(d=11, h=6.5, center=true);
            }
            #translate ([81-6.5, 25-11, 0]) {
                cube(size=[6.5, 11, 4], center=false);
                translate ([6.5/2, 5.5, 4]) rotate([90, 0, 90]) cylinder(d=11, h=6.5, center=true);
            }
            }}
        }

        // wire tie holes
        #translate ([-45, -45, 0]) cylinder(d=5, h=20, center=true);
        #translate ([-45,  45, 0]) cylinder(d=5, h=20, center=true);
        #translate ([-35, -45, 0]) cylinder(d=5, h=20, center=true);
        #translate ([-35,  45, 0]) cylinder(d=5, h=20, center=true);

        // esc power wires
        #hull() {
            translate ([48-12.5-5, 23, 0]) cylinder(d=6, h=20, center=true);
            translate ([54-12.5,   23, 0]) cylinder(d=6, h=20, center=true);
        }

        // esc motor wires
        #hull() {
            translate ([48-12.5-5, -23,   0]) cylinder(d=6, h=20, center=true);
            translate ([54-12.5,   -23+4, 0]) cylinder(d=6, h=20, center=true);
            translate ([54-12.5,   -23,   0]) cylinder(d=6, h=20, center=true);
            translate ([48-12.5,   -23+4, 0]) cylinder(d=6, h=20, center=true);
        }

        // space save
        #hull() {
            translate ([52, -10, 0]) cylinder(d=5, h=20, center=true);
            translate ([42, -10, 0]) cylinder(d=5, h=20, center=true);
            translate ([42,  10, 0]) cylinder(d=5, h=20, center=true);
            translate ([52,  10, 0]) cylinder(d=5, h=20, center=true);
        }

        // space save
        #hull() {
            translate ([-72, -10, 0]) cylinder(d=5, h=20, center=true);
            translate ([-67, -10, 0]) cylinder(d=5, h=20, center=true);
            translate ([-67,  10, 0]) cylinder(d=5, h=20, center=true);
            translate ([-72,  10, 0]) cylinder(d=5, h=20, center=true);
        }

        // board mount holes
        #translate ([-(45-2.5)-10,  (35-2.5), 2.5]) screw2x6bore();
        #translate ([-(45-2.5)-10, -(35-2.5), 2.5]) screw2x6bore();
        #translate ([ (45-2.5)-10,  (35-2.5), 2.5]) screw2x6bore();
        #translate ([ (45-2.5)-10, -(35-2.5), 2.5]) screw2x6bore();

        // mount holes
        // front
        // M3 hex nut in front H=2.4, Dmin = 5.4
        // left
        #translate ([81, 42.5/2-3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81-4-5/2, 42.5/2-3/2, 8-2-3/2]) rotate([90, 90, 90]) hexagon(5.6, 6);
        // right
        #translate ([81,-42.5/2+3/2, 8-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([81-4-5/2,-42.5/2+3/2, 8-2-3/2]) rotate([90, 90, 90]) hexagon(5.6, 6);

        // rear
        // left
        #translate ([-81, 46.5/2-3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81,-46.5/2+3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
        // right
        #translate ([-81,-46.5/2+3/2, 12-2-3/2]) rotate([90, 0, 90]) cylinder(d=3, h=20, center=true);
        #translate ([-81, 46.5/2-3/2, 12-2-3/2-6]) rotate([90, 0, 90]) cylinder(d=3, h=12, center=true);
    }
    #arrangebottom(30)
    {
        hbaseholes(center=true, right=1, left=1);
        hbaseholes(center=true, right=0, left=1);
        hbaseholes(center=true, right=0, left=1);
        hbaseholes(center=true, right=1, left=0);
        hbaseholes(center=true, right=1, left=0);
    }
    // cage holes
    #cage(mode=1/*cut*/);

    //arrangebottom(45) hbaseholes();
    }
}

module board() {

    translate ([-12.5, 0, 47]) {
    // base
    color("yellow") cube(size=[90, 70, 1.2], center=true);

    // teensy
    color("green") translate ([-12, 0, 5]) cube(size=[63, 18, 10], center=true);

    // MPU-9250
    color("red") translate ([-24, 21, 5]) cube(size=[18.5, 19, 10], center=true);

    // servo conn
    color("black") translate ([27, -21, 1.5]) cube(size=[10, 7.5, 3], center=true);
    }
}

module esc() {
    color("green") cube(size=[36, 26, 2], center=true);
    color("black") translate ([36/2, 0, 0]) rotate([0, 90, 0]) cylinder(d=8, h=16, center=false);

    // esc support box ?
    // hcolor("black") translate ([0, 0, -11]) cube(size=[30, 20, 20], center=true);
}

module vsonar() {

    // vertical sonar
    translate ([0, -10, 45]) rotate([0, 90, 0]) hcsr04();

    // mount plate
    color("gray") translate ([1.5, -10, -6]) cube(size=[3, 20, 51], center=false);
    color("gray") translate ([-8.5, -10, -6]) cube(size=[10, 20, 5], center=false);

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 22.5]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module hbaseholes(center = true, left = 2, right = 2)
{
    if (center) translate ([-5,    0, -15]) cylinder(d=3.2, h=15, center=false);

    if (left >= 1) translate ([-5,  9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (left >= 2) translate ([-5,  19, -15]) cylinder(d=3.2, h=15, center=false);

    if (right >= 1) translate ([-5, -9.5, -15]) cylinder(d=3.2, h=15, center=false);
    if (right >= 2) translate ([-5, -19, -15]) cylinder(d=3.2, h=15, center=false);
}

module hmount() {
    // mount plate
    color ("gray") {

        // front
        difference() {
            translate ([1.5, -48/2, -6]) #hull() {
                cube(size=[3, 48, 25], center=false);
                translate ([0, 48-3, 25]) rotate([90, 0, 90]) cylinder(r=3, h=3, center=false);
                translate ([0, 3, 25]) rotate([90, 0, 90]) cylinder(r=3, h=3, center=false);
            }

            translate ([0, -45/2, 0]) rotate([90, 0, 90]) {

                // sonar
                translate([45/2-(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);
                translate([45/2+(42-16)/2,18/2+1,1.3]) cylinder(d=17, h=15);

                //xtal(s)
                hull () {
                    translate([45/2-3.25,20-3.5,1.3])
                    {
                        translate([0,0,0]) cylinder(d=6, h=5);
                        translate([6.5,0,0]) cylinder(d=6, h=5);
                    }
                    translate([45/2-3.25, 4,1.3]) hull()
                    {
                        //translate([0,0,0]) cylinder(d=6, h=5);
                        //translate([6.5,0,0]) cylinder(d=6, h=5);
                        translate([0,-2,0]) cylinder(d=6, h=5);
                        translate([6.5,-2,0]) cylinder(d=6, h=5);
                    }
                }

                // screws
                translate([   1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([45-1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
                translate([45-1.0,    1.0, 4.5-0.5]) screw2x6bore();
                translate([   1.0, 20-1.5, 4.5-0.5]) screw2x6bore();
            }

            translate ([3, 0, 10])
                cube(size=[5, 20, 11], center=true);
        }

        //base
        difference() {
            #hull() {
                translate ([-3.5, -48/2, -6]) cube(size=[5, 48, 5], center=false);
                translate ([-3.5, -48/2+5, -6]) cylinder(r=5, h=5, center=false);
                translate ([-3.5, 48/2-5, -6]) cylinder(r=5, h=5, center=false);
            }
            hbaseholes();
        }
    }
}

module screw2x6bore() {
    rotate([180, 0, 0]) {
        cylinder(d=2.2, h=6);
        translate ([0, 0, -1.3])
            cylinder(d1=2*3.6, d2=0, h=2*1.3);
    }
}

module hsonar() {

    // horizontal sonar
    translate ([0, -45/2, 0]) rotate([90, 0, 90]) hcsr04();

    hmount();

    // sonar ray
    //color("white") translate ([20+1000/2, 0, 10]) rotate([0, 90, 0]) cylinder(d1=40, d2=520,h=1000, center=true);
}

module barbox(p1, p2, s=1, r=1) {

    a = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]];
    l = norm(a);
    b = [a[0]/l, a[1]/l, a[2]/l];

    l1 = l+s-2*r;

    c = cross([0,0,1], b);

    az = atan2(c[0], c[1]);
    ax = acos(b[2]);

    o = s/2-r;
    s1 = s-2*r;

    translate(p1)
        rotate([0, 0, -az])
           rotate([0, ax, 0])
               translate([0, 0, l/2]) {
                    cube(size=[s1, s, l1], center=true);
                    cube(size=[s, s1, l1], center=true);

                    for (x=[o, -o])
                        for (y=[o, -o]) {
                            translate([x,y,0]) cylinder(r=r, h=l1, center=true);
                            for (z=[l1/2, -l1/2]) {
                                translate([x,y,z]) sphere(r=r, center=true);
                            }
                        }

                    for (z=[l1/2, -l1/2]) {
                        translate([0,0,z]) cube(size=[s1, s1, 2*r], center=true);

                        translate([ 0, o, z]) rotate([0,90,0]) cylinder(r=r, h=s1, center=true);
                        translate([ 0,-o, z]) rotate([0,90,0]) cylinder(r=r, h=s1, center=true);
                        translate([ o, 0, z]) rotate([90,0,0]) cylinder(r=r, h=s1, center=true);
                        translate([-o, 0, z]) rotate([90,0,0]) cylinder(r=r, h=s1, center=true);
                    }

               }
}

module bar(p1, p2, s=1) {

    a = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]];
    l = norm(a);
    b = [a[0]/l, a[1]/l, a[2]/l];

    c = cross([0,0,1], b);

    az = atan2(c[0], c[1]);
    ax = acos(b[2]);

    translate(p1) sphere(d=s, center=true);
    translate(p2) sphere(d=s, center=true);

    translate(p1)
        rotate([0, 0, -az])
           rotate([0, ax, 0])
               cylinder(d=s, h=l, center=false);
}

module ball8(p1, s=1, r=1) {

    o = s/2-r;

    translate(p1)
        for (x=[o, -o])
            for (y=[o, -o])
                for (z=[o, -o])
                    translate([x,y,z])
                        sphere(r=r, center=true);
}

module skew(p1, p2) { // TODO - not working

    a = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]];
    b = [a[0]/a[2], a[1]/a[2]];

    matrix = [
        [ 1, 0, b[1], 0 ],
        [ 0, 1, b[2], 0 ],
        [ 0, 0, 1, 0 ],
        [ 0, 0, 0, 1 ]
    ];

    translate(p1)
        multmatrix(matrix)
                children();
}

module cage_leg(p1, p2, d, db, r, mode)
{
    if (mode == 2) {
        bar(p1, p2, d);
    }
    else {
        hull() {
            ball8(p2, d, r);
            translate([0, 0, -d/2]) translate(p1) difference() {
                sphere(d=db, center=true);
                translate([0, 0, -db/2]) cube(size=[db, db, db], center=true);
            }
        }
    }
}

module cage_pin(p1, p2, d, pd, ph, mode)
{
    extra = mode == 1 /*cut*/ ? 0.5 : 0;

    if (mode == 1)
    {
        bar(p1, p2, d+extra);
    }
    else
    difference() {
        bar(p1, p2, d+extra);

        #translate ([0,0,-ph])
            translate (p1)
                rotate([0,90,0])
                    cylinder(d=pd, h=2*d, center=true);
    }
}

module lcd_mount(p1, x1, x2)
{
    translate(p1) difference() {
        #translate([(x1-x2)/2,0,-1-0.5/2]) cube(size=[x1+x2, 6, 2.5], center=true);
        #translate([0,0,-0.5]) screw2x6bore();
    }
}

module cage(mode = 0)
{
    // mode 0 - full, mode 1 - cutout for platform, 2 - simple full

    d = 4;
    r1 = 1;
    n = 4;
    db = 6;
    hb = d;
    pd = 1;
    ph = d/2 + 3 /*platform*/+ 1/*freespace*/;

    // measurements
    top = 82;

    top_side = 30;

    top_front = 20;
    top_rear = -40;

    top_esc = top_front+26/*esc size*/;
    top_lcd = top_rear+27/*lcd size*/+d+1;

    bottom = 51/*platform top*/+d/2;

    bottom_front = 27;
    bottom_rear = -50;

    bottom_front_side = 40;
    bottom_rear_side = 40;

    pin = 8;
    pin_base = bottom - pin;

    mid = (top+bottom)/2;
    mid_side = 15;
    mid_front = top_esc+10;

    // points
    top_front_left = [top_front, top_side, top];
    top_front_right = [top_front, -top_side, top];

    top_esc_left = [top_esc, top_side, top];
    top_esc_right = [top_esc, -top_side, top];

    top_lcd_left = [top_lcd, top_side, top];
    top_lcd_right = [top_lcd, -top_side, top];

    top_rear_left = [top_rear, top_side, top];
    top_rear_right = [top_rear, -top_side, top];

    mid_front_left = [mid_front, mid_side, mid];
    mid_front_right = [mid_front_left[0], -mid_front_left[1], mid_front_left[2]];

    bottom_front_left = [bottom_front, bottom_front_side, bottom];
    bottom_front_right = [bottom_front, -bottom_front_side, bottom];

    bottom_rear_left = [bottom_rear, bottom_rear_side, bottom];
    bottom_rear_right = [bottom_rear, -bottom_rear_side, bottom];

    pin_front_left = [bottom_front, bottom_front_side, pin_base];
    pin_front_right = [bottom_front, -bottom_front_side, pin_base];

    pin_rear_left = [bottom_rear, bottom_rear_side, pin_base];
    pin_rear_right = [bottom_rear, -bottom_rear_side, pin_base];

    // bars
    if (mode != 1 /*cut*/)
    {
        barbox(top_front_left, top_front_right, d, r1);
        barbox(top_rear_left, top_rear_right, d, r1);
        barbox(top_esc_left, top_rear_left, d, r1);
        barbox(top_esc_right, top_rear_right, d, r1);

        barbox(top_esc_left, top_esc_right, d, r1);
        barbox(top_lcd_left, top_lcd_right, d, r1);

        bar(mid_front_left, top_esc_left, d);
        bar(mid_front_right, top_esc_right, d);

        lcd_mount([top_rear+d/2+2.5+23+0.5,  23.5/2, top+d/2], 4, 2);
        lcd_mount([top_rear+d/2+2.5+23+0.5, -23.5/2, top+d/2], 4, 2);
        lcd_mount([top_rear+d/2+2.5-0.5,     23.5/2, top+d/2], 2, 4);
        lcd_mount([top_rear+d/2+2.5-0.5,    -23.5/2, top+d/2], 2, 4);

        cage_leg(bottom_front_left, top_front_left, d, db, r1, mode);
        cage_leg(bottom_front_right, top_front_right, d, db, r1, mode);
        cage_leg(bottom_rear_left, top_rear_left, d, db, r1, mode);
        cage_leg(bottom_rear_right, top_rear_right, d, db, r1, mode);

        // lcd lead protector
        translate([top_lcd+1,0,top-3]) cube(size=[2, 12, 6], center=true);
        translate([top_lcd+1,0,top-5]) cube(size=[2, 16, 2], center=true);
    }

    cage_pin(bottom_front_left, pin_front_left, d, pd, ph, mode);
    cage_pin(bottom_front_right, pin_front_right, d, pd, ph, mode);
    cage_pin(bottom_rear_left, pin_rear_left, d, pd, ph, mode);
    cage_pin(bottom_rear_right, pin_rear_right, d, pd, ph, mode);
}

module car()
{
    base();
    platform();
    board();
    color("white") cage(mode=2/*simple*/);
    translate ([33, -8, 79]) rotate([0, 0, 90]) esc();
    lcd();
}

module arrangebottom(a) {
    translate ([68, 0, 57]) if ($children == 1) children(); else children(0);

    translate ([45, 42, 57]) rotate([0, 0, a]) if ($children == 1) children(); else children(1);
    translate ([-5, 45, 57]) rotate([0, 0, 2*a]) if ($children == 1) children(); else children(2);

    translate ([45, -42, 57]) rotate([0, 0, -a]) if ($children == 1) children(); else children(3);
    translate ([-5, -45, 57]) rotate([0, 0, -2*a]) if ($children == 1) children(); else children(4);
}

module lcd() {
    color("blue") translate([-40+2+27.5/2+0.5,0,81]) cube(size=[27.5, 27.5, 2], center=true);
}

module full() {
    car();
    arrangebottom(30) hsonar();

}

//car();

//cage();

//board();
//platform();

full();

//barbox([0,0,0], [0,0,50], 10, 3);

//translate ([0, 0, 4.5]) rotate([0, 90, 0]) hmount();

/* // small front
intersection() {
    platform();
    translate ([80, -15, 0]) cube(size=[40, 35, 400], center=true);
}*/

/* // full front
intersection() {
    platform();
    #translate ([100+20, 0, 0]) cube(size=[200, 200, 400], center=true);
}*/

/* // rear
intersection() {
    platform();
    translate ([-80, 0, 0]) cube(size=[20, 200, 400], center=true);
}*/

//screw2x6bore();

//rotate([0,0,180]) projection(cut=true) translate ([0, 0, -49]) platform();
//projection() translate ([0, 0, 10]) hsonar();

//translate([0,0,90]) rotate([180,0,0]) cage();