Example #1
0
 @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;
 }
Example #2
0
  @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;
  }
Example #3
0
 @Override
 public void preProcessAllHalfEdges() {
   metrics.compute();
   final int roughNrNodes = mesh.getTriangles().size() / 2;
   quadricMap = new HashMap<Vertex, Quadric3DError>(roughNrNodes);
   for (Triangle af : mesh.getTriangles()) {
     if (!af.isWritable()) continue;
     for (int i = 0; i < 3; i++) {
       final Vertex n = af.getV(i);
       if (!quadricMap.containsKey(n)) quadricMap.put(n, new Quadric3DError());
     }
   }
   // Compute quadrics
   final double[] vect1 = new double[3];
   final double[] vect2 = new double[3];
   final double[] normal = new double[3];
   for (Triangle f : mesh.getTriangles()) {
     if (!f.isWritable()) continue;
     f.getV1().sub(f.getV0(), vect1);
     f.getV2().sub(f.getV0(), vect2);
     Matrix3D.prodVect3D(vect1, vect2, normal);
     double norm = Matrix3D.norm(normal);
     // This is in fact 2*area, but that does not matter
     double area = norm;
     if (tolerance > 0.0) area /= tolerance;
     if (norm > 1.e-20) {
       norm = 1.0 / norm;
       for (int k = 0; k < 3; k++) normal[k] *= norm;
     }
     double d = -Matrix3D.prodSca(normal, f.getV0());
     for (int i = 0; i < 3; i++) {
       final Quadric3DError q = quadricMap.get(f.getV(i));
       q.addError(normal, d, area);
     }
     // Penalty for boundary triangles
     HalfEdge e = (HalfEdge) f.getAbstractHalfEdge();
     for (int i = 0; i < 3; i++) {
       e = e.next();
       if (e.hasAttributes(AbstractHalfEdge.BOUNDARY | AbstractHalfEdge.NONMANIFOLD)) {
         for (Iterator<AbstractHalfEdge> it = e.fanIterator(); it.hasNext(); ) {
           HalfEdge b = (HalfEdge) it.next();
           //  Add a virtual plane
           //  In his dissertation, Garland suggests to
           //  add a weight proportional to squared edge
           //  length.
           //  Here norm(vect2) == norm(vect1)
           b.destination().sub(b.origin(), vect1);
           Matrix3D.prodVect3D(vect1, normal, vect2);
           norm = Matrix3D.norm(vect2);
           if (norm > 1.e-20) {
             double invNorm = 1.0 / norm;
             for (int k = 0; k < 3; k++) vect2[k] *= invNorm;
           }
           d = -Matrix3D.prodSca(vect2, b.origin());
           final Quadric3DError q1 = quadricMap.get(b.origin());
           final Quadric3DError q2 = quadricMap.get(b.destination());
           q1.addWeightedError(vect2, d, norm);
           q2.addWeightedError(vect2, d, norm);
         }
       }
     }
   }
 }