Skip to content

Instantly share code, notes, and snippets.

@REAS
Last active December 14, 2015 01:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save REAS/0dc169be1ebf19a62358 to your computer and use it in GitHub Desktop.
Save REAS/0dc169be1ebf19a62358 to your computer and use it in GitHub Desktop.
Example code for Print, Paper, Process: Marbling and Technology at the Hammer Museum
/**
PRINT PAPER PROCESS: MARBLING AND TECHNOLOGY
23 FEB 2013, HAMMER MUSEUM
UCLA ARTS SOFTWARE STUDIO <http://software.arts.ucla.edu>
(Based on code in Dan Shiffman's Nature of Code <http://natureofcode.com/>)
Operate the program with the mouse, keyboard, or modify the code.
Click to draw a new field
Click right to draw a uniform field
Click left to draw a scattered field
BASIC USE
Spacebar - save PDF
MODIFY
+ - increase size
- - descrease size
R - reset particles
D - density of field
GRAPHICS
1 - circles
2 - lines
3 - triangles
COLOR
5 - grays
6 - contrast
7 - color
HIDE/REVEAL
F - field hide
P - particle hide
*/
// Add you name here
String name = "Your-Name-Here";
// Change the number of particles
int numParticles = 2400; // Try up to 20000;
//
// More control over the desity of the grid
int gridSize = 20;
// These allow more control over the particle motion
float speedLow = 2;
float speedHigh = 5;
float forceLow = 0.1;
float forceHigh = 0.5;
// Set the initial size range of the particles
float minSize = 10;
float maxSize = 30;
// Change the colors for color mode (7)
// Click "Color Selector" from the Tools menu
color c1 = #8DD30D;
color c2 = #F0CE46;
color c3 = #70BDBF;
color c4 = #E3B0E3;
color c5 = #2079D1;
color[] colors = {c1, c2, c3, c4, c5};
color backgroundColor = #FFFFFF;
int smoothAmount = 8; // Can be 0, 2, 4, 8
//
import processing.pdf.*;
FlowField flowfield; // FlowField object
ArrayList<Particle> particles; // An ArrayList of Particles
float fieldDiff = 0.1;
boolean captureField = false;
int graphicsMode = 1;
boolean showField = true;
boolean showParticles = true;
int colorMode = 1;
float scalar = 0.3;
void setup() {
size(756, 576, P2D);
smooth(smoothAmount);
generateField();
generateParticles();
}
void generateParticles() {
particles = new ArrayList<Particle>();
for (int i = 0; i < numParticles; i++) {
float rx = random(width);
float ry = random(height);
float speed = random(speedLow, speedHigh);
float force = random(forceLow, forceHigh);
particles.add(new Particle(new PVector(rx, ry), speed, force, minSize, maxSize));
}
}
void generateField() {
flowfield = new FlowField(gridSize);
}
void draw() {
// Start creating the PDF
if (captureField == true) {
beginRecord(PDF, "Field-" + name + "-" + nf(frameCount, 8) + ".pdf");
}
// Make the background a solid color
background(backgroundColor);
// Draw the vector field
if (showField) {
flowfield.display();
}
// Tell all the Particles to follow the flow field
if (showParticles) {
for (Particle v : particles) {
v.follow(flowfield);
v.run();
v.display();
}
}
// Finish the PDF
if (captureField == true) {
endRecord();
captureField = false;
}
}
// Make a new flowfield
void mousePressed() {
fieldDiff = map(mouseX, 0, width, 0.5, 0.01);
flowfield.init();
}
/**
*
* FLOW FIELD
*
*/
class FlowField {
// A flow field is a two dimensional array of PVectors
PVector[][] field;
int cols, rows; // Columns and Rows
int resolution; // How large is each "cell" of the flow field
int halfRes;
FlowField(int res) {
resolution = res;
halfRes = resolution/2;
// Determine the number of columns and rows based on sketch's width and height
cols = width/resolution;
rows = height/resolution;
field = new PVector[cols][rows];
init();
}
void init() {
// Reseed noise so we get a new flow field every time
noiseSeed((int)random(10000));
float xoff = 0;
for (int i = 0; i < cols; i++) {
float yoff = 0;
for (int j = 0; j < rows; j++) {
float theta = map(noise(xoff, yoff), 0, 1, 0, TWO_PI);
// Polar to cartesian coordinate transformation to get x and y components of the vector
field[i][j] = new PVector(cos(theta), sin(theta));
yoff += fieldDiff;
}
xoff += fieldDiff;
}
}
// Draw every vector
void display() {
pushMatrix();
translate(resolution, resolution);
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
drawVector(field[i][j], i*resolution, j*resolution, resolution-2);
}
}
popMatrix();
}
// Renders a vector object 'v' as an arrow and a location 'x,y'
void drawVector(PVector v, float x, float y, float scayl) {
pushMatrix();
float arrowsize = 4;
// Translate to location to render vector
translate(x, y);
stroke(102);
strokeWeight(0.5);
// Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate
rotate(v.heading2D());
// Calculate length of vector & scale it to be bigger or smaller if necessary
float len = v.mag()*scayl*0.5;
// Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction)
line(-len, 0, len, 0);
//line(len,0,len-arrowsize,+arrowsize/2);
//line(len,0,len-arrowsize,-arrowsize/2);
popMatrix();
}
PVector lookup(PVector lookup) {
int column = int(constrain(lookup.x/resolution, 0, cols-1));
int row = int(constrain(lookup.y/resolution, 0, rows-1));
return field[column][row].get();
}
}
/**
*
* KEYBOARD
*
*/
void keyPressed() {
if (key == 'd' || key == 'D') {
gridSize += 10;
if (gridSize > 50) {
gridSize = 10;
}
generateField();
}
if (key == 'f' || key == 'F') {
showField = !showField;
}
if (key == 'p' || key == 'P') {
showParticles = !showParticles;
}
if (key == 'r' || key == 'R') {
generateParticles();
}
if (key == ' ') {
captureField = true;
}
if (key == '1') {
graphicsMode = 1;
}
if (key == '2') {
graphicsMode = 2;
}
if (key == '3') {
graphicsMode = 3;
}
if (key == '5') {
colorMode = 1;
for (Particle v : particles) {
v.setColor();
}
}
if (key == '6') {
colorMode = 2;
for (Particle v : particles) {
v.setColor();
}
}
if (key == '7') {
colorMode = 3;
for (Particle v : particles) {
v.setColor();
}
}
if (key == '=' || key == '+') {
scalar += 0.1;
}
if (key == '-' || key == '_') {
scalar -= 0.1;
}
scalar = constrain(scalar, 0.1, 2.0);
}
/**
*
* PARTICLE
*
*/
class Particle {
// The usual stuff
PVector location;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
color c;
float alpha = 204;
Particle(PVector l, float ms, float mf, float minrad, float maxrad) {
location = l.get();
r = random(minrad, maxrad);
maxspeed = ms;
maxforce = mf;
acceleration = new PVector(0, 0);
velocity = new PVector(0, 0);
setColor();
}
void setColor() {
if (colorMode == 1) {
alpha = 204;
c = color(random(0, 204));
}
else if (colorMode == 2) {
alpha = 255;
if (random(1) > 0.5) {
c = color(255);
}
else {
c = color(0);
}
}
else {
alpha = 204;
int rpick = int(random(5));
c = colors[rpick];
}
}
void run() {
update();
borders();
}
void display() {
displayParticle();
}
// Implementing Reynolds' flow field following algorithm
// http://www.red3d.com/cwr/steer/FlowFollow.html
void follow(FlowField flow) {
// What is the vector at that spot in the flow field?
PVector desired = flow.lookup(location);
// Scale it up by maxspeed
desired.mult(maxspeed);
// Steering is desired minus velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce); // Limit to maximum steering force
applyForce(steer);
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// Method to update location
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
location.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
void displayParticle() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + HALF_PI;
float rr = r * scalar;
pushMatrix();
translate(location.x, location.y);
rotate(theta);
if (graphicsMode == 1) {
stroke(c, alpha);
strokeCap(ROUND);
strokeWeight(rr);
point(0, 0);
}
else if (graphicsMode == 2) {
stroke(c, alpha);
strokeWeight(rr/4.0);
strokeCap(SQUARE);
stroke(c);
line(-rr, 0, rr, 0);
}
else if (graphicsMode == 3) {
noStroke();
fill(c, alpha);
beginShape(TRIANGLES);
vertex(0, -rr);
vertex(-rr/2, rr);
vertex(rr/2, rr);
endShape();
}
popMatrix();
}
// Wraparound
void borders() {
if (location.x < -r) location.x = width+r;
if (location.y < -r) location.y = height+r;
if (location.x > width+r) location.x = -r;
if (location.y > height+r) location.y = -r;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment