Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

added traer and original java sketches@

  • Loading branch information...
commit 706a51029b81dffe9bc1ed56bbd3ef46ab98a11d 1 parent 8e12182
Ray Brooks authored October 24, 2011
566  java/sketch_jul05.pde
... ...
@@ -0,0 +1,566 @@
  1
+import traer.physics.*;
  2
+import org.json.*;
  3
+import java.net.*;
  4
+import java.util.*;
  5
+import java.lang.*;
  6
+
  7
+import java.io.File;
  8
+import java.io.FileInputStream;
  9
+
  10
+final float NODE_SIZE = 10;
  11
+final float EDGE_LENGTH = 150;
  12
+final float EDGE_STRENGTH_MULT = 0.03;
  13
+final float SPACER_STRENGTH = 700;
  14
+
  15
+final int LOADINTERVAL = 10;
  16
+
  17
+final String JSONURL = "http://www.raymondbrooks.co.uk:8001/dump.json";
  18
+
  19
+ParticleSystem physics;
  20
+float scale = 1;
  21
+int translateX = 0;
  22
+int translateY = 0;
  23
+
  24
+boolean timerFlag = false;
  25
+
  26
+HashMap people = new HashMap();
  27
+//HashMap connections = new HashMap();
  28
+String[] myArray = new String[100];
  29
+
  30
+// PROCESSING /////////////////////////////////////
  31
+
  32
+FileInputStream fis = null;
  33
+
  34
+/******************************************************************************************
  35
+* Person class - viz - a node
  36
+******************************************************************************************/
  37
+
  38
+public class Person extends Particle {
  39
+	private String name;
  40
+	private ArrayList springs;
  41
+	private ArrayList forces;
  42
+	
  43
+	public Person(String n) {
  44
+		
  45
+		super();
  46
+		
  47
+		name = n;
  48
+  		
  49
+		set( random( -400, 400 ), random( -400, 400 ), 0 );
  50
+		
  51
+		springs = new ArrayList();
  52
+		forces = new ArrayList();
  53
+	}
  54
+		
  55
+	public String getName() {
  56
+		return name;
  57
+	}
  58
+	
  59
+	//replace getParticle with the classed object! EASY!
  60
+	public Particle getParticle() {
  61
+		return this;
  62
+	}
  63
+	
  64
+	//no need for this longer
  65
+	public void removeParticle() {
  66
+		physics.removeParticle(particle);
  67
+		particle = null;
  68
+	}
  69
+		
  70
+	public Spring getSpring(int i) {
  71
+		return (Spring)springs.get(i);
  72
+	}
  73
+	
  74
+	public int numSprings() {
  75
+		return springs.size();
  76
+	}
  77
+	
  78
+	//all springs, including foreign connections
  79
+	public int totalSprings() {
  80
+		return springs.size() + getOtherEnds().size();
  81
+	}
  82
+	
  83
+	public void addSpring(Person otherEnd, int strength) {
  84
+		println("making connection between " + getName() + " and " + otherEnd.getName());
  85
+		float edgeStrength = log(1 + strength) * EDGE_STRENGTH_MULT;
  86
+		Spring spring = physics.makeSpring(this, otherEnd, edgeStrength, 0, EDGE_LENGTH);
  87
+		println("adding spring strength " + strength);
  88
+		springs.add(spring);
  89
+	}
  90
+		
  91
+	synchronized public ArrayList getOtherEnds() {
  92
+		ArrayList otherEnds = new ArrayList();
  93
+		
  94
+		HashMap ppl = new HashMap(people);
  95
+		Iterator users = ppl.keySet().iterator();
  96
+	  
  97
+		while (users.hasNext()) {
  98
+			Person p = (Person)ppl.get(users.next().toString());
  99
+			for (int i = 0; i < p.numSprings(); i++) {
  100
+				if (p.getSpring(i).getTheOtherEnd() == particle) {
  101
+					otherEnds.add(p.getName());
  102
+				}
  103
+			}
  104
+		}
  105
+				
  106
+		return otherEnds;
  107
+	}
  108
+	
  109
+	public void addForce(Particle otherEnd) {
  110
+		forces.add(physics.makeAttraction( particle, otherEnd, -SPACER_STRENGTH, 20 ));
  111
+	}
  112
+	
  113
+	void setMass() {
  114
+		particle.setMass(1);
  115
+	}
  116
+	
  117
+	public void addReactions(JSONObject connections, JSONObject listdata) {
  118
+
  119
+		springs = new ArrayList();
  120
+		forces = new ArrayList();
  121
+		
  122
+		Iterator users = connections.keys();
  123
+		while (users.hasNext()) {
  124
+			
  125
+			int strength = 1;
  126
+			
  127
+			Person p = (Person) people.get(users.next().toString());
  128
+						
  129
+			try {
  130
+				strength = connections.getInt(p.getName());
  131
+				try {
  132
+					JSONObject conn = listdata.getJSONObject(p.getName());
  133
+					strength += conn.getInt(name);
  134
+				} catch (JSONException e) {
  135
+					//There should probably be some better exception handling here...
  136
+					println ("inside +" + e.toString());
  137
+				}
  138
+				
  139
+			} catch (JSONException e) {
  140
+				//There should probably be some better exception handling here...
  141
+				println ("inside +" + e.toString());
  142
+			}
  143
+			if (name.equals(p.getName()) == false && getOtherEnds().indexOf(name) < 0) {
  144
+				addSpring(p, strength);
  145
+			}
  146
+		}
  147
+		
  148
+		users = people.keySet().iterator();
  149
+	  
  150
+		while (users.hasNext()) {
  151
+			Person p = (Person)people.get(users.next().toString());
  152
+			addForce(p);
  153
+
  154
+		}
  155
+
  156
+		return;
  157
+	}
  158
+	
  159
+	public void removeReactions() {
  160
+		for (int i = 0; i  < springs.size(); i++) {
  161
+			physics.removeSpring((Spring)springs.get(i));
  162
+			springs.remove(i);
  163
+		}
  164
+				
  165
+		for (int i = 0; i  < forces.size(); i++) {
  166
+			physics.removeAttraction((Attraction)forces.get(i));
  167
+			forces.remove(i);
  168
+		}
  169
+	}
  170
+	
  171
+}
  172
+
  173
+
  174
+/******************************************************************************************
  175
+* Read the JSON data from the web server
  176
+******************************************************************************************/
  177
+
  178
+JSONObject pullJSON(String targetURL) {
  179
+	String jsonTxt = "";   //String to hold the json txt
  180
+	JSONObject retVal = new JSONObject();  //return val
  181
+	InputStream  in = null;                //Data from the URL
  182
+	
  183
+	//Connect to the URL and pull  the json data into a string
  184
+	try {
  185
+		URL url = new URL(targetURL);          //Create the URL
  186
+		in = url.openStream();                 //Get a stream to it
  187
+		byte[] buffer = new byte[8192];
  188
+		int bytesRead;
  189
+		while ( (bytesRead = in.read(buffer)) != -1) {
  190
+			String outStr = new String(buffer, 0, bytesRead);
  191
+			jsonTxt += outStr;
  192
+		}
  193
+		in.close();
  194
+	} catch (Exception e) {
  195
+		//There should probably be some better exception handling here...
  196
+		System.out.println (e);
  197
+	}
  198
+	
  199
+	//Now convert to a JSON object
  200
+	try {
  201
+		retVal = new JSONObject(jsonTxt);
  202
+	} catch (JSONException e) {
  203
+		//There should probably be some better exception handling here...
  204
+		println (e.toString());
  205
+	}
  206
+	
  207
+	return retVal;  // Return the json object
  208
+}
  209
+
  210
+/******************************************************************************************
  211
+* Read the JSON data from a file
  212
+******************************************************************************************/
  213
+
  214
+JSONObject pullJSONFromFile(String fileName) {
  215
+	String jsonTxt = "";   //String to hold the json txt
  216
+	JSONObject retVal = new JSONObject();  //return val
  217
+	
  218
+	println("got filename " + fileName);
  219
+	
  220
+	File file = new File(fileName);
  221
+	FileInputStream fis = null;
  222
+	BufferedInputStream bis = null;
  223
+	DataInputStream dis = null;
  224
+	
  225
+	try {
  226
+		fis = new FileInputStream(file);
  227
+		
  228
+		// Here BufferedInputStream is added for fast reading.
  229
+		bis = new BufferedInputStream(fis);
  230
+		dis = new DataInputStream(bis);
  231
+	
  232
+		// dis.available() returns 0 if the file does not have more lines.
  233
+		while (dis.available() != 0) {
  234
+		  // this statement reads the line from the file and print it to
  235
+		  // the console.
  236
+		  jsonTxt += dis.readLine();
  237
+		}
  238
+	  
  239
+		println(jsonTxt);
  240
+	
  241
+		// dispose all the resources after using them.
  242
+		fis.close();
  243
+		bis.close();
  244
+		dis.close();
  245
+	} catch (FileNotFoundException e) {
  246
+		e.printStackTrace();
  247
+	} catch (IOException e) {
  248
+		e.printStackTrace();
  249
+	}
  250
+    
  251
+	//Now convert to a JSON object
  252
+	try {
  253
+		retVal = new JSONObject(jsonTxt);
  254
+	} catch (JSONException e) {
  255
+		println (e.toString());
  256
+		//There should probably be some better exception handling here...
  257
+	}
  258
+	return retVal;  // Return the json object
  259
+}
  260
+
  261
+/******************************************************************************************
  262
+* Timer class - to read the data from the sever
  263
+* Nicked and modified from http://www.exampledepot.com/egs/java.util/ScheduleRepeat.html
  264
+******************************************************************************************/
  265
+
  266
+public class loadJSONTimer extends TimerTask {  
  267
+	private int timerInterval;
  268
+	
  269
+	public loadJSONTimer(int timeInterval) {
  270
+		this.timerInterval=timeInterval * 1000;
  271
+	}
  272
+
  273
+	public void run() {
  274
+		reloadJSON();
  275
+	}
  276
+}
  277
+
  278
+/******************************************************************************************
  279
+* Processing directives
  280
+******************************************************************************************/
  281
+
  282
+void setup() {
  283
+	size( 1000, 1000 );
  284
+	smooth();
  285
+	strokeWeight( 1 );
  286
+	ellipseMode( CENTER );       
  287
+	
  288
+	physics = new ParticleSystem( 0, 0.1 );
  289
+	//physics.setIntegrator( ParticleSystem.MODIFIED_EULER ); 
  290
+	physics.setDrag( 0.5 );
  291
+	//physics.setGravity( 1.0 );
  292
+	textFont( loadFont( "URWGothicL-Demi-10.vlw" ) );
  293
+
  294
+	physics.clear();
  295
+	
  296
+	Particle centre = physics.makeParticle(10, 0, 0, 0);
  297
+	centre.makeFixed();
  298
+	
  299
+	java.util.Timer t1 = new java.util.Timer();
  300
+	loadJSONTimer tt = new loadJSONTimer(0);
  301
+	t1.schedule(tt, 0, LOADINTERVAL * 1000);
  302
+	
  303
+	background( 0 );
  304
+	fill( 128 );
  305
+	updateCentroid();
  306
+		
  307
+}
  308
+
  309
+void draw()
  310
+{
  311
+
  312
+		background( 0 );
  313
+		fill( 128 );
  314
+		text( "" + (physics.numberOfParticles() - 1) + " USERS\n" + (int)frameRate + " FPS", 10, 20 );
  315
+		text( "+/left mouse - zoom in\n-/right mouse - zoom out\na / middle mouse - autocentre/centre", 10, 50 );
  316
+
  317
+		translate(translateX, translateY);
  318
+		scale( scale );
  319
+		
  320
+		drawNetwork();
  321
+		if ( physics.numberOfParticles() > 1 ) {
  322
+			
  323
+			HashMap ppl = new HashMap(people);
  324
+			Iterator users;
  325
+			users = ppl.keySet().iterator();
  326
+			fill(255);
  327
+			
  328
+			while (users.hasNext()) {
  329
+				Person u = (Person)ppl.get(users.next().toString());
  330
+				if (u.totalSprings() > 0) {
  331
+					text(u.getName(), u.position().x() + 10, u.position().y() + 4);
  332
+				}
  333
+			}
  334
+		}
  335
+
  336
+
  337
+		doTick();		
  338
+}
  339
+
  340
+synchronized void doTick() {
  341
+	physics.tick();
  342
+}
  343
+
  344
+synchronized void drawNetwork() {      
  345
+	
  346
+		HashMap ppl = new HashMap(people);
  347
+		Iterator users;
  348
+
  349
+		if (true) {
  350
+			stroke( 64 );
  351
+			
  352
+			beginShape( LINES );
  353
+			
  354
+			users = ppl.keySet().iterator();
  355
+			
  356
+			while (users.hasNext()) {
  357
+				Person u = (Person)ppl.get(users.next().toString());
  358
+				for (int i = 0; i < u.numSprings(); i++) { 
  359
+					Spring e = u.getSpring( i );
  360
+					strokeWeight( e.strength() / EDGE_STRENGTH_MULT);
  361
+					Particle a = e.getOneEnd();
  362
+					Particle b = e.getTheOtherEnd();
  363
+					vertex( a.position().x(), a.position().y() );
  364
+					vertex( b.position().x(), b.position().y() );
  365
+				}
  366
+			}
  367
+			
  368
+			endShape();
  369
+			
  370
+			strokeWeight( 1 );
  371
+		}
  372
+		
  373
+		// draw vertices
  374
+		if (true) {
  375
+			noStroke();
  376
+			
  377
+			users = ppl.keySet().iterator();
  378
+			fill( 192, 192, 0 );
  379
+		  
  380
+			while (users.hasNext()) {
  381
+				Person u = (Person)ppl.get(users.next().toString());
  382
+				if (u.totalSprings() > 0) {
  383
+					ellipse( u.position().x(), u.position().y(), NODE_SIZE * sqrt(u.totalSprings() + 1), NODE_SIZE * sqrt(u.totalSprings() + 1));
  384
+				}
  385
+			}
  386
+		}
  387
+	  
  388
+		/*if (false) {
  389
+			users = ppl.keySet().iterator();
  390
+			fill(255);
  391
+			
  392
+			while (users.hasNext()) {
  393
+				Person u = (Person)ppl.get(users.next().toString());
  394
+				if (u.totalSprings() > 0) {
  395
+					Particle p = u.getParticle();
  396
+					text(u.getName(), p.position().x() + 10, p.position().y() + 4);
  397
+				}
  398
+			}
  399
+		}*/
  400
+		
  401
+}
  402
+
  403
+void keyPressed()
  404
+{
  405
+  	if (key == '+') {
  406
+  		scale += 0.2;
  407
+  	} else if (key == '-') {
  408
+  		scale -= 0.2;
  409
+  	} else if (key == 'a') {
  410
+  		updateCentroid();
  411
+  		translate( width/2 , height/2 );
  412
+  		scale(scale);
  413
+		translate( translateX, translateY );
  414
+  	}
  415
+}
  416
+
  417
+void mousePressed() {
  418
+	println (mouseButton);
  419
+	if (mouseButton == 37) {
  420
+		translateX -= (int)(mouseX - width / 2);
  421
+		translateY -= (int)(mouseY - height / 2);
  422
+		scale += 0.2;
  423
+	} else if (mouseButton == 39) {
  424
+		translateX -= (int)(mouseX - width / 2);
  425
+		translateY -= (int)(mouseY - height / 2);
  426
+		scale -= 0.2;
  427
+	} else if (mouseButton == 3) {
  428
+		translateX -= (int)(mouseX - width / 2);
  429
+		translateY -= (int)(mouseY - height / 2);
  430
+	}
  431
+}
  432
+
  433
+void mouseButton() {
  434
+}
  435
+
  436
+void mouseDragged() {
  437
+		
  438
+	
  439
+}
  440
+
  441
+synchronized void updateCentroid()
  442
