Skip to content

Instantly share code, notes, and snippets.

@alexras
Created September 25, 2011 21:07
Show Gist options
  • Save alexras/1241152 to your computer and use it in GitHub Desktop.
Save alexras/1241152 to your computer and use it in GitHub Desktop.
Quick-and-dirty Delaunay triangulation in Processing used to create http://youtu.be/dsrMjbR0usA
float dpLength(DelaunayPoint p1, DelaunayPoint p2) {
float deltaX = p2.x - p1.x;
float deltaY = p2.y - p1.y;
float deltaZ = p2.z - p1.z;
return sqrt((deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ));
}
DelaunayPoint dpAdd(DelaunayPoint p1, DelaunayPoint p2)
{
DelaunayPoint p = new DelaunayPoint(p1);
p.x += p2.x;
p.y += p2.y;
p.z += p2.z;
return p;
}
boolean tooFar(DelaunayPoint target, DelaunayPoint host)
{
return dpLength(target, host) > 10;
}
boolean disqualifyTri(DelaunayTriangle tri) {
return Float.isNaN(tri.area()) || tri.area() > 25;
}
public class DelaunayPoint {
public float x;
public float y;
public float z;
public int intensity;
public DelaunayPoint(float x, float y, float z, int intensity) {
this.x = x;
this.y = y;
this.z = z;
this.intensity = intensity;
}
public void draw() {
stroke(intensity * 1.6, intensity * 1.2, 200);
line(x, y, z, x+0.5, y+0.5, z+0.5);
}
public DelaunayPoint(DelaunayPoint p) {
x = p.x;
y = p.y;
z = p.z;
intensity = p.intensity;
}
public DelaunayPoint() {}
public DelaunayPoint scalarMult(float scalar) {
DelaunayPoint p = new DelaunayPoint(this);
p.x *= scalar;
p.y *= scalar;
p.z *= scalar;
return p;
}
public String toString() {
return x + "," + y + "," + z;
}
}
public class DelaunayTriangle {
DelaunayPoint p1;
DelaunayPoint p2;
DelaunayPoint p3;
DelaunayPoint circumcenter = null;
float area;
private boolean areaDefined = false;
float threshold = 2;
public DelaunayTriangle(DelaunayPoint p1, DelaunayPoint p2, DelaunayPoint p3) {
this.p1 = new DelaunayPoint(p1);
this.p2 = new DelaunayPoint(p2);
this.p3 = new DelaunayPoint(p3);
}
public String toString() {
// return p1 + " : " + p2 + " : " + p3;
return Float.toString(area());
}
public float area() {
if (!areaDefined) {
float a = dpLength(p1, p2);
float b = dpLength(p2, p3);
float c = dpLength(p3, p1);
float x = ((a * a) + (b * b) - (c * c));
area = sqrt(4 * a * a * b * b - x * x) / 4.0;
areaDefined = true;
}
return area;
}
public DelaunayPoint circumcenter() {
if (circumcenter == null) {
float a = dpLength(p3, p2);
float b = dpLength(p1, p3);
float c = dpLength(p1, p2);
float aSquared = a*a;
float bSquared = b*b;
float cSquared = c*c;
DelaunayPoint A = p1.scalarMult(aSquared * (bSquared + cSquared - aSquared));
DelaunayPoint B = p2.scalarMult(bSquared * (aSquared + cSquared - bSquared));
DelaunayPoint C = p3.scalarMult(cSquared * (aSquared + bSquared - cSquared));
DelaunayPoint D = dpAdd(dpAdd(A, B), C);
circumcenter = D.scalarMult(1.0 / ( 2 * (aSquared * bSquared + aSquared * cSquared + bSquared * cSquared ) - (aSquared * aSquared + bSquared * bSquared + cSquared * cSquared)));
}
return circumcenter;
}
public float circumradius() {
return dpLength(p1, circumcenter());
}
public void grow(float growFactor) {
growPoint(p1, growFactor);
growPoint(p2, growFactor);
growPoint(p3, growFactor);
}
private void growPoint(DelaunayPoint p, float growFactor) {
DelaunayPoint c = circumcenter();
float deltaX = p.x - c.x;
float deltaY = p.y - c.y;
float deltaZ = p.z - c.z;
float mult = growFactor - 1.0;
p.x += mult * deltaX;
p.y += mult * deltaY;
p.z += mult * deltaZ;
}
public void draw() {
int avgIntensity = (p1.intensity + p2.intensity + p3.intensity) / 3;
// int avgIntensity = int(floor(random(0, 255)));
// int g = int(floor(random(0, 255)));
// int b = int(floor(random(0, 255)));
//intensity*1.1,intensity*1.6,200,255
float r = avgIntensity * 1.1;
float g = avgIntensity * 1.6;
float b = 200;
fill(r,g,b,255);
noStroke();
/*
line(p1.x, p1.y, p1.z, p1.x + 1.0, p1.y + 1.0, p1.z + 1.0);
line(p2.x, p2.y, p2.z, p2.x + 1.0, p2.y + 1.0, p2.z + 1.0);
line(p3.x, p3.y, p3.z, p3.x + 1.0, p3.y + 1.0, p3.z + 1.0);
*/
// grow(2.5);
smooth();
beginShape(TRIANGLES);
vertex(int(p1.x), int(p1.y), int(p1.z));
vertex(int(p2.x), int(p2.y), int(p2.z));
vertex(int(p3.x), int(p3.y), int(p3.z));
endShape();
strokeWeight(1);
}
}
public class Delaunay {
public ArrayList points;
public Delaunay(String[] raw, int threshold) {
points = new ArrayList();
for(int i = 0; i < raw.length;i++){
// For each line we're going to divide up each paramety
String[] thisLine = split(raw[i],',');
// Now we will make a variable for each parameter specified in the file. They will be decimal values.
float x = float(thisLine[0]);
float y = float(thisLine[1]);
float z = float(thisLine[2]);
int intensity = int(thisLine[3]);
if (intensity > threshold) {
DelaunayPoint newPoint = new DelaunayPoint(x, y, z, intensity);
newPoint.draw();
points.add(newPoint);
}
}
Collections.shuffle(points);
}
public void draw() {
int numPoints = points.size();
boolean printed = false;
int numTris = 0;
for (ListIterator i = points.listIterator(); i.hasNext(); ) {
////println("i " + i.nextIndex() + " : " + (DelaunayPoint) points.get(i.nextIndex()));
DelaunayPoint pointA = (DelaunayPoint) i.next();
for (ListIterator j = points.listIterator(i.nextIndex()); j.hasNext(); ) {
////println("j " + j.nextIndex() + " : " + (DelaunayPoint) points.get(j.nextIndex()));
DelaunayPoint pointB = (DelaunayPoint) j.next();
if (tooFar(pointB, pointA)) {
continue;
}
for (ListIterator k = points.listIterator(j.nextIndex()); k.hasNext(); ) {
////println("k " + k.nextIndex() + " : " + (DelaunayPoint) points.get(k.nextIndex()));
DelaunayPoint pointC = (DelaunayPoint) k.next();
if (tooFar(pointC,pointB) || tooFar(pointC, pointA)) {
continue;
}
////println("Before: " + points);
DelaunayTriangle tri = new DelaunayTriangle(pointA, pointB, pointC);
////println("After: " + points);
// ////println(tri);
if (!disqualifyTri(tri)) {
/*
pointA.draw(255);
pointB.draw(255);
pointC.draw(255);
tri.circumcenter().draw(126);
tri.draw();
*/
boolean canDraw = true;
for (ListIterator l = points.listIterator(); l.hasNext(); ) {
DelaunayPoint innerPoint = (DelaunayPoint) l.next();
float len = dpLength(innerPoint, tri.circumcenter());
if (dpLength(innerPoint, tri.circumcenter()) < tri.circumradius() - 0.1) {
canDraw = false;
break;
}
}
if (canDraw) {
tri.draw();
numTris++;
}
}
}
}
int percent = (i.nextIndex() * 100) / numPoints;
if (percent % 10 == 0) {
if(!printed) {
println(percent + "%");
printed = true;
}
} else {
printed = false;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment