checkpoint
authoradam <adam@megacz.com>
Tue, 8 Jul 2008 05:01:05 +0000 (22:01 -0700)
committeradam <adam@megacz.com>
Tue, 8 Jul 2008 05:01:05 +0000 (22:01 -0700)
darcs-hash:20080708050105-5007d-a8a630f43e861883d78bf3707b464048ccf27260.gz

src/edu/berkeley/qfat/Main.java
src/edu/berkeley/qfat/Mesh.java
src/edu/berkeley/qfat/MeshViewer.java
src/edu/berkeley/qfat/bind/BindingGroup.java
src/edu/berkeley/qfat/bind/HasBindingGroup.java
src/edu/berkeley/qfat/geom/Plane.java
src/edu/berkeley/qfat/geom/Point.java

index b7df3d4..178ca5a 100644 (file)
@@ -170,48 +170,51 @@ public class Main extends InteractiveMeshViewer {
                         Point t1v1 = m.times(t1.v1().p);
                         Point t1v2 = m.times(t1.v2().p);
                         Point t1v3 = m.times(t1.v3().p);
                         Point t1v1 = m.times(t1.v1().p);
                         Point t1v2 = m.times(t1.v2().p);
                         Point t1v3 = m.times(t1.v3().p);
+
                         if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v3().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v2().p) < MATCHING_EPSILON) {
                         if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v3().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v2().p) < MATCHING_EPSILON) {
-                            t2.e3().bindEdge(t1.e1(), m);
-                            t2.e2().bindEdge(t1.e2(), m);
-                            t2.e1().bindEdge(t1.e3(), m);
+                            t2.e3().bindEdge(t1.e1().pair, m);
+                            t2.e2().bindEdge(t1.e2().pair, m);
+                            t2.e1().bindEdge(t1.e3().pair, m);
                         }
                         if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v3().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v2().p) < MATCHING_EPSILON) {
                         }
                         if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v3().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v2().p) < MATCHING_EPSILON) {
-                            t2.e3().bindEdge(t1.e2(), m);
-                            t2.e2().bindEdge(t1.e3(), m);
-                            t2.e1().bindEdge(t1.e1(), m);
+                            t2.e3().bindEdge(t1.e2().pair, m);
+                            t2.e2().bindEdge(t1.e3().pair, m);
+                            t2.e1().bindEdge(t1.e1().pair, m);
                         }
                         if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v3().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v2().p) < MATCHING_EPSILON) {
                         }
                         if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v3().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v2().p) < MATCHING_EPSILON) {
-                            t2.e3().bindEdge(t1.e3(), m);
-                            t2.e2().bindEdge(t1.e1(), m);
-                            t2.e1().bindEdge(t1.e2(), m);
+                            t2.e3().bindEdge(t1.e3().pair, m);
+                            t2.e2().bindEdge(t1.e1().pair, m);
+                            t2.e1().bindEdge(t1.e2().pair, m);
                         }
                         }
+
                         if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v2().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v3().p) < MATCHING_EPSILON) {
                         if (t1v1.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v2().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v3().p) < MATCHING_EPSILON) {
-                            t2.e1().bindEdge(t1.e1().pair, m);
-                            t2.e2().bindEdge(t1.e2().pair, m);
-                            t2.e3().bindEdge(t1.e3().pair, m);
+                            t2.e1().bindEdge(t1.e1(), m);
+                            t2.e2().bindEdge(t1.e2(), m);
+                            t2.e3().bindEdge(t1.e3(), m);
                         }
                         if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v2().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v3().p) < MATCHING_EPSILON) {
                         }
                         if (t1v2.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v3.distance(t2.v2().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v3().p) < MATCHING_EPSILON) {
-                            t2.e2().bindEdge(t1.e1().pair, m);
-                            t2.e3().bindEdge(t1.e2().pair, m);
-                            t2.e1().bindEdge(t1.e3().pair, m);
+                            t2.e2().bindEdge(t1.e1(), m);
+                            t2.e3().bindEdge(t1.e2(), m);
+                            t2.e1().bindEdge(t1.e3(), m);
                         }
                         if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v2().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v3().p) < MATCHING_EPSILON) {
                         }
                         if (t1v3.distance(t2.v1().p) < MATCHING_EPSILON &&
                             t1v1.distance(t2.v2().p) < MATCHING_EPSILON &&
                             t1v2.distance(t2.v3().p) < MATCHING_EPSILON) {
-                            t2.e3().bindEdge(t1.e1().pair, m);
-                            t2.e1().bindEdge(t1.e2().pair, m);
-                            t2.e2().bindEdge(t1.e3().pair, m);
+                            t2.e3().bindEdge(t1.e1(), m);
+                            t2.e1().bindEdge(t1.e2(), m);
+                            t2.e2().bindEdge(t1.e3(), m);
                         }
                         }
