moved vertical rail outside of boundaries and extended length to floor

use <projector_plate.scad>;
include <projector.scad>;
use <plate.scad>;
include <profile.scad>;
use <../scad/ob_wheel.scad>
use <../scad/ob_spacer.scad>
include <gantry_cart.scad>
use <../scad/brackets.scad>
use <../scad/geom.scad>
use <support_projector_beam.scad>
include <materials.scad>
use <basin_support.scad>
use <big_screw.scad>

module printer(projector_position = 0) {
  offset_depth = 50;

  middle_sections = 2;

  height = 500;
  width = 500;
  base_depth = 360;
  display_projection = false;
  base_sections = 3;

  projector_movement = height / 2 - acer_projector_distances[projector_position] + middle_sections * 20;

  // projector
  translate([0, 0, -offset_depth]) {
    translate([0, projector_movement, 0]) {
      center_projector() {
        Acer_Plate(160, 120, 85, 100);
        Acer_H6510BD(display_projection);
      }
    }
  }
  beam_offset = 10;
  beam_width = width - 2 * beam_offset;

  carriage_tower_sections = 3;

  translate([0, projector_movement, -offset_depth]) {
    translate([-beam_width/2,-20 * base_sections,-10])
      rotate([90,90,90])
        profile(base_sections, beam_width);
  /*
    translate([beam_width/2,-60,-10])
      rotate([90,0,90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
    translate([-beam_width/2,-60,-10])
      rotate([90,0,-90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
  */
  }

