CGAL Lab: Rendering polygons with ghost edges (#7898)

Polygons and meshes with non-triangular faces that have ghost edges,
i.e., holes connected via two identical edges to the outer border of the
polygon, are now correctly rendered.

The FacetTriangulator now uses mark_domain_in_triangulation to set
is_external property.

## Release Management

* Affected package(s): Polyhedron/demo
This commit is contained in:
Laurent Rineau 2024-01-11 14:01:52 +01:00 committed by GitHub
commit 61800d1be7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 263 additions and 228 deletions

View File

@ -190,13 +190,10 @@ private:
for(boost::graph_traits<Face_graph>::face_descriptor f : faces(*poly)) { for(boost::graph_traits<Face_graph>::face_descriptor f : faces(*poly)) {
Vector nf = get(nf_pmap, f); Vector nf = get(nf_pmap, f);
typedef FacetTriangulator<Face_graph, Kernel, boost::graph_traits<Face_graph>::vertex_descriptor> FT;
//compute distance with other polyhedron //compute distance with other polyhedron
//sample facet //sample facet
std::vector<Kernel::Point_3> sampled_points; std::vector<Kernel::Point_3> sampled_points;
std::size_t nb_points = (std::max)((int)std::ceil(nb_pts_per_face * PMP::face_area(f,*poly,CGAL::parameters::geom_traits(Kernel()))), std::size_t nb_points = (std::max)((int)std::ceil(nb_pts_per_face * PMP::face_area(f,*poly,CGAL::parameters::geom_traits(Kernel()))), 1);
1);
Kernel::Point_3 &p = get(vpmap,target(halfedge(f,*poly),*poly)); Kernel::Point_3 &p = get(vpmap,target(halfedge(f,*poly),*poly));
Kernel::Point_3 &q = get(vpmap,target(next(halfedge(f,*poly),*poly),*poly)); Kernel::Point_3 &q = get(vpmap,target(next(halfedge(f,*poly),*poly),*poly));
Kernel::Point_3 &r = get(vpmap,target(next(next(halfedge(f,*poly),*poly),*poly),*poly)); Kernel::Point_3 &r = get(vpmap,target(next(next(halfedge(f,*poly),*poly),*poly),*poly));
@ -207,36 +204,42 @@ private:
sampled_points.push_back(r); sampled_points.push_back(r);
//triangle facets with sample points for color display //triangle facets with sample points for color display
FT triangulation(f,sampled_points,nf,poly); auto func = [&](auto& ffit, auto&) {
if (ffit.info().is_external)
return;
if(triangulation.cdt->dimension() != 2 ) for (int i = 0; i < 3; ++i)
{
qDebug()<<"Error : cdt not right (dimension != 2). Facet not displayed";
continue;
}
//iterates on the internal faces to add the vertices to the positions
//and the normals to the appropriate vectors
for(FT::CDT::Finite_faces_iterator
ffit = triangulation.cdt->finite_faces_begin(),
end = triangulation.cdt->finite_faces_end();
ffit != end; ++ffit)
{
if(ffit->info().is_external)
continue;
for (int i = 0; i<3; ++i)
{ {
total_points.push_back(ffit->vertex(i)->point()); total_points.push_back(ffit.vertex(i)->point());
m_vertices.push_back(ffit->vertex(i)->point().x()); m_vertices.push_back(ffit.vertex(i)->point().x());
m_vertices.push_back(ffit->vertex(i)->point().y()); m_vertices.push_back(ffit.vertex(i)->point().y());
m_vertices.push_back(ffit->vertex(i)->point().z()); m_vertices.push_back(ffit.vertex(i)->point().z());
normals.push_back(nf.x()); normals.push_back(nf.x());
normals.push_back(nf.y()); normals.push_back(nf.y());
normals.push_back(nf.z()); normals.push_back(nf.z());
} }
};
try {
FacetTriangulator<Face_graph, Kernel, boost::graph_traits<Face_graph>::vertex_descriptor> triangulation(f, sampled_points, nf, poly);
if (triangulation.cdt->dimension() != 2)
{
qDebug() << "Error : cdt not right (dimension != 2). Facet not displayed";
continue;
}
triangulation.per_face(func);
}
catch (...) {
FacetTriangulator<Face_graph, Kernel, boost::graph_traits<Face_graph>::vertex_descriptor, CGAL::Exact_intersections_tag> triangulation(f, sampled_points, nf, poly);
if (triangulation.cdt->dimension() != 2)
{
qDebug() << "Error : cdt not right (dimension != 2). Facet not displayed";
continue;
}
triangulation.per_face(func);
} }
} }
//compute the distances //compute the distances

View File

@ -137,80 +137,71 @@ Scene_polygon_soup_item_priv::triangulate_polygon(Polygons_iterator pit, int pol
if (normal == CGAL::NULL_VECTOR) // No normal could be computed, return if (normal == CGAL::NULL_VECTOR) // No normal could be computed, return
return; return;
typedef FacetTriangulator<SMesh, EPICK, std::size_t> FT; typedef std::pair<EPICK::Point_3, std::size_t> PointAndId;
std::size_t it = 0; std::size_t it = 0;
std::size_t it_end =pit->size(); std::size_t it_end =pit->size();
std::vector<FT::PointAndId> pointIds; std::vector<PointAndId> pointIds;
do { do {
FT::PointAndId pointId; PointAndId pointId;
pointId.point = soup->points[pit->at(it)]+offset; pointId.first = soup->points[pit->at(it)]+offset;
pointId.id = pit->at(it); pointId.second = pit->at(it);
pointIds.push_back(pointId); pointIds.push_back(pointId);
} while( ++it != it_end ); } while( ++it != it_end );
//detect degenerated faces
std::vector<FT::PointAndId> pid_stack = pointIds;
for(std::size_t i = 0; i< pointIds.size(); ++i)
{
FT::PointAndId pid = pid_stack.back();
pid_stack.pop_back();
for(FT::PointAndId poai : pid_stack)
{
if (pid.point== poai.point)
{
return;
}
}
}
FT triangulation(pointIds,normal);
//iterates on the internal faces to add the vertices to the positions //iterates on the internal faces to add the vertices to the positions
//and the normals to the appropriate vectors //and the normals to the appropriate vectors
for(FT::CDT::Finite_faces_iterator auto f = [&](auto& ffit, auto& v2v) {
ffit = triangulation.cdt->finite_faces_begin(), if (ffit.info().is_external)
end = triangulation.cdt->finite_faces_end(); return;
ffit != end; ++ffit)
{
if(ffit->info().is_external)
continue;
positions_poly.push_back(ffit->vertex(0)->point().x()); positions_poly.push_back(ffit.vertex(0)->point().x());
positions_poly.push_back(ffit->vertex(0)->point().y()); positions_poly.push_back(ffit.vertex(0)->point().y());
positions_poly.push_back(ffit->vertex(0)->point().z()); positions_poly.push_back(ffit.vertex(0)->point().z());
positions_poly.push_back(ffit.vertex(1)->point().x());
positions_poly.push_back(ffit.vertex(1)->point().y());
positions_poly.push_back(ffit.vertex(1)->point().z());
positions_poly.push_back(ffit->vertex(1)->point().x()); positions_poly.push_back(ffit.vertex(2)->point().x());
positions_poly.push_back(ffit->vertex(1)->point().y()); positions_poly.push_back(ffit.vertex(2)->point().y());
positions_poly.push_back(ffit->vertex(1)->point().z()); positions_poly.push_back(ffit.vertex(2)->point().z());
positions_poly.push_back(ffit->vertex(2)->point().x()); CGAL::IO::Color color;
positions_poly.push_back(ffit->vertex(2)->point().y()); if (!soup->fcolors.empty())
positions_poly.push_back(ffit->vertex(2)->point().z()); color = soup->fcolors[polygon_id];
for (int i = 0; i < 3; i++)
CGAL::IO::Color color; {
if(!soup->fcolors.empty()) normals.push_back(normal.x());
color = soup->fcolors[polygon_id]; normals.push_back(normal.y());
for(int i=0; i<3; i++) normals.push_back(normal.z());
if (!soup->fcolors.empty())
{ {
normals.push_back(normal.x()); f_colors.push_back(static_cast<float>(color.red()) / 255);
normals.push_back(normal.y()); f_colors.push_back(static_cast<float>(color.green()) / 255);
normals.push_back(normal.z()); f_colors.push_back(static_cast<float>(color.blue()) / 255);
if(!soup->fcolors.empty())
{
f_colors.push_back(static_cast<float>(color.red())/255);
f_colors.push_back(static_cast<float>(color.green())/255);
f_colors.push_back(static_cast<float>(color.blue())/255);
}
if(!soup->vcolors.empty())
{
CGAL::IO::Color vcolor = soup->vcolors[triangulation.v2v[ffit->vertex(i)]];
v_colors.push_back(static_cast<float>(vcolor.red())/255);
v_colors.push_back(static_cast<float>(vcolor.green())/255);
v_colors.push_back(static_cast<float>(vcolor.blue())/255);
}
} }
if (!soup->vcolors.empty())
{
CGAL::IO::Color vcolor = soup->vcolors[v2v[ffit.vertex(i)]];
v_colors.push_back(static_cast<float>(vcolor.red()) / 255);
v_colors.push_back(static_cast<float>(vcolor.green()) / 255);
v_colors.push_back(static_cast<float>(vcolor.blue()) / 255);
}
}
};
try {
FacetTriangulator<SMesh, EPICK, std::size_t> triangulation(pointIds, normal);
triangulation.per_face(f);
}
catch (...) {
FacetTriangulator<SMesh, EPICK, std::size_t, CGAL::Exact_intersections_tag> triangulation(pointIds, normal);
triangulation.per_face(f);
} }
} }
void void
Scene_polygon_soup_item_priv::compute_normals_and_vertices() const{ Scene_polygon_soup_item_priv::compute_normals_and_vertices() const{

View File

@ -282,26 +282,29 @@ Scene_polyhedron_selection_item_priv::triangulate_facet(fg_face_descriptor fit,c
const CGAL::qglviewer::Vec off = Three::mainViewer()->offset(); const CGAL::qglviewer::Vec off = Three::mainViewer()->offset();
EPICK::Vector_3 offset(off.x,off.y,off.z); EPICK::Vector_3 offset(off.x,off.y,off.z);
typedef FacetTriangulator<Face_graph, EPICK, fg_vertex_descriptor> FT; //iterates on the internal faces to add the vertices to the positions
FT triangulation(fit,normal,poly, offset); //and the normals to the appropriate vectors
//iterates on the internal faces to add the vertices to the positions auto f = [&](auto& ffit, auto& /* v2v */) {
//and the normals to the appropriate vectors if (ffit.info().is_external)
for(FT::CDT::Finite_faces_iterator return;
ffit = triangulation.cdt->finite_faces_begin(),
end = triangulation.cdt->finite_faces_end();
ffit != end; ++ffit)
{
if(ffit->info().is_external)
continue;
push_back_xyz(ffit->vertex(0)->point(), p_facets); push_back_xyz(ffit.vertex(0)->point(), p_facets);
push_back_xyz(ffit->vertex(1)->point(), p_facets); push_back_xyz(ffit.vertex(1)->point(), p_facets);
push_back_xyz(ffit->vertex(2)->point(), p_facets); push_back_xyz(ffit.vertex(2)->point(), p_facets);
push_back_xyz(normal, p_normals); push_back_xyz(normal, p_normals);
push_back_xyz(normal, p_normals); push_back_xyz(normal, p_normals);
push_back_xyz(normal, p_normals); push_back_xyz(normal, p_normals);
} };
try {
FacetTriangulator<Face_graph, EPICK, fg_vertex_descriptor> triangulation(fit, normal, poly, offset);
triangulation.per_face(f);
}
catch (...) {
FacetTriangulator<Face_graph, EPICK, fg_vertex_descriptor, CGAL::Exact_intersections_tag> triangulation(fit, normal, poly, offset);
triangulation.per_face(f);
}
} }

