Project: 06 – Abstract Clock

Crop Circles

I was inspired by crop circles for my clock. Each node is one hour in a day. The crops in the background grow with the mouse.

Sketch
sketch
/* Evan Stuhlfire
** estuhlfi@andrew.cmu.edu, section B
** Project 06: Abstract Clock  */

var r = 90; // radius of center circle, noon
var deg = 360; // degrees in a circle
var nodeCount = 24; // 24 hours, each node is one hour
var c = []; // color array
var x = []; // x position of circle
var theta = []; //angle
var size = []; // diam of the circles
var defaultColor;
var tempSize = 0; // allows the nodes to grow with time
var pSize = 25;

function setup() {
    createCanvas(480, 480);
    background(127, 198, 164);
    fillArray(); // fill arrays with start values

}

function draw() {
    var thetaRotate = 40; // canvas rotation

    background(127, 198, 164);
    drawCrops();

    // build color array
    buildColorArray();

    stroke(93, 115, 126);
    // settings to draw circles (nodes)
    push(); // save settings
    translate(width/2, height/2); // reset origin to center
    rotate(radians(thetaRotate)); // rotate canvas to draw at an angle

    // call function to draw the nodes
    drawNodes();
    pop(); // restore settings

    // make crops reactive to mouse location and time
    pSize = mouseX/hour();
}

function drawCrops() {
    var rows = width/30;
    var cols = height/30;
    var incr = width/16;
    
    var s1 = width/16;
    var s2 = height/16;
    var len = pSize;
    var a = len/4; 

    // loop over double for loop to add colums and rows of crops
    for(var i = 0; i < rows; i++) {
        for(var j = 0; j < cols; j++) {
            push();
            translate(s1/2, s2/2);
            drawOne(len, a); 
            pop();
            s2 += 2 * incr;
        }
        s1 += 2 * incr;
        s2 = incr;
    }
}

function drawOne(len, a) {
    // function to draw on plant for crops
    stroke(93, 115, 126, 60);
    line(0, -a, 0, len);
    line(-a, -a, 0, len/2);
    line(a, -a, 0, len/2);
}

function buildColorArray() {
    // set the default color
    defaultColor = color(242, 245, 234);

    // fill array with colors
    for(var i = 0; i < x.length; i++){
        if(i < 3) {
            c[i] = color(93, 115, 126);    
        } else if(i < 6) {
            c[i] = color(118, 129, 179);
        } else if(i < 9) {
            c[i] = color(214, 248, 214);
        } else if(i < 11) {
            c[i] = color(163, 213, 255);
        } else if(i < 14) {
            c[i] = color(250, 243, 62);
        } else if (i < 16) {
            c[i] = color(163, 213, 255);
        } else if (i < 19) {
            c[i] = color(214, 248, 214);
        } else if (i < 22) {
            c[i] = color(118, 129, 179);
        } else if (i < 25) {
            c[i] = color(93, 115, 126)
        }
    }
}

function fillArray() {
    var angle = 30; // nodes are positioned 30 degrees apart
    var angle2 = 150; // starting point for second set of nodes
    var dist = 65; // nodes begin at dist from center
    var offset = 1.2 // distance offset 
    var offset2 = .8 
    var minSize = 15; // can be no smaller than minSize

    // fill arrays with start values
    x.push((-deg/2) + 10);
    theta.push(180);
    size.push(r * offset2); // 80% size of center

    // fill array with first 12 nodes
    for(var i = 1; i < nodeCount/2; i++) {
        x[i] = dist;
        theta[i] = angle * i;
        size[i] = max(r * i/18, minSize);

        dist = dist + i * offset;
    }

    // push center circle into array
    x.push(deg/2 - 10);
    theta.push(0);
    size.push(r);

    dist = dist - i * offset; // undo last dist calc
    // fill array with last 12 nodes
    // loop backward so that decreasing i can be used to decrease size
    for(i = x.length; i > 2; i--) {
        x.push(dist);
        theta.push(angle2);
        size.push(max(r * i/22, minSize));

        dist = dist - i * offset2;
        angle2 -= angle;
    }

    // push last circle into array, midnight
    x.push(0);
    theta.push(0);
    size.push(r * offset2); // 80% size of center
}

function drawNodes() {
    var h = hour();
 
    stroke(93, 115, 126);
    // draw line behind center node so that it is behind
    line(0, 0, deg/2, 0);

    // draw the satellite nodes
    push();

    translate(x[0], 0); // reset origin to top circle
    loopAndDraw(0, x.length/2, h);

    // draw top midnight circle
    fill(c[0]);
    circle(0, 0, r * .8);
    pop();

    push();
    translate((deg/2) -10, 0);
    loopAndDraw(int(x.length/2) + 1, x.length, h);

    pop();
}

function loopAndDraw(start, end, h) {
    var dx;
    var dy;
    var current = false; // identify the current node

    // iterate over arrays
    for(var i = start; i < end; i++) {
        dx = x[i] * cos(radians(theta[i]));
        dy = x[i] * sin(radians(theta[i]));

        // midnight
        if(h == 0) {
            h = 24;
        }
        // if the hour has passed or is the current hour use fill
        if(i < h){
            fill(c[i]);
        } else if (i == h) {
            current = true;
            fill(c[i]);
        } else {
            fill(defaultColor);
        }

        stroke(93, 115, 126);
        line(0, 0, dx, dy);
        circle(dx, dy, size[i]);

        if(current) {
            currentHour(i, dx, dy);
        }

        current = false;
    }
}

function currentHour(i, dx, dy) {
    // add time elements to nodes to track time
    // subtract to adjust for rotation of canvas
    var s = second() * 6 - 140;
    var m = minute() * 6 - 140;
    var h = hour() * 30 + minute()/2 - 140; 

    fill(c[i]); // use the color stored in the array
    push();
    translate(dx, dy);
    // make current circle bigger
    tempSize = size[i] * 1.32;
    circle(0, 0, tempSize);

    // have a second hand orbit the current hour
    if(i > 3 & i < 23) {
        fill(c[i - 3]); //use previous color.
    } else {
        fill(defaultColor);
    }
    // mark hours
    var hx = size[i] * .6 * cos(radians(h));
    var hy = size[i] * .6 * sin(radians(h));
    circle(hx, hy, tempSize * .25);

    // mark minutes
    var mx = size[i] * .3 * cos(radians(m));
    var my = size[i] * .3 * sin(radians(m));
    
    circle(mx, my, tempSize * .2);

    // mark seconds
    var armX = size[i] * .55 * cos(radians(s));
    var armY = size[i] * .55 * sin(radians(s));
    strokeWeight(1);
    circle(armX, armY, tempSize * .15);
    pop();
}

Leave a Reply