예제 #1
0
파일: delaunay.cpp 프로젝트: omco/geode
// InsertVertex in the paper
static void insert_cavity_vertex_helper(MutableTriangleTopology& mesh, RawField<const Perturbed2,VertexId> X,
                                        RawField<bool,VertexId> marked, const HalfedgeId vw) {
  // If wv is a boundary edge, or we're already Delaunay and properly oriented, we're done
  const auto wv = mesh.reverse(vw);
  if (mesh.is_boundary(wv))
    return;
  const auto u = mesh.opposite(vw),
             v = mesh.src(vw),
             w = mesh.dst(vw),
             x = mesh.opposite(wv);
  const auto Xu = X[u],
             Xv = X[v],
             Xw = X[w],
             Xx = X[x];
  const bool in = incircle(Xu,Xv,Xw,Xx);
  if (!in && triangle_oriented(Xu,Xv,Xw))
    return;

  // Flip edge and recurse
  const auto xu = mesh.flip_edge(wv);
  assert(mesh.vertices(xu)==vec(x,u));
  const auto vx = mesh.prev(xu),
             xw = mesh.next(mesh.reverse(xu)); // Grab this now before the recursive call changes uvx
  insert_cavity_vertex_helper(mesh,X,marked,vx),
  insert_cavity_vertex_helper(mesh,X,marked,xw);
  if (!in)
    marked[u] = marked[v] = marked[w] = marked[x] = true;
}
예제 #2
0
파일: delaunay.cpp 프로젝트: omco/geode
static void insert_cavity_vertex(MutableTriangleTopology& mesh, RawField<const Perturbed2,VertexId> X,
                                 RawField<bool,VertexId> marked,
                                 const VertexId u, const VertexId v, const VertexId w) {
#ifndef NDEBUG
  {
    const auto vw = mesh.halfedge(v);
    assert(mesh.is_boundary(vw) && mesh.dst(vw)==w);
  }
#endif
  mesh.add_face(vec(u,v,w));
  const auto vw = mesh.prev(mesh.reverse(mesh.halfedge(u)));
  assert(mesh.vertices(vw)==vec(v,w));
  insert_cavity_vertex_helper(mesh,X,marked,vw);
}
예제 #3
0
void decimate_inplace(MutableTriangleTopology& mesh, RawField<TV,VertexId> X,
                      const T distance, const T max_angle, const int min_vertices, const T boundary_distance) {
  if (mesh.n_vertices() <= min_vertices)
    return;
  const T area = sqr(distance);
  const T sign_sqr_min_cos = sign_sqr(max_angle > .99*pi ? -1 : cos(max_angle));

  // Finds the best edge to collapse v along.  Returns (q(e),dst(e)).
  const auto best_collapse = [&mesh,X](const VertexId v) {
    Quadric q = compute_quadric(mesh,X,v);

    // Find the best edge, ignoring normal constraints
    T min_q = inf;
    HalfedgeId min_e;
    for (const auto e : mesh.outgoing(v)) {
      const T qx = q(X[mesh.dst(e)]);
      if (min_q > qx) {
        min_q = qx;
        min_e = e;
      }
    }
    return tuple(min_q,mesh.dst(min_e));
  };

  // Initialize quadrics and heap
  Heap heap(mesh.n_vertices_);
  for (const auto v : mesh.vertices()) {
    const auto qe = best_collapse(v);
    if (qe.x <= area)
      heap.inv_heap[v] = heap.heap.append(tuple(v,qe.x,qe.y));
  }
  heap.make();

  // Update the quadric information for a vertex
  const auto update = [&heap,best_collapse,area](const VertexId v) {
    const auto qe = best_collapse(v);
    if (qe.x <= area)
      heap.set(v,qe.x,qe.y);
    else
      heap.erase(v);
  };

  // Repeatedly collapse the best vertex
  while (heap.size()) {
    const auto v = heap.pop();

    // Do these vertices still exist?
    if (mesh.valid(v.x) && mesh.valid(v.y)) {
      const auto e = mesh.halfedge(v.x,v.y);

      // Is the collapse invalid?
      if (e.valid() && mesh.is_collapse_safe(e)) {
        const auto vs = mesh.src(e),
                   vd = mesh.dst(e);
        const auto xs = X[vs],
                   xd = X[vd];

        // Are we moving a boundary vertex too far from its two boundary lines?
        {
          const auto b = mesh.halfedge(vs);
          if (mesh.is_boundary(b)) {
            const auto x0 = X[mesh.dst(b)],
                       x1 = X[mesh.src(mesh.prev(b))];
            if (   line_point_distance(simplex(xs,x0),xd) > boundary_distance
                || line_point_distance(simplex(xs,x1),xd) > boundary_distance)
              goto bad;
          }
        }

        // Do the normals change too much?
        if (sign_sqr_min_cos > -1)
          for (const auto ee : mesh.outgoing(vs))
            if (e!=ee && !mesh.is_boundary(ee)) {
              const auto v2 = mesh.opposite(ee);
              if (v2 != vd) {
                const auto x1 = X[mesh.dst(ee)],
                           x2 = X[v2];
                const auto n0 = cross(x2-x1,xs-x1),
                           n1 = cross(x2-x1,xd-x1);
                if (sign_sqr(dot(n0,n1)) < sign_sqr_min_cos*sqr_magnitude(n0)*sqr_magnitude(n1))
                  goto bad;
              }
            }

        // Collapse vs onto vd, then update the heap
        mesh.unsafe_collapse(e);
        if (mesh.n_vertices() <= min_vertices)
          break;
        update(vd);
        for (const auto e : mesh.outgoing(vd))
          update(mesh.dst(e));
      }
    }
    bad:;
  }
}