1 package edu.berkeley.qfat.geom;
2 import javax.media.opengl.*;
5 * An oriented triangle, defined by three points in order;
6 * note that the Point objects returned by p1/p2/p3 may vary over time.
8 public abstract class Triangle implements HasBoundingBox {
9 public abstract Point p1();
10 public abstract Point p2();
11 public abstract Point p3();
13 /** the face normal vector */
15 return p2().minus(p1()).cross(p3().minus(p1())).norm();
18 /** the area of the triangle */
21 (float)Math.abs(0.5*p1().distance(p2())
22 * new Vec(p1(), p2()).norm().dot(new Vec(p2(), p3())));
25 /** issue gl.glVertex() for each of the triangle's points */
26 public void glVertices(GL gl, Matrix m) {
27 (m==null ? norm() : m.times(norm())).glNormal(gl);
28 (m==null ? p1() : m.times(p1())).glVertex(gl);
29 (m==null ? p2() : m.times(p2())).glVertex(gl);
30 (m==null ? p3() : m.times(p3())).glVertex(gl);
33 /** the triangle's centroid */
34 public Point centroid() {
35 return new Point((p1().x+p2().x+p3().x)/3,
36 (p1().y+p2().y+p3().y)/3,
37 (p1().z+p2().z+p3().z)/3);
40 /** ratio of the area of the triangle to that of the square formed from its longest edge */
42 public float aspect() {
43 float max = Math.max(Math.max(p1().distance(p2()),
45 p3().distance(p1())) / 2;
46 return 1/(1+area()/(max*max));
50 public float circumcircleRadius() {
51 double a = p1().distance(p2());
52 double b = p2().distance(p3());
53 double c = p3().distance(p1());
54 return (float)((a*b*c)/Math.sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c)));
58 public float shortestEdgeLength() {
59 float a = p1().distance(p2());
60 float b = p2().distance(p3());
61 float c = p3().distance(p1());
62 return Math.min(a, Math.min(b,c));
65 /** a number ranging from 0..1 with 0 being lower quality */
67 public float quality() {
68 float d = shortestEdgeLength();
69 float r = circumcircleRadius();
70 if (r==0) throw new Error();
71 float ret = (float)((d*Math.cos(Math.PI/6))/(r*2));
72 if (ret < 0 || ret > 1) throw new Error("ret="+ret);
77 // FIXME: I stole this off the net, and I need to credit whoever wrote it
78 /** decide if the segment from p1-p2 intersects this triangle */
79 public boolean intersects(Point p1, Point p2) {
80 double A0=p1().x, A1=p1().y, A2=p1().z;
81 double B0=p2().x, B1=p2().y, B2=p2().z;
82 double C0=p3().x, C1=p3().y, C2=p3().z;
83 double j0=p1.x, j1=p1.y, j2=p1.z;
84 double k0=p2.x, k1=p2.y, k2=p2.z;
92 double R00, R01, R02, R03,
106 /* c = a × b */
107 c0 = a1 * b2 - a2 * b1;
108 c1 = a2 * b0 - a0 * b2;
109 c2 = a0 * b1 - a1 * b0;
111 /* M^(-1) = (1/det(M)) * adj(M) */
112 in_det = 1 / (c0 * c0 + c1 * c1 + c2 * c2);
113 R00 = (b1 * c2 - b2 * c1) * in_det;
114 R01 = (b2 * c0 - b0 * c2) * in_det;
115 R02 = (b0 * c1 - b1 * c0) * in_det;
116 R10 = (c1 * a2 - c2 * a1) * in_det;
117 R11 = (c2 * a0 - c0 * a2) * in_det;
118 R12 = (c0 * a1 - c1 * a0) * in_det;
124 R03 = -(R00 * A0 + R01 * A1 + R02 * A2);
125 R13 = -(R10 * A0 + R11 * A1 + R12 * A2);
126 R23 = -(R20 * A0 + R21 * A1 + R22 * A2);
128 /* fill in last row of 4x4 matrix */
132 J2 = R20 * j0 + R21 * j1 + R22 * j2 + R23;
133 K2 = R20 * k0 + R21 * k1 + R22 * k2 + R23;
134 if (J2 * K2 >= 0) return false;
136 J0 = R00 * j0 + R01 * j1 + R02 * j2 + R03;
137 K0 = R00 * k0 + R01 * k1 + R02 * k2 + R03;
138 i0 = J0 + J2 * ((K0 - J0) / (J2 - K2));
139 if (i0 < 0 || i0 > 1) return false;
141 J1 = R10 * j0 + R11 * j1 + R12 * j2 + R13;
142 K1 = R10 * k0 + R11 * k1 + R12 * k2 + R13;
143 i1 = J1 + J2 * ((K1 - J1) / (J2 - K2));
144 if (i1 < 0 || i1 > 1 || i0 + i1 > 1) return false;
149 public float getMaxX() { return Math.max(p1().x, Math.max(p2().x, p3().x)); }
150 public float getMinX() { return Math.min(p1().x, Math.min(p2().x, p3().x)); }
151 public float getMaxY() { return Math.max(p1().y, Math.max(p2().y, p3().y)); }
152 public float getMinY() { return Math.min(p1().y, Math.min(p2().y, p3().y)); }
153 public float getMaxZ() { return Math.max(p1().z, Math.max(p2().z, p3().z)); }
154 public float getMinZ() { return Math.min(p1().z, Math.min(p2().z, p3().z)); }