xxxxxxxxxx
326
const radius = 150;
const originX = 0;
const originY = 0;
const pointSize = 4;
const RAND_WALK = 0;
const TREE_WALK = 1;
const TEST_HIST = 2;
const EVEN_SAMPLE = 3;
const RAND_SAMPLE = 4;
const BLUE_NOISE = 5;
const BLUE_INIT = 6;
const sampleSize = 20;
let history = [];
let leafs = [];
let growthStep = 10;
let treeStep = 135;
let randSamples = 400;
let render = BLUE_NOISE;
let lifeCycles = 6;
let executionStepCount = 0;
let singleStep = true;
let population = [];
let drawCount = 0;
let storeHistory = true;
let myFont;
function preload() {
myFont = loadFont('FontAwesome.otf');
console.log(myFont);
}
function isExecutionStep(step){
if (!singleStep) return true;
// at step 2
// execute 0, 1, 2
// 0 < 0
//console.log(step, executionStepCount);
return (step <= executionStepCount);
}
function wrapExecutionStep(maxStep){
executionStepCount = executionStepCount % maxStep;
}
//function square(A){
// return A * A;
//}
function haversine(p0, p1, radius){
/* NOTE(casey): This is not meant to be a "good" way to calculate the Haversine distance.
Instead, it attempts to follow, as closely as possible, the formula used in the real-world
question on which these homework exercises are loosely based.
*/
lat1 = p0.lat;
lat2 = p1.lat;
lon1 = p0.long;
lon2 = p1.long;
dLat = rad(lat2 - lat1);
dLon = rad(lon2 - lon1);
lat1 = rad(lat1);
lat2 = rad(lat2);
a = pow(sin(dLat/2.0), 2) + cos(lat1)*cos(lat2)*pow(sin(dLon/2), 2);
c = 2.0*asin(sqrt(a));
return radius * c;
}
function setup() {
createCanvas(400, 400, WEBGL);
noStroke();
switch(render){
case RAND_WALK: history.push({"lat": 90, "long": 0}); break;
case TREE_WALK: leafs.push({"lat": 0, "long": 0}); break;
case EVEN_SAMPLE: createEvenSample(); break;
case RAND_SAMPLE: createRandSample(); break;
case BLUE_NOISE:
history.push({"lat": random(-180, 180), "long": random(-90, 90)});
population = randomPopulation(sampleSize);
break;
case BLUE_INIT:
history.push({"lat": random(-180, 180), "long": random(-90, 90)});
blueInitNoise();
break;
}
}
function createEvenSample(){
for(let i = -90; i < 90; i+= 10){
for(let j = -180; j < 180; j+=10){
history.push({"lat": j, "long": i});
}
}
}
function createRandSample(){
for(let i = 0; i < randSamples; i++){
let long = random(-90, 90);
let lat = random(-180, 180);
history.push({"lat": lat, "long": long});
}
}
function rad(deg){
return (deg * PI)/180.0;
}
//Move down the vertical axis by some angle
//This would be the latitude line
function getSliceInfo(theta){
let y = radius * sin(rad(theta));
let x = radius * cos(rad(theta));
let xp = -x;
//push();
//translate(0, y, 0);
//plane(x - xp, pointSize);
//pop();
//console.log(sin(theta), y, xp, x, theta, diameter);
return {"radius": abs(x), "y": y};
}
function getXY(theta, radius){
return [radius * cos(rad(theta)), radius * sin(rad(theta))];
}
function pointAt(v3, size){
//console.log(v3);
push();
translate(v3[0], v3[1], v3[2]);
plane(size, size);
pop();
}
function xyzFromGeo(geo){
let info = getSliceInfo(geo.long);
let v = getXY(geo.lat, info.radius);
return [v[0], info.y, v[1]];
}
function drawSet(setOfLocations, fillColor, strokeColor){
if (fillColor)
fill(fillColor[0], fillColor[1], fillColor[2]);
if (strokeColor){
noFill();
stroke(strokeColor);
}
for(let i = 0; i < setOfLocations.length; i++){
pointAt(xyzFromGeo(setOfLocations[i]), pointSize);
//console.log(i, v[0], info.y, v[1]);
}
if (strokeColor){
noStroke();
}
}
function randomWalk(){
let head = history[history.length - 1];
let current = {"long": max(min(head.long + (random(growthStep) -(growthStep/2)), 90), -90),
"lat": max(min(head.lat + (random(growthStep) -(growthStep/2)), 180), -180)};
history.push(current);
drawSet(history);
}
function treeWalk(){
let leafCount = leafs.length;
//console.log(leafCount);
if (lifeCycles > 0){
lifeCycles--;
while(leafCount > 0){
let leaf = leafs.shift();
leafs.push({"long": leaf.long + treeStep, "lat": leaf.lat});
leafs.push({"long": leaf.long - treeStep, "lat": leaf.lat});
leafs.push({"long": leaf.long, "lat": leaf.lat + treeStep});
leafs.push({"long": leaf.long, "lat": leaf.lat - treeStep});
history.push({"long": leaf.long, "lat": leaf.lat});
leafCount--;
}
//console.log(history);
}
treeStep = treeStep/4;
drawSet(history);
}
function randomPopulation(size){
let result = [];
for (let i = 0; i < size; i++){
let long = random(-180, 180);
let lat = random(-180, 180);
result.push({"lat": lat, "long": long});
}
return result;
}
function textOut(s, v3){
let _text = createGraphics(400,400);
_text.noStroke();
_text.fill(0);
_text.textAlign(LEFT);
_text.textSize(80);
_text.text(s, 0, 300);
push();
translate(v3[0], v3[1], v3[2]);
texture(_text);
plane(50,50);
pop();
}
function blueNoise(){
const maxStep = 4;
let bestLong = 0;
let bestLat = 0;
let bestDistance = 0;
wrapExecutionStep(maxStep);
if (isExecutionStep(0)){
drawSet(history, [255, 255, 255]);
drawSet(population, [255, 0, 0]);
}
if (isExecutionStep(1)){
for (let i = 0; i < population.length; i++){
let localDistance = 0;
for(let j = 0; j < history.length; j++){
let d = haversine(history[j], population[i], radius);
//console.log(i, j, d);
if (d !== 0 && (localDistance === 0 || d < localDistance)){
localDistance = d;
}
}
if (localDistance > bestDistance){
bestLong = population[i].long;
bestLat = population[i].lat;
bestDistance = localDistance;
//console.log("best", d);
}
let textLocation = xyzFromGeo(population[i]);
textOut("L " + round(localDistance), textLocation);
}
let g = createGraphics(100, 100);
let x = [{"lat": bestLat, "long": bestLong}];
//let textLocation = xyzFromGeo({"lat": x[0].lat, "long": x[0].long + 10});
////textOut("best " + round(bestDistance), textLocation);
drawSet(x, undefined, [0, 255, 0]);
}
if (isExecutionStep(2)){
if (storeHistory){
history.push({"lat": bestLat, "long": bestLong});
storeHistory = false;
}
drawSet([{"lat": bestLat, "long": bestLong}], [255, 255, 255]);
}
if (isExecutionStep(3)){
population = randomPopulation(sampleSize);
executionStepCount++;
storeHistory = true;
}
}
function blueInitNoise(){
for(let k = 0; k < randSamples; k++){
let bestLong = 0;
let bestLat = 0;
let bestDistance = 0;
for (let i = 0; i < 5; i++){
let long = random(-90, 90);
let lat = random(-180, 180);
for(let j = 0; j < history.length; j++){
let d = haversine(history[j], {"lat": lat, "long": long}, radius);
if (d > bestDistance){
bestLong = long;
bestLat = lat;
bestDistance = d;
//console.log("best", d);
}
}
}
history.push({"lat": bestLat, "long": bestLong});
}
}
//This would be a cool effect if you kept like a few levels of history
//and the age of that frame set a fade or alpha level. Sort of like phosphor fading
function keyPressed() {
executionStepCount++;
//console.log(executionStepCount);
}
function draw() {
background(220);
//sphere(radius);
orbitControl();
switch(render){
case RAND_WALK : randomWalk(); break;
case TREE_WALK : treeWalk(); break;
case TEST_HIST : drawSet(history); break;
case EVEN_SAMPLE : drawSet(history); break;
case RAND_SAMPLE : drawSet(history); break;
case BLUE_NOISE : blueNoise(); break;
case BLUE_INIT : drawSet(history); break;
}
if (drawCount++ % 5 === 0){
executionStepCount++;
}
//console.log(drawCount);
}