mirror of https://github.com/CGAL/cgal
Merge pull request #5583 from sloriot/PMP-face_epsilon_map
Polyhedral_envelope: face epsilon map
This commit is contained in:
commit
fa4a31a87b
|
|
@ -121,6 +121,7 @@ CGAL_add_named_parameter(do_not_modify_t, do_not_modify, do_not_modify)
|
|||
CGAL_add_named_parameter(allow_self_intersections_t, allow_self_intersections, allow_self_intersections)
|
||||
CGAL_add_named_parameter(non_manifold_feature_map_t, non_manifold_feature_map, non_manifold_feature_map)
|
||||
CGAL_add_named_parameter(polyhedral_envelope_epsilon_t, polyhedral_envelope_epsilon, polyhedral_envelope_epsilon)
|
||||
CGAL_add_named_parameter(face_epsilon_map_t, face_epsilon_map, face_epsilon_map)
|
||||
|
||||
// List of named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ void test(const NamedParameters& np)
|
|||
assert(get_parameter(np, CGAL::internal_np::maximum_number_of_faces).v == 78910);
|
||||
assert(get_parameter(np, CGAL::internal_np::non_manifold_feature_map).v == 60);
|
||||
assert(get_parameter(np, CGAL::internal_np::filter).v == 61);
|
||||
assert(get_parameter(np, CGAL::internal_np::face_epsilon_map).v == 62);
|
||||
|
||||
// Named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
assert(get_parameter(np, CGAL::internal_np::get_cost_policy).v == 34);
|
||||
|
|
@ -225,6 +226,7 @@ void test(const NamedParameters& np)
|
|||
check_same_type<78910>(get_parameter(np, CGAL::internal_np::maximum_number_of_faces));
|
||||
check_same_type<60>(get_parameter(np, CGAL::internal_np::non_manifold_feature_map));
|
||||
check_same_type<61>(get_parameter(np, CGAL::internal_np::filter));
|
||||
check_same_type<62>(get_parameter(np, CGAL::internal_np::face_epsilon_map));
|
||||
|
||||
// Named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
check_same_type<34>(get_parameter(np, CGAL::internal_np::get_cost_policy));
|
||||
|
|
@ -353,6 +355,7 @@ int main()
|
|||
.use_compact_clipper(A<45>(45))
|
||||
.non_manifold_feature_map(A<60>(60))
|
||||
.filter(A<61>(61))
|
||||
.face_epsilon_map(A<62>(62))
|
||||
.apply_per_connected_component(A<46>(46))
|
||||
.output_iterator(A<47>(47))
|
||||
.erase_all_duplicates(A<48>(48))
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ private:
|
|||
|
||||
|
||||
// The class `Plane` is used for the 7-8 walls of a prism.
|
||||
// We store at the same time threee points and a plane.
|
||||
// We store at the same time three points and a plane.
|
||||
// That is easier than retrieving the 3 points of a lazy plane.
|
||||
struct Plane {
|
||||
Plane()
|
||||
|
|
@ -351,6 +351,11 @@ public:
|
|||
* \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
|
||||
* must be available in `TriangleMesh`.}
|
||||
* \cgalParamNEnd
|
||||
* \cgalParamNBegin{face_epsilon_map}
|
||||
* \cgalParamDescription{a property map associating to each face of `tm` an epsilon value}
|
||||
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%face_descriptor`
|
||||
* as key type and `double` as value type}
|
||||
* \cgalParamDefault{Use `epsilon` for all faces}
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \note The triangle mesh gets copied internally, that is it can be modifed after having passed as argument,
|
||||
|
|
@ -363,8 +368,10 @@ public:
|
|||
{
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
using parameters::is_default_parameter;
|
||||
|
||||
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
|
||||
typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type
|
||||
vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
|
|
@ -383,7 +390,8 @@ public:
|
|||
}
|
||||
|
||||
GeomTraits gt;
|
||||
for(typename Graph_traits::face_descriptor f : faces(tmesh)){
|
||||
std::unordered_set<face_descriptor> deg_faces;
|
||||
for(face_descriptor f : faces(tmesh)){
|
||||
if(! Polygon_mesh_processing::is_degenerate_triangle_face(f, tmesh, parameters::geom_traits(gt).vertex_point_map(vpm))){
|
||||
typename Graph_traits::halfedge_descriptor h = halfedge(f, tmesh);
|
||||
int i = get(vim, source(h, tmesh));
|
||||
|
|
@ -393,8 +401,30 @@ public:
|
|||
Vector3i face = { i, j, k };
|
||||
env_faces.push_back(face);
|
||||
}
|
||||
else
|
||||
deg_faces.insert(f);
|
||||
}
|
||||
if (is_default_parameter(get_parameter(np, internal_np::face_epsilon_map)))
|
||||
init(epsilon);
|
||||
else
|
||||
{
|
||||
std::vector<double> epsilon_values;
|
||||
epsilon_values.reserve(env_faces.size());
|
||||
|
||||
typedef typename internal_np::Lookup_named_param_def<
|
||||
internal_np::face_epsilon_map_t,
|
||||
NamedParameters,
|
||||
Constant_property_map<face_descriptor, double>
|
||||
> ::type Epsilon_map;
|
||||
|
||||
Epsilon_map epsilon_map = choose_parameter(get_parameter(np, internal_np::face_epsilon_map),
|
||||
Constant_property_map<face_descriptor, double>(epsilon));
|
||||
|
||||
for(face_descriptor f : faces(tmesh))
|
||||
if(deg_faces.count(f)==0)
|
||||
epsilon_values.push_back( get(epsilon_map, f) );
|
||||
init(epsilon_values);
|
||||
}
|
||||
init(epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -420,6 +450,12 @@ public:
|
|||
* \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
|
||||
* must be available in `TriangleMesh`.}
|
||||
* \cgalParamNEnd
|
||||
* \cgalParamNBegin{face_epsilon_map}
|
||||
* \cgalParamDescription{a property map associating to each face of `tm` an epsilon value}
|
||||
* \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<TriangleMesh>::%face_descriptor`
|
||||
* as key type and `double` as value type}
|
||||
* \cgalParamDefault{Use `epsilon` for all faces}
|
||||
* \cgalParamNEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* \note The triangle mesh gets copied internally, that is it can be modifed after having passed as argument,
|
||||
|
|
@ -437,6 +473,7 @@ public:
|
|||
{
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
using parameters::is_default_parameter;
|
||||
|
||||
typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type
|
||||
vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
|
|
@ -461,6 +498,7 @@ public:
|
|||
return insert_res.first->second;
|
||||
};
|
||||
|
||||
std::unordered_set<face_descriptor> deg_faces;
|
||||
for(face_descriptor f : face_range){
|
||||
if(! Polygon_mesh_processing::is_degenerate_triangle_face(f, tmesh, parameters::geom_traits(gt).vertex_point_map(vpm))){
|
||||
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor h = halfedge(f, tmesh);
|
||||
|
|
@ -471,8 +509,31 @@ public:
|
|||
Vector3i face = { i, j, k };
|
||||
env_faces.push_back(face);
|
||||
}
|
||||
else
|
||||
deg_faces.insert(f);
|
||||
}
|
||||
|
||||
if (is_default_parameter(get_parameter(np, internal_np::face_epsilon_map)))
|
||||
init(epsilon);
|
||||
else
|
||||
{
|
||||
std::vector<double> epsilon_values;
|
||||
epsilon_values.reserve(env_faces.size());
|
||||
|
||||
typedef typename internal_np::Lookup_named_param_def<
|
||||
internal_np::face_epsilon_map_t,
|
||||
NamedParameters,
|
||||
Constant_property_map<face_descriptor, double>
|
||||
> ::type Epsilon_map;
|
||||
|
||||
Epsilon_map epsilon_map = choose_parameter(get_parameter(np, internal_np::face_epsilon_map),
|
||||
Constant_property_map<face_descriptor, double>(epsilon));
|
||||
|
||||
for(face_descriptor f : face_range)
|
||||
if(deg_faces.count(f)==0)
|
||||
epsilon_values.push_back( get(epsilon_map, f) );
|
||||
init(epsilon_values);
|
||||
}
|
||||
init(epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -496,6 +557,10 @@ public:
|
|||
* \cgalParamType{a model of `ReadablePropertyMap` whose value type is `Point_3` and whose key
|
||||
* is the value type of `PointRange::const_iterator`}
|
||||
* \cgalParamDefault{`CGAL::Identity_property_map`}
|
||||
* \cgalParamNBegin{face_epsilon_map}
|
||||
* \cgalParamDescription{a property map associating to each triangle an epsilon value}
|
||||
* \cgalParamType{a class model of `ReadablePropertyMap` with `std::size_t` as key type and `double` as value type}
|
||||
* \cgalParamDefault{Use `epsilon` for all triangles}
|
||||
* \cgalParamNEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
|
|
@ -512,6 +577,7 @@ public:
|
|||
{
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
using parameters::is_default_parameter;
|
||||
|
||||
typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::const_type Point_map;
|
||||
Point_map pm = choose_parameter<Point_map>(get_parameter(np, internal_np::point_map));
|
||||
|
|
@ -529,7 +595,27 @@ public:
|
|||
Vector3i face = { int(t[0]), int(t[1]), int(t[2]) };
|
||||
env_faces.emplace_back(face);
|
||||
}
|
||||
init(epsilon);
|
||||
|
||||
if (is_default_parameter(get_parameter(np, internal_np::face_epsilon_map)))
|
||||
init(epsilon);
|
||||
else
|
||||
{
|
||||
std::vector<double> epsilon_values;
|
||||
epsilon_values.reserve(env_faces.size());
|
||||
|
||||
typedef typename internal_np::Lookup_named_param_def<
|
||||
internal_np::face_epsilon_map_t,
|
||||
NamedParameters,
|
||||
Constant_property_map<std::size_t, double>
|
||||
> ::type Epsilon_map;
|
||||
|
||||
Epsilon_map epsilon_map = choose_parameter(get_parameter(np, internal_np::face_epsilon_map),
|
||||
Constant_property_map<std::size_t, double>(epsilon));
|
||||
|
||||
for(std::size_t i=0; i<triangles.size(); ++i)
|
||||
epsilon_values.push_back( get(epsilon_map, i) );
|
||||
init(epsilon_values);
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
|
@ -560,9 +646,10 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void init(double epsilon)
|
||||
template <class Epsilons>
|
||||
void init(const Epsilons& epsilon_values)
|
||||
{
|
||||
halfspace_generation(env_vertices, env_faces, halfspace, bounding_boxes, epsilon);
|
||||
halfspace_generation(env_vertices, env_faces, halfspace, bounding_boxes, epsilon_values);
|
||||
|
||||
Datum_map<GeomTraits> datum_map(bounding_boxes);
|
||||
Point_map<GeomTraits> point_map(bounding_boxes);
|
||||
|
|
@ -1836,15 +1923,23 @@ private:
|
|||
return Plane(plane0, plane1,plane2);
|
||||
}
|
||||
|
||||
double get_epsilon(double epsilon, std::size_t)
|
||||
{
|
||||
return epsilon;
|
||||
}
|
||||
|
||||
double get_epsilon(const std::vector<double>& epsilon_values, std::size_t i)
|
||||
{
|
||||
return epsilon_values[i];
|
||||
}
|
||||
|
||||
// build prisms for a list of triangles. each prism is represented by 7-8 planes, which are represented by 3 points
|
||||
template <class Epsilons>
|
||||
void
|
||||
halfspace_generation(const std::vector<Point_3> &ver, const std::vector<Vector3i> &faces,
|
||||
std::vector<Prism>& halfspace,
|
||||
std::vector<Iso_cuboid_3>& bounding_boxes, const double epsilon)
|
||||
std::vector<Iso_cuboid_3>& bounding_boxes, const Epsilons& epsilon_values)
|
||||
{
|
||||
double tolerance = epsilon / std::sqrt(3);// the envelope thickness, to be conservative
|
||||
double bbox_tolerance = epsilon *(1 + 1e-6);
|
||||
Vector_3 AB, AC, BC, normal;
|
||||
Plane plane;
|
||||
std::array<Vector_3, 8> box;
|
||||
|
|
@ -1870,6 +1965,10 @@ private:
|
|||
bounding_boxes.resize(faces.size());
|
||||
for (unsigned int i = 0; i < faces.size(); ++i)
|
||||
{
|
||||
const double epsilon = get_epsilon(epsilon_values,i);
|
||||
double tolerance = epsilon / std::sqrt(3);// the envelope thickness, to be conservative
|
||||
double bbox_tolerance = epsilon *(1 + 1e-6);
|
||||
|
||||
Bbox bb = ver[faces[i][0]].bbox () + ver[faces[i][1]].bbox() + ver[faces[i][2]].bbox();
|
||||
// todo: Add a grow() function to Bbox
|
||||
bounding_boxes[i] = Iso_cuboid_3(Point_3(bb.xmin()-bbox_tolerance, bb.ymin()-bbox_tolerance, bb.zmin()-bbox_tolerance),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ void test_API()
|
|||
CGAL::Polyhedron_3<EPIC> poly;
|
||||
PMP::polygon_soup_to_polygon_mesh(points, triangles, sm);
|
||||
PMP::polygon_soup_to_polygon_mesh(points, triangles, poly);
|
||||
auto epsilon_map = sm.add_property_map<CGAL::Surface_mesh<EPIC::Point_3>::Face_index, double>("f:em", 0.0001).first;
|
||||
|
||||
// build from the same kernel
|
||||
{
|
||||
|
|
@ -32,12 +33,23 @@ void test_API()
|
|||
assert(envelope(sm));
|
||||
assert(envelope(poly));
|
||||
assert(envelope(points, triangles));
|
||||
envelope = CGAL::Polyhedral_envelope<EPIC>(sm,0, CGAL::parameters::face_epsilon_map(epsilon_map));
|
||||
assert(!envelope.is_empty());
|
||||
assert(envelope(sm));
|
||||
assert(envelope(poly));
|
||||
assert(envelope(points, triangles));
|
||||
|
||||
envelope=CGAL::Polyhedral_envelope<EPIC>(points,triangles,0.0001);
|
||||
assert(!envelope.is_empty());
|
||||
assert(envelope(sm));
|
||||
assert(envelope(poly));
|
||||
assert(envelope(points, triangles));
|
||||
std::vector<double> eps(triangles.size(), 0.0001);
|
||||
envelope=CGAL::Polyhedral_envelope<EPIC>(points,triangles,0,CGAL::parameters::face_epsilon_map(CGAL::make_property_map(eps)));
|
||||
assert(!envelope.is_empty());
|
||||
assert(envelope(sm));
|
||||
assert(envelope(poly));
|
||||
assert(envelope(points, triangles));
|
||||
|
||||
std::vector<decltype(sm)::Face_index> subfaces(faces(sm).begin(), std::next(faces(sm).begin(), 150));
|
||||
envelope=CGAL::Polyhedral_envelope<EPIC>(subfaces,sm,0.0001);
|
||||
|
|
@ -45,6 +57,11 @@ void test_API()
|
|||
assert(!envelope(sm));
|
||||
assert(!envelope(poly));
|
||||
assert(!envelope(points, triangles));
|
||||
envelope=CGAL::Polyhedral_envelope<EPIC>(subfaces,sm,0, CGAL::parameters::face_epsilon_map(epsilon_map));
|
||||
assert(!envelope.is_empty());
|
||||
assert(!envelope(sm));
|
||||
assert(!envelope(poly));
|
||||
assert(!envelope(points, triangles));
|
||||
}
|
||||
|
||||
// build from different kernels
|
||||
|
|
|
|||
Loading…
Reference in New Issue