use law of cosines to make smoother curve between arms
authordaniel watson <ozzloy@gmail.com>
Sat, 1 Apr 2017 23:43:46 +0000 (16:43 -0700)
committerdaniel watson <ozzloy@gmail.com>
Sat, 1 Apr 2017 23:44:16 +0000 (16:44 -0700)
spin-data.scad
spin.scad

index e25eed3a61c2b9c2adb815834bcdd36ee9968cf8..57e3b2dc79c8b6c262c6611f68b96aa81ef98726 100644 (file)
@@ -121,7 +121,6 @@ module spin_slice(weight_radius,
                   arms) {
   joiner_radius = (bearing_radius + weight_radius) / 2;
 
-  bearing_xy = [0, 0];
   // a = side along x axis
   a = bearing_radius + weight_radius + wall;
   // b = side from center to joiner
@@ -129,11 +128,11 @@ module spin_slice(weight_radius,
   // c = side between joiner and arm center
   c = joiner_radius + weight_radius + round_extra;
 
-  weight_xy = [a, 0];
-
   cos_C = (pow(a, 2) + pow(b, 2) - pow(c, 2)) / (2 * a * b);
   sin_C = sqrt(1 - pow(cos_C, 2));
 
+  bearing_xy = [0, 0];
+  weight_xy = [a, 0];
   joiner_xy = [cos_C, sin_C] * b;
 
   for(arm = [0 : arms - 1]) {
@@ -150,6 +149,66 @@ module spin_slice(weight_radius,
           translate(joiner_xy) {
             circle(joiner_radius); } } } } } }
 
+module spin_cosine_slice(weight_radius,
+                         bearing_radius,
+                         round_extra,
+                         wall,
+                         arms) {
+  /* in order to make a smooth transition from one arm to the next,
+     follow the path of a circle just barely touching both arms and
+     the center circle.  this is referred to as the joiner circle.
+
+     the joiner circle's radius and position are calculated using
+     geometry.  the center of the bearing, weight and joiner circle
+     create a triangle.
+
+     a = side between bearing and weight centers
+     b = side between bearing and joiner centers
+     c = side between joiner and weight centers
+
+     A = angle opposite a, inside joiner
+     B = angle opposite b, inside weight
+     C = angle opposite c, inside bearing
+   */
+
+  r0 = bearing_radius;
+  r1 = weight_radius;
+  // slightly cheated.  calculated using 3 arms, C = 60.
+  r2 = ((pow(r0, 2)
+       + r0 * wall
+       + r0 * r1
+       + pow(wall, 2)
+       + 2 * r1 * wall
+       + r0 * round_extra
+       - wall * round_extra
+       - 3 * r1 * round_extra)
+      / (3 * r1 + wall - r0));
+
+  joiner_radius = r2;
+
+  // a = side along x axis
+  a = r0 + wall + r1;
+  // b = side from center to joiner
+  b = r0 + round_extra + r2;
+  // c = side between joiner and arm center
+  c = r1 + round_extra + r2;
+
+  bearing_xy = [0, 0];
+  weight_xy = [a, 0];
+  joiner_xy = [cos(60), sin(60)] * b;
+
+  translate(bearing_xy) {
+    circle(bearing_radius + round_extra); }
+  for(arm = [0 : arms - 1]) {
+    rotate(arm * (360 / arms)) {
+      translate(weight_xy) {
+        circle(weight_radius + round_extra); }
+      mirrored([0, 1]) {
+        difference() {
+          polygon([bearing_xy, weight_xy, joiner_xy]);
+          translate(joiner_xy) {
+            circle(joiner_radius); } } } } } }
+
 module spin_slices(weight_radius,
                    weight_thickness,
                    bearing_radius,
@@ -221,6 +280,77 @@ module spin_slices(weight_radius,
                    r = weight_radius + 0.15,
                    center = true); } } } } }
 