+{
  443
+	float 
  444
+		xMax = Float.NEGATIVE_INFINITY, 
  445
+		xMin = Float.POSITIVE_INFINITY, 
  446
+		yMin = Float.POSITIVE_INFINITY, 
  447
+		yMax = Float.NEGATIVE_INFINITY;
  448
+
  449
+	Iterator users = people.keySet().iterator();
  450
+	  
  451
+	while (users.hasNext()) {
  452
+		Person u = (Person)people.get(users.next().toString());
  453
+		if (u.numSprings() > 0 || u.getOtherEnds().size() > 0) {
  454
+			xMax = max( xMax, u.position().x() ) + 5;
  455
+			xMin = min( xMin, u.position().x() );
  456
+			yMin = min( yMin, u.position().y() );
  457
+			yMax = max( yMax, u.position().y() );
  458
+		}
  459
+	}
  460
+	
  461
+	
  462
+	float deltaX = xMax-xMin;
  463
+	float deltaY = yMax-yMin;
  464
+	
  465
+	translateX = (int)(xMin + 0.5*deltaX + width / 2);
  466
+	translateY = (int)(yMin +0.5*deltaY + height / 2);
  467
+  
  468
+	if ( deltaY > deltaX ) {
  469
+		scale = height/(deltaY+50);
  470
+	} else {
  471
+		scale = width/(deltaX+50);
  472
+	}
  473
+}
  474
+
  475
+HashMap getNetworks() {
  476
+	//find individual networks
  477
+	//and return a hashmap of string arrays
  478
+	HashMap networks = new HashMap();
  479
+	
  480
+	return networks;
  481
+	
  482
+}
  483
+
  484
+synchronized void reloadJSON() { // add the task here
  485
+		JSONObject listdata = pullJSON(JSONURL);
  486
+		//JSONObject listdata = pullJSONFromFile("/www/node/js-bin/twitter/data/dump.json");
  487
+		
  488
+		//println("Loading data from: " + System.getProperty("user.home") + "/dump.json");
  489
+		//JSONObject listdata = pullJSONFromFile(System.getProperty("user.home") + "/dump.json");
  490
+	  
  491
+		//now we must:
  492
+
  493
+		//set fl;ag to avoid concurrency exception
  494
+		
  495
+		timerFlag = true;
  496
+		
  497
+		//1. add any new nodes
  498
+
  499
+		Iterator users = listdata.keys();
  500
+		
  501
+	
  502
+		while (users.hasNext()) {
  503
+			String user = users.next().toString();
  504
+				if (!people.containsKey(user)) {
  505
+					println("adding " + user);
  506
+					people.put(user, new Person(user));
  507
+				}
  508
+		}
  509
+		
  510
+		//2. remove connections
  511
+		
  512
+		users = listdata.keys();
  513
+		
  514
+		while (users.hasNext()) {
  515
+			String user = users.next().toString();
  516
+			Person p = (Person)people.get(user);
  517
+			p.removeReactions();
  518
+		}
  519
+	
  520
+		//3. make springs and add repulsive force
  521
+
  522
+		users = people.keySet().iterator();
  523
+
  524
+		println("making springs, adding repulsion");
  525
+		
  526
+		while (users.hasNext()) {
  527
+			String user = users.next().toString();
  528
+			Person p = (Person)people.get(user);
  529
+			try {
  530
+				//we replace the string array with a hashmap of hashmaps!
  531
+				//this will totally affect 
  532
+				JSONObject connections = listdata.getJSONObject(p.getName());
  533
+				
  534
+				p.addReactions(connections, listdata);
  535
+			} catch (JSONException e) {
  536
+				println(e.toString());
  537
+			}
  538
+		}
  539
+	
  540
+		//4. add mass and remove unused users
  541
+		
  542
+		ArrayList toRemove = new ArrayList();
  543
+		users = people.keySet().iterator();
  544
+		
  545
+		while (users.hasNext()) {
  546
+			String user = users.next().toString();
  547
+			Person p = (Person)people.get(user);
  548
+			if (p.totalSprings() <= 0) {
  549
+				println("removing unused user " + p.getName());
  550
+				p.removeReactions();
  551
+				p.removeParticle();
  552
+				//people.remove(user);
  553
+				toRemove.add(user);
  554
+			} else {
  555
+				p.setMass();
  556
+			}
  557
+		}
  558
+		
  559
+		//avoid concurrency!
  560
+		for (int i = 0; i < toRemove.size(); i++) {
  561
+			String user = (String)toRemove.get(i);
  562
+			people.remove(user);
  563
+		}
  564
+				
  565
+		timerFlag = false;
  566
+}
520  js/traer.js
... ...
@@ -0,0 +1,520 @@
  1
+/**
  2
+ * traer.js
  3
+ * A particle-based physics engine ported from Jeff Traer's Processing library to JavaScript. This version is intended for use with the HTML5 canvas element.
  4
+ *
  5
+ * @author Adam Saponara <saponara TA gmail TOD com> (JavaScript port)
  6
+ * @author Jeffrey Traer Bernstein <jeff TA traer TOD cc> (original Java library)
  7
+ * @version 0.2
  8
+ * @date August 8, 2010
  9
+ *
  10
+ */
  11
+
  12
+
  13
+/**
  14
+ * A 3-dimensional vector representation with common vector operations
  15
+ */
  16
+function Vector() {
  17
+	var argc = arguments.length;
  18
+	if (argc == 3) {
  19
+		this.x = arguments[0];
  20
+		this.y = arguments[1];
  21
+		this.z = arguments[2];
  22
+	}
  23
+	else if (argc == 1) {
  24
+		this.x = arguments[0].x;
  25
+		this.y = arguments[0].y;
  26
+		this.z = arguments[0].z;
  27
+	}
  28
+	else {
  29
+		this.x = 0;
  30
+		this.y = 0;
  31
+		this.z = 0;
  32
+	}
  33
+}
  34
