# Recursive Sierpinski triangle (just a bit of fun)

**URL:** <https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546>\
**Category:** Gallery\
**Created:** [August 29, 2020, 10:54am UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546 "2020-08-29T10:54:41Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [September 2, 2020, 11:24pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/41 "2020-09-02T23:24:35Z")

</div>

What fun!

A while ago I wrote a small recursion library for animated recursion.

> [@Update screen during draw() without thread?](https://discourse.processing.org/t/update-screen-during-draw-without-thread/18599/5):
>
> If you want to be able to render progressively from an unbounded recursive process in a single thread – and don’t want to use thread() – then there are ways. I mentioned a linked data structure that acts as a recursion queue. I actually have a draft library I wrote that does that – “Recursor”. Supposing you start out with a basic recursive function that cannot be animated. It looks like this: void tree(float[] seg) { line(seg[0], seg[1], seg[0]+seg[2], seg[1]+seg[3]); PVector s = new PV…

It has an animated recursive serpinski triangle demo:

![export-714](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/3/3e262ec22cd8bcaef985591ea4a978ba6aa00694.gif)

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 11:01am UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/42 "2020-09-03T11:01:54Z")

</div>

> [@raron](#):
>
> Here: _link_

Ahh I was just searching for Sierpinski triangle (simple).  
So, while there I just posted this as well. Very simple.

```auto
void setup() {
  size(410, 230);
  background(255);
  fill(0);
  triangle (10, 25, 100, 5);
}
 
void triangle (int x, int y, int l, int n) {
    if( n == 0) text("*", x, y);
    else {
        triangle(x, y+l, l/2, n-1);
        triangle(x+l, y, l/2, n-1);
        triangle(x+l*2, y+l, l/2, n-1);
    }
}

```

![sp](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/950d7475868b00ba984e785791c94de1f80055e7.png)

---

<div class="post-metadata">

**Author:** ![raron](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/raron/32/13651_2.png) [@raron](https://discourse.processing.org/u/raron)\
**Post date:** [September 3, 2020, 11:15am UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/43 "2020-09-03T11:15:40Z")

</div>

> [@noel](#):
>
> So, while there I just posted this as well. Very simple.

Nice one!

(\>=20 character posts)

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 11:22am UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/44 "2020-09-03T11:22:23Z")

</div>

> [@raron](#):
>
> (\>=20 character posts)

Just…

---

<div class="post-metadata">

**Author:** ![raron](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/raron/32/13651_2.png) [@raron](https://discourse.processing.org/u/raron)\
**Post date:** [September 3, 2020, 12:18pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/45 "2020-09-03T12:18:30Z")

</div>

> [@noel](#):
>
> Just…

Odd. It’s just that it complained my post was too short.

Anyway, my tetrahedron wasn’t quite symmetrical it turns out. The top was a bit off 😳

Brushed up a bit on geometry, hoping this is better:

```auto
// 3D Sierpinski tetrahedron vertices
PVector [] coord = {
  new PVector( 0, 0, 0), 
  new PVector( 300, 0, 0), 
  new PVector( 150, 0, -260), 
  new PVector( 150, -245, -86.6)
};

// "random" start point (mid point)
PVector startPoint = new PVector(150, 183.7, 173.2);

```

Tried to keep startPoint in the middle, which it now should be (after translating it into view).

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 12:41pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/46 "2020-09-03T12:41:14Z")

</div>

> [@raron](#):
>
> Brushed up a bit on geometry, hoping this is better:

Yes, nice.  
And thanks for posting on the Rosetta page. Jeremy already said that it was a good idea to post the strict version and an animated && || 3d as well. So maybe you want to do that?  
b.t.w I meant keep typing points and at the end only three will be shown.

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 1:39pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/47 "2020-09-03T13:39:19Z")

</div>

Curious about Jeremy’s animated version I found no jar in the lib, but here is an abstract of the code.

```auto
/**
 * 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();
  }
}

```

---

<div class="post-metadata">

**Author:** ![raron](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/raron/32/13651_2.png) [@raron](https://discourse.processing.org/u/raron)\
**Post date:** [September 3, 2020, 2:21pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/48 "2020-09-03T14:21:10Z")

</div>

> [@noel](#):
>
> Jeremy already said that it was a good idea to post the strict version and an animated && || 3d as well. So maybe you want to do that?

Sure, I can try! By “strict version” I guess a minimalistic one? Like the one I posted, but I think it can be improved a bit.

> [@noel](#):
>
> b.t.w I meant keep typing points and at the end only three will be shown.

Ah, got it!

---

<div class="post-metadata">

**Author:** ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)\
**Post date:** [September 3, 2020, 3:55pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/49 "2020-09-03T15:55:00Z")

</div>

Here’s a video of the Sierpinski sketch JRubyArt ContextFreeArt DSL on [YouTube](https://youtu.be/LLabqx4LTdU).

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 5:17pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/50 "2020-09-03T17:17:34Z")

</div>

Good, but what does take the biggest part of the 30 seconds start-to-play time?

---

<div class="post-metadata">

**Author:** ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)\
**Post date:** [September 3, 2020, 5:41pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/51 "2020-09-03T17:41:19Z")

</div>

I guess it’s the DSL, basically all the intermediate steps are calculated. Which is why when loaded the response to slider is relatively quick, there is a lot of recursion (similar to [cfdg](https://www.contextfreeart.org/) but that has the benefit of being written in C++). Nevertheless it is a bit of fun to create a DSL, and because it is not entirely symmetric (unlike cfdg) it can lead to some [interesting results](https://github.com/monkstone/cf3ruby).

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 6:02pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/52 "2020-09-03T18:02:04Z")

</div>

I see. I also discovered that discourse does not count a link as visited when you right-click it to open in a new window. That explains for me now, people responding to a topic as if they had visited the link, but without really showing that as ‘visit-count’ sum.  
Another annoying thing is, that every time I post here, I get the message,  
“It could be better if you gave other people space to share their points of view, too.”  
Really intimidating

---

<div class="post-metadata">

**Author:** ![monkstone](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/monkstone/32/64_2.png) [@monkstone](https://discourse.processing.org/u/monkstone)\
**Post date:** [September 3, 2020, 6:10pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/53 "2020-09-03T18:10:13Z")

</div>

Naah just ignore it like I do, otherwise there’s no chance of building an interesting thread. In the older forums there was a lot more interesting discussions, but here we get drowned out by newbie questions.

---

<div class="post-metadata">

**Author:** ![raron](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/raron/32/13651_2.png) [@raron](https://discourse.processing.org/u/raron)\
**Post date:** [September 3, 2020, 6:22pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/54 "2020-09-03T18:22:34Z")

</div>

> [@noel](#):
>
> So, while there I just posted this as well. Very simple.

I un-simplified it a bit, made it gradual. It’s rather “wasteful” though, going through all the recursions all the time even if not plotting.

Space key resets (as in jeremydouglass’ example).

```auto
int depth = 5;
int interval = 10;

int currentTime;
int lastTime;
int progress = 0;
int lastProgress = 0;
//int finished = int(pow(3,depth));
boolean intervalExpired = false;

void setup() {
  size(410, 230);
  background(255);
  fill(0);
  lastTime = millis();
}

void draw() {
  currentTime = millis();
  triangle (10, 25, 100, depth);
}

 
void triangle (int x, int y, int l, int n) {
  if( n == 0) {
    checkIfIntervalExpired();
    if (intervalExpired) {
      if (progress == lastProgress) {
        text("*", x, y);
        lastProgress++;
        intervalExpired = false;
      }
    }
    progress++;
  } else {
      triangle(x, y+l, l/2, n-1);
      triangle(x+l, y, l/2, n-1);
      triangle(x+l*2, y+l, l/2, n-1);
  }
}

void checkIfIntervalExpired() {
  if (currentTime-lastTime > interval) {
    lastTime = currentTime;
    progress = 0;
    intervalExpired = true;
  }
}

void keyReleased() {  
  if (key==' ') { // reset
    progress = 0;
    lastProgress = 0;
    background(255);
  }
}

```

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 3, 2020, 6:54pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/55 "2020-09-03T18:54:03Z")

</div>

Nice, we can add it as an animated version! 😃

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [September 5, 2020, 4:01am UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/56 "2020-09-05T04:01:08Z")

</div>

The [Chaos Game](https://en.wikipedia.org/wiki/Chaos_game) is actually very interesting! I found a very nice code on the old forum by @noahbuddy using the triangle. For the easy of copying I will post it here.

```auto
int N = 3; // Number of control points
int MAX_DIST = 60;
int MANY_TIMES = 2000;
float DIV = 2.0; // You can change the rules for drawing the pattern
 
// Control points
float[] px = new float[N];
float[] py = new float[N];
 
// The moving point, draws the pattern
float selx = 0;
float sely = 0;
 
boolean held = false;
int nearest = -1;
 
void setup()
{
  size(800,600,P2D);
 
  // Initial points, anywhere you like
  px[0] = width/4;
  py[0] = height/4;
  px[1] = width - (width/4);
  py[1] = height/4;
  px[2] = width - (width/4);
  py[2] = height - (height/4);
 
  noFill();
  frameRate(60);
  background(0);
}
 
void mouseMoved()
{
  float neardist = width + height;
  for (int i=0; i<N; i++)
  {
    float nd = dist(px[i],py[i], mouseX,mouseY);
    if (nd < neardist)
    {
      nearest = i;
      neardist = nd;
    }
  }
  if (MAX_DIST < neardist)
  {
    nearest = -1;
  }
}
 
void mousePressed()
{
  if (-1 != nearest)
  {
    held = true;
  }
}
void mouseReleased()
{
  held = false;
}
 
void draw()
{
  // This section allows you to move the control points
  if (held)
  {
    px[nearest] = constrain(mouseX,0,width);
    py[nearest] = constrain(mouseY,0,height);
    background(0);
  }
  // Still not to the pattern code
 
  // Show control points
  for (int i=0; i<N; i++)
  {
    if (i == nearest)
    {
      stroke(0,255,0);
    }
    else
    {
      stroke(0,0,255);
    }
    ellipse( px[i],py[i], MAX_DIST,MAX_DIST );
  }
 
  stroke(255);
  for (int i=0; i<MANY_TIMES; i++) // Draw many points
  {
    // These are the lines that actually generate the pattern.
    int thistime = (int)random(N);
    float nx = ((px[thistime] - selx) / DIV) + selx;
    float ny = ((py[thistime] - sely) / DIV) + sely;
    selx = nx;
    sely = ny;
    // Yep, that is it.
 
    point( nx, ny );
  }
}

```

---

<div class="post-metadata">

**Author:** ![raron](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/raron/32/13651_2.png) [@raron](https://discourse.processing.org/u/raron)\
**Post date:** [September 6, 2020, 4:52pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/57 "2020-09-06T16:52:56Z")

</div>

> [@noel](#):
>
> Nice, we can add it as an animated version!

Sorry it took a little while… Added them now, not entirely sure if the category is right though. Feel free to edit them also!

Interesting tidbit: The “Enhanced loop” works different than the regular one, which I didn’t expect. It only gives the same 3 points for any recursion depth except 0 (which only plots the starting point). I’m not sure why that happens.

```auto
/** Sierpinski test 3 c

    All paths method (using recursion)
    
    2020.09.05 Improved with Crisir's method of not using a temp PVector
    2020.08.31 Improved with Crisir's method of only displaying at the last recursion depth
    2020.08.29 raron
*/
PVector [] coord = {new PVector(0, 0), new PVector(150, 300), new PVector(300, 0)};

void setup()
{
  size(400,400);
  background(32);  
  sierpinski(new PVector(150,150), 8);
  noLoop();
}

void sierpinski(PVector cPoint, int cDepth)
{
  if (cDepth == 0) {
    set(50+int(cPoint.x), (height-50)-int(cPoint.y), color(192));
    return;
  }

  for (int v=0; v<3; v++) {
    sierpinski(new PVector((cPoint.x+coord[v].x)/2, (cPoint.y+coord[v].y)/2), cDepth-1);
  }

  // "Enhanced loop" doesn't work!
/** 
  for (PVector sVertice : coord) {
    sierpinski(new PVector(cPoint.x+sVertice.x/2, cPoint.y+sVertice.y/2), cDepth-1);
  }
 */
}

```

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [September 9, 2020, 8:19pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/58 "2020-09-09T20:19:45Z")

</div>

> [@noel](#):
>
> Curious about Jeremy’s animated version I found no jar in the lib

If you are looking for the jar, there is a release here:

> **[Release v0.1 · jeremydouglass/recursor](https://github.com/jeremydouglass/recursor/releases/tag/v0.1)**
>
> Recursor release v0.1

…and if you download recursor.zip, it contains recursor/library/recursor.jar

---

<div class="post-metadata">

**Author:** ![noahbuddy](https://avatars.discourse-cdn.com/v4/letter/n/73ab20/32.png) [@noahbuddy](https://discourse.processing.org/u/noahbuddy)\
**Post date:** [October 31, 2020, 10:54pm UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/59 "2020-10-31T22:54:45Z")

</div>

Something I found interesting while playing this “game” was the apparent projection from four points to a 3D illusion.  
(Aside: I should probably pay more attention to my notifications. 🙃)

```auto
int NUMPTS = 10000;

float px = 0;
float py = 0;
//float pz = 0;
int nowc = 0;

int P = 4;

float[] nodex = new float[P];
float[] nodey = new float[P];
float[] nodez = new float[P];
int[] cols = new int[P];

float M = 350;
float N = 70;
float tm = 0;
float tn = PI;
float dm = 0.02;
float dn = -0.01;

void setup()
{
  size(768,768,P2D); // note the lack of third dimension
  cols[0] = color(42, 42, 42);
  cols[1] = color(0, 255, 255);
  cols[2] = color(0x3B, 0x1A, 0xC4);
  cols[3] = color(0, 255, 255);
  frameRate(30);
}

void draw()
{
  background(0);
  
  float ph = TWO_PI / 3;
  for (int i=0; i<(P-1); i++)
  {
    nodex[i] = M * cos(i*ph + tm);
    nodey[i] = M * sin(i*ph + tm);
    nodez[i] = 0;
  }
  nodex[P-1] = N * cos(tn);
  nodey[P-1] = N * sin(tn);
  //nodez[P-1] = 0;
  tm += dm;
  tn += dn;
  
  fill(255);
  text("Four control points.\nCenter is rotating at a different rate", 20, 20);
  
  translate(width/2, height/2);
  
  beginShape(POINTS);
  for (int i=0; i<NUMPTS; i++)
  {
    int t = (int)random(P);
    float tx = nodex[t];
    float ty = nodey[t];
    //float tz = nodez[t];
    int to = cols[t];
    
    nowc = lerpColor(nowc, to, 0.5);
    stroke(nowc);
    
    px = px + (tx - px)/2;
    py = py + (ty - py)/2;
    //pz = pz + (tz - pz)/2;
    vertex(px,py);
  }
  endShape();
}

```

---

<div class="post-metadata">

**Author:** ![codeguppy](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/codeguppy/32/8322_2.png) [@codeguppy](https://discourse.processing.org/u/codeguppy)\
**Post date:** [November 26, 2020, 2:03am UTC](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546/60 "2020-11-26T02:03:43Z")

</div>

I’ll also add an implementation to the list. Press Play ▶ to run the program:

https://www.codeguppy.com/code.html?BGap9We3JaUR4eoz2fvY

[Previous page](https://discourse.processing.org/t/recursive-sierpinski-triangle-just-a-bit-of-fun/23546.md?page=2)