View File

@ -984,62 +984,66 @@ Scene_surface_mesh_item_priv::triangulate_facet(face_descriptor fd,
return; return;
} }
typedef FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor> FT;
const CGAL::qglviewer::Vec off = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset(); const CGAL::qglviewer::Vec off = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
EPICK::Vector_3 offset(off.x,off.y,off.z); EPICK::Vector_3 offset(off.x,off.y,off.z);
FT triangulation(fd,normal,smesh_, offset);
//iterates on the internal faces //iterates on the internal faces
for(FT::CDT::Finite_faces_iterator auto f = [&](auto& ffit, auto& v2v) {
ffit = triangulation.cdt->finite_faces_begin(), if (ffit.info().is_external)
end = triangulation.cdt->finite_faces_end(); return;
ffit != end; ++ffit)
{
if(ffit->info().is_external)
continue;
//add the vertices to the positions //add the vertices to the positions
//adds the vertices, normals and colors to the appropriate vectors //adds the vertices, normals and colors to the appropriate vectors
if(!index) if (!index)
{ {
CGAL::IO::Color* color; CGAL::IO::Color* color;
if(has_fpatch_id) if (has_fpatch_id)
{ {
QColor c= item->color_vector()[fpatch_id_map[fd] - min_patch_id]; QColor c = item->color_vector()[fpatch_id_map[fd] - min_patch_id];
color = new CGAL::IO::Color(c.red(),c.green(),c.blue()); color = new CGAL::IO::Color(c.red(), c.green(), c.blue());
} }
else if(has_fcolors) else if (has_fcolors)
color = &(*fcolors)[fd]; color = &(*fcolors)[fd];
else else
color = nullptr; color = nullptr;
addFlatData(ffit->vertex(0)->point()-offset, addFlatData(ffit.vertex(0)->point() - offset,
(*fnormals)[fd], (*fnormals)[fd],
color, color,
name); name);
addFlatData(ffit->vertex(1)->point()-offset, addFlatData(ffit.vertex(1)->point() - offset,
(*fnormals)[fd], (*fnormals)[fd],
color, color,
name); name);
addFlatData(ffit->vertex(2)->point()-offset, addFlatData(ffit.vertex(2)->point() - offset,
(*fnormals)[fd], (*fnormals)[fd],
color, color,
name); name);
if(has_fpatch_id) if (has_fpatch_id)
delete color; delete color;
} }
//adds the indices to the appropriate vector //adds the indices to the appropriate vector
else else
{ {
if(name.testFlag(Scene_item_rendering_helper::GEOMETRY)) if (name.testFlag(Scene_item_rendering_helper::GEOMETRY))
{ {
idx_data_.push_back((*im)[triangulation.v2v[ffit->vertex(0)]]); idx_data_.push_back((*im)[v2v[ffit.vertex(0)]]);
idx_data_.push_back((*im)[triangulation.v2v[ffit->vertex(1)]]); idx_data_.push_back((*im)[v2v[ffit.vertex(1)]]);
idx_data_.push_back((*im)[triangulation.v2v[ffit->vertex(2)]]); idx_data_.push_back((*im)[v2v[ffit.vertex(2)]]);
} }
} }
};
try {
FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor> triangulation(fd, normal, smesh_, offset);
triangulation.per_face(f);
}
catch (...) {
FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor, CGAL::Exact_intersections_tag> triangulation(fd, normal, smesh_, offset);
triangulation.per_face(f);
} }
} }
void delete_aabb_tree(Scene_surface_mesh_item* item) void delete_aabb_tree(Scene_surface_mesh_item* item)
{ {
QVariant aabb_tree_property = item->property(aabb_property_name); QVariant aabb_tree_property = item->property(aabb_property_name);
@ -1356,7 +1360,6 @@ void Scene_surface_mesh_item::invalidate(Gl_data_names name)
QList<EPICK::Triangle_3> Scene_surface_mesh_item_priv::triangulate_primitive(face_descriptor fit, QList<EPICK::Triangle_3> Scene_surface_mesh_item_priv::triangulate_primitive(face_descriptor fit,
EPICK::Vector_3 normal) EPICK::Vector_3 normal)
{ {
typedef FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor> FT;
//The output list //The output list
QList<EPICK::Triangle_3> res; QList<EPICK::Triangle_3> res;
//check if normal contains NaN values //check if normal contains NaN values
@ -1365,23 +1368,27 @@ QList<EPICK::Triangle_3> Scene_surface_mesh_item_priv::triangulate_primitive(fac
qDebug()<<"Warning in triangulation of the selection item: normal contains NaN values and is not valid."; qDebug()<<"Warning in triangulation of the selection item: normal contains NaN values and is not valid.";
return QList<EPICK::Triangle_3>(); return QList<EPICK::Triangle_3>();
} }
FT triangulation(fit,normal,smesh_);
//iterates on the internal faces to add the vertices to the positions //iterates on the internal faces to add the vertices to the positions
//and the normals to the appropriate vectors //and the normals to the appropriate vectors
for( FT::CDT::Finite_faces_iterator auto f = [&](auto &ffit, auto&) {
ffit = triangulation.cdt->finite_faces_begin(), if (ffit.info().is_external)
end = triangulation.cdt->finite_faces_end(); return;
ffit != end; ++ffit)
{
if(ffit->info().is_external)
continue;
res << EPICK::Triangle_3(ffit.vertex(0)->point(),
ffit.vertex(1)->point(),
ffit.vertex(2)->point());
};
res << EPICK::Triangle_3(ffit->vertex(0)->point(), try {
ffit->vertex(1)->point(), FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor> triangulation(fit, normal, smesh_);
ffit->vertex(2)->point()); triangulation.per_face(f);
} }
catch (...) {
FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor, CGAL::Exact_intersections_tag> triangulation(fit, normal, smesh_);
triangulation.per_face(f);
}
return res; return res;
} }
@ -2619,21 +2626,24 @@ void Scene_surface_mesh_item::fill_flat_vertex_map()
return; return;
} }
typedef FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor> FT;
const CGAL::qglviewer::Vec off = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset(); const CGAL::qglviewer::Vec off = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
EPICK::Vector_3 offset(off.x,off.y,off.z); EPICK::Vector_3 offset(off.x,off.y,off.z);
FT triangulation(fd,normal,face_graph(), offset);
//iterates on the internal faces auto f = [&](auto ffit, auto &v2v) {
for(FT::CDT::Finite_faces_iterator if (ffit.info().is_external)
ffit = triangulation.cdt->finite_faces_begin(), return;
end = triangulation.cdt->finite_faces_end(); d->flat_vertices_map[v2v[ffit.vertex(0)]].push_back(counter++);
ffit != end; ++ffit) d->flat_vertices_map[v2v[ffit.vertex(1)]].push_back(counter++);
{ d->flat_vertices_map[v2v[ffit.vertex(2)]].push_back(counter++);
if(ffit->info().is_external) };
continue;
d->flat_vertices_map[triangulation.v2v[ffit->vertex(0)]].push_back(counter++); try {
d->flat_vertices_map[triangulation.v2v[ffit->vertex(1)]].push_back(counter++); FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor> triangulation(fd, normal, face_graph(), offset);
d->flat_vertices_map[triangulation.v2v[ffit->vertex(2)]].push_back(counter++); triangulation.per_face(f);
}
catch (...) {
FacetTriangulator<SMesh, EPICK, boost::graph_traits<SMesh>::vertex_descriptor, CGAL::Exact_intersections_tag> triangulation(fd, normal, face_graph(), offset);
triangulation.per_face(f);
} }
} }
} }

