Wednesday, May 31, 2017

Find a point some partial length along a poly-line

len3v sum's up total length if a poly-line
v2t returns a point
 some partial length along the poly-line.
Far_Along is a 0-1 multiplier to regularize the expression with other code
Usage:



My_poly_line=make_points(6);
LengthOfIt=(len3v(My_poly_line));
Far_Along=rnd(1);
My_Point_Exactly=v2t(My_poly_line,LengthOfIt*Far_Along);
echo( str(round(Far_Along*100),"% "),My_Point_Exactly);
polyline(My_poly_line);
translate(My_Point_Exactly)color("gold")sphere(3);
translate(My_poly_line[0])color("red")sphere(2);
translate(My_poly_line[len(My_poly_line)-1])color("blue")sphere(2);

module line(p1, p2 ,width=0.1) { hull() {        
translate(p1) sphere(width);
translate(p2) sphere(width);    }}

module polyline(p) {for(i=[0:max(0,len(p)-2)])line(p[i],p[i+1]);}

function un(v)=v/max(1e-15,norm(v));
function len3v(v,acc=0,p=0)=p+1>len(v)-1?
        acc: len3v(v,acc+norm(v[p]-v[p+1]),p+1)  ;
function v2t(v,stop,p=0)=p+1>len(v)-1|| norm(v[p]-v[p+1])>stop?  
 v[p]+un(v[p+1]-v[p])*stop:v2t(v,stop-norm(v[p]-v[p+1]),p+1);
function make_points(j=10,l1=[-30,-30,-30],l2=[30,30,30])= 
     ([for(i=[1:j])[
rnd(l1.x,l2.x)/10+i*10,//linear spagetti
rnd(l1.y,l2.y),
rnd(l1.z,l2.z)]]);
function rnd(a = 1, b = 0, s = []) = 
  s == [] ? 
   (rands(min(a, b), max(   a, b), 1)[0]) 
  : 
   (rands(min(a, b), max(a, b), 1, s)[0])
  ; 

module line(p1, p2 ,width=0.1) { hull() {        
translate(p1) sphere(width);
translate(p2) sphere(width);    }}

module polyline(p) {for(i=[0:max(0,len(p)-2)])line(p[i],p[i+1]);}


 

Map Cartesian coordinates to and from Hilbert curve

Curve  in range 0-1 is mapped to   Cartesian coordinates [0,0]-[1,1]

Usage:



p=[rnd(),rnd()];
translate(p)sphere(0.05);
n=cartesian_to_curve(p);
 echo("point:",p,"on curve:",n);

step=0.003/3/3;
for(i=[0:step :1-step]){
t1=curve_to_cartesian(i);t2=curve_to_cartesian(i+step); 
color([i,sin(i*5000)*0.5+0.5,1-i]) 
hull(){translate (t1) sphere(0.005);translate (t2) sphere(0.005); }}
translate ([-0.1,-0.1])scale(0.01)text("0");
translate ([1,-0.1])scale(0.01)text("1");
 
function curve_to_cartesian
(i,order=4,a=[0,0],b=[0,1],c=[1,1],d=[1,0],s=0,e=1)=let(
p1=lerp(s,e,1/4),p2=lerp(s,e,2/4),p3=lerp(s,e,3/4),
ab=(a+b)/2,bc=(b+c)/2,cd=(c+d)/2,da=(d+a)/2,
center=(a+b+c+d)/4     )
!order>0?let(
a2=lerp(a,center,0.5),b2=lerp(b,center,0.5),
c2=lerp(c,center,0.5),d2=lerp(d,center,0.5))
along([a2,b2,c2,d2],(i-s)/max(1e-16,abs(e-s)))
: i<p1?    curve_to_cartesian(i,order-1,a,da,center,ab,s,p1):
i>p1&&i<p2?curve_to_cartesian(i,order-1,ab,b,bc,center,p1,p2):
i>p2&&i<p3?curve_to_cartesian(i,order-1,center,bc,c,cd,p2,p3):
           curve_to_cartesian(i,order-1,cd,center,da,d,p3,e);