+
                     }
                 }
             }
                     }
                 }
             }
@@ -574,6 +577,7 @@ public class Main extends InteractiveMeshViewer {
                 generateTile(transforms, tile);
                 fixupTile();
             } });
                 generateTile(transforms, tile);
                 fixupTile();
             } });
+
             tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
                 setTile(new Mesh(false));
                 float unit = 0.4f;
             tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
                 setTile(new Mesh(false));
                 float unit = 0.4f;
@@ -585,6 +589,10 @@ public class Main extends InteractiveMeshViewer {
                 float height = 2*r*(float)Math.sqrt(2f/3f);
 
                 transforms = new Matrix[] {
                 float height = 2*r*(float)Math.sqrt(2f/3f);
 
                 transforms = new Matrix[] {
+
+                    //Matrix.rotate(new Vec(1,0,0), (float)Math.PI),
+                    //Matrix.reflect(new Vec(1,0,0)),
+
                     Matrix.translate(new Vec(-unit, 0, 0)),
                     Matrix.translate(new Vec( unit, 0, 0)),
                     Matrix.translate(new Vec(-cos,  0,  sin)),
                     Matrix.translate(new Vec(-unit, 0, 0)),
                     Matrix.translate(new Vec( unit, 0, 0)),
                     Matrix.translate(new Vec(-cos,  0,  sin)),
@@ -592,6 +600,13 @@ public class Main extends InteractiveMeshViewer {
                     Matrix.translate(new Vec(-cos,  0, -sin)),
                     Matrix.translate(new Vec( cos,  0, -sin)),
 
                     Matrix.translate(new Vec(-cos,  0, -sin)),
                     Matrix.translate(new Vec( cos,  0, -sin)),
 
+                    Matrix.translate(new Vec( 0,  height, -z)),
+                    Matrix.translate(new Vec(-r,  height,  x)),
+                    Matrix.translate(new Vec( r,  height,  x)),
+                    Matrix.translate(new Vec( 0, -height,  z)),
+                    Matrix.translate(new Vec(-r, -height, -x)),
+                    Matrix.translate(new Vec( r, -height, -x)),
+
                     /*
                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
                     /*
                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
@@ -601,14 +616,6 @@ public class Main extends InteractiveMeshViewer {
                     Matrix.translate(new Vec( r, -height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
                     */
 
                     Matrix.translate(new Vec( r, -height,  x)).times(Matrix.rotate(new Vec(0,1,0), (float)Math.PI)),
                     */
 
-                    Matrix.translate(new Vec( 0,  height, -z)),
-                    Matrix.translate(new Vec(-r,  height,  x)),
-                    Matrix.translate(new Vec( r,  height,  x)),
-                    Matrix.translate(new Vec( 0, -height,  z)),
-                    Matrix.translate(new Vec(-r, -height, -x)),
-                    Matrix.translate(new Vec( r, -height, -x)),
-                    //Matrix.rotate(new Vec(0,0,1), (float)Math.PI),
-
                     /*
                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.scale(-1,1,-1)),
                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.scale(-1,1,-1)),
                     /*
                     Matrix.translate(new Vec( 0,  height, -z)).times(Matrix.scale(-1,1,-1)),
                     Matrix.translate(new Vec(-r,  height,  x)).times(Matrix.scale(-1,1,-1)),
@@ -620,12 +627,23 @@ public class Main extends InteractiveMeshViewer {
                     Matrix.ONE
                 };
                 generateTile(transforms, tile);
                     Matrix.ONE
                 };
                 generateTile(transforms, tile);
+
+
+                transforms = new Matrix[] {
+                    Matrix.reflect(new Vec( 0,  height, -z).norm()),
+                    //Matrix.reflect(new Vec( 0, -height,  z)),
+                    Matrix.ONE
+                };
+
                 //for(int i=0; i<transforms.length; i++) transforms[i] = Matrix.translate(m.times(vecs[i]));
                 //for(int i=0; i<transforms.length; i++) transforms[i] = Matrix.translate(m.times(vecs[i]));
+                /*
                 Matrix m = Matrix.scale(1.9f, 1f ,1);
                 //Matrix m = Matrix.scale(1f, 2.1f, 1f);
                 tile.transform(m);
                 for(int i=0; i<transforms.length; i++)
                     transforms[i] = preMultiplyTranslationalComponentBy(transforms[i], m);
                 Matrix m = Matrix.scale(1.9f, 1f ,1);
                 //Matrix m = Matrix.scale(1f, 2.1f, 1f);
                 tile.transform(m);
                 for(int i=0; i<transforms.length; i++)
                     transforms[i] = preMultiplyTranslationalComponentBy(transforms[i], m);
+                */
+
                 fixupTile();
 
             } });
                 fixupTile();
 
             } });
