simplified build a bit, using square tubes instead of additional forks

// try to draw Jansen linkage leg assembly as it might appear in steel

// these are for configuration "E" as referenced in other drawings
AC=17.5;
Ay =  3.318; Bx = 53.833;
BD = 48.020; BE = 46.977; BH = 40.359;
CD = 59.635; CH = 71.441; DE = 66.437;
EF = 47.467; FG = 75.792;
FH = 40.843; GH = 55.790;

DEleft = (DE*DE + BD*BD - BE*BE)/(2*DE);
FGleft = (FG*FG + FH*FH - GH*GH)/(2*FG);
DEperp = sqrt(BD*BD - DEleft*DEleft);
FGperp = sqrt(FH*FH - FGleft*FGleft);

echo(str("DEleft=",DEleft,"   DEperp=",DEperp));
echo(str("FGleft=",FGleft,"   FGperp=",FGperp));

//r38 = (3/8)*2.54/2;  // radius of 3/8" bolt

a=360*$t;
legAssembly(a,0);
mirror([1,0,0]) legAssembly(180-a,1.3);

//  -------------------------- crank-arm circle reference
%color([1,.5,.3,.4]) translate([0,Ay,-2]) difference() {
  cylinder(r=AC,h=1,$fn=48,center=true);
  cylinder(r=2,h=2,center=true);
}
color([0.3,.3,1,.7]) // axles
for(x=[-1,1]) translate([x*Bx,0,0]) difference() {
   cylinder(r=2.54/2,h=20,$fn=24,center=true);
   cylinder(r=2.54/2-.4,h=22,$fn=19,center=true);
}

%translate([0,-93,0]) cube([200,2,2],center=true); // ground
%color([0,0,1,.2]) translate([0,0,-8])
   cube([114,1.75*2.54,1.75*2.54],center=true);

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

// plot a link shadow, a different way, to check kinematic correctness
module checkLink(xa,ya,xb,yb,ab) {
  *translate([(xa+xb)/2,(ya+yb)/2,-9])
    rotate([0,0,atan2(yb-ya,xb-xa)]) cube([ab,1,1],center=true);
}

function triK1(ax,ay,ca,bx,by,cb) = (cb*cb - ca*ca + ax*ax -bx*bx +ay*ay -by*by)/(2*(ax-bx));

// ===================================================================