+module spin_cosine(weight_radius,
+                   weight_thickness,
+                   bearing_radius,
+                   bearing_thickness,
+                   weight_lip_overhang = 0.3,
+                   bearing_lip_overhang = 0.3,
+                   wall = 3,
+                   arms = 3,
+                   layer_height = 0.15) {
+  thicker_thickness = (bearing_thickness > weight_thickness) ?
+    bearing_thickness : weight_thickness;
+  calculated_height = thicker_thickness + 2 * wall;
+  layers = 2 * ceil(ceil(calculated_height / layer_height) / 2);
+  actual_height = layers * layer_height;
+  round_radius = actual_height / 2;
+
+  /* rounding the outside edge of the spinner with a semi-circle leads
+     to a shape that an overhang on the second layer several times the
+     thickness of a printed extrusion width.
+
+     rather than using a full semi-circle, this code aims to use just the
+     portion in the middle, where the overhang is less severe */
+  old_start = 0;
+  old_end = (layers / 2) - 1;
+
+  /* add one to have some thickness all around weight holes
+     for first layer */
+  new_start = old_end / 16 + 1;
+  new_end = old_end;
+
+  old_range = old_end - old_start;
+  new_range = new_end - new_start;
+
+  factor = new_range / old_range;
+
+  /* initial adjacent is adjusted to (new start - 1) to allow some
+     thickness all around weight holes on first layer */
+  initial_adjacent = round_radius - ((new_start - 1) * layer_height);
+  initial_angle = acos(initial_adjacent / round_radius);
+  initial_round_extra = initial_adjacent * tan(initial_angle);
+
+  difference() {
+    mirrored([0, 0, 1]) {
+      for(layer = [0 : (layers / 2) - 1]) {
+        translate([0, 0, layer * layer_height - actual_height / 2]) {
+          linear_extrude(height = layer_height) {
+            new_layer = (layer - old_start) * factor + new_start;
+            adjacent = round_radius - (new_layer * layer_height);
+            angle = acos(adjacent / round_radius);
+            round_extra = adjacent * tan(angle) - initial_round_extra;
+            spin_cosine_slice(weight_radius,
+                              bearing_radius,
+                              round_extra,
+                              wall,
+                              arms); } } } }
+    cylinder(h = actual_height + 0.1,
+             r = bearing_radius - bearing_lip_overhang,
+             center = true);
+    cylinder(h = bearing_thickness + 0.05,
+             r = bearing_radius + 0.15,
+             center = true);
+    for(arm = [0 : arms - 1]) {
+      rotate(arm * (360 / arms)) {
+        translate([bearing_radius + wall + weight_radius, 0]) {
+          cylinder(h = actual_height + 0.1,
+                   r = weight_radius - weight_lip_overhang,
+                   center = true);
+          cylinder(h = weight_thickness + 0.05,
+                   r = weight_radius + 0.15,
+                   center = true); } } } } }
+
 module spin_donut(weight_radius,
                   weight_thickness,
                   bearing_radius,
index 37b74f00c6be7e9c75e9d8923ac63e08dea1ba25..d72e2dd0452a5311e0b19e27f6d42b14b938b8ec 100644 (file)
--- a/spin.scad
+++ b/spin.scad
@@ -2,9 +2,9 @@
    see bottom for more license info */
 
 /* spin thing that erin likes */
-include<spin-data.scad>
+include <spin-data.scad>
 
-object = "spin_slices";
+object = "spin_cosine";
 
 if (object == "spin_slices") {
   spin_slices(weight_radius,
@@ -25,6 +25,15 @@ else if (object == "spin_donut") {
              bearing_lip_overhang,
              wall,
              arms); }
+else if (object == "spin_cosine") {
+  spin_cosine(weight_radius,
+              weight_thickness,
+              bearing_radius,
+              bearing_thickness,
+              weight_lip_overhang,
+              bearing_lip_overhang,
+              wall,
+              arms); }
 else if (object == "cap") {
   cap(bearing_inner_radius,
       bearing_cap_footprint_radius,