checkpoint
[anneal.git] / src / Geom.java
1 import java.awt.*;
2 import java.util.*;
3 import java.awt.event.*;
4 import javax.swing.*;
5 import javax.media.opengl.*;
6 import javax.media.opengl.glu.*;
7 import edu.wlu.cs.levy.CG.KDTree;
8
9 public class Geom implements Iterable<Geom.T> {
10
11     private KDTree kd = new KDTree(3);
12
13     public static float EPSILON = (float)0.0001;
14     public static Random random = new Random();
15
16     private HashMap<P,V>  ps = new HashMap<P,V>();
17     public  HashSet<E>    es = new HashSet<E>();
18     public  ArrayList<T>  ts = new ArrayList<T>();
19
20     public Iterator<T> iterator() { return ts.iterator(); }
21
22     public P origin() { return new P(0, 0, 0); }
23
24     public Geom score_against = null;
25     public double score = 0;
26     public float score() {
27         return (float)score;
28     }
29
30     public float rescore() {
31         int num = 0;
32         double dist = 0;
33         HashSet<V> done = new HashSet<V>();
34         for(T t : ts)
35             for(V p : new V[] { t.p1(), t.p2(), t.p3() }) {
36                 if (done.contains(p)) continue;
37                 done.add(p);
38                 p.rescore();
39             }
40         for(T t : ts)
41             for(V p : new V[] { t.p1(), t.p2(), t.p3() })
42                 p.kdremove();
43         kd = new KDTree(3);
44         for(T t : ts)
45             for(V p : new V[] { t.p1(), t.p2(), t.p3() })
46                 p.kdinsert();
47         return (float)(dist/num);
48     }
49
50     public void transform(M m) {
51         ArrayList<V> set = new ArrayList<V>();
52         set.addAll(ps.values());
53         for(V v : set) v.transform(m);
54     }
55
56     public Vec diagonal() {
57         float min_x = Float.MAX_VALUE;
58         float min_y = Float.MAX_VALUE;
59         float min_z = Float.MAX_VALUE;
60         float max_x = Float.MIN_VALUE;
61         float max_y = Float.MIN_VALUE;
62         float max_z = Float.MIN_VALUE;
63         for(P p : ps.keySet()) {
64             if (p.x < min_x) min_x = p.x;
65             if (p.y < min_y) min_y = p.y;
66             if (p.z < min_z) min_z = p.z;
67             if (p.x > max_x) max_x = p.x;
68             if (p.y > max_y) max_y = p.y;
69             if (p.z > max_z) max_z = p.z;
70         }
71         return new Vec(max_x - min_x, max_y - min_y, max_z - min_z);
72     }
73
74     public P centroid() {
75         float min_x = Float.MAX_VALUE;
76         float min_y = Float.MAX_VALUE;
77         float min_z = Float.MAX_VALUE;
78         float max_x = Float.MIN_VALUE;
79         float max_y = Float.MIN_VALUE;
80         float max_z = Float.MIN_VALUE;
81         for(P p : ps.keySet()) {
82             if (p.x < min_x) min_x = p.x;
83             if (p.y < min_y) min_y = p.y;
84             if (p.z < min_z) min_z = p.z;
85             if (p.x > max_x) max_x = p.x;
86             if (p.y > max_y) max_y = p.y;
87             if (p.z > max_z) max_z = p.z;
88         }
89         return new P((float)(max_x + min_x)/2,
90                      (float)(max_y + min_y)/2,
91                      (float)(max_z + min_z)/2);
92     }
93
94     public T newT(V p12, V p23, V p31, Vec norm) {
95         Vec norm2 = p31.p.minus(p12.p).cross(p23.p.minus(p12.p));
96         float dot = norm.dot(norm2);
97         //if (Math.abs(dot) < EPSILON) throw new Error("dot products within epsilon of each other: "+norm+" "+norm2);
98         if (dot < 0) { V p = p12; p12=p23; p23 = p; }
99         return newT(p12, p23, p31);
100     }
101
102     public float volume() {
103         double total = 0;
104         for(T t : ts) {
105             double area = t.area();
106             Vec origin_to_centroid = new Vec(new P(0, 0, 0), t.centroid());
107             boolean facingAway = t.norm().dot(origin_to_centroid) > 0;
108             double height = Math.abs(t.norm().dot(origin_to_centroid));
109             total += ((facingAway ? 1 : -1) * area * height) / 3.0;
110         }
111         return (float)total;
112     }
113
114     public V nearest(P p) {
115         Object[] results;
116         try { results = kd.nearest(new double[]{p.x,p.y,p.z},1); } catch (Exception e) { throw new Error(e); }
117         return (V)results[0];
118     }
119
120     public T newT(V p1, V p2, V p3) {
121         E e12 = p1.makeE(p2);
122         E e23 = p2.makeE(p3);
123         E e31 = p3.makeE(p1);
124         while(e12.next != e23 || e23.next != e31 || e31.next != e12) {
125             e12.makeAdjacent(e23);
126             e23.makeAdjacent(e31);
127             e31.makeAdjacent(e12);
128         }
129         T ret = e12.makeT();
130         if (e12.t == null) throw new Error();
131         if (e23.t == null) throw new Error();
132         if (e31.t == null) throw new Error();
133         return ret;
134     }
135
136     public final class V {
137         public P p;
138         public V(P p) {
139             this.p = p;
140             if (ps.get(p) != null) throw new Error();
141             ps.put(this.p, this);
142         }
143         /*
144         public int hashCode() {
145             throw new Error();
146         }
147         */
148         public void kdremove() {
149             if (!inserted) return;
150             inserted = false;
151             try { kd.delete(new double[]{p.x,p.y,p.z}); } catch (Exception e) { }
152         }
153         public void kdinsert() {
154             if (inserted) return;
155             inserted = true;
156             try { kd.insert(new double[]{p.x,p.y,p.z},this); } catch (Exception e) { throw new Error(e); }
157         }
158
159         public float score() { return oldscore; }
160         public void unscore() {
161             if (watch == null) return;
162             watch.watch_x -= p.x;
163             watch.watch_y -= p.y;
164             watch.watch_z -= p.z;
165             watch.watch_count--;
166             if (watch.watch_count==0) {
167                 watch.watch_x = 0;
168                 watch.watch_y = 0;
169                 watch.watch_z = 0;
170             }
171             watch = null;
172         }
173         public V partner() { return watch==null ? this : watch; }
174         public V watchback() { return watch_count==0 ? partner() :
175                 new P(watch_x/watch_count, watch_y/watch_count, watch_z/watch_count).register(); }
176         public void rescore() {
177             if (score_against == null) return;
178
179             score -= oldscore;
180             oldscore = 0;
181
182             if (watch != null) unscore();
183             V po = this;
184             if (watch == null) {
185                 watch = score_against.nearest(po.p);
186
187                 // don't attract to vertices that face the other way
188                 if (watch.norm().dot(norm()) < 0) {
189                     watch = null;
190                 } else {
191                     watch.watch_x += po.p.x;
192                     watch.watch_y += po.p.y;
193                     watch.watch_z += po.p.z;
194                     watch.watch_count++;
195                 }
196             }
197
198             double s1, s2;
199             if (watch_count==0) s1 = 0;
200             else                s1 = p.distance(watch_x/watch_count, watch_y/watch_count, watch_z/watch_count);
201             s2 = watch==null ? 0 : po.p.distance(watch.p);
202             oldscore = (float)(s1 + s2);
203             score += oldscore;
204         }
205
206
207         /** does NOT update bound pairs! */
208         public boolean transform(M m) {
209             // FIXME: screws up kdtree 
210             // FIXME: screws up hashmap
211             unscore();
212             try {
213                 if (ps.get(this.p)==null) throw new Error();
214                 ps.remove(this.p);
215                 float newx = m.a*p.x + m.b*p.y + m.c*p.z + m.d;
216                 float newy = m.e*p.x + m.f*p.y + m.g*p.z + m.h;
217                 float newz = m.i*p.x + m.j*p.y + m.k*p.z + m.l;
218                 this.p = new P(newx, newy, newz);
219                 // FIXME: what if we move onto exactly where another point is?
220                 ps.put(this.p,(V)this);
221             } catch (Exception e) {
222                 throw new RuntimeException(e);
223             }
224             rescore();
225             boolean good = true;
226             /*
227             for(T t : ts) {
228                 for(E e = this.e; ;) {
229                     if (e.intersects(t)) { good = false; break; }
230                     e = e.pair.next;
231                     if (e == this.e) break;
232                 }
233             }
234             */
235             /*
236                 if (t==this.t) continue;
237                 if (this.intersects(t)) good = false;
238             }
239             */
240             return good;
241         }
242         public boolean move(Vec v) {
243             M m = new M(v);
244             V p = this;
245             boolean good = true;
246             do {
247                 good &= p.transform(m);
248                 v = v.times(binding); // bleh wrong
249                 p = p.bound_to;
250             } while (p != this);
251             return good;
252         }
253
254         public E makeE(V p2) {
255             E e = getE(p2);
256             if (e != null) return e;
257             e = p2.getE(this);
258             if (this.e == null && p2.e == null) return this.e = new E(this, p2);
259             if (this.e == null && p2.e != null) return p2.makeE(this).pair;
260             return new E(getFreeIncident(), p2);
261         }
262
263         public E getFreeIncident() {
264             E ret = getFreeIncident(e, e);
265             if (ret != null) return ret;
266             ret = getFreeIncident(e.pair.next, e.pair.next);
267             if (ret == null) throw new Error("unable to find free incident to " + this);
268             return ret;
269         }
270
271         public E getFreeIncident(E start, E before) {
272             E e = start;
273             do {
274                 if (e.pair.p2 == this && e.pair.t == null && e.pair.next.t == null) return e.pair;
275                 e = e.pair.next;
276             } while(e != before);
277             return null;
278         }
279
280         public E getE(V p2) {
281             E e = this.e;
282             do {
283                 if (e==null) return null;
284                 if (e.p1 == this && e.p2 == p2) return e;
285                 e = e.pair.next;
286             } while (e!=this.e);
287             return null;
288         }
289
290         public boolean isBoundTo(V p) {
291             V px = p;
292             do {
293                 if (px==this) return true;
294                 px = px.bound_to;
295             } while(px != p);
296             return false;
297         }
298
299         public void unbind() { bound_to = this; binding = new M(); }
300         public void bind(V p) { bind(p, new M()); }
301         public void bind(V p, M binding) {
302             if (isBoundTo(p)) return;
303             V temp_bound_to = p.bound_to;
304             M temp_binding = p.binding;
305             p.bound_to = this.bound_to;
306             p.binding = binding.times(this.binding); // FIXME: may have order wrong here
307             this.bound_to = temp_bound_to;
308             this.binding = temp_binding.times(temp_binding); // FIXME: may have order wrong here
309         }
310         public Vec norm() {
311             Vec norm = new Vec(0, 0, 0);
312             E e = this.e;
313             do {
314                 if (e.t != null) norm = norm.plus(e.t.norm().times((float)e.prev.angle()));
315                 e = e.pair.next;
316             } while(e != this.e);
317             return norm.norm();
318         }
319         V bound_to = this;
320
321         int watch_count;
322         float watch_x;
323         float watch_y;
324         float watch_z;
325         V watch;
326         E e;                // some edge *leaving* this point
327         M binding = new M();
328         float oldscore = 0;
329         boolean inserted = false;
330     }
331
332     public class P {
333         float x, y, z;
334         public P(double x, double y, double z) { this((float)x, (float)y, (float)z); }
335         public P(float x, float y, float z) { this.x = x; this.y = y; this.z = z; }
336         public float distance(P p) { return distance(p.x, p.y, p.z); }
337         public float distance(float ox, float oy, float oz) { return (float)Math.sqrt((x-ox)*(x-ox)+(y-oy)*(y-oy)+(z-oz)*(z-oz)); }
338         public V register() { V v = ps.get(this); return v==null ? new V(this) : v; }
339         public P times(M m) { return m.times(this); }
340         public Vec minus(P p) { return new Vec(x-p.x, y-p.y, z-p.z); }
341         public P plus(Vec v) { return new P(x+v.x, y+v.y, z+v.z); }
342         public boolean equals(Object o) { return o!=null && (o instanceof P) && ((P)o).x==x && ((P)o).y==y && ((P)o).z==z; }
343         public void glVertex(GL gl) { _glVertex(gl); }
344         private void _glVertex(GL gl) { gl.glVertex3f(x, y, z); }
345         public String toString() { return "("+x+","+y+","+z+")"; }
346         // FIXME: moving a point alters its hashCode
347         public int hashCode() {
348             return
349                 Float.floatToIntBits(x) ^
350                 Float.floatToIntBits(y) ^
351                 Float.floatToIntBits(z);
352         }
353     }
354
355     /** vector in 3-space */
356     public final class Vec {
357         public final float x, y, z;
358         public Vec(double x, double y, double z) { this((float)x, (float)y, (float)z); }
359         public Vec(float x, float y, float z) { this.x = x; this.y = y; this.z = z; }
360         public Vec(P p1, P p2) { this(p2.x-p1.x, p2.y-p1.y, p2.z-p1.z); }
361         public Vec cross(Vec v) { return new Vec(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); }
362         public Vec plus(Vec v) { return new Vec(x+v.x, y+v.y, z+v.z); }
363         public Vec norm() { return mag()==0 ? this : div(mag()); }
364         public Vec times(M m) { return m.apply(this); }
365         public float mag() { return (float)Math.sqrt(x*x+y*y+z*z); }
366         public float dot(Vec v) { return x*v.x + y*v.y + z*v.z; }
367         public Vec times(float mag) { return new Vec(x*mag, y*mag, z*mag); }
368         public Vec div(float mag) { return new Vec(x/mag, y/mag, z/mag); }
369         public String toString() { return "<"+x+","+y+","+z+">"; }
370     }
371
372     public class BindingGroup {
373         public HashSet<E> es = new HashSet<E>();
374         public BindingGroup() { }
375         public BindingGroup(E e) {
376             es.add(e);
377         }
378         public void add(E e) {
379             if (e.bg != null) { merge(e.bg); return; }
380             es.add(e);
381             e.bg = this;
382         }
383         public void merge(BindingGroup bg) {
384             for(E e : bg.es) {
385                 e.bg = null;
386                 add(e);
387             }
388         }
389     }
390
391     /** [UNIQUE] an edge */
392     public final class E implements Comparable<E> {
393
394         public boolean intersects(T t) {
395             double A0=t.p1().p.x, A1=t.p1().p.y, A2=t.p1().p.z;
396             double B0=t.p2().p.x, B1=t.p2().p.y, B2=t.p2().p.z;
397             double C0=t.p3().p.x, C1=t.p3().p.y, C2=t.p3().p.z;
398             double j0=p1.p.x, j1=p1.p.y, j2=p1.p.z;
399             double k0=p2.p.x, k1=p2.p.y, k2=p2.p.z;
400             double J0, J1, J2;
401             double K0, K1, K2;
402             double i0, i1, i2;
403             double a0, a1, a2;
404             double b0, b1, b2;
405             double c0, c1, c2;
406             double in_det;
407             double R00, R01, R02, R03,
408                 R10, R11, R12, R13,
409                 R20, R21, R22, R23,
410                 R30, R31, R32, R33;
411
412
413             /* a = B - A */
414             a0 = B0 - A0; 
415             a1 = B1 - A1; 
416             a2 = B2 - A2;
417             /* b = C - B */
418             b0 = C0 - A0;
419             b1 = C1 - A1;
420             b2 = C2 - A2;
421             /* c = a &times; b */
422             c0 = a1 * b2 - a2 * b1;
423             c1 = a2 * b0 - a0 * b2;
424             c2 = a0 * b1 - a1 * b0;
425  
426             /* M^(-1) = (1/det(M)) * adj(M) */
427             in_det = 1 / (c0 * c0 + c1 * c1 + c2 * c2);
428             R00 = (b1 * c2 - b2 * c1) * in_det;
429             R01 = (b2 * c0 - b0 * c2) * in_det;
430             R02 = (b0 * c1 - b1 * c0) * in_det;
431             R10 = (c1 * a2 - c2 * a1) * in_det;
432             R11 = (c2 * a0 - c0 * a2) * in_det;
433             R12 = (c0 * a1 - c1 * a0) * in_det;
434             R20 = (c0) * in_det;
435             R21 = (c1) * in_det;
436             R22 = (c2) * in_det;
437   
438             /* O = M^(-1) * A */
439             R03 = -(R00 * A0 + R01 * A1 + R02 * A2);
440             R13 = -(R10 * A0 + R11 * A1 + R12 * A2);
441             R23 = -(R20 * A0 + R21 * A1 + R22 * A2);
442  
443             /* fill in last row of 4x4 matrix */
444             R30 = R31 = R32 = 0;
445             R33 = 1;
446   
447             J2 = R20 * j0 + R21 * j1 + R22 * j2 + R23;
448             K2 = R20 * k0 + R21 * k1 + R22 * k2 + R23;
449             if (J2 * K2 >= 0) return false;
450
451             J0 = R00 * j0 + R01 * j1 + R02 * j2 + R03;
452             K0 = R00 * k0 + R01 * k1 + R02 * k2 + R03;
453             i0 = J0 + J2 * ((K0 - J0) / (J2 - K2));
454             if (i0 < 0 || i0 > 1) return false;
455   
456             J1 = R10 * j0 + R11 * j1 + R12 * j2 + R13;
457             K1 = R10 * k0 + R11 * k1 + R12 * k2 + R13;
458             i1 = J1 + J2 * ((K1 - J1) / (J2 - K2));
459             if (i1 < 0 || i1 > 1 || i0 + i1 > 1) return false;
460
461             return true;            
462         }
463
464         public int compareTo(E e) {
465             return e.length() > length() ? 1 : -1;
466         }
467
468         public final V p1, p2;
469         T t;     // triangle to our "left"
470         E prev;  // previous half-edge
471         E next;  // next half-edge
472         E pair;  // partner half-edge
473
474
475         public BindingGroup bg = new BindingGroup(this);
476
477         public void bind(E e) { bind(e, new M()); }
478         public void bind(E e, M m) { e.bg.add(this); }
479
480         public void dobind() {
481             if (bg==null) return;
482             for(E ex : bg.es) {
483                 if (ex==this) continue;
484                 p1.bind(ex.p1);
485                 p2.bind(ex.p2);
486             }
487         }
488
489         boolean shattered = false;
490         public V shatter() { return shatter(midpoint().register(), null, null); }
491         public V shatter(V mid, BindingGroup bg1, BindingGroup bg2) {
492             if (shattered) return mid;
493             shattered = true;
494
495             V r = next.p2;
496             E next = this.next;
497             E prev = this.prev;
498
499             if (bg1==null) bg1 = new BindingGroup();
500             if (bg2==null) bg2 = new BindingGroup();
501             for(E e : bg.es) e.shatter(e.midpoint().register(), bg1, bg2);
502             pair.shatter();
503             destroy();
504
505             newT(r, p1, mid);
506             newT(r, mid, p2);
507             bg1.add(p1.getE(mid));
508             bg2.add(mid.getE(p2));
509             return mid;
510         }
511
512         public boolean destroyed = false;
513         public void destroy() {
514             if (destroyed) return;
515             destroyed = true;
516             pair.destroyed = true;
517             if (next.t != null) next.t.destroy();
518             if (prev.t != null) prev.t.destroy();
519             if (pair.next.t != null) ts.remove(pair.next.t);
520             if (pair.prev.t != null) ts.remove(pair.prev.t);
521             next.t = null;
522             prev.t = null;
523             pair.next.t = null;
524             pair.prev.t = null;
525             this.bg = null;
526             pair.bg = null;
527             pair.prev.next = next;
528             next.prev = pair.prev;
529             prev.next = pair.next;
530             pair.next = prev;
531             if (p1.e == this) p1.e = prev.next;
532             if (pair.p1.e == pair) pair.p1.e = pair.prev.next;
533             es.remove(this);
534             es.remove(pair);
535             avgedge -= this.length();
536             avgedge -= pair.length();
537             numedges--;
538             numedges--;
539         }
540
541         private void sync() {
542             this.prev.next = this;
543             this.next.prev = this;
544             this.pair.pair = this;
545             if (this.next.p1 != p2) throw new Error();
546             if (this.prev.p2 != p1) throw new Error();
547             if (this.p1.e == null) this.p1.e = this;
548             es.add(this);
549             if (!added) {
550                 added = true;
551                 numedges++;
552                 avgedge += length();
553             }
554         }
555         private boolean added = false;
556
557         public T makeT() { return t==null ? (t = new T(this)) : t; }
558
559         /** angle between this half-edge and the next */
560         public double angle() {
561             Vec v1 = next.p2.p.minus(p2.p);
562             Vec v2 = this.p1.p.minus(p2.p);
563             return Math.acos(v1.norm().dot(v2.norm()));
564         }
565
566         public void makeAdjacent(E e) {
567             if (this.next == e) return;
568             if (p2 != e.p1) throw new Error("cannot make adjacent -- no shared vertex");
569             if (t != null || e.t != null) throw new Error("cannot make adjacent -- edges not both free");
570
571             E freeIncident = p2.getFreeIncident(e, this);
572
573             e.prev.next = freeIncident.next;
574             freeIncident.next.prev = e.prev;
575
576             freeIncident.next = this.next;
577             this.next.prev = freeIncident;
578             
579             this.next = e;
580             e.prev = this;
581
582             sync();
583             freeIncident.sync();
584         }
585
586         /** creates an isolated edge out in the middle of space */
587         public E(V p1, V p2) {
588             if (p1==p2) throw new Error("attempt to create edge with single vertex: " + p1);
589             this.p1 = p1;
590             this.p2 = p2;
591             this.prev = this.next = this.pair = new E(this, this, this);
592             sync();
593         }
594
595         /** adds a new half-edge from prev.p2 to p2 */
596         public E(E prev, V p2) {
597             this.p1 = prev.p2;
598             this.p2 = p2;
599             this.prev = prev;
600             if (p2.getE(p1) != null) throw new Error();
601             if (p2.e==null) {
602                 this.next = this.pair = new E(this, this, prev.next);
603             } else {
604                 E q = p2.getFreeIncident();
605                 this.next = q.next;
606                 this.next.prev = this;
607                 E z = prev.next;
608                 this.prev.next = this;
609                 this.pair = new E(q, this, z);
610             }
611             sync();
612         }
613
614         /** adds a new half-edge to the mesh with a given predecessor, successor, and pair */
615         public E(E prev, E pair, E next) {
616             this.p1 = prev.p2;
617             this.p2 = next.p1;
618             this.prev = prev;
619             this.next = next;
620             this.pair = pair;
621             sync();
622         }
623         public P midpoint() { return new P((p1.p.x+p2.p.x)/2, (p1.p.y+p2.p.y)/2, (p1.p.z+p2.p.z)/2); }
624         public boolean has(V v) { return v==p1 || v==p2; }
625         public float length() { return p1.p.minus(p2.p).mag(); }
626         public String toString() { return p1+"->"+p2; }
627     }
628
629     /** [UNIQUE] a triangle (face) */
630     public final class T {
631         public final E e1;
632         public final int color;
633
634         public void destroy() {
635             ts.remove(this);
636         }
637
638         public V nearest(P p) {
639             float d1 = p1().p.distance(p);
640             float d2 = p2().p.distance(p);
641             float d3 = p3().p.distance(p);
642             if (d1 < d2 && d1 < d3) return p1();
643             if (d2 < d3) return p2();
644             return p3();
645         }
646
647         T(E e1) {
648             this.e1 = e1;
649             E e2 = e1.next;
650             E e3 = e2.next;
651             if (e1==e2     || e1==e3) throw new Error();
652             if (e3.next!=e1) throw new Error();
653             if (e1.t!=null || e2.t!=null || e3.t!=null)
654                 throw new Error("non-manifold surface or disagreeing normals");
655             e1.t = this;
656             e1.next.t = this;
657             e1.next.next.t = this;
658
659             // FIXME: check for sealed/watertight surface once construction is complete (and infer normal(s)?)
660
661             int color = Math.abs(random.nextInt());
662             while(true) {
663                 color = color % 4;
664                 if (e1().pair.t != null && color == e1().pair.t.color) { color++; continue; }
665                 if (e2().pair.t != null && color == e2().pair.t.color) { color++; continue; }
666                 if (e3().pair.t != null && color == e3().pair.t.color) { color++; continue; }
667                 break;
668             }
669
670             // FIXME unnecssary
671             ts.add(this);
672             p1().kdinsert();
673             p2().kdinsert();
674             p3().kdinsert();
675
676             this.color = color;
677         }
678         public V p1() { return e1.p1; }
679         public V p2() { return e1.p2; }
680         public V p3() { return e1.next.p2; }
681         public E e1() { return e1; }
682         public E e2() { return e1.next; }
683         public E e3() { return e1.prev; }
684         public Vec norm() { return p2().p.minus(p1().p).cross(p3().p.minus(p1().p)).norm(); }
685         public boolean hasE(E e) { return e1==e || e1.next==e || e1.prev==e; }
686         public boolean has(V v) { return p1()==v || p2()==v || p3()==v; }
687
688         public float area() {
689             return (float)Math.abs(0.5 * e1().length() * new Vec(p1().p, p2().p).norm().dot(new Vec(p2().p, p3().p)));
690         }
691
692         public void glVertices(GL gl) {
693             p1().p.glVertex(gl);
694             p2().p.glVertex(gl);
695             p3().p.glVertex(gl);
696         }
697
698         public P centroid() { return new P((p1().p.x+p2().p.x+p3().p.x)/3,
699                                           (p1().p.y+p2().p.y+p3().p.y)/3, 
700                                           (p1().p.z+p2().p.z+p3().p.z)/3); }
701         public float diameter() {
702             // FIXME: what is this supposed to be?
703             return Math.max(Math.max(e1().length(), e2().length()), e3().length()) / 2;
704         }
705
706
707     }
708
709
710     /** matrix */
711     public class M {
712         //
713         //  [ a b c d ]   [ x ]
714         //  [ e f g h ]   [ y ]
715         //  [ i j k l ]   [ z ]
716         //  [ 0 0 0 1 ]   [ 1 ]
717         //
718         public final float a, b, c, d, e, f, g, h, i, j, k, l;
719         public M() { this(1); }
720         public M(float scale) {
721             a = f = k = scale;
722             l = h = d = e = b = i = c = j = g = 0;            
723         }
724         public M(float scalex, float scaley, float scalez) {
725             a = scalex;
726             f = scaley;
727             k = scalez;
728             l = h = d = e = b = i = c = j = g = 0;            
729         }
730         public M(Vec translate) {
731             d = translate.x; h = translate.y; l = translate.z;
732             a = f = k = 1;
733             b = c = e = g = i = j = 0;
734         }
735         public M(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l) {
736             this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h; this.i = i;
737             this.j = j; this.k = k; this.l = l;
738         }
739         public M times(float x) {
740             return new M(a*x, b*x, c*x, d*x, e*x, f*x, g*x, h*x, i*x, j*x, k*x, l*x);
741         }
742         public M(Vec axis, float angle) {
743             double q = Math.cos(angle);
744             double s = Math.sin(angle);
745             double t = 1.0 - q;
746             a = (float)(q + axis.x*axis.x*t);
747             f = (float)(q + axis.y*axis.y*t);
748             k = (float)(q + axis.z*axis.z*t);
749             double tmp1 = axis.x*axis.y*t;
750             double tmp2 = axis.z*s;
751             e = (float)(tmp1 + tmp2);
752             b = (float)(tmp1 - tmp2);
753             tmp1 = axis.x*axis.z*t;
754             tmp2 = axis.y*s;
755             i = (float)(tmp1 - tmp2);
756             c = (float)(tmp1 + tmp2);
757             tmp1 = axis.y*axis.z*t;
758             tmp2 = axis.x*s;
759             j = (float)(tmp1 + tmp2);
760             g = (float)(tmp1 - tmp2);
761             d = h = l = 0;
762         }
763         public P times(P p) {
764             return new P(a*p.x + b*p.y + c*p.z + d,
765                         e*p.x + f*p.y + g*p.z + h,
766                         i*p.x + j*p.y + k*p.z + l);
767         }
768         public P apply(P p) { return p; }
769         public Vec apply(Vec v) { return v; }
770         public M invert() { return this; }
771         public M times(M m) { return this; }
772     }
773
774     public void unbind() {
775
776         for(Geom.T t : this) {
777             t.p1().unbind();
778             t.p2().unbind();
779             t.p3().unbind();
780         }
781
782     }
783     public void bind() {
784         for(Geom.T t : this) {
785             t.e1().dobind();
786             t.e2().dobind();
787             t.e3().dobind();
788         }
789     }
790     public int numedges = 0;
791     public float avgedge = 0;
792 }