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);
}
+
}
}
}
generateTile(transforms, tile);
fixupTile();
} });
+
tileMenu.add(new MyMenuItem("Slim Dense Packing (Cubic)") { public void hit() {
setTile(new Mesh(false));
float unit = 0.4f;
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(-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( 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.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]));
+ /*
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();
} });
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);
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)),
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();
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()) {
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()); }
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);
}
}
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() {
if (e==this) continue;
v1.bindTo(getBindingMatrix(e), e.v1);
v2.bindTo(getBindingMatrix(e), e.v2);
- /*
- e.v1.setConstraint(getAffineConstraint());
- e.v2.setConstraint(getAffineConstraint());
- */
}
}
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;
}
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;
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>();
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);
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()) {
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;
+ }
+ }
}
}
}
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);
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();
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();
}
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;
}
+ // 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;
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 =
/** 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;
+ }
}
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();
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) {
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
}
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+"]";
}
}
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); }