deal with non-manifold surfaces

because a CGAL::Polyhedron cannot be non-manifold along an edge, we need
to build the polyhedral surface using PMP::orient_polygon_soup, and
PMP::polygon_soup_to_polygon_mesh.
These functions introduce duplicated points, that are dealt with in this commit

when reading a .surf file, isolated vertices are ignored
This commit is contained in:
Jane Tournois 2017-04-21 14:40:08 +02:00
parent 9f4eb7c887
commit 2b16193db4
4 changed files with 61 additions and 13 deletions

View File

@ -29,6 +29,7 @@
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h> #include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
#include <CGAL/algorithm.h> #include <CGAL/algorithm.h>
#include <set> #include <set>
#include <boost/dynamic_bitset.hpp>
#include <boost/range/size.hpp> #include <boost/range/size.hpp>
#include <boost/range/value_type.hpp> #include <boost/range/value_type.hpp>
@ -67,13 +68,29 @@ public:
_polygons(polygons) _polygons(polygons)
{ } { }
void operator()(PM& pmesh) void operator()(PM& pmesh, const bool insert_isolated_vertices = true)
{ {
Vpmap vpmap = get(CGAL::vertex_point, pmesh); Vpmap vpmap = get(CGAL::vertex_point, pmesh);
boost::dynamic_bitset<> not_isolated;
if (!insert_isolated_vertices)
{
not_isolated.resize(_points.size());
for (std::size_t i = 0, end = _polygons.size(); i < end; ++i)
{
const Polygon& polygon = _polygons[i];
const std::size_t size = polygon.size();
for (std::size_t j = 0; j < size; ++j)
not_isolated.set(polygon[j], true);
}
}
std::vector<vertex_descriptor> vertices(_points.size()); std::vector<vertex_descriptor> vertices(_points.size());
for (std::size_t i = 0, end = _points.size(); i < end; ++i) for (std::size_t i = 0, end = _points.size(); i < end; ++i)
{ {
if (!insert_isolated_vertices && !not_isolated.test(i))
continue;
Point_3 pi(_points[i][0], _points[i][1], _points[i][2]); Point_3 pi(_points[i][0], _points[i][1], _points[i][2]);
vertices[i] = add_vertex(pmesh); vertices[i] = add_vertex(pmesh);
put(vpmap, vertices[i], pi); put(vpmap, vertices[i], pi);
@ -162,6 +179,8 @@ public:
typename Orienter::Marked_edges marked_edges; typename Orienter::Marked_edges marked_edges;
Orienter::fill_edge_map(edges, marked_edges, polygons); Orienter::fill_edge_map(edges, marked_edges, polygons);
//returns false if duplication is necessary //returns false if duplication is necessary
if (!marked_edges.empty())
return false;
return Orienter::has_singular_vertices(static_cast<std::size_t>(max_id+1),polygons,edges,marked_edges); return Orienter::has_singular_vertices(static_cast<std::size_t>(max_id+1),polygons,edges,marked_edges);
} }

View File

@ -15,6 +15,7 @@
#include "Color_map.h" #include "Color_map.h"
#include <fstream> #include <fstream>
#include <boost/container/flat_set.hpp>
using namespace CGAL::Three; using namespace CGAL::Three;
class Surf_io_plugin: class Surf_io_plugin:
@ -62,13 +63,19 @@ CGAL::Three::Scene_item* Surf_io_plugin::load(QFileInfo fileinfo)
std::vector<MaterialData> material_data; std::vector<MaterialData> material_data;
CGAL::Bbox_3 grid_box; CGAL::Bbox_3 grid_box;
CGAL::cpp11::array<unsigned int, 3> grid_size = {{1, 1, 1}}; CGAL::cpp11::array<unsigned int, 3> grid_size = {{1, 1, 1}};
read_surf(in, patches, material_data, grid_box, grid_size); boost::container::flat_set<Polyhedron::Point_3> duplicated_points;
read_surf(in, patches, material_data, grid_box, grid_size
, std::inserter(duplicated_points, duplicated_points.end()));
for(std::size_t i=0; i<material_data.size(); ++i) for(std::size_t i=0; i<material_data.size(); ++i)
{ {
std::cout<<"The patch #"<<i<<":\n -inner region : material's id = "<<material_data[i].innerRegion.first<<" material's name = " std::cout<<"The patch #"<<i<<":\n -inner region : material's id = "<<material_data[i].innerRegion.first<<" material's name = "
<<material_data[i].innerRegion.second<<"\n -outer region: material's id = "<<material_data[i].outerRegion.first<<" material's name = " <<material_data[i].innerRegion.second<<"\n -outer region: material's id = "<<material_data[i].outerRegion.first<<" material's name = "
<<material_data[i].outerRegion.second<<std::endl; <<material_data[i].outerRegion.second<<std::endl;
} }
if (!duplicated_points.empty())
std::cout << duplicated_points.size() << " points have been duplicated." << std::endl;
std::vector<QColor> colors_; std::vector<QColor> colors_;
compute_color_map(QColor(100, 100, 255), static_cast<unsigned>(patches.size()), compute_color_map(QColor(100, 100, 255), static_cast<unsigned>(patches.size()),
std::back_inserter(colors_)); std::back_inserter(colors_));

View File

@ -14,6 +14,7 @@
#include "Color_map.h" #include "Color_map.h"
#include <fstream> #include <fstream>
#include <boost/container/flat_set.hpp>
using namespace CGAL::Three; using namespace CGAL::Three;
class Surf_io_plugin: class Surf_io_plugin:
@ -51,6 +52,7 @@ public:
CGAL::Three::Scene_item* Surf_io_plugin::load(QFileInfo fileinfo) CGAL::Three::Scene_item* Surf_io_plugin::load(QFileInfo fileinfo)
{ {
typedef Scene_surface_mesh_item::SMesh SMesh; typedef Scene_surface_mesh_item::SMesh SMesh;
typedef Scene_surface_mesh_item::Point Point;
// Open file // Open file
std::ifstream in(fileinfo.filePath().toUtf8()); std::ifstream in(fileinfo.filePath().toUtf8());
if(!in) { if(!in) {
@ -62,13 +64,19 @@ CGAL::Three::Scene_item* Surf_io_plugin::load(QFileInfo fileinfo)
std::vector<MaterialData> material_data; std::vector<MaterialData> material_data;
CGAL::Bbox_3 grid_box; CGAL::Bbox_3 grid_box;
CGAL::cpp11::array<unsigned int, 3> grid_size = {{1, 1, 1}}; CGAL::cpp11::array<unsigned int, 3> grid_size = {{1, 1, 1}};
read_surf(in, patches, material_data, grid_box, grid_size); boost::container::flat_set<Point> duplicated_points;
read_surf(in, patches, material_data, grid_box, grid_size
, std::inserter(duplicated_points, duplicated_points.end()));
for (std::size_t i = 0; i<material_data.size(); ++i) for (std::size_t i = 0; i<material_data.size(); ++i)
{ {
std::cout<<"The patch #"<<i<<":\n -inner region : material's id = "<<material_data[i].innerRegion.first<<" material's name = " std::cout<<"The patch #"<<i<<":\n -inner region : material's id = "<<material_data[i].innerRegion.first<<" material's name = "
<<material_data[i].innerRegion.second<<"\n -outer region: material's id = "<<material_data[i].outerRegion.first<<" material's name = " <<material_data[i].innerRegion.second<<"\n -outer region: material's id = "<<material_data[i].outerRegion.first<<" material's name = "
<<material_data[i].outerRegion.second<<std::endl; <<material_data[i].outerRegion.second<<std::endl;
} }
if (!duplicated_points.empty())
std::cout << duplicated_points.size() << " points have been duplicated." << std::endl;
std::vector<QColor> colors_; std::vector<QColor> colors_;
compute_color_map(QColor(100, 100, 255), static_cast<unsigned>(patches.size()), compute_color_map(QColor(100, 100, 255), static_cast<unsigned>(patches.size()),
std::back_inserter(colors_)); std::back_inserter(colors_));

View File

@ -77,16 +77,18 @@ bool line_starts_with(const std::string& line, const char* cstr)
* read_surf reads a file which extension is .surf and fills `output` with one `Mesh` per patch. * read_surf reads a file which extension is .surf and fills `output` with one `Mesh` per patch.
* Mesh is a model of FaceListGraph. * Mesh is a model of FaceListGraph.
*/ */
template<class Mesh, class NamedParameters> template<class Mesh, typename DuplicatedPointsOutIterator, class NamedParameters>
bool read_surf(std::istream& input, std::vector<Mesh>& output, bool read_surf(std::istream& input, std::vector<Mesh>& output,
std::vector<MaterialData>& metadata, std::vector<MaterialData>& metadata,
CGAL::Bbox_3& grid_box, CGAL::Bbox_3& grid_box,
CGAL::cpp11::array<unsigned int, 3>& grid_size, CGAL::cpp11::array<unsigned int, 3>& grid_size,
DuplicatedPointsOutIterator out,
const NamedParameters&) const NamedParameters&)
{ {
typedef typename CGAL::GetGeomTraits<Mesh, typedef typename CGAL::GetGeomTraits<Mesh,
NamedParameters>::type Kernel; NamedParameters>::type Kernel;
typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Point_3 Point_3;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
std::vector<Point_3> points; std::vector<Point_3> points;
std::string line; std::string line;
std::istringstream iss; std::istringstream iss;
@ -264,33 +266,45 @@ bool read_surf(std::istream& input, std::vector<Mesh>& output,
{ {
std::cout << "Orientation of patch #" << (i + 1) << "..."; std::cout << "Orientation of patch #" << (i + 1) << "...";
std::cout.flush(); std::cout.flush();
const std::size_t nbp_init = points.size();
bool no_duplicates = bool no_duplicates =
PMP::orient_polygon_soup(points, polygons);//returns false if some points PMP::orient_polygon_soup(points, polygons);//returns false if some points
//were duplicated //were duplicated
std::cout << "\rOrientation of patch #" << (i + 1) << " done"; std::cout << "\rOrientation of patch #" << (i + 1) << " done";
if (!no_duplicates)
std::cout << " (non manifold -> duplicated vertices)"; if(!no_duplicates) //collect duplicates
{
for (std::size_t i = nbp_init; i < points.size(); ++i)
*out++ = points[i];
std::cout << " (non manifold -> "
<< (points.size() - nbp_init) << " duplicated vertices)";
}
std::cout << "." << std::endl; std::cout << "." << std::endl;
} }
Mesh& mesh = output[i]; Mesh& mesh = output[i];
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh( PMP::internal::Polygon_soup_to_polygon_mesh<Mesh, Point_3, Triangle_ind>
points, polygons, mesh); converter(points, polygons);
CGAL::Polygon_mesh_processing::remove_isolated_vertices(mesh); converter(mesh, false/*insert_isolated_vertices*/);
CGAL_assertion(PMP::remove_isolated_vertices(mesh) == 0);
CGAL_assertion(is_valid(mesh)); CGAL_assertion(is_valid(mesh));
} // end loop on patches } // end loop on patches
return true; return true;
} }
template<class Mesh> template<class Mesh, typename DuplicatedPointsOutIterator>
bool read_surf(std::istream& input, std::vector<Mesh>& output, bool read_surf(std::istream& input, std::vector<Mesh>& output,
std::vector<MaterialData>& metadata, std::vector<MaterialData>& metadata,
CGAL::Bbox_3& grid_box, CGAL::Bbox_3& grid_box,
CGAL::cpp11::array<unsigned int, 3>& grid_size) CGAL::cpp11::array<unsigned int, 3>& grid_size,
DuplicatedPointsOutIterator out)
{ {
return read_surf(input, output, metadata, grid_box, grid_size, return read_surf(input, output, metadata, grid_box, grid_size, out,
CGAL::Polygon_mesh_processing::parameters::all_default()); CGAL::Polygon_mesh_processing::parameters::all_default());
} }