@paulgoux Speculatively tried to translate a @solub Wolfram Physics Sketch to run in vanilla processing. Here I offer you the CircleGrowth sketch (that I had previously translated to JRubyArt). To do this I created a small library class to help with java array operations (not all functions are used in the sketch):-
package monkstone.utils;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
*
* @author tux
*/
public class ArrayOps {
/**
* Return true if number num is appeared only once in the array num is
* unique.
*
* @param array
* @param num
* @return
*/
public static boolean isUnique(int[] array, int num) {
for (int i = 0; i < array.length; i++) {
if (array[i] == num) {
return false;
}
}
return true;
}
/**
* Convert the given array to an array with unique values without duplicates
* and returns it.
*
* @param array
* @return
*/
public static int[] toUniqueArray(int[] array) {
int[] temp = new int[array.length];
for (int i = 0; i < temp.length; i++) {
temp[i] = -1; // in case u have value of 0 in the array
}
int counter = 0;
for (int i = 0; i < array.length; i++) {
if (isUnique(temp, array[i])) {
temp[counter++] = array[i];
}
}
int[] uniqueArray = new int[counter];
System.arraycopy(temp, 0, uniqueArray, 0, uniqueArray.length);
return uniqueArray;
}
/**
*
* @param array
* @return
*/
public static int numberOfUniques(int[] array) {
int count = 1;
Arrays.sort(array);
for (int i = 1; i < array.length - 1; i++) {
if (array[i] != array[i + 1]) {
count++;
}
}
return count;
}
/**
*
* @param array
* @return
*/
public static int[] flatten(int[][] array) {
IntStream stream = Stream.of(array) // returns Stream<int[]>
.flatMapToInt(Arrays::stream);
return stream.toArray();
}
/**
*
* @param input
* @param index
* @return
*/
public static int[][] removeElementAt(int[][] input, int index) {
if (input == null || index < 0 || index > input.length) {
return input;
}
int[][] result = new int[input.length - 1][2];
int count = 0;
for (int i = 0; i < input.length; i++) {
if (i != index) {
result[count] = input[i];
count++;
}
}
return result;
}
/**
*
* @param input
* @param index
* @return
*/
public static int[] removeElementAt(int[] input, int index) {
if (input == null || index < 0 || index > input.length) {
return input;
}
return IntStream.range(0, input.length)
.filter(i -> i != index)
.map(i -> input[i]).toArray();
}
/**
*
* @param origin array of nodes
* @param other array of nodes
* @return array of nodes
*/
public static int[][] mergeArray(int[][] origin, int[][] other) {
int first = origin.length;
int second = other.length;
int[][] result = new int[first + second][2];
System.arraycopy(origin, 0, result, 0, first);
System.arraycopy(other, 0, result, first, second);
return result;
}
}
Here’s the sketch (for processing 4.0, only because I use a lambda expression, rather than a for loop)
import processing.core.*;
import toxi.geom.*;
import toxi.physics2d.*;
import toxi.physics2d.behaviors.*;
import monkstone.utils.ArrayOps;
int[][] axiom = {{0, 1}, {0, 2}, {1, 2}};
int[] flata;
int z;
VerletPhysics2D physics;
int uniqueCount;
void setup() {
size(1000, 600);
flata = ArrayOps.flatten(axiom);
z = max(flata) + 1;
physics = new VerletPhysics2D();
physics.setDrag(0.2f);
uniqueCount = ArrayOps.numberOfUniques(flata);
for (int i = 0; i < uniqueCount; i++) {
VerletParticle2D p = new VerletParticle2D(
Vec2D.randomVector().add(new Vec2D(width / 2, height / 2))
);
physics.addParticle(p);
physics.addBehavior(new AttractionBehavior2D(p, 10, -0.5f));
}
for (int[] node : axiom) {
VerletParticle2D p1 = physics.particles.get(node[0]);
VerletParticle2D p2 = physics.particles.get(node[1]);
VerletSpring2D s = new VerletSpring2D(p1, p2, 10, -0.5f);
physics.addSpring(s);
}
}
void draw() {
background(0xffffffff);
stroke(0);
physics.update();
int id = PApplet.parseInt(random(z));
int[] node = axiom[id];
axiom = ArrayOps.removeElementAt(axiom, id);
int[][] temp = {{node[1], z}, {z, node[0]}};
axiom = ArrayOps.mergeArray(axiom, temp);
// Manage physics accordingly
VerletParticle2D px = physics.particles.get(node[0]); //coordinate of node x
VerletParticle2D py = physics.particles.get(node[1]); //coordinate of node y
VerletParticle2D pz = new VerletParticle2D(px.add(py).scale(0.5f)); //create a new particle in between
VerletSpring2D s = physics.getSpring(px, py); // find spring between the deleted edge
physics.removeSpring(s); // remove that spring
physics.addParticle(pz); // add particle
physics.addBehavior(new AttractionBehavior2D(pz, 10, -0.5f)); // attach a repulsion behavior to it
VerletSpring2D s1 = new VerletSpring2D(py, pz, 4, 0.5f); // create spring between 1st new edge
VerletSpring2D s2 = new VerletSpring2D(pz, px, 4, 0.5f); // create spring between 2nd new edge
physics.addSpring(s1); // add them to physics
physics.addSpring(s2);
z += 1; //increment 'z'
physics.springs.forEach(sp -> {
line(sp.a.x(), sp.a.y(), sp.b.x(), sp.b.y());
});
}