+Vector.prototype.set = function() {
  35
+	var argc = arguments.length;
  36
+	if (argc == 3) {
  37
+		this.x = arguments[0];
  38
+		this.y = arguments[1];
  39
+		this.z = arguments[2];
  40
+	}
  41
+	else if (argc == 1) {
  42
+		this.x = arguments[0].x;
  43
+		this.y = arguments[0].y;
  44
+		this.z = arguments[0].z;
  45
+	}
  46
+}
  47
+Vector.prototype.add = function(v) {
  48
+	var argc = arguments.length;
  49
+	if (argc == 3) {
  50
+		this.x += arguments[0];
  51
+		this.y += arguments[1];
  52
+		this.z += arguments[2];
  53
+	}
  54
+	else if (argc == 1) {
  55
+		this.x += arguments[0].x;
  56
+		this.y += arguments[0].y;
  57
+		this.z += arguments[0].z;
  58
+	}
  59
+}
  60
+Vector.prototype.substract = function(v) {
  61
+	var argc = arguments.length;
  62
+	if (argc == 3) {
  63
+		this.x -= arguments[0];
  64
+		this.y -= arguments[1];
  65
+		this.z -= arguments[2];
  66
+	}
  67
+	else if (argc == 1) {
  68
+		this.x -= arguments[0].x;
  69
+		this.y -= arguments[0].y;
  70
+		this.z -= arguments[0].z;
  71
+	}
  72
+}
  73
+Vector.prototype.scale = function(f) { this.x *= f; this.y *= f; this.z *= f; }
  74
+Vector.prototype.distanceTo = function() { 
  75
+	var argc = arguments.length;
  76
+	if (argc == 3) {
  77
+		var dx = this.x - arguments[0];
  78
+		var dy = this.y - arguments[1];
  79
+		var dz = this.z - arguments[2];
  80
+		return Math.sqrt(dx*dx + dy*dy + dz*dz);
  81
+	}
  82
+	else if (argc == 1) {
  83
+		return Math.sqrt(this.distanceSquaredTo(v))
  84
+	}
  85
+}
  86
+Vector.prototype.distanceSquaredTo = function(v) {
  87
+	var dx = this.x - v.x;
  88
+	var dy = this.y - v.y;
  89
+	var dz = this.z - v.z;
  90
+	return dx*dx + dy*dy + dz*dz;
  91
+}
  92
+Vector.prototype.dot = function(v) { return this.x*v.x + this.y*v.y + this.z*v.z; }
  93
+Vector.prototype.length = function() { return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); }
  94
+Vector.prototype.lengthSquared = function() { return this.x*this.x + this.y*this.y + this.z*this.z; }
  95
+Vector.prototype.clear = function() { this.x = 0; this.y = 0; this.z = 0; }
  96
+Vector.prototype.toString = function() { return '('+this.x+','+this.y+','+this.z+')'; }
  97
+Vector.prototype.cross = function(v) {
  98
+	return new Vector(
  99
+		this.y*v.z - this.z*v.y,
  100
+		this.x*v.z - this.z*v.x,
  101
+		this.x*v.y - this.y*v.x
  102
+	);
  103
+}
  104
+Vector.prototype.isZero = function() {
  105
+	return this.x === 0 && this.y === 0 && this.z === 0;
  106
+}
  107
+
  108
+
  109
+/**
  110
+ * A particle with position, velocity, and force vectors and mass
  111
+ */
  112
+function Particle(mass) {
  113
+	this.position = new Vector();
  114
+	this.velocity = new Vector();
  115
+	this.force = new Vector();
  116
+	this.mass = mass;
  117
+	this.fixed = false;
  118
+	this.age = 0;
  119
+	this.dead = false;
  120
+}
  121
+Particle.prototype.distanceTo = function(p) { return this.position().distanceTo(p.position()); }
  122
+Particle.prototype.makeFixed = function() { this.fixed = true; this.velocity.clear(); }
  123
+Particle.prototype.reset = function() {
  124
+	this.age = 0;
  125
+	this.dead = false;
  126
+	this.position.clear();
  127
+	this.velocity.clear();
  128
+	this.force.clear();
  129
+	this.mass = 1.0;
  130
+}
  131
+
  132
+
  133
+/**
  134
+ * A force between two particles based on a spring constant
  135
+ */
  136
+function Spring(a, b, k, d, l) {
  137
+	this.constant = k;
  138
+	this.damping = d;
  139
+	this.length = l;
  140
+	this.a = a;
  141
+	this.b = b;
  142
+	this.on = true;
  143
+}
  144
+Spring.prototype.currentLength = function() { return this.a.position().distanceTo(this.b.position()); }
  145
