+ if (error_against==null) return;
+ float nerror =
+ nearest_in_other_mesh != null
+ ? nearest_in_other_mesh.fundamentalQuadric().preAndPostMultiply(p)
+ : nearest().fundamentalQuadric().preAndPostMultiply(p);
+ if (quadric_count != 0)
+ nerror = (nerror + quadric.preAndPostMultiply(p))/(quadric_count+1);
+
+ if (!immutableVertices && quadric_count == 0)
+ nerror *= 2;
+
+ for(E e = this.e; e!=null; e=e.pair.next==this.e?null:e.pair.next) {
+ double ang = Math.abs(e.dihedralAngle());
+ if (ang > Math.PI) throw new Error();
+ float minangle = (float)(Math.PI * 0.8);
+ if (ang > minangle) nerror += (ang - minangle);
+ if (e.t.aspect() < 0.2) {
+ nerror += (0.2-e.t.aspect()) * 10;
+ }
+ }
+
+ setError(nerror);
+ }
+
+ public boolean move(Matrix m, boolean ignoreProblems) {
+ boolean good = true;
+
+ // t1' = M * t1
+ // t2' = t2.getMatrix(t1) * t1'
+ // t2' = t2.getMatrix(t1) * M * t1
+ // t1 = t1.getMatrix(t2) * t2
+ // M * t1 = M * t1.getMatrix(t2) * t2
+ if (bindingGroup!=null && this != bindingGroup.getMaster()) {
+ Matrix v = getBindingMatrix(bindingGroup.getMaster());
+ return ((Vertex)bindingGroup.getMaster()).move(v.inverse().times(m).times(v), ignoreProblems);
+ }
+
+ if (bindingGroup != null) {
+ Matrix m2 = null;
+ for(int i=0; i<20 && !m.equals(m2); i++) {
+ m2 = m.times(bindingGroup.krank);
+ //System.out.println(m.minus(m2));
+ }
+ if (!m.equals(m2)) return true;
+ }
+
+ Point op = this.p;
+ Point pt = m.times(this.p);
+ for(Vertex v : (Iterable<Vertex>)getBoundPeers()) {
+ Point pt2 = v.getBindingMatrix(this).times(pt);
+ /*
+ if (Math.abs( v.p.minus(pt2).mag() / pt.minus(op).mag() ) > 5)
+ throw new Error(v.p+" "+pt2+"\n"+op+" "+pt+"\n"+v.getBindingMatrix(this));
+ if (Math.abs( v.p.minus(pt2).mag() / pt.minus(op).mag() ) < 1/5) throw new Error();
+ */
+ good &= v.transform(pt2,
+ ignoreProblems, v.getBindingMatrix(this));
+ }
+
+ for(Vertex v : (Iterable<Vertex>)getBoundPeers())
+ v.recomputeFundamentalQuadricIfNeighborChanged();
+ return good;