void index_uniqueness_poly(const Polyhedron& g) { std::cerr << "testing Polyhedron\n"; index_uniqueness(g, edges(g) , get(boost::edge_index, g)); index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); index_uniqueness(g, faces(g), get(boost::face_index, g)); index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); index_uniqueness(g, edges(g) , get(boost::edge_external_index, g)); index_uniqueness(g, vertices(g), get(boost::vertex_external_index, g)); index_uniqueness(g, faces(g), get(boost::face_external_index, g)); index_uniqueness(g, halfedges(g), get(boost::halfedge_external_index, g)); }
void remove_face_test_1() { CGAL_GRAPH_TRAITS_MEMBERS(T); Surface_fixture_1<T> f; // find the edge between x and y bool found; halfedge_descriptor e; boost::tie(e, found) = halfedge(f.x, f.y, f.m); assert(found); assert(face(e, f.m) == f.f3); CGAL::Euler::remove_face(e,f.m); assert(CGAL::is_valid(f.m)); assert_EQUAL(degree(f.v, f.m) == 3); assert_EQUAL(degree(f.x, f.m) == 2); assert_EQUAL(CGAL::internal::exact_num_faces(f.m) == 2); assert_EQUAL(CGAL::internal::exact_num_edges(f.m) == 5); assert_EQUAL(CGAL::internal::exact_num_vertices(f.m) == 4); halfedge_iterator eb, ee; int count = 0; for(boost::tie(eb, ee) = halfedges(f.m); eb != ee; ++eb) { if(face(*eb,f.m) == boost::graph_traits<T>::null_face()) ++count; } assert(count == 4); }
void index_uniqueness_omesh(const OMesh& g) { std::cerr << "testing OpenMesh\n"; index_uniqueness(g, edges(g) , get(boost::edge_index, g)); index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); index_uniqueness(g, faces(g), get(boost::face_index, g)); index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); }
void index_uniqueness_sm(const SM& g) { std::cerr << "testing Surface_mesh\n"; index_uniqueness(g, edges(g) , get(boost::edge_index, g)); index_uniqueness(g, vertices(g), get(boost::vertex_index, g)); index_uniqueness(g, faces(g), get(boost::face_index, g)); index_uniqueness(g, halfedges(g), get(boost::halfedge_index, g)); }
void gnu() { SM sm; CGAL::make_triangle(Point_3(0,0,0), Point_3(1,0,0), Point_3(1,1,0),sm); halfedge_descriptor hd = *(halfedges(sm).first); hd = next(hd,sm); std::cout << hd; }
int main(int argc, char* argv[]) { const char* filename = (argc > 1) ? argv[1] : "data/mech-holes-shark.off"; LCC mesh; CGAL::read_off(filename, mesh); // Incrementally fill the holes unsigned int nb_holes = 0; for ( halfedge_iterator it=halfedges(mesh).begin(); it!=halfedges(mesh).end(); ++it) { halfedge_descriptor h=*it; if(is_border(h,mesh)) { std::vector<face_descriptor> patch_facets; std::vector<vertex_descriptor> patch_vertices; bool success = CGAL::cpp11::get<0>( CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole( mesh, h, std::back_inserter(patch_facets), std::back_inserter(patch_vertices), CGAL::Polygon_mesh_processing::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)). geom_traits(Kernel())) ); std::cout << "* Number of facets in constructed patch: " << patch_facets.size() << std::endl; std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() << std::endl; std::cout << " Is fairing successful: " << success << std::endl; nb_holes++; } } std::cout << std::endl; std::cout << nb_holes << " holes have been filled" << std::endl; std::ofstream out("filled_LCC.off"); out.precision(17); CGAL::write_off(out, mesh); return 0; }
void test_edge_hash_and_null(const P& p) { typedef boost::graph_traits<P> GT; typedef typename GT::halfedge_descriptor halfedge_descriptor; typedef typename GT::vertex_descriptor vertex_descriptor; typedef typename GT::face_descriptor face_descriptor; BOOST_FOREACH(halfedge_descriptor h, halfedges(p)) { assert( hash_value( edge(h,p) ) == hash_value( edge(opposite(h,p),p) ) ); }
int main(int argc, char *argv[]) { FILE *fp; char comment[80]; float *verts; vertex_t *tris; halfedge_t *enext; vertex_t *evert; halfedge_t *vnext; uint16_t *attrs; triangle_t ntris; halfedge_t nedges; vertex_t nverts; int i, nrounds, opt; nrounds = 5; while((opt = getopt(argc, argv, "n:")) != -1){ switch(opt){ case 'n': nrounds = strtol(optarg, NULL, 10); break; default: caseusage: fprintf(stderr, "usage: %s [-n nrounds] path/to/file.stl\n", argv[0]); exit(1); } } if(optind == argc) goto caseusage; for(i = 0; i < nrounds; i++){ if(argc > 1){ fp = fopen(argv[optind], "rb"); } else { fp = stdin; } loadstl(fp, comment, &verts, &nverts, &tris, &attrs, &ntris); halfedges(tris, ntris, &enext, &evert, &nedges); dualedges(enext, nedges, &vnext); fclose(fp); free(tris); free(verts); free(attrs); free(enext); free(evert); free(vnext); } return 0; }
void test(const char *fname, bool triangle, bool quad, bool tetrahedron, bool hexahedron) { typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor; std::cerr << "test(" << fname << ")"<< std::endl; Mesh m; std::ifstream in(fname); in >> m; halfedge_descriptor hd = *halfedges(m).first; assert(CGAL::is_isolated_triangle(hd, m) == triangle); assert(CGAL::is_isolated_quad(hd, m) == quad); assert(CGAL::is_tetrahedron(hd, m) == tetrahedron); assert(CGAL::is_hexahedron(hd, m) == hexahedron); }
int main( int argc, char** argv ) { Surface_mesh surface_mesh; std::ifstream is(argv[1]); is >> surface_mesh; if (!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } // The items in this polyhedron have an "id()" field // which the default index maps used in the algorithm // need to get the index of a vertex/edge. // However, the Polyhedron_3 class doesn't assign any value to // this id(), so we must do it here: int index = 0; BOOST_FOREACH(halfedge_descriptor hd , halfedges(surface_mesh)){ hd->id() = index++; } index = 0; BOOST_FOREACH(vertex_descriptor vd , vertices(surface_mesh)){ vd->id() = index++; } // In this example, the simplification stops when the number of undirected edges // drops below 10% of the initial count SMS::Count_ratio_stop_predicate<Surface_mesh> stop(0.1); // The index maps are not explicitelty passed as in the previous // example because the surface mesh items have a proper id() field. // On the other hand, we pass here explicit cost and placement // function which differ from the default policies, ommited in // the previous example. int r = SMS::edge_collapse(surface_mesh, stop); std::cout << "\nFinished...\n" << r << " edges removed.\n" << (surface_mesh.size_of_halfedges()/2) << " final edges.\n"; std::ofstream os( argc > 2 ? argv[2] : "out.off" ); os.precision(17); os << surface_mesh; return EXIT_SUCCESS; }
int main(int,char*[]) { Triangulation t; t.insert(Point(0.1,0,1)); t.insert(Point(1,0,1)); t.insert(Point(0.2,0.2, 2)); t.insert(Point(0,1,2)); t.insert(Point(0,2,3)); vertex_iterator vit, ve; // Associate indices to the vertices int index = 0; // boost::tie assigns the first and second element of the std::pair // returned by boost::vertices to the variables vit and ve for(boost::tie(vit,ve) = vertices(t); vit!=ve; ++vit ){ vertex_descriptor vd = *vit; if(! t.is_infinite(vd)){ vertex_id_map[vd]= index++; } } std::cerr << index << " vertices" << std::endl; index = 0; face_iterator fit,fe; for(boost::tie(fit,fe) = faces(t); fit!= fe; ++fit){ face_descriptor fd = *fit; halfedge_descriptor hd = halfedge(fd,t); halfedge_descriptor n = next(hd,t); halfedge_descriptor nn = next(n,t); if(next(nn,t) != hd){ std::cerr << "the face is not a triangle" << std::endl; } ++index; } std::cerr << index << " faces" << std::endl; index = 0; edge_iterator eit,ee; for(boost::tie(eit,ee) = edges(t); eit!= ee; ++eit){ edge_descriptor ed = *eit; vertex_descriptor vd = source(ed,t); CGAL_USE(vd); ++index; } std::cerr << index << " edges" << std::endl; index = 0; halfedge_iterator hit,he; for(boost::tie(hit,he) = halfedges(t); hit!= he; ++hit){ halfedge_descriptor hd = *hit; vertex_descriptor vd = source(hd,t); CGAL_USE(vd); ++index; } std::cerr << index << " halfedges" << std::endl; std::cerr << num_vertices(t) << " " << num_edges(t) << " " << num_halfedges(t) << " " << num_faces(t) << std::endl; typedef boost::property_map<Triangulation, boost::vertex_point_t>::type Ppmap; Ppmap ppmap = get(boost::vertex_point, t); for(vertex_descriptor vd : vertices_around_target(*vertices(t).first, t)){ std::cout << ppmap[vd] << std::endl; } ppmap[*(++vertices(t).first)] = Point(78,1,2); std::cout << " changed point of vertex " << ppmap[*(++vertices(t).first)] << std::endl; return 0; }
int main( int argc, char** argv ) { Surface_mesh surface_mesh; if (argc!=2){ std::cerr << "Usage: " << argv[0] << " input.off\n"; return EXIT_FAILURE; } std::ifstream is(argv[1]); if(!is){ std::cerr << "Filename provided is invalid\n"; return EXIT_FAILURE; } is >> surface_mesh ; if (!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } Surface_mesh::Property_map<halfedge_descriptor,std::pair<Point_3, Point_3> > constrained_halfedges; constrained_halfedges = surface_mesh.add_property_map<halfedge_descriptor,std::pair<Point_3, Point_3> >("h:vertices").first; std::size_t nb_border_edges=0; BOOST_FOREACH(halfedge_descriptor hd, halfedges(surface_mesh)){ if(CGAL::is_border(hd,surface_mesh)){ constrained_halfedges[hd] = std::make_pair(surface_mesh.point(source(hd,surface_mesh)), surface_mesh.point(target(hd,surface_mesh))); ++nb_border_edges; } } // Contract the surface mesh as much as possible SMS::Count_stop_predicate<Surface_mesh> stop(0); Border_is_constrained_edge_map bem(surface_mesh); // This the actual call to the simplification algorithm. // The surface mesh and stop conditions are mandatory arguments. int r = SMS::edge_collapse (surface_mesh ,stop ,CGAL::parameters::edge_is_constrained_map(bem) .get_placement(Placement(bem)) ); std::cout << "\nFinished...\n" << r << " edges removed.\n" << surface_mesh.number_of_edges() << " final edges.\n"; std::ofstream os( argc > 2 ? argv[2] : "out.off" ); os.precision(17); os << surface_mesh; // now check! BOOST_FOREACH(halfedge_descriptor hd, halfedges(surface_mesh)){ if(CGAL::is_border(hd,surface_mesh)){ --nb_border_edges; if(constrained_halfedges[hd] != std::make_pair(surface_mesh.point(source(hd,surface_mesh)), surface_mesh.point(target(hd,surface_mesh)))){ std::cerr << "oops. send us a bug report\n"; } } } assert( nb_border_edges==0 ); return EXIT_SUCCESS; }
Surface_mesh::Face Surface_mesh:: add_face(const std::vector<Vertex>& vertices) { Vertex v; unsigned int i, ii, n((int)vertices.size()), id; std::vector<Halfedge> halfedges(n); std::vector<bool> is_new(n), needs_adjust(n, false); Halfedge inner_next, inner_prev, outer_next, outer_prev, boundary_next, boundary_prev, patch_start, patch_end; // cache for set_next_halfedge and vertex' set_halfedge typedef std::pair<Halfedge, Halfedge> NextCacheEntry; typedef std::vector<NextCacheEntry> NextCache; NextCache next_cache; next_cache.reserve(3*n); // don't allow degenerated faces assert (n > 2); // test for topological errors for (i=0, ii=1; i<n; ++i, ++ii, ii%=n) { if ( !is_boundary(vertices[i]) ) { std::cerr << "Surface_meshT::add_face: complex vertex\n"; return Face(); } halfedges[i] = find_halfedge(vertices[i], vertices[ii]); is_new[i] = !halfedges[i].is_valid(); if (!is_new[i] && !is_boundary(halfedges[i])) { std::cerr << "Surface_meshT::add_face: complex edge\n"; return Face(); } } // re-link patches if necessary for (i=0, ii=1; i<n; ++i, ++ii, ii%=n) { if (!is_new[i] && !is_new[ii]) { inner_prev = halfedges[i]; inner_next = halfedges[ii]; if (next_halfedge(inner_prev) != inner_next) { // here comes the ugly part... we have to relink a whole patch // search a free gap // free gap will be between boundary_prev and boundary_next outer_prev = opposite_halfedge(inner_next); outer_next = opposite_halfedge(inner_prev); boundary_prev = outer_prev; do boundary_prev = opposite_halfedge(next_halfedge(boundary_prev)); while (!is_boundary(boundary_prev) || boundary_prev==inner_prev); boundary_next = next_halfedge(boundary_prev); assert(is_boundary(boundary_prev)); assert(is_boundary(boundary_next)); // ok ? if (boundary_next == inner_next) { std::cerr << "Surface_meshT::add_face: patch re-linking failed\n"; return Face(); } // other halfedges' handles patch_start = next_halfedge(inner_prev); patch_end = prev_halfedge(inner_next); // relink next_cache.push_back(NextCacheEntry(boundary_prev, patch_start)); next_cache.push_back(NextCacheEntry(patch_end, boundary_next)); next_cache.push_back(NextCacheEntry(inner_prev, inner_next)); } } } // create missing edges for (i=0, ii=1; i<n; ++i, ++ii, ii%=n) if (is_new[i]) halfedges[i] = new_edge(vertices[i], vertices[ii]); // create the face Face f(new_face()); set_halfedge(f, halfedges[n-1]); // setup halfedges for (i=0, ii=1; i<n; ++i, ++ii, ii%=n) { v = vertices[ii]; inner_prev = halfedges[i]; inner_next = halfedges[ii]; id = 0; if (is_new[i]) id |= 1; if (is_new[ii]) id |= 2; if (id) { outer_prev = opposite_halfedge(inner_next); outer_next = opposite_halfedge(inner_prev); // set outer links switch (id) { case 1: // prev is new, next is old boundary_prev = prev_halfedge(inner_next); next_cache.push_back(NextCacheEntry(boundary_prev, outer_next)); set_halfedge(v, outer_next); break; case 2: // next is new, prev is old boundary_next = next_halfedge(inner_prev); next_cache.push_back(NextCacheEntry(outer_prev, boundary_next)); set_halfedge(v, boundary_next); break; case 3: // both are new if (!halfedge(v).is_valid()) { set_halfedge(v, outer_next); next_cache.push_back(NextCacheEntry(outer_prev, outer_next)); } else { boundary_next = halfedge(v); boundary_prev = prev_halfedge(boundary_next); next_cache.push_back(NextCacheEntry(boundary_prev, outer_next)); next_cache.push_back(NextCacheEntry(outer_prev, boundary_next)); } break; } // set inner link next_cache.push_back(NextCacheEntry(inner_prev, inner_next)); } else needs_adjust[ii] = (halfedge(v) == inner_next); // set face handle set_face(halfedges[i], f); } // process next halfedge cache NextCache::const_iterator ncIt(next_cache.begin()), ncEnd(next_cache.end()); for (; ncIt != ncEnd; ++ncIt) set_next_halfedge(ncIt->first, ncIt->second); // adjust vertices' halfedge handle for (i=0; i<n; ++i) if (needs_adjust[i]) adjust_outgoing_halfedge(vertices[i]); return f; }
void Surface_mesh:: remove_edge(Halfedge h) { Halfedge hn = next_halfedge(h); Halfedge hp = prev_halfedge(h); Halfedge o = opposite_halfedge(h); Halfedge on = next_halfedge(o); Halfedge op = prev_halfedge(o); Face fh = face(h); Face fo = face(o); Vertex vh = to_vertex(h); Vertex vo = to_vertex(o); // halfedge -> vertex Halfedge_around_vertex_circulator vh_it, vh_end; vh_it = vh_end = halfedges(vo); do { set_vertex(opposite_halfedge(vh_it), vh); } while (++vh_it != vh_end); // halfedge -> halfedge set_next_halfedge(hp, hn); set_next_halfedge(op, on); // face -> halfedge if (fh.is_valid()) set_halfedge(fh, hn); if (fo.is_valid()) set_halfedge(fo, on); // vertex -> halfedge if (halfedge(vh) == o) set_halfedge(vh, hn); adjust_outgoing_halfedge(vh); set_halfedge(vo, Halfedge()); // delete stuff if (!vdeleted_) vdeleted_ = vertex_property<bool>("v:deleted", false); if (!edeleted_) edeleted_ = edge_property<bool>("e:deleted", false); vdeleted_[vo] = true; ++deleted_vertices_; edeleted_[edge(h)] = true; ++deleted_edges_; garbage_ = true; //add for(unsigned int j = 0;j < map_2skel.size();j++) { if(map_2skel[j] == vo.idx()) { //unsigned int tem = map_2skel[j]; map_2skel[j] = vh.idx(); //qDebug("vertex:[%d],change %d to %d",j,tem,vh.idx()); } } //end }