Created
September 25, 2011 21:07
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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