index cca7321..502fa6d 100644 (file)
@@ -26,11 +26,12 @@ public class Mesh implements Iterable<Mesh.T> {
     public boolean option_errorNormals = false;
     public boolean option_selectable   = true;
 
     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);
         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);
             for (T t : this) {
                 // fixme used to be .goodp
                 m.times(t.e1().v1.p).glVertex(gl);
@@ -45,10 +46,11 @@ public class Mesh implements Iterable<Mesh.T> {
             return;
         }
         for(T t : this) {
             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)),
             /*
             if (t.red) {
             gl.glColor4f((float)(0.75+(0.05*t.color)),
@@ -64,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);
                 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();
                         p.p.glVertex(gl);
                         p.p.plus(p.norm().times((float)p.error()*10)).glVertex(gl);
                         gl.glEnd();
@@ -423,7 +426,10 @@ public class Mesh implements Iterable<Mesh.T> {
             Point pt = vv.plus(getPoint());
             Point pp = pt;
             pt = getBindingConstraint().getProjection(pp);
             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()) {
             System.out.println(pt.minus(pp).mag() + " " + getBindingConstraint());
 
             for(Vertex v : (Iterable<Vertex>)getBoundPeers()) {
@@ -587,6 +593,34 @@ public class Mesh implements Iterable<Mesh.T> {
         E pair;  // partner half-edge
         boolean shattered = false;
 
         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()); }
         public boolean intersects(T t) { return t.intersects(v1.p, v2.p); }
 
         public Segment getSegment() { return new Segment(v1.getPoint(), v2.getPoint()); }
@@ -633,21 +667,30 @@ public class Mesh implements Iterable<Mesh.T> {
                 if (next==null || prev==null) continue;
                 if (eother.next==null || eother.prev==null) continue;
 
                 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);
             }
 
         }
             }
 
         }
@@ -666,35 +709,22 @@ public class Mesh implements Iterable<Mesh.T> {
         public int compareTo(E e) {
             return e.comparator() > comparator() ? 1 : -1;
         }
         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));
-            */
-            /*
-            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();
-            */
-            this.bindTo(m, e);
+        public void bindEdge(E e, Matrix m) {
+            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,      EPSILON);
+            this.pair.bindTo(m, e.pair, EPSILON);
         }
         
         public void dobind() {
         }
         
         public void dobind() {
@@ -702,10 +732,6 @@ public class Mesh implements Iterable<Mesh.T> {
                 if (e==this) continue;
                 v1.bindTo(getBindingMatrix(e), e.v1);
                 v2.bindTo(getBindingMatrix(e), e.v2);
                 if (e==this) continue;
                 v1.bindTo(getBindingMatrix(e), e.v1);
                 v2.bindTo(getBindingMatrix(e), e.v2);
-                /*
-                e.v1.setConstraint(getAffineConstraint());
-                e.v2.setConstraint(getAffineConstraint());
-                */
             }
         }
 
             }
         }
 