function cartesian_to_curve
(i,order=28,a=[0,0],b=[0,1],c=[1,1],d=[1,0],s=0,e=1)=let(
p1=lerp(s,e,1/4),p2=lerp(s,e,2/4),p3=lerp(s,e,3/4),
ab=(a+b)/2,bc=(b+c)/2,cd=(c+d)/2,da=(d+a)/2,
center=(a+b+c+d)/4   )
!order>0? s : 
inbox(i,a,da,center,ab)==true?cartesian_to_curve(i,order-1,a,da,center,ab,s,p1):
inbox(i,ab,b,bc,center )==true?cartesian_to_curve(i,order-1,ab,b,bc,center,p1,p2):
inbox(i,center,bc,c,cd)==true?cartesian_to_curve(i,order-1,center,bc,c,cd,p2,p3):
           cartesian_to_curve(i,order-1,cd,center,da,d,p3,e);

function lerp(start, end, bias) = (end * bias + start * (1 - bias));
function len3v(v,acc=0,p=0)=p+1>len(v)-1?acc:len3v(v,acc+norm(v[p]-v[p+1]),p+1)  ;
function un(v)=v/max(1e-15,norm(v));
function along(v,i)=let(r=v2t(v,len3v(v)*i))[r.x,r.y,r.z];
function inbox (i,a,b,c,d)= 
i.x==max(i.x,a.x,b.x,c.x,d.x)||i.x==min(i.x,a.x,b.x,c.x,d.x)||
i.y==max(i.y,a.y,b.y,c.y,d.y)||i.y==min(i.y,a.y,b.y,c.y,d.y)? false:true;
function v2t(v,stop,p=0)=p+1>len(v)-1|| norm(v[p]-v[p+1])>stop?   v[p]+un(v[p+1]-v[p])*stop:  v2t(v,stop-norm(v[p]-v[p+1]),p+1);
function rnd(a = 1, b = 0, s = []) =
s == [] ?
  (rands(min(a, b), max(
    a, b), 1)[0]) :
  (rands(min(a, b), max(a, b), 1, s)[0]);
 

Min & Max for Vertices

Find extremes in a set of [x,y,z] points
Usage:



p= [
[5,5,7],[3,9,8],[7,6,6],[4,8,6],[1,5,3],
[8,8,10],[4,4,6],[5,8,2],[5,9,2],[5,2,4],
[9,4,8],[10,3,8],[0,1,7],[5,8,7],[7,3,7],
[3,9,6],[7,1,8],[8,6,4],[0,5,8],[3,1,4]];

echo("min/max point of x",p[minX(p)],p[IofmaxX(p)]);
echo("min/max point of y",p[IofminY(p)],p[IofmaxY(p)]);
echo("min/max point of z",p[IofminZ(p)],p[IofmaxZ(p)]);

echo("min/max of x", minX(p) , maxX(p) );
echo("min/max of y",  minY(p) , maxY(p) );
echo("min/max of z",  minZ(p) , maxZ(p) );

/* Iof :index_of_...    */
function IofminX(p)=let(m=min([for(i=p)i.x]))search(m,p,0, 0)[0];
function IofmaxX(p)=let(m=max([for(i=p)i.x]))search(m,p,0, 0)[0];
function IofminY(p)=let(m=min([for(i=p)i.y]))search(m,p,0, 1)[0];
function IofmaxY(p)=let(m=max([for(i=p)i.y]))search(m,p,0, 1)[0];
function IofminZ(p)=let(m=min([for(i=p)i.z]))search(m,p,0, 2)[0];
function IofmaxZ(p)=let(m=max([for(i=p)i.z]))search(m,p,0, 2)[0];

function minX(p)=min([for(i=p)i.x]);
function maxX(p)=max([for(i=p)i.x]);
function minY(p)=min([for(i=p)i.y]);
function maxY(p)=max([for(i=p)i.y]);
function minZ(p)=min([for(i=p)i.z]);
function maxZ(p)=max([for(i=p)i.z]); 



Clustering k-means

