// Configurable LEGO shock absorber
// (c) Vitaliy Filippov 2015
// License: GNU GPL 3.0+

// -- CONFIGURATION -- //

$fn = 50;
tube_length = 4; // tube length in studs
piston_length = 3; // piston length in studs
travel_length = piston_length-2; // piston travel in studs
top_type = "ball"; // top mounting type: "pin_hole" = pin hole, "ball_hole" = ball end hole, "axle_hole" = axle hole, "axle" = axle, "ball" = ball, "pin" = pin without friction, "pin_friction" = pin with friction
bottom_type = "pin"; // bottom mounting type
cross_section = false; // show cross-section of the assembly

// -- MAIN -- //

travel = min(travel_length, piston_length-2, tube_length-2);

difference() { union() {

tube();

color([1, 0.5, 0.5]) translate([0, 0, (tube_length+piston_length-1)*8]) rotate([180, 0, 0]) piston();

color([0.5, 0.5, 1]) translate([0, 0, tube_length*8-6]) fixer();

} if (cross_section) { translate([0, -50, -1]) cube(size=[10, 500, (tube_length+piston_length+1)*8]); } }

// -- MODULES -- //

module tube() {
  difference() {
    tube_offset = (bottom_type == "axle_hole" || bottom_type == "axle" || bottom_type == "pin" || bottom_type == "pin_friction" ? 1 : (bottom_type == "ball" ? 0.4 : 0));
    union() {
      translate([0, 0, 8]) cylinder(r=4, h=tube_length*8-8);
      mount_base(type=bottom_type, r=4);
    }
    mount_hole(bottom_type);
    translate([0, 0, 8+tube_offset]) cylinder(r=3.2, h=tube_length*8-tube_offset);
    translate([-5, -0.5, tube_length*8-6]) cube(size=[10, 1, 3], center=false);
  }
}

module piston() {
  difference() {
    union() {
      //translate([0, 0, 4]) cylinder(r=3, h=piston_length*8-4);
      //rotate([90, 0, 0]) translate([0, 4, -4]) cylinder(r=4, h=8);
      translate([0, 0, 8]) cylinder(r=3, h=piston_length*8-8);
      mount_base(top_type);
    }
    mount_hole(top_type);
    translate([-5, -0.7, (piston_length-travel-1)*8+3]) cube(size=[10, 1.4, travel*8+3], center=false);
  }
}

module fixer() {
  translate([-4, -0.5, 0])
    cube(size=[8, 1, 3], center=false);
}

module mount_base(type, r = 3) {
  if (type == "ball_hole" || type == "axle_hole") {
    cylinder(r=4, h=8+0.1);
  }
  else if (type == "pin_hole") {
    hull() {
      translate([0, 0, 4]) cylinder(r=r, h=4);
      difference() {
        rotate([90, 0, 0]) translate([0, 4, -3.2]) cylinder(r=4, h=6.4);
        translate([-5, -5, 7.2]) cube(size=[10, 10, 0.8]);
      }
    }
  }
  else if (type == "axle") {
    axleround(h=8+0.1);
  }
  else if (type == "ball") {
    translate([0, 0, 4]) sphere(r=3);
    translate([0, 0, 6]) linear_extrude(scale=r, height=2) circle(r=1);
  }
  else if (type == "pin") {
    half_pin(false);
  }
  else if (type == "pin_friction") {
    half_pin(true);
  }
}

module mount_hole(type) {
  if (type == "pin_hole") {
    rotate([90, 0, 0]) translate([0, 4, -4]) pin_hole();
  }
  else if (type == "ball_hole") {
    ball_end_n();
  }
  else if (type == "axle_hole") {
    translate([0, 0, -0.1]) axleround(h=8+0.1, axleradius=2.4, axlemesh=1.85);
    translate([0, 0, -0.1]) cylinder($fs=0.5, h=0.8+0.1, r=5);
  }
}

// ball end cut
module ball_end_n() {
  translate([0, 0, 4]) sphere(r=3.05);
  translate([0, 0, 2.3-0.1]) cylinder(r=2.9, h=2);
  translate([0, 0, -0.1]) cylinder(r=5, h=2.4);
}

module axleround(h = 24, axleradius = 2.3, axlemesh = 1.7) {
  difference() {
    cylinder($fn=16, r=axleradius, h=h);
    translate([axlemesh/2, axlemesh/2, -1]) cube([axleradius, axleradius, h+2]);
    translate([axlemesh/2, -axlemesh/2-axleradius, -1]) cube([axleradius, axleradius, h+2]);
    translate([-axlemesh/2-axleradius, axlemesh/2, -1]) cube([axleradius, axleradius, h+2]);
    translate([-axlemesh/2-axleradius, -axlemesh/2-axleradius, -1]) cube([axleradius, axleradius, h+2]);
  }
}

module pin_hole(height=8) {
  translate([0, 0, -0.1]) cylinder($fs=0.5, h=height+0.2, r=2.5);
  translate([0, 0, -0.1]) cylinder($fs=0.5, h=0.8+0.1, r=3);
  translate([0, 0, height-0.8]) cylinder($fs=0.5, h=0.8+0.1, r=3);
}

module half_pin(friction = false) {
  difference() {
    union() {
      cylinder($fs=0.5, h=8, r=2.4);
      if (friction) {
        intersection() {
          cylinder($fs=0.5, h=8, r=2.5);
          union() {
            rotate([0, 0, 45]) translate([-0.4, -2.5, 8-0.8-1.6]) cube(size=[0.6, 5, 1.6]);
            rotate([0, 0, 45]) translate([-0.4, -2.5, 0.6]) cube(size=[0.6, 5, 1.6]);
            rotate([0, 0, 135]) translate([-0.4, -2.5, 8-0.8-1.6]) cube(size=[0.6, 5, 1.6]);
            rotate([0, 0, 135]) translate([-0.4, -2.5, 0.6]) cube(size=[0.6, 5, 1.6]);
          }
        }
      }
      //cylinder($fs=0.5, h=0.6, r=2.6);
      translate([0, 0, 0.2]) minkowski() {
        cylinder($fs=0.5, h=0.2, r=2.4);
        sphere($fn=6, r=0.2);
      }
      translate([0, 0, 8-0.8]) cylinder($fs=0.5, h=0.8, r=2.9);
    }
    translate([0, 0, -0.2]) cylinder($fs=0.5, h=8+0.2, r=2.4-0.8);
    translate([0, 0, 4-0.5]) rotate([90, 0, 0]) cylinder($fn=4, r=0.5, h=8, center=true);
    translate([-0.5, -5, -0.1]) cube(size=[1, 10, 3.6]);
  }
}