@@ -1150,11 +1176,9 @@ public class Mesh implements Iterable<Mesh.T> {
         public boolean destroyed() { return destroyed; }
 
         public boolean shouldBeDrawn() {
         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;
         }
 
             return true;
         }
 
index d7481e5..a0e236d 100644 (file)
@@ -24,7 +24,10 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
     private float anglex = 0;
     private float angley = 0;
 
     private float anglex = 0;
     private float angley = 0;
 
+    boolean drawEdge = false;
+
     private Mesh.Vertex closest = null;
     private Mesh.Vertex closest = null;
+    private Mesh.E      closestEdge = null;
     private Point       closestOriginallyAt = null;
     private int         mousex;
     private int         mousey;
     private Point       closestOriginallyAt = null;
     private int         mousex;
     private int         mousey;
@@ -32,6 +35,7 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
     private Point       clickPoint = null;
     private GLCanvas    glcanvas;
     private boolean     updateVisibilities = false;
     private Point       clickPoint = null;
     private GLCanvas    glcanvas;
     private boolean     updateVisibilities = false;
+    private boolean     updateClosest = false;
     private boolean     mouseInside = false;
 
     private HashSet<Mesh> meshes = new HashSet<Mesh>();
     private boolean     mouseInside = false;
 
     private HashSet<Mesh> meshes = new HashSet<Mesh>();