K-means clustering is a type of unsupervised learning. The algorithm works iteratively to assign each point to the closest of K groups. Each groups centroid is updated as the mean of its assigned points and groups converge. Function returns a list of means and a list of  points sorted in sublists for each group.
Usage:

 
p=make_points(75);
K=Kmeans(p,round(rnd(1,20)),round(rnd(1,10)));
for(i=[0:len(p)-1])translate(p[i])sphere(0.5);  
for(i=[0: max(0,len(K[0])-1)])
    translate(K[0][i])color("Red",0.5)sphere(2,$fn=20);
for(i=[0: max(0,len(K[1])-1)]){
    color([rnd(),rnd(),rnd()] ,0.5)hull(){
    for(j=[0: max(0,len(K[1][i])-1)])translate(K[1][i][j])sphere( 3,$fn=1 );}}

function Kmeans(v,K,c=5,inmeans=undef) =  len(v) < K ? [v,v] :
let(
maxlenv= max(0,len(v)-1),maxK=max(0,K-1),
means=inmeans==undef? /* Initailize means if not done */ [for(i=[0:maxlenv])
        (v[rnd(maxlenv)]+v[rnd(maxlenv)]+v[rnd(maxlenv)])/3]:inmeans, 
vbuckets=[for(i=[0:maxlenv])index_min([for(k=[0:maxK])norm(v[i]-means[k])])],
new_means=[for(k=[0:maxK]) mean([for(i=[0:maxlenv]) if(vbuckets[i]==k)v[i]])]   )
c>0? Kmeans(v,K,c-1,new_means):
let(inbuckets=[for(k=[0:maxK])[for(i=[0:maxlenv]) if(vbuckets[i]==k)v[i]] ])
[new_means,inbuckets] ;


function index_min(l) = search(min(l), l)[0];
function index_max(l) = search(max(l), l)[0];
function mean(a) = !(len(a) > 0)?undef:([ for(b=a) 1 ] * a )/len(a);
function make_points(j=10)= 
     ([for(i=[0:j])[rnd(-30,30),rnd(-20,20),rnd(-10,10)]]);
function rnd(a = 1, b = 0, s = [] ) = 
  s == [] ? 
   (rands(min(a, b), max(   a, b), 1)[0]) 
  : 
   (rands(min(a, b), max(a, b), 1, s)[0])
  ; 

 

Tuesday, May 30, 2017

LookAt function and module

Rotate an object towards a waypoint.
Uses angle+vector format of openSCADs native rotate operand.

Usage:

Lookatpoint=[rnd(-20,20),rnd(-20,20),rnd(-20,20)];
Origin=[rnd(-20,20),rnd(-20,20),rnd(-20,20)];
translate(Lookatpoint)color("red")sphere(2);
translate(Origin)color("blue")sphere(2);
translate(Origin)look_at(Lookatpoint ,Origin ){
translate([0,0,5])cylinder(7,2,0);
translate([0,0,-3])cylinder(9,1,1);
}
module look_at(lookpoint,origin=[0,0,0],rotatefrom=[0,0,1]){
rotations=look_at(lookpoint,origin ,rotatefrom);
rotate(rotations[0],rotations[1]) children();
}

function look_at(p,o=[0,0,0],up=[0,0,1])=
let(
a=up,
b=p-o,
c=cross(a,b) ,
d=angle(a,b))
[d,c];

function angle (a,b)=
atan2(
sqrt((cross(a, b)*cross(a, b))), 
(a* b)
);


function rnd(a = 1, b = 0, s = []) =
s == [] ?
  (rands(min(a, b), max(
    a, b), 1)[0]) :
  (rands(min(a, b), max(a, b), 1, s)[0]);



 

Angle between two vectors in 3D

Angle between two vectors in 3D
Usage:

a=[10,0,0];
b=[0,10,0];
echo(angle(a,b));
function angle (a,b)=atan2(norm(cross(a,b)),a*b);

 

Monday, May 29, 2017

Incircle of a triangle in 3d


Incircle / inscribed circle of a triangle is the largest circle that fits inside a triangle and touches all three sides. 
Usage:


