+
+ /** 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 void flip() {
+ // FIXME: coplanarity check needed
+ if (destroyed) return;
+ for (E e : (Iterable<E>)getBoundPeers()) {
+ if (!e.pair.isBoundTo(pair)) throw new RuntimeException("cannot flip!");
+ }
+ Vertex v1 = t.getOtherVertex(this);
+ Vertex v2 = pair.t.getOtherVertex(pair);
+ destroy();
+ pair.destroy();
+ T t1 = newT(v1, v2, this.v2);
+ T t2 = newT(v2, v1, this.v1);
+ t1.e1().sanity();
+ t1.e2().sanity();
+ t1.e3().sanity();
+ t2.e1().sanity();
+ t2.e2().sanity();
+ t2.e3().sanity();
+
+ for (E e : (Iterable<E>)getBoundPeers()) {
+ if (e==this) continue;
+ if (e.destroyed) continue;
+ Vertex v1e = e.t.getOtherVertex(e);
+ Vertex v2e = e.pair.t.getOtherVertex(e.pair);
+ e.destroy();
+ e.pair.destroy();
+ if (v1e.getE(v2e)!=null) throw new RuntimeException();
+ newT(v1e, v2e, e.v2).red = true;
+ newT(v2e, v1e, e.v1).red = true;
+ v2e.getE(v1e).bindTo(e.getBindingMatrix(this), v1.getE(v2));
+ v1e.getE(v2e).bindTo(e.pair.getBindingMatrix(this.pair), v2.getE(v1));
+ }
+
+ }
+
+ public void bindingGroupChanged() {
+ HashSet<E> nbg = new HashSet<E>();
+ for(E eother : (Iterable<E>)getBoundPeers()) nbg.add(eother);
+ for(E eother : nbg) {
+ if (next==null || prev==null) continue;
+ if (eother.next==null || eother.prev==null) continue;
+
+ 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);
+
+ }
+
+ }
+
+ public float stretchRatio() {
+ Vertex nearest = error_against.nearest(midpoint());
+ float nearest_distance = midpoint().distance(nearest.p);
+ float other_distance =
+ (v1.p.distance(error_against.nearest(v1.p).p)+
+ v2.p.distance(error_against.nearest(v2.p).p))/2;
+ return nearest_distance/other_distance;
+ }