import processing.opengl.*;
import traer.animation.*;
import traer.physics.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
int year = 2007;
/**
*
Die Parteilisten werden am Anfang zufällig verteilt und ziehen sich entsprechend der Stärke
* ihres Panaschierstimmenaustauschs an bzw. stossen sich entsprechend ab. Alle ca. 5 Sekunden wird eine einzelne
* Liste zufällig aus ihrer Position geworfen und sucht sich dann wieder ihren Platz.
*
Tastenbefehle
*
- 0 / 1 / 5 / 9: keine / wenig / viel / sehr viel tremor
*
- : neue zufällige Startverteilung
*
- l: Linien (on/off)
*
- z: einmaliges zufälliges Verschieben einer einzelnen Liste
*
- y: dito, aber laufend automatisch alle paar Sekunden (on/off)
*
- + / -: Zusammenrücken, Auseinanderdriften
*
*/
String inputFile;
ParticleSystem physics;
Particle[] particles;
Color[] colors;
float[] dot_size;
int gridSizefo = 10;
String parteien[];
final float STRENGTH = 0.1;
final float DAMPING = 0.1;
final float NODE_SIZE = 10;
float fac = 1.0;
float gray_start = 20000;
float gray = gray_start;
float angle = 0.0;
Smoother3D centroid;
float tremor = 0;
float distances[];
float chi2min = Float.POSITIVE_INFINITY;
PFont font, font1;
boolean withLines = true;
int nParties;
int springs;
float factor = 1.0;
float initFactor = -1.0;
float x_moved, y_moved, chi2_moved;
float chi2, millis_moved, millis_written;
Particle p;
boolean spicked = true;
boolean withSpick = true;
float expTotal;
float lengthFactor;
float xLeft, yMed;
float deltaX, deltaY;
float xMin, yMin, xMax, yMax;
void setup() {
size(440, 440);
expTotal = 1.25;
lengthFactor = 40;
if (year == 2007) {
inputFile = "federn29a.txt";
}
else {
inputFile = "federn32g.txt";
}
smooth();
fill(0);
frameRate(24);
int ii = 0;
springs = 0;
String lines[];
float weight[];
nParties = 0;
StringTokenizer stval;
physics = new ParticleSystem(0.0, 0.05);
centroid = new Smoother3D(0.8);
physics.clear();
centroid.setValue(0, 0, 0.0);
lines = loadStrings(inputFile, "UTF-16");
println("there are " + lines.length + " lines in the dataset");
stval = new StringTokenizer(lines[0]);
nParties = Integer.parseInt(stval.nextToken());
weight = new float[nParties];
distances = new float[nParties * (nParties - 1)];
parteien = new String[nParties];
particles = new Particle[nParties];
colors = new Color[nParties];
dot_size = new float[nParties];
println("there are " + nParties + " parties");
for (int i = 0; i < nParties; i++) {
ii++;
stval = new StringTokenizer(lines[ii]);
parteien[i] = stval.nextToken();
int par = Integer.parseInt(stval.nextToken());
weight[i] = Float.parseFloat(stval.nextToken());
int red = Integer.parseInt(stval.nextToken());
int green = Integer.parseInt(stval.nextToken());
int blue = Integer.parseInt(stval.nextToken());
dot_size[i] = Float.parseFloat(stval.nextToken());
colors[i] = new Color(red, green, blue);
particles[i] = physics.makeParticle(1.0, random(width-5), random(height-5), 0.0);
println(par + ". " + parteien[i] + " " + weight[i]);
if (dot_size[i] == 0) dot_size[i] = 0.25;
dot_size[i] = sqrt(dot_size[i]);
}
ii++;
println();
for (int i=ii; i < lines.length; i++) {
stval = new StringTokenizer(lines[i]);
int par1 = Integer.parseInt(stval.nextToken());
int par2 = Integer.parseInt(stval.nextToken());
float dist = Float.parseFloat(stval.nextToken());
// int toSelect = Integer.parseInt(stval.nextToken());
if (par1 > par2) {
println(par1 +"-" + par2 + " / " +
parteien[par1-1] + "-" + parteien[par2-1] + " " + dist);
float dd = sqrt(dist);
dd = lengthFactor * pow(dist, expTotal);
physics.makeSpring(particles[par1-1], particles[par2-1], STRENGTH, DAMPING, dd);
distances[springs] = dd;
springs++;
}
}
println(springs + " springs");
println();
font = loadFont("AgencyFB-Reg-48.vlw");
textFont(font);
font1 = loadFont("CourierNewPSMT-14.vlw");
textFont(font1);
if (withSpick) spick();
}
void draw() {
smooth();
physics.tick(0.25);
if (physics.numberOfParticles() > 1) updateCentroid();
centroid.tick();
rotate(angle);
shuffle();
background(255);
translate(width / 2, height / 2);
scale(centroid.z());
translate(-centroid.x(), -centroid.y());
background(255);
drawConnections();
drawCenters();
if (withSpick && (millis() - millis_moved > 5000)) spick();
}
void spick() {
p = physics.getParticle(int(random(physics.numberOfParticles())));
x_moved = p.position().x();
y_moved = p.position().y();
chi2_moved = chi2;
millis_moved = millis();
spicked = true;
float dx = deltaX / 1.5;
float dy = deltaY / 1.5;
p.moveBy(random(-dx, dx),random(-dy, dy), 0.0);
gray = gray_start;
}
void drawConnections() {
chi2 = 0.0;
noFill();
if (withLines) beginShape(LINES);
strokeWeight(1);
for (int i = 0; i < springs; ++i) {
Spring e = physics.getSpring(i);
Particle a = e.getOneEnd();
Particle b = e.getTheOtherEnd();
float dist = sqrt(sq(b.position().x()-a.position().x()) +
sq(b.position().y()-a.position().y()));
chi2 += sq((dist - distances[i]))/distances[i];
if (withLines) {
int g = min(255, max(0,round(255 - 255 * (gray / gray_start))));
stroke(g);
gray--;
int col2 = 188;
if (dist > distances[i]) {
stroke(255, col2, col2);
}
else {
stroke(col2, 255, col2);
}
if (dist < 1.25 * distances[i] && dist > (1.0 / 1.33) * distances[i]) stroke(244);
// all gray:
stroke(240);
vertex(a.position().x(), a.position().y());
vertex(b.position().x(), b.position().y());
}
}
if (withLines) endShape();
if (chi2 < chi2min) chi2min = chi2;
fill(0, 0, 200);
textSize(10);
}
void drawCenters() {
textSize(factor / initFactor * 14);
noStroke();
int r, g, b;
r = 0;
g = 0;
b = 0;
textAlign(LEFT);
for (int i = 0; i < nParties; i++) {
Particle v = physics.getParticle(i);
r = colors[i].getRed();
g = colors[i].getGreen();
b = colors[i].getBlue();
fill(r, g, b);
float nSize;
nSize = factor/initFactor * dot_size[i] * NODE_SIZE;
ellipse(v.position().x(), v.position().y(), nSize, nSize);
fill(0, 0, 0);
text(parteien[i], v.position().x() + nSize/3, v.position().y() - nSize/3);
}
stroke(0);
fill(255);
}
void updateCentroid() {
xMax = Float.NEGATIVE_INFINITY;
xMin = Float.POSITIVE_INFINITY;
yMin = Float.POSITIVE_INFINITY;
yMax = Float.NEGATIVE_INFINITY;
for (int i = 0; i < physics.numberOfParticles(); ++i) {
Particle p = physics.getParticle(i);
xMin = min(xMin, p.position().x());
xMax = max(xMax, p.position().x());
yMin = min(yMin, p.position().y());
yMax = max(yMax, p.position().y());
}
deltaX = xMax - xMin;
deltaY = yMax - yMin;
yMed = (yMax - yMin) / 2.0;
xLeft = xMin;
double ff = 0.03;
xMin -= ff * deltaX;
yMin -= ff * deltaY;
xMax += ff * deltaX;
yMax += ff * deltaY;
deltaX = fac * (xMax - xMin);
deltaY = fac * (yMax - yMin);
if ( deltaY > deltaX )
centroid.setTarget( xMin + 0.5f*deltaX, yMin +0.5f*deltaY, height/(deltaY+50) );
else
centroid.setTarget( xMin + 0.5f*deltaX, yMin +0.5f*deltaY, width/(deltaX+50) );
float scaleX = deltaX / width;
float scaleY = deltaY / height;
factor = max(scaleX, scaleY);
if (initFactor < 0) initFactor = factor;
}
void modifySprings(float exponent) {
expTotal = pow(expTotal, exponent);
println("exponent: " + expTotal);
for (int i = 0; i < springs; ++i) {
Spring e = physics.getSpring(i);
float rl = e.restLength();
e.setRestLength(pow(rl, exponent));
}
}
void setShuffle(float u) {
tremor = u;
}
void shuffle() {
if (tremor == 0) return;
if (tremor < 0) {
for (int i = 0; i < physics.numberOfParticles(); i++) {
Particle p = physics.getParticle(i);
float dx = noise(-tremor);
float dy = random(-tremor);
p.moveBy(dx, dy, 0.0);
}
}
else {
for (int i = 0; i < physics.numberOfParticles(); i++) {
Particle p = physics.getParticle(i);
float dx = random(tremor) - tremor / 2;
float dy = random(tremor) - tremor / 2;
p.moveBy(dx, dy, 0.0);
}
}
}
void keyPressed() {
switch(key) {
case '0':
setShuffle(0);
break;
case '1':
setShuffle(3);
break;
case '2':
setShuffle(-0.2);
break;
case '5':
setShuffle(50);
break;
case '9':
setShuffle(100);
break;
case 'r':
angle += PI / 32.0;
break;
case 'R':
angle -= PI / 32.0;
break;
case 'l':
case 'L':
withLines = !withLines;
break;
case 'y':
case 'Y':
withSpick = !withSpick;
if (withSpick) spick();
break;
case 'z':
case 'Z':
p = physics.getParticle(int(random(physics.numberOfParticles())));
p.moveBy(random(-400, 400),random(-400, 400), 0.0);
gray = gray_start;
break;
case ' ':
for (int i = 0; i < physics.numberOfParticles(); i++) {
p = physics.getParticle(i);
p.moveTo(random(width - 5), random(height - 5), 0.0);
gray = gray_start;
}
break;
case '+':
modifySprings(1.1);
break;
case '-':
modifySprings(1.0/1.1);
break;
}
}
void mouseReleased() {
return;
}
void mousePressed() {
// selection disabled
print(mouseX + "/" + mouseY + " ");
return;
}
static public String[] loadStrings(File file, String _enc) {
InputStream is = openStream(file);
if (is != null) return loadStrings(is, _enc);
return null;
}
public String[] loadStrings(String filename, String _enc) {
InputStream is = openStream(filename);
if (is != null) return loadStrings(is,_enc);
System.err.println("The file \"" + filename + "\" " +
"is missing or inaccessible, make sure " +
"the URL is valid or that the file has been " +
"added to your sketch and is readable.");
return null;
}
static public String[] loadStrings(InputStream input, String _enc)
{
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(input, _enc));
String lines[] = new String[100];
int lineCount = 0;
String line = null;
while ((line = reader.readLine()) != null) {
if (lineCount == lines.length) {
String temp[] = new String[lineCount << 1];
System.arraycopy(lines, 0, temp, 0, lineCount);
lines = temp;
}
lines[lineCount++] = line;
}
reader.close();
if (lineCount == lines.length) {
return lines;
}
// resize array to appropriate amount for these lines
String output[] = new String[lineCount];
System.arraycopy(lines, 0, output, 0, lineCount);
return output;
}
catch (IOException e) {
e.printStackTrace();
//throw new RuntimeException("Error inside loadStrings()");
}
return null;
}