$fn = 50;
point_C = [rnd(-20, 20), rnd(-20, 20), rnd(-20, 20)];
point_B = [rnd(-20, 20), rnd(-20, 20), rnd(-20, 20)];
point_A = [rnd(-20, 20), rnd(-20, 20), rnd(-20, 20)];
center = Incenter(point_A, point_B, point_C);
inradius= point_to_line(center,point_A, point_B);
hull(){translate(point_A) sphere(0.1);
translate(point_B) sphere(0.1);
translate(point_C) sphere(0.1);}
color("red") translate(center) sphere(inradius);
echo(center, inradius);

function Incenter(A, B, C) =
let (
a=norm(B-C),
b=norm(A-C),
c=norm(A-B),
  p = a + b + c, 
  Ox = (a * A.x + b * B.x + c * C.x) / p, 
  Oy = (a * A.y + b * B.y + c * C.y) / p,
  Oz = (a * A.z + b * B.z + c * C.z) / p
    )
[Ox, Oy, Oz];

function point_to_line(p,a,b)=
let(
pa = p - a, 
ba = b - a,
h = clamp( (pa*ba)/ (ba*ba)))
norm( pa - ba*h ) ;
function clamp(a, b = 0, c = 1) = min(max(a, b), c); 

 
function rnd(a = 1, b = 0, s = []) =
s == [] ?
  (rands(min(a, b), max(
    a, b), 1)[0]) :
  (rands(min(a, b), max(a, b), 1, s)[0]);

 
 

Friday, May 26, 2017

Rows to columns transposition

Rows to columns transposition.
Works best with even length lists.

In other case, columns will be padded with undefined.
Usage:

rows = [[40, 16, 54, 36, 36, 42, 67, 17, 40] ,
        [76, 20, 60, 51, 58, 73, 11, 17, 48] ,
        [50, 72, 11, 57,  3, 94, 33, 93, 13] ];
cols=rows_to_columns(rows);
echo ( rows);echo (  cols);

function rows_to_columns(l)= 
let(longest_list=max( [for(i=[0:len(l)-1])len(l[i])-1]))
[for( i=[0:longest_list])[for( j=[0:len(l)-1]) l[j][i]]];
 

Thursday, May 25, 2017

Euclidean distance between a point and a line segment

Function to find the shortest distance between a point and a line segment
Usage:


echo(point_to_line(   [150,50,0],   [0,0,0],   [100,0,0]  ));

function point_to_line(p,a,b)=
let(
pa = p - a, 
ba = b - a,
h = clamp( (pa*ba)/ (ba*ba)))
norm( pa - ba*h ) ;
function clamp(a, b = 0, c = 1) = min(max(a, b), c); 

Wednesday, May 24, 2017

Deleting multiple elements of a list by index

Deleting multiple elements of a list,
Filter a list by list of index, either keep or remove  elements.
Selection may well be the result of search(My_search_term,List)
or something else.


Usage:



List=[12,3,4,5,6,7,8,90,1 ]; Selection=[0,3,4,5]; 

echo(" List :",List);
echo(" Indices of elements to remove :",Selection);
/*Indexes and indices are both accepted and 
widely used plurals of the noun index. */
echo(" List after removal :",split_keepers(List,Selection));
echo(" List of removed elements :", split_removed(List,Selection));

 
function split_keepers(List,Selection)=
        [for(i=[0:max(0,len(List)-1)]) if(search(i,Selection)==[])List[i]];
function split_removed(List,Selection)=
        [for(i=[0:max(0,len(List)-1)]) if(search(i,Selection)!=[])List[i]]; 


Tuesday, May 23, 2017

Round to next Power of 2

Calculate the next power of two higher than or equal to a given number
Usage:


for (i = [0: 100])
  echo(i, ":", next_pow2(i));

function next_pow2(x) = pow(2, ceil(log(x)/log(2))); 

Monday, May 22, 2017

Test if a number is a Fibonacci number

