/*
"OpenScad library. Threads for screws and nuts V1" 
by ANDRES ROMAN (AKA Cuiso) September 2018

-> V1.2 30/03/2021 Change Log:
- Since OpenScad version 2021.01 version 1.1 of this library stopped with error. 
The necessary modifications have been made in this version 1.2 
so that it also works with OpenScad 2021.01.
- Due to these necessary modifications, unfortunately now the preview 
time has increased slightly. 
- Remember that if necessary you can increase the speed for previewing and 
rendering using the functions with full parameters and specifying a 
smaller number of the "divs" parameter.
If you prefer, you can also improve the speed at a 
general level by changing the variable "stddivs" 
located on line 167, increasing this variable increases the 
preview and rendering time (and increases the resolution), 
decreasing the value of this variable decreases the time 
preview and the resolution is lowered. 
The default value of 50 is generally adequate and in 
most cases you don't need to worry about this unless 
your computer is really slow, or you want to get really large diameter threads.
This version continues to be compatible with OpenScad versions prior to 2021.01.
- Some warnings that did not affect operation have been removed.
- Some "echo" that did not affect operation have been removed. 
- This version is completely compatible with your projects made 
with previous versions, the name of the library "threads-library-by-cuiso-v1.scad" 
has been kept so you do not have to change anything in your source code, you only 
have to replace the old file "threads-library-by-cuiso-v1.scad" by the new 
"threads-library-by-cuiso-v1.scad" and you are ready to work with OpenScad 2021.01.
- Happy designing !!!

-> V1.1 23/08/2019 Change Log:
-Fixed bug. Using fullparms functions with "divs" no divider of 360 (200 for example) the thread could be incomplete. Now you can use any number of "divs" without problem.
-A small improvement. Now the diameter reductions at the beginning of the screw for easy entry are created with the same level of detail as the rest of the screw.

* Copyright 2018 ANDRES ROMAN (AKA Cuiso)
* Licensed under the Creative Commons - Attribution license.
* This software is free software, you can Share and Adapt under the terms of Attribution
(give appropriate credit).
*   
* you can visit https://creativecommons.org/licenses/by/3.0/ for more details

* This software is distributed WITHOUT ANY WARRANTY.

*/

//For use this library you can put the file threads-library-by-cuiso-v1.scad in the same directory of your proyect and put the line use <threads-library-by-cuiso-v1.scad> in your own .scad file
//You can see examples of use in file examples.scad

/*
This is a library to include threads for screws and nuts in your own designs.

This library is focused to provide simple functions with preset parameters by default,
and not to be too demanding in CPU consumption neither in previsualizacion nor in rendering

This library has been tested printing on PLA with 0.1 layer. Except for smaller diameter
threads layers greater than 0.1 should work well.
Diamaters tested between 3mm and 10mm, but you can use any diameter of your choice. 

Shape of the threads are similar (but not equal) to ISO METRIC threads.
Some tests have been done using screws and nuts printed with this library in
combination with screws and nuts of metal with acceptable results. However, they have
not been exhaustive tests.
*/

/*
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
AVAILABLE FUNCTIONS:

BASIC FUNCTIONS (USING PREDEFINED PARAMETERS):

thread_for_screw(diameter, length);
    Generates a screw thread of the diameter indicated by the "diameter" parameter and of the length indicated by "length". This function uses standard pitch values depending on the diameter specified.
    diameter: Free value, in milimeters.
    length: Free value, in milimeters.
    
    Example:
    thread_for_screw(diameter=10, length=30);

thread_for_nut(diameter, length, usrclearance=0);
    Generates a nut thread of the diameter indicated by the "diameter" parameter and of the length indicated by "length". This function uses standard pitch values depending on the diameter specified.
    The generated thread can be subtracted from any element of your design using the operator "difference()", thus obtaining a thread where a screw will fit.
    This function uses standard clearance for adjustment between screw and nut depending on the diameter specified.
    diameter: Free value, in milimeters.
    length: Free value, in milimeters.
    usrclearance: (optional) If the screw fits too tight on the nut you can specify a positive correction value (try 0.1 for example).
    If the screw fits too loose in the nut you can specify a negative correction value (try -0.1 for example).
    
    Example:
    thread_for_nut(diameter=10, length=20);
    

MORE AVAILABLE FUNCTIONS (WITH ADDITIONAL PARAMETERS):

thread_for_screw_fullparm(diameter, length, pitch, divs=50);
    Generates a screw thread of the diameter indicated by the "diameter" parameter and of the length indicated by "length", with pitch indicated by "pitch", and a resolution indicated by "divs". 
    This function allows you to specify a non-standard "pitch" value.
    diameter: Free value, in milimeters.
    length: Free value, in milimeters.
    pitch: Pitch value.
    divs: (optional) you can obtain more or less resolution with parm. Higher values for more resolution (and more rendering time). Default value is 50.
        
    Example:
    thread_for_screw_fullparm(diameter=10, length=30, pitch=2, divs=60);

thread_for_nut_fullparm(diameter, length, usrclearance=0, pitch, divs=50, entry=1);
    Generates a nut thread with additional parameters:
    diameter: Free value, in milimeters.
    length: Free value, in milimeters.
    usrclearance: (optional) If the screw fits too tight on the nut you can specify a positive correction value (try 0.1 for example).
    If the screw fits too loose in the nut you can specify a negative correction value (try -0.1 for example).
    pitch: Pitch value.
    divs: (optional) you can obtain more or less resolution with parm. Higher values for more resolution (and more rendering time). Default value is 50.
    entry: By default, the nut threads include a wider entrance area at the beginning and end to facilitate the introduction of the screw and minimize "elephant foot" problems.
    Specify 1 in entry to use these zones and 0 to not use them.
    
    Example:
    thread_for_nut_fullparm(diameter=10,length=20,usrclearance=0.1,pitch=1.5,divs=60, entry=1);
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
*/   

/*
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
SOME NOTES:
- At first preview(F5) of the design may appear in console a lot of messages:
"PolySet has nonplanar faces. Attempting alternate construction"
simply ignore those messages, they are not a problem.
In versión 1.2 these messages no longer appear.

- I have no lag problems in preview(F5) mode during the test of this library. If you are suffering lag problems in preview you can try to un-comment the "render()" al lines 286 and 293.
  You can also try decreasing the value of the stddivs variable on line 169 (50 is the default value).

- This library uses by default PITCH values: 
  DIAMETER    PITCH_VALUE
  3mm        0.5mm
  4mm        0.7mm
  5mm        0.8mm
  6mm        1.0mm
  8mm        1.25mm
 10mm        1.5mm
 ...
 24mm        3.0mm
 (complete list defined at get_std_pitch(diam))
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
*/


//EXAMPLE FOR CUSTOMIZER:
//1 to draw rod, 0 to not draw rod
drawrod=1; 
//1 to draw nut, 0 to not draw nut
drawnut=1;
diameter=8; 
lengthrod=15; 
lengthnut=7; 
//Example of USE, a rod SCREW:
if(drawrod==1)thread_for_screw(diameter=diameter, length=lengthrod);
//Example of USE, a FEMALE THREAD to be removed (with difference ()) from another figure:
if(drawnut==1)
translate([diameter,1.5*diameter,0]){
thread_for_nut(diameter=diameter, length=lengthnut);
}




//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
stddivs=50;

module thread_for_screw(diameter, length)
{
stdpitch=get_std_pitch(diameter);
thread_for_screw_cuiso_tec(diameter,length,stdpitch,divdelta=stddivs);
//echo(diameter);echo(stdpitch);
}