@@ -110,10 +114,73 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
         if (closest != null) {
             gl.glDisable(GL.GL_LIGHTING);
             gl.glShadeModel(GL.GL_FLAT);
         if (closest != null) {
             gl.glDisable(GL.GL_LIGHTING);
             gl.glShadeModel(GL.GL_FLAT);
-            gl.glColor3f(1,1,1);
-            gl.glBegin(gl.GL_POINTS);
-            closest.getPoint().glVertex(gl);
-            gl.glEnd();
+
+            if (drawEdge) {
+                for(Mesh.E e : (Iterable<Mesh.E>)closestEdge.getBoundPeers()) {
+                    gl.glColor3f(0,1,0);
+                    gl.glBegin(gl.GL_LINES);
+                    e.glVertices(gl);
+                    gl.glEnd();
+                    gl.glColor3f(1,0,0);
+                    gl.glBegin(gl.GL_LINES);
+                    e.pair.glVertices(gl);
+                    gl.glEnd();
+                }
+                /*
+                if (closestEdge != null) {
+                    gl.glColor3f(1,1,0);
+                    gl.glBegin(gl.GL_TRIANGLES);
+                    Mesh.T t = closestEdge.t;
+                    t.p1().glVertex(gl);
+                    t.p2().glVertex(gl);
+                    t.p3().glVertex(gl);
+                    gl.glColor3f(0,1,1);
+                    main.transforms[main.whichNeighbor-1].times(closestEdge.t.p1()).glVertex(gl);
+                    main.transforms[main.whichNeighbor-1].times(closestEdge.t.p2()).glVertex(gl);
+                    main.transforms[main.whichNeighbor-1].times(closestEdge.t.p3()).glVertex(gl);
+                    System.out.println("t="
+                                       +t.p1()+"\n  "
+                                       +t.p2()+"\n  "
+                                       +t.p3()+"\n  "
+                                       );
+                    System.out.println("x="
+                                       +main.transforms[main.whichNeighbor-1].times(t.p1())+"\n  "
+                                       +main.transforms[main.whichNeighbor-1].times(t.p2())+"\n  "
+                                       +main.transforms[main.whichNeighbor-1].times(t.p3())+"\n  "
+                                       );
+                    gl.glEnd();
+                }
+                */
+            }
+
+            if (closest.visible) {
+                gl.glDisable(GL.GL_DEPTH_TEST);
+                gl.glColor3f(1,1,0);
+                gl.glBegin(gl.GL_POINTS);
+                closest.getPoint().glVertex(gl);
+                gl.glColor3f(0.5f,0.5f,0);
+                for(Mesh.Vertex v : (Iterable<Mesh.Vertex>)closest.getBoundPeers())
+                    if (v!=closest)
+                        v.getPoint().glVertex(gl);
+                gl.glEnd();
+
+                if (closest.getBindingConstraint() instanceof Plane) {
+                    Plane p = (Plane)closest.getBindingConstraint();
+                    Vec v = p.norm();
+                    gl.glEnable(gl.GL_BLEND);
+                    gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA);
+                    gl.glColor4f(1,1,0,0.3f);
+                    gl.glBegin(gl.GL_LINES);
+                    closest.getPoint().glVertex(gl);
+                    v.plus(closest.getPoint()).glVertex(gl);
+                    closest.getPoint().glVertex(gl);
+                    v.times(-1).plus(closest.getPoint()).glVertex(gl);
+                    gl.glEnd();
+                    gl.glDisable(gl.GL_BLEND);
+                }
+
+                gl.glEnable(GL.GL_DEPTH_TEST);
+            }
         }
 
         projection = Matrix.getProjectionMatrix(gl);
         }
 
         projection = Matrix.getProjectionMatrix(gl);
@@ -122,11 +189,15 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
             updateVisibilities = false;
             // update vertex visibilities
             updateVisibility(gl);
             updateVisibilities = false;
             // update vertex visibilities
             updateVisibility(gl);
-            
-            //Matrix projection = Matrix.getProjectionMatrix(gl);
+        }
+
+        if (updateClosest) {
+            updateClosest = false;
             double dist = Double.MAX_VALUE;
             double dist = Double.MAX_VALUE;
+            double distE = Double.MAX_VALUE;
             closest = null;
             closestOriginallyAt = null;
             closest = null;
             closestOriginallyAt = null;
+            closestEdge = null;
             for(Mesh mesh : meshes)
                 if (mesh.option_selectable)
                     for(Mesh.Vertex v : mesh.vertices()) {
             for(Mesh mesh : meshes)
                 if (mesh.option_selectable)
                     for(Mesh.Vertex v : mesh.vertices()) {
@@ -140,6 +211,17 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
                             dist = (x-mousex)*(x-mousex)+(y-mousey)*(y-mousey);
                             closest = v;
                         }
                             dist = (x-mousex)*(x-mousex)+(y-mousey)*(y-mousey);
                             closest = v;
                         }
+                        for(Mesh.E e = v.e; e!=null; e=e.pair.next==v.e?null:e.pair.next) {
+                            if (!e.v2.visible) continue;
+                            Segment s =
+                                new Segment(projection.times(e.v1.getPoint()),
+                                            projection.times(e.v2.getPoint()));
+                            double dist2 = s.distance(getMouse());
+                            if (dist2 < distE) {
+                                distE = dist2;
+                                closestEdge = e;
+                            }
+                        }
                     }
         }
     }
                     }
         }
     }
@@ -153,24 +235,26 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
         gl.glFlush();
         gl.glDisable(GL.GL_LIGHTING);
         gl.glShadeModel(GL.GL_FLAT);
         gl.glFlush();
         gl.glDisable(GL.GL_LIGHTING);
         gl.glShadeModel(GL.GL_FLAT);
