/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://cd3d.sketchpad.cc/sp/pad/view/ro.VMM5CYF5AeM/rev.34
*
* authors:
* Pascal Romon
* Lorenzo Milesi
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
Vertex[] v;
Edge[] e;
Face[] f;
Edge S; // the surface, aka initial handle on an edge
float distance = 50; // for camera
void setup() {
size(300, 300, P3D);
S = pyramid();
}
void draw() {
background(50);
// horizontal angle phi = PI*(2*mouseX/width -1)
// vertical angle theta = (PI/2)*(2*mouseY/height/2 - 1)
camera(width/2-distance*sin(TWO_PI*mouseX/width)*sin(PI*mouseY/height),
height/2+distance*cos(PI*mouseY/height),
-distance*cos(TWO_PI*mouseX/width)*sin(PI*mouseY/height),
width/2, height/2, 0,
0, 1, 0);
/*
for (int i=0; i < 5; i++) {
f[i].draw(250,137);
}
*/
ArrayList<Face> list = faceTraversal(f[0]);
for(Face currentFace : list) {
currentFace.draw(250,137);
}
/*
noStroke();
fill(137);
beginShape();
vertex(p.xpos,p.ypos,p.zpos);
vertex(q.xpos,q.ypos,q.zpos);
vertex(r.xpos,r.ypos,r.zpos);
endShape();
*/
}
void mouseWheel(MouseEvent event) { // for zooming in and out
float e = event.getCount();
distance += e;
}
class Vertex {
float xpos;
float ypos;
float zpos;
Edge edgefrom; // one of the oriented edges emanating from the vertex
int status; // for listing purposes
Vertex(float x,float y,float z) {
xpos = x + width/2;
ypos = y + height/2;
zpos = z;
status = 0;
}
void draw() {
noStroke();
lights();
pushMatrix();
translate(xpos,ypos,zpos);
sphere(10);
popMatrix();
}
}
class Edge { // oriented
Vertex first;
Vertex last;
Edge opposite;
Edge next;
Edge previous;
Face face;
int status; // for listing purposes
Edge(Vertex theFirst, Vertex theLast) {
first = theFirst;
last = theLast;
status = 0;
}
void draw() {
stroke(255);
line(first.xpos,first.ypos,first.zpos,last.xpos,last.ypos,last.zpos);
}
}
class Face { //oriented
Edge inedge;
int degree; // face degree, i.e. number of edges
int status; // for listing purposes
String name;
Face(Edge e, int d) {
inedge = e;
degree = d;
status = 0;
}
void draw(int theStroke, int theFill) {
if (theStroke == -1) {
noStroke();
} else {
stroke(theStroke);
}
if (theFill == -1) {
noFill();
} else {
fill(theFill);
}
Edge e = inedge;
// vertex(e.xpos,e.first.ypos,e.first.zpos);
beginShape();
for (int i=0; i <= degree; i++) {
vertex(e.last.xpos,e.last.ypos,e.last.zpos);
// vertex(inedge.next.last.xpos,inedge.next.last.ypos,inedge.next.last.zpos);
e = e.next;
}
endShape();
}
void drawEdges(int strokeColor) {
draw(strokeColor,-1);
}
void drawFace(int fillColor) {
draw(-1,fillColor);
}
ArrayList<Edge> boundingEdges() { // returns the list of boundary edges
Edge e = inedge;
ArrayList<Edge> list = new ArrayList<Edge>();
for (int i=0; i < degree; i++) {
list.add(e);
e = e.next;
}
return(list);
}
ArrayList<Face> incidentFaces() { // returns the list of incident faces
ArrayList<Face> faces = new ArrayList<Face>();
Edge e = inedge;
for (int i=0; i < degree; i++) {
faces.add(e.opposite.face);
e = e.next;
}
return(faces);
}
}
class Surface {
// not as half-edge convention
Edge initialEdge;
Surface(Edge e) {
initialEdge = e;
}
void draw() {
// draws all faces by enumeration
}
}
Edge pyramid() {
v = new Vertex[5];
e = new Edge[16]; // two directions!
f = new Face[5];
v[0] = new Vertex(0,10,0); // apex
v[0].edgefrom = e[0]; // e01
v[1] = new Vertex(0,0,10);
v[1].edgefrom = e[8]; // e12
v[2] = new Vertex(10,0,0);
v[2].edgefrom = e[10]; // e23
v[3] = new Vertex(0,0,-10);
v[3].edgefrom = e[12]; // e34
v[4] = new Vertex(-10,0,0);
v[4].edgefrom = e[14]; // e41
e[0] = new Edge(v[0],v[1]);
e[1] = new Edge(v[1],v[0]);
e[0].opposite = e[1];
e[1].opposite = e[0];
e[2] = new Edge(v[0],v[2]);
e[3] = new Edge(v[2],v[0]);
e[2].opposite = e[3];
e[3].opposite = e[2];
e[4] = new Edge(v[0],v[3]);
e[5] = new Edge(v[3],v[0]);
e[4].opposite = e[5];
e[5].opposite = e[4];
e[6] = new Edge(v[0],v[4]);
e[7] = new Edge(v[4],v[0]);
e[6].opposite = e[7];
e[7].opposite = e[6];
e[8] = new Edge(v[1],v[2]);
e[9] = new Edge(v[2],v[1]);
e[8].opposite = e[9];
e[9].opposite = e[8];
e[10] = new Edge(v[2],v[3]);
e[11] = new Edge(v[3],v[2]);
e[10].opposite = e[11];
e[11].opposite = e[10];
e[12] = new Edge(v[3],v[4]);
e[13] = new Edge(v[4],v[3]);
e[12].opposite = e[13];
e[13].opposite = e[12];
e[14] = new Edge(v[4],v[1]);
e[15] = new Edge(v[1],v[4]);
f[0] = new Face(e[15],4);
f[1] = new Face(e[0],3);
f[2] = new Face(e[2],3);
f[3] = new Face(e[4],3);
f[4] = new Face(e[6],3);
f[0].name = "f0";
f[1].name = "f1";
f[2].name = "f2";
f[3].name = "f3";
f[4].name = "f4";
e[14].opposite = e[15];
e[15].opposite = e[14];
e[0].next = e[8];
e[0].previous = e[3];
e[0].face = f[1];
e[1].next = e[6];
e[1].previous = e[14];
e[1].face = f[4];
e[2].next = e[10];
e[2].previous = e[5];
e[2].face = f[2];
e[3].next = e[0];
e[3].previous = e[8];
e[3].face = f[1];
e[4].next = e[12];
e[4].previous = e[7];
e[4].face = f[3];
e[5].next = e[2];
e[5].previous = e[10];
e[5].face = f[2];
e[6].next = e[14];
e[6].previous = e[1];
e[6].face = f[4];
e[7].next = e[4];
e[7].previous = e[12];
e[7].face = f[3];
e[8].next = e[3];
e[8].previous = e[0];
e[8].face = f[1];
e[9].next = e[15];
e[9].previous = e[11];
e[9].face = f[0];
e[10].next = e[5];
e[10].previous = e[2];
e[10].face = f[2];
e[11].next = e[9];
e[11].previous = e[13];
e[11].face = f[0];
e[12].next = e[7];
e[12].previous = e[4];
e[12].face = f[3];
e[13].next = e[11];
e[13].previous = e[15];
e[13].face = f[0];
e[14].next = e[1];
e[14].previous = e[6];
e[14].face = f[4];
e[15].next = e[13];
e[15].previous = e[9];
e[15].face = f[0];
return e[0];
}
ArrayList<Face> faceTraversal(Face initialFace) { // lists all faces starting from initialFace
// assumes all face statuses are = 0
// uses Dijkstra-like algorithm
ArrayList<Face> finalList = new ArrayList<Face>();
ArrayList<Face> discoveredList = new ArrayList<Face>(); // list of discovered faces
ArrayList<Face> neighborsList = new ArrayList<Face>();
Face currentFace;
//Edge currentEdge = initialFace.inedge;
discoveredList.add(initialFace);
while (discoveredList.size() > 0) {
currentFace = discoveredList.get(0);
println(" currentFace = " + currentFace.name);
discoveredList.remove(0);
neighborsList = currentFace.incidentFaces();
for (Face f : neighborsList) {
if (f.status == 0) { // new face
f.status = 1; // switch to discovered
discoveredList.add(f);
}
}
finalList.add(currentFace);
currentFace.status = 2; // switch to marked
}
// clean all faces once done
for (Face f : finalList) {
f.status = 0;
}
println("exit faceTraversal");
return(finalList);
}