From 00235327934dbc5ffaf5b09cbda538ee0d3686e8 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 7 Jul 2008 22:01:05 -0700 Subject: [PATCH] checkpoint darcs-hash:20080708050105-5007d-a8a630f43e861883d78bf3707b464048ccf27260.gz --- src/edu/berkeley/qfat/Main.java | 70 ++++++----- src/edu/berkeley/qfat/Mesh.java | 142 +++++++++++++---------- src/edu/berkeley/qfat/MeshViewer.java | 119 ++++++++++++++++--- src/edu/berkeley/qfat/bind/BindingGroup.java | 7 ++ src/edu/berkeley/qfat/bind/HasBindingGroup.java | 13 +++ src/edu/berkeley/qfat/geom/Plane.java | 35 ++++-- src/edu/berkeley/qfat/geom/Point.java | 4 +- 7 files changed, 280 insertions(+), 110 deletions(-) diff --git a/src/edu/berkeley/qfat/Main.java b/src/edu/berkeley/qfat/Main.java index b7df3d4..178ca5a 100644 --- a/src/edu/berkeley/qfat/Main.java +++ b/src/edu/berkeley/qfat/Main.java @@ -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); + 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) { - 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) { - 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) { - 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) { - 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) { - 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(); } }); + 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[] { + + //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)), @@ -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( 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)), @@ -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( 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)), @@ -620,12 +627,23 @@ public class Main extends InteractiveMeshViewer { 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 { 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); @@ -45,10 +46,11 @@ public class Mesh implements Iterable { 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)), @@ -64,7 +66,8 @@ public class Mesh implements Iterable { 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(); @@ -423,7 +426,10 @@ public class Mesh implements Iterable { 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)getBoundPeers()) { @@ -587,6 +593,34 @@ public class Mesh implements Iterable { 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()); } @@ -633,21 +667,30 @@ public class Mesh implements Iterable { 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 { 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.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() { @@ -702,10 +732,6 @@ public class Mesh implements Iterable { 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 { 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; } diff --git a/src/edu/berkeley/qfat/MeshViewer.java b/src/edu/berkeley/qfat/MeshViewer.java index d7481e5..a0e236d 100644 --- a/src/edu/berkeley/qfat/MeshViewer.java +++ b/src/edu/berkeley/qfat/MeshViewer.java @@ -24,7 +24,10 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener private float anglex = 0; private float angley = 0; + boolean drawEdge = false; + private Mesh.Vertex closest = null; + private Mesh.E closestEdge = null; 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 boolean updateClosest = false; private boolean mouseInside = false; private HashSet meshes = new HashSet(); @@ -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); - gl.glColor3f(1,1,1); - gl.glBegin(gl.GL_POINTS); - closest.getPoint().glVertex(gl); - gl.glEnd(); + + if (drawEdge) { + for(Mesh.E e : (Iterable)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)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); @@ -122,11 +189,15 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener updateVisibilities = false; // update vertex visibilities updateVisibility(gl); - - //Matrix projection = Matrix.getProjectionMatrix(gl); + } + + if (updateClosest) { + updateClosest = false; double dist = Double.MAX_VALUE; + double distE = Double.MAX_VALUE; closest = null; closestOriginallyAt = null; + closestEdge = null; 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; } + 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.glColor3f(0,0,0); 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(); + 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(); - - 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); - - boolean vis = false; for(int j=0; j<9*4; j++) vis |= buf.get(j)!=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(); - if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) + + if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) { updateVisibilities = true; + drawEdge = true; + updateClosest = true; + } } 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(); @@ -230,7 +320,10 @@ public class MeshViewer extends JPanel implements GLEventListener, MouseListener closest.move(delta, false); } } + } else if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) { + // move edge } else { + updateVisibilities = true; anglex -= mousex - e.getX(); angley += mousey - e.getY(); } diff --git a/src/edu/berkeley/qfat/bind/BindingGroup.java b/src/edu/berkeley/qfat/bind/BindingGroup.java index 501fb81..6b06b47 100644 --- a/src/edu/berkeley/qfat/bind/BindingGroup.java +++ b/src/edu/berkeley/qfat/bind/BindingGroup.java @@ -33,11 +33,18 @@ class BindingGroup implements Iterable { void merge(BindingGroup 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; } + // 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; diff --git a/src/edu/berkeley/qfat/bind/HasBindingGroup.java b/src/edu/berkeley/qfat/bind/HasBindingGroup.java index b7c8db3..56b7d9b 100644 --- a/src/edu/berkeley/qfat/bind/HasBindingGroup.java +++ b/src/edu/berkeley/qfat/bind/HasBindingGroup.java @@ -32,6 +32,13 @@ public abstract class HasBindingGroup { 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 = @@ -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() { } + + public boolean bindingGroupUnconstrained() { + if (bindingGroupSize() > 1) return false; + if (getBindingConstraint()!=AffineConstraint.ALL) return false; + return true; + } } diff --git a/src/edu/berkeley/qfat/geom/Plane.java b/src/edu/berkeley/qfat/geom/Plane.java index ed721ed..fe23b83 100644 --- a/src/edu/berkeley/qfat/geom/Plane.java +++ b/src/edu/berkeley/qfat/geom/Plane.java @@ -1,12 +1,14 @@ 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 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(); @@ -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.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) { + // 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.p = p; } 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)); } - 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 - 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 @@ -84,6 +89,14 @@ public class Plane implements AffineConstraint { } 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+"]"; } } diff --git a/src/edu/berkeley/qfat/geom/Point.java b/src/edu/berkeley/qfat/geom/Point.java index d53a2e8..f011243 100644 --- a/src/edu/berkeley/qfat/geom/Point.java +++ b/src/edu/berkeley/qfat/geom/Point.java @@ -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) { - 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); } -- 1.7.10.4