module thread_for_nut(diameter, length, usrclearance=0)
{
stdpitch=get_std_pitch(diameter);
stdclearance=get_std_clearance(diameter);

thread_for_nut_cuiso_tec
(diameter+stdclearance+usrclearance,length,stdpitch,divdelta=stddivs,entry=1);
    
//echo(diameter);echo(stdpitch);echo(stdclearance+usrclearance);
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
module thread_for_screw_fullparm(diameter, length, pitch, divs=50)
{
if(divs<20) thread_for_screw_cuiso_tec(diameter,length,pitch,20);
    else if(divs>360) thread_for_screw_cuiso_tec(diameter,length,pitch,360);
        else thread_for_screw_cuiso_tec(diameter,length,pitch,divs);
}

module thread_for_nut_fullparm(diameter, length, usrclearance=0, pitch, divs=50, entry=1)
{
stdclearance=get_std_clearance(diameter);

if(divs<20)thread_for_nut_cuiso_tec
(diameter+stdclearance+usrclearance,length,pitch,20,entry=entry);
else
if(divs>360)thread_for_nut_cuiso_tec
(diameter+stdclearance+usrclearance,length,pitch,360,entry=entry);
else
thread_for_nut_cuiso_tec
(diameter+stdclearance+usrclearance,length,pitch,divs,entry=entry);
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
function get_std_pitch(diam) = 
lookup(diam,[[3,0.5],[4,0.7],[5,0.8],[6,1.0],[8,1.25],[10,1.5],
[12,1.75],[14,2.0],[16,2.0],[18,2.5],[20,2.5],[22,2.5],[24,3.0]
]);

function get_std_clearance(diam) = 
lookup(diam,[[3,0.4],[4,0.4],[5,0.5],[6,0.6],[8,0.6],[10,0.6],
[12,0.7],[14,0.7],[16,0.7],[18,0.7],[20,0.8],[22,0.8],[24,0.8]
]);
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
module thread_for_screw_cuiso_tec(diameter,lenght,pitch,divdelta){
delta=360/divdelta;
intersection(){
cubointter(long=lenght,pitch=pitch,diameter=diameter,divdeltacube=divdelta);
rosca(long=lenght,p=pitch,delta=delta,diameter=diameter);
}
//#cylinder(d=diameter,h=lenght,$fn=100);
}

module thread_for_nut_cuiso_tec(diameter,lenght,pitch,divdelta,entry){
delta=360/divdelta;
translate([0,0,-0.001])
intersection(){
rosca(long=lenght+0.002,p=pitch,delta=delta,diameter=diameter,nut=1);
cubointter_nut(lenght+0.002,pitch,diameter);
}
if(entry==1){translate([0,0,-0.001])cubointter_nut_entry(lenght+0.002,pitch,diameter,divdeltacube=divdelta);}
//#cylinder(d=diameter,h=lenght,$fn=100);
}

module cubointter(long,pitch,diameter,divdeltacube)
{
longcube=long-pitch;
translate([0,0,longcube/2+pitch/2])cube([diameter,diameter,longcube],center=true);
translate([0,0,longcube+pitch/2])
cylinder(d1=diameter,d2=diameter-2*pitch*0.866,h=pitch/2, $fn=divdeltacube);
cylinder(d2=diameter,d1=diameter-2*pitch*0.866,h=pitch/2, $fn=divdeltacube);
}

module cubointter_nut(long,pitch,diameter)
{
longcube=long;
translate([0,0,longcube/2])cube([diameter,diameter,longcube],center=true);
}

module cubointter_nut_entry(long,pitch,diameter,divdeltacube)
{
longcube=long-0.6;
translate([0,0,longcube])
cylinder(d2=diameter+0.4,d1=diameter,h=0.6, $fn=divdeltacube);
cylinder(d1=diameter+0.4,d2=diameter,h=0.6, $fn=divdeltacube);
}

module rosca(long,p,delta,diameter,nut=0)
{
vueltas=round(long/p+0.5)+1;
translate([0,0,-p/4])
for(v = [0 : 1 : vueltas-1])
translate([0,0,v*p])
vuelta(p=p,delta=delta,diameter=diameter,nut=nut);
}

module vuelta(p,delta,diameter,nut)
{
medio(p=p,delta=delta,diameter=diameter,nut=nut);

translate([0,0.001,0])
rotate([0,180,180])
medio(p=p,delta=delta,diameter=diameter,nut=nut);
}

module medio(p,delta,diameter,nut)
{
if(nut==1)
//render()
hull(){
for(k = [0 : delta : 180])
translate([0,0,k*p/360])rotate([0,0,k])pieza_nut(diameter=diameter, p=p);
translate([0,0,180*p/360])rotate([0,0,180])pieza_nut(diameter=diameter, p=p);
}
else
//render()
hull(){
for(k = [0 : delta : 180])
translate([0,0,k*p/360])rotate([0,0,k])pieza(diameter=diameter, p=p);
translate([0,0,180*p/360])rotate([0,0,180])pieza(diameter=diameter, p=p);
}
}

module pieza(diameter, p)
{
r=diameter/2;
h=p*0.866;
pp=p/2;
pm=-p/2;
hh=r-h;
g=0.001;

rotate([90,0,0])
linear_extrude(height = g, center = true, convexity = 10){
polygon([
    [0,pp],[hh,pp],[r-h/8,p/16],[r-h/8,-p/16],[hh,pm],[0,pm]
    ], 
    [
    [0,1,2,3,4,5]
    ]);
}
}

module pieza_nut(diameter, p)
{
r=diameter/2;
h=p*0.866;
pp=p/2;
pm=-p/2;
hh=r-h;
g=0.001;
    
rotate([90,0,0])
linear_extrude(height = g, center = true, convexity = 10){
polygon([
    [0,pp],[hh,pp],[r,0],[hh,pm],[0,pm]
    ], 
    [
    [0,1,2,3,4]
    ]);
}
}