// springs.scad: Rudolf Huttary 2018.12
//==============================================
// module 
// some usage examples: 
//  spring(); // spring with default values 
//  spring(R1=100, w = 20,  h=10); // rect spring
//  spring(R=100, w = 5,  h=10, pitch = 25); // rect cylinder spring with pitch
//  spring(w=10); // quadratic spring 
//  spring(windings=2.5, H=-30, center = false, start=true);   // negative height, partial windings allowed, ring at start added 
//  spring(windings=5.5, R=30, R1=100, ends=true); // conical spring
//  spring(r=15);  // emits warning, because of self intersection 
//  spring(H=0, R=100, R1=10); // flat spring
//  spring(H=0, R=70, R1=10, w=2, h=10); // flat rect spring
//  spring(H=0, R=100, R1=10, w=8, ends=true); // flat quadratic spring ccw with end rings
//  spring(H=0, R=10, R1=100, w=8); // flat quadratic spring cw
//  springmaker(r=3, R=20, R1=40, H=50, ends=true); 

help(); 

use <Naca_Sweep.scad> // for explanation refer to https://www.thingiverse.com/thing:900137

module help() help_spring();  
module help_spring()
{
  h = "<br>
  <b>Modules in spring.scad </b> (by Rudolf Huttary, Berlin 2018)<br>
  help(): shows this help<br>
  help_spring(): shows this help<br>
  module spring(r=5, R=40, windings=5, H=150, center = true, R1 = undef, start=false, end=false, ends=undef, w=undef, h=undef) construct a spring<br>
  module springmaker(r=5, R=40, windings=5, H=150, R1 = undef, start=false, end=false, ends=undef , w=undef, h=undef) construct a negative to roll a spring<br> 
  function spring(r=5, R=40, windings=5, H=150, R1=undef, w = undef, h = undef, reverse=false) // prepare data for sweep()<br> 
  <b>Examples</b><br>
  spring(); // spring with default values <br>
  spring(R1=100, w = 20,  h=10); // rect spring; // rect spring <br>
  spring(R=100, w = 5,  h=10, pitch = 25); // rect cylinder spring with pitch<br>
  spring(w=10); // quadratic spring <br>
  spring(windings=2.5, H=-30, center=false, start=true);   // negative height, partial windings allowed, ring at start added <br>
  spring(windings=5.5, R=30, R1=100, ends=true); // conical spring<br> 
  spring(r=15);  // emits warning, because of self intersection <br>
  spring(H=0, R=100, R1=10); // flat spring<br>
  spring(H=0, R=100, R1=10, w=8); // flat quadratic spring ccw<br>
  spring(H=0, R=10, R1=100, w=8); // flat quadratic spring cw<br>
  springmaker(r=3, R=20, R1=40, H=50, ends=true); // device to produce a spring<br> 
  "; 
  echo(str(h)); 
}

module springmaker(r=5, R=40, windings=5, H=150, R1 = undef, start=false, end=false, ends=undef, w = undef, h=undef, reverse = false)
{
  R1 = R1?R1:R; 
  h = h?h:w; 
  dh = w?4*h:4*r; 
  dR = cos(atan(H/(R1-R)))*dh/2; 
  R_ = R<R1?R-dR:R+dR; 
  R1_ = R<R1?R1+dR:R1-dR; 
  difference()
  {
    cylinder(r2 = R_, r1 = R1_, h=H+dh); 
    translate([0,0,dh/2])spring(r, R, windings, H, false, R1, start, end, ends, w, h); 
  }
}

module spring(r=5, R=40, windings=5, H=150, center = true, R1 = undef, start=false, end=false, ends=undef, w = undef, h=undef, reverse=false, pitch = 0)
{
  N = $fn?$fn:180/$fa; 
  M_ = ceil(N*windings*R/r); // slices
  h = h?h:2*r; 
  R1 = R1?R1:R; 
  slope = atan(H/windings/2/R/PI);
  dist = norm([R1-R, H]/windings)/2;  
  if(w && abs(R1-R)/windings<=w && abs(H/windings)<=h)  
    echo(str("<font color=\"red\">Warning: Self intersection. F6 will have no valid result!</font>"));  
  if(!w && dist<=r) 
    echo(str("<font color=\"red\">Warning: Self intersection. F6 will have no valid result! r &lt; ", dist, " expected</font>"));  
  translate([0, 0, center?-H/2:0])
  {
    tr = spring(r, R, windings, H, R1, w, h, reverse, pitch); 
    sweep(tr);   
    if (ends||start) sweep(ends(R1,0, w, h), close = true);   
    if (ends || end) sweep(ends(R,H, w, h), close = true);   
  }
  
