mirror of https://github.com/CGAL/cgal
279 lines
8.9 KiB
C++
279 lines
8.9 KiB
C++
#ifndef CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
|
|
#define CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
|
|
|
|
#include <CGAL/Three/Scene_item.h>
|
|
|
|
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
|
#include <CGAL/Triangulation_face_base_with_info_2.h>
|
|
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
|
#include <CGAL/mark_domain_in_triangulation.h>
|
|
|
|
#include <CGAL/Projection_traits_3.h>
|
|
|
|
#include <QColor>
|
|
|
|
#include <CGAL/boost/graph/properties.h>
|
|
#include <boost/graph/graph_traits.hpp>
|
|
|
|
#include <iostream>
|
|
#include <queue>
|
|
#include <vector>
|
|
|
|
// Ensure that all the facets are triangles
|
|
// @todo just use PMP::triangulate_face()...?
|
|
// or at least mark_faces_in_domain()
|
|
|
|
template<class Mesh, typename Kernel, typename Index_type, typename CDT_ITag = CGAL::Exact_predicates_tag>
|
|
class FacetTriangulator
|
|
{
|
|
public:
|
|
using Traits = Kernel;
|
|
using Point = typename Kernel::Point_3;
|
|
using Vector = typename Kernel::Vector_3;
|
|
|
|
using Index = Index_type;
|
|
|
|
using P_traits = CGAL::Projection_traits_3<Traits>;
|
|
|
|
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
|
|
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
|
|
|
|
struct Face_info
|
|
{
|
|
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
|
|
bool is_external;
|
|
};
|
|
|
|
using Vb = CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor, 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 TDS = CGAL::Triangulation_data_structure_2<Vb, Fb>;
|
|
using CDT = CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, CDT_ITag>;
|
|
|
|
using Vertex_handle = typename CDT::Vertex_handle;
|
|
using Face_handle = typename CDT::Face_handle;
|
|
|
|
public:
|
|
CDT* cdt;
|
|
CGAL::Unique_hash_map<Vertex_handle, Index> v2v;
|
|
|
|
public:
|
|
// Constructor
|
|
FacetTriangulator(face_descriptor fd,
|
|
const Vector& normal,
|
|
Mesh* poly,
|
|
Vector offset = Vector(0,0,0))
|
|
{
|
|
std::vector<std::pair<typename Kernel::Point_3, Index> > idPoints;
|
|
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
|
|
idPoints.emplace_back(std::make_pair(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
|
|
source(he_circ, *poly)));
|
|
|
|
if(!triangulate(idPoints, normal))
|
|
std::cerr << "Facet not displayed" << std::endl;
|
|
}
|
|
|
|
FacetTriangulator(face_descriptor fd,
|
|
const std::vector<Point>& more_points,
|
|
const Vector& normal,
|
|
Mesh* poly,
|
|
Vector offset = Vector(0,0,0))
|
|
{
|
|
std::vector<std::pair<typename Kernel::Point_3, Index> > idPoints;
|
|
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
|
|
idPoints.emplace_back(std::make_pair(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
|
|
source(he_circ, *poly)));
|
|
|
|
if(!triangulate_with_points(idPoints, more_points, normal))
|
|
std::cerr << "Facet not displayed" << std::endl;
|
|
}
|
|
|
|
FacetTriangulator(std::vector<std::pair<typename Kernel::Point_3, Index> >& idPoints,
|
|
const Vector& normal)
|
|
{
|
|
if(!triangulate(idPoints, normal))
|
|
std::cerr << "Facet not displayed" << std::endl;
|
|
}
|
|
FacetTriangulator(std::vector < std::pair<typename Kernel::Point_3, Index> >& idPoints,
|
|
const std::vector<Point>& more_points,
|
|
const Vector& normal)
|
|
{
|
|
if(!triangulate_with_points(idPoints, more_points, normal))
|
|
std::cerr << "Facet not displayed" << std::endl;
|
|
}
|
|
|
|
~FacetTriangulator()
|
|
{
|
|
if(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:
|
|
bool triangulate(std::vector<std::pair<typename Kernel::Point_3, Index> >& idPoints,
|
|
const Vector& normal)
|
|
{
|
|
P_traits cdt_traits(normal);
|
|
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;
|
|
|
|
// 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);
|
|
|
|
for(std::size_t i = 0;i<idPoints.size();i++)
|
|
{
|
|
const std::pair<typename Kernel::Point_3, Index>& idPoint = idPoints[i];
|
|
x += idPoint.first.x();
|
|
y += idPoint.first.y();
|
|
z += idPoint.first.z();
|
|
|
|
Vertex_handle vh;
|
|
// Always insert the first point, then only insert if the distance with the previous is reasonable.
|
|
if(first == Vertex_handle() || idPoint.first != previous->point())
|
|
{
|
|
vh = cdt->insert(idPoint.first);
|
|
v2v[vh] = idPoint.second;
|
|
if (first == Vertex_handle()) {
|
|
first = vh;
|
|
}
|
|
|
|
if(previous != nullptr && previous != vh)
|
|
{
|
|
if (!skip[i])
|
|
cdt->insert_constraint(previous, vh);
|
|
last_inserted = previous;
|
|
}
|
|
previous = vh;
|
|
}
|
|
}
|
|
|
|
if(last_inserted == Vertex_handle())
|
|
return false;
|
|
|
|
if(previous != first && !skip[0])
|
|
cdt->insert_constraint(previous, first);
|
|
|
|
// ignore degenerate polygons
|
|
if (cdt->dimension() != 2)
|
|
return true;
|
|
|
|
// sets mark is_external
|
|
for(Face_handle f2 : cdt->all_face_handles())
|
|
f2->info().is_external = false;
|
|
|
|
std::unordered_map<Face_handle, bool> in_domain_map;
|
|
boost::associative_property_map< std::unordered_map<Face_handle, bool> > in_domain(in_domain_map);
|
|
CGAL::mark_domain_in_triangulation<CDT>(*cdt, in_domain);
|
|
|
|
for (const Face_handle& fh : cdt->all_face_handles())
|
|
fh->info().is_external = !get(in_domain, fh);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool triangulate_with_points(std::vector<std::pair<typename Kernel::Point_3, Index> >& idPoints,
|
|
const std::vector<Point>& more_points,
|
|
const Vector& normal)
|
|
{
|
|
P_traits cdt_traits(normal);
|
|
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
|
|
Vertex_handle previous, first, last_inserted;
|
|
for (std::size_t i = 0; i < idPoints.size(); i++)
|
|
{
|
|
const std::pair<typename Kernel::Point_3, Index>& idPoint = idPoints[i];
|
|
Vertex_handle vh;
|
|
// Always insert the first point, then only insert if the distance with the previous is reasonable.
|
|
if(first == Vertex_handle() || idPoint.first != previous->point())
|
|
{
|
|
vh = cdt->insert(idPoint.first);
|
|
v2v[vh] = idPoint.second;
|
|
if(first == Vertex_handle())
|
|
first = vh;
|
|
|
|
if(previous != nullptr && previous != vh)
|
|
{
|
|
if (!skip[i])
|
|
cdt->insert_constraint(previous, vh);
|
|
last_inserted = previous;
|
|
}
|
|
previous = vh;
|
|
}
|
|
}
|
|
|
|
if(last_inserted == Vertex_handle())
|
|
return false;
|
|
|
|
if (previous != first && !skip[0])
|
|
cdt->insert_constraint(previous, first);
|
|
|
|
for(const Point& point : more_points)
|
|
cdt->insert(point);
|
|
|
|
// sets mark is_external
|
|
for(Face_handle f2 : cdt->all_face_handles())
|
|
f2->info().is_external = false;
|
|
|
|
std::unordered_map<Face_handle, bool> in_domain_map;
|
|
boost::associative_property_map< std::unordered_map<Face_handle, bool> > in_domain(in_domain_map);
|
|
CGAL::mark_domain_in_triangulation<CDT>(*cdt, in_domain);
|
|
|
|
for (const Face_handle& fh : cdt->all_face_handles())
|
|
fh->info().is_external = !get(in_domain, fh);
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
#endif // CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
|
|
|