> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.d0ISMlrvCzv/rev.1783
 * 
 * authors: 
 *   hansi raber

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



// Distance-parametrized Catmul-Rom curves. 
// use alpha=0.5 (key 's') for the prettiest curves. 

// Press q/w to change curve parameter (0...1)
//       a,s,d are special values (resp. 0.0, 0.5, 1.0)
// Press space for new random points

int N = 6; 
float points[][] = new float[N][2]; 
float alpha = 0.5; 


void setup(){
    size( 500, 500 );
    randomize(); 
}

void randomize(){
    for( int i = 0; i < N; i++ ){
        points[i][0] = random( 10, width-20 ); 
        points[i][1] = random( 10, height-20 ); 
    }
}


void draw(){
    background( 255 ); 
    
    fill( 0 ); 
    noStroke(); 
    for( int i = 0; i < N; i++ ){
        ellipse( points[i][0], points[i][1], 5, 5 ); 
    }
    
    stroke( 0 ); 
    noFill(); 
    cmrCurve( points, alpha, false ); 
}


void cmrCurve( float[] points[], float alpha, boolean close ){
    int N = points.length; 
    
    for( int i = 0; i < N - 3; i++ ){
        cmrSegment( points[i+0], points[i+1], points[i+2], points[i+3], alpha ); 
    }
    
    if( close && N >= 3 ){
        cmrSegment( points[N-3], points[N-2], points[N-1], points[0], alpha ); 
        cmrSegment( points[N-2], points[N-1], points[0], points[1], alpha ); 
        cmrSegment( points[N-1], points[0], points[1], points[2], alpha ); 
    }
}


void cmrSegment( float p0[], float p1[], float p2[], float p3[], alpha ){
    float d1 = dist( p0[0], p0[1], p1[0], p1[1] ); 
    float d2 = dist( p1[0], p1[1], p2[0], p2[1] ); 
    float d3 = dist( p2[0], p2[1], p3[0], p3[1] ); 
    bezier( 
        p1[0], 
        p1[1], 

        (pow(d1, 2*alpha)*p2[0]-pow(d2, 2*alpha)*p0[0] + (2 * pow(d1, 2*alpha) + 3*pow(d1*d2, alpha) + pow(d2, 2*alpha))*p1[0])  /  (3*pow(d1,alpha)*(pow(d1,alpha)+pow(d2,alpha))), 
        (pow(d1, 2*alpha)*p2[1]-pow(d2, 2*alpha)*p0[1] + (2 * pow(d1, 2*alpha) + 3*pow(d1*d2, alpha) + pow(d2, 2*alpha))*p1[1])  /  (3*pow(d1,alpha)*(pow(d1,alpha)+pow(d2,alpha))), 

        (pow(d3, 2*alpha)*p1[0]-pow(d2, 2*alpha)*p3[0] + (2 * pow(d3, 2*alpha) + 3*pow(d2*d3, alpha) + pow(d2, 2*alpha))*p2[0])  /  (3*pow(d3,alpha)*(pow(d3,alpha)+pow(d2,alpha))), 
        (pow(d3, 2*alpha)*p1[1]-pow(d2, 2*alpha)*p3[1] + (2 * pow(d3, 2*alpha) + 3*pow(d2*d3, alpha) + pow(d2, 2*alpha))*p2[1])  /  (3*pow(d3,alpha)*(pow(d3,alpha)+pow(d2,alpha))), 

        p2[0], 
        p2[1]
    ); 
}


void keyPressed(){
    var str = "" + String.fromCharCode( parseInt(key) ); 
    if( str == "q" ) alpha += 0.1; 
    if( str == "w" ) alpha -= 0.1; 
    if( str == "a" ) alpha  = 0.0; 
    if( str == "s" ) alpha  = 0.5; 
    if( str == "d" ) alpha  = 1.0; 
    if( str == " " ) randomize(); 
    alpha = constrain( alpha, 0.0, 1.0 );  
}