svitoora – 03 Dynamic Gravity Drawings

Gravity

//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
//
// Gravity is a point mass dynamic drawing inspired
// from physics, nature, and falling off a skateboard.
// f = G (m1*m2)/d^2
// f = G sum(m)/(d from avg)^2


// World Model Setup /////////////////////////////////////
var w = 480;
var h = 640;
var t = 1; // time variable
var g = .0025; // gravity
var count = 0; // global count of objects

var ball;
var balls = []; // Array of objects
var ball_size = w * .010 // Default object size

var max_count = 30;
var auto_every = 35;
var max_line = 1000; // Prevents crash


// Control ///////////////////////////////////////////////

// Creates new object in system given (x,y)
function ball_create(x, y) {
	this.x = x;
	this.y = y;
	this.vx = 0;
	this.vy = 0;
	this.r = ball_size;
	this.m = 1;
	this.alpha = 255
}

// Add new object and delete oldest object
function mouseDragged() {
	if (t % 10) {
		balls.push(new ball_create(mouseX, mouseY));
	}
	if (balls.length >= max_count) {
		balls.splice(0, 1)
	}
}

// Add new object and delete oldest object
function mousePressed() {
	balls.push(new ball_create(mouseX, mouseY));
	if (balls.length >= max_count) {
		balls.splice(0, 1)
	}
}


// World /////////////////////////////////////////////////

// Maintain global count of balls
function count_balls(balls) {
	count = balls.length;
}

// Maintain global mass of system
function sum_mass(balls) {
	sum_m = 0;
	for (i in balls) {
		sum_m += balls[i].m;
	}
	return sum_m;
}

// Determines the system's average position X
function average_posX(balls) {
	if (balls.length == 0) {
		return w / 2;
	};
	var sum_x = 0;
	for (i in balls) {
		sum_x += balls[i].x;
	}
	avg = sum_x / balls.length
	return avg;
}

// Determines the system's average position Y
function average_posY(balls) {
	if (balls.length == 0) {
		return h / 2;
	};
	var sum_y = 0;
	for (i in balls) {
		sum_y += balls[i].y;
	}
	avg = sum_y / balls.length;
	return avg
}

// Apply gravity for all objects in the system
function gravity(balls) {
	var avg_x = average_posX(balls);
	var avg_y = average_posY(balls);
	var speed = .1 //0-1 Multuplier for controlling velocity of attratction
	for (i in balls) {
		d = dist(balls[i].x, balls[i].y, avg_x, avg_y);
        ds = map(d,0,w/2,1,0);  // used to simulate d^2
		
        // Gravity X
        if (balls[i].x > avg_x) {
			balls[i].x *= 1 - (g * (count * speed));
		} else { balls[i].x *= 1 + (g * (count * speed+ds));}

        // Gravity Y
		if (balls[i].y > avg_y) {
			balls[i].y *= 1 - (g * (count * speed))
		} else { balls[i].y *= 1 + (g * (count * speed+ds));}
	}
}

// Add object to system in the middle; // Used at setup()
function add_ball(balls) {
	balls.push(new ball_create(w / 2, h / 2));
}

// Prevents software from crashing
// from too many objects beyond max_count
function death(balls, t) {
	if (balls.length >= max_count) {
		balls.splice(0, 1);
		for (i in balls) {
			balls[i].r *= .99;
		}
	}
}

// Connects all the object in the system via a line
function draw_line(balls) {
	lines = 0
	alpha = 255 * .2

	if (lines < max_line) {
		for (i in balls) {
			var x_1 = balls[i].x;
			var y_1 = balls[i].y;
			for (i in balls) {
				var x_2 = balls[i].x;
				var y_2 = balls[i].y;
				stroke(255, 255, 255, alpha);
				line(x_1, y_1, x_2, y_2);
				lines += 1;
			}
		}
	}
}

// SETUP
function setup() {
	createCanvas(w, h);
	g = .0025;
	background(50);
	balls.length = 0; // Kill all objects in system
	add_ball(balls);
}

// Refreshes the systems with new objects
// Removes old objects and add new objects
function auto_refresh(balls, t) {
	// Starts refreshing system at 5 objects
	// every auto_every interval.
	if (t % auto_every == 0 & balls.length > 5) {
		balls.splice(0, 1);
	}
	X = constrain(mouseX, 1, w);
	Y = constrain(mouseY, 1, h)
	if (t % auto_every == 0) {
		balls.push(new ball_create(X, Y));
	}

	// Resets the system to 8 objects once every 500 ms
	// This prevents overload; Array starts at [0]
	if (t % 500 == 0 & balls.length > 8) {
		balls.length = 7;
	}
}

// Draw ////////////////////////////////////////////////////

// Draw all objects in systems mapped by distance from avg
function draw_balls(balls) {
	for (ball in balls) {
		noStroke();
		var avg_x = average_posX(balls);
		var avg_y = average_posY(balls);
		var d = dist(balls[ball].x, balls[ball].y, avg_x, avg_y);

		// Size and Alpha of Ball is a function of distance
		var alpha = map(d, balls[ball].r, w / 2, 255, 0);
		var size = map(d, 0, w / 2, .5, -1.5) //max to min

		fill(255, 255, 255, alpha);
		ellipse(balls[ball].x, balls[ball].y,
			balls[ball].r * (2 + size),
			balls[ball].r * (2 + size));
	}
}


// Execute /////////////////////////////////////////////////
function draw() {
	background(50);
	noStroke();
	// Update World
	t = t + 1;
	count_balls(balls);
	auto_refresh(balls, t);
	if (balls.length > 1) {
		gravity(balls);
	}
	death(balls, t);

	// Draw World
	draw_line(balls);
	draw_balls(balls);
}

Physics

 Gravity is a point mass dynamic drawing inspired from physics, nature, and falling off a skateboard. I wanted to create a systematic representation of mass attracts mass. To do this I was inspired by the physics formula:

Image result for f = m1m2

The problem with this forumla is that it is meant for physicist dealing with a two body system. In my case, I wanted a forumla that worked with multiple bodies in a system algorithmically. After sketching for a while with equations on the white board, I realized that that the problem I was trying to solve was much simplier than I expected.

Trying to figure out the algorithm behind multiple bodied system gravity.

Essentially the problem boils down to averages. If all the object in the system had a mass of 1, then the center of mass of the system would be at the average coordinate position of every point mass. By definition this is the centroid of the system.

Related image
Center of gravity is by definition the centroid of a multiple body system.

After defininig the centroid, I simply make every object in the system moves towards it. To replicate d^2’s effect on speed, I use a position *= and /= function, in addition to a mapping function of speed based off distance away from the centroid.

Model-View-Controller  (MVC)

This programs uses the MVC framework taught in 15-112. Objects are models are added to an array, modfified by the controller, and then representated through view functions. Because of the complexity of this code, I used to object-oriented programming to organize my variables. I didn’t quite understand object-based methods in javascript yet, so I worked around them.

Demo and Project Requirments:

Press and hold.

To sastify the project requirement, there are no random or non-deterministic element. Every function is deterministic, therefore given the exact same mouse input the Gravity will create the exact same drawing. The variables that are being altered in how the image is being created are: size, position, opacity, angle, etc.

Stills from Gravity: Slow vs Fast Drawing

SaveSave

SaveSave

SaveSave

Leave a Reply