コード例 #1
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);
}
コード例 #2
0
ファイル: delaunay.cpp プロジェクト: omco/geode
// Retriangulate a cavity formed when a constraint edge is inserted, following Shewchuck and Brown.
// The cavity is defined by a counterclockwise list of vertices v[0] to v[m-1] as in Shewchuck and Brown, Figure 5.
static void cavity_delaunay(MutableTriangleTopology& parent_mesh, RawField<const EV,VertexId> X,
                            RawArray<const VertexId> cavity, Random& random) {
  // Since the algorithm generates meshes which may be inconsistent with the outer mesh, and the cavity
  // array may have duplicate vertices, we use a temporary mesh and then copy the triangles over when done.
  // In the temporary, vertices are indexed consecutively from 0 to m-1.
  const int m = cavity.size();
  assert(m >= 3);
  const auto mesh = new_<MutableTriangleTopology>();
  Field<Perturbed2,VertexId> Xc(m,uninit);
  for (const int i : range(m))
    Xc.flat[i] = Perturbed2(cavity[i].id,X[cavity[i]]);
  mesh->add_vertices(m);
  const auto xs = Xc.flat[0],
             xe = Xc.flat[m-1];

  // Set up data structures for prev, next, pi in the paper
  const Field<VertexId,VertexId> prev(m,uninit),
                                 next(m,uninit);
  for (int i=0;i<m-1;i++) {
    next.flat[i] = VertexId(i+1);
    prev.flat[i+1] = VertexId(i);
  }
  const Array<VertexId> pi_(m-2,uninit);
  for (int i=1;i<=m-2;i++)
    pi_[i-1] = VertexId(i);
  #define PI(i) pi_[(i)-1]

  // Randomly shuffle [1,m-2], subject to vertices closer to xs-xe than both their neighbors occurring later
  for (int i=m-2;i>=2;i--) {
    int j;
    for (;;) {
      j = random.uniform<int>(0,i)+1;
      const auto pj = PI(j);
      if (!(   segment_directions_oriented(xe,xs,Xc[pj],Xc[prev[pj]])
            && segment_directions_oriented(xe,xs,Xc[pj],Xc[next[pj]])))
        break;
    }
    swap(PI(i),PI(j));
    // Remove PI(i) from the list
    const auto pi = PI(i);
    next[prev[pi]] = next[pi];
    prev[next[pi]] = prev[pi];
  }

  // Add the first triangle
  mesh->add_face(vec(VertexId(0),PI(1),VertexId(m-1)));

  // Add remaining triangles, flipping to ensure Delaunay
  const Field<bool,VertexId> marked(m);
  Array<HalfedgeId> fan;
  bool used_chew = false;
  for (int i=2;i<m-1;i++) {
    const auto pi = PI(i);
    insert_cavity_vertex(mesh,Xc,marked,pi,next[pi],prev[pi]);
    if (marked[pi]) {
      used_chew = true;
      marked[pi] = false;
      // Retriangulate the fans of triangles that have all three vertices marked
      auto e = mesh->reverse(mesh->halfedge(pi));
      auto v = mesh->src(e);
      bool mv = marked[v];
      marked[v] = false;
      fan.clear();
      do {
        const auto h = mesh->prev(e);
        e = mesh->reverse(mesh->next(e));
        v = mesh->src(e);
        const bool mv2 = marked[v];
        marked[v] = false;
        if (mv) {
          if (mv2)
            fan.append(h);
          if (!mv2 || mesh->is_boundary(e)) {
            chew_fan(mesh,Xc,pi,fan,random);
            fan.clear();
          }
        }
        mv = mv2;
      } while (!mesh->is_boundary(e));
    }
  }
  #undef PI

  // If we ran Chew's algorithm, validate the output.  I haven't tested this
  // case enough to be confident of its correctness.
  if (used_chew)
    assert_delaunay("Failure in extreme special case.  If this triggers, please email [email protected]: ",
                    mesh,Xc,Tuple<>(),false,false);

  // Copy triangles from temporary mesh to real mesh
  for (const auto f : mesh->faces()) {
    const auto v = mesh->vertices(f);
    parent_mesh.add_face(vec(cavity[v.x.id],cavity[v.y.id],cavity[v.z.id]));
  }
}
コード例 #3
0
ファイル: delaunay.cpp プロジェクト: omco/geode
// Delaunay retriangulate a triangle fan
static void chew_fan(MutableTriangleTopology& parent_mesh, RawField<const Perturbed2,VertexId> X,
                     const VertexId u, RawArray<HalfedgeId> fan, Random& random) {
  chew_fan_count_ += 1;
#ifndef NDEBUG
  for (const auto e : fan)
    assert(parent_mesh.opposite(e)==u);
  for (int i=0;i<fan.size()-1;i++)
    GEODE_ASSERT(parent_mesh.src(fan[i])==parent_mesh.dst(fan[i+1]));
#endif
  const int n = fan.size();
  if (n < 2)
    return;
  chew_fan_count_ += 1024*n;

  // Collect vertices
  const Field<VertexId,VertexId> vertices(n+2,uninit);
  vertices.flat[0] = u;
  vertices.flat[1] = parent_mesh.src(fan[n-1]);
  for (int i=0;i<n;i++)
    vertices.flat[i+2] = parent_mesh.dst(fan[n-1-i]);

  // Delete original vertices
  for (const auto e : fan)
    parent_mesh.erase(parent_mesh.face(e));

  // Make the vertices into a doubly linked list
  const Field<VertexId,VertexId> prev(n+2,uninit),
                                 next(n+2,uninit);
  prev.flat[0].id = n+1;
  next.flat[n+1].id = 0;
  for (int i=0;i<n+1;i++) {
    prev.flat[i+1].id = i;
    next.flat[i].id = i+1;
  }

  // Randomly shuffle the vertices, then pulling elements off the linked list in reverse order of our final shuffle.
  const Array<VertexId> pi(n+2,uninit);
  for (int i=0;i<n+2;i++)
    pi[i].id = i;
  random.shuffle(pi);
  for (int i=n+1;i>=0;i--) {
    const auto j = pi[i];
    prev[next[j]] = prev[j];
    next[prev[j]] = next[j];
  }

  // Make a new singleton mesh
  const auto mesh = new_<MutableTriangleTopology>();
  mesh->add_vertices(n+2);
  small_sort(pi[0],pi[1],pi[2]);
  mesh->add_face(vec(pi[0],pi[1],pi[2]));

  // Insert remaining vertices
  Array<HalfedgeId> work;
  for (int i=3;i<n+2;i++) {
    const auto j = pi[i];
    const auto f = mesh->add_face(vec(j,next[j],prev[j]));
    work.append(mesh->reverse(mesh->opposite(f,j)));
    while (work.size()) {
      auto e = work.pop();
      if (   !mesh->is_boundary(e)
          && incircle(X[vertices[mesh->src(e)]],
                      X[vertices[mesh->dst(e)]],
                      X[vertices[mesh->opposite(e)]],
                      X[vertices[mesh->opposite(mesh->reverse(e))]])) {
        work.append(mesh->reverse(mesh->next(e)));
        work.append(mesh->reverse(mesh->prev(e)));
        e = mesh->unsafe_flip_edge(e);
      }
    }
  }

  // Copy triangles back to parent
  for (const auto f : mesh->faces()) {
    const auto vs = mesh->vertices(f);
    parent_mesh.add_face(vec(vertices[vs.x],vertices[vs.y],vertices[vs.z]));
  }
}