+Spring.prototype.apply = function() {
  146
+
  147
+	var a = this.a;
  148
+	var b = this.b;
  149
+	if (!(this.on && (!a.fixed || !b.fixed))) return;
  150
+
  151
+	var a2bx = a.position.x - b.position.x;
  152
+	var a2by = a.position.y - b.position.y;
  153
+	var a2bz = a.position.z - b.position.z;
  154
+
  155
+	var a2bd = Math.sqrt(a2bx*a2bx + a2by*a2by + a2bz*a2bz);
  156
+	if (a2bd == 0) {
  157
+		a2bx = 0;
  158
+		a2by = 0;
  159
+		a2bz = 0;
  160
+	}
  161
+	else {
  162
+		a2bx /= a2bd;
  163
+		a2by /= a2bd;
  164
+		a2bz /= a2bd;
  165
+	}
  166
+
  167
+	var fspring = -1 * (a2bd - this.length) * this.constant;
  168
+
  169
+	var va2bx = a.velocity.x - b.velocity.x;
  170
+	var va2by = a.velocity.y - b.velocity.y;
  171
+	var va2bz = a.velocity.z - b.velocity.z;
  172
+
  173
+	var fdamping = -1 * this.damping * (a2bx*va2bx + a2by*va2by + a2bz*va2bz);
  174
+
  175
+	var fr = fspring + fdamping;
  176
+
  177
+	a2bx *= fr;
  178
+	a2by *= fr;
  179
+	a2bz *= fr;
  180
+
  181
+	if (!a.fixed) a.force.add(a2bx, a2by, a2bz);
  182
+	if (!b.fixed) b.force.add(-1 * a2bx, -1 * a2by, -1 * a2bz);
  183
+
  184
+}
  185
+
  186
+/**
  187
+ * Applies physics rules to a collection of particles
  188
+ */
  189
+function ParticleSystem() {
  190
+
  191
+	this.particles = [];
  192
+	this.springs = [];
  193
+	this.attractions = [];
  194
+	this.forces = [];
  195
+	this.integrator = new RungeKuttaIntegrator(this);
  196
+	this.hasDeadParticles = false;
  197
+
  198
+	var argc = arguments.length;
  199
+	if (argc == 2) {
  200
+		this.gravity = new Vector(0, arguments[0], 0);
  201
+		this.drag = arguments[1];
  202
+	}
  203
+	else if (argc == 4) {
  204
+		this.gravity = new Vector(arguments[0], arguments[1], arguments[2]);
  205
+		this.drag = arguments[3];
  206
+	}
  207
+	else {
  208
+		this.gravity = new Vector(0, ParticleSystem.DEFAULT_GRAVITY, 0);
  209
+		this.drag = ParticleSystem.DEFAULT_DRAG;
  210
+	}
  211
+}
  212
+ParticleSystem.DEFAULT_GRAVITY = 0;
  213
+ParticleSystem.DEFAULT_DRAG = 0.001;
  214
+/**
  215
+ * @todo Implement other integrators
  216
+
  217
+ParticleSystem.RUNGE_KUTTA = 0;
  218
+ParticleSystem.EULER = 1;
  219
+ParticleSystem.MODIFIED_EULER = 2;
  220
+
  221
+ParticleSystem.prototype.setIntegrator = function(integrator) {
  222
+	switch (integrator) {
  223
+		case ParticleSystem.RUNGE_KUTTA:
  224
+			this.integrator = new RungeKuttaIntegrator(this);
  225
+			break;
  226
+		case ParticleSystem.EULER:
  227
+			this.integrator = new EulerIntegrator(this);
  228
+			break;
  229
+		case ParticleSystem.MODIFIED_EULER:
  230
+			this.integrator = new ModifiedEulerIntegrator(this);
  231
+			break;
  232
+	}
  233
+}
  234
+ */
  235
+ParticleSystem.prototype.setGravity = function () {
  236
+	var argc = arguments.length;
  237
+	if (argc == 1) {
  238
+		this.gravity.set(0, arguments[0], 0);
  239
+	}
  240
+	else if (argc == 3) {
  241
+		this.gravity.set(arguments[0], arguments[1], arguments[2]);
  242
+	}
  243
+}
  244
+ParticleSystem.prototype.tick = function() {
  245
+	this.integrator.step(arguments.length == 0 ? 1 : arguments[0]);
  246
+}
  247
+ParticleSystem.prototype.makeParticle = function() {
  248
+	var mass = 1.0;
  249
+	var x = 0;
  250
+	var y = 0;
  251
+	var z = 0;
  252
+	if (arguments.length == 4) {
  253
+		mass = arguments[0];
  254
+		x = arguments[1];
  255
+		y = arguments[2];
  256
+		z = arguments[3];
  257
+	}
  258
+	var p = new Particle(mass);
  259
+	p.position.set(x, y, z);
  260
+	this.particles.push(p);
  261
+	return p;
  262
+}
  263
+ParticleSystem.prototype.makeSpring = function(a, b, k, d, l) {
  264
+	var s = new Spring(a, b, k, d, l);
  265
+	this.springs.push(s);
  266
+	return s;
  267
+}
  268
+ParticleSystem.prototype.makeAttraction = function(a, b, k, d) {
  269
+	var m = new Attraction(a, b, k, d);
  270
+	this.attractions.push(m);
  271
+	return m;
  272
+}
  273
+ParticleSystem.prototype.clear = function() {
  274
+	this.particles.clear();
  275
+	this.springs.clear();
  276
+	this.attractions.clear();
  277
+}
  278