-        gl.glColor3f(0,0,0);
         gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
         gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
-        for(Mesh mesh : meshes) mesh.render(gl, Matrix.ONE);
+        gl.glColor3f(0,0,0);
+        for(Mesh mesh : meshes) mesh.render(gl, Matrix.ONE, true);
         for(Mesh mesh : meshes)
             if (mesh.option_selectable)
                 for(Mesh.Vertex v : mesh.vertices()) {
                     Point p = v.getPoint();
         for(Mesh mesh : meshes)
             if (mesh.option_selectable)
                 for(Mesh.Vertex v : mesh.vertices()) {
                     Point p = v.getPoint();
+                    Point projected = projection.times(p);
+                    boolean vis = false;
+
                     gl.glColor3f(1,1,1);
                     gl.glBegin(gl.GL_POINTS);
                     p.glVertex(gl);
                     gl.glEnd();
                     gl.glFlush();
                     gl.glColor3f(1,1,1);
                     gl.glBegin(gl.GL_POINTS);
                     p.glVertex(gl);
                     gl.glEnd();
                     gl.glFlush();
-                    
-                    Point projected = projection.times(p);
+
+                    vis = false;
                     gl.glReadPixels((int)projected.x-1, (int)projected.y-1, 3, 3, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, buf);
                     gl.glReadPixels((int)projected.x-1, (int)projected.y-1, 3, 3, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, buf);
-                    
-                    boolean vis = false;
                     for(int j=0; j<9*4; j++) vis |= buf.get(j)!=0;
                     for(int j=0; j<9*4; j++) vis |= buf.get(j)!=0;
+
                     v.visible = vis;
                     if (vis) {
                         gl.glColor3f(0,0,0);
                     v.visible = vis;
                     if (vis) {
                         gl.glColor3f(0,0,0);
@@ -216,12 +300,18 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
     public void mouseMoved(MouseEvent e) {
         mousex = e.getX();
         mousey = e.getY();
     public void mouseMoved(MouseEvent e) {
         mousex = e.getX();
         mousey = e.getY();
-        if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0)
+
+        if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) {
             updateVisibilities = true;
             updateVisibilities = true;
+            drawEdge = true;
+            updateClosest = true;
+        }
     }
 
     public void mouseDragged(MouseEvent e) {
         if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) {
     }
 
     public void mouseDragged(MouseEvent e) {
         if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) {
+            updateVisibilities = true;
+            drawEdge = true;
             if (closest != null && projection != null) {
                 synchronized(this) {
                     if (closestOriginallyAt==null) closestOriginallyAt = closest.getPoint();
             if (closest != null && projection != null) {
                 synchronized(this) {
                     if (closestOriginallyAt==null) closestOriginallyAt = closest.getPoint();
@@ -230,7 +320,10 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener
                     closest.move(delta, false);
                 }
             }
                     closest.move(delta, false);
                 }
             }
+        } else if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) {
+            // move edge
         } else {
         } else {
+            updateVisibilities = true;
             anglex -= mousex - e.getX();
             angley += mousey - e.getY();
         }
             anglex -= mousex - e.getX();
             angley += mousey - e.getY();
         }
index 501fb81..6b06b47 100644 (file)
@@ -33,11 +33,18 @@ class BindingGroup<T extends HasBindingGroup> implements Iterable<T> {
     void merge(BindingGroup<T> bg, Matrix m, float epsilon) {
         if (bg==this) {
             if (m.equalsModuloEpsilon(Matrix.ONE, epsilon)) return;
     void merge(BindingGroup<T> bg, Matrix m, float epsilon) {
         if (bg==this) {
             if (m.equalsModuloEpsilon(Matrix.ONE, epsilon)) return;
+            /*
+            if (master instanceof edu.berkeley.qfat.Mesh.Vertex)
+                System.err.println(m.times(m));
+            */
             // FIXME: what if points do not fall on the merged constraint-line?
             constraint = constraint.intersect(m.getAffineConstraint(epsilon), epsilon);
             return;
         }
 
             // FIXME: what if points do not fall on the merged constraint-line?
             constraint = constraint.intersect(m.getAffineConstraint(epsilon), epsilon);
             return;
         }
 
+        // bg.master = m * master
+        // hbg       = bg.getMatrix(hbg) * bg.master
+        // hbg       = bg.getMatrix(hbg) * m * master
         for(HasBindingGroup hbg : bg) {
             matrices.put((T)hbg, bg.getMatrix((T)hbg).times(m));
             hbg.bindingGroup = this;
         for(HasBindingGroup hbg : bg) {
             matrices.put((T)hbg, bg.getMatrix((T)hbg).times(m));
             hbg.bindingGroup = this;
index b7c8db3..56b7d9b 100644 (file)
@@ -32,6 +32,13 @@ public abstract class HasBindingGroup {
         if (bindingGroup == null) bindingGroup = new BindingGroup(this);
         if (other.bindingGroup == null) other.bindingGroup = new BindingGroup(other);
 
         if (bindingGroup == null) bindingGroup = new BindingGroup(this);
         if (other.bindingGroup == null) other.bindingGroup = new BindingGroup(other);
 
+        //                            this  =                         bg.getMatrix(this)   * bg.master
+        //                            other =                         obg.getMatrix(other) * obg.master
+        //                            this  =                         bindingMatrix        * other
+        //                            this  =                         bindingMatrix        * obg.getMatrix(other) * obg.master
+        // bg.getMatrix(this)  * bg.master  =                         bindingMatrix        * obg.getMatrix(other) * obg.master
+        //                       bg.master  = bg.getMatrix(this)^-1 * bindingMatrix        * obg.getMatrix(other) * obg.master
+        // bg.master = XXX * obg.master
         Matrix bm = bindingGroup.getMatrix(this);
         Matrix obm = other.bindingGroup.getMatrix(other);
         bindingMatrix =
         Matrix bm = bindingGroup.getMatrix(this);
         Matrix obm = other.bindingGroup.getMatrix(other);
         bindingMatrix =
@@ -81,4 +88,10 @@ public abstract class HasBindingGroup {
     /** invoked after the binding group of this HBG has changed due to bindTo() or unbind() */
     public void bindingGroupChanged() {
     }
     /** invoked after the binding group of this HBG has changed due to bindTo() or unbind() */
     public void bindingGroupChanged() {
     }
+
+    public boolean bindingGroupUnconstrained() {
+        if (bindingGroupSize() > 1) return false;
+        if (getBindingConstraint()!=AffineConstraint.ALL) return false;
+        return true;
+    }
 }
 }
index ed721ed..fe23b83 100644 (file)
@@ -1,12 +1,14 @@
 package edu.berkeley.qfat.geom;
 import javax.media.opengl.*;
 
 package edu.berkeley.qfat.geom;
 import javax.media.opengl.*;
 
+// FEATURE: represent a plane by the matrix that projects points onto that plane?
 public class Plane implements AffineConstraint {
 
     // ax+by+cz=d
     public final float a, b, c, d;
 public class Plane implements AffineConstraint {
 
     // ax+by+cz=d
     public final float a, b, c, d;
+    public final Point p;
 
 
-    public Vec norm() { return new Vec(a, b, c); }
+    public Vec norm() { return new Vec(a, b, c).norm(); }
 
     public Plane(Point p, Vec norm) {
         norm = norm.norm();
 
     public Plane(Point p, Vec norm) {
         norm = norm.norm();
@@ -14,14 +16,21 @@ public class Plane implements AffineConstraint {
         this.b = norm.y;
         this.c = norm.z;
         this.d = p.x*norm.x+p.y*norm.y+p.z*norm.z;
         this.b = norm.y;
         this.c = norm.z;
         this.d = p.x*norm.x+p.y*norm.y+p.z*norm.z;
+        this.p = p;
     }
 
     }
 
-    /** provided at least one of a,b,c is nonzero, return the Plane representing ax+by+cz=d */
     public Plane(float a, float b, float c, float d) {
     public Plane(float a, float b, float c, float d) {
+        // FIXME, what if c==0?
+        this(a, b, c, d, new Point(0, 0, d/c));
+    }
+
+    /** provided at least one of a,b,c is nonzero, return the Plane representing ax+by+cz=d */
+    public Plane(float a, float b, float c, float d, Point p) {
         this.a = a;
         this.b = b;
         this.c = c;
         this.d = d;
         this.a = a;
         this.b = b;
         this.c = c;
         this.d = d;
+        this.p = p;
     }
 
     public Point intersect(Plane p1, Plane p2) {
     }
 
     public Point intersect(Plane p1, Plane p2) {
@@ -35,19 +44,15 @@ public class Plane implements AffineConstraint {
         return Point.ZERO.plus(v1.plus(v2).plus(v3).times(1/z));
     }
 
         return Point.ZERO.plus(v1.plus(v2).plus(v3).times(1/z));
     }
 
-    public Point getProjection(Point p) {
-        throw new RuntimeException("not implemented yet");
-    }
-
     public AffineConstraint intersect(AffineConstraint c, float epsilon) {
         if (c instanceof Plane) {
             Plane p = (Plane)c;
 
             // same plane
     public AffineConstraint intersect(AffineConstraint c, float epsilon) {
         if (c instanceof Plane) {
             Plane p = (Plane)c;
 
             // same plane
-            if (Math.abs(p.a-this.a) <= epsilon &&
-                Math.abs(p.b-this.b) <= epsilon &&
-                Math.abs(p.c-this.c) <= epsilon &&
-                Math.abs(p.d-this.d) <= epsilon)
+            if (Math.abs(p.a*this.d-this.a*p.d) <= epsilon &&
+                Math.abs(p.b*this.d-this.b*p.d) <= epsilon &&
+                Math.abs(p.c*this.d-this.c*p.d) <= epsilon &&
+                Math.abs(p.d*this.d-this.d*p.d) <= epsilon)
                 return this;
 
             // parallel planes
                 return this;
 
             // parallel planes
@@ -84,6 +89,14 @@ public class Plane implements AffineConstraint {
     }
 
     public AffineConstraint multiply(Matrix m) {
     }
 
     public AffineConstraint multiply(Matrix m) {
-        throw new RuntimeException("not yet implemented");
+        return new Plane( m.times(p), m.times(norm()).norm() );
+    }
+
+    public Point getProjection(Point p) {
+        Point ret = norm().times(p.minus(this.p).dot(norm())).times(-1).plus(p);
+        return ret;
+    }
+    public String toString() {
+        return "[plane "+a+"x+"+b+"y+"+c+"z="+d+"]";
     }
 }
     }
 }
index d53a2e8..f011243 100644 (file)
@@ -36,7 +36,9 @@ public final class Point implements HasBoundingBox, AffineConstraint, HasPoint {
 
     public Point getProjection(Point p) { return this; }
     public AffineConstraint intersect(AffineConstraint c, float epsilon) {
 
     public Point getProjection(Point p) { return this; }
     public AffineConstraint intersect(AffineConstraint c, float epsilon) {
-        if (c.getProjection(this).distance(this) <= epsilon) return this;
+        Point p2 = c.getProjection(this);
+        if (p2==null) return AffineConstraint.NONE;
+        if (p2.distance(this) <= epsilon) return this;
         return AffineConstraint.NONE;
     }
     public AffineConstraint multiply(Matrix m) { return m.times(this); }
         return AffineConstraint.NONE;
     }
     public AffineConstraint multiply(Matrix m) { return m.times(this); }