====== Figures de Lichtenberg ====== Définition sur [[https://en.wikipedia.org/wiki/Lichtenberg_figure|Wikipedia]] En mode analogique : [[https://youtu.be/1jhqZg8UBJU?t=145|Dangerous! Electrifying Woodworking!]] Sinon d’autres renseignements : [[http://capturedlightning.com/frames/lichtenbergs.html|What are Lichtenberg figures, and how do we make them?]] [[https://images.wur.nl/digital/collection/coll13/search/page/1|Système racinaire]] ==== Illustration ==== {{media_07:hydrographie_france.jpg?400|}} ==== Théorie ==== [[http://paulbourke.net/fractals/dla/|DLA - Diffusion Limited Aggregation]] ===== Simulation ===== ==== Résultat ==== {{media_03:dla-002986.png?400|}} ==== Processing ==== ArrayList arbre; ArrayList marcheurs; int nombreMarcheurs = 2000; int rangMax = 0; void setup() { size(1600, 1000); arbre = new ArrayList(); arbre.add(new Marcheur(width / 2, height)); marcheurs = new ArrayList(); for (int i = 0; i < nombreMarcheurs; i++) { marcheurs.add(new Marcheur()); } } void draw() { background(0); for (int i = marcheurs.size() - 1; i >= 0; i--) { Marcheur m = marcheurs.get(i); m.rafraichir(); //m.afficher(rangMax); for (int j = 0; j < arbre.size(); j++) { Marcheur ma = arbre.get(j); if (m.position.dist(ma.position) < (2 * ma.rayon - 4)) { if (m.position.y < ma.position.y) { marcheurs.remove(m); m.rayon = ma.rayon * 0.97; m.rang = ma.rang + 1; m.parent = ma; if (m.rang > rangMax) { rangMax = m.rang; } arbre.add(m); break; } else { m.position = haut(); } } } } for (int i = arbre.size() - 1; i >= 0; i--) { Marcheur ma = arbre.get(i); ma.afficher(rangMax); } if (marcheurs.size() == 0) { affichageArbre(); println(rangMax); saveFrame("images/DLA-######.png"); noLoop(); } } void affichageArbre() { background(0); for (int j = 1; j < arbre.size(); j++) { Marcheur ma1 = arbre.get(j); Marcheur ma2 = ma1.parent; stroke(255); strokeWeight(ma2.rayon / 3.5); line(ma1.position.x, ma1.position.y, ma2.position.x, ma2.position.y); } } class Marcheur { PVector position; Marcheur parent; float rayon; int rang; Marcheur() { position = haut(); rayon = 15; rang = 0; } Marcheur(int x, int y) { position = new PVector(x, y); rayon = 30; rang = 0; } void rafraichir() { PVector vitesse = PVector.random2D().setMag(30); position.add(vitesse); position.x = constrain(position.x, 0, width); position.y = constrain(position.y, 0, height); } void afficher(int r) { noStroke(); int teinte = (int)map(rang, 0, r, 255, 10); fill(teinte); ellipse(position.x, position.y, 2 * rayon, 2 * rayon); } } PVector pourtour() { int a = (int)random(3); if (a == 0) { float r = random(width); return new PVector(r, 0); } else if (a == 1) { float t = random(height); return new PVector(0, t); } else { float u = random(width); return new PVector(width, u); } } PVector haut() { float r = random(width); return new PVector(r, 0); } float distSq(PVector a, PVector b) { float dx = b.x - a.x; float dy = b.y - a.y; return dx * dx + dy * dy; } ==== Processing 3D ==== Voici le code avec exportation .png et .stl : import java.io.*; import peasy.PeasyCam; PeasyCam cam; File repertoire; ArrayList arbre; ArrayList marcheurs; int nombreMarcheurs = 1000; int limite = 800; int rangMax = 0; public void settings() { size(1000, 1000, P3D); arbre = new ArrayList(); arbre.add(new Marcheur(0, 0, 0, limite)); marcheurs = new ArrayList(); for (int i = 0; i < nombreMarcheurs; i++) { marcheurs.add(new Marcheur(limite)); } } public void setup() { cam = new PeasyCam(this, 400); repertoire = new File(sketchPath()); } public void draw() { lights(); scale(1); rotateX(PI/2); background(0); for (int i = marcheurs.size() - 1; i >= 0; i--) { Marcheur m = marcheurs.get(i); m.rafraichir(); //m.afficher(1); for (int j = 0; j < arbre.size(); j++) { Marcheur ma = arbre.get(j); if (dist3DSq(m.position, ma.position) < (4 * ma.rayon * ma.rayon)) { if (m.position.z > ma.position.z) { marcheurs.remove(m); m.rayon = ma.rayon * 0.97; m.rang = ma.rang + 1; m.parent = ma; if (m.rang > rangMax) { rangMax = m.rang; } arbre.add(m); break; } else { m.position = pourtour(limite); } } } } affichageArbre(arbre); if (marcheurs.size() == 0) { println(rangMax); } } void affichageArbre(ArrayList a) { background(0); for (int j = 1; j < a.size(); j++) { Marcheur ma1 = a.get(j); Marcheur ma2 = ma1.parent; stroke(255); strokeWeight(ma2.rayon / 3.5); line(ma1.position.x, ma1.position.y, ma1.position.z, ma2.position.x, ma2.position.y, ma2.position.z); } } void keyPressed() { if (key == ' ') { saveFrame("images/DLA3D-######.png"); } if (key == 'e') { exporterSTL(arbre); } } void exporterSTL(ArrayList a) { String ligne = "["; for (int j = 1; j < a.size(); j++) { if (j != 1) { ligne += ","; } Marcheur ma1 = a.get(j); Marcheur ma2 = ma1.parent; String p1 = "[" + ma1.position.x + "," + ma1.position.y + "," + ma1.position.z + "]"; String p2 = "[" + ma2.position.x + "," + ma2.position.y + "," + ma2.position.z + "]"; ligne += "[[" + p1 + "," + ma1.rayon / 3.5 + "]," + "[" + p2 + "," + ma2.rayon / 3.5 + "]]"; } ligne += "]"; println(ligne); String[] cmd = {"/Applications/OpenSCAD.app/Contents/MacOS/OpenSCAD", "-o", "Arbre.stl", "-D", "u = " + ligne, "Arbre.scad"}; Process p; try { p = Runtime.getRuntime().exec(cmd, new String[0], repertoire); p.waitFor(); float error = p.exitValue(); println("Erreur = " + error); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } class Marcheur { PVector position; Marcheur parent; float rayon; int rang; int limite; Marcheur(int l) { limite = l; position = pourtour(limite); rayon = 15; rang = 0; } Marcheur(int x, int y, int z, int l) { limite = l; position = new PVector(x, y, z); rayon = 30; rang = 1; } void rafraichir() { PVector vitesse = PVector.random3D().setMag(30); position.add(vitesse); position.setMag(constrain(position.mag(), 0, limite)); } void afficher(int r) { noStroke(); int teinte = (int)map(rang, 0, r, 255, 10); fill(teinte); pushMatrix(); translate(position.x, position.y, position.z); sphere( 2 * rayon); popMatrix(); } } PVector pourtour(int l) { PVector v = PVector.random3D().setMag(l); v.z = abs(v.z); return v; } float dist3DSq(PVector a, PVector b) { float dx = b.x - a.x; float dy = b.y - a.y; float dz = b.z - a.z; return dx * dx + dy * dy + dz * dz; } Pour la partie OpenSACD de l'exportation .stl : $fn = 15; u = [[[[10, 10, 10], 30], [[30, 20, 40], 20]], [[[30, 20, 40], 20], [[60, 30, 45], 10]]]; for (i = [0:len(u) - 1]) { element(u[i]); } module element(e) { a = e[0]; b = e[1]; hull() { translate(a[0]) sphere(d = a[1]); translate(b[0]) sphere(d = b[1]); } } ==== Code ==== === Heightmap === [[https://forum.processing.org/two/discussion/25167/fly-over-a-heightmap-generated-landscape|v]] === Agrégation limitée par la diffusion (DLA) === [[https://medium.com/@jason.webb/simulating-dla-in-js-f1914eb04b1d|Simulating 2D diffusion-limited aggregation (DLA) with JavaScript]] [[https://thecodingtrain.com/CodingChallenges/034-dla.html|Diffusion-Limited Aggregation]] [[https://www.openprocessing.org/sketch/460864|Challenge #34: Diffusion-Limited Aggregation]] {{tag> processing sylvain}}