View File

@ -6,6 +6,7 @@
#include <CGAL/Triangulation_vertex_base_with_info_2.h> #include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/Triangulation_face_base_with_info_2.h> #include <CGAL/Triangulation_face_base_with_info_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h> #include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/mark_domain_in_triangulation.h>
#include <CGAL/Projection_traits_3.h> #include <CGAL/Projection_traits_3.h>
@ -22,7 +23,7 @@
// @todo just use PMP::triangulate_face()...? // @todo just use PMP::triangulate_face()...?
// or at least mark_faces_in_domain() // or at least mark_faces_in_domain()
template<class Mesh, typename Kernel, typename Index_type> template<class Mesh, typename Kernel, typename Index_type, typename CDT_ITag = CGAL::Exact_predicates_tag>
class FacetTriangulator class FacetTriangulator
{ {
public: public:
@ -30,6 +31,8 @@ public:
using Point = typename Kernel::Point_3; using Point = typename Kernel::Point_3;
using Vector = typename Kernel::Vector_3; using Vector = typename Kernel::Vector_3;
using Index = Index_type;
using P_traits = CGAL::Projection_traits_3<Traits>; using P_traits = CGAL::Projection_traits_3<Traits>;
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor; using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
@ -45,23 +48,14 @@ public:
using Fbb = CGAL::Triangulation_face_base_with_info_2<Face_info, P_traits>; using Fbb = CGAL::Triangulation_face_base_with_info_2<Face_info, P_traits>;
using Fb = CGAL::Constrained_triangulation_face_base_2<P_traits, Fbb>; using Fb = CGAL::Constrained_triangulation_face_base_2<P_traits, Fbb>;
using TDS = CGAL::Triangulation_data_structure_2<Vb, Fb>; using TDS = CGAL::Triangulation_data_structure_2<Vb, Fb>;
using Itag = CGAL::Exact_predicates_tag; using CDT = CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, CDT_ITag>;
using CDT = CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, Itag>;
using Vertex_handle = typename CDT::Vertex_handle; using Vertex_handle = typename CDT::Vertex_handle;
using Face_handle = typename CDT::Face_handle; using Face_handle = typename CDT::Face_handle;
struct PointAndId
{
Point point;
Index_type id;
PointAndId() = default;
PointAndId(const Point& point, const Index_type id) : point(point), id(id) { }
};
public: public:
CDT* cdt; CDT* cdt;
CGAL::Unique_hash_map<Vertex_handle, Index_type> v2v; CGAL::Unique_hash_map<Vertex_handle, Index> v2v;
public: public:
// Constructor // Constructor
@ -70,10 +64,10 @@ public:
Mesh* poly, Mesh* poly,
Vector offset = Vector(0,0,0)) Vector offset = Vector(0,0,0))
{ {
std::vector<PointAndId> idPoints; std::vector<std::pair<typename Kernel::Point_3, Index> > idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly)) for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
idPoints.emplace_back(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset, idPoints.emplace_back(std::make_pair(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
source(he_circ, *poly)); source(he_circ, *poly)));
if(!triangulate(idPoints, normal)) if(!triangulate(idPoints, normal))
std::cerr << "Facet not displayed" << std::endl; std::cerr << "Facet not displayed" << std::endl;
@ -85,22 +79,22 @@ public:
Mesh* poly, Mesh* poly,
Vector offset = Vector(0,0,0)) Vector offset = Vector(0,0,0))
{ {
std::vector<PointAndId> idPoints; std::vector<std::pair<typename Kernel::Point_3, Index> > idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly)) for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
idPoints.emplace_back(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset, idPoints.emplace_back(std::make_pair(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
source(he_circ, *poly)); source(he_circ, *poly)));
if(!triangulate_with_points(idPoints, more_points, normal)) if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr << "Facet not displayed" << std::endl; std::cerr << "Facet not displayed" << std::endl;
} }
FacetTriangulator(std::vector<PointAndId>& idPoints, FacetTriangulator(std::vector<std::pair<typename Kernel::Point_3, Index> >& idPoints,
const Vector& normal) const Vector& normal)
{ {
if(!triangulate(idPoints, normal)) if(!triangulate(idPoints, normal))
std::cerr << "Facet not displayed" << std::endl; std::cerr << "Facet not displayed" << std::endl;
} }
FacetTriangulator(std::vector<PointAndId>& idPoints, FacetTriangulator(std::vector < std::pair<typename Kernel::Point_3, Index> >& idPoints,
const std::vector<Point>& more_points, const std::vector<Point>& more_points,
const Vector& normal) const Vector& normal)
{ {
@ -114,36 +108,66 @@ public:
delete cdt; delete cdt;
} }
template<class Func>
void per_face(const Func& f) {
for (typename CDT::Finite_faces_iterator fit = cdt->finite_faces_begin(); fit != cdt->finite_faces_end(); ++fit)
f(*fit, v2v);
}
private: private:
bool triangulate(std::vector<PointAndId>& idPoints, bool triangulate(std::vector<std::pair<typename Kernel::Point_3, Index> >& idPoints,
const Vector& normal) const Vector& normal)
{ {
P_traits cdt_traits(normal); P_traits cdt_traits(normal);
cdt = new CDT(cdt_traits); cdt = new CDT(cdt_traits);
std::map<std::pair<Point, Point>, std::size_t> edge_map;
std::vector<bool> skip(idPoints.size(), false);
for (std::size_t i = 0; i < idPoints.size(); i++) {
std::size_t prev = (i - 1 + idPoints.size()) % idPoints.size();
if (idPoints[i].first < idPoints[prev].first) {
auto it = edge_map.emplace(std::make_pair(idPoints[i].first, idPoints[prev].first), i);
if (!it.second) {
skip[i] = true;
skip[it.first->second] = true;
}
}
else {
auto it = edge_map.emplace(std::make_pair(idPoints[prev].first, idPoints[i].first), i);
if (!it.second) {
skip[i] = true;
skip[it.first->second] = true;
}
}
}
Vertex_handle previous, first, last_inserted; Vertex_handle previous, first, last_inserted;
// Iterate the points of the facet and decide if they must be inserted in the CDT // Iterate the points of the facet and decide if they must be inserted in the CDT
typename Kernel::FT x(0), y(0), z(0); typename Kernel::FT x(0), y(0), z(0);
for(const PointAndId& idPoint : idPoints) for(std::size_t i = 0;i<idPoints.size();i++)
{ {
x += idPoint.point.x(); const std::pair<typename Kernel::Point_3, Index>& idPoint = idPoints[i];
y += idPoint.point.y(); x += idPoint.first.x();
z += idPoint.point.z(); y += idPoint.first.y();
z += idPoint.first.z();
Vertex_handle vh; Vertex_handle vh;
// Always insert the first point, then only insert if the distance with the previous is reasonable. // Always insert the first point, then only insert if the distance with the previous is reasonable.
if(first == Vertex_handle() || idPoint.point != previous->point()) if(first == Vertex_handle() || idPoint.first != previous->point())
{ {
vh = cdt->insert(idPoint.point); vh = cdt->insert(idPoint.first);
v2v[vh] = idPoint.id; v2v[vh] = idPoint.second;
if(first == Vertex_handle()) if (first == Vertex_handle()) {
first = vh; first = vh;
}
if(previous != nullptr && previous != vh) if(previous != nullptr && previous != vh)
{ {
cdt->insert_constraint(previous, vh); if (!skip[i])
cdt->insert_constraint(previous, vh);
last_inserted = previous; last_inserted = previous;
} }
previous = vh; previous = vh;
@ -153,57 +177,69 @@ private:
if(last_inserted == Vertex_handle()) if(last_inserted == Vertex_handle())
return false; return false;
if(previous != first) if(previous != first && !skip[0])
cdt->insert_constraint(previous, first); cdt->insert_constraint(previous, first);
// sets mark is_external // sets mark is_external
for(Face_handle f2 : cdt->all_face_handles()) for(Face_handle f2 : cdt->all_face_handles())
f2->info().is_external = false; f2->info().is_external = false;
// check if the facet is external or internal std::unordered_map<Face_handle, bool> in_domain_map;
std::queue<typename CDT::Face_handle> face_queue; boost::associative_property_map< std::unordered_map<Face_handle, bool> > in_domain(in_domain_map);
face_queue.push(cdt->infinite_vertex()->face()); CGAL::mark_domain_in_triangulation<CDT>(*cdt, in_domain);
while(! face_queue.empty())
{
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(fh->info().is_external)
continue;
fh->info().is_external = true; for (const Face_handle& fh : cdt->all_face_handles())
for(int i = 0; i <3; ++i) fh->info().is_external = !get(in_domain, fh);
{
if(!cdt->is_constrained(std::make_pair(fh, i)))
face_queue.push(fh->neighbor(i));
}
}
return true; return true;
} }
bool triangulate_with_points(std::vector<PointAndId >& idPoints, bool triangulate_with_points(std::vector<std::pair<typename Kernel::Point_3, Index> >& idPoints,
const std::vector<Point>& more_points, const std::vector<Point>& more_points,
const Vector& normal) const Vector& normal)
{ {
P_traits cdt_traits(normal); P_traits cdt_traits(normal);
cdt = new CDT(cdt_traits); cdt = new CDT(cdt_traits);
std::map<std::pair<Point, Point>, std::size_t> edge_map;
std::vector<bool> skip(idPoints.size(), false);
for (std::size_t i = 0; i < idPoints.size(); i++) {
std::size_t prev = (i - 1 + idPoints.size()) % idPoints.size();
if (idPoints[i].first < idPoints[prev].first) {
auto it = edge_map.emplace(std::make_pair(idPoints[i].first, idPoints[prev].first), i);
if (!it.second) {
skip[i] = true;
skip[it.first->second] = true;
}
}
else {
auto it = edge_map.emplace(std::make_pair(idPoints[prev].first, idPoints[i].first), i);
if (!it.second) {
skip[i] = true;
skip[it.first->second] = true;
}
}
}
// Iterate the points of the facet and decide if they must be inserted in the CDT // Iterate the points of the facet and decide if they must be inserted in the CDT
Vertex_handle previous, first, last_inserted; Vertex_handle previous, first, last_inserted;
for(const PointAndId& idPoint : idPoints) for (std::size_t i = 0; i < idPoints.size(); i++)
{ {
const std::pair<typename Kernel::Point_3, Index>& idPoint = idPoints[i];
Vertex_handle vh; Vertex_handle vh;
// Always insert the first point, then only insert if the distance with the previous is reasonable. // Always insert the first point, then only insert if the distance with the previous is reasonable.
if(first == Vertex_handle() || idPoint.point != previous->point()) if(first == Vertex_handle() || idPoint.first != previous->point())
{ {
vh = cdt->insert(idPoint.point); vh = cdt->insert(idPoint.first);
v2v[vh] = idPoint.id; v2v[vh] = idPoint.second;
if(first == Vertex_handle()) if(first == Vertex_handle())
first = vh; first = vh;
if(previous != nullptr && previous != vh) if(previous != nullptr && previous != vh)
{ {
cdt->insert_constraint(previous, vh); if (!skip[i])
cdt->insert_constraint(previous, vh);
last_inserted = previous; last_inserted = previous;
} }
previous = vh; previous = vh;
@ -213,7 +249,9 @@ private:
if(last_inserted == Vertex_handle()) if(last_inserted == Vertex_handle())
return false; return false;
if (previous != first && !skip[0])
cdt->insert_constraint(previous, first); cdt->insert_constraint(previous, first);
for(const Point& point : more_points) for(const Point& point : more_points)
cdt->insert(point); cdt->insert(point);
@ -221,22 +259,12 @@ private:
for(Face_handle f2 : cdt->all_face_handles()) for(Face_handle f2 : cdt->all_face_handles())
f2->info().is_external = false; f2->info().is_external = false;
// check if the facet is external or internal std::unordered_map<Face_handle, bool> in_domain_map;
std::queue<typename CDT::Face_handle> face_queue; boost::associative_property_map< std::unordered_map<Face_handle, bool> > in_domain(in_domain_map);
face_queue.push(cdt->infinite_vertex()->face()); CGAL::mark_domain_in_triangulation<CDT>(*cdt, in_domain);
while(!face_queue.empty())
{ for (const Face_handle& fh : cdt->all_face_handles())
typename CDT::Face_handle fh = face_queue.front(); fh->info().is_external = !get(in_domain, fh);
face_queue.pop();
if(fh->info().is_external)
continue;
fh->info().is_external = true;
for(int i = 0; i <3; ++i)
{
if(!cdt->is_constrained(std::make_pair(fh, i)))
face_queue.push(fh->neighbor(i));
}
}
return true; return true;
} }