use rtree for intersection testing
[anneal.git] / src / edu / berkeley / qfat / Mesh.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 Mesh implements Iterable<Mesh.T> {
13
14     public static final float EPSILON = (float)0.0001;
15     public static final Random random = new Random();
16
17     private PointSet<Vert> pointset = new PointSet<Vert>();
18     public int size() { return pointset.size(); }
19     public Iterable<Vert> vertices() { return pointset; }
20
21     public Iterable<E> edges() {
22         return
23             new Iterable<E>() {
24             public Iterator<E> iterator() {
25                 // HACK
26                 HashSet<E> hse = new HashSet<E>();
27                 for(T t : Mesh.this) {
28                     hse.add(t.e1());
29                     hse.add(t.e2());
30                     hse.add(t.e3());
31                     hse.add(t.e1().pair);
32                     hse.add(t.e2().pair);
33                     hse.add(t.e3().pair);
34                 }
35                 return hse.iterator();
36             } };
37     }
38
39     public Iterator<T> iterator() {
40         /*
41         for(Vert v : pointset)
42             if (v.e != null && v.e.t != null)
43                 return new FaceIterator(v);
44         return new FaceIterator();
45         */
46         return ts.iterator();
47     }
48
49     public HashSet<T> ts = new HashSet<T>();
50     public RTree<T> tris = new RTree<T>();
51
52     public Mesh score_against = null;
53     public double score = 0;
54     public float score() { return (float)score; }
55
56     public int numedges = 0;
57     public float avgedge = 0;
58
59     public void rebindPoints() {
60         // unbind all points
61         for(Mesh.T t : this) {
62             t.v1().unbind();
63             t.v2().unbind();
64             t.v3().unbind();
65         }
66         // ask edges to re-implement their bindings
67         for(Mesh.T t : this) {
68             t.e1().dobind();
69             t.e2().dobind();
70             t.e3().dobind();
71         }
72     }
73
74     public void unApplyQuadricToNeighborAll() {
75         HashSet<Vert> done = new HashSet<Vert>();
76         for(T t : this)
77             for(Vert p : new Vert[] { t.v1(), t.v2(), t.v3() }) {
78                 if (done.contains(p)) continue;
79                 done.add(p);
80                 p.unApplyQuadricToNeighbor();
81             }
82     }
83     public void recomputeAllFundamentalQuadrics() {
84         HashSet<Vert> done = new HashSet<Vert>();
85         for(T t : this)
86             for(Vert p : new Vert[] { t.v1(), t.v2(), t.v3() }) {
87                 if (done.contains(p)) continue;
88                 done.add(p);
89                 p.recomputeFundamentalQuadric();
90             }
91     }
92     public float applyQuadricToNeighborAll() {
93         int num = 0;
94         double dist = 0;
95         HashSet<Vert> done = new HashSet<Vert>();
96         for(T t : this)
97             for(Vert p : new Vert[] { t.v1(), t.v2(), t.v3() }) {
98                 if (done.contains(p)) continue;
99                 done.add(p);
100                 p.applyQuadricToNeighbor();
101                 
102             }
103         return (float)(dist/num);
104     }
105
106     public void transform(Matrix m) {
107         ArrayList<Vert> set = new ArrayList<Vert>();
108         for (Vert v : pointset)
109             set.add(v);
110         for(Vert v : set) v.transform(m);
111     }
112
113     public float volume() {
114         double total = 0;
115         for(T t : this) {
116             double area = t.area();
117             Vec origin_to_centroid = new Vec(new Point(0, 0, 0), t.centroid());
118             boolean facingAway = t.norm().dot(origin_to_centroid) > 0;
119             double height = Math.abs(t.norm().dot(origin_to_centroid));
120             total += ((facingAway ? 1 : -1) * area * height) / 3.0;
121         }
122         return (float)total;
123     }
124
125     public void rebuildPointSet() { pointset.rebuild(); }
126     public Vec diagonal() { return pointset.diagonal(); }
127     public Point centroid() { return pointset.centroid(); }
128     public Vert nearest(Point p) { return pointset.nearest(p); }
129
130     public final class Vert extends HasPoint {
131         public String toString() { return p.toString(); }
132         public Point p;
133         E e;                // some edge *leaving* this point
134
135         /** the nearest vertex in the "score_against" mesh */
136         Vert   nearest_in_other_mesh;
137         /** the number of vertices in the other mesh for which this is the nearest_in_other_mesh */
138         int    quadric_count;
139         /** the total error quadric (contributions from all vertices in other mesh for which this is nearest) */
140         Matrix quadric = Matrix.ZERO;
141
142         Vert bound_to = this;
143         Matrix binding = new Matrix();
144         float oldscore = 0;
145         boolean quadricStale = false;
146
147         public Matrix errorQuadric() { return quadric; }
148         public Point getPoint() { return p; }
149         public float score() { return oldscore; }
150
151         private Matrix fundamentalQuadric = null;
152         public Matrix fundamentalQuadric() {
153             if (fundamentalQuadric == null) recomputeFundamentalQuadric();
154             return fundamentalQuadric;
155         }
156
157         private Vert(Point p) {
158             this.p = p;
159             if (pointset.get(p) != null) throw new Error();
160             pointset.add(this);
161         }
162
163         private void glNormal(GL gl) {
164             Vec norm = norm();
165             gl.glNormal3f(norm.x, norm.y, norm.z);
166         }
167
168         public void recomputeFundamentalQuadric() {
169             //if (!quadricStale && fundamentalQuadric != null) return;
170             quadricStale = false;
171             unApplyQuadricToNeighbor();
172             Matrix m = Matrix.ZERO;
173             E e = this.e;
174             int count = 0;
175             do {
176                 T t = e.t;
177                 m = m.plus(t.norm().fundamentalQuadric(t.centroid()));
178                 count++;
179                 e = e.pair.next;
180             } while(e != this.e);
181             fundamentalQuadric = m.times(1/(float)count);
182             applyQuadricToNeighbor();
183         }
184
185         public void unApplyQuadricToNeighbor() {
186             if (nearest_in_other_mesh == null) return;
187             if (fundamentalQuadric == null) return;
188             nearest_in_other_mesh.unComputeError();
189             nearest_in_other_mesh.quadric = nearest_in_other_mesh.quadric.minus(fundamentalQuadric);
190             nearest_in_other_mesh.quadric_count--;
191             if (nearest_in_other_mesh.quadric_count==0)
192                 nearest_in_other_mesh.quadric = Matrix.ZERO;
193             nearest_in_other_mesh.computeError();
194             nearest_in_other_mesh = null;
195         }
196
197         public void applyQuadricToNeighbor() {
198             if (score_against == null) return;
199
200             Vert new_nearest = score_against.nearest(p);
201             if (nearest_in_other_mesh != null && new_nearest == nearest_in_other_mesh) return;
202
203             if (nearest_in_other_mesh != null) unApplyQuadricToNeighbor();
204             if (nearest_in_other_mesh != null) throw new Error();
205
206             nearest_in_other_mesh = new_nearest;
207                 
208             // don't attract to vertices that face the other way
209             if (nearest_in_other_mesh.e == null || nearest_in_other_mesh.norm().dot(norm()) < 0) {
210                 nearest_in_other_mesh = null;
211             } else {
212                 nearest_in_other_mesh.unComputeError();
213                 nearest_in_other_mesh.quadric = nearest_in_other_mesh.quadric.plus(fundamentalQuadric());
214                 nearest_in_other_mesh.quadric_count++;
215                 nearest_in_other_mesh.computeError();
216             }
217             reComputeError();
218         }
219
220         public void reComputeErrorAround() {
221             reComputeError();
222             if (nearest_in_other_mesh != null) nearest_in_other_mesh.reComputeError();
223             E e = this.e;
224             do {
225                 e.p2.reComputeError();
226                 e = e.pair.next;
227             } while (e != this.e);
228         }
229         public void reComputeError() {
230             unComputeError();
231             computeError();
232         }
233         public void unComputeError() {
234             score -= oldscore;
235             oldscore = 0;
236         }
237         public void computeError() {
238             if (quadric_count == 0) {
239                 if (!tilemesh) {
240                 }
241                 else if (nearest_in_other_mesh == null) {
242                     if (score_against != null) {
243                         Vert ne = score_against.nearest(p);
244                         oldscore = ne.fundamentalQuadric().preAndPostMultiply(p) * 100 * 10;
245                     } else {
246                         oldscore = 0;
247                     }
248                 } else {
249                     oldscore = nearest_in_other_mesh.fundamentalQuadric().preAndPostMultiply(p) * 100 * 10;
250                 }
251             } else {
252                 oldscore = (quadric.preAndPostMultiply(p) * 100) / quadric_count;
253             }
254
255             oldscore = oldscore;
256
257             int numaspects = 0;
258             float aspects = 0;
259             E e = this.e;
260             do {
261                 //double ang = Math.abs(e.crossAngle());
262                 double ang = Math.abs(e.crossAngle());
263                 if (ang > Math.PI) throw new Error();
264                 /*
265                 if (e.t != null) {
266                     numaspects++;
267                     aspects += e.t.aspect()*e.t.aspect();
268                 }
269                 */
270
271                 float minangle = (float)(Math.PI * 0.8);
272                 if (ang > minangle)
273                     oldscore += (ang - minangle);
274
275                 e = e.pair.next;
276             } while (e != this.e);
277             if (numaspects > 0) oldscore += (aspects / numaspects);
278
279             //System.out.println(oldscore);
280             //oldscore = oldscore*oldscore;
281             score += oldscore;
282         }
283
284         private void removeTrianglesFromRTree() {
285             E e = this.e;
286             do {
287                 if (e.t != null) e.t.removeFromRTree();
288                 e = e.pair.next;
289             } while(e != this.e);
290         }
291         private void addTrianglesToRTree() {
292             E e = this.e;
293             do {
294                 if (e.t != null) e.t.addToRTree();
295                 e = e.pair.next;
296             } while(e != this.e);
297         }
298
299         /** does NOT update bound pairs! */
300         public boolean transform(Matrix m) {
301             unApplyQuadricToNeighbor();
302             Point oldp = this.p;
303             try {
304                 if (pointset.get(this.p)==null) throw new Error();
305                 pointset.remove(this);
306                 removeTrianglesFromRTree();
307                 float newx = m.a*p.x + m.b*p.y + m.c*p.z + m.d;
308                 float newy = m.e*p.x + m.f*p.y + m.g*p.z + m.h;
309                 float newz = m.i*p.x + m.j*p.y + m.k*p.z + m.l;
310                 this.p = new Point(newx, newy, newz);
311                 addTrianglesToRTree();
312                 pointset.add(this);
313             } catch (Exception e) {
314                 throw new RuntimeException(e);
315             }
316             applyQuadricToNeighbor();
317
318             // FIXME: intersection test needed?
319             good = true;
320
321             // should recompute fundamental quadrics of all vertices sharing a face, but we defer...
322             E e = this.e;
323             do {
324                 /*
325                 if (Math.abs(e.crossAngle()) > (Math.PI * 0.9) ||
326                     Math.abs(e.next.crossAngle()) > (Math.PI * 0.9)) {
327                     good = false;
328                 }
329                 if (e.t.aspect() < 0.1) {
330                     good = false;
331                 }
332                 */
333                 e.p2.quadricStale = true;
334                 e = e.pair.next;
335             } while(e != this.e);
336
337
338             if (!ignorecollision && good) {
339
340                 tris.range(new Segment(oldp, this.p),
341                             new Visitor<T>() {
342                                 public void visit(T t) {
343                                     if (!good) return;
344                                     E e = Vert.this.e;
345                                     do {
346                                         if (!t.has(e.p1) && !t.has(e.p2) && e.intersects(t)) { good = false; }
347                                         if (e.t != null) {
348                                             if (!e.t.has(t.e1().p1) && !e.t.has(t.e1().p2) && t.e1().intersects(e.t)) { good = false; }
349                                             if (!e.t.has(t.e2().p1) && !e.t.has(t.e2().p2) && t.e2().intersects(e.t)) { good = false; }
350                                             if (!e.t.has(t.e3().p1) && !e.t.has(t.e3().p2) && t.e3().intersects(e.t)) { good = false; }
351                                         }
352                                         e = e.pair.next;
353                                     } while(e != Vert.this.e);
354                                 }
355                             });
356
357                 /*
358                 for(T t : Mesh.this) {
359                     if (!good) break;
360                     e = this.e;
361                     do {
362                         if (!t.has(e.p1) && !t.has(e.p2) && e.intersects(t)) { good = false; break; }
363                         if (e.t != null) {
364                             if (!e.t.has(t.e1().p1) && !e.t.has(t.e1().p2) && t.e1().intersects(e.t)) { good = false; break; }
365                             if (!e.t.has(t.e2().p1) && !e.t.has(t.e2().p2) && t.e2().intersects(e.t)) { good = false; break; }
366                             if (!e.t.has(t.e3().p1) && !e.t.has(t.e3().p2) && t.e3().intersects(e.t)) { good = false; break; }
367                         }
368                         e = e.pair.next;
369                     } while(e != this.e);
370                 }
371                 */
372             }
373
374
375             reComputeErrorAround();
376             return good;
377         }
378         private boolean good;
379
380         public boolean move(Vec v) {
381             Matrix m = new Matrix(v);
382             Vert p = this;
383             boolean good = true;
384             do {
385                 good &= p.transform(m);
386                 p = p.bound_to;
387             } while (p != this);
388             return good;
389         }
390
391         public E getFreeIncident() {
392             E ret = getFreeIncident(e, e);
393             if (ret != null) return ret;
394             ret = getFreeIncident(e.pair.next, e.pair.next);
395             if (ret == null) {
396                 E ex = e;
397                 do {
398                     System.out.println(ex + " " + ex.t);
399                     ex = ex.pair.next;
400                 } while (ex != e);
401                 throw new Error("unable to find free incident to " + this);
402             }
403             return ret;
404         }
405
406         public E getFreeIncident(E start, E before) {
407             E e = start;
408             do {
409                 if (e.pair.p2 == this && e.pair.t == null && e.pair.next.t == null) return e.pair;
410                 e = e.pair.next;
411             } while(e != before);
412             return null;
413         }
414
415         public E getE(Point p2) {
416             Vert v = pointset.get(p2);
417             if (v==null) return null;
418             return getE(v);
419         }
420         public E getE(Vert p2) {
421             E e = this.e;
422             do {
423                 if (e==null) return null;
424                 if (e.p1 == this && e.p2 == p2) return e;
425                 e = e.pair.next;
426             } while (e!=this.e);
427             return null;
428         }
429
430         public Vec norm() {
431             Vec norm = new Vec(0, 0, 0);
432             E e = this.e;
433             do {
434                 if (e.t != null) norm = norm.plus(e.t.norm().times((float)e.prev.angle()));
435                 e = e.pair.next;
436             } while(e != this.e);
437             return norm.norm();
438         }
439
440         public boolean isBoundTo(Vert p) {
441             Vert px = p;
442             do {
443                 if (px==this) return true;
444                 px = px.bound_to;
445             } while(px != p);
446             return false;
447         }
448         public void unbind() { bound_to = this; binding = new Matrix(); }
449         public void bind(Vert p) { bind(p, new Matrix()); }
450         public void bind(Vert p, Matrix binding) {
451             if (isBoundTo(p)) return;
452             Vert temp_bound_to = p.bound_to;
453             Matrix temp_binding = p.binding;
454             p.bound_to = this.bound_to;
455             p.binding = binding.times(this.binding); // FIXME: may have order wrong here
456             this.bound_to = temp_bound_to;
457             this.binding = temp_binding.times(temp_binding); // FIXME: may have order wrong here
458         }
459     }
460
461     public class BindingGroup {
462         private HashSet<E> set = new HashSet<E>();
463         public BindingGroup bind_others;
464         public BindingGroup other() { return bind_others; }
465         public BindingGroup(BindingGroup bind_others) { this.bind_others = bind_others; }
466         public BindingGroup() { this.bind_others = new BindingGroup(this); }
467         public BindingGroup(E e) { this(); set.add(e); }
468         public void add(E e) {
469             if (set.contains(e)) return;
470             set.add(e);
471             BindingGroup e_bind_peers = e.bind_peers;
472             BindingGroup e_bind_to    = e.bind_to;
473             e.bind_peers = this;
474             e.bind_to    = bind_others;
475             for (E epeer  : e_bind_peers.set) add(epeer);
476             for (E eother : e_bind_to.set)    bind_others.add(eother);
477
478             for(E eother : bind_others.set) {
479                 if (e.next.bind_to.set.contains(eother.prev)) {
480                     e.next.next.bindEdge(eother.prev.prev);
481                 }
482                 if (e.prev.bind_to.set.contains(eother.next)) {
483                     e.prev.prev.bindEdge(eother.next.next);
484                 }
485             }
486
487         }
488         public void dobind(E e) {
489             for(E ebound : set) {
490                 e.p1.bind(ebound.p2);
491                 e.p2.bind(ebound.p1);
492             }
493         }
494         public void shatter(BindingGroup bg1, BindingGroup bg2) {
495             for(E e : set) {
496                 e.shatter(e.midpoint(), bg1, bg2);
497             }
498         }
499     }
500
501     /** [UNIQUE] an edge */
502     public final class E implements Comparable<E> {
503
504         public final Vert p1, p2;
505         T t;     // triangle to our "left"
506         E prev;  // previous half-edge
507         E next;  // next half-edge
508         E pair;  // partner half-edge
509         public BindingGroup bind_peers  = new BindingGroup(this);
510         public BindingGroup bind_to     = bind_peers.other();
511         boolean shattered = false;
512
513         public float comparator() {
514             Vert nearest = score_against.nearest(midpoint());
515             //if (t==null) return length();
516             /*
517             double ang = Math.abs(crossAngle());
518             float minangle = (float)(Math.PI * 0.9);
519             if (ang > minangle)
520                 return 300;
521             */
522             /*
523             if ((length() * length()) / t.area() > 10)
524                 return (float)(length()*Math.sqrt(t.area()));
525             return length()*t.area();
526             */
527             return (float)Math.max(length(), midpoint().distance(nearest.p));
528             //return length();
529         }
530         public int compareTo(E e) {
531             return e.comparator() > comparator() ? 1 : -1;
532         }
533         public void bindEdge(E e) { bind_to.add(e); }
534         public void dobind() { bind_to.dobind(this); }
535
536         public Point shatter() { return shatter(midpoint(), null, null); }
537         public Point shatter(Point mid, BindingGroup bg1, BindingGroup bg2) {
538             if (shattered || destroyed) return mid;
539             shattered = true;
540
541             Vert r = next.p2;
542             E next = this.next;
543             E prev = this.prev;
544
545             int old_colorclass = t==null ? 0 : t.colorclass;
546             if (bg1==null) bg1 = new BindingGroup();
547             if (bg2==null) bg2 = new BindingGroup();
548             BindingGroup old_bind_to = bind_to;
549             bind_peers.shatter(bg1, bg2);
550             old_bind_to.shatter(bg2.other(), bg1.other());
551             pair.shatter();
552             destroy();
553
554             newT(r.p, p1.p, mid, null, old_colorclass);
555             newT(r.p, mid, p2.p, null, old_colorclass);
556             bg1.add(p1.getE(mid));
557             bg2.add(p2.getE(mid).pair);
558             return mid;
559         }
560
561         public boolean destroyed = false;
562         public void destroy() {
563             if (destroyed) return;
564             destroyed = true;
565             pair.destroyed = true;
566
567             if (t != null) t.destroy();
568             t = null;
569
570             if (pair.t != null) pair.t.destroy();
571             pair.t = null;
572
573             if (next.t != null) next.t.destroy();
574             if (prev.t != null) prev.t.destroy();
575             next.t = null;
576             prev.t = null;
577
578             if (pair.next.t != null) pair.next.t.destroy();
579             if (pair.prev.t != null) pair.next.t.destroy();
580             pair.next.t = null;
581             pair.prev.t = null;
582
583             this.bind_to = null;
584             pair.bind_to = null;
585             this.bind_peers = null;
586             pair.bind_peers = null;
587             pair.prev.next = next;
588             next.prev = pair.prev;
589             prev.next = pair.next;
590             pair.next = prev;
591             if (p1.e == this) p1.e = prev.next;
592             if (pair.p1.e == pair) pair.p1.e = pair.prev.next;
593             avgedge -= this.length();
594             avgedge -= pair.length();
595             numedges--;
596             numedges--;
597         }
598
599         private void sync() {
600             this.prev.next = this;
601             this.next.prev = this;
602             this.pair.pair = this;
603             bind_peers.add(this);
604             if (this.next.p1 != p2) throw new Error();
605             if (this.prev.p2 != p1) throw new Error();
606             if (this.p1.e == null) this.p1.e = this;
607             if (!added) {
608                 added = true;
609                 numedges++;
610                 avgedge += length();
611             }
612         }
613         private boolean added = false;
614
615         public T makeT(int colorclass) { return t==null ? (t = new T(this, colorclass)) : t; }
616
617         public double crossAngle() {
618             Vec v1 = t.norm().times(-1);
619             Vec v2 = pair.t.norm().times(-1);
620             return Math.acos(v1.norm().dot(v2.norm()));
621         }
622
623         /** angle between this half-edge and the next */
624         public double angle() {
625             Vec v1 = next.p2.p.minus(p2.p);
626             Vec v2 = this.p1.p.minus(p2.p);
627             return Math.acos(v1.norm().dot(v2.norm()));
628         }
629
630         public void makeAdjacent(E e) {
631             if (this.next == e) return;
632             if (p2 != e.p1) throw new Error("cannot make adjacent -- no shared vertex");
633             if (t != null || e.t != null) throw new Error("cannot make adjacent -- edges not both free");
634
635             E freeIncident = p2.getFreeIncident(e, this);
636
637             e.prev.next = freeIncident.next;
638             freeIncident.next.prev = e.prev;
639
640             freeIncident.next = this.next;
641             this.next.prev = freeIncident;
642             
643             this.next = e;
644             e.prev = this;
645
646             sync();
647             freeIncident.sync();
648         }
649
650         /** creates an isolated edge out in the middle of space */
651         public E(Point p1, Point p2) {
652             if (pointset.get(p1) != null) throw new Error();
653             if (pointset.get(p2) != null) throw new Error();
654             this.p1 = new Vert(p1);
655             this.p2 = new Vert(p2);
656             this.prev = this.next = this.pair = new E(this, this, this);
657             this.p1.e = this;
658             this.p2.e = this.pair;
659             sync();
660         }
661
662         /** adds a new half-edge from prev.p2 to p2 */
663         public E(E prev, Point p) {
664             Vert p2;
665             p2 = pointset.get(p);
666             if (p2 == null) p2 = new Vert(p);
667             this.p1 = prev.p2;
668             this.p2 = p2;
669             this.prev = prev;
670             if (p2.getE(p1) != null) throw new Error();
671             if (p2.e==null) {
672                 this.next = this.pair = new E(this, this, prev.next);
673             } else {
674                 E q = p2.getFreeIncident();
675                 this.next = q.next;
676                 this.next.prev = this;
677                 E z = prev.next;
678                 this.prev.next = this;
679                 this.pair = new E(q, this, z);
680             }
681             if (p2.e==null) p2.e = this.pair;
682             sync();
683         }
684
685         /** adds a new half-edge to the mesh with a given predecessor, successor, and pair */
686         public E(E prev, E pair, E next) {
687             this.p1 = prev.p2;
688             this.p2 = next.p1;
689             this.prev = prev;
690             this.next = next;
691             this.pair = pair;
692             sync();
693         }
694         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); }
695         public boolean has(Vert v) { return v==p1 || v==p2; }
696         public float length() { return p1.p.minus(p2.p).mag(); }
697         public String toString() { return p1+"->"+p2; }
698
699         public boolean intersects(T t) {
700             double A0=t.v1().p.x, A1=t.v1().p.y, A2=t.v1().p.z;
701             double B0=t.v2().p.x, B1=t.v2().p.y, B2=t.v2().p.z;
702             double C0=t.v3().p.x, C1=t.v3().p.y, C2=t.v3().p.z;
703             double j0=p1.p.x, j1=p1.p.y, j2=p1.p.z;
704             double k0=p2.p.x, k1=p2.p.y, k2=p2.p.z;
705             double J0, J1, J2;
706             double K0, K1, K2;
707             double i0, i1, i2;
708             double a0, a1, a2;
709             double b0, b1, b2;
710             double c0, c1, c2;
711             double in_det;
712             double R00, R01, R02, R03,
713                 R10, R11, R12, R13,
714                 R20, R21, R22, R23,
715                 R30, R31, R32, R33;
716
717
718             /* a = B - A */
719             a0 = B0 - A0; 
720             a1 = B1 - A1; 
721             a2 = B2 - A2;
722             /* b = C - B */
723             b0 = C0 - A0;
724             b1 = C1 - A1;
725             b2 = C2 - A2;
726             /* c = a &times; b */
727             c0 = a1 * b2 - a2 * b1;
728             c1 = a2 * b0 - a0 * b2;
729             c2 = a0 * b1 - a1 * b0;
730  
731             /* M^(-1) = (1/det(M)) * adj(M) */
732             in_det = 1 / (c0 * c0 + c1 * c1 + c2 * c2);
733             R00 = (b1 * c2 - b2 * c1) * in_det;
734             R01 = (b2 * c0 - b0 * c2) * in_det;
735             R02 = (b0 * c1 - b1 * c0) * in_det;
736             R10 = (c1 * a2 - c2 * a1) * in_det;
737             R11 = (c2 * a0 - c0 * a2) * in_det;
738             R12 = (c0 * a1 - c1 * a0) * in_det;
739             R20 = (c0) * in_det;
740             R21 = (c1) * in_det;
741             R22 = (c2) * in_det;
742   
743             /* O = M^(-1) * A */
744             R03 = -(R00 * A0 + R01 * A1 + R02 * A2);
745             R13 = -(R10 * A0 + R11 * A1 + R12 * A2);
746             R23 = -(R20 * A0 + R21 * A1 + R22 * A2);
747  
748             /* fill in last row of 4x4 matrix */
749             R30 = R31 = R32 = 0;
750             R33 = 1;
751   
752             J2 = R20 * j0 + R21 * j1 + R22 * j2 + R23;
753             K2 = R20 * k0 + R21 * k1 + R22 * k2 + R23;
754             if (J2 * K2 >= 0) return false;
755
756             J0 = R00 * j0 + R01 * j1 + R02 * j2 + R03;
757             K0 = R00 * k0 + R01 * k1 + R02 * k2 + R03;
758             i0 = J0 + J2 * ((K0 - J0) / (J2 - K2));
759             if (i0 < 0 || i0 > 1) return false;
760   
761             J1 = R10 * j0 + R11 * j1 + R12 * j2 + R13;
762             K1 = R10 * k0 + R11 * k1 + R12 * k2 + R13;
763             i1 = J1 + J2 * ((K1 - J1) / (J2 - K2));
764             if (i1 < 0 || i1 > 1 || i0 + i1 > 1) return false;
765
766             return true;            
767         }
768     }
769
770     public E makeE(Point p1, Point p2) {
771         Vert v1 = pointset.get(p1);
772         Vert v2 = pointset.get(p2);
773         if (v1 != null && v2 != null) {
774             E e = v1.getE(v2);
775             if (e != null) return e;
776             e = v2.getE(v1);
777             if (e != null) return e;
778         }
779         if (v1 != null) return new E(v1.getFreeIncident(), p2);
780         if (v2 != null) return new E(v2.getFreeIncident(), p1).pair;
781         return new E(p1, p2);
782     }
783     public T newT(Point p1, Point p2, Point p3, Vec norm, int colorclass) {
784         if (norm != null) {
785             Vec norm2 = p3.minus(p1).cross(p2.minus(p1));
786             float dot = norm.dot(norm2);
787             //if (Math.abs(dot) < EPointSILON) throw new Error("dot products within evertsilon of each other: "+norm+" "+norm2);
788             if (dot < 0) { Point p = p1; p1=p2; p2 = p; }
789         }
790         E e12 = makeE(p1, p2);
791         E e23 = makeE(p2, p3);
792         E e31 = makeE(p3, p1);
793         while(e12.next != e23 || e23.next != e31 || e31.next != e12) {
794             e12.makeAdjacent(e23);
795             e23.makeAdjacent(e31);
796             e31.makeAdjacent(e12);
797         }
798         T ret = e12.makeT(colorclass);
799         if (e12.t == null) throw new Error();
800         if (e23.t == null) throw new Error();
801         if (e31.t == null) throw new Error();
802         return ret;
803     }
804
805
806     public class FaceIterator implements Iterator<T> {
807         private HashSet<T> visited = new HashSet<T>();
808         private LinkedList<T> next = new LinkedList<T>();
809         public FaceIterator() { }
810         public FaceIterator(Vert v) { next.addFirst(v.e.t); }
811         public boolean hasNext() { return next.peek()!=null; }
812         public void remove() { throw new Error(); }
813         public T next() {
814             T ret = next.removeFirst();
815             if (ret == null) return null;
816             visited.add(ret);
817             T t1 = ret.e1().pair.t;
818             T t2 = ret.e2().pair.t;
819             T t3 = ret.e3().pair.t;
820             if (t1 != null && !visited.contains(t1)) next.addFirst(t1);
821             if (t2 != null && !visited.contains(t2)) next.addFirst(t2);
822             if (t3 != null && !visited.contains(t3)) next.addFirst(t3);
823             return ret;
824         }
825     }
826
827     /** [UNIQUE] a triangle (face) */
828     public final class T extends Triangle {
829         public final E e1;
830         public final int color;
831         public final int colorclass;
832
833         public void removeFromRTree() { tris.remove(this); }
834         public void addToRTree() { tris.insert(this); }
835
836         public void destroy() {
837             tris.remove(this);
838             ts.remove(this);
839         }
840
841         T(E e1, int colorclass) {
842             this.e1 = e1;
843             E e2 = e1.next;
844             E e3 = e2.next;
845             if (e1==e2 || e1==e3) throw new Error();
846             if (e3.next!=e1) throw new Error();
847             if (e1.t!=null || e2.t!=null || e3.t!=null) throw new Error("non-manifold surface or disagreeing normals");
848             e1.t = this;
849             e1.next.t = this;
850             e1.next.next.t = this;
851
852             // FIXME: check for sealed/watertight surface once construction is complete (and infer normal(s)?)
853
854             int color = Math.abs(random.nextInt());
855             while(true) {
856                 color = color % 4;
857                 if (e1().pair.t != null && color == e1().pair.t.color) { color++; continue; }
858                 if (e2().pair.t != null && color == e2().pair.t.color) { color++; continue; }
859                 if (e3().pair.t != null && color == e3().pair.t.color) { color++; continue; }
860                 break;
861             }
862             this.color = color;
863             this.colorclass = colorclass;
864             ts.add(this);
865             tris.add(this);
866         }
867         public E e1() { return e1; }
868         public E e2() { return e1.next; }
869         public E e3() { return e1.prev; }
870         public Vert v1() { return e1.p1; }
871         public Vert v2() { return e1.p2; }
872         public Vert v3() { return e1.next.p2; }
873         public Point p1() { return e1.p1.p; }
874         public Point p2() { return e1.p2.p; }
875         public Point p3() { return e1.next.p2.p; }
876         public boolean hasE(E e) { return e1==e || e1.next==e || e1.prev==e; }
877         public boolean has(Vert v) { return v1()==v || v2()==v || v3()==v; }
878
879         public void glVertices(GL gl) {
880
881             if (e1().bind_to.set.size() == 0) return;
882             if (e2().bind_to.set.size() == 0) return;
883             if (e3().bind_to.set.size() == 0) return;
884
885             norm().glNormal(gl);
886             p1().glVertex(gl);
887             p2().glVertex(gl);
888             p3().glVertex(gl);
889         }
890     }
891     public boolean tilemesh = false;
892     public boolean ignorecollision = false;
893 }