Curious about Jeremy’s animated version I found no jar in the lib, but here is an abstract of the code.
/**
* RecursorTriangle
* 2020-03-20 Jeremy Douglass - Processing 3.4
* Progressively animate a recursive Sierpinski Triangle.
* Press space to restart.
*/
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
void setup() {
size(600, 550);
smooth();
noStroke();
colorMode(HSB, 360, 100, 100);
// seed
rq.add(new CallST(0, 450, 400, 0, 500, 550, 8));
background(0, 0, 40);
}
void draw() {
rq.stepUntil(3, 0);
}
void keyReleased() {
if (key==' ') { // reset
rq.clear();
frameCount=-1;
}
}
RecursorQueue rq = new RecursorQueue<CallST>() {
public ArrayList<CallST> recurse(CallST call) {
return call.recurse();
}
};
class CallST {
float x1, y1, x2, y2, x3, y3;
int n;
CallST(float x1, float y1, float x2,
float y2, float x3, float y3, int n) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.x3 = x3;
this.y3 = y3;
this.n = n;
}
ArrayList<CallST> recurse() {
ArrayList<CallST> calls = new ArrayList<CallST>();
if ( n > 0 ) {
int h = (110+n*(360/8))%360;
fill(h, 100, 100);
triangle(x1, y1, x2, y2, x3, y3);
// calculate segment midpoints
float h1 = (x1+x2)/2.0;
float w1 = (y1+y2)/2.0;
float h2 = (x2+x3)/2.0;
float w2 = (y2+y3)/2.0;
float h3 = (x3+x1)/2.0;
float w3 = (y3+y1)/2.0;
// call three subtriangles at corners
calls.add(new CallST(x1, y1, h1, w1, h3, w3, n-1));
calls.add(new CallST(h1, w1, x2, y2, h2, w2, n-1));
calls.add(new CallST(h3, w3, h2, w2, x3, y3, n-1));
}
return calls;
}
}
public enum Mode {
FIRST, LAST, EITHER;
private static final Mode[] VALUES = values();
private static final Random RANDOM = new Random();
/**
* @return Returns either FIRST or LAST, randomly.
*/
public static Mode either() {
return VALUES[RANDOM.nextInt(2)];
}
/**
* @return Returns any one of FIRST, LAST, EITHER.
*/
public static Mode random() {
return VALUES[RANDOM.nextInt(VALUES.length)];
}
}
public class RecursorQueue<E> extends LinkedList<E> {
private static final long serialVersionUID = -3584631587915680024L;
/** Running count of calls added to the queue since initialize or reset(). */
private int adds;
/** Running count of calls popped off the queue since initialize or reset(). */
private int pops;
private int addsLast;
private int popsLast;
/** Mode for add operations: FIRST, LAST, EITHER. */
public Mode addMode;
/** Mode for pop operations: FIRST, LAST, EITHER. */
public Mode popMode;
public RecursorQueue() {
super();
this.popMode = Mode.FIRST;
this.addMode = Mode.LAST;
}
public RecursorQueue( Mode addMode, Mode popMode) {
super();
this.addMode = addMode;
this.popMode = popMode;
}
public ArrayList<E> recurse(E call) {
ArrayList<E> result = new ArrayList<E>();
// result.add(call);
return result;
}
public int getAdds() {
return adds;
}
public int getPops() {
return pops;
}
public void resetCounts() {
pops = 0;
adds = 0;
popsLast = 0;
addsLast = 0;
}
public void shuffle() {
Collections.shuffle(this);
}
public E step() {
return step(this.popMode, this.addMode);
}
public E step(Mode popMode, Mode addMode) {
// pop from first or last end of deque
if(popMode==Mode.EITHER) popMode = Mode.either();
E call = (popMode==Mode.FIRST) ? this.removeFirst() : this.removeLast();
pops++;
ArrayList<E> calls = recurse(call);
// add to first or last end of deque
if(addMode==Mode.EITHER) addMode = Mode.either();
if(addMode==Mode.FIRST) {
for (int i=0; i<calls.size(); i++) {
this.addFirst(calls.get(i));
}
} else {
for (int i=0; i<calls.size(); i++) {
this.addLast(calls.get(i));
}
}
adds += calls.size();
return call;
}
public int[] stepAll() {
return stepUntil(0, 0, popMode, addMode);
}
public int[] stepUntil(int popMax, int addCheck) {
return stepUntil(popMax, addCheck, popMode, addMode);
}
public int[] stepUntil(int popMax, int addCheck, Mode popMode, Mode addMode) {
// offset current counts
this.popsLast = this.pops;
this.addsLast = this.adds;
int popsStop = popMax + popsLast;
int addsStop = addCheck + addsLast;
//System.out.println(popMax +" "+ pops +" "+ addCheck +" "+ adds +" "+ this.isEmpty());
while ((popMax==0 || pops<popsStop) && (addCheck==0 || adds<addsStop) && !this.isEmpty()) {
step(popMode, addMode);
}
return new int[] {getPopsLast(), getAddsLast()};
}
public int getAddsLast() {
return adds-addsLast;
}
public int getPopsLast() {
return pops-popsLast;
}
public String status() {
return "pop,add[ " + popMode + "," + addMode + " ] cnt[ " + pops + "," + adds + " ] chg[ " + getPopsLast() + "," + getAddsLast() + " ] size[" + size() + "]";
}
public String toString() {
return getClass().getName() + "" + status();
}
}