Esempio n. 1
0
void
split_faces(union tree *left_tree, union tree *right_tree, const struct bn_tol *tol)
{
    struct soup_s *l, *r;
    unsigned long int i, j;

    RT_CK_TREE(left_tree);
    RT_CK_TREE(right_tree);
    l = (struct soup_s *)left_tree->tr_d.td_r->m_p;
    r = (struct soup_s *)right_tree->tr_d.td_r->m_p;
    SOUP_CKMAG(l);
    SOUP_CKMAG(r);

    /* this is going to be big and hairy. Has to walk both meshes finding
     * all intersections and split intersecting faces so there are edges at
     * the intersections. Initially going to be O(n^2), then change to use
     * space partitioning (binning? octree? kd?). */
    for (i=0;i<l->nfaces;i++) {
	struct face_s *lf = l->faces+i, *rf = NULL;
	int ret;

	for (j=0;j<r->nfaces;j++) {
	    rf = r->faces+j;
	    /* quick bounding box test */
	    if (lf->min[X]>rf->max[X] || lf->max[X]>lf->max[X] ||
	       lf->min[Y]>rf->max[Y] || lf->max[Y]>lf->max[Y] ||
	       lf->min[Z]>rf->max[Z] || lf->max[Z]>lf->max[Z])
		continue;
	    /* two possibly overlapping faces found */
	    ret = split_face(l, i, r, j, tol);
	    if (ret&0x1) i--;
	    if (ret&0x2) j--;
	}
    }
}
Esempio n. 2
0
// This routine assumes the sentinel points have already been added, and processes points in order
GEODE_NEVER_INLINE static Ref<MutableTriangleTopology> deterministic_exact_delaunay(RawField<const Perturbed2,VertexId> X, const bool validate) {

  const int n = X.size()-3;
  const auto mesh = new_<MutableTriangleTopology>();
  IntervalScope scope;

  // Initialize the mesh to a Delaunay triangle containing the sentinels at infinity.
  mesh->add_vertices(n+3);
  mesh->add_face(vec(VertexId(n+0),VertexId(n+1),VertexId(n+2)));
  if (self_check) {
    mesh->assert_consistent();
    assert_delaunay("self check 0: ",mesh,X);
  }

  // The randomized incremental construction algorithm uses the history of the triangles
  // as the acceleration structure.  Specifically, we maintain a BSP tree where the nodes
  // are edge tests (are we only the left or right of an edge) and the leaves are triangles.
  // There are two operations that modify this tree:
  //
  // 1. Split: A face is split into three by the insertion of an interior vertex.
  // 2. Flip: An edge is flipped, turning two triangles into two different triangles.
  //
  // The three starts out empty, since one triangle needs zero tests.
  Array<Node> bsp; // All BSP nodes including leaves
  bsp.preallocate(3*n); // The minimum number of possible BSP nodes
  Field<Vector<int,2>,FaceId> face_to_bsp; // Map from FaceId to up to two BSP leaf points (2*node+(right?0:1))
  face_to_bsp.flat.preallocate(2*n+1); // The exact maximum number of faces
  face_to_bsp.flat.append_assuming_enough_space(vec(0,-1)); // By the time we call set_links, node 0 will be valid
  if (self_check)
    check_bsp(*mesh,bsp,face_to_bsp,X);

  // Allocate a stack to simulate recursion when flipping non-Delaunay edges.
  // Invariant: if edge is on the stack, the other edges of face(edge) are Delaunay.
  // Since halfedge ids change during edge flips in a corner mesh, we store half edges as directed vertex pairs.
  Array<Tuple<HalfedgeId,Vector<VertexId,2>>> stack;
  stack.preallocate(8);

  // Insert all vertices into the mesh in random order, maintaining the Delaunay property
  for (const auto i : range(n)) {
    const VertexId v(i);
    check_interrupts();

    // Search through the BSP tree to find the containing triangle
    const auto f0 = bsp_search(bsp,X,v);
    const auto vs = mesh->vertices(f0);

    // Split the face by inserting the new vertex and update the BSP tree accordingly.
    mesh->split_face(f0,v);
    const auto e0 = mesh->halfedge(v),
               e1 = mesh->left(e0),
               e2 = mesh->right(e0);
    assert(mesh->dst(e0)==vs.x);
    const auto f1 = mesh->face(e1),
               f2 = mesh->face(e2);
    const int base = bsp.extend(3,uninit);
    set_links(bsp,face_to_bsp[f0],base);
    bsp[base+0] = Node(vec(v,vs.x),base+2,base+1);
    bsp[base+1] = Node(vec(v,vs.y),~f0.id,~f1.id);
    bsp[base+2] = Node(vec(v,vs.z),~f1.id,~f2.id);
    face_to_bsp[f0] = vec(2*(base+1)+0,-1);
    face_to_bsp.flat.append_assuming_enough_space(vec(2*(base+1)+1,2*(base+2)+0));
    face_to_bsp.flat.append_assuming_enough_space(vec(2*(base+2)+1,-1));
    if (self_check) {
      mesh->assert_consistent();
      check_bsp(*mesh,bsp,face_to_bsp,X);
    }

    // Fix all non-Delaunay edges
    stack.copy(vec(tuple(mesh->next(e0),vec(vs.x,vs.y)),
                   tuple(mesh->next(e1),vec(vs.y,vs.z)),
                   tuple(mesh->next(e2),vec(vs.z,vs.x))));
    if (self_check)
      assert_delaunay("self check 1: ",mesh,X,Tuple<>(),true);
    while (stack.size()) {
      const auto evs = stack.pop();
      auto e = mesh->vertices(evs.x)==evs.y ? evs.x : mesh->halfedge(evs.y.x,evs.y.y);
      if (e.valid() && !is_delaunay(*mesh,X,e)) {
        // Our mesh is linearly embedded in the plane, so edge flips are always safe
        assert(mesh->is_flip_safe(e));
        e = mesh->unsafe_flip_edge(e);
        GEODE_ASSERT(is_delaunay(*mesh,X,e));
        // Update the BSP tree for the triangle flip
        const auto f0 = mesh->face(e),
                   f1 = mesh->face(mesh->reverse(e));
        const int node = bsp.append(Node(mesh->vertices(e),~f1.id,~f0.id));
        set_links(bsp,face_to_bsp[f0],node);
        set_links(bsp,face_to_bsp[f1],node);
        face_to_bsp[f0] = vec(2*node+1,-1);
        face_to_bsp[f1] = vec(2*node+0,-1);
        if (self_check) {
          mesh->assert_consistent();
          check_bsp(*mesh,bsp,face_to_bsp,X);
        }
        // Recurse to successor edges to e
        const auto e0 = mesh->next(e),
                   e1 = mesh->prev(mesh->reverse(e));
        stack.extend(vec(tuple(e0,mesh->vertices(e0)),
                         tuple(e1,mesh->vertices(e1))));
        if (self_check)
          assert_delaunay("self check 2: ",mesh,X,Tuple<>(),true);
      }
    }
    if (self_check) {
      mesh->assert_consistent();
      assert_delaunay("self check 3: ",mesh,X);
    }
  }

  // Remove sentinels
  for (int i=0;i<3;i++)
    mesh->erase_last_vertex_with_reordering();

  // If desired, check that the final mesh is Delaunay
  if (validate)
    assert_delaunay("delaunay validate: ",mesh,X);

  // Return the mesh with the sentinels removed
  return mesh;
}
Esempio n. 3
0
HEFace VoronoiDiagram::split_faces(const Point& p) {
    HEFace newface =  hedi::add_face( FaceProps( HEEdge(), p, NONINCIDENT ), g );
    fgrid->add_face( g[newface] );
    BOOST_FOREACH( HEFace f, incident_faces ) {
        split_face(newface, f); // each INCIDENT face is split into two parts: newface and f
    }
Esempio n. 4
0
PST_Edge* PST_Edge::split_face( PST_Point* start, PST_Point* end, PST_Face* face )
{
  if( !start->edge_ || !end->edge_ )
    return 0;
  
  if( ! face )
  {
    PST_Edge* start_edge = start->edge();
    do
    {
      PST_Face* curr_face = start_edge->forward()->face();
      PST_Face* rev_face = start_edge->reverse()->face();
      while( true )
      {
        PST_CoEdge* coe = curr_face->coedge_;
        do
        {
          if( coe->other( end ) )
          {
            if( face ) return 0;
            
            face = curr_face;
            curr_face = rev_face;
            break;
          }
          coe = coe->next();
        } while( coe != curr_face->coedge_ );
        
        if( curr_face == rev_face )
          break;
        else
          curr_face = rev_face;
      }

      start_edge = start_edge->next(start);
    } while( start_edge != start->edge() );
    
    if( !face ) return 0;
  }
  
  PST_CoEdge* start_coedge = 0;
  PST_CoEdge*   end_coedge = 0;
  
  PST_CoEdge* coedge = face->coedge_;
  do
  {
    if( coedge->end_point() == start )
    {
      start_coedge = coedge;
      break;
    }
    coedge = coedge->next();
  } while( coedge != face->coedge_ );
  
  if( ! start_coedge ) 
    return 0;
  
  coedge = start_coedge->next();
  PST_CoEdge* stop = start_coedge;
  do
  {
    if( coedge->end_point() == start )
    {
      start_coedge = coedge;
    }
   
    if( coedge->end_point() == end )
    {
      end_coedge = coedge;
      break;
    }
    
    coedge = coedge->next();
  } while( coedge != stop );
  
  if( ! end_coedge )
    return 0;
  
  
  return split_face( start_coedge, end_coedge );
}