@Override protected final double cost(final HalfEdge e) { final Vertex o = e.origin(); final Vertex d = e.destination(); HalfEdge current = uniqueOrientation(e); if (current.hasAttributes(AbstractHalfEdge.IMMUTABLE)) return Double.MAX_VALUE; if (freeEdgesOnly && !current.hasAttributes(AbstractHalfEdge.BOUNDARY)) return Double.MAX_VALUE; final Vertex v1 = current.origin(); final Vertex v2 = current.destination(); assert v1 != v2 : current; // If an endpoint is not writable, its neighborhood is // not fully determined and contraction must not be // performed. if (!v1.isWritable() || !v2.isWritable()) return Double.MAX_VALUE; if (!v1.isMutable() && !v2.isMutable()) return Double.MAX_VALUE; final Quadric3DError q1 = quadricMap.get(o); assert q1 != null : o; final Quadric3DError q2 = quadricMap.get(d); assert q2 != null : d; qCostOpt.computeQuadric3DError(q1, q2); qCostOpt.optimalPlacement(o, d, q1, q2, placement, vCostOpt); final double ret = q1.value(vCostOpt) + q2.value(vCostOpt); // TODO: check why this assertion sometimes fail // assert ret >= -1.e-2 : q1+"\n"+q2+"\n"+ret; return ret; }
@Override public boolean canProcessEdge(HalfEdge current) { current = uniqueOrientation(current); final Vertex v1 = current.origin(); final Vertex v2 = current.destination(); assert v1 != v2 : current; final Quadric3DError q1 = quadricMap.get(v1); final Quadric3DError q2 = quadricMap.get(v2); assert q1 != null : v1; assert q2 != null : v2; q3.computeQuadric3DError(q1, q2); q3.optimalPlacement(v1, v2, q1, q2, placement, v3); if (!mesh.canCollapseEdge(current, v3)) return false; if (!metrics.isEmpty()) { EuclidianMetric3D m3 = metrics.get(v3, current.getTri()); if (!checkSize(v1, m3)) return false; if (!checkSize(v2, m3)) return false; } return true; }