module legAssembly(ang=0,linkOffset=0) {

// solve kinematics for given crank angle
xC = AC*cos(ang);
yC = AC*sin(ang)+Ay;
echo("C",xC,yC);

k1=(yC*yC - Bx*Bx + BD*BD - CD*CD + xC*xC)/(2*yC);
k2=(xC+Bx)/yC;
c=k1*k1-BD*BD+Bx*Bx;
b=2*(Bx-k1*k2);
a=k2*k2+1;
sgnD=(yC<0)?1:-1;
xD=(-b+sgnD*sqrt(b*b-4*a*c))/(2*a);
yD=sqrt(BD*BD - pow(xD+Bx,2));
echo("D",xD,yD,"CD err",sqrt(pow(xC-xD,2)+pow(yC-yD,2))-CD);

hipRot = atan2(yD,Bx+xD)-atan2(DEperp,DEleft);
echo("hipRot",hipRot);
xE = cos(hipRot) * (DEleft-DE) - sin(hipRot) * DEperp - Bx;
yE = sin(hipRot) * (DEleft-DE) + cos(hipRot) * DEperp;
/*
ke1=(yD*yD + xD*xD + DE*DE + BE*BE)/(2*yD);
ke2=(xD+Bx)/yD;
ae=2+ke2*ke2;
be=2*(Bx-ke1*ke2);
ce=ke1*ke1 - BE*BE +Bx*Bx;
echo("E abc:",ae,be,ce);
xE=(-be+sqrt(be*be-4*ae*ce))/(2*ae);
yE=sqrt(BE*BE - pow(xE+Bx,2));
*/
echo("E",xE,yE);

k1h=(xC*xC + yC*yC + BH*BH - CH*CH - Bx*Bx)/(2*yC);
k2h=-(xC+Bx)/yC;
ah=k2h*k2h+1;
bh=2*(k1h*k2h + Bx);
ch=k1h*k1h + Bx*Bx - BH*BH;
sgnH=(yC>0)?1:-1;
xH=(-bh+sgnH*sqrt(bh*bh-4*ah*ch))/(2*ah);
yH=-sqrt(BH*BH - pow(xH+Bx,2));
bhRot=atan2(yH,xH+Bx);
echo("H",xH,yH,"rot",bhRot,"CH err",sqrt(pow(xH-xC,2)+pow(yH-yC,2))-CH);

/*
k1f=(FH*FH - EF*EF - yE*yE - yH*yH + xE*xE - xH*xH) / (2*(yE-yH));
k2f=(xH-xE)/(yE-yH);
af=k2f*k2f+1;
bf=2*(k1f*k2f - xH - k2f*yH);
cf=xH*xH + yH*yH - 2*k1f*yH + k1f*k1f - FH*FH;
xF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
yF=k1f+k2f*xF;
*/
k2f = (yE-yH)/(xE-xH);
k1f = triK1(xE,yE,EF,xH,yH,FH);
af=k2f*k2f+1;
bf=2*(k2f*xE - k1f*k2f -yE);
cf=k1f*k1f - 2*k1f*xE + xE*xE + yE*yE - EF*EF;
yF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
xF=k1f-k2f*yF;
echo("F",xF,yF,"EF err",sqrt(pow(xF-xE,2)+pow(yF-yE,2))-EF);
echo("FH err",sqrt(pow(xF-xH,2)+pow(yF-yH,2))-FH);

// draw the hip so that the main "plane", the ED centerline plane, is at z=0
translate([-Bx,0,0]) rotate([0,0,hipRot])
    translate([DEleft-DE,DEperp,0]) hip();
//translate([-Bx,0,2.5]) rotate([0,0,12.5]) translate([-DEleft,DEperp,0]) hip();
//translate([ Bx,0,0]) rotate([0,0,-20]) translate([DE-DEleft,DEperp,0]) mirror([1,0,0])
//  hip();
checkLink(-Bx,0,xD,yD,BD);
checkLink(-Bx,0,xE,yE,BE);
checkLink(xD,yD,xE,yE,DE);

translate([-Bx,0,0]) rotate([0,0,bhRot])
   BHlinks();
checkLink(-Bx,0,xH,yH,BH);

//------------------------------------------------------- CrankLinks
translate([xC,yC,linkOffset-.6]) rotate([0,0,atan2(yD-yC,xD-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CD);
checkLink(xC,yC,xD,yD,CD);

translate([xC,yC,linkOffset+2]) rotate([0,0,atan2(yH-yC,xH-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CH);
checkLink(xC,yC,xH,yH,CH);

translate([xF,yF,0]) rotate([0,0,atan2(yE-yF,xE-xF)]) EFlink();
checkLink(xE,yE,xF,yF,EF);

footRot = atan2(yH-yF,xH-xF)-atan2(FGperp,FGleft);
translate([xF,yF,0]) rotate([0,0,footRot])
   foot();
checkLink(xF,yF,xH,yH,FH);

} // end module legAssembly()

// include includes whole text.
// use just imports modules
use <util.scad>

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

module foot() {
useF698=0;
thin=1;
withBrace=0;  // use wobble braces at knee as fork

  // FG (shin)
    if (withBrace) {
      hull() {  // FG (shin)
        translate([4,0,.2]) cube([4,2.5,2.5],center=true);
        translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.6,$fn=24,center=true); // foot
      }
    } else {
      // knee end fork cut out of square tube
      difference() {
        hull() {
          cube([4,2.54,2.54],center=true);
          translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.54,$fn=24,center=true); // foot
        }

        #cylinder(r=.4,h=4,$fn=17,center=true);
        translate([-.5,.2,0]) cube([4,2.54,2.1],center=true);
      }
    }

  // knee braces/fork
  *%color([0,1,1,.2])
  for (z=[-1.3,thin?1.6:7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for thin knee
      translate([-5,2,z])scale([3,5,1])cylinder(r=1,h=.4,$fn=64,center=true);

      // wider knee shouldn't need brace
      //translate([0,0,z]) cylinder(r=2.5,h=.4,$fn=24,center=true);
      translate([9,0,z])cylinder(r=1,h=.4,center=true);
    }
    #cylinder(r=.4,h=thin?4:17,$fn=17,center=true);
  }

  // hinge holders at H
  if (useF698) {
    // F698 tubes for H-hinge fork
    %color([0,0,.6,.4])
    translate([FGleft,FGperp,-1]) difference() {
      cylinder(r=2.54/2,h=7,$fn=36);

      cylinder(r=1.9/2,h=22,center=true,$fn=24);
      translate([0,0,3.6])cube([3,3,2.8],center=true);
    }
    translate([FGleft,FGperp,-.87]) {
      rotate([180,0,0]) F698();
      translate([0,0,5.0]) rotate([180,0,0]) F698();
      translate([0,0,1.95]) F698();
      translate([0,0,6.75]) F698();
    }
  } else {
    // use SA8 Heim rod-ends for H fork
    // use some washers/spacers to get heim a few mm inside fork, to allow
    // room for connecting rod to clear fork
    for (z=[-.7+.3,5.6-.3]) translate([FGleft,FGperp,z])
      rotate([0,0,142]) SI8onBolt(); //SA8();
  }

  if (thin==0) {
    // vertical brace extension at knee
    translate([3.5,0,4.1]) cube([2.5,2.5,5.3],center=true);
    hull() {  // gusset
      translate([ 5.5,-1,1]) cylinder(r=.2,h=5.8,$fn=8);
      translate([18, 1,0]) cylinder(r=.3,h=1  ,$fn=8);
    }
  }

  // FH segment bracing
  if (thin) {
    for (z=[-.3]) hull() {
      translate([   3    ,   1    ,]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }
    hull() {
      translate([FGleft+4.5,FGperp-4,6]) barEnd1();
      translate([7,4.4,0]) barEnd1();
    }

  } else {
    for (z=[-.3,5.1]) hull() {
      translate([   3    ,   1    ,z]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }

    hull() {  // dig brace.  Could be gusset?
       translate([3,1,5.7]) barEnd1();
       translate([useF698?12:13+2,11,-.3]) barEnd1();
    }

    hull() {
      translate([FGleft-(useF698?7.2:5-4),FGperp-8,5.3]) barEnd1();
      translate([useF698?14:15.5+2.6,13.5,-.3]) barEnd1();
    }
  }

  // GH braces
  hull() {
      translate([FG-8,0,-.3]) barEnd1();
      translate([FGleft+4,FGperp-3,-.3-1.7]) barEnd1();
  }
  hull() {
      translate([FG-10,0,0]) barEnd1();
      translate([FGleft+4,
                 FGperp-3,5.2+2]) barEnd1();
  }

  hull() {    // perp brace
      //translate([FGleft,FGperp-1,5.2]) barEnd1();
      translate([FGleft+4,FGperp-4,5.2]) barEnd1();
      translate([FGleft,0,0]) barEnd1();
  }
  hull() {    // perp brace
      //translate([FGleft,FGperp-1,-.3]) barEnd1();
      translate([FGleft+4,FGperp-4,-.3]) barEnd1();
      translate([FGleft,0,-.3]) barEnd1();
  }

  // extra truss braces
  hull() {
      translate([46,15,3]) barEnd1();
      translate([35, 0,0]) barEnd1();
  }

  // out-of-plane perp braces
  if (useF698) {
    translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  } else {
    ////translate([FGleft+1,FGperp-2,.3]) cylinder(r=.6,h=5);
    ////translate([FGleft-1,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    //translate([FGleft+4,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    translate([FGleft+4.5,FGperp-3.5,2.4]) rotate([0,0,142])
      cube([.75*2.54,.75*2.54,8],center=true);
  }
}

$fn=12;
module hip() {
squareTop=1;  // 1==let top tube be square, no additional fork pieces

  if (squareTop) {
    // crank link width with flange bearings is a little over 1"
    // so go with 1.25" square top tube
    *difference() {
      translate([DE/2,0,0])    // top tube
        cube([DE+4,1.25*2.54,1.25*2.54],center=true);

      translate([-1,-.3,0]) cube([5,3.2,2.8],center=true);
      #cylinder(r=.4,h=4,$fn=12,center=true);
      translate([DE,-.3,0]) cube([5,3.2,2.8],center=true);
      #translate([DE,0,0]) cylinder(r=.4,h=4,$fn=12,center=true);
    }

    // Even though , technically, the crank link hits the
    // edge with a 1" top tube, I think there is enough slop
    // with the heim joint to use a 1" top tube anyway.
    // also... if needed, we can shift the top tube
    // up or down 1/8" depending in which side we are, and make it work.
    // have slightly uneven spacers at F, and we are fine
    difference() {
      translate([DE/2,0,0])    // top tube
        cube([DE+4,2.54,2.54],center=true);

      translate([-1,-.3,0]) cube([5,2.6,2.2],center=true);
      #cylinder(r=.4,h=4,$fn=12,center=true);
      translate([DE,-.3,0]) cube([5,2.6,2.2],center=true);
      #translate([DE,0,0]) cylinder(r=.4,h=4,$fn=12,center=true);
    }

  } else {
    translate([DE/2,0,-.2]) rotate([0,90,0])      // top tube
      cylinder(r=.9,h=DE-4,$fn=17,center=true);
  }

  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     union() {
       cylinder(r=2.54*1.75/2,h=7.2,$fn=36);                // axle

       hull() {  // diag tubes
         translate([-1.6,1.4,1.2]) barEnd1();
         translate([DEleft-DE+2,DEperp,1.2]) barEnd1();
       }
       hull() {
         translate([0,0,1.2]) barEnd1();
         translate([DE-DEleft-1,DEperp,1.2]) barEnd1();
       }

       // extra brace
       translate([0,0,6.2]) rotate([-105,0,0]) cylinder(r=.8,h=20);
     }

     // bore out for 6805 bearing
     cylinder(r=3.7/2+.1,h=22,$fn=18,center=true);
  }

  if (squareTop==0) {
  // use cut-out square tube (or channel) for forks, instead of all welded.
  // easier to drill and maintain aligned holes
  // 14ga roughly 2mm thick
  translate([DE,0,0]) rotate([0,0,180]) channelFork();
  channelFork();
  }

  // extra bracing
  translate([DE/2,-15,0]) rotate([0,90,0]) cylinder(r=.8,h=35,center=true);
}

// cut-out square tube (or channel) for forks
//     easier to drill and maintain aligned holes
module channelFork(od=2.54*1.24,gu=.2,len=3,hd=.82,co=.5)
translate([co,0,0]) difference() {
  cube([od     ,len  ,od     ],center=true);
  cube([od-2*gu,len+1,od-2*gu],center=true);

  // open one side of square tube to make a channel
  translate([-od/2,0,0]) cube([2.1*gu,len+1,od-2*gu-.05],center=true);

  // put hole at x=0,y=0 in part space.
  #translate([-co,0,0]) cylinder(r=hd/2,h=od+1,$fn=17,center=true);
}

/*
module eFork() for(z=[-1,1]) difference() {
  hull() {
    translate([0,0,1.4*z]) cylinder(r=2,h=.3,$fn=24,center=true);
    translate([6,0,1.4*z]) cube([1,2,.3],center=true);
  }
  cylinder(r=.4,h=11,$fn=17,center=true);
}
*/

module crankLink(dx=CD) {
  %color([0,0,.6,.4]) difference() {
    cylinder(r=2.54/2,h=.9,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .31]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.31]) rotate([180,0,0]) F698();

  //translate([dx/2-1,0,0]) cube([dx-3,1.3,1.3],center=true);
  %color([0,.8,0,.6])
  translate([dx/2-1-1,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3-3,$fn=11,center=true);

  translate([dx,0,0]) SI8onBolt(); //SA8();
}

module EFlink() {
thin=1;

  translate([EF,0,0]) SI8onBolt(); //SA8();

  if (thin) {
    rotate([0,0,180]) SI8onBolt();

    // main tube
    translate([EF/2,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-9,$fn=13,center=true);

  } else {

    // main tube
    translate([EF/2-.4-1.5,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-3-3,$fn=13,center=true);

    // ------ tube and knee bearings
    %color([0,0,.6,.4])
    translate([0,0,-.84]) difference() {
       cylinder(r=2.54/2,h=2.54*3-.25,$fn=36);
       cylinder(r=2.54/2-.3,h=22,$fn=36,center=true);
    }
    translate([0,0,6.41]) F698();
    translate([0,0,-.7]) rotate([180,0,0]) F698();

    hull() {  // gusset
      translate([1.3,0,2*2.54/2]) cylinder(r=.2,h=2.54*3,$fn=12,center=true);
      translate([9,0,   0    ]) cylinder(r=.2,h=1,$fn=12);
    }
  }

  //translate([EF,0,0]) cylinder(r=r38,h=5,center=true);
    //                //cylinder(r=r38,h=55,center=true);
  //cylinder(r=1.2,h=22,$fn=36,center=true);
}

// this link drawn with B axle at origin, always.
module BHlinks() {
  difference() {  // main axle rings
    union() {
      // main axle tube
      translate([0,0,2.4]) cylinder(r=2.54*1.75/2,h=13.5,$fn=36,center=true);

      for(z=[-2.4,7.2]) {  // main side rails
        hull() {
          translate([BH-6,0,z]) barEnd1();
          translate([   0,0,z]) barEnd1();
        }
      }

    }

    translate([0,0,2.4]) cube([5,5,7.9],center=true);
    cylinder(r=3.7/2+.1,h=22,$fn=19,center=true);
  }

  // brace near axle
  translate([3.3,0,2.2]) cylinder(r=.8,h=10,$fn=19,center=true);

/* get rid of fork brace.  Comes close to hitting CH cranklink.
   let cross members hold forks apart
  //    fork brace
  translate([BH-7,0,2.43]) cube([2.5,2.5,7.6],center=true);

  hull() {
    translate([   4,.7,-1.6]) barEnd1();
    translate([BH-9,.7, 6.2]) barEnd1();
  }
  hull() {
    translate([   4,-.7, 6.2]) barEnd1();
    translate([BH-9,-.7,-1.6]) barEnd1();
  }
*/

  BHcrosses();

  // H forks
  for(z=[-1.7,6.2]) translate([BH,0,z]) difference() {
     hull() {
       cylinder(r=2,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     #cylinder(r=.4,h=2+6,center=true);
  }

  // to check dimensions
  //%translate([BH/2,0,2.4]) cube([BH,1,7.8],center=true);
}

// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses() {
h1=BH-4;  // node closest to H
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([b1, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([b1,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
}

/*
// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses2() {
h1=BH-4;  // node closest to H
h2=h1-19;
b2=h2-4;
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([h2, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([h2,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
  hull() {
    translate([b1,-spread,lo]) barEnd1();
    translate([b2,-spread,hi]) barEnd1();
  }
  hull() {
    translate([b2,spread,lo]) barEnd1();
    translate([b1,spread,hi]) barEnd1();
  }
}
*/

module barEnd1() sphere(.8,$fn=12);

// try to draw Jansen linkage leg assembly as it might appear in steel

// these are for configuration "E" as referenced in other drawings
AC=17.5;
Ay =  3.318; Bx = 53.833;
BD = 48.020; BE = 46.977; BH = 40.359;
CD = 59.635; CH = 71.441; DE = 66.437;
EF = 47.467; FG = 75.792;
FH = 40.843; GH = 55.790;

DEleft = (DE*DE + BD*BD - BE*BE)/(2*DE);
FGleft = (FG*FG + FH*FH - GH*GH)/(2*FG);
DEperp = sqrt(BD*BD - DEleft*DEleft);
FGperp = sqrt(FH*FH - FGleft*FGleft);

echo(str("DEleft=",DEleft,"   DEperp=",DEperp));
echo(str("FGleft=",FGleft,"   FGperp=",FGperp));

//r38 = (3/8)*2.54/2;  // radius of 3/8" bolt

a=360*$t;
legAssembly(a,0);
mirror([1,0,0]) legAssembly(180-a,1.3);

//  -------------------------- crank-arm circle reference
%color([1,.5,.3,.4]) translate([0,Ay,-2]) difference() {
  cylinder(r=AC,h=1,$fn=48,center=true);
  cylinder(r=2,h=2,center=true);
}
color([0.3,.3,1,.7]) // axles
for(x=[-1,1]) translate([x*Bx,0,0]) difference() {
   cylinder(r=2.54/2,h=20,$fn=24,center=true);
   cylinder(r=2.54/2-.4,h=22,$fn=19,center=true);
}

%translate([0,-93,0]) cube([200,2,2],center=true); // ground
%color([0,0,1,.2]) translate([0,0,-8])
   cube([114,1.75*2.54,1.75*2.54],center=true);

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

// plot a link shadow, a different way, to check kinematic correctness
module checkLink(xa,ya,xb,yb,ab) {
  *translate([(xa+xb)/2,(ya+yb)/2,-9])
    rotate([0,0,atan2(yb-ya,xb-xa)]) cube([ab,1,1],center=true);
}

function triK1(ax,ay,ca,bx,by,cb) = (cb*cb - ca*ca + ax*ax -bx*bx +ay*ay -by*by)/(2*(ax-bx));

// ===================================================================

module legAssembly(ang=0,linkOffset=0) {

// solve kinematics for given crank angle
xC = AC*cos(ang);
yC = AC*sin(ang)+Ay;
echo("C",xC,yC);

k1=(yC*yC - Bx*Bx + BD*BD - CD*CD + xC*xC)/(2*yC);
k2=(xC+Bx)/yC;
c=k1*k1-BD*BD+Bx*Bx;
b=2*(Bx-k1*k2);
a=k2*k2+1;
sgnD=(yC<0)?1:-1;
xD=(-b+sgnD*sqrt(b*b-4*a*c))/(2*a);
yD=sqrt(BD*BD - pow(xD+Bx,2));
echo("D",xD,yD,"CD err",sqrt(pow(xC-xD,2)+pow(yC-yD,2))-CD);

hipRot = atan2(yD,Bx+xD)-atan2(DEperp,DEleft);
echo("hipRot",hipRot);
xE = cos(hipRot) * (DEleft-DE) - sin(hipRot) * DEperp - Bx;
yE = sin(hipRot) * (DEleft-DE) + cos(hipRot) * DEperp;
/*
ke1=(yD*yD + xD*xD + DE*DE + BE*BE)/(2*yD);
ke2=(xD+Bx)/yD;
ae=2+ke2*ke2;
be=2*(Bx-ke1*ke2);
ce=ke1*ke1 - BE*BE +Bx*Bx;
echo("E abc:",ae,be,ce);
xE=(-be+sqrt(be*be-4*ae*ce))/(2*ae);
yE=sqrt(BE*BE - pow(xE+Bx,2));
*/
echo("E",xE,yE);

k1h=(xC*xC + yC*yC + BH*BH - CH*CH - Bx*Bx)/(2*yC);
k2h=-(xC+Bx)/yC;
ah=k2h*k2h+1;
bh=2*(k1h*k2h + Bx);
ch=k1h*k1h + Bx*Bx - BH*BH;
sgnH=(yC>0)?1:-1;
xH=(-bh+sgnH*sqrt(bh*bh-4*ah*ch))/(2*ah);
yH=-sqrt(BH*BH - pow(xH+Bx,2));
bhRot=atan2(yH,xH+Bx);
echo("H",xH,yH,"rot",bhRot,"CH err",sqrt(pow(xH-xC,2)+pow(yH-yC,2))-CH);

/*
k1f=(FH*FH - EF*EF - yE*yE - yH*yH + xE*xE - xH*xH) / (2*(yE-yH));
k2f=(xH-xE)/(yE-yH);
af=k2f*k2f+1;
bf=2*(k1f*k2f - xH - k2f*yH);
cf=xH*xH + yH*yH - 2*k1f*yH + k1f*k1f - FH*FH;
xF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
yF=k1f+k2f*xF;
*/
k2f = (yE-yH)/(xE-xH);
k1f = triK1(xE,yE,EF,xH,yH,FH);
af=k2f*k2f+1;
bf=2*(k2f*xE - k1f*k2f -yE);
cf=k1f*k1f - 2*k1f*xE + xE*xE + yE*yE - EF*EF;
yF=(-bf-sqrt(bf*bf - 4*af*cf))/(2*af);
xF=k1f-k2f*yF;
echo("F",xF,yF,"EF err",sqrt(pow(xF-xE,2)+pow(yF-yE,2))-EF);
echo("FH err",sqrt(pow(xF-xH,2)+pow(yF-yH,2))-FH);

// draw the hip so that the main "plane", the ED centerline plane, is at z=0
translate([-Bx,0,0]) rotate([0,0,hipRot])
    translate([DEleft-DE,DEperp,0]) hip();
//translate([-Bx,0,2.5]) rotate([0,0,12.5]) translate([-DEleft,DEperp,0]) hip();
//translate([ Bx,0,0]) rotate([0,0,-20]) translate([DE-DEleft,DEperp,0]) mirror([1,0,0])
//  hip();
checkLink(-Bx,0,xD,yD,BD);
checkLink(-Bx,0,xE,yE,BE);
checkLink(xD,yD,xE,yE,DE);

translate([-Bx,0,0]) rotate([0,0,bhRot])
   BHlinks();
checkLink(-Bx,0,xH,yH,BH);

//------------------------------------------------------- CrankLinks
translate([xC,yC,linkOffset-.6]) rotate([0,0,atan2(yD-yC,xD-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CD);
checkLink(xC,yC,xD,yD,CD);

translate([xC,yC,linkOffset+2]) rotate([0,0,atan2(yH-yC,xH-xC)])
  mirror([0,0,(linkOffset>0)?1:0]) crankLink(CH);
checkLink(xC,yC,xH,yH,CH);

translate([xF,yF,0]) rotate([0,0,atan2(yE-yF,xE-xF)]) EFlink();
checkLink(xE,yE,xF,yF,EF);

footRot = atan2(yH-yF,xH-xF)-atan2(FGperp,FGleft);
translate([xF,yF,0]) rotate([0,0,footRot])
   foot();
checkLink(xF,yF,xH,yH,FH);

} // end module legAssembly()

// include includes whole text.
// use just imports modules
use <util.scad>

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

module foot() {
useF698=0;
thin=1;
  hull() {  // FG
    translate([4,0,.2]) cube([4,2.5,2.5],center=true);
    translate([FG-1.3,0,.2]) cylinder(r=1.3,h=2.6,$fn=24,center=true);
  }

  // knee braces/fork
  for (z=[-1.3,thin?1.6:7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for thin knee
      translate([-5,2,z])scale([3,5,1])cylinder(r=1,h=.4,$fn=64,center=true);

      // wider knee shouldn't need brace
      //translate([0,0,z]) cylinder(r=2.5,h=.4,$fn=24,center=true);
      translate([9,0,z])cylinder(r=1,h=.4,center=true);
    }
    #cylinder(r=.4,h=thin?4:17,$fn=17,center=true);
  }

  // hinge holders at H
  if (useF698) {
    // F698 tubes for H-hinge fork
    %color([0,0,.6,.4])
    translate([FGleft,FGperp,-1]) difference() {
      cylinder(r=2.54/2,h=7,$fn=36);

      cylinder(r=1.9/2,h=22,center=true,$fn=24);
      translate([0,0,3.6])cube([3,3,2.8],center=true);
    }
    translate([FGleft,FGperp,-.87]) {
      rotate([180,0,0]) F698();
      translate([0,0,5.0]) rotate([180,0,0]) F698();
      translate([0,0,1.95]) F698();
      translate([0,0,6.75]) F698();
    }
  } else {
    // use SA8 Heim rod-ends for H fork
    // use some washers/spacers to get heim a few mm inside fork, to allow
    // room for connecting rod to clear fork
    for (z=[-.7+.3,5.6-.3]) translate([FGleft,FGperp,z])
      rotate([0,0,142]) SI8onBolt(); //SA8();
  }

  if (thin==0) {
    // vertical brace extension at knee
    translate([3.5,0,4.1]) cube([2.5,2.5,5.3],center=true);
    hull() {  // gusset
      translate([ 5.5,-1,1]) cylinder(r=.2,h=5.8,$fn=8);
      translate([18, 1,0]) cylinder(r=.3,h=1  ,$fn=8);
    }
  }

  // FH segment bracing
  if (thin) {
    for (z=[-.3]) hull() {
      translate([   3    ,   1    ,]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }
    hull() {
      translate([FGleft+4.5,FGperp-4,6]) barEnd1();
      translate([7,4.4,0]) barEnd1();
    }

  } else {
    for (z=[-.3,5.1]) hull() {
      translate([   3    ,   1    ,z]) barEnd1();
      translate([FGleft-(useF698?1:-4),
                 FGperp-(useF698?1:4),z]) barEnd1();
    }

    hull() {  // dig brace.  Could be gusset?
       translate([3,1,5.7]) barEnd1();
       translate([useF698?12:13+2,11,-.3]) barEnd1();
    }

    hull() {
      translate([FGleft-(useF698?7.2:5-4),FGperp-8,5.3]) barEnd1();
      translate([useF698?14:15.5+2.6,13.5,-.3]) barEnd1();
    }
  }

  // GH braces
  hull() {
      translate([FG-8,0,-.3]) barEnd1();
      translate([FGleft+4,FGperp-3,-.3-1.7]) barEnd1();
  }
  hull() {
      translate([FG-10,0,0]) barEnd1();
      translate([FGleft+4,
                 FGperp-3,5.2+2]) barEnd1();
  }

  hull() {    // perp brace
      //translate([FGleft,FGperp-1,5.2]) barEnd1();
      translate([FGleft+4,FGperp-4,5.2]) barEnd1();
      translate([FGleft,0,0]) barEnd1();
  }
  hull() {    // perp brace
      //translate([FGleft,FGperp-1,-.3]) barEnd1();
      translate([FGleft+4,FGperp-4,-.3]) barEnd1();
      translate([FGleft,0,-.3]) barEnd1();
  }

  // extra truss braces
  hull() {
      translate([46,15,3]) barEnd1();
      translate([35, 0,0]) barEnd1();
  }

  // out-of-plane perp braces
  if (useF698) {
    translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
    translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  } else {
    ////translate([FGleft+1,FGperp-2,.3]) cylinder(r=.6,h=5);
    ////translate([FGleft-1,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    //translate([FGleft+4,FGperp-4,.3]) cylinder(r=.8,h=5,$fn=11);
    translate([FGleft+4.5,FGperp-3.5,2.4]) rotate([0,0,142])
      cube([.75*2.54,.75*2.54,8],center=true);
  }
}

$fn=12;
module hip() {
  translate([DE/2,0,-.2]) rotate([0,90,0])      // top tube
    cylinder(r=.9,h=DE-4,$fn=17,center=true);

  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     union() {
       cylinder(r=2.54*1.75/2,h=7.2,$fn=36);                // axle

       hull() {  // diag tubes
         translate([-1.6,1.4,1.2]) barEnd1();
         translate([DEleft-DE+2,DEperp,1.2]) barEnd1();
       }
       hull() {
         translate([0,0,1.2]) barEnd1();
         translate([DE-DEleft-1,DEperp,1.2]) barEnd1();
       }

       // extra brace
       translate([0,0,6.2]) rotate([-105,0,0]) cylinder(r=.8,h=20);
     }

     // bore out for 6805 bearing
     cylinder(r=3.7/2+.1,h=22,$fn=18,center=true);
  }

  // use cut-out square tube (or channel) for forks, instead of all welded.
  // easier to drill and maintain aligned holes
  // 14ga roughly 2mm thick
  translate([DE,0,0]) rotate([0,0,180]) channelFork();
  channelFork();

  // extra bracing
  translate([DE/2,-15,0]) rotate([0,90,0]) cylinder(r=.8,h=35,center=true);
}

// cut-out square tube (or channel) for forks
//     easier to drill and maintain aligned holes
module channelFork(od=2.54*1.24,gu=.2,len=3,hd=.82,co=.5)
translate([co,0,0]) difference() {
  cube([od     ,len  ,od     ],center=true);
  cube([od-2*gu,len+1,od-2*gu],center=true);

  // open one side of square tube to make a channel
  translate([-od/2,0,0]) cube([2.1*gu,len+1,od-2*gu-.05],center=true);

  // put hole at x=0,y=0 in part space.
  #translate([-co,0,0]) cylinder(r=hd/2,h=od+1,$fn=17,center=true);
}

/*
module eFork() for(z=[-1,1]) difference() {
  hull() {
    translate([0,0,1.4*z]) cylinder(r=2,h=.3,$fn=24,center=true);
    translate([6,0,1.4*z]) cube([1,2,.3],center=true);
  }
  cylinder(r=.4,h=11,$fn=17,center=true);
}
*/

module crankLink(dx=CD) {
  %color([0,0,.6,.4]) difference() {
    cylinder(r=2.54/2,h=.9,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .31]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.31]) rotate([180,0,0]) F698();

  //translate([dx/2-1,0,0]) cube([dx-3,1.3,1.3],center=true);
  %color([0,.8,0,.6])
  translate([dx/2-1-1,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3-3,$fn=11,center=true);

  translate([dx,0,0]) SI8onBolt(); //SA8();
}

module EFlink() {
thin=1;

  translate([EF,0,0]) SI8onBolt(); //SA8();

  if (thin) {
    rotate([0,0,180]) SI8onBolt();

    // main tube
    translate([EF/2,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-9,$fn=13,center=true);

  } else {

    // main tube
    translate([EF/2-.4-1.5,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-3-3,$fn=13,center=true);

    // ------ tube and knee bearings
    %color([0,0,.6,.4])
    translate([0,0,-.84]) difference() {
       cylinder(r=2.54/2,h=2.54*3-.25,$fn=36);
       cylinder(r=2.54/2-.3,h=22,$fn=36,center=true);
    }
    translate([0,0,6.41]) F698();
    translate([0,0,-.7]) rotate([180,0,0]) F698();

    hull() {  // gusset
      translate([1.3,0,2*2.54/2]) cylinder(r=.2,h=2.54*3,$fn=12,center=true);
      translate([9,0,   0    ]) cylinder(r=.2,h=1,$fn=12);
    }
  }

  //translate([EF,0,0]) cylinder(r=r38,h=5,center=true);
    //                //cylinder(r=r38,h=55,center=true);
  //cylinder(r=1.2,h=22,$fn=36,center=true);
}

// this link drawn with B axle at origin, always.
module BHlinks() {
  difference() {  // main axle rings
    union() {
      // main axle tube
      translate([0,0,2.4]) cylinder(r=2.54*1.75/2,h=13.5,$fn=36,center=true);

      for(z=[-2.4,7.2]) {  // main side rails
        hull() {
          translate([BH-6,0,z]) barEnd1();
          translate([   0,0,z]) barEnd1();
        }
      }

    }

    translate([0,0,2.4]) cube([5,5,7.9],center=true);
    cylinder(r=3.7/2+.1,h=22,$fn=19,center=true);
  }

  // brace near axle
  translate([3.3,0,2.2]) cylinder(r=.8,h=10,$fn=19,center=true);

/* get rid of fork brace.  Comes close to hitting CH cranklink.
   let cross members hold forks apart
  //    fork brace
  translate([BH-7,0,2.43]) cube([2.5,2.5,7.6],center=true);

  hull() {
    translate([   4,.7,-1.6]) barEnd1();
    translate([BH-9,.7, 6.2]) barEnd1();
  }
  hull() {
    translate([   4,-.7, 6.2]) barEnd1();
    translate([BH-9,-.7,-1.6]) barEnd1();
  }
*/

  BHcrosses();

  // H forks
  for(z=[-1.7,6.2]) translate([BH,0,z]) difference() {
     hull() {
       cylinder(r=2,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     #cylinder(r=.4,h=2+6,center=true);
  }

  // to check dimensions
  //%translate([BH/2,0,2.4]) cube([BH,1,7.8],center=true);
}

// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses() {
h1=BH-4;  // node closest to H
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([b1, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([b1,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
}

/*
// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses2() {
h1=BH-4;  // node closest to H
h2=h1-19;
b2=h2-4;
b1=4;
spread=.7;
lo=-1.6;
hi=6.5;
rBar=.8;
  hull() {
    translate([h2, spread,lo]) barEnd1();
    translate([h1, spread,hi]) barEnd1();
  }
  hull() {
    translate([h2,-spread,hi]) barEnd1();
    translate([h1,-spread,lo]) barEnd1();
  }
  hull() {
    translate([b1,-spread,lo]) barEnd1();
    translate([b2,-spread,hi]) barEnd1();
  }
  hull() {
    translate([b2,spread,lo]) barEnd1();
    translate([b1,spread,hi]) barEnd1();
  }
}
*/

module barEnd1() sphere(.8,$fn=12);


Element-wise vector multiplication now works

/**
Program by Ankur Gupta
www.github.com/agupta231
Jan 2017

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/

init_square_size = 40;
connector_length = 30;
connector_thickness = 0.1;
iteration_multiplier = 0.5;
iterations = 2;

echo(version());

translation_vectors = [[1, 1], [-1, -1], [-1, 1], [1, -1]];
rotation_vectors = [[1, 1, -1], [1, 1, -1], [1, 1, 1], [1, 1, 1]];

function ev_mult(vec1, vec2) =
    len(vec1) != len(vec2) ? false : [for(i = [0:len(vec1) - 1]) vec1[i] * vec2[i]];

module translated_cube(translation_vector, starting_pos, size) {
    translate(translation_vector + starting_pos) {
        square(size, center = true);
    }
}

module connector(vector_keys, size, starting_pos, current_iteration) {
    if(current_iteration < iterations) {
        for(i = vector_keys) {
            echo(ev_mult(translation_vectors[i], [size / (2 * sqrt(2)), size / (2 * sqrt(2))]));

            translate(translation_vectors[i] * [size / (2 * sqrt(2)), size / (2 * sqrt(2))] + starting_pos) {
                rotate(rotation_vectors[i] * [0, 45, 45]) {
                    #square([connector_thickness, size], center = true);
                }
            }
        }
    }
}

module pattern(starting_pos, seed_corner, current_iteration) {
    translation = false;
    translations = false;
    rotations = false;
    current_size = init_square_size * pow(iteration_multiplier, current_iteration - 1);
    current_connector_size = connector_length * pow(iteration_multiplier, current_iteration - 1);

    if(seed_corner == "center") {
        translated_cube([0,0], starting_pos, current_size);
        connector([0, 1, 2, 3], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "bottom_left") {
        translated_cube([current_size / 2, current_size / 2], starting_pos, current_size);
        connector([0, 2, 3], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "bottom_right") {
        translated_cube([-current_size / 2, current_size / 2], starting_pos, current_size);
        connector([0, 1, 2], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "top_left") {
        translated_cube([current_size / 2, -current_size / 2], starting_pos, current_size);
        connector([0, 1, 3], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "top_right") {
        translated_cube([-current_size / 2, -current_size / 2], starting_pos, current_size);
        connector([1, 2, 3], current_connector_size, starting_pos, current_iteration);
    }
}

pattern([0, 0], "center", 1);

/**
Program by Ankur Gupta
www.github.com/agupta231
Jan 2017

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/

init_square_size = 40;
connector_length = 30;
connector_thickness = 0.1;
iteration_multiplier = 0.5;
iterations = 2;

echo(version());

translation_vectors = [[1, 1], [-1, -1], [-1, 1], [1, -1]];
rotation_vectors = [[1, 1, -1], [1, 1, -1], [1, 1, 1], [1, 1, 1]];

function ev_mult(vec1, vec2) =
    if(len(vec1) != len(vec2)) {
        echo("Vectors not the same dimensions");
        break;
    =
}

module translated_cube(translation_vector, starting_pos, size) {
    translate(translation_vector + starting_pos) {
        square(size, center = true);
    }
}

module connector(vector_keys, size, starting_pos, current_iteration) {
    if(current_iteration < iterations) {
        for(i = vector_keys) {
            echo(translation_vectors[i] );

            translate(translation_vectors[i] * [size / (2 * sqrt(2)), size / (2 * sqrt(2))] + starting_pos) {
                rotate(rotation_vectors[i] * [0, 45, 45]) {
                    #square([connector_thickness, size], center = true);
                }
            }
        }
    }
}

module pattern(starting_pos, seed_corner, current_iteration) {
    translation = false;
    translations = false;
    rotations = false;
    current_size = init_square_size * pow(iteration_multiplier, current_iteration - 1);
    current_connector_size = connector_length * pow(iteration_multiplier, current_iteration - 1);

    if(seed_corner == "center") {
        translated_cube([0,0], starting_pos, current_size);
        connector([0, 1, 2, 3], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "bottom_left") {
        translated_cube([current_size / 2, current_size / 2], starting_pos, current_size);
        connector([0, 2, 3], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "bottom_right") {
        translated_cube([-current_size / 2, current_size / 2], starting_pos, current_size);
        connector([0, 1, 2], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "top_left") {
        translated_cube([current_size / 2, -current_size / 2], starting_pos, current_size);
        connector([0, 1, 3], current_connector_size, starting_pos, current_iteration);
    }
    else if(seed_corner == "top_right") {
        translated_cube([-current_size / 2, -current_size / 2], starting_pos, current_size);
        connector([1, 2, 3], current_connector_size, starting_pos, current_iteration);
    }
}

pattern([0, 0], "center", 1);


stub of the front panel moved to outside of the back module

use <front.scad>
include <positions.scad>

module back()
{
  difference()
  {
    union()
    {
      // main mounting legs
      for(offset = [ [0, 0, 0], [boxSize[0]-16, 0, 0], [boxSize[0]-70, 0, 0] ])
        translate(offset)
          cube([16, 40+13, 7]);
      // side mounting wing
      translate([15, 0, 0])
        cube([18, 20, 7]);
      // upper beam, mounting all legs together
      translate([0, 40+13, 0])
        cube([boxSize[0], 5+5, 7]);
      // both upper holdings
      for(offsetOX = [0, 29])
        translate([offsetOX, 40+13+5+5, 0])
          cube([10, boxSize[1]-(40+13+5+5), 7]);
      // bridge between holdings
      translate([10, 40+13+5+5+50, 0])
        cube([29-10, 7, 7]);
      // knob back holding (if screw would not fit in properly)
      translate([10+(29-10-8)/2, 40+13+5+5+50+7, 0])
        cube([8, 20, 7]);
    }

    // SD card cable hole
    translate(sdCardOffset - [6, 0, 7])
      cube([8, 31+2, 7]);
    // reset button hole
    translate(resetButtonOffset - [0, 0, 10])
      cylinder(r=16/2+1, h=30);
    // frame-mounting drills
    for(offsetOY = [ 13/2+5/2, 40+13+5])
      for(offsetOX = [15/2, boxSize[0]-70+16/2, boxSize[0]-16/2])
        translate([offsetOX, offsetOY, -1])
          cylinder(r=5/2, h=6+7+2, $fs=1);
  }
}

// front stub
%translate([0, 0, 7])
  front();

//rotate([180, 0, 0])
  back();

use <front.scad>
include <positions.scad>

module back()
{
  difference()
  {
    union()
    {
      // main mounting legs
      for(offset = [ [0, 0, 0], [boxSize[0]-16, 0, 0], [boxSize[0]-70, 0, 0] ])
        translate(offset)
          cube([16, 40+13, 7]);
      // side mounting wing
      translate([15, 0, 0])
        cube([18, 20, 7]);
      // upper beam, mounting all legs together
      translate([0, 40+13, 0])
        cube([boxSize[0], 5+5, 7]);
      // both upper holdings
      for(offsetOX = [0, 29])
        translate([offsetOX, 40+13+5+5, 0])
          cube([10, boxSize[1]-(40+13+5+5), 7]);
      // bridge between holdings
      translate([10, 40+13+5+5+50, 0])
        cube([29-10, 7, 7]);
      // knob back holding (if screw would not fit in properly)
      translate([10+(29-10-8)/2, 40+13+5+5+50+7, 0])
        cube([8, 20, 7]);
    }

    // SD card cable hole
    translate(sdCardOffset - [6, 0, 7])
      cube([8, 31+2, 7]);
    // reset button hole
    translate(resetButtonOffset - [0, 0, 10])
      cylinder(r=16/2+1, h=30);
    // frame-mounting drills
    for(offsetOY = [ 13/2+5/2, 40+13+5])
      for(offsetOX = [15/2, boxSize[0]-70+16/2, boxSize[0]-16/2])
        translate([offsetOX, offsetOY, -1])
          cylinder(r=5/2, h=6+7+2, $fs=1);
  }

  // front stub
  %translate([0, 0, 7])
    front();
}

//rotate([180, 0, 0])
  back();


Show cross section of LED and clips

Show cross section of LED and clips

/*

    Playground for developing the vitamins/LEDClip.scad library

*/

include <../config/config.scad>

// include the LEDClip.scad library
include <../vitamins/LEDClip.scad>

// include the LED.scad library
include <../vitamins/LED.scad>

module LEDClip_Layout_Sandbox()
{
    // normal recessed clip for 5mm LED
    LEDClip();
    // show with LED
    translate([0, 0, 3 - 8.6])
        LED(LED_5mm);

    // closed (with diffuser) for 5mm LED
    color("white") {
        translate([12, 0, 0])
            LEDClip(LEDClip_Closed);
    }
    // show with LED
    translate([12, 0, 2 - 8.6])
        LED(LED_5mm);
}

// show cross section of LED Clips
section() {
    LEDClip_Layout_Sandbox();
}

/*

	Playground for developing the vitamins/LEDClip.scad library

*/

include <../config/config.scad>

// include the LEDClip.scad library
include <../vitamins/LEDClip.scad>

// include the LED.scad library
include <../vitamins/LED.scad>

module LEDClip_Layout_Sandbox()
{
    // normal recessed clip for 5mm LED
    LEDClip();
    // show with LED
    translate([0, 0, 3 - 8.6])
        LED(LED_5mm);

    // closed (with diffuser) for 5mm LED
    color("white", 0.6) {
        translate([12, 0, 0])
            LEDClip(LEDClip_Closed);
    }
    // show with LED
    translate([12, 0, 2 - 8.6])
        LED(LED_5mm);

}

LEDClip_Layout_Sandbox();


Delete LifeLoggingCameraV4.scad

Delete LifeLoggingCameraV4.scad

$fs = 0.1; // smoothness of curves in render
$fa = 0.1;

/* Box */
{
    thickness = 2; //wall thickness
    extraThickness = 0.1; // required for proper rendering when $fs is large
    curve = 4; // curve on the edges of the box, must be > thickness
    internalDimensions = [65, 65, 32]; //internal dimensions
    externalDimensions = [internalDimensions[0] + (thickness * 2), internalDimensions[1] + (thickness * 2), internalDimensions[2] + (thickness * 2)];
    bottomHeight = 30; // height of the bottom half of the box
    topHeight = internalDimensions[2] - bottomHeight; // height of the top half of the box
    FR4Thickness = 1.7;
    overlap = 3;
}
//

cameraHolePos = [externalDimensions[0] / 2, externalDimensions[1] / 2];
ledHolePos = [externalDimensions[2] / 2, externalDimensions[1] - (externalDimensions[2] / 2)];
usbHolePos = [-0.01, 31.25 + curve, thickness + FR4Thickness];
sdHolePos = [-0.01, 6.5 + curve, thickness + FR4Thickness];
resetHolePos = [externalDimensions[2] / 2, externalDimensions[1] - (thickness / 2), externalDimensions[2] / 2];
powerHolePos = [externalDimensions[0] * ((sqrt(5) - 1) / 2), externalDimensions[1] - (thickness / 2) - 0.5, externalDimensions[2] / 2];
usbSize = [21.5, 36, 7.2];
sdSize = [25, 31, 3.55];
resetHoleSize = 6;
powerHoleSize = [6.5, thickness + extraThickness + 1, 3.5];
ledHoleRad = 2.5;
cameraHoleRad = 3.7;
cameraStandoffHeight = 4;

{
    /*
loc =   [
            [externalDimensions[0] + 3 , 0, 0],
            [externalDimensions[0] + 3 , 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0], 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0], 0, 22 + (thickness * 2)],
            [externalDimensions[0], 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0] + 3 , 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0] + 3 , 0, 0],
            [externalDimensions[0] + 3 , 0, 0]
        ];

function xyz(t,i) =
    lookup(t, [
    [0/len(loc),loc[0][i]],
    [1/len(loc),loc[1][i]],
    [2/len(loc),loc[2][i]],
    [3/len(loc),loc[3][i]],
    [4/len(loc),loc[4][i]],
    [5/len(loc),loc[5][i]],
    [6/len(loc),loc[6][i]],
    [7/len(loc),loc[7][i]],

]);

loc2 =   [
            [0, 0, 0],
            [0, 0, 0],
            [0, -180, 0],
            [0, -180, 0],
            [0, -180, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]
        ];

function xyz2(t,i) =
    lookup(t, [
    [0/len(loc2),loc2[0][i]],
    [1/len(loc2),loc2[1][i]],
    [2/len(loc2),loc2[2][i]],
    [3/len(loc2),loc2[3][i]],
    [4/len(loc2),loc2[4][i]],
    [5/len(loc2),loc2[5][i]],
    [6/len(loc2),loc2[6][i]],
    [7/len(loc2),loc2[7][i]],

]);

loc3 =   [
            [0, 0, 0],
            [0, 0, 90],
            [0, 0, 180],
            [0, 0, 270],
            [0, 0, 360],
            [0, 0, 180],
            [0, 0, 0],
            [0, 0, 0]
        ];

function xyz3(t,i) =
    lookup(t, [
    [0/len(loc3),loc3[0][i]],
    [1/len(loc3),loc3[1][i]],
    [2/len(loc3),loc3[2][i]],
    [3/len(loc3),loc3[3][i]],
    [4/len(loc3),loc3[4][i]],
    [5/len(loc3),loc3[5][i]],
    [6/len(loc3),loc3[6][i]],
    [7/len(loc3),loc3[7][i]],

]);
*/
}
//

module cylinderHull(a, r)
{
    hull()
        {
            cylinder(r = r, h = a[2]);
            translate([a[0], 0, 0])
                cylinder(r = r, h = a[2]);
            translate([0, a[1], 0])
                cylinder(r = r, h = a[2]);
            translate([a[0], a[1], 0])
                cylinder(r = r, h = a[2]);
        }
}
//

module box(height, lip)
{
    // 0 = outer lip, 1 = inner lip
    translate([curve, curve, 0]) difference()
    {
        union()
        {
            cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), height + thickness], curve);
            if(lip == 1)
            {
                translate([0, 0, thickness])
                    cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), height + overlap],curve - (thickness / 2));
            }
        }
        {
            translate([0, 0, thickness])
                cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), height + thickness + overlap], curve - thickness);
            if(lip == 0)
            {
                translate([0, 0, height + thickness - overlap])
                    cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), 0.01 + overlap], curve - (thickness / 2));
            }
        }
    }
}
//

module bottom(height)
{
    difference()
    {
        union()
        {
            box(height, 0);
            if(thickness < 3)
            {
                translate([externalDimensions[0] * ((sqrt(5) - 1) / 2) - 9.5, externalDimensions[1] - 3, thickness])
                cube([19, 3 - thickness, height - overlap]);//power switch extra thickness
            }
            translate([usbHolePos[0] + thickness, usbHolePos[1] - ((usbSize[0] - 11) / 2), thickness])
            {
                translate([2.6, usbSize[0] - 2.6, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
                translate([2.6, 2.6, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
                translate([usbSize[1] - 2.25, usbSize[0] - 2 - 2.25, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
                translate([usbSize[1] - 2.25, 2 + 2.25, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
            }
            translate([sdHolePos[0] + thickness, sdHolePos[1] - ((sdSize[0] - 14) / 2) - 1, thickness])
            {
                translate([2.575, sdSize[0] - 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
                translate([2.575, 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
                translate([sdSize[1] - 5.6 - 2.575, sdSize[0] - 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
                translate([sdSize[1] - 5.6 - 2.575, 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
            }
            translate([powerHolePos[0], powerHolePos[1], powerHolePos[2]])
            {
                translate([-7.5, 0, 0])
                    rotate([90, 0, 0])
                        cylinder(h = 3, r = 0.8);
                translate([7.5, 0, 0])
                    rotate([90, 0, 0])
                        cylinder(h = 3, r = 0.8);
            }
        }
        {
            translate([usbHolePos[0], usbHolePos[1], usbHolePos[2]])
                cube([thickness + extraThickness, 11, 6]);//usb hole
            translate([sdHolePos[0], sdHolePos[1], sdHolePos[2]])
                cube([thickness + extraThickness, 14, 4]);//sd hole
            translate([resetHolePos[0], resetHolePos[1], resetHolePos[2]])
                cube([resetHoleSize, thickness + extraThickness, resetHoleSize], center = true);//reset switch hole
            translate([powerHolePos[0], powerHolePos[1], powerHolePos[2]])
                cube([powerHoleSize[0], powerHoleSize[1], powerHoleSize[2]], center = true);//power switch hole
            hull ()
            {
                translate([sdHolePos[0], sdHolePos[1] + (thickness / 2), sdHolePos[2]]) sphere(r = thickness / 2, center = true);
                translate([sdHolePos[0], sdHolePos[1] + 14 - (thickness / 2), sdHolePos[2]]) sphere(r = thickness / 2, center = true);
            }
            hull ()
            {
                translate([sdHolePos[0], sdHolePos[1] + (thickness / 2), sdHolePos[2] + 4]) sphere(r = thickness / 2, center = true);
                translate([sdHolePos[0], sdHolePos[1] + 14 - (thickness / 2), sdHolePos[2] + 4]) sphere(r = thickness / 2, center = true);
            }
            translate([0, 61 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([0, 54 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([65 + thickness, 61 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([65 + thickness, 54 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([usbHolePos[0] + thickness, usbHolePos[1] - ((usbSize[0] - 11) / 2), 0])
            {
                translate([7, usbSize[0] - 2.6, 0])
                {
                    cylinder(h = usbSize[2], r = 1.5);
                }
                translate([7, 2.6, 0])
                {
                    cylinder(h = usbSize[2], r = 1.5);
                }
                translate([usbSize[1] - 2.25, usbSize[0] - 2 - 2.25 + 4, 0])
                {
                    cylinder(h = usbSize[2], r = 1.5);
                }
            }
        }
    }
}
//

module top(height)
{
    difference()
    {
        union()
        {
            box(height, 1);
            translate([cameraHolePos[0], cameraHolePos[1], thickness])
            {
                translate([-8.5, 19.9, 0])// Top L
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
                translate([8.5, 19.9, 0])// Top R
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
                translate([-8.5, -5.5, 0])// Bottom L
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
                translate([8.5, -5.5, 0])// Bottom R
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
            }
        }
        {
            translate([cameraHolePos[0], cameraHolePos[1], -0.01])
                cylinder(r = cameraHoleRad, h = thickness + extraThickness);//camera hole
            translate([ledHolePos[0], ledHolePos[1], -0.01])
                cylinder(r = ledHoleRad, h = thickness + extraThickness);//led hole
        }
    }
}
//

bottom(bottomHeight);

//top(topHeight);

//translate([externalDimensions[0], 0, 22 + 2 + (thickness * 2)]) rotate([0,180,0]) top(topHeight);

//translate([xyz($t,0),xyz($t,1),xyz($t,2)]) rotate([xyz2($t,0),xyz2($t,1),xyz2($t,2)]) top(topHeight);

//translate([2, 4, 3]) cube([31, 25, 3.55]);//sd
//translate([2, 30, 3]) cube([36, 21.5, 7.2]);//usb


Rotator: added 3D print OpenSCAD design #30

/*

 Basic Lego brick builder module for OpenScad by Jorg Janssen 2013 (CC BY-NC 3.0)
 To use this in your own projects add:

 use <path_to_this_file/lego_brick_builder.scad>
 brick (length, width, height [,smooth]);

 Length and width are in standard lego brick dimensions.
 Height is in flat brick heights, so for a normal lego brick height = 3.
 Add optional smooth = true for a brick without studs.
 Use height = 0 to just put studs/knobs on top of other things.

 */
$fn = 150;

 // this is it:
brick(2,2,1);

// and this is how it's done:

FLU = 1.6; // Fundamental Lego Unit = 1.6 mm

BRICK_WIDTH = 5*FLU; // basic brick width
BRICK_HEIGHT = 6*FLU; // basic brick height
PLATE_HEIGHT = 2*FLU; // basic plate height
WALL_THICKNESS = FLU; // outer wall of the brick
STUD_RADIUS = 1.5*FLU; // studs are the small cylinders on top of the brick with the lego logo ('nopje' in Dutch)
STUD_HEIGHT = FLU;
ANTI_STUD_RADIUS = 0.5*4.07*FLU;  // an anti stud is the hollow cylinder inside bricks that have length > 1 and width > 1
PIN_RADIUS = FLU; // a pin is the small cylinder inside bricks that have length = 1 or width = 1
SUPPORT_THICKNESS = 0.254; // support is the thin surface between anti studs, pins and walls, your printer might not print this thin, try thicker!
EDGE = 0.254; // this is the width and height of the bottom line edge of smooth bricks
CORRECTION = 0.1; // addition to each size, to make sure all parts connect by moving them a little inside each other

module brick(length = 4, width = 2, height = 3, smooth = false){

	// brick shell
	difference(){
		cube(size = [length*BRICK_WIDTH,width*BRICK_WIDTH,height*PLATE_HEIGHT]);
                translate([length*BRICK_WIDTH/2,width*BRICK_WIDTH/2, -1])
        cylinder(h=6, r=0.7);
        translate([length*BRICK_WIDTH/2,width*BRICK_WIDTH/2, -0.1])
        cylinder(h=1, r=2.75);
                translate([length*BRICK_WIDTH/2,width*BRICK_WIDTH/2, 2.3])
        cylinder(h=2, r=1.75);

		translate([WALL_THICKNESS,WALL_THICKNESS,-WALL_THICKNESS])
		union(){

			// stud inner holes, radius = pin radius

		}

	}
	// Studs
	if(!smooth){
		translate([STUD_RADIUS+WALL_THICKNESS,STUD_RADIUS+WALL_THICKNESS,height*PLATE_HEIGHT])
		for (y = [0:width-1]){
			for (x = [0:length-1]){
				translate ([x*BRICK_WIDTH,y*BRICK_WIDTH,-CORRECTION])
				difference(){
					cylinder(h=STUD_HEIGHT+CORRECTION, r=STUD_RADIUS);
					// Stud inner holes
					translate([0,0,-CORRECTION])
					cylinder(h=0.5*STUD_HEIGHT+CORRECTION,r=PIN_RADIUS);

				}
				// tech logo - disable this if your printer isn't capable of printing this small
				if ( length > width){
					translate([x*BRICK_WIDTH+0.8,y*BRICK_WIDTH-1.9,STUD_HEIGHT-CORRECTION])
					resize([1.2*1.7,2.2*1.7,0.254+CORRECTION])
					rotate(a=[0,0,90])
					import("tech.stl");
				}
				else {
					translate([x*BRICK_WIDTH-1.9,y*BRICK_WIDTH-0.8,STUD_HEIGHT-CORRECTION])
					resize([2.2*1.7,1.2*1.7,0.254+CORRECTION])
					import("tech.stl");
				}
				/*
				// Alternative 2-square logo
				translate ([x*BRICK_WIDTH+CORRECTION,y*BRICK_WIDTH-CORRECTION,STUD_HEIGHT-CORRECTION])
				cube([1,1,2*CORRECTION]);
				translate ([x*BRICK_WIDTH-0.9,y*BRICK_WIDTH-0.9,STUD_HEIGHT-CORRECTION])
				cube([1,1,0.3]);
				*/
			}
		}
	}

}

error: pathspec 'Modules/Action/Rotator/LegoShaft/LegoShaft.scad' did not match any file(s) known to git


handle bar added as a separate print

handle bar added as a separate print

use <m3d/screw_head_hex.scad>

eps = 0.01;
d_rod = 8+0.5;
d_hand = 20;
h_hand = 110;

// standard ball bearing: 8x22x7mm
module bearing()
{
  difference()
  {
    cylinder(d=22, h=7, $fn=100);
    translate(eps*[0,0,-1])
      cylinder(d=8, h=7+2*eps, $fn=40);
  }
}

module screw_head() { screw_head_hex_m8(); }

module washer(dh=0)
{
  difference()
  {
    cylinder(d=15.5, h=1.4+dh);
    translate(eps*[0,0,-1])
      cylinder(d=8.5, h=1.4+dh+2*eps);
  }
}

// slot for ball bearing + 2 washers
module bearing_slot()
{
  d_spacing = 0.5;
  h_spacing = 0.2;
  screw_head_hex_m8(d_spacing, h_spacing);

  for(dh=[-1.4, 7+h_spacing])
    translate([0, 0, dh])
      washer();
}

module bearing_mount()
{
  $fn=90;
  wall = 5;
  d_ext = 22+2*wall;

  // bottom bearing hold
  difference()
  {
    cylinder(d=d_ext, h=7);
    translate([0,0,-eps])
      cylinder(d=22+0.5, h=7+2*eps, $fn=180);
  }
  %bearing();

  translate([0, 0, 7])
  {
    // connecting element
    difference()
    {
      cylinder(d1=d_ext, d2=d_hand, h=(d_ext-d_hand)/2);
      cylinder(d1=d_ext-2*wall+0.5, d2=d_rod, h=(d_ext-d_hand)/2);
    }

    // main e
  }
}

module handle()
{
  h_bm = 13;
  // bottom bearing mount
  bearing_mount();
  translate([0, 0, h_bm])
  {
    // center rod
    difference()
    {
      cylinder(d=d_hand, h=h_hand, $fn=100);
      cylinder(d=d_rod, h=h_hand, $fn=100);
    }
    // top bearing mount
    translate([0, 0, h_hand])
      translate([0, 0, h_bm])
        mirror([0,0,1])
          bearing_mount();
  }
}

for(i=[0:1])
  translate(i*[35,0,0])
    handle();

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


dimensions of the top enclosure

dimensions of the top enclosure

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

// box thickness
th = 2;

shift_x = 4;
shift_y = th + 1;

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

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

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

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

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

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

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

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

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

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

//    for (i = [0:1:socket_n-1]) {
//        translate([start_socket_x+i*socket_int-tol, box_y-th-eps, start_socket_z]) {
//            cube(size=[socket_w+2*tol, th+2*eps, box_z]);
//        }
//    }

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

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

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

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

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

top_box_z = 17 + th;
stoiki_h = top_box_z - th;
pcb_room = 0.5;
screen_start_x = shift_x + 28;
screen_start_y = shift_y + 40;
screen_length_x = 72;
screen_length_y = 24;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 14;
screen_hold_y_shift = -2;

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

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

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

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

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

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

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

// box thickness
th = 2;

//TODO
shift_x = 4;
shift_y = th + 1;

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

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

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

// TODO
usb_type_b_w = 15.2;
usb_type_b_h = 11.5;
start_type_b_y = shift_y + pcb_y - 30.1;
//start_type_b_z = th + pcb_z + tol;

// TODO
usb_type_a_w = 17.3;
usb_type_a_h = 8;
start_type_a_y = shift_y + 44.7;
//start_type_a_z = th + pcb_z + tol;

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

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

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

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

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

//    for (i = [0:1:socket_n-1]) {
//        translate([start_socket_x+i*socket_int-tol, box_y-th-eps, start_socket_z]) {
//            cube(size=[socket_w+2*tol, th+2*eps, box_z]);
//        }
//    }

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

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

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

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

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

top_box_z = 17 + th;
stoiki_h = top_box_z - th;
pcb_room = 0.5;
screen_start_x = shift_x + 28;
screen_start_y = shift_y + 40;
screen_length_x = 72;
screen_length_y = 24;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 14;
screen_hold_y_shift = -2;

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

!difference() {
  union() {
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room]) {
	       cylinder($fn=6, r=stoiki_r, h=top_box_z-th+eps);
          //cube(size=[under_pcb, under_pcb, stoiki_h + eps], center=true);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y + screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=top_box_z+2*eps);
      }
      translate([dx, dy, top_box_z - top_bolt_h]) {
        cylinder($fn=6, r=top_bolt_r, h=top_bolt_h + eps);
      }
    }
  }

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

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

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


WIP base

WIP base

use <dummies.scad>;
use <detection.scad>;

$fn=60;
sphere_phi_out = 72;
rail_phi = 100;
sphere_phi_in = 62;
stand_width = 12;
latitude = 30;

module ring(h, d_in, d_out){
     difference(){
          cylinder(d=d_out, h=h);
          translate([0, 0, -1])
               cylinder(d=d_in, h=h+2);
     }
}

module slider(){
     translate([0, -sphere_phi_out/2+5-3, 0]) rotate([90, 0, 0]) union(){
          cylinder(d=6, h=10, center=true);
          translate([0, 0, -5]) cylinder(d=10, h=1, center=true);

     }
     translate([0, 0, -stand_width/2]) difference(){
          cylinder(h=stand_width, d=rail_phi);
          translate([0, 100-sphere_phi_out/2-3, 0]) cube([200, 200, 200], center=true);
          translate([70, 0, 0]) cube(100, center=true);
          translate([-70, 0, 0]) cube(100, center=true);
          union(){
               translate([0, 0, stand_width/2+2]) ring(h=6, d_in=rail_phi-4, d_out=rail_phi+2);
               translate([0, 0, -stand_width/2+2]) ring(h=6, d_in=rail_phi-4, d_out=rail_phi+2);
          }
     }
}

module sliders(){
     slider();
     rotate([0, 0, 180]) slider();
}

module rail(){
     difference(){
          translate([0, 0, -stand_width/2]) ring(h=stand_width, d_in=rail_phi-2, d_out=rail_phi+8);
          translate([0, 0, -stand_width/2+2]) ring(h=stand_width-4, d_in=rail_phi-3, d_out=rail_phi+4);
     }

}

sliders();
rotate([0, latitude, 0]) detection();
rail();

use <detection.scad>;
$fn=120;
sphere_phi_out = 72;
sphere_phi_in = 62;
stand_width = 12;

module rotation_ring(){
     translate([0, 0, -stand_width/2]) difference(){
          cylinder(d=sphere_phi_out+2*stand_width, h=stand_width);
          translate([0, 0, -1])
               cylinder(d=sphere_phi_out+2, h=stand_width+2);
     }
}
rotation_ring();
detection($fn=120);


added profiled bearings holders

added profiled bearings holders

difference()
{
  cylinder(h=20, r1=120/2, r2=40/2); // main hull
  cylinder(h=20, r=(22-1)/2);            // center rod
  // bearing holdings
  for(offset = [ [0,0,0], [0,0,20-(7+1)] ])
    translate(offset)
      cylinder(h=7+1, r=(22+1)/2);
}

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