+ParticleSystem.prototype.applyForces = function() {
  279
+
  280
+	var t;
  281
+
  282
+	if (!this.gravity.isZero()) {
  283
+		for (var i = 0; i < this.particles.length; i++) {
  284
+			t = this.particles[i];
  285
+			t.force.add(this.gravity);
  286
+		}
  287
+	}
  288
+
  289
+	for (var i = 0; i < this.particles.length; i++) {
  290
+		t = this.particles[i];
  291
+		t.force.add(t.velocity.x * -1 * this.drag, t.velocity.y * -1 * this.drag, t.velocity.z * -1 * this.drag);
  292
+	}
  293
+
  294
+	for (var i = 0; i < this.springs.length; i++) {
  295
+		t = this.springs[i];
  296
+		t.apply();
  297
+	}
  298
+
  299
+	for (var i = 0; i < this.attractions.length; i++) {
  300
+		t = this.attractions[i];
  301
+		t.apply();
  302
+	}
  303
+
  304
+	for (var i = 0; i < this.forces.length; i++) {
  305
+		t = this.forces[i];
  306
+		t.apply();
  307
+	}
  308
+
  309
+}
  310
+ParticleSystem.prototype.clearForces = function() {
  311
+	for (var i = 0; i < this.particles.length; i++) {
  312
+		this.particles[i].clear();
  313
+	}
  314
+}
  315
+
  316
+/**
  317
+ * Fourth-order integration approximator
  318
+ */
  319
+function RungeKuttaIntegrator(s) {
  320
+	this.s = s;
  321
+	this.originalPositions = [];
  322
+	this.originalVelocities = [];
  323
+	this.k1Forces = [];
  324
+	this.k1Velocities = [];
  325
+	this.k2Forces = [];
  326
+	this.k2Velocities = [];
  327
+	this.k3Forces = [];
  328
+	this.k3Velocities = [];
  329
+	this.k4Forces = [];
  330
+	this.k4Velocities = [];
  331
+}
  332
+RungeKuttaIntegrator.prototype.allocateParticles = function() {
  333
+	while (this.s.particles.length > this.originalPositions.length) {
  334
+		this.originalPositions.push(new Vector());
  335
+		this.originalVelocities.push(new Vector());
  336
+		this.k1Forces.push(new Vector());
  337
+		this.k1Velocities.push(new Vector());
  338
+		this.k2Forces.push(new Vector());
  339
+		this.k2Velocities.push(new Vector());
  340
+		this.k3Forces.push(new Vector());
  341
+		this.k3Velocities.push(new Vector());
  342
+		this.k4Forces.push(new Vector());
  343
+		this.k4Velocities.push(new Vector());
  344
+	}
  345
+}
  346