  function ends(R, H, w, h) = let(m = M_/windings)
  let(shape = w&&h?rect(w,h):spring_circle2D(r, N))
  [for (i=[0:m-1]) let(W = -360/m*i)
    T_(0,0,H,
      Rz_(W,
      Tx_(R,
        Rx_(slope-90,
          vec3D(shape)))))];

  
  function trajectory(R, R1, windings, H, w = undef, h = undef) =  // prepare data for sweep()
  let(f=reverse?-1:1)
  let(shape = w&&h?spring_rect(w,h):spring_circle2D(r, N))
  [for (i=[0:M_]) let(W = 360*windings/M_*i)
    let(R2 = R1+i/M_*(R-R1))
    Rz_(f*W,
      T_(R2, 0, H/M_*i,
        Rx_((slope-90)*f,
          vec3D(shape))))];
}

function spring(r=5, R=40, windings=5, H=150, R1=undef, w = undef, h = undef, reverse=false, pitch = 0) =  // prepare data for sweep()
  let(N = $fn?$fn:180/$fa) 
  let(M = ceil(N*windings*R/r)) // slices
  let(f=reverse?-1:1, h = h?h:2*r, R1 = R1?R1:R)
  let(slope = atan(H/windings/2/R/PI))
  let(shape = w&&h?spring_rect(w,h):spring_circle2D(r, N))
  [for (i=[0:M]) let(W = 360*windings/M*i)
    let(R2 = R1+i/M*(R-R1))
    Rz_(f*W,
      T_(R2, 0, H/M*i,
        Rx_((slope-90)*f,
          Rz_(pitch, vec3D(shape)))))];

  function spring_circle2D(r=10, N=40) =  // polygon for cross section
  [for (i=[0:N]) let(w = 360/N*i) r*[sin(w), cos(w)]];
    
  function spring_rect(a,b) = [[a/2, b/2], [-a/2, b/2],[-a/2, -b/2], [a/2, -b/2]];    



diam_cable=1.3;
diam_ressort_exterieur=12;
pas_ressort_detendu_exterieur=5.7;
hauteur_ressort_exterieur=43.4; 
nb_spires=9.5;
  
 ////////////////////////
  module ressort(){
    spring(r=0.3+diam_cable/2, R=(diam_ressort_exterieur-diam_cable)/2, windings=9.5, H=hauteur_ressort_exterieur-diam_cable, center = true, R1 = undef, start=false, end=false, ends=undef, w=undef, h=undef);
      }
  ////////////////////////
  module fixation_ressort(){
  difference(){
  cube([18,18,10],center=true);
      cylinder(d=diam_ressort_exterieur-diam_cable,h=hauteur_ressort_exterieur,center=true,$fn=60);
     ressort();
      //trou pour fixation  
      rotate([90,0,0])
        #cylinder(d=2,h=30,center=true);
      }      
  }
  
  ////////////////////////
//cylindre pour vérifier:
//cylinder(d=diam_ressort_exterieur,h=hauteur_ressort_exterieur,center=true,$fn=60);
//ressort
 //spring(r=diam_cable/2, R=(diam_ressort_exterieur-diam_cable)/2, windings=9.5, H=hauteur_ressort_exterieur-diam_cable, center = true, R1 = undef, start=false, end=false, ends=undef, w=undef, h=undef);
  
  //fixation_ressort();
  //////////////////////////////////
  module bouchon_evian(){
    diam=31.5; //diamètre du bouchon sans les dents
    haut_bouchon=11;
    epaisseur_dents=0.3;
    union(){
        //les bords du bouchon sont évasés 
        translate([0,0,2-0.1])
            cylinder(h=haut_bouchon-2,d=diam,$fn=180);
        //évasé au début pour centrer
        translate([0,0,2-0.1])
        rotate([180,0,0])
           cylinder(h=2,d1=diam,d2=diam-3,$fn=180);        
        nbdents=72;//72 dents sur le bouchon à creuser
        for (i=[0:nbdents]){ 
            rotate([0,0,i*360/nbdents])
                translate([diam/2,0,2]) 
                    cylinder(h=haut_bouchon-2,d=epaisseur_dents*2,$fn=10);  
        }    
    }}
  //////////////////////////////////
    //      bouchon_evian();
  
  
  //#cylinder(h=10.1,d1=31.8,d2=31.8,$fn=180);
    //////////////////////////////////
   module fixation_bouchon_evian(){
      bouchon_evian();
  translate([0,0,11+8.99])
  rotate([90,0,0])
  rotate([0,0,90])
  fixation_ressort();
   }
     ////////////////////////////////// 
   module criterium(){
       cylinder(d=8,h=150,$fn=6);
       translate([0,0,150-0.01])
       cylinder(d1=8,d2=0,h=30,$fn=6);
   }
        ////////////////////////////////// 
   module assemblage(){
       fixation_bouchon_evian();  
     translate([0,40,11+8.99])
  rotate([90,0,0])
  rotate([0,0,90])
   {
   fixation_ressort();
   translate([0,0,20])
       ressort();
translate([0,0,-30])       
   criterium();
   }
   }
         ////////////////////////////////// 
    assemblage(); 
  // fixation_ressort();