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