+RungeKuttaIntegrator.prototype.step = function (deltaT) {
  347
+	var s = this.s;
  348
+	var p;
  349
+
  350
+	this.allocateParticles();
  351
+
  352
+	for (var i = 0; i < s.particles.length; i++) {
  353
+		p = s.particles[i];
  354
+		if (!p.fixed) {
  355
+			this.originalPositions[i].set(p.position);
  356
+			this.originalVelocities[i].set(p.velocity);
  357
+		}
  358
+		p.force.clear();	// and clear the forces
  359
+	}
  360
+
  361
+	////////////////////////////////////////////////////////
  362
+	// get all the k1 values
  363
+
  364
+	s.applyForces();
  365
+
  366
+	// save the intermediate forces
  367
+	for (var i = 0; i < s.particles.length; i++) {
  368
+		p = s.particles[i];
  369
+		if (!p.fixed) {
  370
+			this.k1Forces[i].set(p.force);
  371
+			this.k1Velocities[i].set(p.velocity);
  372
+		}
  373
+
  374
+		p.force.clear();
  375
+	}
  376
+
  377
+	////////////////////////////////////////////////////////////////
  378
+	// get k2 values
  379
+
  380
+	for (var i = 0; i < s.particles.length; i++) {
  381
+		p = s.particles[i];
  382
+		if (!p.fixed) {
  383
+			var originalPosition = this.originalPositions[i];
  384
+			var k1Velocity = this.k1Velocities[i];
  385
+			p.position.x = originalPosition.x + k1Velocity.x * 0.5 * deltaT;
  386
+			p.position.y = originalPosition.y + k1Velocity.y * 0.5 * deltaT;
  387
+			p.position.z = originalPosition.z + k1Velocity.z * 0.5 * deltaT;
  388
+			var originalVelocity = this.originalVelocities[i];
  389
+			var k1Force = this.k1Forces[i];
  390
+			p.velocity.x = originalVelocity.x + k1Force.x * 0.5 * deltaT / p.mass;
  391
+			p.velocity.y = originalVelocity.y + k1Force.y * 0.5 * deltaT / p.mass;
  392
+			p.velocity.z = originalVelocity.z + k1Force.z * 0.5 * deltaT / p.mass;
  393
+		}
  394
+	}
  395
+
  396
+	s.applyForces();
  397
+
  398
+	// save the intermediate forces
  399
+	for (var i = 0; i < s.particles.length; i++) {
  400
+		p = s.particles[i];
  401
+		if (!p.fixed) {
  402
+			this.k2Forces[i].set(p.force);
  403
+			this.k2Velocities[i].set(p.velocity);
  404
+		}
  405
+		p.force.clear();	// and clear the forces now that we are done with them
  406
+	}
  407
+
  408
+
  409
+	/////////////////////////////////////////////////////
  410
+	// get k3 values
  411
+
  412
+	for (var i = 0; i < s.particles.length; i++) {
  413
+		p = s.particles[i];
  414
+		if (!p.fixed) {
  415
+			var originalPosition = this.originalPositions[i];
  416
+			var k2Velocity = this.k2Velocities[i];
  417
+			p.position.x = originalPosition.x + k2Velocity.x * 0.5 * deltaT;
  418
+			p.position.y = originalPosition.y + k2Velocity.y * 0.5 * deltaT;
  419
+			p.position.z = originalPosition.z + k2Velocity.z * 0.5 * deltaT;
  420
+			var originalVelocity = this.originalVelocities[i];
  421
+			var k2Force = this.k2Forces[i];
  422
+			p.velocity.x = originalVelocity.x + k2Force.x * 0.5 * deltaT / p.mass;
  423
+			p.velocity.y = originalVelocity.y + k2Force.y * 0.5 * deltaT / p.mass;
  424
+			p.velocity.z = originalVelocity.z + k2Force.z * 0.5 * deltaT / p.mass;
  425
+		}
  426
+	}
  427
+
  428
+	s.applyForces();
  429
+
  430
+	// save the intermediate forces
  431
+	for (var i = 0; i < s.particles.length; i++) {
  432
+		p = s.particles[i];
  433
+		if (!p.fixed) {
  434
+			this.k3Forces[i].set(p.force);
  435
+			this.k3Velocities[i].set(p.velocity);
  436
+		}
  437
+		p.force.clear();	// and clear the forces now that we are done with them
  438
+	}
  439
+
  440
+
  441
+	//////////////////////////////////////////////////
  442
+	// get k4 values
  443
+	for (var i = 0; i < s.particles.length; i++) {
  444
+		p = s.particles[i];
  445
+		if (!p.fixed) {
  446
+			var originalPosition = this.originalPositions[i];
  447
+			var k3Velocity = this.k3Velocities[i];
  448
+			p.position.x = originalPosition.x + k3Velocity.x * deltaT;
  449
+			p.position.y = originalPosition.y + k3Velocity.y * deltaT;
  450
+			p.position.z = originalPosition.z + k3Velocity.z * deltaT;
  451
+			var originalVelocity = this.originalVelocities[i];
  452
+			var k3Force = this.k3Forces[i];
  453
+			p.velocity.x = originalVelocity.x + k3Force.x * deltaT / p.mass;
  454
+			p.velocity.y = originalVelocity.y + k3Force.y * deltaT / p.mass;
  455
+			p.velocity.z = originalVelocity.z + k3Force.z * deltaT / p.mass;
  456
+		}
  457
+	}
  458
+
  459
+	s.applyForces();
  460
+
  461
+	// save the intermediate forces
  462
+	for (var i = 0; i < s.particles.length; i++) {
  463
+		p = s.particles[i];
  464
+		if (!p.fixed) {
  465
+			this.k4Forces[i].set(p.force);
  466
+			this.k4Velocities[i].set(p.velocity);
  467
+		}
  468
+	}
  469
+
  470
+	/////////////////////////////////////////////////////////////
  471
+	// put them all together and what do you get?
  472
+
  473
+	for (var i = 0; i < s.particles.length; i++) {
  474
+
  475
+		p = s.particles[i];
  476
+		p.age += deltaT;
  477
+		if (p.fixed) continue;
  478
+
  479
+		// update position
  480
+		var originalPosition = this.originalPositions[i];
  481
+		var k1Velocity = this.k1Velocities[i];
  482
+		var k2Velocity = this.k2Velocities[i];
  483
+		var k3Velocity = this.k3Velocities[i];
  484
+		var k4Velocity = this.k4Velocities[i];
  485
+		p.position.x = originalPosition.x + deltaT / 6.0 * (k1Velocity.x + 2.0*k2Velocity.x + 2.0*k3Velocity.x + k4Velocity.x);
  486
+		p.position.y = originalPosition.y + deltaT / 6.0 * (k1Velocity.y + 2.0*k2Velocity.y + 2.0*k3Velocity.y + k4Velocity.y);
  487
+		p.position.z = originalPosition.z + deltaT / 6.0 * (k1Velocity.z + 2.0*k2Velocity.z + 2.0*k3Velocity.z + k4Velocity.z);
  488
+
  489
+		// update velocity
  490
+		var originalVelocity = this.originalVelocities[i];
  491
+		var k1Force = this.k1Forces[i];
  492
+		var k2Force = this.k2Forces[i];
  493
+		var k3Force = this.k3Forces[i];
  494
+		var k4Force = this.k4Forces[i];
  495
+		p.velocity.x = originalVelocity.x + deltaT / (6.0 * p.mass) * (k1Force.x + 2.0*k2Force.x + 2.0*k3Force.x + k4Force.x);
  496
+		p.velocity.y = originalVelocity.y + deltaT / (6.0 * p.mass) * (k1Force.y + 2.0*k2Force.y + 2.0*k3Force.y + k4Force.y);
  497
+		p.velocity.z = originalVelocity.z + deltaT / (6.0 * p.mass) * (k1Force.z + 2.0*k2Force.z + 2.0*k3Force.z + k4Force.z);
  498
+	}
  499
+}
  500
+
  501
+
  502
+/**
  503
+ * remove method of Array type
  504
+ * @param o    If a number, removes the corresponding index. Else, removes any elements that match parameter in type & value.
  505
+ */
  506
+Array.prototype.remove = function(o) {
  507
+	if (typeof o == 'number') {
  508
+		this.splice(o, 1);
  509
+	}
  510
+	else {
  511
+		var tokill = [];
  512
+		for (var i = 0; i < this.length; i++) {
  513
+			if (this[i] === o) {
  514
+				this.remove(i);
  515
+				i--;
  516
+			}
  517
+		}
  518
+	}
  519
+
  520
+}

0 notes on commit 706a510

Please sign in to comment.
Something went wrong with that request. Please try again.