  // projector towers
  translate([0, 0, -offset_depth]) {
    translate([-width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
    translate([width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
  }

  // supports for horizontal beam
  translate([0, middle_sections * 20, -offset_depth])
  for(d = acer_projector_distances) {
    translate([0,d-height/2+10,0])
      support_projector_beam(width-60);
  }
  //height / 2 - d

  // base
  module base(width, depth, sections = 2) {
    profile_height = sections * 20;
    translate([-width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    translate([width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    lateral_beam_width = width - 20;
    translate([-lateral_beam_width/2,0,-base_depth/2+10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);

    translate([-lateral_beam_width/2,0,base_depth/2-10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);
  }

  bottom_sections = 3;
  translate([0,-(height+bottom_sections*20)/2,0])
    base(width, base_depth, bottom_sections);

  translate([0,(height+middle_sections*20)/2,0])
    base(width, base_depth, middle_sections);

  // support towers
  tower_pos = base_depth / 2 - 10;
  translate([-width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);
  translate([width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);

  rotate([0,180,0]) {

    offset = 16;
    plate_width = width + 20 - offset * 2;
    plate_depth = base_depth - 20 * 2;
    cut_width = 440;
    cut_offset = 7.5;
    translate([
      -plate_width/2,
      height/2 + middle_sections * 20,
      -plate_depth / 2 + 20 - offset])
      basin_support(plate_width, plate_depth, cut_width, cut_offset);

    translate([0, height/2 + 20 * middle_sections, base_depth / 2 + 20])
      big_screw();

    // TODO review
    screw_height = 640;
    rail_sections = 2;
    rotate([-90, 0, 0]) {
      translate([65, -base_depth / 2 - 20, -height / 2 - 20 * (bottom_sections)]) {
        profile(rail_sections, screw_height + height + 20 * (bottom_sections + middle_sections));
      }
      translate([-65, -base_depth / 2 - 20, -height / 2 - 20 * (bottom_sections)]) {
        profile(rail_sections, screw_height + height + 20 * (bottom_sections + middle_sections));
      }
    }
    translate([0,0,30]) {
      translate([40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
        rotate([0, 180, 0])
          profile(4, 240);
      translate([-40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
        rotate([0, 180, 0])
          profile(4, 240);
      translate([-50, height / 2 + 20 * middle_sections + 300, base_depth / 2 -60])
        plate(100, 4, 80);
      translate([-50, height / 2 + 20 * middle_sections + 216, base_depth / 2 -60])
        plate(100, 4, 80);
      translate([0, height / 2 + 20 * middle_sections + 300, base_depth / 2 - 210])
        rotate([90,90,0])
          profile(3, 140);

      translate([65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();

      translate([-65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([-65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
      translate([-65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
        rotate([0,90,0])
          ob_solid_wheel();
    }
  }
}

use <projector_plate.scad>;
include <projector.scad>;
use <plate.scad>;
include <profile.scad>;
use <../scad/ob_wheel.scad>
use <../scad/ob_spacer.scad>
include <gantry_cart.scad>
use <../scad/brackets.scad>
use <../scad/geom.scad>
use <support_projector_beam.scad>
include <materials.scad>
use <basin_support.scad>
use <big_screw.scad>

module printer(projector_position = 0) {
  offset_depth = 50;

  middle_sections = 2;

  height = 500;
  width = 500;
  base_depth = 360;
  display_projection = false;

  projector_movement = height / 2 - acer_projector_distances[projector_position] + middle_sections * 20;

  // projector
  translate([0, 0, -offset_depth]) {
    translate([0, projector_movement, 0]) {
      center_projector() {
        Acer_Plate(160, 120, 85, 100);
        Acer_H6510BD(display_projection);
      }
    }
  }
  beam_offset = 10;
  beam_width = width - 2 * beam_offset;

  carriage_tower_sections = 3;

  translate([0, projector_movement, -offset_depth]) {
    translate([-beam_width/2,-60,-10])
      rotate([90,90,90])
        profile_20x60(beam_width);
  /*
    translate([beam_width/2,-60,-10])
      rotate([90,0,90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
    translate([-beam_width/2,-60,-10])
      rotate([90,0,-90])
        gantry_cart_big(carriage_tower_sections, offset = 1);
  */
  }

  // projector towers
  translate([0, 0, -offset_depth]) {
    translate([-width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
    translate([width/2,-height/2,-10])
      rotate([-90,0,0])
        profile(carriage_tower_sections, height);
  }

  // supports for horizontal beam
  translate([0, middle_sections * 20, -offset_depth])
  for(d = acer_projector_distances) {
    translate([0,d-height/2+10,0])
      support_projector_beam(width-60);
  }
  //height / 2 - d

  // base
  module base(width, depth, sections = 2) {
    profile_height = sections * 20;
    translate([-width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    translate([width/2,0,-base_depth/2])
      rotate([0,0,0])
        profile(sections, base_depth);

    lateral_beam_width = width - 20;
    translate([-lateral_beam_width/2,0,-base_depth/2+10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);

    translate([-lateral_beam_width/2,0,base_depth/2-10])
      rotate([0,90,0])
        profile(sections, lateral_beam_width);
  }

  bottom_sections = 4;
  translate([0,-(height+bottom_sections*20)/2,0])
    base(width, base_depth, bottom_sections);

  translate([0,(height+middle_sections*20)/2,0])
    base(width, base_depth, middle_sections);

  // support towers
  tower_pos = base_depth / 2 - 10;
  translate([-width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);
  translate([width/2,-height/2,tower_pos])
    rotate([-90,0,0])
      profile(1, height);

  rotate([0,180,0]) {

    offset = 16;
    plate_width = width + 20 - offset * 2;
    plate_depth = base_depth - 20 * 2;
    cut_width = 440;
    cut_offset = 7.5;
    translate([
      -plate_width/2,
      height/2 + middle_sections * 20,
      -plate_depth / 2 + 20 - offset])
      basin_support(plate_width, plate_depth, cut_width, cut_offset);

    translate([0, height/2 + 20 * middle_sections, base_depth / 2 - 10])
      big_screw();

    // TODO review
    screw_height = 640;
    rail_sections = 2;
    rotate([-90, 0, 0]) {
      translate([65, -base_depth / 2 + 10, height / 2 + 20 * middle_sections]) {
        profile(rail_sections, screw_height);
      }
      translate([-65, -base_depth / 2 + 10, height / 2 + 20 * middle_sections]) {
        profile(rail_sections, screw_height);
      }
    }
    translate([40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
      rotate([0, 180, 0])
        profile(4, 210);
    translate([-40, height / 2 + 20 * middle_sections + 260, base_depth / 2 + 20])
      rotate([0, 180, 0])
        profile(4, 210);
    translate([-50, height / 2 + 20 * middle_sections + 300, base_depth / 2 -60])
      plate(100, 4, 80);
    translate([-50, height / 2 + 20 * middle_sections + 216, base_depth / 2 -60])
      plate(100, 4, 80);
    translate([0, height / 2 + 20 * middle_sections + 300, base_depth / 2 - 180])
      rotate([90,90,0])
        profile(3, 140);

    translate([65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
      rotate([0,90,0])
        ob_solid_wheel();
    translate([65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
      rotate([0,90,0])
        ob_solid_wheel();
    translate([65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
      rotate([0,90,0])
        ob_solid_wheel();

    translate([-65, height / 2 + 20 * middle_sections + 300 - 10, base_depth / 2 - 20 - rail_sections * 10])
      rotate([0,90,0])
        ob_solid_wheel();
    translate([-65, height / 2 + 20 * middle_sections + 240 - 10, base_depth / 2 - 20 - rail_sections * 10])
      rotate([0,90,0])
        ob_solid_wheel();
    translate([-65, height / 2 + 20 * middle_sections + 270 - 10, base_depth / 2 + rail_sections * 10])
      rotate([0,90,0])
        ob_solid_wheel();
  }
}


A yTranlate varialbe was introduced.

A yTranlate varialbe was introduced.

/**
  * This is a library for evenly spacted cutouts.
  */
module originalRotatedSpiralCutout(verticalSpacingFromBottom=0,
                                   z=0,
								   charmCount = 6,
								   xyScale = 0.125,
								   charmStl = "../../../shapes/spurs/spurs-a.stl",
								   rowSpacing = 30)
{
	// outer spurs
	for ( i = [0 : charmCount-1] )
	{
		yTranslate = verticalSpacingFromBottom + (z*rowSpacing);

		rotate([
				90,
				0,
				i * 360 / charmCount
		])
		// normally x,y,z - but here y moves the little spurs up and down
		translate([15, yTranslate, 30])
		scale([xyScale, xyScale, 20.2])
		import(charmStl);
	}
}

module propossedRotatedSpiralCutout(charmStl = "../shapes/oshw/oshw.stl",
									charmCount = 16,
									xyScale = 0.4)
{
    for ( i = [0 : charmCount] )
    {
		yTranslate = 5 * i;

        rotate([
                90,
                0,
                i * 30
        ])
        // normally x,y,z - but here y moves the little spurs up and down
        translate([15, yTranslate, 30])
        scale([xyScale, xyScale, 20.2])
        import(charmStl);
    }
}

/**
  * This is a library for evenly spacted cutouts.
  */
module originalRotatedSpiralCutout(verticalSpacingFromBottom=0,
                                   z=0,
								   charmCount = 6,
								   xyScale = 0.125,
								   charmStl = "../../../shapes/spurs/spurs-a.stl",
								   rowSpacing = 30)
{
	// outer spurs
	for ( i = [0 : charmCount-1] )
	{
		yTranslate = verticalSpacingFromBottom + (z*rowSpacing);

		rotate([
				90,
				0,
				i * 360 / charmCount
		])
		// normally x,y,z - but here y moves the little spurs up and down
		translate([15, yTranslate, 30])
		scale([xyScale, xyScale, 20.2])
		import(charmStl);
	}
}

module propossedRotatedSpiralCutout(spurStl = "../shapes/oshw/oshw.stl",
									charmCount = 16,
									xyScale = 0.4)
{
    for ( i = [0 : charmCount] )
    {
        rotate([
                90,
                0,
                i * 30
        ])
        // normally x,y,z - but here y moves the little spurs up and down
        translate([15, 5 * i, 30])
        scale([xyScale, xyScale, 20.2])
        import(spurStl);
    }
}


added sd card

added sd card

$fn = 64;

// interference fit adjustment for 3D printer
iFitAdjust = .4;
iFitAdjust_d = .25;

// latch buttons
latchButtonDiameter = 13;
latchButtonHeight = 30;
module latch_button(color="green") {
    color(color)
        cylinder(h = latchButtonHeight, d = latchButtonDiameter, center = false);
}

// led momentary buttons
ledButtonDiameter = 25;
ledButtonHeight = 33;
module momentary_button(color="white") {
    color(color)
        cylinder(h = ledButtonHeight, d = ledButtonDiameter, center = false);
}

// encoders
encoderShaftDiameter = 8;
encoderShaftHeight = 18;
encoderShaftOffset = 9;
encoderWidth = 18;
encoderLength = 31;
encoderDepth = 8.2;
module encoder() {
    // encoder shaft
    cylinder(h = encoderShaftHeight, d = encoderShaftDiameter, center=false);
    // encoder base
    translate([-encoderWidth/2, -encoderShaftOffset, -encoderDepth/2])
        cube([encoderWidth, encoderLength, encoderDepth]);
}

// string
stringWallThickness = 1;
stringRecess = 5;
stringLength = 60;
photoresistorWidth = 5.5 + iFitAdjust_d;
photoresistorLength = photoresistorWidth;
photoresistorWireSep = 3.5;
ledLaserDiameter = 6.5 + iFitAdjust_d;
ledLaserLength = 10;
wireCasingDepth = 3;
stringWidth = ledLaserDiameter;
module photoresistor_holder() {
    difference() {
        cylinder(h = stringRecess + stringWallThickness * 2, d = 2 * stringWallThickness + photoresistorWidth + iFitAdjust_d, center = false);
        translate([0,0,-.1])
            cylinder(h = stringRecess + stringWallThickness * 2 + 1, d = photoresistorWidth + iFitAdjust_d, center = false);
        /*
        for (i = [-1,1])
            translate([i * photoresistorWireSep / 2, 0, -1])
                cylinder(h = 20, d = 1, center = false);
        */
    }
    rotate([0, 0, 180])
        translate([-(ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness)/2, -(ledLaserDiameter )/2 - 1, -(wireCasingDepth + stringWallThickness * 2)])
        difference() {
            cube([ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness, ledLaserDiameter + ledLaserDiameter / 2 + 1, wireCasingDepth + stringWallThickness * 2], center=false);
            translate([stringWallThickness, stringWallThickness * 2 + 1, stringWallThickness])
                cube([ledLaserDiameter + iFitAdjust_d , ledLaserDiameter + ledLaserDiameter / 2 - stringWallThickness, wireCasingDepth], center=false);
            translate([ledLaserDiameter / 2 + stringWallThickness, ledLaserDiameter / 2 + stringWallThickness, stringWallThickness])
                cylinder(h=wireCasingDepth + 2 * stringWallThickness, d = ledLaserDiameter + iFitAdjust, center=false);
        }
}
module led_holder() {
    difference() {
        cylinder(h = ledLaserLength + stringWallThickness * 2, d = 2 * stringWallThickness + ledLaserDiameter + iFitAdjust_d, center = false);
        translate([0,0,-.1])
            cylinder(h = ledLaserLength + stringWallThickness * 2 + 1, d = ledLaserDiameter + iFitAdjust_d, center = false);
        /*
        for (i = [-1,1])
            translate([i * photoresistorWireSep / 2, 0, -1])
                cylinder(h = 20, d = 1, center = false);
        */
    }
    translate([-(ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness)/2, -(ledLaserDiameter )/2 - 1, -(wireCasingDepth + stringWallThickness * 2)])
        difference() {
            cube([ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness, ledLaserDiameter + ledLaserDiameter / 2 + 1, wireCasingDepth + stringWallThickness * 2], center=false);
            translate([stringWallThickness, stringWallThickness * 2 + 1, stringWallThickness])
                cube([ledLaserDiameter + iFitAdjust_d , ledLaserDiameter + ledLaserDiameter / 2 - stringWallThickness, wireCasingDepth], center=false);
            translate([ledLaserDiameter / 2 + stringWallThickness, ledLaserDiameter / 2 + stringWallThickness, stringWallThickness])
                cylinder(h=wireCasingDepth + 2 * stringWallThickness, d = ledLaserDiameter + iFitAdjust, center=false);
        }
}
module string() {
 rotate([0, 0, 90])
  translate([0, -(wireCasingDepth + stringWallThickness * 2), ledLaserDiameter]) rotate([90, 0, 0])
   union() {
    photoresistor_holder();
    translate([0, 0, stringLength])
        rotate([180, 0, 0])
            led_holder();
    difference() {
        translate([-(ledLaserDiameter + 2 * stringWallThickness + iFitAdjust_d)/2, - ledLaserDiameter, 0])
            cube([ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness, ledLaserDiameter / 2, stringLength ], center = false);
        cylinder(h=100, d = ledLaserDiameter + iFitAdjust, center=false);
    }
   }
}

// display
OLEDWidth = 27.3;
OLEDDisplayHeight = 19;
OLEDScrewWidth = 20.7;
OLEDScrewHeight = 23.2;
OLEDScrewDiameter = 3;
OLEDDepth = 1;
OLEDDisplayDepth = 1;
module display() {
    difference() {
        union() {
            cube([OLEDWidth, OLEDWidth, OLEDDepth]);
            translate([0, (OLEDWidth - OLEDDisplayHeight) / 2, 1])
                cube([OLEDWidth, OLEDDisplayHeight, OLEDDisplayDepth]);
        }
        for (i = [0: 1])
            for (j = [0: 1])
                translate([(OLEDWidth - OLEDScrewWidth) / 2 + i * OLEDScrewWidth, (OLEDWidth - OLEDScrewHeight) / 2 + j * OLEDScrewHeight, -.1])
                    cylinder(h=boxThickness + 1, d=OLEDScrewDiameter);
    }
}

lidWidth = 100;
lidThickness = 2.5;
rowWidth = ledButtonDiameter + 10;
lidLength = rowWidth * 2 + ledButtonDiameter / 2;
controlOffset = 10;
lidScrewDiameter = 3.5;
lidScrewBoundaryOffset = 10;
module spoke_lid() {
    union() {
        difference () {
            cube([lidWidth, lidLength, lidThickness]);
            for (i = [0:1]) {
                translate([0, ledButtonDiameter + i * rowWidth, -lidThickness * 2]) {
            // led buttons
                    translate([ledButtonDiameter / 2 + controlOffset, 0, 0])
                        momentary_button();
            // encoders
                    translate([ledButtonDiameter / 2 + controlOffset + 2 * controlOffset + latchButtonDiameter / 2 + encoderLength / 4, 0, 0])
                    rotate([0, 0, 270])
                        encoder();
            // latch buttons
                    translate([ledButtonDiameter / 2 + controlOffset + 2 * controlOffset + latchButtonDiameter / 2 + encoderLength + 5, 0, 0])
                        latch_button();

                }
            }
            translate([lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
        }
    }
}

module string_lid() {
    union() {
        difference () {
            union() {
                cube([lidWidth, lidLength, lidThickness]);
            }
            translate([lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            for (i = [0:7])
                translate([15 + stringWidth * i * 1.5, 5, -.01])
                    rotate([0, 0, 90])
                        hull() string();
        }
        for (i = [0:7])
            translate([15 + stringWidth * i * 1.5, 5, 0])
                rotate([0, 0, 90])
                    string();
   }
}

boxHeight = 45;
screwTabDim = 10;
boxThickness = lidThickness;
boxWidth = lidWidth;
boxLength = lidLength;
boxScrewDiameter = lidScrewDiameter;
module spoke_box() {
    difference() {
        union() {
             difference () {
                union() {
                    cube([lidWidth, lidLength, lidThickness]);
                    for (i = [0,1])
                        for (j = [0,1]) {
                            translate([i * lidWidth - i * screwTabDim, j * lidLength - j * screwTabDim, 0])
                                cube([screwTabDim, screwTabDim, boxHeight]);
                    }
                    cube([boxWidth, boxThickness, boxHeight]);
                    translate([0, boxLength - boxThickness, 0])
                        cube([boxWidth, boxThickness, boxHeight]);
                    cube([boxThickness, boxLength, boxHeight]);
                    translate([boxWidth - screwTabDim, 0, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
                }
                for (i = [0,1])
                    for (j = [0,1]) {
                        translate([i * boxWidth - i * screwTabDim + screwTabDim / 2, j * boxLength - j * screwTabDim + screwTabDim / 2, boxHeight - 9])
                            cylinder(h=20, d = lidScrewDiameter);
                    }
                for (i = [1, 2])
                    translate([boxWidth - screwTabDim / 2, i * boxLength / 3, boxThickness])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                translate([boxWidth - screwTabDim / 2, screwTabDim + .1, (boxHeight / 3) * 2])
                    rotate([90, 0, 0])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                translate([boxWidth - screwTabDim / 2, boxLength - boxThickness, (boxHeight / 3) * 2])
                    rotate([90, 0, 0])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
            }
        }
    }
}

pentagonRadius = boxLength / (2.0 * sin(180. / 5.));
pentagonR = (1/10) * sqrt(25 + 10 * sqrt(5)) * boxLength;
module pentagon_core() {
    difference() {
        union() {
            cylinder(h=boxThickness, r=pentagonRadius, $fn=5);
            translate([-pentagonR, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  36])
                translate([pentagonR - screwTabDim, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  2 * 36])
                translate([-pentagonR, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  3 * 36])
                translate([pentagonR - screwTabDim, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  4 * 36])
                translate([-pentagonR, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            for (i = [0:4])
                rotate([0, 0, i * 72])
                    for (j = [-1, 1])
                        translate([-pentagonR + screwTabDim / 2, j * boxLength / 2 - j * screwTabDim / 2, 0])
                            translate([0, 0, boxHeight/2])
                                cube([screwTabDim, screwTabDim, boxHeight], center=true);
        }
        for (i = [0:4])
            rotate([0, 0, i * 72])
                translate([-pentagonR + screwTabDim / 2, 0, 0]) {
                    translate([0, -boxLength / 3 / 2, boxThickness])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                    translate([0, boxLength / 3 / 2, boxThickness])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                }
        for (i = [0:4])
            rotate([0, 0, i * 72])
                for (j = [-1, 1])
                    translate([-pentagonR + screwTabDim / 2, j * boxLength / 2 - (j == -1 ? -1 * screwTabDim : screwTabDim / 4), 0])
                        translate([0, 0, (boxHeight / 3) * 2])
                            rotate([90, 0, 0])
                                #cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
         for (i = [0:4])
            rotate([0, 0, i * 72])
                translate([pentagonRadius - (screwTabDim / 3) * 2, 0, boxHeight - 9.9])
                    cylinder(h=10, d=boxScrewDiameter);
   }
}

module pentagon_lid() {
    difference() {
        union() {
            cylinder(h=boxThickness, r=pentagonRadius, $fn=5);
        }
        for (i = [0:4])
            rotate([0, 0, i * 72])
                translate([pentagonRadius - (screwTabDim / 3) * 2, 0, -.1])
                    cylinder(h=10, d=boxScrewDiameter);
        translate([-OLEDWidth / 2, 0, 0]) rotate([0, 0, -18]) {
            translate([0, (OLEDWidth - OLEDDisplayHeight) / 2, -.1])
                cube([OLEDWidth, OLEDDisplayHeight, boxThickness + .2]);
            for (i = [0: 1])
                for (j = [0: 1])
                    translate([(OLEDWidth - OLEDScrewWidth) / 2 + i * OLEDScrewWidth, (OLEDWidth - OLEDScrewHeight) / 2 + j * OLEDScrewHeight, -.1])
                        cylinder(h=boxThickness + 1, d=OLEDScrewDiameter);
        }
        for (i = [3:4])
            rotate([0, 0, i * 72])
                translate([pentagonRadius - ledButtonDiameter * 1.5, 0, -.1])
                    momentary_button(color="red");
        for (i = [3:4])
            rotate([0, 0, 180 + i * 72])
                translate([pentagonRadius - latchButtonDiameter * 2.2, 0, -.1])
                    latch_button((i == 3 ? "red" : "green"));
        for (i = [0,2])
            rotate([0, 0, (i == 0 ? - 1 : 1) * 12 + i * 72])
                translate([pentagonRadius - latchButtonDiameter * 2.2, 0, -10])
                    encoder();

        rotate([0, 0, 4*-72])
            translate([-pentagonR + boxThickness, -sdCardWidth / 2, 10])
                rotate([0, 90, 0])
                    sd_card(iFitAdjust);
    }
//    display();
}

sdCardHeight = 32;
sdCardWidth = 24;
sdCardThickness = 2.1;
module sd_card(adjust) {
    cube([sdCardHeight + adjust, sdCardWidth + adjust, sdCardThickness + adjust]);
}

module screw_tab() {
    difference() {
        cube([screwTabDim, 2 * screwTabDim, boxThickness]);
        for (i = [0,1])
            translate([screwTabDim / 2, screwTabDim / 2 + i * screwTabDim, -.1])
                cylinder(h=10, d=boxScrewDiameter);
    }
}

module case() {
    //translate([0, 0, boxHeight + boxThickness]) spoke_lid();
    //string_lid();
    //spoke_box();
    //screw_tab();
    //pentagon_core();
    //translate([0, 0, boxHeight + boxThickness])
        pentagon_lid();
    //display();
}

case();

$fn = 64;

// interference fit adjustment for 3D printer
iFitAdjust = .4;
iFitAdjust_d = .25;

// latch buttons
latchButtonDiameter = 13;
latchButtonHeight = 30;
module latch_button(color="green") {
    color(color)
        cylinder(h = latchButtonHeight, d = latchButtonDiameter, center = false);
}

// led momentary buttons
ledButtonDiameter = 25;
ledButtonHeight = 33;
module momentary_button(color="white") {
    color(color)
        cylinder(h = ledButtonHeight, d = ledButtonDiameter, center = false);
}

// encoders
encoderShaftDiameter = 8;
encoderShaftHeight = 18;
encoderShaftOffset = 9;
encoderWidth = 18;
encoderLength = 31;
encoderDepth = 8.2;
module encoder() {
    // encoder shaft
    cylinder(h = encoderShaftHeight, d = encoderShaftDiameter, center=false);
    // encoder base
    translate([-encoderWidth/2, -encoderShaftOffset, -encoderDepth/2])
        cube([encoderWidth, encoderLength, encoderDepth]);
}

// string
stringWallThickness = 1;
stringRecess = 5;
stringLength = 60;
photoresistorWidth = 5.5 + iFitAdjust_d;
photoresistorLength = photoresistorWidth;
photoresistorWireSep = 3.5;
ledLaserDiameter = 6.5 + iFitAdjust_d;
ledLaserLength = 10;
wireCasingDepth = 3;
stringWidth = ledLaserDiameter;
module photoresistor_holder() {
    difference() {
        cylinder(h = stringRecess + stringWallThickness * 2, d = 2 * stringWallThickness + photoresistorWidth + iFitAdjust_d, center = false);
        translate([0,0,-.1])
            cylinder(h = stringRecess + stringWallThickness * 2 + 1, d = photoresistorWidth + iFitAdjust_d, center = false);
        /*
        for (i = [-1,1])
            translate([i * photoresistorWireSep / 2, 0, -1])
                cylinder(h = 20, d = 1, center = false);
        */
    }
    rotate([0, 0, 180])
        translate([-(ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness)/2, -(ledLaserDiameter )/2 - 1, -(wireCasingDepth + stringWallThickness * 2)])
        difference() {
            cube([ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness, ledLaserDiameter + ledLaserDiameter / 2 + 1, wireCasingDepth + stringWallThickness * 2], center=false);
            translate([stringWallThickness, stringWallThickness * 2 + 1, stringWallThickness])
                cube([ledLaserDiameter + iFitAdjust_d , ledLaserDiameter + ledLaserDiameter / 2 - stringWallThickness, wireCasingDepth], center=false);
            translate([ledLaserDiameter / 2 + stringWallThickness, ledLaserDiameter / 2 + stringWallThickness, stringWallThickness])
                cylinder(h=wireCasingDepth + 2 * stringWallThickness, d = ledLaserDiameter + iFitAdjust, center=false);
        }
}
module led_holder() {
    difference() {
        cylinder(h = ledLaserLength + stringWallThickness * 2, d = 2 * stringWallThickness + ledLaserDiameter + iFitAdjust_d, center = false);
        translate([0,0,-.1])
            cylinder(h = ledLaserLength + stringWallThickness * 2 + 1, d = ledLaserDiameter + iFitAdjust_d, center = false);
        /*
        for (i = [-1,1])
            translate([i * photoresistorWireSep / 2, 0, -1])
                cylinder(h = 20, d = 1, center = false);
        */
    }
    translate([-(ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness)/2, -(ledLaserDiameter )/2 - 1, -(wireCasingDepth + stringWallThickness * 2)])
        difference() {
            cube([ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness, ledLaserDiameter + ledLaserDiameter / 2 + 1, wireCasingDepth + stringWallThickness * 2], center=false);
            translate([stringWallThickness, stringWallThickness * 2 + 1, stringWallThickness])
                cube([ledLaserDiameter + iFitAdjust_d , ledLaserDiameter + ledLaserDiameter / 2 - stringWallThickness, wireCasingDepth], center=false);
            translate([ledLaserDiameter / 2 + stringWallThickness, ledLaserDiameter / 2 + stringWallThickness, stringWallThickness])
                cylinder(h=wireCasingDepth + 2 * stringWallThickness, d = ledLaserDiameter + iFitAdjust, center=false);
        }
}
module string() {
 rotate([0, 0, 90])
  translate([0, -(wireCasingDepth + stringWallThickness * 2), ledLaserDiameter]) rotate([90, 0, 0])
   union() {
    photoresistor_holder();
    translate([0, 0, stringLength])
        rotate([180, 0, 0])
            led_holder();
    difference() {
        translate([-(ledLaserDiameter + 2 * stringWallThickness + iFitAdjust_d)/2, - ledLaserDiameter, 0])
            cube([ledLaserDiameter + iFitAdjust_d + 2 * stringWallThickness, ledLaserDiameter / 2, stringLength ], center = false);
        cylinder(h=100, d = ledLaserDiameter + iFitAdjust, center=false);
    }
   }
}

// display
OLEDWidth = 27.3;
OLEDDisplayHeight = 19;
OLEDScrewWidth = 20.7;
OLEDScrewHeight = 23.2;
OLEDScrewDiameter = 3;
OLEDDepth = 1;
OLEDDisplayDepth = 1;
module display() {
    difference() {
        union() {
            cube([OLEDWidth, OLEDWidth, OLEDDepth]);
            translate([0, (OLEDWidth - OLEDDisplayHeight) / 2, 1])
                cube([OLEDWidth, OLEDDisplayHeight, OLEDDisplayDepth]);
        }
        for (i = [0: 1])
            for (j = [0: 1])
                translate([(OLEDWidth - OLEDScrewWidth) / 2 + i * OLEDScrewWidth, (OLEDWidth - OLEDScrewHeight) / 2 + j * OLEDScrewHeight, -.1])
                    cylinder(h=boxThickness + 1, d=OLEDScrewDiameter);
    }
}

lidWidth = 100;
lidThickness = 2.5;
rowWidth = ledButtonDiameter + 10;
lidLength = rowWidth * 2 + ledButtonDiameter / 2;
controlOffset = 10;
lidScrewDiameter = 3.5;
lidScrewBoundaryOffset = 10;
module spoke_lid() {
    union() {
        difference () {
            cube([lidWidth, lidLength, lidThickness]);
            for (i = [0:1]) {
                translate([0, ledButtonDiameter + i * rowWidth, -lidThickness * 2]) {
            // led buttons
                    translate([ledButtonDiameter / 2 + controlOffset, 0, 0])
                        momentary_button();
            // encoders
                    translate([ledButtonDiameter / 2 + controlOffset + 2 * controlOffset + latchButtonDiameter / 2 + encoderLength / 4, 0, 0])
                    rotate([0, 0, 270])
                        encoder();
            // latch buttons
                    translate([ledButtonDiameter / 2 + controlOffset + 2 * controlOffset + latchButtonDiameter / 2 + encoderLength + 5, 0, 0])
                        latch_button();

                }
            }
            translate([lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
        }
    }
}

module string_lid() {
    union() {
        difference () {
            union() {
                cube([lidWidth, lidLength, lidThickness]);
            }
            translate([lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            translate([lidWidth - lidScrewBoundaryOffset/2, lidLength - lidScrewBoundaryOffset/2, -.1])
                cylinder(h=lidThickness * 2, d=lidScrewDiameter);
            for (i = [0:7])
                translate([15 + stringWidth * i * 1.5, 5, -.01])
                    rotate([0, 0, 90])
                        hull() string();
        }
        for (i = [0:7])
            translate([15 + stringWidth * i * 1.5, 5, 0])
                rotate([0, 0, 90])
                    string();
   }
}

boxHeight = 45;
screwTabDim = 10;
boxThickness = lidThickness;
boxWidth = lidWidth;
boxLength = lidLength;
boxScrewDiameter = lidScrewDiameter;
module spoke_box() {
    difference() {
        union() {
             difference () {
                union() {
                    cube([lidWidth, lidLength, lidThickness]);
                    for (i = [0,1])
                        for (j = [0,1]) {
                            translate([i * lidWidth - i * screwTabDim, j * lidLength - j * screwTabDim, 0])
                                cube([screwTabDim, screwTabDim, boxHeight]);
                    }
                    cube([boxWidth, boxThickness, boxHeight]);
                    translate([0, boxLength - boxThickness, 0])
                        cube([boxWidth, boxThickness, boxHeight]);
                    cube([boxThickness, boxLength, boxHeight]);
                    translate([boxWidth - screwTabDim, 0, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
                }
                for (i = [0,1])
                    for (j = [0,1]) {
                        translate([i * boxWidth - i * screwTabDim + screwTabDim / 2, j * boxLength - j * screwTabDim + screwTabDim / 2, boxHeight - 9])
                            cylinder(h=20, d = lidScrewDiameter);
                    }
                for (i = [1, 2])
                    translate([boxWidth - screwTabDim / 2, i * boxLength / 3, boxThickness])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                translate([boxWidth - screwTabDim / 2, screwTabDim + .1, (boxHeight / 3) * 2])
                    rotate([90, 0, 0])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                translate([boxWidth - screwTabDim / 2, boxLength - boxThickness, (boxHeight / 3) * 2])
                    rotate([90, 0, 0])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
            }
        }
    }
}

pentagonRadius = boxLength / (2.0 * sin(180. / 5.));
pentagonR = (1/10) * sqrt(25 + 10 * sqrt(5)) * boxLength;
module pentagon_core() {
    difference() {
        union() {
            cylinder(h=boxThickness, r=pentagonRadius, $fn=5);
            translate([-pentagonR, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  36])
                translate([pentagonR - screwTabDim, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  2 * 36])
                translate([-pentagonR, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  3 * 36])
                translate([pentagonR - screwTabDim, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            rotate([0, 0,  4 * 36])
                translate([-pentagonR, 0, 0])
                    translate([0, -boxLength / 2, 0])
                        cube([screwTabDim, boxLength, screwTabDim]);
            for (i = [0:4])
                rotate([0, 0, i * 72])
                    for (j = [-1, 1])
                        translate([-pentagonR + screwTabDim / 2, j * boxLength / 2 - j * screwTabDim / 2, 0])
                            translate([0, 0, boxHeight/2])
                                cube([screwTabDim, screwTabDim, boxHeight], center=true);
        }
        for (i = [0:4])
            rotate([0, 0, i * 72])
                translate([-pentagonR + screwTabDim / 2, 0, 0]) {
                    translate([0, -boxLength / 3 / 2, boxThickness])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                    translate([0, boxLength / 3 / 2, boxThickness])
                        cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
                }
        for (i = [0:4])
            rotate([0, 0, i * 72])
                for (j = [-1, 1])
                    translate([-pentagonR + screwTabDim / 2, j * boxLength / 2 - (j == -1 ? -1 * screwTabDim : screwTabDim / 4), 0])
                        translate([0, 0, (boxHeight / 3) * 2])
                            rotate([90, 0, 0])
                                #cylinder(h=screwTabDim + .1 - boxThickness, d=boxScrewDiameter);
         for (i = [0:4])
            rotate([0, 0, i * 72])
                translate([pentagonRadius - (screwTabDim / 3) * 2, 0, boxHeight - 9.9])
                    cylinder(h=10, d=boxScrewDiameter);
   }
}

module pentagon_lid() {
    difference() {
        union() {
            cylinder(h=boxThickness, r=pentagonRadius, $fn=5);
        }
        for (i = [0:4])
            rotate([0, 0, i * 72])
                translate([pentagonRadius - (screwTabDim / 3) * 2, 0, -.1])
                    cylinder(h=10, d=boxScrewDiameter);
        translate([-OLEDWidth / 2, 0, 0]) rotate([0, 0, -18]) {
            translate([0, (OLEDWidth - OLEDDisplayHeight) / 2, -.1])
                cube([OLEDWidth, OLEDDisplayHeight, boxThickness + .2]);
            for (i = [0: 1])
                for (j = [0: 1])
                    translate([(OLEDWidth - OLEDScrewWidth) / 2 + i * OLEDScrewWidth, (OLEDWidth - OLEDScrewHeight) / 2 + j * OLEDScrewHeight, -.1])
                        cylinder(h=boxThickness + 1, d=OLEDScrewDiameter);
        }
        for (i = [3:4])
            rotate([0, 0, i * 72])
                translate([pentagonRadius - ledButtonDiameter * 1.5, 0, -.1])
                    momentary_button(color="red");
        for (i = [3:4])
            rotate([0, 0, 180 + i * 72])
                translate([pentagonRadius - latchButtonDiameter * 2.2, 0, -.1])
                    latch_button((i == 3 ? "red" : "green"));
        for (i = [0,2])
            rotate([0, 0, (i == 0 ? - 1 : 1) * 12 + i * 72])
                translate([pentagonRadius - latchButtonDiameter * 2.2, 0, -10])
                    encoder();
    }
//    display();
}

module screw_tab() {
    difference() {
        cube([screwTabDim, 2 * screwTabDim, boxThickness]);
        for (i = [0,1])
            translate([screwTabDim / 2, screwTabDim / 2 + i * screwTabDim, -.1])
                cylinder(h=10, d=boxScrewDiameter);
    }
}

module case() {
    //translate([0, 0, boxHeight + boxThickness]) spoke_lid();
    //string_lid();
    //spoke_box();
    //screw_tab();
    //pentagon_core();
    //translate([0, 0, boxHeight + boxThickness])
        pentagon_lid();
    //display();
}

case();


improved CH clearance at H node on BH segments

// 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.4);

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

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

// 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.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() {
  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,7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for knee
      //translate([-5,2,1.5*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=22,$fn=17,center=true);
  }

  // hinge holders at H
  %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.9])cube([3,3,2.8],center=true);
  }
  translate([FGleft,FGperp,-.87]) {
    rotate([180,0,0]) F698();
    translate([0,0,5.3]) rotate([180,0,0]) F698();
    translate([0,0,2.24]) F698();
    translate([0,0,6.74]) F698();
  }

  // vertical brace extension at knee
  translate([3.5,0,4.1]) cube([2.6,2.6,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
  for (z=[-.3,5.1]) hull() {
    translate([   3    ,   1    ,z]) barEnd1();
    translate([FGleft-1,FGperp-1,z]) barEnd1();
  }
  hull() {  // dig brace.  Could be gusset?
      translate([3,1,5.7]) barEnd1();
      translate([12,11,-.3]) barEnd1();
  }
  translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  hull() {
      translate([FGleft-7.2,FGperp-8,5.3]) barEnd1();
      translate([14,13.5,-.3]) barEnd1();
  }

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

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

  // extra truss braces
  hull() {
      translate([46,15,3]) barEnd1();
      translate([35, 0,0]) barEnd1();
  }
  translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
  translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
}

$fn=12;
module hip() {
  translate([DE/2,0,-.2]) cube([DE-5,2.5,2.5],center=true); // top tube
  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     cylinder(r=2.54*1.5/2,h=7.2,$fn=36); // axle
     cylinder(r=2.54*1.5/2-.3,h=22,$fn=18,center=true);
  }

  // top tube fork plates
  translate([DE,0,0]) mirror([1,0,0]) eFork();
                                      eFork();

  hull() {  // diag tubes
    translate([DE-DEleft,-DEperp,0]) barEnd1();
    translate([8,0,0]) barEnd1();
  }
  hull() {
    translate([DE-DEleft,-DEperp,0]) barEnd1();
    translate([DE-8,0,0]) barEnd1();
  }

  // extra bracing
  translate([DE/2,-20,0]) rotate([0,90,0]) cylinder(r=.8,h=20,center=true);
  translate([DE-DEleft,-DEperp,5]) rotate([-110,0,0]) cylinder(r=.8,h=14.4);
}

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=1,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .36]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.36]) 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,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3,$fn=11,center=true);

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

module EFlink() {
  translate([EF,0,0]) SA8();
  translate([EF/2-.4,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-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
    translate([0,0,2.4]) cylinder(r=2.54*1.5/2,h=13.5,$fn=36,center=true);
    translate([0,0,2.4]) cube([5,5,7.9],center=true);
    cylinder(r=2.54*1.5/2-.3,h=22,$fn=19,center=true);
  }

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

  // brace near axle
  translate([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=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }

  // to check dimensions
  //%translate([BH/2,0,2.4]) cube([BH,1,7.8],center=true);
}
module barEnd1() sphere(.8,$fn=12);
// diag braces.  Try to leave fork area open to allow clearance for CH link
module BHcrosses() {
h1=BH-4;  // node closest to H
h2=h1-20;
b2=h2-2;
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,hi]) barEnd1();
    translate([b2,-spread,lo]) barEnd1();
  }
  hull() {
    translate([b2,spread,hi]) barEnd1();
    translate([b1,spread,lo]) barEnd1();
  }
}
module BHlinks1() {
  translate([0,0, 6.8])                 BHlink();
  translate([0,0,-2  ]) mirror([0,0,1]) BHlink();
}
module BHlink() {
  cylinder(r=1.4,h=6,$fn=24);

  //%translate([BH/2-1,0,1.3]) cube([BH-2,2.5,2.5],center=true);
  for (q=[-1,1]) hull() {
    translate([  0 ,1.5*q,1]) barEnd1();
    translate([BH-3,1  *q,1]) barEnd1();
  }
  hull() {
    translate([  0 ,0,5]) barEnd1();
    translate([BH-3,0,1]) barEnd1();
  }

  translate([BH,0,-.3]) difference() {
     hull() {
       cylinder(r=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }
}

// 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.4);

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

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

// 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.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() {
  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,7]) rotate([0,0,(z>0)?25*0:0]) difference() {
    hull() {
      // This was elongated as a brace for knee
      //translate([-5,2,1.5*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=22,$fn=17,center=true);
  }

  // hinge holders at H
  %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.9])cube([3,3,2.8],center=true);
  }
  translate([FGleft,FGperp,-.87]) {
    rotate([180,0,0]) F698();
    translate([0,0,5.3]) rotate([180,0,0]) F698();
    translate([0,0,2.24]) F698();
    translate([0,0,6.74]) F698();
  }

  // vertical brace extension at knee
  translate([3.5,0,4.1]) cube([2.6,2.6,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
  for (z=[-.3,5.1]) hull() {
    translate([   3    ,   1    ,z]) sphere(.8);
    translate([FGleft-1,FGperp-1,z]) sphere(.8);
  }
  hull() {  // dig brace.  Could be gusset?
      translate([3,1,5.7]) sphere(.8);
      translate([12,11,-.3]) sphere(.8);
  }
  translate([FGleft-2,FGperp-2,.3]) cylinder(r=.8,h=5,$fn=11);
  hull() {
      translate([FGleft-7.2,FGperp-8,5.3]) sphere(.8);
      translate([14,13.5,-.3]) sphere(.8);
  }

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

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

  // extra truss braces
  hull() {
      translate([46,15,3]) sphere(.8);
      translate([35, 0,0]) sphere(.8);
  }
  translate([FGleft+2,FGperp-2,.3]) cylinder(r=.6,h=5);
  translate([FGleft,FGperp-2,.3]) cylinder(r=.6,h=5);
}

$fn=12;
module hip() {
  translate([DE/2,0,-.2]) cube([DE-5,2.5,2.5],center=true); // top tube
  translate([DE-DEleft,-DEperp,-1.2]) difference() {
     cylinder(r=2.54*1.5/2,h=7.2,$fn=36); // axle
     cylinder(r=2.54*1.5/2-.3,h=22,$fn=18,center=true);
  }

  // top tube fork plates
  translate([DE,0,0]) mirror([1,0,0]) eFork();
                                      eFork();

  hull() {  // diag tubes
    translate([DE-DEleft,-DEperp,0]) sphere(.8);
    translate([8,0,0]) sphere(.8);
  }
  hull() {
    translate([DE-DEleft,-DEperp,0]) sphere(.8);
    translate([DE-8,0,0]) sphere(.8);
  }

  // extra bracing
  translate([DE/2,-20,0]) rotate([0,90,0]) cylinder(r=.8,h=20,center=true);
  translate([DE-DEleft,-DEperp,5]) rotate([-110,0,0]) cylinder(r=.8,h=14.4);
}

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=1,$fn=36,center=true);
    cylinder(r=2.54/2-.17,h=2,$fn=24,center=true);
  }
  translate([0,0, .36]) F698(); //cylinder(r=1.4,h=.7,$fn=24,center=true);
  translate([0,0,-.36]) 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,0,0]) rotate([0,90,0])
     cylinder(r=.6,h=dx-3,$fn=11,center=true);

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

module EFlink() {
  translate([EF,0,0]) SA8();
  translate([EF/2-.4,0,0]) rotate([0,90,0])
      cylinder(r=.8,h=EF-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
    translate([0,0,2.4]) cylinder(r=2.54*1.5/2,h=13.5,$fn=36,center=true);
    translate([0,0,2.4]) cube([5,5,7.9],center=true);
    cylinder(r=2.54*1.5/2-.3,h=22,$fn=19,center=true);
  }

  // brace near axle
  translate([3,0,2.2]) cylinder(r=.8,h=10,$fn=19,center=true);
  // fork brace
  translate([BH-7,0,2.43]) cube([2.5,2.5,7.6],center=true);

  for(z=[-2.4,7.2]) {
     hull() {
       translate([BH-6,0,z]) sphere(.8);
       translate([   0,0,z]) sphere(.8);
     }
  }

  hull() {
    translate([   4,.7,-1.6]) sphere(.8);
    translate([BH-9,.7, 6.2]) sphere(.8);
  }
  hull() {
    translate([   4,-.7, 6.2]) sphere(.8);
    translate([BH-9,-.7,-1.6]) sphere(.8);
  }

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

  // to check dimensions
  //%translate([BH/2,0,2.4]) cube([BH,1,7.8],center=true);
}
module BHlinks1() {
  translate([0,0, 6.8])                 BHlink();
  translate([0,0,-2  ]) mirror([0,0,1]) BHlink();
}
module BHlink() {
  cylinder(r=1.4,h=6,$fn=24);

  //%translate([BH/2-1,0,1.3]) cube([BH-2,2.5,2.5],center=true);
  for (q=[-1,1]) hull() {
    translate([  0 ,1.5*q,1]) sphere(0.8);
    translate([BH-3,1  *q,1]) sphere(0.8);
  }
  hull() {
    translate([  0 ,0,5]) sphere(0.8);
    translate([BH-3,0,1]) sphere(0.8);
  }

  translate([BH,0,-.3]) difference() {
     hull() {
       cylinder(r=3,h=.33,$fn=36);
       translate([-8,0,0]) cylinder(r=1,h=.33);
     }
     cylinder(r=.7,h=2,center=true);
  }
}


main brick

main brick

length = 144.5;

module main_track()
{
  cube([length, 40, 12]);
}

main_track();

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


The stand was fleshed out some more.

The stand was fleshed out some more.

use <MCAD/shapes.scad>

use <../../../basics/rounded-edges/rounded-cube/rounded-cube.scad>

module wallMountedStand(mount_cube_xLength,
						mount_cube_yLength,
						mount_cube_zLength,
						platform_height,
						platform_segmentCount,
						platform_topRadius,
						support_xLength,
						support_zLength)
{
	union()
	{
		wallMountedStand_platform(height = platform_height,
								  segmentCount = platform_segmentCount,
							  	  topRadius = platform_topRadius);

		wallMountedStand_support(platform_topRadius = platform_topRadius,
								 support_xLength = support_xLength,
								 support_zLength = support_zLength);

		wallMountedStand_mount(cube_xLength = mount_cube_xLength,
							   cube_yLength = mount_cube_yLength,
							   cube_zLength = mount_cube_zLength,
							   platform_topRadius = platform_topRadius);
   }
}

module wallMountedStand_platform(height,
								 segmentCount,
							 	 topRadius)
{
	color("orange")
	cylinder(h=height, r1=topRadius, r2=40, $fn=segmentCount);
}

module wallMountedStand_support(platform_topRadius,
								support_xLength,
								support_zLength)
{
	echo("slooop");
	adjacent = support_zLength - 15;
	opposite = support_xLength; //platform_topRadius + 5;
	depth = 10;

	zTranslate = -platform_topRadius;

	color("green")
	translate([zTranslate, 0, 0])
	rotate([180, 90, 90])
	rightTriangle(adjacent, opposite, depth);

	echo("slooop 2");
}

module wallMountedStand_mount(cube_xLength,
							  cube_yLength,
							  cube_zLength,
							  platform_topRadius)
{
	size = [cube_xLength, cube_yLength, cube_zLength];

	cornerRadius = 2;

	xTranslate = -platform_topRadius + cornerRadius;
	yTranslate = -cube_yLength / 2.0;

	difference()
	{
		color("orange")
		translate([xTranslate, yTranslate, 0])
		roundedCube(cornerRadius = cornerRadius,
		            sides=20,
		            sidesOnly=true,
		            size=size);

		wallMountedStand_mountCutouts();
	}
}

module wallMountedStand_mountCutouts()
{
	xTranslate = -70;
	yTranslate = -15;
	zTranslate = 15;

	rotation = [0, 90, 0];

	color("purple")
	translate([xTranslate, yTranslate, zTranslate])
	rotate(rotation)
	cylinder(r=1, h = 80, $fn = 30);

	color("purple")
	translate([xTranslate, -yTranslate, zTranslate])
	rotate(rotation)
	cylinder(r=1, h = 80, $fn = 30);
}

use <MCAD/shapes.scad>

use <../../../basics/rounded-edges/rounded-cube/rounded-cube.scad>

module wallMountedStand(mount_cube_yLength,
						platform_height,
						platform_segmentCount,
						platform_topRadius,
						support_height)
{
	union()
	{
		wallMountedStand_platform(height = platform_height,
								  segmentCount = platform_segmentCount,
							  	  topRadius = platform_topRadius);

		wallMountedStand_support(platform_topRadius = platform_topRadius,
								 support_height = support_height);

		wallMountedStand_mount(cube_yLength = mount_cube_yLength,
							   platform_topRadius = platform_topRadius);
   }
}

module wallMountedStand_platform(height,
								 segmentCount,
							 	 topRadius)
{
	color("orange")
	cylinder(h=height, r1=topRadius, r2=40, $fn=segmentCount);
}

module wallMountedStand_support(platform_topRadius,
								support_height)
{
	echo("slooop");
	adjacent = support_height - 25;
	opposite = platform_topRadius - 4;
	depth = 40;

	zTranslate = -platform_topRadius;

	color("green")
	translate([zTranslate, 0, 0])
	rotate([180, 90, 90])
	rightTriangle(adjacent, opposite, depth);

	echo("slooop 2");
}

module wallMountedStand_mount(cube_yLength,
							  platform_topRadius)
{
	boardLength = 10;
	boardHeight = 19;

	size = [boardLength, cube_yLength, boardHeight];

	xTranslate = -platform_topRadius;

	color("orange")
	translate([xTranslate, 0, 0])
	roundedCube(cornerRadius = 5,
	            sides=20,
	            sidesOnly=true,
	            size=size);
}