# Creating a structure of linked tetrahedra

**URL:** https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955
**Category:** Coding Questions
**Created:** [January 8, 2020, 1:05pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955 "2020-01-08T13:05:39Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![dauwpunt](https://avatars.discourse-cdn.com/v4/letter/d/71c47a/32.png) [@dauwpunt](https://discourse.processing.org/u/dauwpunt)
#### Post date: [January 8, 2020, 1:05pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/1 "2020-01-08T13:05:39Z")

</div>

Hi there. I am trying to generate a 3D landscape of tetrahedra, so to say, and I’m having some trouble with the mathematics and coding of it. I’m also still quite new to Processing! If I am not being clear enough about something, please let me know and I’ll do my best to provide more info.

Drawing just one tetrahedron (let’s refer to it as ABCD) is not so hard, using:  
vertex(1,1,1)  
vertex(1,-1,-1)  
vertex(-1,1,-1)  
vertex(-1,-1,1)

My next step is to choose one of the faces of my tetrahedron (ABD for example), and generate a new vertex E which, when connected to the A, B and D, makes a new tetrahedron ABDE. Pretty much like the image below!!  
[tetras|507x142](https://discourse.processing.org/uploads/short-url/svY5VZDivES8WtHfvx1H4noPWfk.jpeg)

Does anyone have any tips or knowledge on how to do this? Thanks!

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [January 8, 2020, 3:09pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/2 "2020-01-08T15:09:15Z")

</div>

i would use:

> **[createShape() / Reference](https://processing.org/reference/createShape_.html)**
>
> The createShape() function is used to define a new shape. Once created, this shape can be drawn with the shape() function. The basic way to use the function defines new primitive shapes.…

> **[PVector / Reference](https://processing.org/reference/PVector.html)**
>
> A class to describe a two or three dimensional vector, specifically a Euclidean (also known as geometric) vector. A vector is an entity that has both magnitude and direction. The datatype, however, st…

for 3D view

> **[peasycam](https://mrfeinberg.com/peasycam/)**
>
> a library for the programming environment processing

* * *

> [@dauwpunt](#):
>
> Drawing just one tetrahedron (let’s refer to it as ABCD) is not so hard, using:

good, show us that part you have already  
( as a running code formatted and pasted into

```auto
</> code tag 

```

* * *

 ![pyramid](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/96b833135412b75e3e19c7f9fc6ad2faefed7882.png)

---

<div class="post-metadata">

### Author: ![dauwpunt](https://avatars.discourse-cdn.com/v4/letter/d/71c47a/32.png) [@dauwpunt](https://discourse.processing.org/u/dauwpunt)
#### Post date: [January 8, 2020, 3:28pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/3 "2020-01-08T15:28:47Z")

</div>

Ah, I had already been using peasycam and createshape, but I’ll check out PVector, thanks! Below is what I have right now:

 ![8-1 screenshot](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/c/c31fe91cb9aa41f91b43398ea5544eaf3dd8f612.png)

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [January 8, 2020, 3:45pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/4 "2020-01-08T15:45:11Z")

</div>

ok, next

- try to fill it and you will see that you need 4 times triangles ( each 3 vertex )

* * *

but for the real job  
4 sides can have a vertex “E”  
how you choose side and point

---

<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: [January 8, 2020, 3:52pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/5 "2020-01-08T15:52:33Z")

</div>

Hi @dauwpunt Welcome to the forum.

If you really want structures of tetrahedrons you will eventually run into problems. Linking them together will force you to use the quadray coordinate system instead of the cartesian. And tetrahedrons are not space filling. The best computer simulations last year gave about 85 % space filling. In other words you can’t always link/attach them.  
The cube is the only Platonic solid which does fill space, as well as some combinations of tetrahedra and octahedra do.  
Below a not question related code, but if you plan to run on android you can’t use the peasycam lib mentioned by kll, but this code does rotate without going to the first begin position every time you touch the screen, rather starting at last position. It also shows the quadray axes

```auto
float rotX, rotY, s;

void setup(){
  size(720, 480, P3D);
  s = 60;  
  noFill();
  stroke(255);
}

void draw(){
  background(0);
  translate(width/2, height/2);
  rotateX(rotX); 
  rotateY(-rotY); 
  beginShape(TRIANGLE_STRIP);
  stroke(255, 0, 0);
  strokeWeight(3);
  vertex( s, s, s); // red v1
  stroke(0, 255, 0);
  vertex(-s, -s, s); // green v2
  stroke(0, 0, 255);
  vertex(-s, s, -s); // blue v3
  stroke(255, 255, 0);
  vertex( s, -s, -s); // yellow v4
  stroke(255, 0, 0);
  vertex( s, s, s); // red v1 again to close tetrahedron
  endShape();
  stroke(200, 0, 0);
  line(0, 0, 0, -4*s, -4*s, -4*s);
  stroke(255, 50, 50);
  line(0, 0, 0, 4*s, 4*s, 4*s);
  stroke(0, 200, 0);
  line(0, 0, 0, -4*s, -4*s, 4*s);
  stroke(50, 255, 50);
  line(0, 0, 0, 4*s, 4*s, -4*s);
  stroke(0, 0, 200);
  line(0, 0, 0, -4*s, 4*s, -4*s);
  stroke(50, 50, 255);
  line(0, 0, 0, 4*s, -4*s, 4*s);
  stroke(255);
  line(0, 0, 0, 4*s, -4*s, -4*s);
  stroke(150);
  line(0, 0, 0, -4*s, 4*s, 4*s);
}

void mouseDragged() { 
  rotY -= (mouseX - pmouseX) * 0.01; 
  rotX -= (mouseY - pmouseY) * 0.01;
}

```

---

<div class="post-metadata">

### Author: ![kll](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kll/32/964_2.png) [@kll](https://discourse.processing.org/u/kll)
#### Post date: [January 8, 2020, 4:01pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/6 "2020-01-08T16:01:33Z")

</div>

here is why i think PVector  
now even PVector[] could make sense:

```auto
// https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955

//Drawing just one tetrahedron (let’s refer to it as ABCD) is not so hard, using:
//vertex(1,1,1)
//vertex(1,-1,-1)
//vertex(-1,1,-1)
//vertex(-1,-1,1)

// https://en.wikipedia.org/wiki/Tetrahedron
// http://learningprocessing.com/examples/chp14/example-14-04-pyramid
// https://processing.org/tutorials/p3d/

import peasy.*;
PeasyCam cam;
PShape thd;

int big = 100;
int alpha = 255;

PVector a = new PVector(big, big, big);
PVector b = new PVector(big, -big, -big);
PVector c = new PVector(-big, big, -big);
PVector d = new PVector(-big, -big, big);

PVector[] t4 = {a,b,c,d};//new PVector[4];

void setup() {
  size(500, 500, P3D);
  make_thd(t4);
  cam = new PeasyCam(this, 400);
}

void make_thd(PVector[] t) {
  thd = createShape();
  thd.beginShape(TRIANGLES);

  thd.stroke(0,200,200);
  thd.strokeWeight(2);
  
  thd.fill(100,0,0,alpha);
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[2].x,t[2].y,t[2].z);
  
  thd.fill(0,100,0,alpha);
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);

  thd.fill(0,0,100,alpha);
  thd.vertex(t[2].x,t[2].y,t[2].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);

  thd.fill(0,0,0,alpha);
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  thd.vertex(t[2].x,t[2].y,t[2].z);

  thd.endShape();
}

void show_points() {
  fill(200,0,0);
  textSize(20);
  push();
  translate(a.x,a.y,a.z);
  text("A",0,0);
  pop();
  push();
  translate(b.x,b.y,b.z);
  text("B",0,0);
  pop();
  push();
  translate(c.x,c.y,c.z);
  text("C",0,0);
  pop();
  push();
  translate(d.x,d.y,d.z);
  text("D",0,0);
  pop();
}

void draw() {
  background(200, 200, 0);
  shape(thd, 0, 0);
  show_points();
}

```

---

<div class="post-metadata">

### Author: ![dauwpunt](https://avatars.discourse-cdn.com/v4/letter/d/71c47a/32.png) [@dauwpunt](https://discourse.processing.org/u/dauwpunt)
#### Post date: [January 8, 2020, 4:02pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/7 "2020-01-08T16:02:42Z")

</div>

Thank you very much for this in-depth reply Noel! I will look into the quadray coordinate system you mentioned. It’s been a while since I’ve been doing something so math-heavy haha.  
I am aware that they are not space-filling! It’s not that I necessarily want a space that is filled to the brim with tetrahedra, but it would be perfect if I could have one centered tetrahedron, and then pick one of its faces and attach a new tetrahedron to it. I’m starting to find out this sounds a lot easier than it will probably be.

I saw some posts about using the translate() and rotatex/y/z functions to move the grid. Could that be something useful?

---

<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: [January 9, 2020, 1:06pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/8 "2020-01-09T13:06:11Z")

</div>

> [@dauwpunt](#):
>
> I saw some posts about using the translate() and rotatex/y/z functions to move the grid. Could that be something useful?

I guess not, because translation will occur in Cartesian space.  
You can still build from the center using two points of a face and distance the other along the quadray axis.  
Below a code with one tetrahedron attached forming a triangular bipyramid, rotating around centroid of the center tetrahedron. I did not close all faces just to see through.  
Maybe you can build something using a PVector array like @kll suggested. Let us know if you succeed.

```auto

float rotX, rotY, s, t;

void setup(){
  size(720, 480, P3D);
  s = 60;  
  t = 2*sqrt(6)/3;
  noFill();
  stroke(255);
  hint ( DISABLE_DEPTH_TEST);
} 

void draw(){
  background(0);
  translate(width/2, height/2);
  rotateX(rotX); 
  rotateY(-rotY); 
  
  fill(255, 0, 0, 200); // first red face
  beginShape(TRIANGLES);
  strokeWeight(3); 
  vertex( s, s, s); 
  vertex(-s, -s, s);
  vertex(-s, s, -s); 
  endShape();
  
  fill(0, 255, 0, 200); // second green face
  beginShape(TRIANGLES);
  //stroke(255, 255, 0);
  vertex( s, -s, -s); 
  //stroke(255, 0, 0);
  vertex( s, s, s); 
  //stroke(0, 255, 0);
  vertex(-s, -s, s); 
  endShape();
  
  fill(255, 255, 0, 200); // third yellow face
  beginShape(TRIANGLES);
  vertex( -s, s, -s); 
  vertex( s, s, s); 
  vertex(s, -s, -s);
  endShape();
  
  // Using two points of first red face and distance the other
  fill(255, 0, 0, 200); 
  beginShape(TRIANGLES);
  strokeWeight(3);
  vertex( s, s, s); 
  vertex(-s, -s, s); 
  vertex(-t*s, t*s, t*s); 
  endShape();
  
  fill(255, 0, 0, 200); 
  beginShape(TRIANGLES);
  strokeWeight(3);
  vertex( s, s, s); 
  vertex(-t*s, t*s, t*s); 
  vertex(-s, s, -s); 
  endShape();
 
  // The axes
  stroke(200, 0, 0, 100);
  line(0, 0, 0, -4*s, -4*s, -4*s);
  stroke(255, 50, 50, 100);
  line(0, 0, 0, 4*s, 4*s, 4*s);
  stroke(0, 200, 0, 100);
  line(0, 0, 0, -4*s, -4*s, 4*s);
  stroke(50, 255, 50, 100);
  line(0, 0, 0, 4*s, 4*s, -4*s);
  stroke(0, 0, 200, 100);
  line(0, 0, 0, -4*s, 4*s, -4*s);
  stroke(50, 50, 255, 100);
  line(0, 0, 0, 4*s, -4*s, 4*s);
  stroke(255, 100);
  line(0, 0, 0, 4*s, -4*s, -4*s);
  stroke(150, 100);
  line(0, 0, 0, -4*s, 4*s, 4*s);
}

void mouseDragged() { 
  rotY -= (mouseX - pmouseX) * 0.01; 
  rotX -= (mouseY - pmouseY) * 0.01;
}

```

---

<div class="post-metadata">

### Author: ![dauwpunt](https://avatars.discourse-cdn.com/v4/letter/d/71c47a/32.png) [@dauwpunt](https://discourse.processing.org/u/dauwpunt)
#### Post date: [January 14, 2020, 10:06am UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/9 "2020-01-14T10:06:48Z")

</div>

@noel this was a tremendous help, thank you. I’ve made some progress and am looking next to apply the pVector idea that @kll suggested.

Right now, this is my goal:

- One visual configuration that shows the center tetrahedron, plus its 4 companions that are attached via the triangular faces. This was fairly easy to achieve with the help of your code.
- One visual configuration that shows the center tetrahedron, plus its 12(?) companions that are attached via the sides only. This one is more tricky, but I have managed to create some of these companions (the green tetrahedra).

any ideas on how to make my code more efficient are of course very welcome haha.

```auto
float s, t;
import peasy.*;
PeasyCam cam;

void setup(){
  size(720, 480, P3D);
  s = 60;  
  t = 2*sqrt(6)/3;
  noFill();
  stroke(255);
  cam = new PeasyCam(this, 100);
  cam.setMinimumDistance(500);
  cam.setMaximumDistance(2000);
} 

void draw(){
  background(0);
  //translate(width/2, height/2);
  
  // TETRA 1: the base
  fill(255, 0, 0); // first red face
  beginShape(TRIANGLES);
  strokeWeight(3); 
  vertex( s, s, s); 
  vertex(-s, -s, s);
  vertex(-s, s, -s); 
  endShape();
  
  fill(255, 0, 0); // second red face
  beginShape(TRIANGLES);
  vertex( s, -s, -s); 
  vertex( s, s, s); 
  vertex(-s, -s, s); 
  endShape();
  
  fill(255, 0, 0); // third red face
  beginShape(TRIANGLES);
  vertex( -s, s, -s); 
  vertex( s, s, s); 
  vertex(s, -s, -s);
  endShape();
  
  fill(255, 0, 0); // fourth red face
  beginShape(TRIANGLES);
  vertex(-s, -s, s);
  vertex(-s, s, -s);
  vertex( s, -s, -s);
  endShape();
  
        // TETRA 2.1: Using two points of first red face and distance the other using t
        fill(0, 85, 0, 200); 
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( s, s, s); 
        vertex(-s, -s, s); 
        vertex(-t*s, t*s, t*s); 
        endShape();
        
        fill(0, 170, 0, 200);
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( s, s, s);  
        vertex(-s, s, -s); 
        vertex(-t*s, t*s, t*s);
        endShape();
        
        fill(0, 255, 0, 200);
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex(-s, -s, s);  
        vertex(-s, s, -s); 
        vertex(-t*s, t*s, t*s);
        endShape();
        
              // TETRA 2.1.1: Using two points of third 2.1 and distance the other using t
              fill(0, 255, 0, 200); 
              beginShape(TRIANGLES);
              strokeWeight(3);
              vertex(-s, -s, s); 
              vertex(-t*s, t*s, t*s); 
              vertex(-2*t*s, 0, 0);  
              endShape();
              
              beginShape(TRIANGLES);
              strokeWeight(3);
              vertex(-s, s, -s); 
              vertex(-t*s, t*s, t*s); 
              vertex(-2*t*s, 0, 0);
              endShape();
              
              beginShape(TRIANGLES);
              strokeWeight(3);
              vertex(-s, -s, s); 
              vertex(-s, s, -s); 
              vertex(-2*t*s, 0, 0);
              endShape();
              
              // TETRA 2.1.2: Using two points of first 2.1 and distance the other using t
              fill(0, 85, 0, 200); 
              beginShape(TRIANGLES);
              strokeWeight(3);
              vertex( s, s, s); 
              vertex(-s, -s, s); 
              vertex(0, 0, 2*t*s);  
              endShape();
              
              beginShape(TRIANGLES);
              strokeWeight(3);
              vertex(-s, -s, s); 
              vertex(-t*s, t*s, t*s); 
              vertex(0, 0, 2*t*s);
              endShape();
              
              beginShape(TRIANGLES);
              strokeWeight(3);
              vertex(-s, -s, s); 
              vertex(-t*s, t*s, t*s); 
              vertex(0, 0, 2*t*s);
              endShape();
        
        // TETRA 2.2: Using two points of second red face and distance the other using t      
        fill(0, 0, 255, 150); 
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( s, -s, -s);   
        vertex( s, s, s);
        vertex(t*s, -t*s, t*s);
        endShape();
        
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( s, -s, -s);   
        vertex(-s, -s, s);
        vertex(t*s, -t*s, t*s);
        endShape();
        
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( s, s, s);   
        vertex(-s, -s, s);
        vertex(t*s, -t*s, t*s);
        endShape();
        
              //// TETRA 2.2.1: Using two points of 2.2 and distance the other using t      
              //fill(0, 255, 255, 150); 
              //beginShape(TRIANGLES);
              //strokeWeight(3);
              //vertex( s, -s, -s);   
              //vertex(-s, -s, s);
              //vertex(0, -2*t*s, 0);
              //endShape();
              
              //beginShape(TRIANGLES);
              //strokeWeight(3);
              //vertex( s, -s, -s);   
              //vertex(t*s, -t*s, t*s);
              //vertex(0, -2*t*s, 0);
              //endShape();
              
              //beginShape(TRIANGLES);
              //strokeWeight(3);
              //vertex(-s, -s, s);   
              //vertex(t*s, -t*s, t*s);
              //vertex(0, -2*t*s, 0);
              //endShape();
        
        // TETRA 2.3: Using two points of third red face and distance the other using t  
        fill(255, 255, 0, 150); 
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( -s, s, -s); 
        vertex( s, s, s);
        vertex(t*s, t*s, -t*s);
        endShape();
        
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( -s, s, -s);   
        vertex(s, -s, -s);
        vertex(t*s, t*s, -t*s);
        endShape();
        
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex( s, s, s);   
        vertex(s, -s, -s);
        vertex(t*s, t*s, -t*s);
        endShape();
        
        // TETRA 2.4: Using two points of fourth red face and distance the other using t  
        fill(255, 0, 255, 150); 
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex(-s, -s, s);
        vertex(-s, s, -s);
        vertex(-t*s, -t*s, -t*s);
        endShape();
        
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex(-s, -s, s);   
        vertex( s, -s, -s);
        vertex(-t*s, -t*s, -t*s);
        endShape();
        
        beginShape(TRIANGLES);
        strokeWeight(3);
        vertex(-s, s, -s);   
        vertex( s, -s, -s);
        vertex(-t*s, -t*s, -t*s);
        endShape();
  
  // The axes
  stroke(200, 0, 0, 100);
  line(0, 0, 0, -4*s, -4*s, -4*s);
  stroke(255, 50, 50, 100);
  line(0, 0, 0, 4*s, 4*s, 4*s);
  stroke(0, 200, 0, 100);
  line(0, 0, 0, -4*s, -4*s, 4*s);
  stroke(50, 255, 50, 100);
  line(0, 0, 0, 4*s, 4*s, -4*s);
  stroke(0, 0, 200, 100);
  line(0, 0, 0, -4*s, 4*s, -4*s);
  stroke(50, 50, 255, 100);
  line(0, 0, 0, 4*s, -4*s, 4*s);
  stroke(255, 100);
  line(0, 0, 0, 4*s, -4*s, -4*s);
  stroke(150, 100);
  line(0, 0, 0, -4*s, 4*s, 4*s);
}

```

---

<div class="post-metadata">

### Author: ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)
#### Post date: [January 14, 2020, 11:59am UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/10 "2020-01-14T11:59:44Z")

</div>

I‘d go for a class Tetrahedron and then make an Arraylist of this.

Then in setup you do the calculations and fill the arraylist

In draw you only do the display bit

**Animation :**

Remember the rubicks cube?

Similarly there is

> **[Sunshane 12 Stücke 24 Blöcke Magische Schlangen Würfel, Mini Schlangen...](https://www.amazon.de/Sunshane-Schlangen-Geschwindigkeit-Kunststoff-Spielzeug/dp/B07HFDSKZC/ref=asc_df_B07HFDSKZC/?tag=googshopde-21&linkCode=df0&hvadid=356435695564&hvpos=1o1&hvnetw=g&hvrand=4647012024808083883&hvpone&hvptwo&hvqmt&hvdev=m&hvdvcmdl&hvlocint&hvlocphy=9043198&hvtargid=pla-574499056252&psc=1&th=1&psc=1&tag&ref&adgrpid=70244624577&hvpone&hvptwo&hvadid=356435695564&hvpos=1o1&hvnetw=g&hvrand=4647012024808083883&hvqmt&hvdev=m&hvdvcmdl&hvlocint&hvlocphy=9043198&hvtargid=pla-574499056252)**
>
> Sunshane 12 Stücke 24 Blöcke Magische Schlangen Würfel, Mini Schlangen Geschwindigkeit Würfel, Mini Kunststoff Puzzle Würfel Spielzeug für Kinder Party Tasche Füllstoff, Party Favors, Zufällige Farbe bei Amazon.de | Günstiger Preis | Kostenloser...

A snake which is turnable at each element (I programmed this actually)

Maybe you could apply this to your program.

Then each element is attached by a rotating joint to the next element

---

<div class="post-metadata">

### Author: ![dauwpunt](https://avatars.discourse-cdn.com/v4/letter/d/71c47a/32.png) [@dauwpunt](https://discourse.processing.org/u/dauwpunt)
#### Post date: [February 11, 2020, 3:03pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/11 "2020-02-11T15:03:20Z")

</div>

Hi there, been a while! I’ve made good progress with this but now am in need of some more mathematical wisdom. Code below!

There is a coordinate I need for the black tetrahedron that will sit against the green tetrahedron (0,1,4,9). For the life of me I can’t figure out what the coordinates should be… Any ideas how to find them?

```auto
import peasy.*;
PeasyCam cam;
PShape thd;
float s = 60;
float t = 2*sqrt(6)/3;
int alpha = 200;

PVector a = new PVector(s, s, s);
PVector b = new PVector(-s, -s, s);
PVector c = new PVector(-s, s, -s);
PVector d = new PVector(s, -s, -s);

PVector e = new PVector(-t*s, t*s, t*s);
PVector f = new PVector(t*s, -t*s, t*s);
PVector g = new PVector(-t*s, -t*s, -t*s);
PVector h = new PVector(t*s, t*s, -t*s);

PVector i = new PVector(-2*t*s, 0, 0); // e+g
PVector j = new PVector(0, 0, 2*t*s); // e+f
PVector k = new PVector(0, 2*t*s, 0); // e+h // ook voor geel
PVector l = new PVector(2*t*s, 0, 0); // f+h // ook voor geel
PVector m = new PVector(0, -2*t*s, 0); // f+g
PVector n = new PVector(0, 0, -2*t*s); // g+h // ook voor geel, wordt 13

PVector o = new PVector(-2*t*s, 0, 2*t*s); //b+e

// geel = 10,11,15

PVector[] t15 = {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o};

void setup(){
  size(720, 480, P3D);   
  make_thd(t15);
  cam = new PeasyCam(this, 100);
  cam.setMinimumDistance(500);
  cam.setMaximumDistance(2000);
} 

void make_thd(PVector[] t) {
  thd = createShape();
  thd.beginShape(TRIANGLES);
  
  thd.stroke(200,200,200);
  thd.strokeWeight(3);
  
thd.fill(255,255,255,alpha); // base 0,1,2,3
thd.vertex(t[0].x,t[0].y,t[0].z);
thd.vertex(t[1].x,t[1].y,t[1].z);
thd.vertex(t[2].x,t[2].y,t[2].z);
  
thd.vertex(t[0].x,t[0].y,t[0].z);
thd.vertex(t[1].x,t[1].y,t[1].z);
thd.vertex(t[3].x,t[3].y,t[3].z);

thd.vertex(t[2].x,t[2].y,t[2].z);
thd.vertex(t[1].x,t[1].y,t[1].z);
thd.vertex(t[3].x,t[3].y,t[3].z);

thd.vertex(t[0].x,t[0].y,t[0].z);
thd.vertex(t[3].x,t[3].y,t[3].z);
thd.vertex(t[2].x,t[2].y,t[2].z);
  
  thd.fill(0,255,0,alpha); // base 0,1,2,4
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[2].x,t[2].y,t[2].z);
  
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[4].x,t[4].y,t[4].z);

  thd.vertex(t[2].x,t[2].y,t[2].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[4].x,t[4].y,t[4].z);

  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[4].x,t[4].y,t[4].z);
  thd.vertex(t[2].x,t[2].y,t[2].z);
        
        thd.fill(0,125,0,alpha); // base 0,1,4,9
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
  
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[9].x,t[9].y,t[9].z);

        thd.vertex(t[4].x,t[4].y,t[4].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[9].x,t[9].y,t[9].z);

        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[9].x,t[9].y,t[9].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
        
              thd.fill(0,0,0,alpha); // base 4,1,9,14
              thd.vertex(t[4].x,t[4].y,t[4].z);
              thd.vertex(t[1].x,t[1].y,t[1].z);
              thd.vertex(t[9].x,t[9].y,t[9].z);
  
              thd.vertex(t[4].x,t[4].y,t[4].z);
              thd.vertex(t[1].x,t[1].y,t[1].z);
              thd.vertex(t[14].x,t[14].y,t[14].z);

              thd.vertex(t[9].x,t[9].y,t[9].z);
              thd.vertex(t[1].x,t[1].y,t[1].z);
              thd.vertex(t[14].x,t[14].y,t[14].z);

              thd.vertex(t[4].x,t[4].y,t[4].z);
              thd.vertex(t[14].x,t[14].y,t[14].z);
              thd.vertex(t[9].x,t[9].y,t[9].z);
        
        thd.fill(0,125,0,alpha); // base 2,1,4,8
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
  
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[8].x,t[8].y,t[8].z);

        thd.vertex(t[4].x,t[4].y,t[4].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[8].x,t[8].y,t[8].z);

        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[8].x,t[8].y,t[8].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
        
        thd.fill(0,125,0,alpha); // base 0,4,2,10
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
        thd.vertex(t[2].x,t[2].y,t[2].z);
  
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
        thd.vertex(t[10].x,t[10].y,t[10].z);

        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[4].x,t[4].y,t[4].z);
        thd.vertex(t[10].x,t[10].y,t[10].z);

        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[10].x,t[10].y,t[10].z);
        thd.vertex(t[2].x,t[2].y,t[2].z);
  
  thd.fill(255,0,0,alpha); // base 0,1,3,5
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[5].x,t[5].y,t[5].z);

  thd.vertex(t[3].x,t[3].y,t[3].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[5].x,t[5].y,t[5].z);

  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[5].x,t[5].y,t[5].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  
        thd.fill(125,0,0,alpha); // 0,5,3,11
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
  
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
        thd.vertex(t[11].x,t[11].y,t[11].z);

        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
        thd.vertex(t[11].x,t[11].y,t[11].z);

        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[11].x,t[11].y,t[11].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
  
        thd.fill(125,0,0,alpha); // 3,1,5,12
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
  
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[12].x,t[12].y,t[12].z);

        thd.vertex(t[5].x,t[5].y,t[5].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[12].x,t[12].y,t[12].z);

        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[12].x,t[12].y,t[12].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
  
        thd.fill(125,0,0,alpha); // 0,1,5,9
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
  
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[9].x,t[9].y,t[9].z);

        thd.vertex(t[5].x,t[5].y,t[5].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[9].x,t[9].y,t[9].z);

        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[9].x,t[9].y,t[9].z);
        thd.vertex(t[5].x,t[5].y,t[5].z);
  
  thd.fill(0,0,255,alpha); // base 2,1,3,6
  thd.vertex(t[2].x,t[2].y,t[2].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  
  thd.vertex(t[2].x,t[2].y,t[2].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[6].x,t[6].y,t[6].z);

  thd.vertex(t[3].x,t[3].y,t[3].z);
  thd.vertex(t[1].x,t[1].y,t[1].z);
  thd.vertex(t[6].x,t[6].y,t[6].z);

  thd.vertex(t[2].x,t[2].y,t[2].z);
  thd.vertex(t[6].x,t[6].y,t[6].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  
        thd.fill(0,0,125,alpha); // 2,1,6,8
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);
  
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[8].x,t[8].y,t[8].z);

        thd.vertex(t[6].x,t[6].y,t[6].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[8].x,t[8].y,t[8].z);

        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[8].x,t[8].y,t[8].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);
        
        thd.fill(0,0,125,alpha); // 2,6,3,13
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
  
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);
        thd.vertex(t[13].x,t[13].y,t[13].z);

        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);
        thd.vertex(t[13].x,t[13].y,t[13].z);

        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[13].x,t[13].y,t[13].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);

        thd.fill(0,0,125,alpha); // 3,1,6,12
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);
  
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[12].x,t[12].y,t[12].z);

        thd.vertex(t[6].x,t[6].y,t[6].z);
        thd.vertex(t[1].x,t[1].y,t[1].z);
        thd.vertex(t[12].x,t[12].y,t[12].z);

        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[12].x,t[12].y,t[12].z);
        thd.vertex(t[6].x,t[6].y,t[6].z);

  thd.fill(255,255,0,alpha); // base 0,3,2,7
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  thd.vertex(t[2].x,t[2].y,t[2].z);
  
  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  thd.vertex(t[7].x,t[7].y,t[7].z);

  thd.vertex(t[2].x,t[2].y,t[2].z);
  thd.vertex(t[3].x,t[3].y,t[3].z);
  thd.vertex(t[7].x,t[7].y,t[7].z);

  thd.vertex(t[0].x,t[0].y,t[0].z);
  thd.vertex(t[7].x,t[7].y,t[7].z);
  thd.vertex(t[2].x,t[2].y,t[2].z);
  
        thd.fill(125,125,0,alpha); // 2,3,7,13
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[7].x,t[7].y,t[7].z);
  
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[13].x,t[13].y,t[13].z);

        thd.vertex(t[7].x,t[7].y,t[7].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[13].x,t[13].y,t[13].z);

        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[13].x,t[13].y,t[13].z);
        thd.vertex(t[7].x,t[7].y,t[7].z);
  
        thd.fill(125,125,0,alpha); // 0,3,7,11
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[7].x,t[7].y,t[7].z);
  
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[11].x,t[11].y,t[11].z);

        thd.vertex(t[7].x,t[7].y,t[7].z);
        thd.vertex(t[3].x,t[3].y,t[3].z);
        thd.vertex(t[11].x,t[11].y,t[11].z);

        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[11].x,t[11].y,t[11].z);
        thd.vertex(t[7].x,t[7].y,t[7].z);
        
        thd.fill(125,125,0,alpha); // 0,2,7,10
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[7].x,t[7].y,t[7].z);
  
        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[10].x,t[10].y,t[10].z);

        thd.vertex(t[7].x,t[7].y,t[7].z);
        thd.vertex(t[2].x,t[2].y,t[2].z);
        thd.vertex(t[10].x,t[10].y,t[10].z);

        thd.vertex(t[0].x,t[0].y,t[0].z);
        thd.vertex(t[10].x,t[10].y,t[10].z);
        thd.vertex(t[7].x,t[7].y,t[7].z);
  
  thd.endShape();
}

void show_points() {
  textAlign(CENTER, CENTER);
  
  fill(200,200,200);
  textSize(45);
  push();
  translate(a.x*1.2,a.y*1.2,a.z*1.2);
  text("C (0)",0,0);
  pop();
  push();
  translate(b.x*1.2,b.y*1.2,b.z*1.2);
  text("E (1)",0,0);
  pop();
  push();
  translate(c.x*1.2,c.y*1.2,c.z*1.2);
  text("G (2)",0,0);
  pop();
  push();
  translate(d.x*1.2,d.y*1.2,d.z*1.2);
  text("B (3)",0,0);
  pop();
  
  push();
  translate(e.x*1.15,e.y*1.15,e.z*1.15);
  text("D (4)",0,0);
  pop();
  push();
  translate(f.x*1.15,f.y*1.15,f.z*1.15);
  text("D (5)",0,0);
  pop();
  push();
  translate(g.x*1.15,g.y*1.15,g.z*1.15);
  text("D (6)",0,0);
  pop();
  push();
  translate(h.x*1.15,h.y*1.15,h.z*1.15);
  text("D (7)",0,0);
  pop();
  
  push();
  translate(i.x*1.1,i.y*1.1,i.z*1.1);
  text("F# (8)",0,0);
  pop();
  push();
  translate(j.x*1.1,j.y*1.1,j.z*1.1);
  text("F# (9)",0,0);
  pop();
  push();
  translate(k.x*1.1,k.y*1.1,k.z*1.1);
  text("F# (10)",0,0);
  pop();
  push();
  translate(l.x*1.1,l.y*1.1,l.z*1.1);
  text("F# (11)",0,0);
  pop();
  push();
  translate(m.x*1.1,m.y*1.1,m.z*1.1);
  text("F# (12)",0,0);
  pop();
  push();
  translate(n.x*1.1,n.y*1.1,n.z*1.1);
  text("F# (13)",0,0);
  pop();
}

void draw(){
 background(0);
  shape(thd, 0, 0);
  show_points(); 
  
  // The axes
  stroke(200, 0, 0, 100);
  line(0, 0, 0, -4*s, -4*s, -4*s);
  stroke(255, 50, 50, 100);
  line(0, 0, 0, 4*s, 4*s, 4*s);
  stroke(0, 200, 0, 100);
  line(0, 0, 0, -4*s, -4*s, 4*s);
  stroke(50, 255, 50, 100);
  line(0, 0, 0, 4*s, 4*s, -4*s);
  stroke(0, 0, 200, 100);
  line(0, 0, 0, -4*s, 4*s, -4*s);
  stroke(50, 50, 255, 100);
  line(0, 0, 0, 4*s, -4*s, 4*s);
  stroke(255, 100);
  line(0, 0, 0, 4*s, -4*s, -4*s);
  stroke(150, 100);
  line(0, 0, 0, -4*s, 4*s, 4*s);
}

```

---

<div class="post-metadata">

### Author: ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)
#### Post date: [February 11, 2020, 10:02pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/12 "2020-02-11T22:02:09Z")

</div>

Hello,

One observation…

You are missing F#(14) o.x, o.y, o.z.

I have used modelX(), modelY() and modelZ() in the past.

I tried it on your missing point:

```auto
 push();
  translate(o.x*1.1,o.y*1.1,o.z*1.1);
  text("F# (14)",0,0);
  println(modelX(o.x*1.1,o.y*1.1,o.z*1.1));
  println(modelY(o.x*1.1,o.y*1.1,o.z*1.1));
  println(modelZ(o.x*1.1,o.y*1.1,o.z*1.1));
  pop();

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/200eade615afeeb2d8222c1df5e75e750510b128.png)

---

<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: [February 12, 2020, 1:38pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/13 "2020-02-12T13:38:11Z")

</div>

@dew point  
If you use ortho(); in setup() you will see a far more accurate drawing.  
The further you go outside, the more distortion you will get. Also now a neighbour won’t fit. They will overlap each other.  
I think the use of an PVector array is quite good; however it doesn’t reduce the amount of code. Probably there is a better way.  
Maybe you could build a rotating structure like a [Boerdijk–Coxeter helix](https://en.m.wikipedia.org/wiki/Boerdijk%E2%80%93Coxeter_helix)  
It is not only used in art, as showed in picture below, but also in the science of nano structures.  
See [here](https://www.newswise.com/doescience/?article_id=720070&returnurl=aHR0cHM6Ly93d3cubmV3c3dpc2UuY29tL2FydGljbGVzL2xpc3Q=).  
A tetrahedron helix will also fit in a tube. Would be nice to see.

 ![Screenshot_2020-02-12-10-08-02](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/0/03fd71089b4287d962bdfcb12254731d51aface6.jpeg)

---

<div class="post-metadata">

### Author: ![dauwpunt](https://avatars.discourse-cdn.com/v4/letter/d/71c47a/32.png) [@dauwpunt](https://discourse.processing.org/u/dauwpunt)
#### Post date: [February 19, 2020, 1:41pm UTC](https://discourse.processing.org/t/creating-a-structure-of-linked-tetrahedra/16955/14 "2020-02-19T13:41:12Z")

</div>

Ah thanks @noel , using ortho is indeed much nicer!  
I understand that neighbours will overlap, but I could (for what I’m trying to represent) get away with choosing 1 of the coordinates and having the other neighbour not be a perfect tetrahedron, does that make sense?  
The boerdijk-coxeter helix is not per se interesting for me, as I’m only interested in generating tetrahedra that share at least 1 vertex with an existing central tetrahedron.
