checkpoint
[anneal.git] / src / edu / berkeley / qfat / geom / Triangle.java
index 18c73a0..9db806b 100644 (file)
@@ -2,7 +2,8 @@ package edu.berkeley.qfat.geom;
 import javax.media.opengl.*;
 
 /**
- *  an oriented triangle, defined by three points in clockwise order.
+ *  An oriented triangle, defined by three points in order;
+ *  note that the Point objects returned by p1/p2/p3 may vary over time.
  */
 public abstract class Triangle implements HasBoundingBox {
     public abstract Point p1();
@@ -22,10 +23,18 @@ public abstract class Triangle implements HasBoundingBox {
     }
 
     /** issue gl.glVertex() for each of the triangle's points */
-    public void glVertices(GL gl) {
-        p1().glVertex(gl);
-        p2().glVertex(gl);
-        p3().glVertex(gl);
+    public void glVertices(GL gl, Matrix m) {
+        if (m==null) {
+            norm().glNormal(gl);
+            p1().glVertex(gl);
+            p2().glVertex(gl);
+            p3().glVertex(gl);
+        } else {
+            m.times(norm()).glNormal(gl);
+            m.times(p1()).glVertex(gl);
+            m.times(p2()).glVertex(gl);
+            m.times(p3()).glVertex(gl);
+        }
     }
 
     /** the triangle's centroid */
@@ -36,12 +45,110 @@ public abstract class Triangle implements HasBoundingBox {
     }
 
     /** ratio of the area of the triangle to that of the square formed from its longest edge */
+    /*
     public float aspect() {
         float max = Math.max(Math.max(p1().distance(p2()),
                                       p2().distance(p3())),
                              p3().distance(p1())) / 2;
         return 1/(1+area()/(max*max));
     }
+    */
+
+    public float circumcircleRadius() {
+        double a = p1().distance(p2());
+        double b = p2().distance(p3());
+        double c = p3().distance(p1());
+        return (float)((a*b*c)/Math.sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c)));
+    }
+
+    public float shortestEdgeLength() {
+        float a = p1().distance(p2());
+        float b = p2().distance(p3());
+        float c = p3().distance(p1());
+        return Math.min(a, Math.min(b,c));
+    }
+
+    /** a number ranging from 0..1 with 0 being lower quality */
+    public float quality() {
+        float d = shortestEdgeLength();
+        float r = circumcircleRadius();
+        if (r==0) throw new Error();
+        float ret = (float)((d*Math.cos(Math.PI/6))/(r*2));
+        if (ret < 0 || ret > 1) throw new Error("ret="+ret);
+        return ret;
+    }
+
+    // FIXME: I stole this off the net, and I need to credit whoever wrote it
+    /** decide if the segment from p1-p2 intersects this triangle */
+    public boolean intersects(Point p1, Point p2) {
+        double A0=p1().x, A1=p1().y, A2=p1().z;
+        double B0=p2().x, B1=p2().y, B2=p2().z;
+        double C0=p3().x, C1=p3().y, C2=p3().z;
+        double j0=p1.x, j1=p1.y, j2=p1.z;
+        double k0=p2.x, k1=p2.y, k2=p2.z;
+        double J0, J1, J2;
+        double K0, K1, K2;
+        double i0, i1, i2;
+        double a0, a1, a2;
+        double b0, b1, b2;
+        double c0, c1, c2;
+        double in_det;
+        double R00, R01, R02, R03,
+            R10, R11, R12, R13,
+            R20, R21, R22, R23,
+            R30, R31, R32, R33;
+
+
+        /* a = B - A */
+        a0 = B0 - A0; 
+        a1 = B1 - A1; 
+        a2 = B2 - A2;
+        /* b = C - B */
+        b0 = C0 - A0;
+        b1 = C1 - A1;
+        b2 = C2 - A2;
+        /* c = a &times; b */
+        c0 = a1 * b2 - a2 * b1;
+        c1 = a2 * b0 - a0 * b2;
+        c2 = a0 * b1 - a1 * b0;
+        /* M^(-1) = (1/det(M)) * adj(M) */
+        in_det = 1 / (c0 * c0 + c1 * c1 + c2 * c2);
+        R00 = (b1 * c2 - b2 * c1) * in_det;
+        R01 = (b2 * c0 - b0 * c2) * in_det;
+        R02 = (b0 * c1 - b1 * c0) * in_det;
+        R10 = (c1 * a2 - c2 * a1) * in_det;
+        R11 = (c2 * a0 - c0 * a2) * in_det;
+        R12 = (c0 * a1 - c1 * a0) * in_det;
+        R20 = (c0) * in_det;
+        R21 = (c1) * in_det;
+        R22 = (c2) * in_det;
+  
+        /* O = M^(-1) * A */
+        R03 = -(R00 * A0 + R01 * A1 + R02 * A2);
+        R13 = -(R10 * A0 + R11 * A1 + R12 * A2);
+        R23 = -(R20 * A0 + R21 * A1 + R22 * A2);
+        /* fill in last row of 4x4 matrix */
+        R30 = R31 = R32 = 0;
+        R33 = 1;
+  
+        J2 = R20 * j0 + R21 * j1 + R22 * j2 + R23;
+        K2 = R20 * k0 + R21 * k1 + R22 * k2 + R23;
+        if (J2 * K2 >= 0) return false;
+
+        J0 = R00 * j0 + R01 * j1 + R02 * j2 + R03;
+        K0 = R00 * k0 + R01 * k1 + R02 * k2 + R03;
+        i0 = J0 + J2 * ((K0 - J0) / (J2 - K2));
+        if (i0 < 0 || i0 > 1) return false;
+  
+        J1 = R10 * j0 + R11 * j1 + R12 * j2 + R13;
+        K1 = R10 * k0 + R11 * k1 + R12 * k2 + R13;
+        i1 = J1 + J2 * ((K1 - J1) / (J2 - K2));
+        if (i1 < 0 || i1 > 1 || i0 + i1 > 1) return false;
+
+        return true;            
+    }
 
     public float getMaxX() { return Math.max(p1().x, Math.max(p2().x, p3().x)); }
     public float getMinX() { return Math.min(p1().x, Math.min(p2().x, p3().x)); }