Test if a number is in the list of Fibonacci numbers.
The function is_fibonacci returns a vector [true/false,place],
Usage: 



for (i = [0: 100])
  echo(i, ":", is_fibonacci(i));


function is_fibonacci(N) =
let (
  i = floor(log(N * sqrt(5)) / log((1 + sqrt(5)) / 2) + 0.5),
  n = floor(pow((1 + sqrt(5)) / 2, i) / sqrt(5) + 0.5),
  place = (n == N) ? i : -1)
[(n == N), place];
 

Sunday, May 21, 2017

Euclid's algorithm for finding the Greatest Common Divisor and Least Common Multiple

Euclid's algorithm for finding the Greatest Common Divisor of two numbers.
And its partner the Least Common Multiple
Usage:


echo(gcd(90,15));
echo(lcm(5,4));

function gcd(a,b)=
 a<=0||b<=0?min(sign(a),sign(b)):
   a % b==0?b:
   gcd(b,a % b);

function lcm(a,b)= a * (b / gcd(a, b));

 

Wednesday, May 17, 2017

Circle defined by three points (2d)

Finding the Center of a Circle from Three Points.
Points must not be equal or collinear, - lie on a single straight line 

Usage:


$fn = 20;
point_C = [rnd(-20, -5), rnd(5, 20)];
point_B = [rnd(5, 20), rnd(5, 20)];
point_A = [rnd(5, 20), rnd(-20, -5)];
center = circle_by_three_points(point_A, point_B, point_C);
radius = len3(point_C - center);
translate(point_A) circle(2);
translate(point_B) circle(2);
translate(point_C) circle(2);
color("red") translate(center) circle(radius);
echo(center, radius);


function circle_by_three_points(A, B, C) =
let (
  yD_b = C.y - B.y,  xD_b = C.x - B.x,  yD_a = B.y - A.y,
  xD_a = B.x - A.x,  aS = yD_a / xD_a,  bS = yD_b / xD_b,
  cex = (aS * bS * (A.y - C.y) + 
  bS * (A.x + B.x) -    aS * (B.x + C.x)) / (2 * (bS - aS)),
  cey = -1 * (cex - (A.x + B.x) / 2) / aS + (A.y + B.y) / 2
)
[cex, cey];

// non dependencies helper function for demo

function rnd(a = 1, b = 0, s = []) =s == [] ?
  (rands(min(a, b), max(a, b), 1)[0]) :
  (rands(min(a, b), max(a, b), 1, s)[0]);

function len3(v) = sqrt(pow(v.x, 2) + pow(v.y, 2));
 

Tuesday, May 16, 2017

Distance from a point to a plane

Usage:

my_dist=distance_point2plane([0,0,50],[100,0,0],[-1,0,0]);
point_projected_on_plane= point-my_dist*planes_normal;


function distance_point2plane(point, planes_origin, planes_normal) =
let (v = point - planes_origin)   
(
v.x * planes_normal.x + 
v.y * planes_normal.y + 
v.z * planes_normal.z
)); 

Monday, May 15, 2017

Basic stone module


Usage:
Seed=1;//[0:1000]
s=1.2;//[0.8:0.01:1.5]
color("Grey")translate([1.5,0,0])scale([1,1,0.5])boulder(Seed);
color("DarkGrey")translate([-1.5,0,0])scale([1,1,0.5])cutstone(Seed);

intersection(){
color("Grey")translate([0,0,0])scale([s,s,s*0.5])boulder(Seed);
color("DarkGrey")translate([0,0,0])scale([1,1,0.5])cutstone(Seed);
}


//////////////// stones ////////////////
module boulder(bseed){
loops=6;n=10;l=n*5;ri=rands(0,360,l,bseed);t=rands(-180,180,l,bseed+1);
for(loop=[0:loops]){v21=rands(0,l-1,n*3+1,bseed+loop);
v1=[for(i=[0:l])[sin(ri[i])*cos(t[i]),cos(ri[i])*cos(t[i]),sin(t[i])]];
v2=[for(j=[0:n])[v21[j],v21[j+n],v21[j+n+n]]];
color("Gray")scale(0.6)hull()polyhedron(v1,v2);}}

