import processing.core.*; import traer.physics.*; import traer.animation.*; import processing.net.*; import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; public class domaingraph extends PApplet {// Domain visualization graph for YaCy
// by Michael Christen
//
// this applet uses code and the physics engine from
// http://www.cs.princeton.edu/~traer/physics/
// from Jeffrey Traer Bernstein
// redistribution is granted according to forum posting in
// http://processing.org/discourse/yabb_beta/YaBB.cgi?board=os_libraries_tools;action=display;num=1139193613
final static float NODE_SIZE = 6;
final static float EDGE_LENGTH = 30;
final static float EDGE_STRENGTH = 0.001f;
final static float SPACER_STRENGTH = 250;
ParticleSystem physics;
Smoother3D centroid;
PFont font;
float x = 0.0f;
float y = 0.0f;
float z = 1.0f;
Client myClient;
Particle center0, center1; // two gravity centers to support object ordering for non-quadratic fields
String parsingHostName = "";
String parsingHostID = "";
HashMap nodes = new HashMap(); // map that holds host objects
String host;
int port;
float a = 0.0f;
long lastUpdate = Long.MAX_VALUE;
boolean initTime = true;
public void setup() {
String[] fontList = PFont.list();
//println(fontList);
font = createFont(fontList[0], 32); //just take any, should be mostly Arial
textFont(font, 9);
size(660, 400);
smooth();
frameRate( 6 );
strokeWeight( 1 );
ellipseMode( CENTER );
physics = new ParticleSystem( 0, 0.25f );
centroid = new Smoother3D( 0.8f );
initializePhysics();
URL url = null;
try {
url = getDocumentBase();
} catch (final NullPointerException e) {}
if (url == null) {
host="localhost";
port=8090;
} else {
host=url.getHost();
port=url.getPort();
}
//println("CodeBase: " + url);
//println("host: " + host);
//println("port: " + port);
initRequest(false);
}
public void initializePhysics() {
physics.clear();
center0 = physics.makeParticle(1.0f, -EDGE_LENGTH * 10, 0, 0);
center0.makeFixed();
center1 = physics.makeParticle(1.0f, EDGE_LENGTH * 10, 0, 0);
center1.makeFixed();
centroid.setValue( 0, 0, 1.0f );
}
public void draw() {
processRequestResponse(50);
physics.tick( 1.0f );
HashSet invisible = invisibleParticles();
deleteParticles(invisible);
if (physics.numberOfParticles() > 1) updateCentroid(invisible);
centroid.tick();
background( 0 );
translate( width/2 , height/2 );
scale( centroid.z() );
translate( -centroid.x(), -centroid.y() );
drawNetwork();
}
public void initRequest(boolean update) {
myClient = new Client(this, host, port);
myClient.write((update) ? "GET /api/webstructure.xml?latest= HTTP/1.1\n" : "GET /xml/webstructure.xml HTTP/1.1\n");
myClient.write("Host: localhost\n\n");
}
public void processRequestResponse(int steps) {
if (((myClient == null) || (myClient.available() <= 0)) && (System.currentTimeMillis() - lastUpdate > 10000)) {
initRequest(true);
lastUpdate = Long.MAX_VALUE;
return;
}
for (int i = 0; i < steps; i++) {
if (myClient.available() > 0) {
String line = myClient.readStringUntil((byte) 10);
//println("Line: " + line);
if (line == null) line = ""; else line = line.trim();
/*
<domain host="www.oreilly.com" id="-1po3Y" date="20090510">
<reference id="uU2r5Q" count="2">www.catb.org</reference>
<reference id="zG43kY" count="516">oreilly.com</reference>
<reference id="QEf_LZ" count="44">www.oreillynet.com</reference>
</domain>
*/
int p = line.indexOf("<domain",0);
if (p >= 0) {
//println("domain :" + line.substring(p + 8, line.length() - 1).trim());
processDomain(parseProps(line.substring(p + 8, line.length() - 1).trim()));
}
p = line.indexOf("<reference",0);
if (p >= 0) {
int q = line.indexOf("</reference>",0);
if (q > 0) {
int r = line.lastIndexOf('>', q);
if (r > 0) {
String refhost = line.substring(r, q);
//println("reference:" + line.substring(p + 11, r).trim());
processCitation(refhost, parseProps(line.substring(p + 11, r).trim()));
}
}
}
lastUpdate = System.currentTimeMillis();
} else {
initTime = false;
}
}
}
public void processDomain(HashMap props) {
//println("Domain: " + props.toString());
parsingHostName = (String) props.get("host"); if (parsingHostName == null) parsingHostName = "";
parsingHostID = (String) props.get("id"); if (parsingHostID == null) parsingHostID = "";
host h = (host) nodes.get(parsingHostID);
if (h != null) {
h.time = System.currentTimeMillis();
return;
}
h = new host(parsingHostName, physics.makeParticle(1.0f, EDGE_LENGTH * 20 * cos(a), -EDGE_LENGTH * 10 * sin(a), 0));
a += TWO_PI/256.0f + TWO_PI / 2; if (a > TWO_PI) a -= TWO_PI;
nodes.put(parsingHostID, h);
addAttraction(h.node);
}
public void processCitation(String host, HashMap props) {
//println("Citation: " + props.toString());
String id = (String) props.get("id"); if (id == null) id = "";
try {
String counts = (String) props.get("count"); if (counts != null) count = Integer.parseInt(counts);
} catch (final NumberFormatException e) {}
// find the two nodes that have a relation
host h = (host) nodes.get(id);
if (h == null) {
return; /*
h = new host(host, physics.makeParticle(1.0, EDGE_LENGTH * 20 * cos(a), -EDGE_LENGTH * 10 * sin(a), 0));
a += TWO_PI/256.0 + TWO_PI / 2; if (a > TWO_PI) a -= TWO_PI;
nodes.put(id, h);
addAttraction(h.node);*/
}
h.time = System.currentTimeMillis();
host p = (host) nodes.get(parsingHostID); // this should be successful
if (p == null) return;
// prevent that a spring is made twice
for ( int i = 0; i < physics.numberOfSprings(); ++i ) {
Spring e = physics.getSpring(i);
Particle a = e.getOneEnd();
Particle b = e.getTheOtherEnd();
if (((a == h.node) && (b == p.node)) || ((b == h.node) && (a == p.node))) return;
}
physics.makeSpring(h.node, p.node, EDGE_STRENGTH, EDGE_STRENGTH, EDGE_LENGTH );
}
public HashMap parseProps(String s) {
String[] l = CommonPattern.SPACE.split(s);
HashMap map = new HashMap();
int p;
String z;
for (int i = 0; i < l.length; i++) {
p = l[i].indexOf('=',0);
if (p > 0) {
z = l[i].substring(p + 1).trim();
if (z.length() > 0 && z.charAt(0) == '"') z = z.substring(1);
if (z.charAt(z.length() - 1) == '"') z = z.substring(0, z.length() - 1);
map.put(l[i].substring(0, p), z);
}
}
return map;
}
public HashSet invisibleParticles() {
// get nodes that have no edges
HashSet particles = new HashSet();
Iterator j = nodes.values().iterator();
host h;
long t = 0, n = System.currentTimeMillis();
while (j.hasNext()) {
h = (host) j.next();
t += n - h.time;
particles.add(h.node);
}
t = t / (nodes.size() + 1);
for ( int i = 0; i < physics.numberOfSprings(); ++i ) {
Spring e = physics.getSpring(i);
particles.remove(e.getOneEnd());
particles.remove(e.getTheOtherEnd());
}
// add more nodes if the number is too large
if (nodes.size() > 80) {
j = nodes.values().iterator();
while (j.hasNext()) {
h = (host) j.next();
if (n - h.time > 15000) particles.add(h.node);
if (nodes.size() - particles.size() < 80) break;
}
}
return particles;
}
public void deleteParticles(HashSet particles) {
Iterator j = nodes.values().iterator();
host h;
while (j.hasNext()) {
h = (host) j.next();
if (particles.contains(h.node)) {
h.node.kill();
j.remove();
}
}
}
public void drawNetwork() {
// draw vertices
fill( 120, 255, 120 );
noStroke();
String name;
host h;
Iterator j = nodes.values().iterator();
while (j.hasNext()) {
h = (host) j.next();
Particle v = h.node;
ellipse(v.position().x(), v.position().y(), NODE_SIZE, NODE_SIZE);
name = h.name;
text(name, v.position().x() - (name.length() * 26 / 10), v.position().y() + 14);
}
// draw center
//fill( 255, 0, 0 );
//ellipse( center0.position().x(), center0.position().y(), NODE_SIZE * 2, NODE_SIZE * 2 );
//ellipse( center1.position().x(), center1.position().y(), NODE_SIZE * 2, NODE_SIZE * 2 );
// draw edges
stroke( 200 );
for ( int i = 0; i < physics.numberOfSprings(); ++i ) {
Spring e = physics.getSpring( i );
Particle a = e.getOneEnd();
Particle b = e.getTheOtherEnd();
line(a.position().x(), a.position().y(), b.position().x(), b.position().y());
}
}
public void keyPressed() {
if ( key == 'c' ) initializePhysics();
if ( key == 'a' ) x = Math.max(-1.0f, x - 0.1f);
if ( key == 'd' ) x = Math.min( 1.0f, x + 0.1f);
if ( key == 'w' ) y = Math.max(-1.0f, y - 0.1f);
if ( key == 's' ) y = Math.min( 1.0f, y + 0.1f);
if ( key == '-' ) z = Math.max( 1.0f, z - 1.0f);
if ( key == '+' ) z = Math.min(10.0f, z + 1.0f);
if ( key == '0' ) { x = 0.0f; y = 0.0f; z = 1.0f; }
if ( key == 't' ) {
HashSet hs = new HashSet();
for (int i = 0; i < physics.numberOfParticles(); ++i ) {
hs.add(physics.getParticle(i));
}
for (int i = 0; i < physics.numberOfSprings(); ++i ) {
hs.remove(physics.getSpring(i).getOneEnd());
hs.remove(physics.getSpring(i).getTheOtherEnd());
}
Iterator i = hs.iterator();
while (i.hasNext()) {
((Particle) i.next()).kill();
}
return;
}
}
public void updateCentroid(HashSet invisible) {
float
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);
if ((i >= 2) && ((p == center0) || (p == center1) || (invisible.contains(p)))) continue;
xMax = max( xMax, p.position().x() );
xMin = min( xMin, p.position().x() );
yMin = min( yMin, p.position().y() );
yMax = max( yMax, p.position().y() );
}
float deltaX = xMax-xMin;
float deltaY = yMax-yMin;
centroid.setTarget(
xMin + (x + 1) * 0.5f * deltaX,
yMin + (y + 1) * 0.5f * deltaY,
z * ((deltaY > deltaX) ? height / (deltaY + 50) : width / (deltaX + 50))
);
}
public void addAttraction(Particle p) {
physics.makeAttraction(center0, p, SPACER_STRENGTH * 10000.0f, 100 * EDGE_LENGTH);
physics.makeAttraction(center1, p, SPACER_STRENGTH * 10000.0f, 100 * EDGE_LENGTH);
// spacers
for ( int i = 0; i < physics.numberOfParticles(); ++i ) {
Particle q = physics.getParticle( i );
if (p != q) physics.makeAttraction( p, q, -SPACER_STRENGTH, 20);
}
}
static class host {
String name;
Particle node;
long time;
public host(String name, Particle node) {
this.name = name;
this.node = node;
this.time = System.currentTimeMillis();
}
}
static public void main(String args[]) { PApplet.main(new String[] { "domaingraph" }); }}