add items to TODO list
[anneal.git] / src / edu / berkeley / qfat / Mesh.java
index 926a5b7..2e68c17 100644 (file)
@@ -1,6 +1,7 @@
 package edu.berkeley.qfat;
 import java.awt.*;
 import java.util.*;
+import java.io.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.media.opengl.*;
@@ -25,11 +26,12 @@ public class Mesh implements Iterable<Mesh.T> {
     public boolean option_errorNormals = false;
     public boolean option_selectable   = true;
 
-    public void render(GL gl, Matrix m) {
+    public void render(GL gl, Matrix m) { render(gl, m, false); }
+    public void render(GL gl, Matrix m, boolean noColor) {
         if (option_wireframe) {
             gl.glDisable(GL.GL_LIGHTING);
             gl.glBegin(GL.GL_LINES);
-            gl.glColor3f(1, 1, 1);
+            if (!noColor) gl.glColor3f(1, 1, 1);
             for (T t : this) {
                 // fixme used to be .goodp
                 m.times(t.e1().v1.p).glVertex(gl);
@@ -44,10 +46,11 @@ public class Mesh implements Iterable<Mesh.T> {
             return;
         }
         for(T t : this) {
-            gl.glColor4f((float)(0.25+(0.05*t.color)),
-                         (float)(0.25+(0.05*t.color)),
-                         (float)(0.75+(0.05*t.color)),
-                         (float)0.3); 
+            if (!noColor)
+                gl.glColor4f((float)(0.25+(0.05*t.color)),
+                             (float)(0.25+(0.05*t.color)),
+                             (float)(0.75+(0.05*t.color)),
+                             (float)0.3); 
             /*
             if (t.red) {
             gl.glColor4f((float)(0.75+(0.05*t.color)),
@@ -63,7 +66,8 @@ public class Mesh implements Iterable<Mesh.T> {
                 for(Mesh.Vertex p : new Mesh.Vertex[] { t.v1(), t.v2(), t.v3() }) {
                     if (p.ok) {
                         gl.glBegin(GL.GL_LINES);
-                        gl.glColor3f(1, 1, 1);
+                        if (!noColor)
+                            gl.glColor3f(1, 1, 1);
                         p.p.glVertex(gl);
                         p.p.plus(p.norm().times((float)p.error()*10)).glVertex(gl);
                         gl.glEnd();
@@ -81,6 +85,7 @@ public class Mesh implements Iterable<Mesh.T> {
     public float error() { return (float)error; }
 
     public int size() { return vertices.size(); }
+    public int numTriangles() { return triangles.size(); }
     public Iterable<Vertex> vertices() { return vertices; }
     public Iterator<T> iterator() { return triangles.iterator(); }
 
@@ -422,7 +427,10 @@ public class Mesh implements Iterable<Mesh.T> {
             Point pt = vv.plus(getPoint());
             Point pp = pt;
             pt = getBindingConstraint().getProjection(pp);
-            if (pt==null) return false;
+            if (pt==null) {
+                System.out.println("constraint violation: " + getBindingConstraint());
+                return false;
+            }
             System.out.println(pt.minus(pp).mag() + " " + getBindingConstraint());
 
             for(Vertex v : (Iterable<Vertex>)getBoundPeers()) {
@@ -586,6 +594,34 @@ public class Mesh implements Iterable<Mesh.T> {
         E pair;  // partner half-edge
         boolean shattered = false;
 
+
+        /** the "edge normal" -- average of the normals of the adjacent faces */
+        public Vec norm() {
+            return
+                (t==null || pair==null || pair.t==null)
+                ? null
+                : t.norm().plus(pair.t.norm()).norm();
+        }
+
+        public void glVertices(GL gl) {
+            Point p1 = v1.p;
+            Point p2 = v2.p;
+            if (t != null) {
+                p1 = p1.plus(t.centroid().minus(p1).times(0.1f));
+                p2 = p2.plus(t.centroid().minus(p2).times(0.1f));
+                p1 = p1.plus(norm().times(length() * 0.01f));
+                p2 = p2.plus(norm().times(length() * 0.01f));
+            }
+            p1.glVertex(gl);
+            p2.glVertex(gl);
+            if (t==null || pair.t==null) return;
+
+            Point atip = p2.minus(Point.ZERO).times(4).plus(p1.minus(Point.ZERO)).div(5).plus(Point.ZERO);
+            atip = (t.norm().plus(pair.t.norm())).norm().times(getSegment().length() / 5).plus(atip);
+            p2.glVertex(gl);
+            atip.glVertex(gl);
+        }
+
         public boolean intersects(T t) { return t.intersects(v1.p, v2.p); }
 
         public Segment getSegment() { return new Segment(v1.getPoint(), v2.getPoint()); }
@@ -632,21 +668,30 @@ public class Mesh implements Iterable<Mesh.T> {
                 if (next==null || prev==null) continue;
                 if (eother.next==null || eother.prev==null) continue;
 
-                if (next.isBoundTo(eother.pair.prev.pair) && !prev.isBoundTo(eother.pair.next.pair))
-                    prev.bindTo(next.getBindingMatrix(eother.pair.prev.pair), eother.pair.next.pair);
-                if (!next.isBoundTo(eother.pair.prev.pair) && prev.isBoundTo(eother.pair.next.pair))
-                    next.bindTo(prev.getBindingMatrix(eother.pair.next.pair), eother.pair.prev.pair);
+                Matrix m = getBindingMatrix(eother);
+                if (next.isBoundTo(eother.pair.prev.pair) &&
+                    !prev.isBoundTo(eother.pair.next.pair) &&
+                    m.equalsModuloEpsilon(next.getBindingMatrix(eother.pair.prev.pair), EPSILON))
+                    prev.bindEdge(next.getBindingMatrix(eother.pair.prev.pair), eother.pair.next.pair);
+                if (!next.isBoundTo(eother.pair.prev.pair) &&
+                    prev.isBoundTo(eother.pair.next.pair)  &&
+                    m.equalsModuloEpsilon(prev.getBindingMatrix(eother.pair.next.pair), EPSILON))
+                    next.bindEdge(prev.getBindingMatrix(eother.pair.next.pair), eother.pair.prev.pair);
+
+                //if (next.isBoundTo(eother.prev) && !prev.isBoundTo(eother.next))
+                //prev.bindTo(next.getBindingMatrix(eother.prev), eother.next);
+                //if (!next.isBoundTo(eother.prev) && prev.isBoundTo(eother.next))
+                //next.bindTo(prev.getBindingMatrix(eother.next), eother.prev);
+
+                if (next.isBoundTo(eother.next) &&
+                    !prev.isBoundTo(eother.prev) &&
+                    m.equalsModuloEpsilon(next.getBindingMatrix(eother.next), EPSILON))
+                    prev.bindEdge(next.getBindingMatrix(eother.next), eother.prev);
+                if (!next.isBoundTo(eother.next) &&
+                    prev.isBoundTo(eother.prev) &&
+                    m.equalsModuloEpsilon(prev.getBindingMatrix(eother.prev), EPSILON))
+                    next.bindEdge(prev.getBindingMatrix(eother.prev), eother.next);
 
-                /*
-                if (next.isBoundTo(eother.prev) && !prev.isBoundTo(eother.next))
-                    prev.bindTo(next.getBindingMatrix(eother.prev), eother.next);
-                if (!next.isBoundTo(eother.prev) && prev.isBoundTo(eother.next))
-                    next.bindTo(prev.getBindingMatrix(eother.next), eother.prev);
-                */
-                if (next.isBoundTo(eother.next) && !prev.isBoundTo(eother.prev))
-                    prev.bindTo(next.getBindingMatrix(eother.next), eother.prev);
-                if (!next.isBoundTo(eother.next) && prev.isBoundTo(eother.prev))
-                    next.bindTo(prev.getBindingMatrix(eother.prev), eother.next);
             }
 
         }
@@ -665,35 +710,24 @@ public class Mesh implements Iterable<Mesh.T> {
         public int compareTo(E e) {
             return e.comparator() > comparator() ? 1 : -1;
         }
-        public void bindEdge(E e, Matrix m) {
-            _bindEdge(e, m);
-            pair._bindEdge(e.pair, m);
+        public void bindEdge(Matrix m, E e) {
+            bindEdge(e, m);
         }
-        public void _bindEdge(E e, Matrix m) {
-            e = e.pair;
-            /*
-            //assumes edges are identical length at binding time
-            Vec reflectionPlaneNormal = e.v2.p.minus(e.v1.p).norm();
-            float a = reflectionPlaneNormal.x;
-            float b = reflectionPlaneNormal.y;
-            float c = reflectionPlaneNormal.z;
-            Matrix reflectionMatrix =
-                new Matrix( 1-2*a*a,  -2*a*b,  -2*a*c, 0,
-                            -2*a*b,  1-2*b*b,  -2*b*c, 0,
-                            -2*a*c,   -2*b*c, 1-2*c*c, 0,
-                            0,       0,       0,       1);
-            m = m.times(Matrix.translate(e.midpoint().minus(Point.ORIGIN))
-                        .times(reflectionMatrix)
-                        .times(Matrix.translate(Point.ORIGIN.minus(e.midpoint()))));
-            System.out.println(reflectionPlaneNormal);
-            System.out.println("  " + v1.p + " " + m.times(e.v1.p));
-            System.out.println("  " + v2.p + " " + m.times(e.v2.p));
-            */
+        public void bindEdge(E e, Matrix m) {
             /*
-            if (m.times(e.v1.p).minus(v1.p).mag() > EPSILON) throw new Error();
-            if (m.times(e.v2.p).minus(v2.p).mag() > EPSILON) throw new Error();
+            for(E e_ : (Iterable<E>)e.getBoundPeers()) {
+                if (e.v1.getPoint().distance((e.getBindingMatrix(e_).times(e_.v1.getPoint()))) > 0.01f)
+                    throw new RuntimeException("blah! " + e.v1.getPoint() + " " + e.getBindingMatrix(e_).times(e_.v1.getPoint()));
+                if (e.v2.getPoint().distance((e.getBindingMatrix(e_).times(e_.v2.getPoint()))) > 0.01f)
+                    throw new RuntimeException("blah! " + e.v2.getPoint() + " " + e.getBindingMatrix(e_).times(e_.v2.getPoint()));
+                if (v1.getPoint().distance(m.times(e.getBindingMatrix(e_).times(e_.v1.getPoint()))) > 0.01f)
+                    throw new RuntimeException("blah! " + v1.getPoint() + " " + m.times(e_.v1.getPoint()));
+                if (v2.getPoint().distance(m.times(e.getBindingMatrix(e_).times(e_.v2.getPoint()))) > 0.01f)
+                    throw new RuntimeException("blah! " + v2.getPoint() + " " + m.times(e_.v2.getPoint()));
+            }
             */
-            this.bindTo(m, e);
+            this.bindTo(m, e,      EPSILON);
+            this.pair.bindTo(m, e.pair, EPSILON);
         }
         
         public void dobind() {
@@ -701,10 +735,6 @@ public class Mesh implements Iterable<Mesh.T> {
                 if (e==this) continue;
                 v1.bindTo(getBindingMatrix(e), e.v1);
                 v2.bindTo(getBindingMatrix(e), e.v2);
-                /*
-                e.v1.setConstraint(getAffineConstraint());
-                e.v2.setConstraint(getAffineConstraint());
-                */
             }
         }
 
@@ -869,6 +899,7 @@ public class Mesh implements Iterable<Mesh.T> {
         public E(Point v1, Point v2) {
             if (vertices.get(v1) != null) throw new Error();
             if (vertices.get(v2) != null) throw new Error();
+            if (v1.equals(v2)) throw new Error("attempt to create a zero-length edge!");
             this.v1 = new Vertex(v1);
             this.v2 = new Vertex(v2);
             this.prev = this.next = this.pair = new E(this, this, this);
@@ -938,9 +969,13 @@ public class Mesh implements Iterable<Mesh.T> {
     public T newT(HasPoint v1, HasPoint v2, HasPoint v3) {
         return newT(v1.getPoint(), v2.getPoint(), v3.getPoint(), null, 0);
     }
+    public T newT(Point v1, Point v2, Point v3, Vec norm) { return newT(v1, v2, v3, norm, 1); }
     public T newT(Point v1, Point v2, Point v3, Vec norm, int colorclass) {
+        if (v1.equals(v2)
+            || v2.equals(v3)
+            || v3.equals(v1))
+            throw new Error("attempt to make a triangle with a length-zero side");
         if (coalesce) {
-
             for(Vertex v : vertices) { if (v1.distance(v.p) < EPSILON) { v1 = v.p; break; } }
             for(Vertex v : vertices) { if (v2.distance(v.p) < EPSILON) { v2 = v.p; break; } }
             for(Vertex v : vertices) { if (v3.distance(v.p) < EPSILON) { v3 = v.p; break; } }
@@ -949,6 +984,11 @@ public class Mesh implements Iterable<Mesh.T> {
             v2 = new Point(round(v2.x), round(v2.y), round(v2.z));
             v3 = new Point(round(v3.x), round(v3.y), round(v3.z));
             */
+            /*
+            // triangle's vertices got merged
+            if (v1.equals(v2) || v2.equals(v3) || v3.equals(v1))
+                return null;
+            */
         }
         if (norm != null) {
             Vec norm2 = v3.minus(v1).cross(v2.minus(v1));
@@ -959,6 +999,7 @@ public class Mesh implements Iterable<Mesh.T> {
         E e12 = makeE(v1, v2);
         E e23 = makeE(v2, v3);
         E e31 = makeE(v3, v1);
+        if (e12==e23 || e23==e31 || e12==e31) throw new Error();
         while(e12.next != e23 || e23.next != e31 || e31.next != e12) {
             e12.makeAdjacent(e23);
             e23.makeAdjacent(e31);
@@ -1149,11 +1190,9 @@ public class Mesh implements Iterable<Mesh.T> {
         public boolean destroyed() { return destroyed; }
 
         public boolean shouldBeDrawn() {
-
-            if (e1().bindingGroupSize() <= 1) return false;
-            if (e2().bindingGroupSize() <= 1) return false;
-            if (e3().bindingGroupSize() <= 1) return false;
-
+            if (e1().bindingGroupUnconstrained()) return false;
+            if (e2().bindingGroupUnconstrained()) return false;
+            if (e3().bindingGroupUnconstrained()) return false;
             return true;
         }
 
@@ -1171,4 +1210,24 @@ public class Mesh implements Iterable<Mesh.T> {
             super.glVertices(gl, m);
         }
     }
+
+    // Dump /////////////////////////////////////////////////////////////////////////////
+
+    public void dump(OutputStream os) throws IOException {
+        PrintWriter pw = new PrintWriter(new OutputStreamWriter(os));
+        pw.println("solid dump");
+        for(Mesh.T t : this) {
+            Vec normal = t.norm();
+            pw.println("facet normal " + normal.x + " " + normal.y + " " + normal.z);
+            pw.println("  outer loop");
+            for(Mesh.Vertex v : new Mesh.Vertex[] { t.v1(), t.v2(), t.v3() }) {
+                pw.println("    vertex " + v.p.x + " " + v.p.y + " " + v.p.z);
+            }
+            pw.println("  endloop");
+            pw.println("endfacet");
+        }
+        pw.println("endsolid dump");
+        pw.flush();
+    }
+
 }