module cutstone(bseed){
loops=1;l=200;n=100;
for(loop=[0:loops]){l1=rands(-0.5,0.5,l*3+3,bseed+loop);
v21=rands(0,l-1,n*3+1,bseed+loop);
v1=[for(i=[0:l])[l1[i],l1[i+l],l1[i+l+1]]];
v2=[for(j=[0:n])[v21[j],v21[j+n],v21[j+n+n]]];
color("Gray")hull()polyhedron(v1,v2);}}


Friday, May 12, 2017

Surface normal of a triangle

 
function face_normal(point_a,point_b,point_c)=
let(u=point_a-point_b,v=point_a-point_c)
un([u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]]);

function un(v)=v/max(len3(v),1e-64);
function len3(v) =len(v)>1?
sqrt(addl([for(i=[0:len(v)-1])pow(v[i], 2)]))
:len(v)==1?v[0]:v; 
function addl(l,c=0)= len(l)-1 >c?l[c]+addl(l,c+1):l[c];

 

Unit Normal / Vector

Unit Vector of a vector in n dimensions

function un(v)=v/max(len3(v),1e-64);// "1e-64" don allow div by zero
function len3(v) =len(v)>1?
sqrt(addl([for(i=[0:len(v)-1])pow(v[i], 2)]))
:len(v)==1?v[0]:v; 
function addl(l,c=0)= len(l)-1 >c?l[c]+addl(l,c+1):l[c];

Euclidean distance

Euclidean distance of a vector in n dimensions
Usage:


echo( len3( [1,1,2] ) );
echo( len3( [1,1,2] - [0,2,0] ) );


function len3(v) =len(v)>1?
sqrt(addl([for(i=[0:len(v)-1])pow(v[i], 2)]))
:len(v)==1?v[0]:v; 
function addl(l,c=0)= len(l)-1 >c?l[c]+addl(l,c+1):l[c];

Smooth and Gaussian Curve

Takes a linear 0-1 value and apply an S-function. Gauss is the inverse of that S-function.

function smooth_curve(a) =
let (b = clamp(a))(b * b * (3 - 2 * b));

function clamp(a, b = 0, c = 1) = min(max(a, b), c);

function gauss(x) =  
     x + (x - smooth_curve(x));


 

Trilinear interpolation

Interpolate a value between eight values, typically corners of a cube. Lerp
Usage:

my_value=trilinear_lerp( 9,12,3,34, 25,16,7,18, 0.1,0.6,0.5 );

function trilinear_lerp(
V000,V100,V010,V001,
V101,V011,V110,V111,
bias_x,bias_y,bias_z)=
lerp(
    lerp(
        lerp(V000,V001,bias_z),
        lerp(V010,V011,bias_z),
    bias_y
    ),
    lerp(
        lerp(V100,V101,bias_z),
        lerp(V110,V111,bias_z),
    bias_y
    )
    ,bias_x
);
function lerp(start, end, bias) = (end * bias + start * (1 - bias));

d

Linear interpolation - Lerp

Lerp is very powerful.
Linear interpolation works on values , point, any pair of list as long as they have same length and substructure. Bias usually goes between 0-1. Bias outside that will extrapolate to corresponding values  along the Linear interpolation line. For example you can lerp between two sets of polyhedra points. Combined with Smooth Curve very interesting effects can be achieved. Sometimes Lerp is called mix.

Usage:


my_point=lerp( [x,y] , [5,1] , 0.30 );

function lerp(start, end, bias) = (end * bias + start * (1 - bias));


Simple 3d Noise

Pseudo random number seeded by a point, 0-1.

Usage:


my_noise=  Coldnoise([x,y,z]);


function  Coldnoise(v) =
 let (
   xseed = round(rnd(1e8, -1e8, round(v.x * 1e6))),
   yseed = round(rnd(1e8, -1e8, xseed + round(v.y * 1e6))),
   zseed = round(rnd(1e8, -1e8, yseed + round(v.z * 1e6))),
   noise  =  (rnd(0, 1e8, zseed))%1)
 noise;

 function rnd(a = 1, b = 0, s = []) = 
  s == [] ? 
   (rands(min(a, b), max(   a, b), 1)[0]) 
  : 
   (rands(min(a, b), max(a, b), 1, s)[0])
  ; 




Vertex hashing

Sometimes its desirable to encode a vertex as a single hash.
Using the seeded rands function in a wrapper.


 my_hash=vertex_hash([x,y,z]);

 function  vertex_hash(v) =
 let (
   xseed = round(rnd(1e8, -1e8, round(v.x * 1e6))),
   yseed = round(rnd(1e8, -1e8, xseed + round(v.y * 1e6))),
   zseed = round(rnd(1e8, -1e8, yseed + round(v.z * 1e6))),
   hash  = round(rnd(1e8, -1e8, zseed)))
 hash;

 function rnd(a = 1, b = 0, s = []) = 
  s == [] ? 
   (rands(min(a, b), max(   a, b), 1)[0]) 
  : 
   (rands(min(a, b), max(a, b), 1, s)[0])
  ; 


Line

Constructs a line between point p1 and point p2

Usage:


line([1,-1],[2,2]);

module line(p1, p2 ,width=0.05) 
{
    hull() {
        translate(p1) sphere(width);
        translate(p2) sphere(width);
    }
}

Quick Sort

Basic quick sort.
Recursively sorts a list of elements


function quicksort(list)= 
!(len(list)>0)?[]:
let(
pivot = list[floor(len(list)/2)],
list_lesser =[ for(i=[0:len(list)-1])if( y[i] < pivot )y[i] ],
list_equal  =[ for(i=[0:len(list)-1])if( y[i]== pivot )y[i] ],
list_greater=[ for(i=[0:len(list)-1])if( y[i] > pivot )y[i] ])

concat(
quicksort(list_lesser),
list_equal,
quicksort(list_greater));

Sorts a list of elements by column col.

function quicksort_col(list,col=0)= 
!(len(list)>0)?[]:
let(
pivot = list[floor(len(list)/2)][col],
list_lesser =[ for(i=[0:len(list)-1])if( list[i][col] < pivot )list[i] ],
list_equal  =[ for(i=[0:len(list)-1])if( list[i][col]== pivot )list[i] ],
list_greater=[ for(i=[0:len(list)-1])if( list[i][col] > pivot )list[i] ])

concat(
quicksort_col(list_lesser),
list_equal,
quicksort_col(list_greater));





Thursday, May 11, 2017

Herons Formula

Herons formula returns the area of an triangle by the length of its sides.

function heron(a,b,c)=
let(s=(a+b+c)/2)
sqrt(abs(s*(s-a)*(s-b)*(s-c)));


Cycle elements of a list

Cycle the first element of a list to the end of the list.
Optionally repet recursively.

Usage:
my_list
=shuffle([1,2,3,4,5,6,7,8]);

function shuffle(list,l=1)=
let(c=concat( [for(i=[1:len(list)-1])list[i]],[list[0]]))
l>0?
 shuffle(c,l-1)
 :c
;

Sum all elements of a list

Recursively sums all elements of a list
Usage:


My_sum1=addl( [ 12, 3, 4, 62, 9 ]);
My_sum2=addl( [ [x,y,z], [x,y,z], [x,y,z], [x,y,z]]);

function addl(list, c = 0) = 
 c < len(list) - 1 ? 
 list[c] + addl(list, c + 1) 
 :
 list[c];


Random-number wrapper

Usage:
  
my_random_number1=rnd(higher);        // between 0-higher
my_random_number2=rnd(higher,seed);   // seeded  between 0-higher
my_random_number3=rnd(lower,higher);  // between lower-higher
my_random_number4=rnd(higher,lower);  // between lower-higher

function rnd(a = 1, b = 0, s = []) = 
  s == [] ? 
   (rands(min(a, b), max(   a, b), 1)[0]) 
  : 
   (rands(min(a, b), max(a, b), 1, s)[0])
  ;