Merge remote-tracking branch 'cgal/master' into Polyhedron-demo__add_qtscript_support_to_Mesh_3_plugin-GF

This commit is contained in:
Laurent Rineau 2020-01-17 11:38:22 +01:00
commit f17d903d75
244 changed files with 63533 additions and 939 deletions

View File

@ -1,6 +1,6 @@
name: CMake all CGAL
on: [push]
on: [push, pull_request]
jobs:
build:
@ -8,9 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 0
- uses: actions/checkout@v2.0.0
- name: install dependencies
run: sudo apt-get install -y libboost-dev libboost-program-options-dev libmpfr-dev libeigen3-dev
- name: configure all

View File

@ -47,11 +47,11 @@ env:
- PACKAGE='Stream_support Subdivision_method_3 Surface_mesh '
- PACKAGE='Surface_mesh_approximation Surface_mesh_deformation Surface_mesh_parameterization '
- PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification '
- PACKAGE='Surface_mesh_skeletonization Surface_mesher Surface_sweep_2 '
- PACKAGE='TDS_2 TDS_3 Testsuite '
- PACKAGE='Three Triangulation Triangulation_2 '
- PACKAGE='Triangulation_3 Union_find Visibility_2 '
- PACKAGE='Voronoi_diagram_2 wininst '
- PACKAGE='Surface_mesh_skeletonization Surface_mesh_topology Surface_mesher '
- PACKAGE='Surface_sweep_2 TDS_2 TDS_3 '
- PACKAGE='Testsuite Three Triangulation '
- PACKAGE='Triangulation_2 Triangulation_3 Union_find '
- PACKAGE='Visibility_2 Voronoi_diagram_2 wininst '
compiler: clang
install:
- echo "$PWD"

View File

@ -122,6 +122,7 @@ Surface_mesh_segmentation
Surface_mesh_shortest_path
Surface_mesh_simplification
Surface_mesh_skeletonization
Surface_mesh_topology
Surface_mesher
Surface_sweep_2
TDS_2

View File

@ -75,7 +75,7 @@ using Intersection_and_primitive_id = unspecified_type;
/// \name Splitting
/// During the construction of the AABB tree, the primitives are
/// splitted according to some comparison functions related to the longest axis:
/// split according to some comparison functions related to the longest axis:
/// @{
/*!

View File

@ -83,6 +83,10 @@ public:
this->p2 = p2;
}
int compute_k(const FT tt) const {
return int(CGAL::to_double(CGAL::sqrt(tt / this->STEP)));
}
void generate_points(std::vector<Point_2>& p) const
{
if ( CGAL::is_zero(this->r) ) {
@ -91,76 +95,70 @@ public:
return;
}
// FT STEP = W.width() / 100.0;
FT s0, s1;
s0 = t(p1);
s1 = t(p2);
if (CGAL::compare(s0, s1) == LARGER) {
if (CGAL::compare(s0, s1) == LARGER)
std::swap(s0, s1);
}
p.clear();
if ( !(CGAL::is_positive(s0)) &&
!(CGAL::is_negative(s1)) ) {
FT tt;
int k;
if ( !(CGAL::is_positive(s0)) && !(CGAL::is_negative(s1)) )
{
FT tt = FT(-this->STEP);
int k = -1;
p.push_back( this->o );
k = 1;
tt = FT(-this->STEP);
while ( CGAL::compare(tt, s0) == LARGER ) {
while ( CGAL::compare(tt, s0) == LARGER )
{
p.insert( p.begin(), f(tt) );
k--;
--k;
tt = - FT(k * k) * this->STEP;
}
p.insert( p.begin(), f(s0) );
k = 1;
tt = FT(this->STEP);
while ( CGAL::compare(tt, s1) == SMALLER ) {
while ( CGAL::compare(tt, s1) == SMALLER )
{
p.push_back( f(tt) );
k++;
++k;
tt = FT(k * k) * this->STEP;
}
p.push_back( f(s1) );
} else if ( !(CGAL::is_negative(s0)) &&
!(CGAL::is_negative(s1)) ) {
FT tt;
int k;
}
else if ( !(CGAL::is_negative(s0)) && !(CGAL::is_negative(s1)) )
{
FT tt = s0;
int k = - compute_k(-tt);
p.push_back( f(s0) );
tt = s0;
k = int(CGAL::to_double(CGAL::sqrt(tt / this->STEP)));
while ( CGAL::compare(tt, s1) == SMALLER ) {
if ( CGAL::compare(tt, s0) != SMALLER )
do
{
p.push_back( f(tt) );
k++;
++k;
tt = FT(k * k) * this->STEP;
}
p.push_back( f(s1) );
} else {
FT tt;
int k;
while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER );
p.push_back( f(s1) );
}
else
{
FT tt = s1;
int k = compute_k(tt);
tt = s1;
k = int(CGAL::to_double(-CGAL::sqrt(-tt / this->STEP)));
while ( CGAL::compare(tt, s0) == LARGER ) {
if ( CGAL::compare(tt, s1) != LARGER )
do
{
p.push_back( f(tt) );
k--;
--k;
tt = - FT(k * k) * this->STEP;
}
while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER );
p.push_back( f(s0) );
}
}

View File

@ -62,85 +62,101 @@ public:
this->p2 = p2;
}
int compute_k(const FT& tt) const {
return int(CGAL::sqrt(CGAL::to_double(tt) / 2));
int compute_k(const FT tt, const FT STEP) const {
return int(CGAL::to_double(CGAL::sqrt(tt / STEP)));
}
// s0 and s1 define a desired drawing "range"
void generate_points(std::vector<Point_2>& p,
const FT STEP = FT(2)) const
const FT STEP,
FT s0, FT s1) const
{
FT s0, s1;
s0 = t(p1);
s1 = t(p2);
if (CGAL::compare(s0, s1) == LARGER) {
std::swap(s0, s1);
}
CGAL_precondition(STEP > 0);
CGAL_precondition(s0 < s1);
p.clear();
if ( !(CGAL::is_positive(s0)) &&
!(CGAL::is_negative(s1)) ) {
FT tt;
int k;
if (CGAL::compare(s0, s1) == LARGER)
std::swap(s0, s1);
// This is a parabola segment that exists between only between p1 and p2 so we gotta crop
// the desired range to actually fit the parabola segment
FT tp1 = t(p1), tp2 = t(p2);
if (CGAL::compare(tp1, tp2) == LARGER)
std::swap(tp1, tp2);
if(tp2 < s0 || s1 < tp1) // nothing to draw because the ranges are completely disjoint
return;
s0 = (std::max)(s0, tp1);
s1 = (std::min)(s1, tp2);
if ( !(CGAL::is_positive(s0)) && !(CGAL::is_negative(s1)) )
{
FT tt = - STEP;
int k = -1;
p.push_back( this->o );
k = -1;
tt = - STEP;
while ( CGAL::compare(tt, s0) == LARGER ) {
// no need to check tt < s1 since we have tt < 0, s1 >= 0 and tt is moving towards -inf
while ( CGAL::compare(tt, s0) == LARGER )
{
p.insert( p.begin(), f(tt) );
k--;
--k;
tt = - FT(k * k) * STEP;
}
p.insert( p.begin(), f(s0) );
k = 1;
tt = STEP;
while ( CGAL::compare(tt, s1) == SMALLER ) {
// no need to check tt > s0 since we have tt > 0, s0 <= 0 and tt is moving towards +inf
while ( CGAL::compare(tt, s1) == SMALLER )
{
p.push_back( f(tt) );
k++;
++k;
tt = FT(k * k) * STEP;
}
p.push_back( f(s1) );
} else if ( !(CGAL::is_negative(s0)) &&
!(CGAL::is_negative(s1)) ) {
FT tt;
int k;
}
else if ( !(CGAL::is_negative(s0)) && !(CGAL::is_negative(s1)) )
{
FT tt = s0;
int k = compute_k(tt, STEP);
p.push_back( f(s0) );
tt = s0;
k = compute_k(tt);
while ( CGAL::compare(tt, s1) == SMALLER ) {
if ( CGAL::compare(tt, s0) != SMALLER )
do
{
p.push_back( f(tt) );
k++;
++k;
tt = FT(k * k) * STEP;
}
p.push_back( f(s1) );
} else {
FT tt;
int k;
while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER );
p.push_back( f(s1) );
}
else
{
FT tt = s1;
int k = - compute_k(-tt, STEP);
tt = s1;
k = -compute_k(-tt);
while ( CGAL::compare(tt, s0) == LARGER ) {
if ( CGAL::compare(tt, s1) != LARGER )
do
{
p.push_back( f(tt) );
k--;
--k;
tt = - FT(k * k) * STEP;
}
while ( CGAL::compare(tt, s0) == LARGER && CGAL::compare(tt, s1) == SMALLER );
p.push_back( f(s0) );
}
}
void generate_points(std::vector<Point_2>& p,
const FT STEP = FT(2)) const
{
return generate_points(p, STEP, t(p1), t(p2));
}
template< class Stream >
void draw(Stream& W) const

View File

@ -112,7 +112,8 @@ namespace CGAL {
typedef typename boost::property_traits<PMap>::value_type type;
};
template<typename PolygonMesh, typename NamedParameters>
template<typename PolygonMesh,
typename NamedParameters = Named_function_parameters<bool, internal_np::all_default_t> >
class GetVertexPointMap
{
typedef typename property_map_selector<PolygonMesh, boost::vertex_point_t>::const_type

View File

@ -82,6 +82,9 @@ CGAL_add_named_parameter(use_angle_smoothing_t, use_angle_smoothing, use_angle_s
CGAL_add_named_parameter(use_area_smoothing_t, use_area_smoothing, use_area_smoothing)
CGAL_add_named_parameter(use_Delaunay_flips_t, use_Delaunay_flips, use_Delaunay_flips)
CGAL_add_named_parameter(do_project_t, do_project, do_project)
CGAL_add_named_parameter(area_threshold_t, area_threshold, area_threshold)
CGAL_add_named_parameter(volume_threshold_t, volume_threshold, volume_threshold)
CGAL_add_named_parameter(dry_run_t, dry_run, dry_run)
// 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)

View File

@ -578,7 +578,7 @@ void expand_face_selection_for_removal(const FaceRange& faces_to_be_deleted,
next_around_vertex = opposite( next(hd, tm), tm);
if (hd==start) break;
}
if ( get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed
if ( is_border(next_around_vertex,tm) || get(is_selected, face(next_around_vertex, tm) ) ) continue; //all incident faces will be removed
while( true )
{
@ -600,7 +600,7 @@ void expand_face_selection_for_removal(const FaceRange& faces_to_be_deleted,
break;
next_around_vertex = opposite( next(next_around_vertex, tm), tm);
}
while( get(is_selected, face(next_around_vertex, tm) ) );
while(is_border(next_around_vertex,tm) || get(is_selected, face(next_around_vertex, tm) ) );
if (next_around_vertex==start)
break;

View File

@ -91,6 +91,9 @@ void test(const NamedParameters& np)
assert(get_parameter(np, CGAL::internal_np::use_area_smoothing).v == 54);
assert(get_parameter(np, CGAL::internal_np::use_Delaunay_flips).v == 55);
assert(get_parameter(np, CGAL::internal_np::use_safety_constraints).v == 56);
assert(get_parameter(np, CGAL::internal_np::area_threshold).v == 57);
assert(get_parameter(np, CGAL::internal_np::volume_threshold).v == 58);
assert(get_parameter(np, CGAL::internal_np::dry_run).v == 59);
// Named parameters that we use in the package 'Surface Mesh Simplification'
assert(get_parameter(np, CGAL::internal_np::get_cost_policy).v == 34);
@ -175,6 +178,9 @@ void test(const NamedParameters& np)
check_same_type<54>(get_parameter(np, CGAL::internal_np::use_area_smoothing));
check_same_type<55>(get_parameter(np, CGAL::internal_np::use_Delaunay_flips));
check_same_type<56>(get_parameter(np, CGAL::internal_np::use_safety_constraints));
check_same_type<57>(get_parameter(np, CGAL::internal_np::area_threshold));
check_same_type<58>(get_parameter(np, CGAL::internal_np::volume_threshold));
check_same_type<59>(get_parameter(np, CGAL::internal_np::dry_run));
// Named parameters that we use in the package 'Surface Mesh Simplification'
check_same_type<34>(get_parameter(np, CGAL::internal_np::get_cost_policy));
@ -265,6 +271,9 @@ int main()
.use_area_smoothing(A<54>(54))
.use_Delaunay_flips(A<55>(55))
.use_safety_constraints(A<56>(56))
.area_threshold(A<57>(57))
.volume_threshold(A<58>(58))
.dry_run(A<59>(59))
);
return EXIT_SUCCESS;

View File

@ -41,6 +41,9 @@
#include <deque>
#include <boost/type_traits/is_same.hpp>
#include <boost/unordered_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/config.h>
#if defined( __INTEL_COMPILER )
@ -55,6 +58,16 @@ _Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
#endif
namespace CGAL {
// functions to allow the call to next/opposite by ADL
template <typename G, typename Desc>
auto CM_ADL_next(Desc&& d, G&& g) {
return next(std::forward<Desc>(d), std::forward<G>(g));
}
template <typename G, typename Desc>
auto CM_ADL_opposite(Desc&& d, G&& g) {
return opposite(std::forward<Desc>(d), std::forward<G>(g));
}
/** @file Combinatorial_map.h
* Definition of generic dD Combinatorial map.
@ -199,18 +212,27 @@ namespace CGAL {
CGAL_assertion(number_of_darts()==0);
}
/** Copy the given combinatorial map into *this.
/** Copy the given combinatorial map 'amap' into *this.
* Note that both CMap can have different dimensions and/or non void attributes.
* @param amap the combinatorial map to copy.
* @post *this is valid.
*/
template <typename CMap2, typename Converters, typename DartInfoConverter,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter,
typename PointConverter>
void copy(const CMap2& amap, const Converters& converters,
void copy(const Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter,
boost::unordered_map<typename CMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
boost::unordered_map
<typename Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>::
Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
typedef Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2> CMap2;
this->clear();
this->mnb_used_marks = amap.mnb_used_marks;
@ -232,81 +254,113 @@ namespace CGAL {
// Create an mapping between darts of the two maps (originals->copies).
// (here we cannot use CGAL::Unique_hash_map because it does not provide
// iterators...
boost::unordered_map<typename CMap2::Dart_const_handle, Dart_handle> local_dartmap;
if (dart_mapping==nullptr)
{ dart_mapping=&local_dartmap; }
boost::unordered_map<typename CMap2::Dart_const_handle, Dart_handle>
local_dartmap;
if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map
{ origin_to_copy=&local_dartmap; }
Dart_handle new_dart;
for (typename CMap2::Dart_const_range::const_iterator
it=amap.darts().begin(), itend=amap.darts().end();
it!=itend; ++it)
{
(*dart_mapping)[it]=mdarts.emplace();
init_dart((*dart_mapping)[it], amap.get_marks(it));
internal::Copy_dart_info_functor<CMap2, Refs, DartInfoConverter>::run
(amap, static_cast<Refs&>(*this), it, (*dart_mapping)[it],
dartinfoconverter);
new_dart=mdarts.emplace();
init_dart(new_dart, amap.get_marks(it));
(*origin_to_copy)[it]=new_dart;
if (copy_to_origin!=NULL) { (*copy_to_origin)[new_dart]=it; }
internal::Copy_dart_info_functor<Refs2, Refs, DartInfoConverter>::run
(static_cast<const Refs2&>(amap), static_cast<Refs&>(*this),
it, new_dart, dartinfoconverter);
}
unsigned int min_dim=(dimension<amap.dimension?dimension:amap.dimension);
typename boost::unordered_map<typename CMap2::Dart_const_handle,Dart_handle>
::iterator dartmap_iter, dartmap_iter_end=dart_mapping->end();
for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end;
::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end();
for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
++dartmap_iter)
{
for (unsigned int i=0; i<=min_dim; i++)
{
if (!amap.is_free(dartmap_iter->first,i) &&
(dartmap_iter->first)<(amap.beta(dartmap_iter->first,i)))
is_free(dartmap_iter->second,i))
{
basic_link_beta(dartmap_iter->second,
(*dart_mapping)[amap.beta(dartmap_iter->first,i)], i);
(*origin_to_copy)[amap.beta(dartmap_iter->first,i)], i);
}
}
}
/** Copy attributes */
for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end;
for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
++dartmap_iter)
{
Helper::template Foreach_enabled_attributes
< internal::Copy_attributes_functor <CMap2, Refs, Converters,
< internal::Copy_attributes_functor <Refs2, Refs, Converters,
PointConverter> >::
run(amap, static_cast<Refs&>(*this),
run(static_cast<const Refs2&>(amap), static_cast<Refs&>(*this),
dartmap_iter->first, dartmap_iter->second,
converters, pointconverter);
}
CGAL_assertion (is_valid () == 1);
CGAL_assertion (is_valid());
}
template <typename CMap2>
void copy(const CMap2& amap,
boost::unordered_map<typename CMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2>
void copy(const Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
boost::unordered_map
<typename Combinatorial_map_base<d2, Refs2, Items2, Alloc2,
Storage2>::Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
std::tuple<> converters;
Default_converter_dart_info<CMap2, Refs> dartinfoconverter;
Default_converter_cmap_0attributes_with_point<CMap2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping);
CGAL::cpp11::tuple<> converters;
Default_converter_dart_info<Refs2, Refs> dartinfoconverter;
Default_converter_cmap_0attributes_with_point<Refs2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter,
origin_to_copy, copy_to_origin);
}
template <typename CMap2, typename Converters>
void copy(const CMap2& amap, const Converters& converters,
boost::unordered_map<typename CMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters>
void copy(const Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>& amap,
const Converters& converters,
boost::unordered_map
<typename Combinatorial_map_base<d2, Refs2, Items2, Alloc2,
Storage2>::Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
Default_converter_cmap_0attributes_with_point<CMap2, Refs> pointconverter;
Default_converter_dart_info<CMap2, Refs> dartinfoconverter;
copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping);
Default_converter_cmap_0attributes_with_point<Refs2, Refs> pointconverter;
Default_converter_dart_info<Refs2, Refs> dartinfoconverter;
copy(amap, converters, dartinfoconverter, pointconverter,
origin_to_copy, copy_to_origin);
}
template <typename CMap2, typename Converters, typename DartInfoConverter>
void copy(const CMap2& amap, const Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter>
void copy(const Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
boost::unordered_map<typename CMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
boost::unordered_map
<typename Combinatorial_map_base<d2, Refs2, Items2, Alloc2,
Storage2>::Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
Default_converter_cmap_0attributes_with_point<CMap2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping);
Default_converter_cmap_0attributes_with_point<Refs2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter,
origin_to_copy, copy_to_origin);
}
// Copy constructor from a map having exactly the same type.
@ -314,25 +368,37 @@ namespace CGAL {
{ copy(amap); }
// "Copy constructor" from a map having different type.
template <typename CMap2>
Combinatorial_map_base(const CMap2& amap)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2>
Combinatorial_map_base(const Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>& amap)
{ copy(amap); }
// "Copy constructor" from a map having different type.
template <typename CMap2, typename Converters>
Combinatorial_map_base(const CMap2& amap, Converters& converters)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters>
Combinatorial_map_base(const Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>& amap,
const Converters& converters)
{ copy(amap, converters); }
// "Copy constructor" from a map having different type.
template <typename CMap2, typename Converters, typename DartInfoConverter>
Combinatorial_map_base(const CMap2& amap, Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters, typename DartInfoConverter>
Combinatorial_map_base(const Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter)
{ copy(amap, converters, dartinfoconverter); }
// "Copy constructor" from a map having different type.
template <typename CMap2, typename Converters, typename DartInfoConverter,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter,
typename PointConverter>
Combinatorial_map_base(const CMap2& amap, Converters& converters,
Combinatorial_map_base(const Combinatorial_map_base<d2, Refs2, Items2,
Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter)
{ copy(amap, converters, dartinfoconverter, pointconverter); }
@ -385,6 +451,62 @@ namespace CGAL {
}
}
/** Import the given hds which should be a model of an halfedge graph. */
template<class HEG>
void import_from_halfedge_graph(const HEG& heg,
boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle,
typename boost::graph_traits<HEG>::halfedge_descriptor>*
copy_to_origin=NULL)
{
// Create an mapping between darts of the two maps (originals->copies).
// (here we cannot use CGAL::Unique_hash_map because it does not provide
// iterators...
boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle> local_dartmap;
if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map
{ origin_to_copy=&local_dartmap; }
Dart_handle new_dart;
for (typename boost::graph_traits<HEG>::halfedge_iterator
it=halfedges(heg).begin(), itend=halfedges(heg).end();
it!=itend; ++it)
{
if (!CGAL::is_border(*it, heg))
{
new_dart=mdarts.emplace();
(*origin_to_copy)[*it]=new_dart;
if (copy_to_origin!=NULL) { (*copy_to_origin)[new_dart]=*it; }
}
}
typename boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle>::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end();
for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
++dartmap_iter)
{
basic_link_beta(dartmap_iter->second,
(*origin_to_copy)[CM_ADL_next(dartmap_iter->first, heg)],
1);
if (!CGAL::is_border(CM_ADL_opposite(dartmap_iter->first, heg), heg) &&
(dartmap_iter->first)<CM_ADL_opposite(dartmap_iter->first, heg))
{
basic_link_beta(dartmap_iter->second,
(*origin_to_copy)
[CM_ADL_opposite(dartmap_iter->first, heg)], 2);
}
}
CGAL_assertion (is_valid());
}
/** Clear the combinatorial map. Remove all darts and all attributes.
* Note that reserved marks are not free.
*/
@ -498,6 +620,16 @@ namespace CGAL {
{ return mdarts.iterator_to(adart); }
Dart_const_handle dart_handle(const Dart& adart) const
{ return mdarts.iterator_to(adart); }
Dart_handle dart_handle(size_type i)
{
CGAL_assertion(darts().is_used(i));
return mdarts.iterator_to(darts()[i]);
}
Dart_const_handle dart_handle(size_type i) const
{
CGAL_assertion(darts().is_used(i));
return mdarts.iterator_to(darts()[i]);
}
/** Return the highest dimension for which dh is not free.
* @param dh a dart handle
@ -673,6 +805,11 @@ namespace CGAL {
Dart_const_handle next(Dart_const_handle ADart) const
{ return this->template beta<1>(ADart); }
Dart_handle opposite2(Dart_handle ADart)
{ return this->template beta<2>(ADart); }
Dart_const_handle opposite2(Dart_const_handle ADart) const
{ return this->template beta<2>(ADart); }
template<unsigned int dim>
Dart_handle opposite(Dart_handle ADart)
{ return this->template beta<dim>(ADart); }
@ -950,6 +1087,27 @@ namespace CGAL {
mnb_times_reserved_marks[amark]=0;
}
template <unsigned int i, unsigned int d=dimension>
bool belong_to_same_cell(Dart_const_handle adart1,
Dart_const_handle adart2) const
{ return CGAL::belong_to_same_cell<Self, i, d>(*this, adart1, adart2); }
template <unsigned int i, unsigned int d=dimension>
bool is_whole_cell_unmarked(Dart_const_handle adart, size_type amark) const
{ return CGAL::is_whole_cell_unmarked<Self, i, d>(*this, adart, amark); }
template <unsigned int i, unsigned int d=dimension>
bool is_whole_cell_marked(Dart_const_handle adart, size_type amark) const
{ return CGAL::is_whole_cell_marked<Self, i, d>(*this, adart, amark); }
template <unsigned int i, unsigned int d=dimension>
size_type mark_cell(Dart_const_handle adart, size_type amark) const
{ return CGAL::mark_cell<Self, i, d>(*this, adart, amark); }
template <unsigned int i, unsigned int d=dimension>
size_type unmark_cell(Dart_const_handle adart, size_type amark) const
{ return CGAL::unmark_cell<Self, i, d>(*this, adart, amark); }
/** Test if this map is without boundary for a given dimension.
* @param i the dimension.
* @return true iff all the darts are not i-free.
@ -2300,6 +2458,30 @@ namespace CGAL {
run(*this, adart, amark);
}
/// Keep the biggest connected component.
/// @return the size (in number of darts) of the biggest cc.
std::size_t keep_biggest_connected_component()
{
std::map<std::size_t, Dart_handle> ccs;
size_type treated=get_new_mark();
for (auto it=darts().begin(), itend=darts().end(); it!=itend; ++it)
{
if (!is_marked(it, treated))
{ ccs[mark_cell<dimension+1>(it, treated)]=it; }
}
if (ccs.size()>1)
{ // Here all darts are marked
this->template unmark_cell<dimension+1>(ccs.rbegin()->second, treated); // Unmark the biggest cc
erase_marked_darts(treated);
}
free_mark(treated);
return ccs.rbegin()->first;
}
/** Count the marked cells (at least one marked dart).
* @param amark the mark to consider.
* @param avector containing the dimensions of the cells to count.
@ -2433,6 +2615,64 @@ namespace CGAL {
}
public:
/// @return the positive turn between the two given darts.
// @pre beta1(d1) and d2 must belong to the same vertex.
std::size_t positive_turn(Dart_const_handle d1, Dart_const_handle d2) const
{
CGAL_assertion((!this->template is_free<1>(d1)));
/* CGAL_assertion((belong_to_same_cell<0>(this->template beta<1>(d1),
d2))); */
if (d2==beta<2>(d1)) { return 0; }
Dart_const_handle dd1=d1;
std::size_t res=1;
while (beta<1>(dd1)!=d2)
{
if (this->template is_free<2>(beta<1>(dd1)))
{ return std::numeric_limits<std::size_t>::max(); }
++res;
dd1=beta<1, 2>(dd1);
CGAL_assertion(!this->template is_free<1>(dd1));
CGAL_assertion(beta<1>(dd1)==d2 || dd1!=d1);
}
return res;
}
/// @return the negative turn between the two given darts.
// @pre beta1(d1) and d2 must belong to the same vertex.
std::size_t negative_turn(Dart_const_handle d1, Dart_const_handle d2) const
{
CGAL_assertion((!this->template is_free<1>(d1)));
/* CGAL_assertion((belong_to_same_cell<0>(this->template beta<1>(d1),
d2))); */
if (d2==beta<2>(d1)) { return 0; }
if (this->template is_free<2>(d1) || this->template is_free<2>(d2))
{ return std::numeric_limits<std::size_t>::max(); }
d1=beta<2>(d1);
d2=beta<2>(d2);
Dart_const_handle dd1=d1;
std::size_t res=1;
while (beta<0>(dd1)!=d2)
{
if (this->template is_free<2>(beta<0>(dd1)))
{ return std::numeric_limits<std::size_t>::max(); }
++res;
dd1=beta<0, 2>(dd1);
CGAL_assertion(!this->template is_free<0>(dd1));
CGAL_assertion(beta<0>(dd1)==d2 || dd1!=d1);
}
return res;
}
/** Erase marked darts from the map.
* Marked darts are unlinked before to be removed, thus surviving darts
* are correctly linked, but the map is not necessarily valid depending
@ -3513,12 +3753,12 @@ namespace CGAL {
!is_face_combinatorial_polygon(d4, 3) ) return false;
// TODO do better with marks (?).
if ( belong_to_same_cell<Self,2,1>(*this, d1, d2) ||
belong_to_same_cell<Self,2,1>(*this, d1, d3) ||
belong_to_same_cell<Self,2,1>(*this, d1, d4) ||
belong_to_same_cell<Self,2,1>(*this, d2, d3) ||
belong_to_same_cell<Self,2,1>(*this, d2, d4) ||
belong_to_same_cell<Self,2,1>(*this, d3, d4) ) return false;
if ( belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d3, d4) ) return false;
if ( beta(d1,1,2)!=beta(d3,0) ||
beta(d4,0,2)!=beta(d3,1) ||
@ -3611,21 +3851,21 @@ namespace CGAL {
!is_face_combinatorial_polygon(d6, 4) ) return false;
// TODO do better with marks.
if ( belong_to_same_cell<Self,2,1>(*this, d1, d2) ||
belong_to_same_cell<Self,2,1>(*this, d1, d3) ||
belong_to_same_cell<Self,2,1>(*this, d1, d4) ||
belong_to_same_cell<Self,2,1>(*this, d1, d5) ||
belong_to_same_cell<Self,2,1>(*this, d1, d6) ||
belong_to_same_cell<Self,2,1>(*this, d2, d3) ||
belong_to_same_cell<Self,2,1>(*this, d2, d4) ||
belong_to_same_cell<Self,2,1>(*this, d2, d5) ||
belong_to_same_cell<Self,2,1>(*this, d2, d6) ||
belong_to_same_cell<Self,2,1>(*this, d3, d4) ||
belong_to_same_cell<Self,2,1>(*this, d3, d5) ||
belong_to_same_cell<Self,2,1>(*this, d3, d6) ||
belong_to_same_cell<Self,2,1>(*this, d4, d5) ||
belong_to_same_cell<Self,2,1>(*this, d4, d6) ||
belong_to_same_cell<Self,2,1>(*this, d5, d6) )
if ( belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d1, d5) ||
belong_to_same_cell<2,1>(d1, d6) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d2, d5) ||
belong_to_same_cell<2,1>(d2, d6) ||
belong_to_same_cell<2,1>(d3, d4) ||
belong_to_same_cell<2,1>(d3, d5) ||
belong_to_same_cell<2,1>(d3, d6) ||
belong_to_same_cell<2,1>(d4, d5) ||
belong_to_same_cell<2,1>(d4, d6) ||
belong_to_same_cell<2,1>(d5, d6) )
return false;
if ( beta(d1,2) !=beta(d4,1,1) ||
@ -3781,7 +4021,7 @@ namespace CGAL {
return this->template beta<1>(adart);
}
/** Insert a vertex in the given 2-cell which is splitted in triangles,
/** Insert a vertex in the given 2-cell which is split in triangles,
* once for each inital edge of the facet.
* @param adart a dart of the facet to triangulate.
* @param update_attributes a boolean to update the enabled attributes
@ -4213,7 +4453,7 @@ namespace CGAL {
if ( od==null_handle ) return false;
// of and *it must belong to the same vertex of the same volume
if ( !belong_to_same_cell<Self, 0, 2>(*this, od, *it) )
if ( !belong_to_same_cell<0, 2>(od, *it) )
return false;
}
prec = *it;
@ -4223,7 +4463,7 @@ namespace CGAL {
od = other_extremity(prec);
if ( od==null_handle ) return false;
if (!belong_to_same_cell<Self, 0, 2>(*this, od, *afirst))
if (!belong_to_same_cell<0, 2>(od, *afirst))
return false;
return true;
@ -4437,24 +4677,33 @@ namespace CGAL {
Combinatorial_map(const Self & amap) : Base(amap)
{}
template < class CMap >
Combinatorial_map(const CMap & amap) : Base(amap)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2>
Combinatorial_map(const Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>&
amap) : Base(amap)
{}
template < class CMap, typename Converters >
Combinatorial_map(const CMap & amap, const Converters& converters) :
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters>
Combinatorial_map(const Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>&
amap, const Converters& converters) :
Base(amap, converters)
{}
template < class CMap, typename Converters, typename DartInfoConverter >
Combinatorial_map(const CMap & amap, const Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters,
typename DartInfoConverter>
Combinatorial_map(const Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>&
amap, const Converters& converters,
const DartInfoConverter& dartinfoconverter) :
Base(amap, converters, dartinfoconverter)
{}
template < class CMap, typename Converters, typename DartInfoConverter,
typename PointConverter >
Combinatorial_map(const CMap & amap, const Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters,
typename DartInfoConverter, typename PointConverter >
Combinatorial_map(const Combinatorial_map_base<d2, Refs2, Items2, Alloc2, Storage2>&
amap, const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter) :
Base(amap, converters, dartinfoconverter, pointconverter)

View File

@ -194,7 +194,7 @@ namespace CGAL
typename Map::size_type amark)
{
return CGAL::is_whole_orbit_unmarked<Map,
typename Map::template Dart_of_cell_range<i,d>::iterator>
typename Map::template Dart_of_cell_range<i,d>::const_iterator>
(amap, adart, amark);
}

View File

@ -39,7 +39,7 @@ insert_cell_0_in_cell_1( CMap& amap, typename CMap::Dart_handle adart,
return amap.insert_cell_0_in_cell_1(adart, ah, update_attributes);
}
/** Insert a vertex in the given 2-cell which is splitted in triangles,
/** Insert a vertex in the given 2-cell which is split in triangles,
* once for each inital edge of the facet.
* @param amap the used combinatorial map.
* @param adart a dart of the facet to triangulate.

View File

@ -127,6 +127,8 @@ namespace CGAL {
CGAL_assertion(i <= dimension);
return dh->mf[i]==null_dart_handle;
}
bool is_perforated(Dart_const_handle /*dh*/) const
{ return false; }
/// Set simultaneously all the marks of this dart to a given value.
void set_dart_marks(Dart_const_handle ADart,

View File

@ -0,0 +1,941 @@
// Copyright (c) 2019 CNRS and LIRIS' Establishments (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
//
#ifndef CGAL_FACE_GRAPH_WRAPPER_H
#define CGAL_FACE_GRAPH_WRAPPER_H 1
#include <CGAL/Functors_for_face_graph_wrapper.h>
#include <CGAL/Iterators_for_face_graph_wrapper.h>
#include <CGAL/internal/Combinatorial_map_internal_functors.h>
#include <CGAL/Polyhedron_3_fwd.h>
#include <CGAL/Surface_mesh/Surface_mesh_fwd.h>
#include <bitset>
namespace CGAL
{
// Forward declarations of all classes model of Face_graph
template <unsigned int d, typename Refs, typename Items, typename Alloc,
typename Storage>
class Combinatorial_map_base;
template <unsigned int d, typename Refs, typename Items, typename Alloc,
typename Storage>
class Generalized_map_base;
template <unsigned int d, unsigned int d2, typename Traits, typename Items,
typename Alloc,
template<unsigned int,class,class,class,class>
class Map, typename Refs, typename Storage>
class Linear_cell_complex_base;
template <unsigned int d, typename Items, typename Alloc,
typename Storage>
class Combinatorial_map;
template <unsigned int d, typename Items, typename Alloc,
typename Storage>
class Generalized_map;
template <unsigned int d, unsigned int d2, typename Traits, typename Items,
typename Alloc,
template<unsigned int,class,class,class,class>
class Map, typename Storage>
class Linear_cell_complex_for_combinatorial_map;
template <unsigned int d, unsigned int d2, typename Traits, typename Items,
typename Alloc,
template<unsigned int,class,class,class,class>
class Map, typename Storage>
class Linear_cell_complex_for_generalized_map;
namespace Surface_mesh_topology
{
template <typename Items, typename Alloc, typename Storage>
class Polygonal_schema_with_combinatorial_map;
template <typename Items, typename Alloc, typename Storage>
class Polygonal_schema_with_generalized_map;
}
////////////////////////////////////////////////////////////////////////////////
/** Class Face_graph_wrapper: to wrap any model of FaceGraph into a
* Combinatorial map. For now, only for const models, i.e. does not support
* modification operators.
*/
template<typename HEG_>
class Face_graph_wrapper
{
public:
typedef HEG_ HEG;
typedef Face_graph_wrapper<HEG> Self;
typedef std::size_t size_type;
struct Dart_container
{
typedef typename boost::graph_traits<HEG>::halfedge_iterator iterator;
typedef typename boost::graph_traits<HEG>::halfedge_iterator const_iterator; // TODO ?
// typedef My_halfedge_iterator<HEG> iterator;
// typedef My_halfedge_iterator<HEG> const_iterator; // TODO ?
};
typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_handle;
typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
typedef Dart_handle Null_handle_type;
// typedef CGAL::Void* Null_handle_type;
static const Null_handle_type null_handle; //=Dart_handle();
static const Null_handle_type null_dart_handle; //=Dart_handle();
/// Number of marks
static const size_type NB_MARKS = 32;
static const size_type INVALID_MARK = NB_MARKS;
/// The dimension of the combinatorial map.
static const unsigned int dimension=2;
static const unsigned int ambient_dimension=3;
typedef typename boost::graph_traits<HEG>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<HEG>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<HEG>::face_descriptor face_descriptor;
typedef boost::undirected_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
struct SM_graph_traversal_category : public virtual boost::bidirectional_graph_tag,
public virtual boost::vertex_list_graph_tag,
public virtual boost::edge_list_graph_tag
{};
typedef SM_graph_traversal_category traversal_category;
Face_graph_wrapper(const HEG& f) : m_fg(f),
mdarts(*this),
m_nb_darts(0),
mnb_used_marks(0)
{
mmask_marks.reset();
for (size_type i=0; i<NB_MARKS; ++i)
{
mfree_marks_stack[i] =i;
mindex_marks[i] =i;
mnb_marked_darts[i] =0;
mnb_times_reserved_marks[i]=0;
}
// Store locally the number of darts: the HEG must not be modified
m_nb_darts=darts().size();
m_all_marks=get(CGAL::dynamic_halfedge_property_t<std::bitset<NB_MARKS> >(), m_fg);
for (typename Dart_range::const_iterator it(darts().begin()),
itend(darts().end()); it!=itend; ++it)
{ put(m_all_marks, it, std::bitset<NB_MARKS>()); }
}
const HEG& get_fg() const
{ return m_fg; }
template<unsigned int i>
bool is_free(Dart_const_handle /* dh */) const
{ return false; } // Not possible to have a free dart with an HEG.
bool is_free(Dart_const_handle /*dh*/, unsigned int /*i*/) const
{ return false; } // Not possible to have a free dart with an HEG.
bool is_perforated(Dart_const_handle dh) const
{ return is_border(dh, m_fg); }
Dart_const_handle get_beta(Dart_const_handle ADart, int B1) const
{
CGAL_assertion(B1>=0 && B1<=static_cast<int>(dimension));
if (B1==1) return Get_beta<HEG, 1>::value(m_fg, ADart);
if (B1==2) return Get_beta<HEG, 2>::value(m_fg, ADart);
return Get_beta<HEG, 0>::value(m_fg, ADart);
}
template<int B1>
Dart_const_handle get_beta(Dart_const_handle ADart) const
{
CGAL_assertion(B1>=0 && B1<=static_cast<int>(dimension));
return Get_beta<HEG, B1>::value(m_fg, ADart);
}
bool is_empty() const
{ return number_of_darts()==0; }
/* ?? bool is_dart_used(Dart_const_handle dh) const
{ return true; ?? } */
int highest_nonfree_dimension(Dart_const_handle /* dh */) const
{ return 2; }
Dart_const_handle previous(Dart_const_handle ADart) const
{ return get_beta<0>(ADart); }
Dart_const_handle next(Dart_const_handle ADart) const
{ return get_beta<1>(ADart); }
Dart_const_handle opposite(Dart_const_handle dh) const
{ return get_beta<2>(dh); }
Dart_const_handle opposite2(Dart_const_handle dh) const
{ return get_beta<2>(dh); }
Dart_const_handle other_extremity(Dart_const_handle dh) const
{ return get_beta<1>(dh); }
template<unsigned int dim>
Dart_const_handle opposite(Dart_const_handle ADart) const
{ return this->template get_beta<dim>(ADart); }
Dart_const_handle other_orientation(Dart_const_handle ADart) const
{ return ADart; }
bool is_previous_exist(Dart_const_handle) const
{ return true; }
bool is_next_exist(Dart_const_handle) const
{ return true; }
template<unsigned int dim>
bool is_opposite_exist(Dart_const_handle /* ADart */) const
{ return true; }
template<typename ...Betas>
Dart_handle beta(Dart_handle ADart, Betas... betas)
{ return CGAL::internal::Beta_functor<Self, Dart_handle, Betas...>::
run(*this, ADart, betas...); }
template<typename ...Betas>
Dart_const_handle beta(Dart_const_handle ADart, Betas... betas) const
{ return CGAL::internal::Beta_functor<const Self, Dart_const_handle, Betas...>::
run(*this, ADart, betas...); }
template<int... Betas>
Dart_handle beta(Dart_handle ADart)
{ return CGAL::internal::Beta_functor_static<Self, Dart_handle, Betas...>::
run(*this, ADart); }
template<int... Betas>
Dart_const_handle beta(Dart_const_handle ADart) const
{ return CGAL::internal::Beta_functor_static<const Self, Dart_const_handle, Betas...>::
run(*this, ADart); }
size_type number_of_darts() const
{ return m_nb_darts; }
size_type number_of_halfedges() const
{ return number_of_darts(); }
size_type number_of_used_marks() const
{ return mnb_used_marks; }
bool is_reserved(size_type amark) const
{
CGAL_assertion(amark<NB_MARKS);
return (mnb_times_reserved_marks[amark]!=0);
}
size_type number_of_marked_darts(size_type amark) const
{
CGAL_assertion( is_reserved(amark) );
return mnb_marked_darts[amark];
}
size_type number_of_unmarked_darts(size_type amark) const
{
CGAL_assertion( is_reserved(amark) );
return number_of_darts() - number_of_marked_darts(amark);
}
bool is_whole_map_unmarked(size_type amark) const
{ return number_of_marked_darts(amark)==0; }
bool is_whole_map_marked(size_type amark) const
{ return number_of_marked_darts(amark)==number_of_darts(); }
class Exception_no_more_available_mark {};
size_type get_new_mark() const
{
if (mnb_used_marks==NB_MARKS)
{
std::cerr << "Not enough Boolean marks: "
"increase NB_MARKS in item class." << std::endl;
std::cerr << " (exception launched)" << std::endl;
throw Exception_no_more_available_mark();
}
size_type m=mfree_marks_stack[mnb_used_marks];
mused_marks_stack[mnb_used_marks]=m;
mindex_marks[m]=mnb_used_marks;
mnb_times_reserved_marks[m]=1;
++mnb_used_marks;
CGAL_assertion(is_whole_map_unmarked(m));
return m;
}
void share_a_mark(size_type amark) const
{
CGAL_assertion( is_reserved(amark) );
++mnb_times_reserved_marks[amark];
}
size_type get_number_of_times_mark_reserved(size_type amark) const
{
CGAL_assertion( amark<NB_MARKS );
return mnb_times_reserved_marks[amark];
}
void negate_mark(size_type amark) const
{
CGAL_assertion(is_reserved(amark));
mnb_marked_darts[amark]=number_of_darts()-mnb_marked_darts[amark];
mmask_marks.flip(amark);
}
void mark_null_dart( size_type /*amark*/) const
{}
bool get_dart_mark(Dart_const_handle ADart, size_type amark) const
{
return get(m_all_marks, ADart)[amark];
}
void set_dart_mark(Dart_const_handle ADart, size_type amark, bool avalue) const
{
const_cast<std::bitset<NB_MARKS>& >(get(m_all_marks, ADart)).set(amark, avalue);
}
void flip_dart_mark(Dart_const_handle ADart, size_type amark) const
{ set_dart_mark(ADart, amark, !get_dart_mark(ADart, amark)); }
bool is_marked(Dart_const_handle adart, size_type amark) const
{
CGAL_assertion(is_reserved(amark));
return get_dart_mark(adart, amark)!=mmask_marks[amark];
}
void set_mark_to(Dart_const_handle adart, size_type amark,
bool astate) const
{
CGAL_assertion(is_reserved(amark));
if (is_marked(adart, amark)!=astate)
{
if (astate) ++mnb_marked_darts[amark];
else --mnb_marked_darts[amark];
flip_dart_mark(adart, amark);
}
}
void mark(Dart_const_handle adart, size_type amark) const
{
CGAL_assertion(is_reserved(amark));
if (is_marked(adart, amark)) return;
++mnb_marked_darts[amark];
flip_dart_mark(adart, amark);
}
void unmark(Dart_const_handle adart, size_type amark) const
{
CGAL_assertion( adart!=this->null_dart_handle );
CGAL_assertion( is_reserved(amark) );
if (!is_marked(adart, amark)) return;
--mnb_marked_darts[amark];
flip_dart_mark(adart, amark);
}
void unmark_all(size_type amark) const
{
CGAL_assertion( is_reserved(amark) );
if ( is_whole_map_marked(amark) )
{
negate_mark(amark);
}
else if ( !is_whole_map_unmarked(amark) )
{
for (typename Dart_range::const_iterator it(darts().begin()),
itend(darts().end()); it!=itend; ++it)
unmark(*it, amark);
}
CGAL_assertion(is_whole_map_unmarked(amark));
}
void free_mark(size_type amark) const
{
CGAL_assertion( is_reserved(amark) );
if ( mnb_times_reserved_marks[amark]>1 )
{
--mnb_times_reserved_marks[amark];
return;
}
unmark_all(amark);
// 1) We remove amark from the array mused_marks_stack by
// replacing it with the last mark in this array.
mused_marks_stack[mindex_marks[amark]] =
mused_marks_stack[--mnb_used_marks];
mindex_marks[mused_marks_stack[mnb_used_marks]] =
mindex_marks[amark];
// 2) We add amark in the array mfree_marks_stack and update its index.
mfree_marks_stack[ mnb_used_marks ]=amark;
mindex_marks[amark] = mnb_used_marks;
mnb_times_reserved_marks[amark]=0;
}
bool is_without_boundary(unsigned int i) const
{
CGAL_assertion(1<=i && i<=dimension);
if (i==1) return true;
for ( typename Dart_range::const_iterator it(darts().begin()),
itend(darts().end()); it!=itend; ++it)
{ if (is_perforated(it)) return false; }
return true;
}
bool is_without_boundary() const
{ return is_without_boundary(2); }
//**************************************************************************
// Dart_of_cell_range
template<unsigned int i>
struct Dart_of_cell_range
{
typedef CGAL::FGW_cell_iterator<Self, i> iterator;
typedef CGAL::FGW_cell_iterator<Self, i> const_iterator;
Dart_of_cell_range(const Self &amap, Dart_handle adart) : mmap(amap),
m_initdart(adart),
msize(0)
{}
const_iterator begin() const { return const_iterator(mmap, m_initdart); }
const_iterator end() const { return const_iterator(mmap, m_initdart, mmap.null_handle); }
size_type size() const
{
if (msize==0)
{
for (const_iterator it=begin(), itend=end(); it!=itend; ++it)
{ ++msize; }
}
return msize;
}
bool empty() const
{ return mmap.is_empty(); }
private:
const Self & mmap;
Dart_handle m_initdart;
mutable typename Self::size_type msize;
};
//**************************************************************************
// Dart_of_cell_const_range
/* template<unsigned int i,int dim=Self::dimension>
struct Dart_of_cell_const_range // TODO REMOVE ??
{}; */
//--------------------------------------------------------------------------
template<unsigned int i>
Dart_of_cell_range<i> darts_of_cell(Dart_handle adart)
{ return Dart_of_cell_range<i>(*this,adart); }
//--------------------------------------------------------------------------
template<unsigned int i>
Dart_of_cell_range<i> darts_of_cell(Dart_const_handle adart) const
{ return Dart_of_cell_range<i>(*this,adart); } // Before it was Dart_of_cell_const_range<i>
//**************************************************************************
// Dart_range
struct Dart_range {
typedef CGAL::FGW_dart_iterator_basic_of_all<Self> iterator;
typedef CGAL::FGW_dart_iterator_basic_of_all<Self> const_iterator;
Dart_range(const Self &amap) : mmap(amap), msize(0)
{}
iterator begin() { return iterator(mmap); }
iterator end() { return iterator(mmap,mmap.null_handle); }
const_iterator begin() const { return const_iterator(mmap); }
const_iterator end() const { return const_iterator(mmap,mmap.null_handle); }
size_type size() const
{
if (msize==0)
{ msize=halfedges(mmap.get_fg()).size(); }
return msize;
}
bool empty() const
{ return mmap.is_empty(); }
size_type capacity() const
{ return num_halfedges(mmap.get_fg()); }
bool is_used(size_type i) const
{
for (typename boost::template graph_traits<typename Self::HEG>::halfedge_iterator
it=halfedges(mmap.get_fg()).begin(),
itend=halfedges(mmap.get_fg()).end(); it!=itend; ++it)
{
if (i==0) { return !is_border(*it, mmap.get_fg()); }
--i;
}
return false;
}
private:
const Self & mmap;
mutable typename Self::size_type msize;
};
//**************************************************************************
// Dart_const_range // TODO REMOVE ?
/* struct Dart_const_range {
typedef CGAL::FGW_dart_iterator_basic_of_all<Self, true> const_iterator;
Dart_const_range(const Self &amap) : mmap(amap), msize(0)
{}
const_iterator begin() const { return const_iterator(mmap); }
const_iterator end() const { return const_iterator(mmap,mmap.null_handle); }
size_type size() const
{
if (msize==0)
{
for (const_iterator it=begin(), itend=end(); it!=itend; ++it)
{ ++msize; }
}
return msize;
}
bool empty() const
{ return mmap.is_empty(); }
private:
const Self & mmap;
mutable typename Self::size_type msize;
};*/
//**************************************************************************
Dart_range& darts()
{ return mdarts; }
//--------------------------------------------------------------------------
const Dart_range& darts() const
{ return mdarts; } // Before it was Dart_const_range(*this)
//**************************************************************************
Dart_handle dart_handle(size_type i)
{
CGAL_assertion(darts().is_used(i));
for (typename boost::template graph_traits<typename Self::HEG>::halfedge_iterator
it=halfedges(get_fg()).begin(),
itend=halfedges(get_fg()).end(); it!=itend; ++it)
{
if (i==0) { return *it; }
--i;
}
CGAL_assertion(false);
return Dart_handle();
}
Dart_const_handle dart_handle(size_type i) const
{
CGAL_assertion(darts().is_used(i));
for (typename boost::template graph_traits<typename Self::HEG>::halfedge_iterator
it=halfedges(get_fg()).begin(),
itend=halfedges(get_fg()).end(); it!=itend; ++it)
{
if (i==0) { return *it; }
--i;
}
CGAL_assertion(false);
return Dart_const_handle();
}
template <unsigned int i>
bool belong_to_same_cell(Dart_const_handle adart1,
Dart_const_handle adart2) const
{
for (typename Dart_of_cell_range<i>::iterator it=darts_of_cell<i>(adart1).begin(),
itend=darts_of_cell<i>(adart1).end(); it!=itend; ++it)
{ if (*it==adart2) { return true; } }
return false;
}
template <unsigned int i>
bool is_whole_cell_unmarked(Dart_const_handle adart, size_type amark) const
{
for (typename Dart_of_cell_range<i>::iterator it=darts_of_cell<i>(adart).begin(),
itend=darts_of_cell<i>(adart).end(); it!=itend; ++it)
{ if (is_marked(*it, amark)) { return false; } }
return true;
}
template <unsigned int i>
bool is_whole_cell_marked(Dart_const_handle adart, size_type amark) const
{
for (typename Dart_of_cell_range<i>::iterator it=darts_of_cell<i>(adart).begin(),
itend=darts_of_cell<i>(adart).end(); it!=itend; ++it)
{ if (!is_marked(*it, amark)) { return false; } }
return true;
}
template <unsigned int i>
size_type mark_cell(Dart_const_handle adart, size_type amark) const
{
size_type res=0;
for (typename Dart_of_cell_range<i>::iterator it=darts_of_cell<i>(adart).begin(),
itend=darts_of_cell<i>(adart).end(); it!=itend; ++it)
{ mark(*it, amark); ++res; }
return res;
}
size_type mark_cell(Dart_const_handle adart, unsigned int i, size_type amark) const
{
if (i==0) { return mark_cell<0>(adart, amark); }
else if (i==1) { return mark_cell<1>(adart, amark); }
else if (i==2) { return mark_cell<2>(adart, amark); }
return mark_cell<3>(adart, amark);
}
template <unsigned int i>
size_type unmark_cell(Dart_const_handle adart, size_type amark) const
{
size_type res=0;
for (typename Dart_of_cell_range<i>::iterator it=darts_of_cell<i>(adart).begin(),
itend=darts_of_cell<i>(adart).end(); it!=itend; ++it)
{ unmark(*it, amark); ++res; }
return res;
}
std::vector<unsigned int>
count_marked_cells(size_type amark, const std::vector<unsigned int>& acells) const
{
std::vector<unsigned int> res(dimension+2);
std::vector<size_type> marks(dimension+2);
// Initialization of the result
for (unsigned int i=0; i<dimension+2; ++i)
{
res[i]=0;
marks[i]=INVALID_MARK;
}
// Mark reservation
for (unsigned int i=0; i<acells.size(); ++i)
{
CGAL_assertion(acells[i]<=dimension+1);
if (marks[acells[i]]==INVALID_MARK )
{
marks[acells[i]]=get_new_mark();
assert(is_whole_map_unmarked(marks[acells[i]]));
}
}
// Counting and marking cells
for (typename Dart_range::const_iterator it(darts().begin()),
itend(darts().end()); it!=itend; ++it)
{
if (is_marked(*it, amark))
{
for (unsigned int i=0; i<acells.size(); ++i)
{
if (!is_marked(*it, marks[acells[i]]))
{
mark_cell(*it, acells[i], marks[acells[i]]);
++res[acells[i]];
}
}
}
}
// Unmarking darts
std::vector<size_type> tounmark;
for (unsigned int i=0; i<acells.size(); ++i)
{
if (is_whole_map_marked(marks[acells[i]]) ||
is_whole_map_unmarked(marks[acells[i]]))
{ free_mark(marks[acells[i]]); }
else
{ tounmark.push_back(marks[acells[i]]); }
}
if (tounmark.size()>0)
{
for (typename Dart_range::const_iterator it(darts().begin()),
itend(darts().end()); it!=itend; ++it)
{
for (unsigned int i=0; i<tounmark.size(); ++i)
{ unmark(*it, tounmark[i]); }
}
for (unsigned int i=0; i<tounmark.size(); ++i)
{
CGAL_assertion(is_whole_map_unmarked(tounmark[i]));
free_mark(tounmark[i]);
}
}
return res;
}
std::vector<unsigned int>
count_cells(const std::vector<unsigned int>& acells) const
{
std::vector<unsigned int> res;
size_type m=get_new_mark();
negate_mark(m); // We mark all the cells.
res=count_marked_cells(m, acells);
negate_mark(m); // We unmark the cells
free_mark(m);
return res;
}
std::vector<unsigned int> count_all_cells() const
{
std::vector<unsigned int> dim(dimension+2);
for ( unsigned int i=0; i<=dimension+1; ++i)
{ dim[i]=i; }
return count_cells(dim);
}
std::ostream& display_characteristics(std::ostream & os) const
{
std::vector<unsigned int> cells(dimension+2);
for ( unsigned int i=0; i<=dimension+1; ++i)
{ cells[i]=i; }
std::vector<unsigned int> res=count_cells(cells);
os<<"#Darts="<<number_of_darts();
for (unsigned int i=0; i<=dimension; ++i)
os<<", #"<<i<<"-cells="<<res[i];
os<<", #ccs="<<res[dimension+1];
return os;
}
protected:
const HEG& m_fg;
Dart_range mdarts;
std::size_t m_nb_darts;
/// Number of times each mark is reserved. 0 if the mark is free.
mutable size_type mnb_times_reserved_marks[NB_MARKS];
/// Mask marks to know the value of unmark dart, for each index i.
mutable std::bitset<NB_MARKS> mmask_marks;
/// Number of used marks.
mutable size_type mnb_used_marks;
/// Index of each mark, in mfree_marks_stack or in mfree_marks_stack.
mutable size_type mindex_marks[NB_MARKS];
/// "Stack" of free marks.
mutable size_type mfree_marks_stack[NB_MARKS];
/// "Stack" of used marks.
mutable size_type mused_marks_stack[NB_MARKS];
/// Number of marked darts for each used marks.
mutable size_type mnb_marked_darts[NB_MARKS];
/// Array of property maps; one for each reserved mark.
typedef typename boost::property_map
<HEG, CGAL::dynamic_halfedge_property_t<std::bitset<NB_MARKS> > >::const_type MarkPMap;
mutable MarkPMap m_all_marks;
};
/// null_handle
// template <typename HEG>
// const typename Face_graph_wrapper<HEG>::Null_handle_type
// Face_graph_wrapper<HEG>::null_handle=nullptr;
template <typename HEG>
const typename Face_graph_wrapper<HEG>::Null_handle_type
Face_graph_wrapper<HEG>::null_handle=typename Face_graph_wrapper<HEG>::Dart_handle();
/// null_dart_handle
// template <typename HEG>
// const typename Face_graph_wrapper<HEG>::Null_handle_type
// Face_graph_wrapper<HEG>::null_dart_handle=nullptr;
template <typename HEG>
const typename Face_graph_wrapper<HEG>::Null_handle_type
Face_graph_wrapper<HEG>::null_dart_handle=typename Face_graph_wrapper<HEG>::Dart_handle();
template<class Base, class HEG>
struct Get_map
{
typedef Face_graph_wrapper<HEG> type;
typedef const Face_graph_wrapper<HEG> storage_type;
Get_map(const HEG& heg): m_map(heg) {}
static const HEG& get_mesh(const storage_type& amap)
{ return amap.get_fg(); }
storage_type m_map;
};
template <unsigned int d, typename Refs, typename Items, typename Alloc,
typename Storage, class Map>
struct Get_map<CGAL::Combinatorial_map_base<d, Refs, Items, Alloc, Storage>, Map>
{
typedef Map type;
typedef const Map& storage_type;
Get_map(const Map& heg): m_map(heg) {}
static const Map& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <unsigned int d, typename Refs, typename Items, typename Alloc,
typename Storage, class Map>
struct Get_map<CGAL::Generalized_map_base<d, Refs, Items, Alloc, Storage>, Map>
{
typedef Map type;
typedef const Map& storage_type;
Get_map(const Map& heg): m_map(heg) {}
static const Map& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <unsigned int d, unsigned int d2, typename Traits, typename Items,
typename Alloc,
template<unsigned int,class,class,class,class>
class Map, typename Refs, typename Storage, class LCC>
struct Get_map<CGAL::Linear_cell_complex_base<d, d2, Traits, Items, Alloc,
Map, Refs, Storage>, LCC>
{
typedef LCC type;
typedef const LCC& storage_type;
Get_map(const LCC& heg): m_map(heg) {}
static const LCC& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <unsigned int d, typename Items, typename Alloc,
typename Storage, class Map>
struct Get_map<CGAL::Combinatorial_map<d, Items, Alloc, Storage>, Map>
{
typedef Map type;
typedef const Map& storage_type;
Get_map(const Map& heg): m_map(heg) {}
static const Map& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <typename Items, typename Alloc, typename Storage, class Map>
struct Get_map<CGAL::Surface_mesh_topology::
Polygonal_schema_with_combinatorial_map<Items, Alloc, Storage>, Map>
{
typedef Map type;
typedef const Map& storage_type;
Get_map(const Map& heg): m_map(heg) {}
static const Map& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <unsigned int d, typename Items, typename Alloc,
typename Storage, class Map>
struct Get_map<CGAL::Generalized_map<d, Items, Alloc, Storage>, Map>
{
typedef Map type;
typedef const Map& storage_type;
Get_map(const Map& heg): m_map(heg) {}
static const Map& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <typename Items, typename Alloc, typename Storage, class Map>
struct Get_map<CGAL::Surface_mesh_topology::
Polygonal_schema_with_generalized_map<Items, Alloc, Storage>, Map>
{
typedef Map type;
typedef const Map& storage_type;
Get_map(const Map& heg): m_map(heg) {}
static const Map& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <unsigned int d, unsigned int d2, typename Traits, typename Items,
typename Alloc,
template<unsigned int,class,class,class,class>
class Map, typename Storage, class LCC>
struct Get_map<CGAL::Linear_cell_complex_for_combinatorial_map
<d, d2, Traits, Items, Alloc, Map, Storage>, LCC>
{
typedef LCC type;
typedef const LCC& storage_type;
Get_map(const LCC& heg): m_map(heg) {}
static const LCC& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template <unsigned int d, unsigned int d2, typename Traits, typename Items,
typename Alloc,
template<unsigned int,class,class,class,class>
class Map, typename Storage, class LCC>
struct Get_map<CGAL::Linear_cell_complex_for_generalized_map
<d, d2, Traits, Items, Alloc, Map, Storage>, LCC>
{
typedef LCC type;
typedef const LCC& storage_type;
Get_map(const LCC& heg): m_map(heg) {}
static const LCC& get_mesh(storage_type& amap)
{ return amap; }
storage_type m_map;
};
template<class Mesh_>
struct Get_traits
{
typedef Mesh_ Mesh;
typedef typename Mesh::Traits Kernel;
typedef typename Mesh::Point Point;
typedef typename Mesh::Vector Vector;
template<class Dart_handle>
static const Point& get_point(const Mesh& m, Dart_handle dh)
{ return m.point(dh); }
};
template<class P>
struct Get_traits<CGAL::Surface_mesh<P> >
{
typedef CGAL::Surface_mesh<P> Mesh;
typedef typename CGAL::Kernel_traits<P>::Kernel Kernel;
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
template<class Dart_handle>
static const Point& get_point(const Mesh& m, Dart_handle dh)
{ return m.point(m.source(dh)); }
};
template<class PolyhedronTraits_3,
class PolyhedronItems_3,
template<class T, class I, class A> class T_HDS,
class Alloc>
struct Get_traits<CGAL::Polyhedron_3<PolyhedronTraits_3,
PolyhedronItems_3, T_HDS, Alloc> >
{
typedef CGAL::Polyhedron_3<PolyhedronTraits_3, PolyhedronItems_3,
T_HDS, Alloc> Mesh;
typedef PolyhedronTraits_3 Kernel;
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
template<class Dart_handle>
static const Point& get_point(const Mesh& /*m*/, Dart_handle dh)
{ return dh->opposite()->vertex()->point(); }
};
} // Namespace CGAL
#endif // CGAL_FACE_GRAPH_WRAPPER_H //
// EOF //

View File

@ -0,0 +1,87 @@
// Copyright (c) 2019 CNRS and LIRIS' Establishments (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
//
#ifndef CGAL_FUNCTORS_FOR_FACE_GRAPH_WRAPPER_H
#define CGAL_FUNCTORS_FOR_FACE_GRAPH_WRAPPER_H 1
#include <boost/graph/graph_traits.hpp>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/Iterators_for_face_graph_wrapper.h>
////////////////////////////////////////////////////////////////////////////////
/** This file contains the following functors for Face_graph_wrapper:
* Is_free<typename HEG, unsigned int i>::
operator() (const HEG& heg, Dart_const_handle dh)
* Get_beta<typename HEG, unsigned int i>::
operator() (const HEG& heg, Dart_const_handle dh)
*/
////////////////////////////////////////////////////////////////////////////////
namespace CGAL
{
/// Is_free
//template<typename HEG, unsigned int i>
//struct Is_free
//{
// typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
// static bool value(const HEG& /*heg*/, Dart_const_handle /*dh*/)
// { CGAL_static_assertion(i==0 || i==1); return false; }
//};
//template<typename HEG>
//struct Is_free<HEG, 2>
//{
// typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
// static bool value(const HEG& heg, Dart_const_handle dh)
// { return is_border(opposite(dh, heg), heg); }
//};
////////////////////////////////////////////////////////////////////////////////
/// Get_beta
template<typename HEG, unsigned int i>
struct Get_beta
{
typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
static Dart_const_handle value(const HEG& /*heg*/, Dart_const_handle /*dh*/)
{ /* CGAL_static_assertion(false);*/
std::cout<<"ERROR Get_beta<HEG, "<<i<<">"<<std::endl;
CGAL_assertion(false);
return nullptr;
}
};
template<typename HEG>
struct Get_beta<HEG, 0>
{
typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
static Dart_const_handle value(const HEG& heg, Dart_const_handle dh)
{ return prev(dh, heg); }
};
template<typename HEG>
struct Get_beta<HEG, 1>
{
typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
static Dart_const_handle value(const HEG& heg, Dart_const_handle dh)
{ return next(dh, heg); }
};
template<typename HEG>
struct Get_beta<HEG, 2>
{
typedef typename boost::graph_traits<HEG>::halfedge_descriptor Dart_const_handle;
static Dart_const_handle value(const HEG& heg, Dart_const_handle dh)
{
//if (Is_free<HEG, 2>::value(heg, dh)) return Dart_const_handle();
return opposite(dh, heg);
}
};
////////////////////////////////////////////////////////////////////////////////
} // namespace CGAL
#endif // CGAL_FUNCTORS_FOR_FACE_GRAPH_WRAPPER_H //
// EOF //

View File

@ -0,0 +1,332 @@
// Copyright (c) 2019 CNRS and LIRIS' Establishments (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
//
#ifndef CGAL_ITERATORS_FOR_FACE_GRAPH_WRAPPER_H
#define CGAL_ITERATORS_FOR_FACE_GRAPH_WRAPPER_H 1
#include <boost/graph/graph_traits.hpp>
#include <CGAL/boost/graph/helpers.h>
#include <stack>
namespace CGAL
{
//****************************************************************************
/* Class CMap_dart_iterator_basic_of_all: to iterate onto all the
* darts of the face graph.
*/
template <typename Map_,bool Const=false>
class FGW_dart_iterator_basic_of_all
{
public:
typedef FGW_dart_iterator_basic_of_all Self;
typedef Map_ Map;
typedef typename Map::Dart_handle Dart_handle;
typedef typename Map::size_type size_type;
public:
/// Main constructor.
FGW_dart_iterator_basic_of_all(const Map& amap):
mmap(amap),
m_it(halfedges(amap.get_fg()).begin())
{
/*if (m_it!=halfedges(amap.get_fg()).end() &&
is_border(*m_it, amap.get_fg()))
{ operator++(0); } */
}
/// Constructor with a dart in parameter (for end iterator).
FGW_dart_iterator_basic_of_all(const Map& amap, Dart_handle /*adart*/):
mmap(amap),
m_it(halfedges(amap.get_fg()).end())
{}
FGW_dart_iterator_basic_of_all(const FGW_dart_iterator_basic_of_all& other):
mmap(other.mmap),
m_it(other.m_it)
{}
operator Dart_handle() const
{ return operator*(); }
bool operator==(const Self& other) const
{ return &mmap==&(other.mmap) && m_it==other.m_it; }
bool operator!=(const Self& other) const
{ return !(operator==(other)); }
/// Prefix ++ operator.
Self& operator++()
{
CGAL_assertion(m_it!=halfedges(this->mmap.get_fg()).end());
//do
{
++m_it;
}
/*while(m_it!=halfedges(this->mmap.get_fg()).end() &&
is_border(*m_it, this->mmap.get_fg())); */
return *this;
}
/// Postfix ++ operator.
Self operator++(int)
{ Self res=*this; operator ++(); return res; }
Dart_handle operator*() const
{
CGAL_assertion(m_it!=halfedges(this->mmap.get_fg()).end());
return *m_it;
}
protected:
const Map& mmap;
typename boost::graph_traits<typename Map_::HEG>::halfedge_iterator m_it;
};
////////////////////////////////////////////////////////////////////////////////
template <typename Map_>
class FGW_basis_for_cell_iterator
{
public:
typedef FGW_basis_for_cell_iterator Self;
typedef Map_ Map;
typedef typename Map::Dart_handle Dart_handle;
typedef typename Map::size_type size_type;
/// Main constructor.
FGW_basis_for_cell_iterator(const Map& amap, Dart_handle adart):
mmap(amap),
m_firstdart(adart),
m_curdart(adart)
{}
/// Constructor with two darts in parameter (for end iterator).
FGW_basis_for_cell_iterator(const Map& amap, Dart_handle adart,
Dart_handle /* d2 */):
mmap(amap),
m_firstdart(adart),
m_curdart(Dart_handle())
{}
bool operator==(const Self& other) const
{ return &mmap==&(other.mmap) && m_firstdart==other.m_firstdart &&
m_curdart==other.m_curdart; }
bool operator!=(const Self& other) const
{ return !(this->operator==(other)); }
operator Dart_handle() const
{ return operator*(); }
Dart_handle operator*() const
{
CGAL_assertion(m_curdart!=Dart_handle());
return m_curdart;
}
protected:
const Map& mmap;
Dart_handle m_firstdart, m_curdart;
};
////////////////////////////////////////////////////////////////////////////////
template<typename HEG, unsigned int i>
class FGW_cell_iterator
{};
////////////////////////////////////////////////////////////////////////////////
/// Vertex iterator
template<typename Map_>
class FGW_cell_iterator<Map_, 0>: public FGW_basis_for_cell_iterator<Map_> // Vertex
{
public:
typedef FGW_cell_iterator Self;
typedef FGW_basis_for_cell_iterator<Map_> Base;
typedef Map_ Map;
typedef typename Map::Dart_handle Dart_handle;
typedef typename Map::size_type size_type;
FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart),
m_second_way(false)
{}
/// Constructor with two darts in parameter (for end iterator).
FGW_cell_iterator(const Map& amap, Dart_handle adart,
Dart_handle d2): Base(amap, adart, d2)
{}
/// Prefix ++ operator.
Self& operator++()
{
if (!m_second_way)
{
if (this->mmap.template is_free<2>(this->m_curdart))
{
m_second_way=true;
this->m_curdart=this->mmap.template beta<0>(this->m_firstdart);
if (this->mmap.template is_free<2>(this->m_curdart))
{ this->m_curdart=Dart_handle(); }
else { this->m_curdart=this->mmap.template beta<2>(this->m_curdart); }
}
else
{
this->m_curdart=this->mmap.template beta<2, 1>(this->m_curdart);
if (this->m_curdart==this->m_firstdart)
{ this->m_curdart=Dart_handle(); }
}
}
else
{
this->m_curdart=this->mmap.template beta<0>(this->m_curdart);
if (this->mmap.template is_free<2>(this->m_curdart))
{ this->m_curdart=Dart_handle(); }
else { this->m_curdart=this->mmap.template beta<2>(this->m_curdart); }
}
return *this;
}
/// Postfix ++ operator.
Self operator++(int)
{ Self res=*this; operator ++(); return res; }
protected:
/// True if we already found a border dart, and thus turn in the second way
bool m_second_way;
};
template<typename Map_>
class FGW_cell_iterator<Map_, 1>: public FGW_basis_for_cell_iterator<Map_> // Edge
{
public:
typedef FGW_cell_iterator Self;
typedef FGW_basis_for_cell_iterator<Map_> Base;
typedef Map_ Map;
typedef typename Map::Dart_handle Dart_handle;
typedef typename Map::size_type size_type;
FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart)
{}
/// Constructor with two darts in parameter (for end iterator).
FGW_cell_iterator(const Map& amap, Dart_handle adart,
Dart_handle d2): Base(amap, adart, d2)
{}
/// Prefix ++ operator.
Self& operator++()
{
if (this->m_curdart==this->m_firstdart)
{
if (this->mmap.template is_free<2>(this->m_curdart))
{ this->m_curdart=Dart_handle(); }
else { this->m_curdart=this->mmap.template beta<2>(this->m_curdart); }
}
else
{ this->m_curdart=Dart_handle(); }
return *this;
}
/// Postfix ++ operator.
Self operator++(int)
{ Self res=*this; operator ++(); return res; }
};
template<typename Map_>
class FGW_cell_iterator<Map_, 2>: public FGW_basis_for_cell_iterator<Map_> // Face
{
public:
typedef FGW_cell_iterator Self;
typedef FGW_basis_for_cell_iterator<Map_> Base;
typedef Map_ Map;
typedef typename Map::Dart_handle Dart_handle;
typedef typename Map::size_type size_type;
FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart)
{}
/// Constructor with two darts in parameter (for end iterator).
FGW_cell_iterator(const Map& amap, Dart_handle adart,
Dart_handle d2): Base(amap, adart, d2)
{}
/// Prefix ++ operator.
Self& operator++()
{
this->m_curdart=this->mmap.template beta<1>(this->m_curdart);
if (this->m_curdart==this->m_firstdart)
{ this->m_curdart=Dart_handle(); }
return *this;
}
/// Postfix ++ operator.
Self operator++(int)
{ Self res=*this; operator ++(); return res; }
};
template<typename Map_>
class FGW_cell_iterator<Map_, 3>: public FGW_basis_for_cell_iterator<Map_> // CC
{
public:
typedef FGW_cell_iterator Self;
typedef FGW_basis_for_cell_iterator<Map_> Base;
typedef Map_ Map;
typedef typename Map::Dart_handle Dart_handle;
typedef typename Map::size_type size_type;
FGW_cell_iterator(const Map& amap, Dart_handle adart) : Base(amap, adart)
{ m_mark=this->mmap.get_new_mark(); }
/// Constructor with two darts in parameter (for end iterator).
FGW_cell_iterator(const Map& amap, Dart_handle adart,
Dart_handle d2): Base(amap, adart, d2)
{ m_mark=this->mmap.get_new_mark(); }
~FGW_cell_iterator()
{ this->mmap.free_mark(m_mark); }
/// Prefix ++ operator.
Self& operator++()
{
if (!this->mmap.is_marked(this->mmap.template beta<1>(this->m_curdart), m_mark))
{
m_to_treat.push(this->mmap.template beta<1>(this->m_curdart));
this->mmap.mark(this->mmap.template beta<1>(this->m_curdart), m_mark);
}
if (!this->mmap.template is_free<2>(this->m_curdart) &&
!this->mmap.is_marked(this->mmap.template beta<2>(this->m_curdart), m_mark))
{
m_to_treat.push(this->mmap.template beta<2>(this->m_curdart));
this->mmap.mark(this->mmap.template beta<2>(this->m_curdart), m_mark);
}
if (m_to_treat.empty())
{ this->m_curdart=Dart_handle(); }
else
{ this->m_curdart=m_to_treat.top(); m_to_treat.pop(); }
return *this;
}
/// Postfix ++ operator.
Self operator++(int)
{ Self res=*this; operator ++(); return res; }
protected:
typename Map_::size_type m_mark;
std::stack<Dart_handle> m_to_treat;
};
////////////////////////////////////////////////////////////////////////////////
} // namespace CGAL
#endif // CGAL_ITERATORS_FOR_FACE_GRAPH_WRAPPER_H //
// EOF //

View File

@ -1,5 +1,6 @@
Algebraic_foundations
Arithmetic_kernel
BGL
Cartesian_kernel
Circulator
Combinatorial_map
@ -17,5 +18,7 @@ Kernel_d
Modular_arithmetic
Number_types
Profiling_tools
Property_map
STL_Extension
Stream_support
Random_numbers

View File

@ -16,6 +16,11 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "${cppfile}" )
endforeach()
find_package( OpenMesh QUIET )
if (TARGET OpenMesh::OpenMesh)
target_link_libraries(Combinatorial_map_copy_test PRIVATE OpenMesh::OpenMesh)
endif()
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")

View File

@ -1,6 +1,13 @@
#include <CGAL/Combinatorial_map.h>
#include <CGAL/Cell_attribute.h>
#include "Combinatorial_map_test_iterators.h"
#include <CGAL/HalfedgeDS_default.h>
#if CGAL_USE_OPENMESH
# include <OpenMesh/Core/IO/MeshIO.hh>
# include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
# include <CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h>
typedef OpenMesh::TriMesh_ArrayKernelT</* MyTraits*/> OpenMesh_mesh;
#endif // CGAL_USE_OPENMESH
#include <iostream>
#include <fstream>
@ -152,6 +159,10 @@ typedef CGAL::Combinatorial_map<4, Map_dart_items_4> Map8;
// info=char, int, int, int, int, double
typedef CGAL::Combinatorial_map<4, Map_dart_max_items_4> Map9;
struct Traits { typedef int Point_2; typedef int Point_3; };
typedef CGAL::HalfedgeDS_default<Traits> HDS;
////////////////////////////////////////////////////////////////////////////////
template<typename Map, unsigned int i, typename Attr=typename Map::
template Attribute_type<i>::type>
struct CreateAttributes
@ -579,6 +590,31 @@ bool testCopy()
return true;
}
bool testImportFromHalfedge()
{
bool res=true;
HDS hds;
CGAL::HalfedgeDS_decorator<HDS> decorator(hds);
decorator.create_loop();
decorator.create_segment();
Map1 map1; map1.import_from_halfedge_graph(hds);
Map2 map2; map2.import_from_halfedge_graph(hds);
Map3 map3; map3.import_from_halfedge_graph(hds);
#if CGAL_USE_OPENMESH
{
// test the compilation, with an empty mesh
OpenMesh_mesh hds;
Map1 map1; map1.import_from_halfedge_graph(hds);
Map2 map2; map2.import_from_halfedge_graph(hds);
Map3 map3; map3.import_from_halfedge_graph(hds);
}
#endif // CGAL_USE_OPENMESH
return res; // TODO compare number of darts/cells
}
int main()
{
std::cout<<"Combinatorial map copy test (v1)."<<std::flush;

View File

@ -1,5 +1,10 @@
#include <CGAL/Combinatorial_map.h>
#include <CGAL/Cell_attribute.h>
#include <CGAL/Face_graph_wrapper.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include "Combinatorial_map_2_test.h"
#include "Combinatorial_map_3_test.h"
@ -193,8 +198,64 @@ bool test_get_new_mark()
return true;
}
bool test_face_graph_wrapper()
{
bool res=true;
typedef CGAL::Surface_mesh<CGAL::Simple_cartesian<double>::Point_3> SMesh;
SMesh m;
std::ifstream in1("data/head.off");
if (in1.fail())
{
std::cout<<"Error: impossible to open 'data/head.off'"<<std::endl;
return false;
}
in1>>m;
CGAL::Face_graph_wrapper<SMesh> fgw1(m);
std::vector<unsigned int> cells=fgw1.count_all_cells();
if (cells[0]!=1487 || cells[1]!=4406 || cells[2]!=2921 ||
fgw1.number_of_darts()!=8812)
{
std::cout<<"Error: incorrect number of cells in test_face_graph_wrapper "
<<"for Surface_mesh: "
<<cells[0]<<", "<<cells[1]<<", "<<cells[2]<<", "<<fgw1.number_of_darts()
<<std::endl;
res=false;
}
typedef CGAL::Polyhedron_3<CGAL::Simple_cartesian<double> > Polyhedron;
Polyhedron p;
std::ifstream in2("data/head.off");
if (in2.fail())
{
std::cout<<"Error: impossible to open 'data/head.off'"<<std::endl;
return false;
}
in2>>p;
CGAL::Face_graph_wrapper<Polyhedron> fgw2(p);
cells=fgw2.count_all_cells();
if (cells[0]!=1487 || cells[1]!=4406 || cells[2]!=2921 ||
fgw2.number_of_darts()!=8812)
{
std::cout<<"Error: incorrect number of cells in test_face_graph_wrapper "
<<"for Polyhedron."
<<cells[0]<<", "<<cells[1]<<", "<<cells[2]<<", "<<fgw2.number_of_darts()
<<std::endl;
res=false;
}
return res;
}
int main()
{
if (!test_face_graph_wrapper())
{
std::cout<<"ERROR during test_face_graph_wrapper."<<std::endl;
return EXIT_FAILURE;
}
if ( !test_get_new_mark() )
{
std::cout<<"ERROR during test_get_new_mark."<<std::endl;

File diff suppressed because it is too large Load Diff

View File

@ -102,3 +102,5 @@ Classification
Hyperbolic_triangulation_2
Periodic_4_hyperbolic_triangulation_2
Surface_mesh_approximation
Surface_mesh_topology

View File

@ -119,6 +119,7 @@
\package_listing{Stream_lines_2}
\package_listing{Classification}
\package_listing{Heat_method_3}
\package_listing{Surface_mesh_topology}
\cgalPackageSection{PartSearchStructures,Spatial Searching and Sorting}

View File

@ -152023,3 +152023,21 @@ pages = {179--189}
HAL_ID = {inria-00412437},
HAL_VERSION = {v1},
}
@InProceedings{ew-tcsr-13,
Title = {Transforming curves on surfaces redux},
Author = {Erickson, Jeff and Whittelsey, Kim},
Booktitle = {24rd Annual ACM-SIAM Symposium on Discrete Algorithms (SODA)},
Year = {2013},
Pages = {1646--1655},
Url = {http://jeffe.cs.illinois.edu/pubs/pdf/dehn.pdf}
}
@InProceedings{lr-hts-12,
Title = {On the homotopy test on surfaces},
Author = {Lazarus, Francis and Rivaud, Julien},
Booktitle = {53rd Annual IEEE Symposium on Foundations of Computer Science (FOCS)},
Year = {2012},
Pages = {440-449},
Url = {http://arxiv.org/abs/1110.4573}
}

View File

@ -339,3 +339,9 @@ div.fragment {
padding: 4px;
margin: 1em 4px 1em 4px;
}
/* Make summary smaller to avoid wrapping of classes and concepts */
div.summary
{
width: auto;
}

View File

@ -339,3 +339,9 @@ div.fragment {
padding: 4px;
margin: 1em 4px 1em 4px;
}
/* Make summary smaller to avoid wrapping of classes and concepts */
div.summary
{
width: auto;
}

View File

@ -329,3 +329,10 @@ div.fragment {
padding: 4px;
margin: 1em 4px 1em 4px;
}
/* Make summary smaller to avoid wrapping of classes and concepts */
div.summary
{
width: auto;
}

View File

@ -181,13 +181,22 @@ namespace CGAL {
* @param amap the generalized map to copy.
* @post *this is valid.
*/
template <typename GMap2, typename Converters, typename DartInfoConverter,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter,
typename PointConverter>
void copy(const GMap2& amap, const Converters& converters,
void copy(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter,
boost::unordered_map<typename GMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
boost::unordered_map
<typename Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>::
Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Generalized_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
typedef Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2> GMap2;
this->clear();
this->mnb_used_marks = amap.mnb_used_marks;
@ -207,107 +216,145 @@ namespace CGAL {
// Create an mapping between darts of the two maps (originals->copies).
// (here we cannot use CGAL::Unique_hash_map because it does not provide
// iterators...
boost::unordered_map<typename GMap2::Dart_const_handle, Dart_handle> local_dartmap;
if (dart_mapping==nullptr)
{ dart_mapping=&local_dartmap; }
boost::unordered_map<typename GMap2::Dart_const_handle, Dart_handle>
local_dartmap;
if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map
{ origin_to_copy=&local_dartmap; }
Dart_handle new_dart;
for (typename GMap2::Dart_const_range::const_iterator
it=amap.darts().begin(), itend=amap.darts().end();
it!=itend; ++it)
{
(*dart_mapping)[it]=mdarts.emplace();
init_dart((*dart_mapping)[it], amap.get_marks(it));
internal::Copy_dart_info_functor<GMap2, Refs, DartInfoConverter>::
run(amap, static_cast<Refs&>(*this), it, (*dart_mapping)[it],
dartinfoconverter);
new_dart=mdarts.emplace();
init_dart(new_dart, amap.get_marks(it));
(*origin_to_copy)[it]=new_dart;
if (copy_to_origin!=NULL) { (*copy_to_origin)[new_dart]=it; }
internal::Copy_dart_info_functor<Refs2, Refs, DartInfoConverter>::
run(static_cast<const Refs2&>(amap), static_cast<Refs&>(*this),
it, new_dart, dartinfoconverter);
}
unsigned int min_dim=(dimension<amap.dimension?dimension:amap.dimension);
typename boost::unordered_map<typename GMap2::Dart_const_handle,Dart_handle>
::iterator dartmap_iter, dartmap_iter_end=dart_mapping->end();
for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end;
::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end();
for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
++dartmap_iter)
{
for (unsigned int i=0; i<=min_dim; i++)
{
if (!amap.is_free(dartmap_iter->first,i) &&
(dartmap_iter->first)<(amap.alpha(dartmap_iter->first,i)))
is_free(dartmap_iter->second,i))
{
basic_link_alpha(dartmap_iter->second,
(*dart_mapping)[amap.alpha(dartmap_iter->first,i)], i);
(*origin_to_copy)[amap.alpha(dartmap_iter->first,i)], i);
}
}
}
/** Copy attributes */
for (dartmap_iter=dart_mapping->begin(); dartmap_iter!=dartmap_iter_end;
for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
++dartmap_iter)
{
Helper::template Foreach_enabled_attributes
< internal::Copy_attributes_functor <GMap2, Refs, Converters,
< internal::Copy_attributes_functor<Refs2, Refs, Converters,
PointConverter> >::
run(amap, static_cast<Refs&>(*this),
run(static_cast<const Refs2&>(amap), static_cast<Refs&>(*this),
dartmap_iter->first, dartmap_iter->second,
converters, pointconverter);
}
CGAL_assertion (is_valid () == 1);
CGAL_assertion(is_valid());
}
template <typename GMap2>
void copy(const GMap2& amap,
boost::unordered_map<typename GMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2>
void copy(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
boost::unordered_map
<typename Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>::
Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Generalized_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
std::tuple<> converters;
Default_converter_dart_info<GMap2, Refs> dartinfoconverter;
Default_converter_cmap_0attributes_with_point<GMap2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping);
CGAL::cpp11::tuple<> converters;
Default_converter_dart_info<Refs2, Refs> dartinfoconverter;
Default_converter_cmap_0attributes_with_point<Refs2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter,
origin_to_copy, copy_to_origin);
}
template <typename GMap2, typename Converters>
void copy(const GMap2& amap, const Converters& converters,
boost::unordered_map<typename GMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters>
void copy(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
boost::unordered_map
<typename Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>::
Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Generalized_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
Default_converter_cmap_0attributes_with_point<GMap2, Refs> pointconverter;
Default_converter_dart_info<GMap2, Refs> dartinfoconverter;
copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping);
Default_converter_cmap_0attributes_with_point<Refs2, Refs> pointconverter;
Default_converter_dart_info<Refs2, Refs> dartinfoconverter;
copy(amap, converters, dartinfoconverter, pointconverter,
origin_to_copy, copy_to_origin);
}
template <typename GMap2, typename Converters, typename DartInfoConverter>
void copy(const GMap2& amap, const Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter>
void copy(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
boost::unordered_map<typename GMap2::Dart_const_handle, Dart_handle>* dart_mapping=nullptr)
boost::unordered_map
<typename Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>::
Dart_const_handle, Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle, typename Generalized_map_base<d2, Refs2, Items2,
Alloc2, Storage2>::Dart_const_handle>* copy_to_origin=NULL)
{
Default_converter_cmap_0attributes_with_point<GMap2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter, dart_mapping);
Default_converter_cmap_0attributes_with_point<Refs2, Refs> pointconverter;
copy(amap, converters, dartinfoconverter, pointconverter,
origin_to_copy, copy_to_origin);
}
// Copy constructor from a map having exactly the same type.
Generalized_map_base (const Self & amap)
{ copy<Self>(amap); }
// "Copy constructor" from a map having different type.
template <typename GMap2>
Generalized_map_base(const GMap2& amap)
{ copy(amap); }
// "Copy constructor" from a map having different type.
template <typename GMap2, typename Converters>
Generalized_map_base(const GMap2& amap, Converters& converters)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2>
Generalized_map_base(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap)
{ copy(amap); }
// "Copy constructor" from a map having different type.
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters>
Generalized_map_base(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters)
{ copy(amap, converters); }
// "Copy constructor" from a map having different type.
template <typename GMap2, typename Converters, typename DartInfoConverter>
Generalized_map_base(const GMap2& amap, Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter>
Generalized_map_base(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter)
{ copy(amap, converters, dartinfoconverter); }
// "Copy constructor" from a map having different type.
template <typename GMap2, typename Converters, typename DartInfoConverter,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter,
typename PointConverter>
Generalized_map_base(const GMap2& amap, Converters& converters,
Generalized_map_base(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter)
{ copy(amap, converters, dartinfoconverter, pointconverter); }
@ -579,6 +626,11 @@ namespace CGAL {
Dart_const_handle next(Dart_const_handle ADart) const
{ return this->template alpha<0, 1>(ADart); }
Dart_handle opposite2(Dart_handle ADart)
{ return this->template alpha<0, 2>(ADart); }
Dart_const_handle opposite2(Dart_const_handle ADart) const
{ return this->template alpha<0, 2>(ADart); }
template<unsigned int dim>
Dart_handle opposite(Dart_handle ADart)
{ return this->template alpha<0, dim>(ADart); }
@ -849,6 +901,27 @@ namespace CGAL {
mnb_times_reserved_marks[amark]=0;
}
template <unsigned int i, unsigned int d=dimension>
bool belong_to_same_cell(Dart_const_handle adart1,
Dart_const_handle adart2) const
{ return CGAL::belong_to_same_cell<Self, i, d>(*this, adart1, adart2); }
template <unsigned int i, unsigned int d=dimension>
bool is_whole_cell_unmarked(Dart_const_handle adart, size_type amark) const
{ return CGAL::is_whole_cell_unmarked<Self, i, d>(*this, adart, amark); }
template <unsigned int i, unsigned int d=dimension>
bool is_whole_cell_marked(Dart_const_handle adart, size_type amark) const
{ return CGAL::is_whole_cell_marked<Self, i, d>(*this, adart, amark); }
template <unsigned int i, unsigned int d=dimension>
size_type mark_cell(Dart_const_handle adart, size_type amark) const
{ return CGAL::mark_cell<Self, i, d>(*this, adart, amark); }
template <unsigned int i, unsigned int d=dimension>
size_type unmark_cell(Dart_const_handle adart, size_type amark) const
{ return CGAL::unmark_cell<Self, i, d>(*this, adart, amark); }
/** Test if this map is without boundary for a given dimension.
* @param i the dimension.
* @return true iff all the darts are not i-free.
@ -1647,6 +1720,61 @@ namespace CGAL {
}
public:
/// @return the positive turn between the two given darts.
// @pre next(d1) and d2 must belong to the same vertex.
std::size_t positive_turn(Dart_const_handle d1, Dart_const_handle d2) const
{
CGAL_assertion((!this->template is_free<1>(d1)));
/* CGAL_assertion((belong_to_same_cell<0>(this->next(d1), d2))); */
if (d2==opposite2(d1)) { return 0; }
Dart_const_handle dd1=d1;
std::size_t res=1;
while (next(dd1)!=d2)
{
if (this->template is_free<2>(next(dd1)))
{ return std::numeric_limits<std::size_t>::max(); }
++res;
dd1=opposite2(next(dd1));
CGAL_assertion(!this->template is_free<1>(dd1));
CGAL_assertion(next(dd1)==d2 || dd1!=d1);
}
return res;
}
/// @return the negative turn between the two given darts.
// @pre next(d1) and d2 must belong to the same vertex.
std::size_t negative_turn(Dart_const_handle d1, Dart_const_handle d2) const
{
CGAL_assertion((!this->template is_free<1>(d1)));
/* CGAL_assertion((belong_to_same_cell<0>(this->next(d1), d2))); */
if (d2==opposite2(d1)) { return 0; }
if (this->template is_free<2>(d1) || this->template is_free<2>(d2))
{ return std::numeric_limits<std::size_t>::max(); }
d1=opposite2(d1);
d2=opposite2(d2);
Dart_const_handle dd1=d1;
std::size_t res=1;
while (previous(dd1)!=d2)
{
if (this->template is_free<2>(previous(dd1)))
{ return std::numeric_limits<std::size_t>::max(); }
++res;
dd1=opposite2(previous(dd1));
CGAL_assertion(!this->template is_free<0>(dd1));
CGAL_assertion(previous(dd1)==d2 || dd1!=d1);
}
return res;
}
/** Erase marked darts from the map.
* Marked darts are unlinked before to be removed, thus surviving darts
* are correctly linked, but the map is not necessarily valid depending
@ -1666,7 +1794,7 @@ namespace CGAL {
if (is_marked(d, amark))
{
for ( i = 0; i <= dimension; ++i)
{ if (!is_free(d, i)) unlink_beta(d, i); }
{ if (!is_free(d, i)) topo_unsew(d, i); }
erase_dart(d); ++res;
}
}
@ -2766,12 +2894,12 @@ namespace CGAL {
!is_face_combinatorial_polygon(d4, 3) ) return false;
// TODO do better with marks (?).
if ( belong_to_same_cell<Self,2,1>(*this, d1, d2) ||
belong_to_same_cell<Self,2,1>(*this, d1, d3) ||
belong_to_same_cell<Self,2,1>(*this, d1, d4) ||
belong_to_same_cell<Self,2,1>(*this, d2, d3) ||
belong_to_same_cell<Self,2,1>(*this, d2, d4) ||
belong_to_same_cell<Self,2,1>(*this, d3, d4) ) return false;
if ( belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d3, d4) ) return false;
if ( alpha(d1, 0,1,2)!=alpha(d3,1) ||
alpha(d4, 1,2)!=alpha(d3,0,1) ||
@ -2847,21 +2975,21 @@ namespace CGAL {
!is_face_combinatorial_polygon(d6, 4) ) return false;
// TODO do better with marks.
if ( belong_to_same_cell<Self,2,1>(*this, d1, d2) ||
belong_to_same_cell<Self,2,1>(*this, d1, d3) ||
belong_to_same_cell<Self,2,1>(*this, d1, d4) ||
belong_to_same_cell<Self,2,1>(*this, d1, d5) ||
belong_to_same_cell<Self,2,1>(*this, d1, d6) ||
belong_to_same_cell<Self,2,1>(*this, d2, d3) ||
belong_to_same_cell<Self,2,1>(*this, d2, d4) ||
belong_to_same_cell<Self,2,1>(*this, d2, d5) ||
belong_to_same_cell<Self,2,1>(*this, d2, d6) ||
belong_to_same_cell<Self,2,1>(*this, d3, d4) ||
belong_to_same_cell<Self,2,1>(*this, d3, d5) ||
belong_to_same_cell<Self,2,1>(*this, d3, d6) ||
belong_to_same_cell<Self,2,1>(*this, d4, d5) ||
belong_to_same_cell<Self,2,1>(*this, d4, d6) ||
belong_to_same_cell<Self,2,1>(*this, d5, d6) )
if ( belong_to_same_cell<2,1>(d1, d2) ||
belong_to_same_cell<2,1>(d1, d3) ||
belong_to_same_cell<2,1>(d1, d4) ||
belong_to_same_cell<2,1>(d1, d5) ||
belong_to_same_cell<2,1>(d1, d6) ||
belong_to_same_cell<2,1>(d2, d3) ||
belong_to_same_cell<2,1>(d2, d4) ||
belong_to_same_cell<2,1>(d2, d5) ||
belong_to_same_cell<2,1>(d2, d6) ||
belong_to_same_cell<2,1>(d3, d4) ||
belong_to_same_cell<2,1>(d3, d5) ||
belong_to_same_cell<2,1>(d3, d6) ||
belong_to_same_cell<2,1>(d4, d5) ||
belong_to_same_cell<2,1>(d4, d6) ||
belong_to_same_cell<2,1>(d5, d6) )
return false;
if ( alpha(d1,2) !=alpha(d4,1,0,1) ||
@ -3020,7 +3148,7 @@ namespace CGAL {
return alpha<0, 1>(adart);
}
/** Insert a vertex in the given 2-cell which is splitted in triangles,
/** Insert a vertex in the given 2-cell which is split in triangles,
* once for each inital edge of the facet.
* @param adart a dart of the facet to triangulate.
* @return A dart incident to the new vertex.
@ -3341,14 +3469,14 @@ namespace CGAL {
if (prec!=null_handle)
{
// prec and *it must belong to the same vertex of the same volume
if ( !CGAL::belong_to_same_cell<Self, 0, 2>(*this, prec, *it) )
if ( !belong_to_same_cell<0, 2>(prec, *it) )
return false;
}
prec = this->template alpha<0>(*it);
}
// The path must be closed.
if (!CGAL::belong_to_same_cell<Self, 0, 2>(*this, prec, *afirst))
if (!belong_to_same_cell<0, 2>(prec, *afirst))
return false;
return true;
@ -3589,24 +3717,34 @@ namespace CGAL {
Generalized_map(const Self & amap) : Base(amap)
{}
template < class Gmap >
Generalized_map(const Gmap & amap) : Base(amap)
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2>
Generalized_map(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap) :
Base(amap)
{}
template < class Gmap, typename Converters >
Generalized_map(const Gmap & amap, const Converters& converters) :
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2, typename Converters>
Generalized_map(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters) :
Base(amap, converters)
{}
template < class Gmap, typename Converters, typename DartInfoConverter >
Generalized_map(const Gmap & amap, const Converters& converters,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter>
Generalized_map(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter) :
Base(amap, converters, dartinfoconverter)
{}
template < class Gmap, typename Converters, typename DartInfoConverter,
template <unsigned int d2, typename Refs2, typename Items2, typename Alloc2,
typename Storage2,
typename Converters, typename DartInfoConverter,
typename PointConverter >
Generalized_map(const Gmap & amap, const Converters& converters,
Generalized_map(const Generalized_map_base<d2, Refs2, Items2, Alloc2, Storage2>& amap,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter) :
Base(amap, converters, dartinfoconverter, pointconverter)

View File

@ -123,6 +123,8 @@ namespace CGAL {
CGAL_assertion(i <= dimension);
return dh->mf[i]==dh;
}
bool is_perforated(Dart_const_handle /*dh*/) const
{ return false; }
/// Set simultaneously all the marks of this dart to a given value.
void set_dart_marks(Dart_const_handle ADart,

View File

@ -406,8 +406,8 @@ public:
if (m_points_of_face.size()<3)
{
std::cerr<<"PB: you try to triangulate a face with "<<m_points_of_face.size()<<" vertices."
<<std::endl;
/* std::cerr<<"PB: you try to triangulate a face with "<<m_points_of_face.size()<<" vertices."
<<std::endl; */
m_face_started=false;
m_points_of_face.clear();
@ -526,6 +526,7 @@ public:
}
return true;
}
CGAL::Bbox_3 *bb() const { return m_bb; }
protected:

View File

@ -1223,6 +1223,7 @@ protected:
setKeyDescription(::Qt::Key_M, "Toggles mono color");
setKeyDescription(::Qt::Key_N, "Inverse direction of normals");
setKeyDescription(::Qt::Key_T, "Toggles text display");
setKeyDescription(::Qt::Key_U, "Move camera direction upside down");
setKeyDescription(::Qt::Key_V, "Toggles vertices display");
setKeyDescription(::Qt::Key_Plus, "Increase size of edges");
setKeyDescription(::Qt::Key_Minus, "Decrease size of edges");
@ -1305,6 +1306,30 @@ protected:
negate_all_normals();
redraw();
}
else if ((e->key()==::Qt::Key_U) && (modifiers==::Qt::NoButton))
{
if (is_two_dimensional())
{
displayMessage(QString("Move camera direction upside down."));
/* CGAL::qglviewer::Vec cur=camera()->viewDirection();
double cx=cur.x, cy=cur.y, cz=cur.z;
if (has_zero_x()) { cx=-cx; }
else if (has_zero_y()) { cy=-cy; }
else { cz=-cz; }
double cx=0., cy=0., cz=0.;
if (has_zero_x()) { cx=(cur.x<0?-1.:1); }
else if (has_zero_y()) { cy=(cur.y<0?-1.:1); }
else { cz=(cur.z<0?-1.:1); }*/
camera()->setUpVector(-camera()->upVector());
//camera()->frame()->setConstraint(NULL);
// camera()->setViewDirection(CGAL::qglviewer::Vec(-cx,-cy,-cz));
//constraint.setRotationConstraintDirection(CGAL::qglviewer::Vec(cx, cy, cz));
//camera()->frame()->setConstraint(&constraint);
//update();
redraw();
}
}
else if ((e->key()==::Qt::Key_T) && (modifiers==::Qt::NoButton))
{
m_draw_text=!m_draw_text;

View File

@ -195,7 +195,6 @@ void
DemosMainWindow::setUseAntialiasing(bool checked)
{
view->setRenderHint(QPainter::Antialiasing, checked);
view->setRenderHint(QPainter::HighQualityAntialiasing, checked);
statusBar()->showMessage(tr("Antialiasing %1activated").arg(checked?"":"de-"),
1000);

View File

@ -21,6 +21,7 @@
#include <QDateTime>
#include <QString>
#include <QTimer>
#include <QElapsedTimer>
namespace CGAL{
namespace qglviewer {
@ -348,7 +349,7 @@ private:
qreal zoomSensitivity_;
// Mouse speed and spinning
QTime last_move_time;
QElapsedTimer last_move_time;
qreal mouseSpeed_;
int delay_;
bool isSpinning_;

View File

@ -28,7 +28,7 @@
#include <QOpenGLBuffer>
#include <QMap>
#include <QVector>
#include <QTime>
#include <QElapsedTimer>
#include <QTimer>
#include <QGLContext>
#include <QOpenGLWidget>
@ -1038,7 +1038,7 @@ protected:
int animationTimerId_;
// F P S d i s p l a y
QTime fpsTime_;
QElapsedTimer fpsTime_;
unsigned int fpsCounter_;
QString fpsString_;
qreal f_p_s_;

View File

@ -46,6 +46,7 @@
#include <QColorDialog>
#include <QOpenGLFramebufferObject>
#include <QFileDialog>
#include <QElapsedTimer>
namespace CGAL{
// Static private variable
@ -2244,7 +2245,7 @@ void CGAL::QGLViewer::keyPressEvent(QKeyEvent *e) {
unsigned int index = pathIndex_[::Qt::Key(key)];
// not safe, but try to double press on two viewers at the same time !
static QTime doublePress;
static QElapsedTimer doublePress;
if (modifiers == playPathKeyboardModifiers()) {
int elapsed = doublePress.restart();

View File

@ -1,17 +1,31 @@
Release History
===============
Release 5.1
[Release 5.1] (https://github.com/CGAL/cgal/releases/tag/releases%2FCGAL-5.1)
-----------
Release date: June 2020
### Surface Mesh Topology (new package)
- This package allows to compute some topological invariants of
surfaces. For now, it is possible to test if two (closed) curves
on a combinatorial surface are homotopic. The user can choose
between free homotopy and homotopy with fixed endpoints.
A contractibility test is also provided.
### 3D Fast Intersection and Distance Computation
- **Breaking change**: the internal search tree is now lazily constructed. To disable it, one must call
the new function `do_not_accelerate_distance_queries()` before the first distance query.
### Polygon Mesh Processing
- Introduced a new function, `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`,
which can be used to remove connected components whose area or volume is under a certain threshold.
Area and volume thresholds are either specified by the user or deduced from the bounding box of the mesh.
- Added a new named parameter for `keep_large_connected_components()` and `remove_connected_components_of_negligible_size`
that can be used to perform a dry run of the operation, meaning that the function will return the number of connected
components that would be removed with the specified threshold, but without actually removing them.
- The function `CGAL::Polygon_mesh_processing::stitch_borders()` now returns the number
of halfedge pairs that were stitched.

View File

@ -55,7 +55,7 @@ set(CGAL_ImageIO_USE_ZLIB "@CGAL_ImageIO_USE_ZLIB@" )
set(CGAL_VERSION "${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}.${CGAL_BUGFIX_VERSION}")
set(CGAL_USE_FILE "${CGAL_MODULES_DIR}/UseCGAL.cmake" )
set(CGAL_GRAPHICSVIEW_PACKAGE_DIR "${CGAL_INCLUDE_DIRS}/CGAL/" CACHE INTERNAL "Directory containing the GraphicsView package")
set(CGAL_GRAPHICSVIEW_PACKAGE_DIR "${CGAL_INSTALL_PREFIX}" CACHE INTERNAL "Directory containing the GraphicsView package")
if ( CGAL_FIND_REQUIRED )
set( CHECK_CGAL_COMPONENT_MSG_ON_ERROR TRUE )

View File

@ -15,7 +15,7 @@ if (NOT GLPK_FOUND)
)
find_library(GLPK_LIBRARIES
NAMES libglpk
NAMES libglpk glpk
PATHS ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/local/lib

View File

@ -6,6 +6,8 @@
# OPENMESH_LIBRARIES - OpenMesh libraries
#
find_package(OpenMesh NO_MODULE QUIET)
# Is it already configured?
if (NOT OpenMesh_FOUND)
@ -44,7 +46,34 @@ endif()
include( FindPackageHandleStandardArgs )
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenMesh
find_package_handle_standard_args(OpenMesh
REQUIRED_VARS OPENMESH_INCLUDE_DIR OPENMESH_LIBRARIES
FOUND_VAR OpenMesh_FOUND
)
if(OpenMesh_FOUND AND NOT TARGET OpenMesh::OpenMesh)
add_library(OpenMesh::OpenMesh UNKNOWN IMPORTED)
if(TARGET OpenMeshCore)
target_link_libraries(OpenMesh::OpenMesh PUBLIC OpenMeshCore)
return()
endif()
set_target_properties(OpenMesh::OpenMesh PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "CGAL_USE_OPENMESH;NOMINMAX;_USE_MATH_DEFINES"
INTERFACE_INCLUDE_DIRECTORIES "${OPENMESH_INCLUDE_DIR}")
if(OPENMESH_LIBRARY_RELEASE)
set_property(TARGET OpenMesh::OpenMesh APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(OpenMesh::OpenMesh PROPERTIES
IMPORTED_LOCATION_RELEASE "${OPENMESH_LIBRARY_RELEASE}")
endif()
if(OPENMESH_LIBRARY_DEBUG)
set_property(TARGET OpenMesh::OpenMesh APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(OpenMesh::OpenMesh PROPERTIES
IMPORTED_LOCATION_DEBUG "${OPENMESH_LIBRARY_DEBUG}")
endif()
endif()

View File

@ -0,0 +1,54 @@
// Copyright (c) 2016 GeometryFactory SARL (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Andreas Fabri
//
// Warning: this file is generated, see include/CGAL/licence/README.md
#ifndef CGAL_LICENSE_SURFACE_MESH_TOPOLOGY_H
#define CGAL_LICENSE_SURFACE_MESH_TOPOLOGY_H
#include <CGAL/config.h>
#include <CGAL/license.h>
#ifdef CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE
# if CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
# if defined(CGAL_LICENSE_WARNING)
CGAL_pragma_warning("Your commercial license for CGAL does not cover "
"this release of the Surface Mesh Topology package.")
# endif
# ifdef CGAL_LICENSE_ERROR
# error "Your commercial license for CGAL does not cover this release \
of the Surface Mesh Topology package. \
You get this error, as you defined CGAL_LICENSE_ERROR."
# endif // CGAL_LICENSE_ERROR
# endif // CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
#else // no CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE
# if defined(CGAL_LICENSE_WARNING)
CGAL_pragma_warning("\nThe macro CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE is not defined."
"\nYou use the CGAL Surface Mesh Topology package under "
"the terms of the GPLv3+.")
# endif // CGAL_LICENSE_WARNING
# ifdef CGAL_LICENSE_ERROR
# error "The macro CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE is not defined.\
You use the CGAL Surface Mesh Topology package under the terms of \
the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR."
# endif // CGAL_LICENSE_ERROR
#endif // no CGAL_SURFACE_MESH_TOPOLOGY_COMMERCIAL_LICENSE
#endif // CGAL_LICENSE_SURFACE_MESH_TOPOLOGY_H

View File

@ -82,6 +82,7 @@ Surface_mesh_segmentation Triangulated Surface Mesh Segmentation
Surface_mesh_shortest_path Triangulated Surface Mesh Shortest Paths
Surface_mesh_simplification Triangulated Surface Mesh Simplification
Surface_mesh_skeletonization Triangulated Surface Mesh Skeletonization
Surface_mesh_topology Surface Mesh Topology
Surface_sweep_2 2D Intersection of Curves
TDS_2 2D Triangulation Data Structure
TDS_3 3D Triangulation Data Structure

View File

@ -89,6 +89,7 @@ template <class R,int dim>
class Construct_bbox_projected_2 {
public:
typedef typename R::Point_3 Point;
typedef Bbox_2 result_type;
Bbox_2 operator()(const Point& p) const { typename R::Construct_bbox_3 bb; return Projector<R, dim>::bbox(bb(p)); }
};

View File

@ -24,7 +24,7 @@ endif()
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
# To use valgrind, we must disable rounding math ckeck.
# add_definition(-DCGAL_DISABLE_ROUNDING_MATH_CHECK)
# add_definitions(-DCGAL_DISABLE_ROUNDING_MATH_CHECK)
if (CGAL_FOUND)

View File

@ -150,6 +150,8 @@ namespace CGAL {
CGAL_assertion(i <= dimension);
return dh->mf[i]==null_dart_handle;
}
bool is_perforated(Dart_const_handle /*dh*/) const
{ return false; }
/// Set simultaneously all the marks of this dart to a given value.
void set_dart_marks(Dart_const_handle ADart,

View File

@ -142,6 +142,8 @@ namespace CGAL {
CGAL_assertion(i <= dimension);
return dh->mf[i]==dh;
}
bool is_perforated(Dart_const_handle /*dh*/) const
{ return false; }
/// Set simultaneously all the marks of this dart to a given value.
void set_dart_marks(Dart_const_handle ADart,

View File

@ -147,24 +147,46 @@ namespace CGAL {
Linear_cell_complex_base(const Self& alcc) : Base(alcc)
{}
template < class LCC2 >
Linear_cell_complex_base(const LCC2& alcc) : Base(alcc)
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Refs2, class Storage2>
Linear_cell_complex_base
(const Linear_cell_complex_base<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Refs2, Storage2>& alcc) : Base(alcc)
{}
template < class LCC2, typename Converters >
Linear_cell_complex_base(const LCC2& alcc, Converters& converters) :
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Refs2,
class Storage2, typename Converters>
Linear_cell_complex_base
(const Linear_cell_complex_base<d2, ambient_dim2, Traits2, Items2,
Alloc2, CMap2, Refs2, Storage2>& alcc, Converters& converters) :
Base(alcc, converters)
{}
template < class LCC2, typename Converters, typename DartInfoConverter >
Linear_cell_complex_base(const LCC2& alcc, Converters& converters,
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Refs2, class Storage2, typename Converters,
typename DartInfoConverter>
Linear_cell_complex_base
(const Linear_cell_complex_base<d2, ambient_dim2, Traits2, Items2,
Alloc2, CMap2, Refs2, Storage2>& alcc, Converters& converters,
const DartInfoConverter& dartinfoconverter) :
Base(alcc, converters, dartinfoconverter)
{}
template < class LCC2, typename Converters, typename DartInfoConverter,
typename Pointconverter >
Linear_cell_complex_base(const LCC2& alcc, Converters& converters,
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Refs2, class Storage2, typename Converters,
typename DartInfoConverter, typename Pointconverter>
Linear_cell_complex_base
(const Linear_cell_complex_base<d2, ambient_dim2, Traits2, Items2,
Alloc2, CMap2, Refs2, Storage2>& alcc, Converters& converters,
const DartInfoConverter& dartinfoconverter,
const Pointconverter& pointconverter) :
Base(alcc, converters, dartinfoconverter, pointconverter)

View File

@ -17,6 +17,7 @@
#include <CGAL/Linear_cell_complex_min_items.h>
#include <CGAL/Combinatorial_map.h>
#include <CGAL/CMap_linear_cell_complex_storages.h>
#include <CGAL/boost/graph/properties.h>
namespace CGAL {
@ -100,40 +101,119 @@ namespace CGAL {
* @param alcc the linear cell complex to copy.
* @post *this is valid.
*/
#ifdef DOXYGEN_RUNNING
Linear_cell_complex_for_combinatorial_map(const Self& alcc) : Base(alcc)
{}
#endif
template < class LCC2 >
Linear_cell_complex_for_combinatorial_map(const LCC2& alcc) : Base(alcc)
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2>
Linear_cell_complex_for_combinatorial_map
(const Linear_cell_complex_for_combinatorial_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc) : Base(alcc)
{}
template < class LCC2, typename Converters >
Linear_cell_complex_for_combinatorial_map(const LCC2& alcc,
Converters& converters) :
Base(alcc, converters)
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2, typename Converters>
Linear_cell_complex_for_combinatorial_map
(const Linear_cell_complex_for_combinatorial_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc,
const Converters& converters) : Base(alcc, converters)
{}
template < class LCC2, typename Converters, typename DartInfoConverter >
Linear_cell_complex_for_combinatorial_map(const LCC2& alcc,
Converters& converters,
const DartInfoConverter&
dartinfoconverter) :
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2, typename Converters, typename DartInfoConverter>
Linear_cell_complex_for_combinatorial_map
(const Linear_cell_complex_for_combinatorial_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc,
const Converters& converters,
const DartInfoConverter& dartinfoconverter) :
Base(alcc, converters, dartinfoconverter)
{}
template < class LCC2, typename Converters, typename DartInfoConverter,
typename PointConverter >
Linear_cell_complex_for_combinatorial_map(const LCC2& alcc,
Converters& converters,
const DartInfoConverter&
dartinfoconverter,
const PointConverter&
pointconverter) :
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2, typename Converters,
typename DartInfoConverter, typename PointConverter>
Linear_cell_complex_for_combinatorial_map
(const Linear_cell_complex_for_combinatorial_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc,
const Converters& converters, const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter) :
Base(alcc, converters, dartinfoconverter, pointconverter)
{}
Self & operator= (const Self & alcc)
{
Base::operator=(alcc);
return *this;
}
/** Import the given hds which should be a model of an halfedge graph. */
template<class HEG, class PointConverter>
void import_from_halfedge_graph(const HEG& heg ,
const PointConverter& pointconverter,
boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle,
typename boost::graph_traits<HEG>::halfedge_descriptor>*
copy_to_origin=NULL)
{
boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle> local_dartmap;
if (origin_to_copy==NULL) // Used local_dartmap if user does not provides its own unordered_map
{ origin_to_copy=&local_dartmap; }
Base::import_from_halfedge_graph(heg, origin_to_copy, copy_to_origin);
typedef typename boost::property_map<HEG,vertex_point_t>::const_type
Point_property_map;
Point_property_map ppmap = get(CGAL::vertex_point, heg);
typename boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle>::iterator dartmap_iter, dartmap_iter_end=origin_to_copy->end();
for (dartmap_iter=origin_to_copy->begin(); dartmap_iter!=dartmap_iter_end;
++dartmap_iter)
{
if (this->vertex_attribute(dartmap_iter->second)==NULL)
{
this->set_vertex_attribute(dartmap_iter->second,
this->create_vertex_attribute());
pointconverter.run(ppmap[source(dartmap_iter->first, heg)],
this->point(dartmap_iter->second));
}
}
}
/** Import the given hds which should be a model of an halfedge graph. */
template<class HEG>
void import_from_halfedge_graph(const HEG& heg,
boost::unordered_map
<typename boost::graph_traits<HEG>::halfedge_descriptor,
Dart_handle>* origin_to_copy=NULL,
boost::unordered_map
<Dart_handle,
typename boost::graph_traits<HEG>::halfedge_descriptor>*
copy_to_origin=NULL)
{
typedef typename boost::property_traits<typename boost::property_map
<HEG, vertex_point_t>::type>::value_type HEG_point;
CGAL::internal::Set_point_if_possible_cmap<HEG_point, Point> default_point_converter;
import_from_halfedge_graph(heg, default_point_converter,
origin_to_copy, copy_to_origin);
}
};
} // namespace CGAL

View File

@ -96,40 +96,59 @@ namespace CGAL {
* @param alcc the linear cell complex to copy.
* @post *this is valid.
*/
#ifdef DOXYGEN_RUNNING
Linear_cell_complex_for_generalized_map(const Self & alcc) : Base(alcc)
{}
#endif
template < class LCC2 >
Linear_cell_complex_for_generalized_map(const LCC2& alcc) : Base(alcc)
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2>
Linear_cell_complex_for_generalized_map
(const Linear_cell_complex_for_generalized_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc) : Base(alcc)
{}
template < class LCC2, typename Converters >
Linear_cell_complex_for_generalized_map(const LCC2& alcc,
Converters& converters) :
Base(alcc, converters)
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2, typename Converters>
Linear_cell_complex_for_generalized_map
(const Linear_cell_complex_for_generalized_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc,
const Converters& converters) : Base(alcc, converters)
{}
template < class LCC2, typename Converters, typename DartInfoConverter >
Linear_cell_complex_for_generalized_map(const LCC2& alcc,
Converters& converters,
const DartInfoConverter&
dartinfoconverter) :
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2, typename Converters, typename DartInfoConverter>
Linear_cell_complex_for_generalized_map
(const Linear_cell_complex_for_generalized_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc,
const Converters& converters,
const DartInfoConverter& dartinfoconverter) :
Base(alcc, converters, dartinfoconverter)
{}
template < class LCC2, typename Converters, typename DartInfoConverter,
template <unsigned int d2, unsigned int ambient_dim2, class Traits2,
class Items2, class Alloc2,
template<unsigned int,class,class,class,class> class CMap2,
class Storage2, typename Converters, typename DartInfoConverter,
typename PointConverter>
Linear_cell_complex_for_generalized_map(const LCC2& alcc,
Converters& converters,
const DartInfoConverter&
dartinfoconverter,
const PointConverter&
pointconverter) :
Linear_cell_complex_for_generalized_map
(const Linear_cell_complex_for_generalized_map<d2, ambient_dim2,
Traits2, Items2, Alloc2, CMap2, Storage2>& alcc,
const Converters& converters,
const DartInfoConverter& dartinfoconverter,
const PointConverter& pointconverter) :
Base(alcc, converters, dartinfoconverter, pointconverter)
{}
Self & operator= (const Self & alcc)
{
Base::operator=(alcc);
return *this;
}
};
} // namespace CGAL

View File

@ -16,7 +16,7 @@
#ifdef CGAL_USE_BASIC_VIEWER
#include <CGAL/Linear_cell_complex_base.h>
#include <CGAL/Linear_cell_complex_operations.h>
#include <CGAL/Random.h>
namespace CGAL

View File

@ -27,7 +27,7 @@ LC_CTYPE=en_US.UTF-8
# "integration"
0 21 * * Mon,Tue,Wed,Thu cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it --public || echo ERROR
# from branch 5.0
0 21 * * fri cd $HOME/CGAL/create_internal_release-5.0-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.14-branch.git --public --do-it || echo ERROR
0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.0-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.0-branch.git --public --do-it || echo ERROR
# from branch 4.14
0 21 * * Sat cd $HOME/CGAL/create_internal_release-4.14-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-4.14-branch.git --public --do-it || echo ERROR

View File

@ -0,0 +1,136 @@
<!doctype html>
<html style='height: 100%'>
<head>
<meta charset="utf-8">
<title>Diff of Testsuites</title>
<script type="text/javascript" src="difflib.js"></script>
<script type="text/javascript" src="fill_empty_lines.js"></script>
<script type="text/javascript" src="print_diff.js"></script>
<script type="text/javascript" src="diff_testsuites.js"></script>
<script type="text/javascript" src="worker.js"></script>
</head>
<body style='background-color: #C0C0D0; min-height: 100%;'>
<p><input type='text' id='baseInput'/>
<select id='baselist'></select>
<input type='text' id='newInput'/>
<select id='newlist'></select>
<button type="button" id='button'>Compare</button><br>
I = Master<br>
Ic = integration
</p>
<p>
<table id=namesTable border="1" cellspacing="2" cellpadding="5"></table>
<table id=diffPlatforms border="1" cellspacing="2" cellpadding="5"></table>
<table id=testTable border="1" cellspacing="2" cellpadding="5"></table>
<table id=namesTableBis border="1" cellspacing="2" cellpadding="5"></table>
</p>
<script type="text/javascript">
//get list of existing testsuites
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cgal.geometryfactory.com/~mgimeno/testsuite_comparison/list_of_testsuites.txt', false);
xhr.send(null);
if (xhr.status !== 200) {
alert("Couldn't find the list of testsuites.");
throw new Error("Couldn't find the list of testsuites.");
}
var tmp=xhr.responseText;
var testsuites=tmp.split("\n");
testsuites.sort();
testsuites.reverse();
var sorted_testsuites = testsuites;
var base = document.getElementById('baselist');
var newlist = document.getElementById('newlist');
var baseinput = document.getElementById('baseInput');
baseinput.oninput=function(){
var length = base.length;
for(i=0; i<length; i++)
{
base.removeChild(base.options[0]);
}
sorted_testsuites=testsuites.filter(word=>word.includes(baseinput.value));
for(var i = 0; i < sorted_testsuites.length; i++) {
var opt1 = document.createElement('option');
opt1.innerHTML = sorted_testsuites[i];
opt1.value = sorted_testsuites[i];
base.appendChild(opt1);
}
}
var newinput = document.getElementById('newInput');
newinput.oninput=function(){
var length = newlist.length;
for(i=0; i<length; i++)
{
newlist.removeChild(newlist.options[0]);
}
sorted_testsuites=testsuites.filter(word=>word.includes(newinput.value));
for(var i = 0; i < sorted_testsuites.length; i++) {
var opt1 = document.createElement('option');
opt1.innerHTML = sorted_testsuites[i];
opt1.value = sorted_testsuites[i];
newlist.appendChild(opt1);
}
}
for(var i = 0; i < sorted_testsuites.length; i++) {
var opt1 = document.createElement('option');
var opt2 = document.createElement('option');
opt1.innerHTML = sorted_testsuites[i];
opt2.innerHTML = sorted_testsuites[i];
opt1.value = sorted_testsuites[i];
opt2.value = sorted_testsuites[i];
base.appendChild(opt1);
newlist.appendChild(opt2);
}
var button = document.getElementById('button');
button.onclick=function(){
var baselist = document.getElementById("baselist");
var newlist = document.getElementById("newlist")
if(baselist.length==0 || newlist.length==0){
alert("You need two valid testsuites to diff.");
throw new Error("You need two valid testsuites to diff.");
}
var baseId = baselist.selectedIndex;
var newId = newlist.selectedIndex;
var baseTest = base.options[base.selectedIndex].value;
var newTest = newlist.options[newlist.selectedIndex].value;
document.body.style.cursor = 'wait';
if(baseTest === newTest){
alert("You chose the same testsuite twice, so no diff is expected !");
}
var namesTable = document.getElementById("namesTable");
var diffPlatforms = document.getElementById("diffPlatforms");
var namesTableBis = document.getElementById("namesTableBis");
var names = "<table id=table border=\"1\" cellspacing=\"2\" cellpadding=\"5\">";
var diff_platforms = "<table id=table border=\"1\" cellspacing=\"2\" cellpadding=\"5\">";
var tests = "<table id=table border=\"1\" cellspacing=\"2\" cellpadding=\"5\">";
tests+="<caption>TESTSUITE1: <a href=\"https://cgal.geometryfactory.com/CGAL/testsuite/"+baseTest.replace('CGAL','results')+".shtml\">"+baseTest+"</a> | TESTSUITE2: <a href=\"https://cgal.geometryfactory.com/CGAL/testsuite/"+newTest.replace('CGAL','results')+".shtml\">"+newTest+"</a></caption>";
var testTable =document.getElementById("testTable");
var message = [baseTest, newTest];
var w = new Worker("worker.js");
w.addEventListener('message', function(e) {
console.log(e.data[0]);
if(e.data[0] === "finished"){
namesTable.innerHTML=names;
diffPlatforms.innerHTML=diff_platforms;
testTable.innerHTML=tests;
namesTableBis.innerHTML=names;
document.body.style.cursor = 'default';
} else if(e.data[0] === "diffPlatforms"){
diff_platforms+= e.data[1];
}else if(e.data[0] === "namesTable"){
names+= e.data[1];
} else if(e.data[0] === "testTable"){
tests+= e.data[1];
}
}, false);
w.postMessage(message);
};
</script>
</body>
</html>

View File

@ -0,0 +1,148 @@
/* Author: Maxime Gimeno <maxime.gimeno@gmail.com> */
/***
Needs difflib.js, fill_empty_lines.js and print_diff.js to work.
Input : 2 strings of the form "CGAL-M.m.mm-I[c]-XXX"
Output: the list of differences between the testsuites.
***/
//v1.7
function diff_testsuites(baseTest, newTest){
var URL_suff='https://cgal.geometryfactory.com/~mgimeno/testsuite_comparison/list_of_suffixes.txt';
var URL_testsuite='https://cgal.geometryfactory.com/CGAL/Members/testsuite/';
//get the list of suffixes
var xhr = new XMLHttpRequest();
xhr.open('GET', URL_suff, false);
xhr.send(null);
var tmp=xhr.responseText;
var suffixes=tmp.split("\n");
suffixes.sort();
suffixes.reverse();
var myArray = new Array();
//contains the diff of existing platforms.
var diffArray = new Array();
var init = false;
for(s = 0; s < suffixes.length; s++) {
var new_column = new Array();
xhr.open('GET', URL_testsuite+baseTest+'/'+suffixes[s], false);
xhr.send(null);
var base_exists = (xhr.status === 200);
var base=xhr.responseText;
xhr.open('GET', URL_testsuite+newTest+'/'+suffixes[s], false);
xhr.send(null);
var new_exists = (xhr.status === 200)
if(base_exists && !new_exists)
{
diffArray.push("-"+suffixes[s]);
continue;
}
if(!base_exists && new_exists)
{
diffArray.push("+"+suffixes[s]);
continue;
}
if(!base_exists && !new_exists)
{
continue;
}
var newtext=xhr.responseText;
var sp_base=base.split("\n");
sp_base.sort();
var sp_newtext=newtext.split("\n");
sp_newtext.sort();
addMissingLines(sp_base, sp_newtext);
if(!init)
{
var first_column = new Array();
first_column.push("Platform")
for(i=0; i< sp_base.length; i++){
if(sp_base[i] !== ""){
first_column.push(sp_base[i].substr(0, sp_base[i].length-2));
} else {
first_column.push(sp_newtext[i].substr(0, sp_newtext[i].length-2));
}
}
myArray.push(first_column);
init = true;
}
var fragments = suffixes[s].split("_");
fragments.shift();
var name = fragments.join("_");
name = name.replace('.txt', '');
if(name !== ""){
new_column.push(name.replace(fragments[0]+"_", ''));
for(i=0; i< sp_base.length; i++){
var broken = false;
var res = print_diff(sp_base[i], sp_newtext[i]);
var compensator=0;
if(sp_base[i] !== ""){
while(sp_base[i].substr(0, sp_base[i].length-2) !== first_column[i+compensator]){
if(compensator >10){
broken=true;
break;
}
compensator++;
}
}
else{
while(sp_newtext[i].substr(0, sp_newtext[i].length-2) !== first_column[i+compensator]){
if(compensator >10){
broken=true;
break;
}
compensator++;
}
}
if(broken)
{
continue;
}
var new_line=first_column[i+compensator]+"||"+"<td style='width: 25px; text-align: right;";
var result="";
if(res[0]===""){
if(res[1] !==""){
result+="+";
}
}
else {
result+="<a href=\""+URL_testsuite+baseTest+"/"+first_column[i+compensator]+"/TestReport_"+name+".gz\">"+res[0]+"</a>\/";
}
if(res[1]===""){
if(res[0]!==""){
result+="-";
}
}
else {
result+="<a href=\""+URL_testsuite+newTest+"/"+first_column[i+compensator]+"/TestReport_"+name+".gz\">"+res[1]+"</a>";
}
if(res[1] === "w"){
new_line+=" background-color: rgb(100%,100%,50%)'> "+result;
} else if(res[1]=== "r"){
new_line+=" background-color: rgb(65%,65%,100%)'> "+result;
} else if(res[1]=== "n"){
new_line+=" background-color: rgb(100%,50%,50%)'> "+result;
}
else if(res[1]==="" && res[0]!==""){
new_line+=" background-color: rgb(50%,25%,75%)'>"+result;
}
else{
new_line+="'>";
}
new_line+="</td>";
new_column.push(new_line);
}
myArray.push(new_column);
}
}
return [myArray, diffArray];
}

View File

@ -0,0 +1,409 @@
/***
This is part of jsdifflib v1.0. <http://snowtide.com/jsdifflib>
Copyright (c) 2007, Snowtide Informatics Systems, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Snowtide Informatics Systems nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
/* Author: Chas Emerick <cemerick@snowtide.com> */
var __whitespace = {" ":true, "\t":true, "\n":true, "\f":true, "\r":true};
var difflib = {
defaultJunkFunction: function (c) {
return __whitespace.hasOwnProperty(c);
},
stripLinebreaks: function (str) { return str.replace(/^[\n\r]*|[\n\r]*$/g, ""); },
stringAsLines: function (str) {
var lfpos = str.indexOf("\n");
var crpos = str.indexOf("\r");
var linebreak = ((lfpos > -1 && crpos > -1) || crpos < 0) ? "\n" : "\r";
var lines = str.split(linebreak);
for (var i = 0; i < lines.length; i++) {
lines[i] = difflib.stripLinebreaks(lines[i]);
}
return lines;
},
// iteration-based reduce implementation
__reduce: function (func, list, initial) {
if (initial != null) {
var value = initial;
var idx = 0;
} else if (list) {
var value = list[0];
var idx = 1;
} else {
return null;
}
for (; idx < list.length; idx++) {
value = func(value, list[idx]);
}
return value;
},
// comparison function for sorting lists of numeric tuples
__ntuplecomp: function (a, b) {
var mlen = Math.max(a.length, b.length);
for (var i = 0; i < mlen; i++) {
if (a[i] < b[i]) return -1;
if (a[i] > b[i]) return 1;
}
return a.length == b.length ? 0 : (a.length < b.length ? -1 : 1);
},
__calculate_ratio: function (matches, length) {
return length ? 2.0 * matches / length : 1.0;
},
// returns a function that returns true if a key passed to the returned function
// is in the dict (js object) provided to this function; replaces being able to
// carry around dict.has_key in python...
__isindict: function (dict) {
return function (key) { return dict.hasOwnProperty(key); };
},
// replacement for python's dict.get function -- need easy default values
__dictget: function (dict, key, defaultValue) {
return dict.hasOwnProperty(key) ? dict[key] : defaultValue;
},
SequenceMatcher: function (a, b, isjunk) {
this.set_seqs = function (a, b) {
this.set_seq1(a);
this.set_seq2(b);
}
this.set_seq1 = function (a) {
if (a == this.a) return;
this.a = a;
this.matching_blocks = this.opcodes = null;
}
this.set_seq2 = function (b) {
if (b == this.b) return;
this.b = b;
this.matching_blocks = this.opcodes = this.fullbcount = null;
this.__chain_b();
}
this.__chain_b = function () {
var b = this.b;
var n = b.length;
var b2j = this.b2j = {};
var populardict = {};
for (var i = 0; i < b.length; i++) {
var elt = b[i];
if (b2j.hasOwnProperty(elt)) {
var indices = b2j[elt];
if (n >= 200 && indices.length * 100 > n) {
populardict[elt] = 1;
delete b2j[elt];
} else {
indices.push(i);
}
} else {
b2j[elt] = [i];
}
}
for (var elt in populardict) {
if (populardict.hasOwnProperty(elt)) {
delete b2j[elt];
}
}
var isjunk = this.isjunk;
var junkdict = {};
if (isjunk) {
for (var elt in populardict) {
if (populardict.hasOwnProperty(elt) && isjunk(elt)) {
junkdict[elt] = 1;
delete populardict[elt];
}
}
for (var elt in b2j) {
if (b2j.hasOwnProperty(elt) && isjunk(elt)) {
junkdict[elt] = 1;
delete b2j[elt];
}
}
}
this.isbjunk = difflib.__isindict(junkdict);
this.isbpopular = difflib.__isindict(populardict);
}
this.find_longest_match = function (alo, ahi, blo, bhi) {
var a = this.a;
var b = this.b;
var b2j = this.b2j;
var isbjunk = this.isbjunk;
var besti = alo;
var bestj = blo;
var bestsize = 0;
var j = null;
var k;
var j2len = {};
var nothing = [];
for (var i = alo; i < ahi; i++) {
var newj2len = {};
var jdict = difflib.__dictget(b2j, a[i], nothing);
for (var jkey in jdict) {
if (jdict.hasOwnProperty(jkey)) {
j = jdict[jkey];
if (j < blo) continue;
if (j >= bhi) break;
newj2len[j] = k = difflib.__dictget(j2len, j - 1, 0) + 1;
if (k > bestsize) {
besti = i - k + 1;
bestj = j - k + 1;
bestsize = k;
}
}
}
j2len = newj2len;
}
while (besti > alo && bestj > blo && !isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) {
besti--;
bestj--;
bestsize++;
}
while (besti + bestsize < ahi && bestj + bestsize < bhi &&
!isbjunk(b[bestj + bestsize]) &&
a[besti + bestsize] == b[bestj + bestsize]) {
bestsize++;
}
while (besti > alo && bestj > blo && isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) {
besti--;
bestj--;
bestsize++;
}
while (besti + bestsize < ahi && bestj + bestsize < bhi && isbjunk(b[bestj + bestsize]) &&
a[besti + bestsize] == b[bestj + bestsize]) {
bestsize++;
}
return [besti, bestj, bestsize];
}
this.get_matching_blocks = function () {
if (this.matching_blocks != null) return this.matching_blocks;
var la = this.a.length;
var lb = this.b.length;
var queue = [[0, la, 0, lb]];
var matching_blocks = [];
var alo, ahi, blo, bhi, qi, i, j, k, x;
while (queue.length) {
qi = queue.pop();
alo = qi[0];
ahi = qi[1];
blo = qi[2];
bhi = qi[3];
x = this.find_longest_match(alo, ahi, blo, bhi);
i = x[0];
j = x[1];
k = x[2];
if (k) {
matching_blocks.push(x);
if (alo < i && blo < j)
queue.push([alo, i, blo, j]);
if (i+k < ahi && j+k < bhi)
queue.push([i + k, ahi, j + k, bhi]);
}
}
matching_blocks.sort(difflib.__ntuplecomp);
var i1 = 0, j1 = 0, k1 = 0, block = 0;
var i2, j2, k2;
var non_adjacent = [];
for (var idx in matching_blocks) {
if (matching_blocks.hasOwnProperty(idx)) {
block = matching_blocks[idx];
i2 = block[0];
j2 = block[1];
k2 = block[2];
if (i1 + k1 == i2 && j1 + k1 == j2) {
k1 += k2;
} else {
if (k1) non_adjacent.push([i1, j1, k1]);
i1 = i2;
j1 = j2;
k1 = k2;
}
}
}
if (k1) non_adjacent.push([i1, j1, k1]);
non_adjacent.push([la, lb, 0]);
this.matching_blocks = non_adjacent;
return this.matching_blocks;
}
this.get_opcodes = function () {
if (this.opcodes != null) return this.opcodes;
var i = 0;
var j = 0;
var answer = [];
this.opcodes = answer;
var block, ai, bj, size, tag;
var blocks = this.get_matching_blocks();
for (var idx in blocks) {
if (blocks.hasOwnProperty(idx)) {
block = blocks[idx];
ai = block[0];
bj = block[1];
size = block[2];
tag = '';
if (i < ai && j < bj) {
tag = 'replace';
} else if (i < ai) {
tag = 'delete';
} else if (j < bj) {
tag = 'insert';
}
if (tag) answer.push([tag, i, ai, j, bj]);
i = ai + size;
j = bj + size;
if (size) answer.push(['equal', ai, i, bj, j]);
}
}
return answer;
}
// this is a generator function in the python lib, which of course is not supported in javascript
// the reimplementation builds up the grouped opcodes into a list in their entirety and returns that.
this.get_grouped_opcodes = function (n) {
if (!n) n = 3;
var codes = this.get_opcodes();
if (!codes) codes = [["equal", 0, 1, 0, 1]];
var code, tag, i1, i2, j1, j2;
if (codes[0][0] == 'equal') {
code = codes[0];
tag = code[0];
i1 = code[1];
i2 = code[2];
j1 = code[3];
j2 = code[4];
codes[0] = [tag, Math.max(i1, i2 - n), i2, Math.max(j1, j2 - n), j2];
}
if (codes[codes.length - 1][0] == 'equal') {
code = codes[codes.length - 1];
tag = code[0];
i1 = code[1];
i2 = code[2];
j1 = code[3];
j2 = code[4];
codes[codes.length - 1] = [tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)];
}
var nn = n + n;
var group = [];
var groups = [];
for (var idx in codes) {
if (codes.hasOwnProperty(idx)) {
code = codes[idx];
tag = code[0];
i1 = code[1];
i2 = code[2];
j1 = code[3];
j2 = code[4];
if (tag == 'equal' && i2 - i1 > nn) {
group.push([tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]);
groups.push(group);
group = [];
i1 = Math.max(i1, i2-n);
j1 = Math.max(j1, j2-n);
}
group.push([tag, i1, i2, j1, j2]);
}
}
if (group && !(group.length == 1 && group[0][0] == 'equal')) groups.push(group)
return groups;
}
this.ratio = function () {
matches = difflib.__reduce(
function (sum, triple) { return sum + triple[triple.length - 1]; },
this.get_matching_blocks(), 0);
return difflib.__calculate_ratio(matches, this.a.length + this.b.length);
}
this.quick_ratio = function () {
var fullbcount, elt;
if (this.fullbcount == null) {
this.fullbcount = fullbcount = {};
for (var i = 0; i < this.b.length; i++) {
elt = this.b[i];
fullbcount[elt] = difflib.__dictget(fullbcount, elt, 0) + 1;
}
}
fullbcount = this.fullbcount;
var avail = {};
var availhas = difflib.__isindict(avail);
var matches = numb = 0;
for (var i = 0; i < this.a.length; i++) {
elt = this.a[i];
if (availhas(elt)) {
numb = avail[elt];
} else {
numb = difflib.__dictget(fullbcount, elt, 0);
}
avail[elt] = numb - 1;
if (numb > 0) matches++;
}
return difflib.__calculate_ratio(matches, this.a.length + this.b.length);
}
this.real_quick_ratio = function () {
var la = this.a.length;
var lb = this.b.length;
return _calculate_ratio(Math.min(la, lb), la + lb);
}
this.isjunk = isjunk ? isjunk : difflib.defaultJunkFunction;
this.a = this.b = null;
this.set_seqs(a, b);
}
};

View File

@ -0,0 +1,47 @@
/* Author: Maxime Gimeno <maxime.gimeno@gmail.com> */
/***
This is designed to treat lines from CGAL testsuites results files,
of the form Package_name [r/y/w/n].
Input : 2 arrays of string, sorted by alphabetical order.
Output: the arrays, alphabetically sorted, of the same size, filled with
empty strings.
Short: Equalizes the sizes of the two inpu arrays by adding empty strings.
Detailed: for each element of the smaller input,
if base[i] != newtest[i] (not taking the last char into account),
adds an empty string in the input that is missing this entry,
based on the alphabetical order. Once it is done, will fill the smaller array
with empty strings if necessary.
***/
function addMissingLines(base, newtext){
for(i=0, j=0; i<Math.min(base.length, newtext.length); i++, j++)
{
if(base[i].substr(0, base[i].length-2) != newtext[i].substr(0,newtext[i].length-2) ) {
var tmp = [base[i], newtext[i]];
tmp.sort();
if(tmp[0] == base[i]){
newtext.splice(i, 0, "");
} else {
base.splice(i, 0, "");
}
}
}
var minsize = base.length;
var maxsize = newtext.length;
var to_fill = base;
if(base.length>newtext.length){
minsize = newtext.length;
maxsize = base.length;
to_fill = newtext;
}
for(i = minsize; i < maxsize; i++)
{
to_fill.push("");
}
}

View File

@ -0,0 +1,44 @@
/* Author: Maxime Gimeno <maxime.gimeno@gmail.com> */
/***
Need difflib.js
Input : 2 strings
Output: res. Contains the difference between the two input strings.
According to the result of difflib, will output :
- replace : -base, +newtext (the two input differs, but none are empty)
- insert: +newtext (the first input is empty)
- delete: -base (the second input is empty)
***/
function print_diff(base, newtext){
// create a SequenceMatcher instance that diffs the two sets of lines
var sm = new difflib.SequenceMatcher(base, newtext);
// get the opcodes from the SequenceMatcher instance
// opcodes is a list of 3-tuples describing what changes should be made to the base text
// in order to yield the new text
var opcodes = sm.get_opcodes();
var res=["",""];
for (var idx = 0; idx < opcodes.length; idx++) {
code = opcodes[idx];
change = code[0];
var b = code[1];
var be = code[2];
var n = code[3];
var ne = code[4];
if(newtext.charAt(newtext.length-1) !== "y"
&& change != "equal"){
res[0]=base.charAt(base.length-1);
res[1]=newtext.charAt(newtext.length-1);
}
//else if(change == "insert") {
// res=newtext.charAt(newtext.length-1);
//}
//else if(change == "delete") {
// res="-";
//}
//}
}
return res;
}

View File

@ -0,0 +1,51 @@
<!doctype html>
<html style='height: 100%'>
<head>
<meta charset="utf-8">
<title>Combo Box Test</title>
<script type="text/javascript" src="diff_testsuites.js"></script>
<body style='background-color: #C0C0D0; min-height: 100%;'>
<button type="button" id='button'>
Wait 1s.
</button>
<script type="text/javascript">
function prendDuTemps(onSuccess) {
setTimeout(
function() {
if(onSuccess) {
onSuccess()
}
},
100);
}
function boucleSynchrone(i) {
if(i<10) {
prendDuTemps(
function(){
console.log("blah"+i);
boucleSynchrone(i+1);
}
);
}
else
{
document.body.style.cursor = 'default';
}
}
function clickDiv() {
document.body.style.cursor = 'wait';
boucleSynchrone(0);
}
var button = document.getElementById('button');
button.onclick=clickDiv;
</script>
</body>
</html>

View File

@ -0,0 +1,62 @@
onmessage=function(e){
importScripts('difflib.js', 'diff_testsuites.js');
importScripts('fill_empty_lines.js','print_diff.js');
var res_arrays = diff_testsuites(e.data[0],e.data[1]);
var myArray = res_arrays[0];
var diffArray = res_arrays[1];
for(var i=0; i<diffArray.length; i++){
postMessage(["diffPlatforms","<tr><td>"+ diffArray[i]+"</td></tr>"]);
}
postMessage(["diffPlatforms", "</table>"]);
//pass over My Array to equalize columns length
var max_length=myArray[0].length;
for( i = 1; i< myArray.length; ++i){
var length = myArray[i].length;
if(length === max_length){ continue; }
for(var j=2; j<length;j++){
var base_line = myArray[i][j];
var max_line = myArray[0][j];
var base_identifier=base_line.split("||")[0];
var max_identifier=max_line.split("||")[0];
if(base_identifier !== max_identifier) {
myArray[i].splice(j, 0, "<td></td>");
}
}
var minsize = myArray[i].length;
for(k = minsize; k < myArray[0].length; k++)
{
myArray[i].push("<td></td>");
}
}
for(i=1; i<myArray.length; i++){
postMessage(["namesTable","<tr><td>"+i+": </td><td>"+ myArray[i][0]+"</td></tr>"]);
}
postMessage(["namesTable", "</table>"]);
postMessage(["testTable", "<tr><td style='width: 25px;'>Platform: </td>"]);
for(i=1; i<myArray.length; i++)
{
postMessage(["testTable", "<td style='width: 25px; text-align: right;'>" + i + "</td>"]);
}
postMessage(["testTable", "</tr>"]);
for (var j=2; j<myArray[0].length; j++) {
postMessage(["testTable", "<tr><td style='width: 25px;'>"+ myArray[0][j]+": </td>"]);
for(i=1; i<myArray.length; i++)
{
var sp = myArray[i][j].split("||");
if(sp.length === 1){
postMessage(["testTable", myArray[i][j]]);
} else{
postMessage(["testTable", sp[1]]);
}
}
postMessage(["testTable", "</tr>"]);
}
postMessage(["testTable", "</table></body>"]);
postMessage(["finished"]);
}

View File

@ -89,7 +89,7 @@ public:
/**
* The following map tells what vertices are in the cluster and if
* the corresponding segment has been splitted once.
* the corresponding segment has been split once.
*/
typedef std::map<Vertex_handle, bool> Vertices_map;
Vertices_map vertices;

View File

@ -493,7 +493,7 @@ public:
/** This version computes the refinement point without handling
clusters. The refinement point of an edge is just the middle point of
the segment.
Saves the handles of the edge that will be splitted.
Saves the handles of the edge that will be split.
This function is overridden in class Refine_edge_with_clusters.
*/
Point refinement_point_impl(const Edge& edge)

View File

@ -106,9 +106,8 @@ public Q_SLOTS:
void insert_mp() {
insert_point(moving_point);
QString str;
ui->viewer->displayMessage(str.sprintf("Added point (%f, %f, %f)",
moving_point.x(),moving_point.y(),moving_point.z()));
ui->viewer->displayMessage(QString("Added point (%1, %2, %3)").arg(
moving_point.x()).arg(moving_point.y()).arg(moving_point.z()));
changed();
}
@ -117,9 +116,8 @@ public Q_SLOTS:
Point pt = *rp+Vector(0.5,0.5,0.5);
rp++;
insert_point(Point(pt.x(),pt.y(),(in_plane? 0.0:pt.z())));
QString str;
ui->viewer->displayMessage(str.sprintf("Added point (%f, %f, %f)",
pt.x(),pt.y(),(in_plane? 0.0:pt.z())));
ui->viewer->displayMessage(QString("Added point (%1, %2, %3)").arg(
pt.x()).arg(pt.y()).arg((in_plane? 0.0:pt.z())));
changed();
}
void insert_point(Point p) {

View File

@ -231,6 +231,18 @@ public:
return *this;
}
/// \cond SKIP_IN_MANUAL
// copy constructor (same as assignment)
Point_set_3 (const Point_set_3& ps)
{
m_base = ps.m_base;
m_indices = this->property_map<Index> ("index").first;
m_points = this->property_map<Point> ("point").first;
m_normals = this->property_map<Vector> ("normal").first;
m_nb_removed = ps.m_nb_removed;
}
/// \endcond
/// @}
/// \cond SKIP_IN_MANUAL

View File

@ -404,31 +404,28 @@ still ensuring that the total sum of the coordinates is `1`.
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{use_angle_smoothing_t} \anchor PMP_use_angle_smoothing
\cgalNPBegin{use_angle_smoothing} \anchor PMP_use_angle_smoothing
Parameter used in the function `smooth_mesh()` to indicate if angle-based smoothing should be used.
When this type of smoothing is used, the algorithm attempts to equalize angles incident to each vertex.
\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{use_area_smoothing_t} \anchor PMP_use_area_smoothing
\cgalNPBegin{use_area_smoothing} \anchor PMP_use_area_smoothing
Parameter used in the function `smooth_mesh()` to indicate if area-based smoothing should be used.
When this type of smoothing is used, the algorithm attempts to equalize the areas of the triangles
incident to each vertex. Since this can create elongated triangles, a second phase uses Delaunay-based
flips to recover good shapes, unless specified otherwise (see below).
\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{use_Delaunay_flips_t} \anchor PMP_use_Delaunay_flips
\cgalNPBegin{use_Delaunay_flips} \anchor PMP_use_Delaunay_flips
Parameter used in the function `smooth_mesh()` to indicate if Delaunay-based flips should be used
after area-based smoothing has been performed. A user wishing to preserve combinatorial information
can set this parameter to `false`, but the mesh might have elongated elements.
\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
@ -439,7 +436,6 @@ Parameter used in the function `smooth_mesh()` to indicate if some sanity checks
if the move of a vertex should be applied or rejected. These sanity checks consists of checking that
no face incident to the vertex becomes inverted and that the minimum angle of the incident faces
is not decreased by the move.
\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
@ -449,7 +445,6 @@ is not decreased by the move.
Parameter used in the functions `keep_large_connected_components()` and
`keep_largest_connected_components()` to pass a property map that gives the size of a face when
evaluating the size of a connected component (which is defined as the sum of the sizes of its faces).
\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and
@ -457,6 +452,33 @@ a value type supporting construction from `0`, `operator+=()`, and comparison op
<b>Default:</b> `CGAL::Constant_property_map<face_descriptor, std::size_t>` with value `1`
\cgalNPEnd
\cgalNPBegin{area_threshold} \anchor PMP_area_threshold
Parameter used in the function `remove_connected_components_of_negligible_size()`
to pass a threshold value such that all connected components with an area smaller
than this value are removed from the mesh.
\n
<b>Type:</b> `Kernel::FT` \n
<b>Default:</b> The square of one percent of the length of the diagonal of the bounding box of the mesh.
\cgalNPEnd
\cgalNPBegin{volume_threshold} \anchor PMP_volume_threshold
Parameter used in the function `remove_connected_components_of_negligible_size()`
to pass a threshold value such that all (closed) connected components with a volume smaller
than this value are removed from the mesh.
\n
<b>Type:</b> `Kernel::FT` \n
<b>Default:</b> The third power of one percent of the length of the diagonal of the bounding box of the mesh.
\cgalNPEnd
\cgalNPBegin{dry_run} \anchor PMP_dry_run
Parameter that tells a function not to alter the input, but rather to only return the expected result.
It is for example used in the fucntion `keep_large_connected_components()`.
\n
<b>Type:</b> `bool` \n
<b>Default:</b> `false`
\cgalNPEnd
\cgalNPTableEnd
*/

View File

@ -155,6 +155,7 @@ and provides a list of the parameters that are used in this package.
- `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()`
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()`
- `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`
\cgalCRPSection{Normal Computation Functions}
- `CGAL::Polygon_mesh_processing::compute_face_normal()`

View File

@ -6,7 +6,10 @@
#include <iostream>
#include <fstream>
namespace PMP = CGAL::Polygon_mesh_processing;
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_3 Point;
typedef K::Vector_3 Vector;
@ -25,24 +28,18 @@ int main(int argc, char* argv[])
return 1;
}
auto fnormals = mesh.add_property_map<face_descriptor, Vector>
("f:normals", CGAL::NULL_VECTOR).first;
auto vnormals = mesh.add_property_map<vertex_descriptor, Vector>
("v:normals", CGAL::NULL_VECTOR).first;
auto vnormals = mesh.add_property_map<vertex_descriptor, Vector>("v:normals", CGAL::NULL_VECTOR).first;
auto fnormals = mesh.add_property_map<face_descriptor, Vector>("f:normals", CGAL::NULL_VECTOR).first;
CGAL::Polygon_mesh_processing::compute_normals(mesh,
vnormals,
fnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).
geom_traits(K()));
PMP::compute_normals(mesh, vnormals, fnormals);
std::cout << "Vertex normals :" << std::endl;
for(vertex_descriptor vd: vertices(mesh))
std::cout << vnormals[vd] << std::endl;
std::cout << "Face normals :" << std::endl;
for(face_descriptor fd: faces(mesh)){
for(face_descriptor fd: faces(mesh))
std::cout << fnormals[fd] << std::endl;
}
std::cout << "Vertex normals :" << std::endl;
for(vertex_descriptor vd: vertices(mesh)){
std::cout << vnormals[vd] << std::endl;
}
return 0;
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2015 GeometryFactory (France).
// Copyright (c) 2015-2019 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
@ -9,51 +9,62 @@
//
//
// Author(s) : Jane Tournois
// Mael Rouxel-Labbé
#ifndef CGAL_POLYGON_MESH_PROCESSING_COMPUTE_NORMAL_H
#define CGAL_POLYGON_MESH_PROCESSING_COMPUTE_NORMAL_H
#include <CGAL/license/Polygon_mesh_processing/Compute_normal.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/properties.h>
#include <boost/graph/graph_traits.hpp>
#include <CGAL/Origin.h>
#include <CGAL/Kernel/global_functions_3.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <boost/type_traits.hpp>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/properties.h>
#include <CGAL/Dynamic_property_map.h>
#include <CGAL/Origin.h>
#include <boost/graph/graph_traits.hpp>
#include <iostream>
#include <utility>
#include <vector>
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
# ifndef CGAL_PMP_COMPUTE_NORMAL_DEBUG
# define CGAL_PMP_COMPUTE_NORMAL_DEBUG
# endif
#endif
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG
#include <fstream>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#endif
namespace CGAL {
namespace Polygon_mesh_processing {
namespace internal {
template <class GT>
void normalize(typename GT::Vector_3& v, const GT& traits)
{
typename GT::FT norm = CGAL::approximate_sqrt(
traits.compute_squared_length_3_object()(v));
typedef typename GT::FT FT;
//If the vector is small enough, approx_sqrt might return 0, and then we get nan values.
//To avoid that, we check the resulted norm. If it is 0, we don't normalize.
if(norm != 0)
const FT norm = CGAL::approximate_sqrt(traits.compute_squared_length_3_object()(v));
if(norm != FT(0))
{
v = traits.construct_divided_vector_3_object()(v, norm);
}
}
template<typename Point
, typename GT>
template<typename Point, typename GT>
typename GT::Vector_3
triangle_normal(const Point& p0, const Point& p1, const Point& p2
, const GT& traits)
triangle_normal(const Point& p0, const Point& p1, const Point& p2, const GT& traits)
{
typedef typename GT::FT FT;
typename GT::Vector_3 n = traits.construct_cross_product_vector_3_object()(
traits.construct_vector_3_object()(p1, p2),
traits.construct_vector_3_object()(p1, p0));
@ -61,12 +72,10 @@ namespace internal {
//cross-product(AB, AC)'s norm is the area of the parallelogram
//formed by these 2 vectors.
//the triangle's area is half of it
return traits.construct_scaled_vector_3_object()(n, 0.5);
}
return traits.construct_scaled_vector_3_object()(n, FT(1)/FT(2));
}
template<typename Point, typename PM, typename VertexPointMap, typename Vector
, typename GT>
template<typename Point, typename PM, typename VertexPointMap, typename Vector, typename GT>
void sum_normals(const PM& pmesh,
typename boost::graph_traits<PM>::face_descriptor f,
VertexPointMap vpmap,
@ -76,21 +85,25 @@ void sum_normals(const PM& pmesh,
typedef typename boost::graph_traits<PM>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<PM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::property_traits<VertexPointMap>::reference Point_ref;
halfedge_descriptor he = halfedge(f, pmesh);
vertex_descriptor v = source(he, pmesh);
const Point& pv = get(vpmap, v);
const Point_ref pv = get(vpmap, v);
while(v != target(next(he, pmesh), pmesh))
{
const Point& pvn = get(vpmap, target(he, pmesh));
const Point& pvnn = get(vpmap, target(next(he, pmesh), pmesh));
const Point_ref pvn = get(vpmap, target(he, pmesh));
const Point_ref pvnn = get(vpmap, target(next(he, pmesh), pmesh));
Vector n = internal::triangle_normal(pv, pvn, pvnn, traits);
const Vector n = internal::triangle_normal(pv, pvn, pvnn, traits);
sum = traits.construct_sum_of_vectors_3_object()(sum, n);
he = next(he, pmesh);
}
}
} // namespace internal
/**
* \ingroup PMP_normal_grp
@ -124,9 +137,9 @@ Vector_3
#else
typename GetGeomTraits<PolygonMesh, NamedParameters>::type::Vector_3
#endif
compute_face_normal(typename boost::graph_traits<PolygonMesh>::face_descriptor f
, const PolygonMesh& pmesh
, const NamedParameters& np)
compute_face_normal(typename boost::graph_traits<PolygonMesh>::face_descriptor f,
const PolygonMesh& pmesh,
const NamedParameters& np)
{
using parameters::choose_parameter;
using parameters::get_parameter;
@ -139,10 +152,10 @@ compute_face_normal(typename boost::graph_traits<PolygonMesh>::face_descriptor f
get_const_property_map(vertex_point, pmesh));
typedef typename GT::Point_3 Point;
typedef typename GT::Vector_3 Vector;
typedef typename GT::Vector_3 Vector_3;
Vector normal = traits.construct_vector_3_object()(CGAL::NULL_VECTOR);
sum_normals<Point>(pmesh, f, vpmap, normal, traits);
Vector_3 normal = traits.construct_vector_3_object()(CGAL::NULL_VECTOR);
internal::sum_normals<Point>(pmesh, f, vpmap, normal, traits);
if(!traits.equal_3_object()(normal, CGAL::NULL_VECTOR))
internal::normalize(normal, traits);
@ -150,16 +163,24 @@ compute_face_normal(typename boost::graph_traits<PolygonMesh>::face_descriptor f
return normal;
}
template <typename PolygonMesh>
typename GetGeomTraits<PolygonMesh>::type::Vector_3
compute_face_normal(typename boost::graph_traits<PolygonMesh>::face_descriptor f,
const PolygonMesh& pmesh)
{
return compute_face_normal(f, pmesh, CGAL::parameters::all_default());
}
/**
* \ingroup PMP_normal_grp
* computes the outward unit vector normal for all faces of the polygon mesh.
* @tparam PolygonMesh a model of `FaceGraph`
* @tparam FaceNormalMap a model of `WritablePropertyMap` with
* @tparam Face_normal_map a model of `WritablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and
`Kernel::Vector_3` as value type.
*
* @param pmesh the polygon mesh
* @param fnm the property map in which the normals are written
* @param face_normals the property map in which the normals are written
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
@ -173,22 +194,366 @@ compute_face_normal(typename boost::graph_traits<PolygonMesh>::face_descriptor f
* If `Kernel::FT` does not have a `sqrt()` operation, the square root computation
* will be done approximately.
*/
template <typename PolygonMesh
, typename FaceNormalMap
, typename NamedParameters>
void
compute_face_normals(const PolygonMesh& pmesh
, FaceNormalMap fnm
, const NamedParameters& np)
template <typename PolygonMesh, typename Face_normal_map, typename NamedParameters>
void compute_face_normals(const PolygonMesh& pmesh,
Face_normal_map face_normals,
const NamedParameters& np)
{
typedef typename GetGeomTraits<PolygonMesh,NamedParameters>::type Kernel;
for(typename boost::graph_traits<PolygonMesh>::face_descriptor f : faces(pmesh)){
for(typename boost::graph_traits<PolygonMesh>::face_descriptor f : faces(pmesh))
{
typename Kernel::Vector_3 vec = compute_face_normal(f, pmesh, np);
put(fnm, f, vec);
put(face_normals, f, vec);
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG
std::cout << "normal at face " << f << " is " << get(face_normals, f) << std::endl;
#endif
}
}
template <typename PolygonMesh, typename Face_normal_map>
void compute_face_normals(const PolygonMesh& pmesh, Face_normal_map face_normals)
{
compute_face_normals(pmesh, face_normals, CGAL::parameters::all_default());
}
namespace internal {
enum Vertex_normal_type {
NO_WEIGHT = 0,
SIN_WEIGHT,
MOST_VISIBLE
};
template <typename GT>
bool almost_equal(const typename GT::Vector_3& v1, const typename GT::Vector_3& v2,
const GT& traits)
{
typedef typename GT::FT FT;
// We are doing a lot of likely inexact constructions to compute min circles on the sphere and
// these degenerate cases often happen (e.g. almost flat surfaces), so we don't want to to the usual
// "switch to the exact kernel" in degenerate cases robustness trick. Rather, use a fixed tolerance
// to assimilate vectors and scalar products.
//
// Tolerance is (arbitrarily) chosen as theta := 0.01°, thus we want sp(v1,v2) >= cos(theta)
const FT cos_theta = 0.99999998476912910;
return traits.compute_scalar_product_3_object()(v1, v2) >= cos_theta;
}
template <typename PolygonMesh, typename FaceNormalVector, typename K>
bool does_enclose_other_normals(const std::size_t i, const std::size_t j, const std::size_t k,
const typename K::Vector_3& nb,
const typename K::FT sp_bi,
const std::vector<typename boost::graph_traits<PolygonMesh>::face_descriptor>& incident_faces,
const FaceNormalVector& face_normals,
const K& traits)
{
typedef typename K::FT FT;
typedef typename boost::property_traits<FaceNormalVector>::reference Vector_ref;
typename K::Compute_scalar_product_3 sp = traits.compute_scalar_product_3_object();
const FT nbn = CGAL::approximate_sqrt(traits.compute_squared_length_3_object()(nb));
// check that this min circle defined by the diameter contains the other points
const std::size_t nif = incident_faces.size();
for(std::size_t l=0; l<nif; ++l)
{
if(l == i || l == j || l == k)
continue;
const Vector_ref nl = get(face_normals, incident_faces[l]);
// this is a bound on how much the scalar product between (v1,v2) and (v1, v3) can change
// when the angle changes theta_bound := 0.01°
// The weird number is thus := max_(theta_i, theta_j)[abs(std::cos(theta_i), std::cos(theta_j))]
// with theta_j - theta_i = theta_bound
const FT sp_diff_bound = nbn * 0.00017453292431333;
const FT sp_bl = sp(nb, nl);
if(CGAL::abs(sp_bi - sp_bl) <= sp_diff_bound)
continue;
if(sp_bl < sp_bi)
return false;
}
return true;
}
template <typename GT>
typename GT::Vector_3 compute_normals_bisector(const typename GT::Vector_3& ni,
const typename GT::Vector_3& nj,
const GT& traits)
{
if(traits.equal_3_object()(ni, nj))
return ni;
return traits.construct_sum_of_vectors_3_object()(ni, nj); // not normalized
}
template <typename GT>
typename GT::Vector_3 compute_normals_bisector(const typename GT::Vector_3& ni,
const typename GT::Vector_3& nj,
const typename GT::Vector_3& nk,
const GT& traits)
{
typedef typename GT::FT FT;
typedef typename GT::Point_3 Point_3;
typedef typename GT::Vector_3 Vector_3;
typename GT::Construct_scaled_vector_3 cslv_3 = traits.construct_scaled_vector_3_object();
typename GT::Construct_sum_of_vectors_3 csv_3 = traits.construct_sum_of_vectors_3_object();
typename GT::Construct_vector_3 cv_3 = traits.construct_vector_3_object();
Vector_3 nb = cv_3(CGAL::NULL_VECTOR);
if(almost_equal(ni, nj, traits))
{
if(almost_equal(nj, nk, traits))
nb = ni;
else // ni == nj, but nij != nk
nb = compute_normals_bisector(nj, nk, traits);
}
else if(almost_equal(ni, nk, traits)) // ni != nj
{
nb = compute_normals_bisector(nj, nk, traits);
}
else if(almost_equal(nj, nk, traits)) // ni != nj, ni != nk
{
nb = compute_normals_bisector(ni, nk, traits);
}
else
{
CGAL_assertion(ni != nj);
CGAL_assertion(ni != nk);
CGAL_assertion(nj != nk);
CGAL_assertion(!traits.collinear_3_object()(CGAL::ORIGIN + ni, CGAL::ORIGIN + nj, CGAL::ORIGIN + nk));
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::cout << "Triplet: ni[" << ni << "] nj[" << nj << "] nk[" << nk << "]" << std::endl;
#endif
const Point_3 c = traits.construct_circumcenter_3_object()(CGAL::ORIGIN + ni, CGAL::ORIGIN + nj, CGAL::ORIGIN + nk);
if(c == CGAL::ORIGIN)
{
// will happen if the three vectors live in the same plan, return some weighted sum
const FT third = FT(1)/FT(3);
return csv_3(csv_3(cslv_3(ni, third), cslv_3(nj, third)), cslv_3(nk, third));
}
nb = cv_3(CGAL::ORIGIN, c); // note that this isn't normalized
}
return nb;
}
template <typename PolygonMesh, typename FaceNormalVector, typename GT>
typename GT::Vector_3
compute_most_visible_normal_2_points(std::vector<typename boost::graph_traits<PolygonMesh>::face_descriptor>& incident_faces,
const FaceNormalVector& face_normals,
const GT& traits)
{
typedef typename GT::FT FT;
typedef typename GT::Vector_3 Vector_3;
typedef typename boost::property_traits<FaceNormalVector>::reference Vector_ref;
typename GT::Compute_scalar_product_3 sp_3 = traits.compute_scalar_product_3_object();
typename GT::Construct_vector_3 cv_3 = traits.construct_vector_3_object();
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::cout << "Trying to find enclosing normal with 2 normals" << std::endl;
#endif
FT min_sp = -1;
Vector_3 n = cv_3(CGAL::NULL_VECTOR);
const std::size_t nif = incident_faces.size();
for(std::size_t i=0; i<nif; ++i)
{
for(std::size_t j=i+1; j<nif; ++j)
{
const Vector_ref ni = get(face_normals, incident_faces[i]);
const Vector_ref nj = get(face_normals, incident_faces[j]);
const Vector_3 nb = compute_normals_bisector(ni, nj, traits);
// Degeneracies like ni == -nj or a numerical error in the construction of 'nb' can happen.
if(traits.equal_3_object()(nb, CGAL::NULL_VECTOR))
return CGAL::NULL_VECTOR;
const FT sp_bi = sp_3(nb, ni);
CGAL_assertion(sp_bi >= 0);
if(sp_bi <= min_sp)
continue;
if(!does_enclose_other_normals<PolygonMesh>(i, j, -1 /*NA*/, nb, sp_bi, incident_faces, face_normals, traits))
continue;
min_sp = sp_bi;
n = nb;
}
}
return n;
}
template <typename PolygonMesh, typename FaceNormalVector, typename GT>
typename GT::Vector_3
compute_most_visible_normal_3_points(const std::vector<typename boost::graph_traits<PolygonMesh>::face_descriptor>& incident_faces,
const FaceNormalVector& face_normals,
const GT& traits)
{
typedef typename GT::FT FT;
typedef typename GT::Vector_3 Vector_3;
typedef typename boost::property_traits<FaceNormalVector>::reference Vector_ref;
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::cout << "Trying to find enclosing normal with 3 normals" << std::endl;
#endif
FT min_sp = -1;
Vector_3 n = traits.construct_vector_3_object()(CGAL::NULL_VECTOR);
const std::size_t nif = incident_faces.size();
for(std::size_t i=0; i<nif; ++i)
{
for(std::size_t j=i+1; j<nif; ++j)
{
for(std::size_t k=j+1; k<nif; ++k)
{
const Vector_ref ni = get(face_normals, incident_faces[i]);
const Vector_ref nj = get(face_normals, incident_faces[j]);
const Vector_ref nk = get(face_normals, incident_faces[k]);
Vector_3 nb = compute_normals_bisector(ni, nj, nk, traits);
if(traits.equal_3_object()(nb, CGAL::NULL_VECTOR))
return nb;
FT sp_bi = traits.compute_scalar_product_3_object()(nb, ni);
if(sp_bi < FT(0))
{
nb = traits.construct_opposite_vector_3_object()(nb);
sp_bi = - sp_bi;
}
if(sp_bi <= min_sp)
continue;
if(!does_enclose_other_normals<PolygonMesh>(i, j, k, nb, sp_bi, incident_faces, face_normals, traits))
continue;
min_sp = sp_bi;
n = nb;
}
}
}
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::cout << "Best normal from 3-normals-approach: " << n << std::endl;
#endif
return n;
}
// Inspired by Aubry et al. On the most 'normal' normal
template <typename PolygonMesh, typename FaceNormalVector, typename GT>
typename GT::Vector_3
compute_vertex_normal_most_visible_min_circle(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v,
const FaceNormalVector& face_normals,
const PolygonMesh& pmesh,
const GT& traits)
{
typedef typename boost::graph_traits<PolygonMesh>::face_descriptor face_descriptor;
typedef typename GT::Vector_3 Vector_3;
std::vector<face_descriptor> incident_faces;
for(face_descriptor f : CGAL::faces_around_target(halfedge(v, pmesh), pmesh))
{
if(f == boost::graph_traits<PolygonMesh>::null_face())
continue;
incident_faces.push_back(f);
}
if(incident_faces.size() == 1)
return get(face_normals, incident_faces.front());
Vector_3 res = compute_most_visible_normal_2_points<PolygonMesh>(incident_faces, face_normals, traits);
if(res != CGAL::NULL_VECTOR) // found a valid normal through 2 point min circle
return res;
CGAL_assertion(incident_faces.size() > 2);
return compute_most_visible_normal_3_points<PolygonMesh>(incident_faces, face_normals, traits);
}
template <typename PolygonMesh, typename FaceNormalVector, typename VertexPointMap, typename GT>
typename GT::Vector_3
compute_vertex_normal_as_sum_of_weighted_normals(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v,
const Vertex_normal_type& vn_type,
const FaceNormalVector& face_normals,
const VertexPointMap& vpmap,
const PolygonMesh& pmesh,
const GT& traits)
{
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
typedef typename GT::FT FT;
typedef typename GT::Vector_3 Vector_3;
typedef typename boost::property_traits<FaceNormalVector>::reference Vector_ref;
typename GT::Construct_vector_3 cv_3 = traits.construct_vector_3_object();
typename GT::Compute_squared_length_3 csl_3 = traits.compute_squared_length_3_object();
Vector_3 normal = cv_3(CGAL::NULL_VECTOR);
halfedge_descriptor h = halfedge(v, pmesh);
if(h == boost::graph_traits<PolygonMesh>::null_halfedge())
return normal;
halfedge_descriptor end = h;
do
{
if(!is_border(h, pmesh))
{
if(vn_type == NO_WEIGHT)
{
const Vector_ref n = get(face_normals, face(h, pmesh));
normal = traits.construct_sum_of_vectors_3_object()(normal, n);
}
else if(vn_type == SIN_WEIGHT)
{
const Vector_3 v1 = cv_3(get(vpmap, v), get(vpmap, source(h, pmesh)));
const Vector_3 v2 = cv_3(get(vpmap, v), get(vpmap, target(next(h, pmesh), pmesh)));
//v(i) and v(i+1) must me seen in ccw order, from v, so we reverse v1 and v2
Vector_3 n = traits.construct_cross_product_vector_3_object()(v2, v1);
n = traits.construct_scaled_vector_3_object()(n, CGAL::approximate_sqrt(FT(1)/(csl_3(v1) * csl_3(v2))));
normal = traits.construct_sum_of_vectors_3_object()(normal, n);
}
else
{
std::cerr << "Error: unknown vertex normal type" << std::endl;
CGAL_assertion(false);
return CGAL::NULL_VECTOR;
}
}
h = opposite(next(h, pmesh), pmesh);
}
while(h != end);
return normal;
}
} // end namespace internal
/**
* \ingroup PMP_normal_grp
* computes the unit normal at vertex `v` as the average of the normals of incident faces.
@ -222,61 +587,101 @@ typename GetGeomTraits<PolygonMesh, NamedParameters>::type::Vector_3
#endif
compute_vertex_normal(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v,
const PolygonMesh& pmesh,
const NamedParameters& np
)
const NamedParameters& np)
{
using parameters::choose_parameter;
using parameters::is_default_parameter;
using parameters::get_parameter;
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<PolygonMesh>::face_descriptor face_descriptor;
typedef typename GetGeomTraits<PolygonMesh, NamedParameters>::type GT;
typedef typename GT::Vector_3 Vector;
typedef typename GT::Vector_3 Vector_3;
GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
typedef typename GetFaceNormalMap<PolygonMesh, NamedParameters>::NoMap DefaultMap;
typedef typename internal_np::Lookup_named_param_def <
internal_np::face_normal_t,
typedef typename GetVertexPointMap<PolygonMesh, NamedParameters>::const_type VPMap;
VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point),
get_const_property_map(vertex_point, pmesh));
typedef std::map<face_descriptor, Vector_3> Face_vector_map;
typedef boost::associative_property_map<Face_vector_map> Default_map;
typedef typename internal_np::Lookup_named_param_def<internal_np::face_normal_t,
NamedParameters,
DefaultMap> ::type FaceNormalMap;
FaceNormalMap fnmap = choose_parameter(get_parameter(np, internal_np::face_normal), DefaultMap());
bool fnmap_valid
= !boost::is_same<FaceNormalMap,
DefaultMap
>::value;
Default_map>::type Face_normal_map;
Face_vector_map default_fvmap;
Face_normal_map face_normals = choose_parameter(get_parameter(np, internal_np::face_normal),
Default_map(default_fvmap));
const bool must_compute_face_normals = is_default_parameter(get_parameter(np, internal_np::face_normal));
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::cout << std::endl << std::endl;
std::cout << "----------------------------------------------------------------------" << std::endl;
std::cout << "compute vertex at " << get(vpmap, v)
<< ", must compute face normals? " << must_compute_face_normals << std::endl;
#endif
Vector normal = traits.construct_vector_3_object()(CGAL::NULL_VECTOR);
halfedge_descriptor he = halfedge(v, pmesh);
// handle isolated vertices
if (he==boost::graph_traits<PolygonMesh>::null_halfedge()) return normal;
halfedge_descriptor end = he;
do
halfedge_descriptor he = halfedge(v, pmesh);
if(he == boost::graph_traits<PolygonMesh>::null_halfedge())
return CGAL::NULL_VECTOR;
if(must_compute_face_normals)
{
if (!is_border(he, pmesh))
for(face_descriptor f : CGAL::faces_around_target(halfedge(v, pmesh), pmesh))
{
Vector n = fnmap_valid ? get(fnmap, face(he, pmesh))
: compute_face_normal(face(he, pmesh), pmesh, np);
normal = traits.construct_sum_of_vectors_3_object()(normal, n);
if(f == boost::graph_traits<PolygonMesh>::null_face())
continue;
put(face_normals, f, compute_face_normal(f, pmesh, np));
}
}
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG
std::cout << "Incident face normals:" << std::endl;
for(halfedge_descriptor h : CGAL::halfedges_around_target(v, pmesh))
{
if(!is_border(h, pmesh))
std::cout << "get normal at f " << face(h, pmesh) << " : " << get(face_normals, face(h, pmesh)) << std::endl;
}
#endif
Vector_3 normal = internal::compute_vertex_normal_most_visible_min_circle(v, face_normals, pmesh, traits);
if(traits.equal_3_object()(normal, CGAL::NULL_VECTOR)) // can't always find a most visible normal
{
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::cout << "Failed to find most visible normal, use weighted sum of normals" << std::endl;
#endif
normal = internal::compute_vertex_normal_as_sum_of_weighted_normals(
v, internal::SIN_WEIGHT, face_normals, vpmap, pmesh, traits);
}
he = opposite(next(he, pmesh), pmesh);
} while (he != end);
if(!traits.equal_3_object()(normal, CGAL::NULL_VECTOR))
internal::normalize(normal, traits);
return normal;
}
template <typename PolygonMesh>
typename GetGeomTraits<PolygonMesh>::type::Vector_3
compute_vertex_normal(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v,
const PolygonMesh& pmesh)
{
return compute_vertex_normal(v, pmesh, CGAL::parameters::all_default());
}
/**
* \ingroup PMP_normal_grp
* computes the outward unit vector normal for all vertices of the polygon mesh.
*
* @tparam PolygonMesh a model of `FaceListGraph`
* @tparam VertexNormalMap a model of `WritablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
the return type of `compute_vertex_normal()` as value type.
* `boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
* the return type of `compute_vertex_normal()` as value type.
*
* @param pmesh the polygon mesh
* @param vnm the property map in which the normals are written
* @param vertex_normals the property map in which the normals are written
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
@ -290,38 +695,82 @@ compute_vertex_normal(typename boost::graph_traits<PolygonMesh>::vertex_descript
* If `Kernel::FT` does not have a `sqrt()` operation, the square root computation
* will be done approximately.
*/
template <typename PolygonMesh
, typename VertexNormalMap
, typename NamedParameters
>
void
compute_vertex_normals(const PolygonMesh& pmesh
, VertexNormalMap vnm
, const NamedParameters& np
)
template <typename PolygonMesh, typename VertexNormalMap, typename NamedParameters>
void compute_vertex_normals(const PolygonMesh& pmesh,
VertexNormalMap vertex_normals,
const NamedParameters& np)
{
typedef typename GetGeomTraits<PolygonMesh,NamedParameters>::type Kernel;
using parameters::choose_parameter;
using parameters::is_default_parameter;
using parameters::get_parameter;
for(typename boost::graph_traits<PolygonMesh>::vertex_descriptor v : vertices(pmesh)){
typename Kernel::Vector_3 vec = compute_vertex_normal(v, pmesh, np);
put(vnm, v, vec);
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
typedef typename GetGeomTraits<PolygonMesh,NamedParameters>::type GT;
typedef typename GT::Vector_3 Vector_3;
typedef CGAL::dynamic_face_property_t<Vector_3> Face_normal_tag;
typedef typename boost::property_map<PolygonMesh, Face_normal_tag>::const_type Face_normal_dmap;
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
typedef typename GetVertexPointMap<PolygonMesh, NamedParameters>::const_type VPMap;
VPMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point),
get_const_property_map(vertex_point, pmesh));
#endif
typedef typename internal_np::Lookup_named_param_def<internal_np::face_normal_t,
NamedParameters,
Face_normal_dmap>::type Face_normal_map;
Face_normal_map face_normals = choose_parameter(get_parameter(np, internal_np::face_normal),
get(Face_normal_tag(), pmesh));
const bool must_compute_face_normals = is_default_parameter(get_parameter(np, internal_np::face_normal));
if(must_compute_face_normals)
compute_face_normals(pmesh, face_normals, np);
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
std::ofstream out("computed_normals.cgal.polylines.txt");
const Bbox_3 bb = bbox(pmesh, np);
const typename GT::FT bbox_diagonal = CGAL::sqrt(CGAL::square(bb.xmax() - bb.xmin()) +
CGAL::square(bb.ymax() - bb.ymin()) +
CGAL::square(bb.zmax() - bb.zmin()));
#endif
for(vertex_descriptor v : vertices(pmesh))
{
const Vector_3 n = compute_vertex_normal(v, pmesh, np.face_normal_map(face_normals));
put(vertex_normals, v, n);
#ifdef CGAL_PMP_COMPUTE_NORMAL_DEBUG_PP
out << "2 " << get(vpmap, v) << " "
<< get(vpmap, v) + traits.construct_scaled_vector_3_object()(n, 0.1 * bbox_diagonal) << "\n";
#endif
}
}
template <typename PolygonMesh, typename VertexNormalMap>
void compute_vertex_normals(const PolygonMesh& pmesh, VertexNormalMap vertex_normals)
{
compute_vertex_normals(pmesh, vertex_normals, CGAL::parameters::all_default());
}
/**
* \ingroup PMP_normal_grp
* computes the outward unit vector normal for all vertices and faces of the polygon mesh.
*
* @tparam PolygonMesh a model of `FaceListGraph`
* @tparam VertexNormalMap a model of `WritablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
`Kernel::Vector_3` as value type.
* `boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
* `Kernel::Vector_3` as value type.
* @tparam FaceNormalMap a model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and
`Kernel::Vector_3` as value type.
* `boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and
* `Kernel::Vector_3` as value type.
*
* @param pmesh the polygon mesh
* @param vnm the property map in which the vertex normals are written
* @param fnm the property map in which the face normals are written
* @param vertex_normals the property map in which the vertex normals are written
* @param face_normals the property map in which the face normals are written
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
@ -335,79 +784,27 @@ compute_vertex_normals(const PolygonMesh& pmesh
* If `Kernel::FT` does not have a `sqrt()` operation, the square root computation
* will be done approximately.
*/
template <typename PolygonMesh
, typename VertexNormalMap
, typename FaceNormalMap
, typename NamedParameters
>
void
compute_normals(const PolygonMesh& pmesh
, VertexNormalMap vnm
, FaceNormalMap fnm
, const NamedParameters& np
)
template <typename PolygonMesh,
typename VertexNormalMap, typename FaceNormalMap,
typename NamedParameters>
void compute_normals(const PolygonMesh& pmesh,
VertexNormalMap vertex_normals,
FaceNormalMap face_normals,
const NamedParameters& np)
{
compute_face_normals(pmesh, fnm, np);
compute_vertex_normals(pmesh, vnm, np.face_normal_map(fnm));
compute_face_normals(pmesh, face_normals, np);
compute_vertex_normals(pmesh, vertex_normals, np.face_normal_map(face_normals));
}
///\cond SKIP_IN_MANUAL
// compute_vertex_normal overloads
template <typename PolygonMesh>
typename CGAL::Kernel_traits< typename property_map_value<PolygonMesh, CGAL::vertex_point_t>::type>::Kernel::Vector_3
compute_vertex_normal(
typename boost::graph_traits<PolygonMesh>::vertex_descriptor v,
const PolygonMesh& pmesh)
{
return compute_vertex_normal(v, pmesh,
CGAL::Polygon_mesh_processing::parameters::all_default());
}
// compute_vertex_normals overloads
template <typename PolygonMesh, typename VertexNormalMap>
void
compute_vertex_normals(const PolygonMesh& pmesh,
VertexNormalMap vnm)
{
compute_vertex_normals(pmesh, vnm,
CGAL::Polygon_mesh_processing::parameters::all_default());
}
// compute_face_normal overload
template <typename PolygonMesh>
typename CGAL::Kernel_traits < typename property_map_value<PolygonMesh, CGAL::vertex_point_t>::type>::Kernel::Vector_3
compute_face_normal(
typename boost::graph_traits<PolygonMesh>::face_descriptor f,
const PolygonMesh& pmesh)
{
return compute_face_normal(f, pmesh,
CGAL::Polygon_mesh_processing::parameters::all_default());
}
// compute_face_normals overload
template <typename PolygonMesh, typename FaceNormalMap>
void
compute_face_normals(const PolygonMesh& pmesh, FaceNormalMap fnm)
{
compute_face_normals(pmesh, fnm,
CGAL::Polygon_mesh_processing::parameters::all_default());
}
// compute_normals overload
template <typename PolygonMesh, typename VertexNormalMap, typename FaceNormalMap>
void
compute_normals(const PolygonMesh& pmesh,
VertexNormalMap vnm,
FaceNormalMap fnm)
void compute_normals(const PolygonMesh& pmesh,
VertexNormalMap vertex_normals,
FaceNormalMap face_normals)
{
compute_normals(pmesh, vnm, fnm,
CGAL::Polygon_mesh_processing::parameters::all_default());
compute_normals(pmesh, vertex_normals, face_normals, CGAL::parameters::all_default());
}
/// \endcond
}
} // end of namespace CGAL::Polygon_mesh_processing
} // namespace Polygon_mesh_processing
} // namespace CGAL
#endif // CGAL_POLYGON_MESH_PROCESSING_COMPUTE_NORMAL_H

View File

@ -27,14 +27,14 @@
#include <boost/graph/connected_components.hpp>
#include <boost/property_map/vector_property_map.hpp>
#include <CGAL/assertions.h>
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/assertions.h>
#include <CGAL/tuple.h>
#include <CGAL/boost/graph/Dual.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/Default.h>
#include <CGAL/Dynamic_property_map.h>
#include <CGAL/iterator.h>
#include <CGAL/tuple.h>
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
@ -238,12 +238,9 @@ typename boost::property_traits<FaceComponentMap>::value_type
connected_components(const PolygonMesh& pmesh,
FaceComponentMap fcm)
{
return CGAL::Polygon_mesh_processing::connected_components(pmesh, fcm,
CGAL::Polygon_mesh_processing::parameters::all_default());
return CGAL::Polygon_mesh_processing::connected_components(pmesh, fcm, CGAL::parameters::all_default());
}
template <typename PolygonMesh
, typename ComponentRange
, typename FaceComponentMap
@ -253,6 +250,50 @@ void keep_connected_components(PolygonMesh& pmesh
, const FaceComponentMap& fcm
, const NamedParameters& np);
namespace internal {
// /*!
// * \ingroup keep_connected_components_grp
// * returns the number of connected components in the mesh.
// *
// * A property map for `CGAL::face_index_t` must be either available as an internal property map
// * to `pmesh` or provided as one of the \ref pmp_namedparameters "Named Parameters".
// *
// * \tparam PolygonMesh a model of `FaceGraph`
// * \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
// *
// * \param pmesh the polygon mesh
// * \param np optional \ref pmp_namedparameters "Named Parameters" described below
// *
// * \cgalNamedParamsBegin
// * \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd
// * \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh` \cgalParamEnd
// * \cgalNamedParamsEnd
// *
// * \returns the output iterator.
// *
// */
template <typename PolygonMesh,
typename CGAL_PMP_NP_TEMPLATE_PARAMETERS>
std::size_t number_of_connected_components(const PolygonMesh& pmesh,
const CGAL_PMP_NP_CLASS& np)
{
typedef CGAL::dynamic_face_property_t<std::size_t> Face_property_tag;
typedef typename boost::property_map<PolygonMesh, Face_property_tag >::const_type Patch_ids_map;
Patch_ids_map patch_ids_map = get(Face_property_tag(), pmesh);
return CGAL::Polygon_mesh_processing::connected_components(pmesh, patch_ids_map, np);
}
template <typename PolygonMesh>
std::size_t number_of_connected_components(const PolygonMesh& pmesh)
{
return internal::number_of_connected_components(pmesh, CGAL::parameters::all_default());
}
} // end namespace internal
/*!
* \ingroup keep_connected_components_grp
*
@ -270,7 +311,8 @@ void keep_connected_components(PolygonMesh& pmesh
* \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
*
* \param pmesh the polygon mesh
* \param nb_components_to_keep the number of components to be kept
* \param nb_components_to_keep the number of components to be kept. If this number is larger than
* the number of components in the mesh, all components are kept.
* \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below
*
* \cgalNamedParamsBegin
@ -282,6 +324,14 @@ void keep_connected_components(PolygonMesh& pmesh
* is chosen by the user, but must be constructible from `0` and support `operator+=()` and
* comparisons.
* \cgalParamEnd
* \cgalParamBegin{dry_run}
* a Boolean parameter. If set to `true`, the mesh will not be altered, but the number
* of components that would be removed is returned. The default value is `false`.
* \cgalParamEnd
* \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type `face_descriptor`.
* When using the "dry run" mode (see parameter `dry_run`), faces that would be removed by the
* algorithm can be collected with this output iterator.
* \cgalParamEnd
* \cgalNamedParamsEnd
*
* \return the number of connected components removed (ignoring isolated vertices).
@ -313,6 +363,13 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh,
FaceSizeMap face_size_pmap = choose_parameter(get_parameter(np, internal_np::face_size_map),
Constant_property_map<face_descriptor, std::size_t>(1));
const bool dry_run = choose_parameter(get_parameter(np, internal_np::dry_run), false);
typedef typename internal_np::Lookup_named_param_def<internal_np::output_iterator_t,
NamedParameters,
Emptyset_iterator>::type Output_iterator;
Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator), Emptyset_iterator());
// vector_property_map
boost::vector_property_map<std::size_t, FaceIndexMap> face_cc(fimap);
std::size_t num = connected_components(pmesh, face_cc, np);
@ -320,12 +377,13 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh,
// Even if we do not want to keep anything we need to first
// calculate the number of existing connected_components to get the
// correct return value.
if(nb_components_to_keep == 0) {
if(nb_components_to_keep == 0)
{
CGAL::clear(pmesh);
return num;
}
if((num == 1)|| (nb_components_to_keep > num) )
if(nb_components_to_keep >= num)
return 0;
std::vector<std::pair<std::size_t, Face_size> > component_size(num);
@ -338,11 +396,25 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh,
// we sort the range [0, num) by component size
std::sort(component_size.begin(), component_size.end(), internal::MoreSecond());
if(dry_run)
{
std::vector<bool> is_to_be_removed(num, false);
for(std::size_t i=0; i<nb_components_to_keep; ++i)
is_to_be_removed[component_size[i].first] = true;
for(face_descriptor f : faces(pmesh))
if(is_to_be_removed[face_cc[f]])
*out++ = f;
}
else
{
std::vector<std::size_t> cc_to_keep;
for(std::size_t i=0; i<nb_components_to_keep; ++i)
cc_to_keep.push_back(component_size[i].first);
keep_connected_components(pmesh, cc_to_keep, face_cc, np);
}
return num - nb_components_to_keep;
}
@ -385,6 +457,14 @@ std::size_t keep_largest_connected_components(PolygonMesh& pmesh,
* is chosen by the user, but must be constructible from `0` and support `operator+=()` and
* comparisons.
* \cgalParamEnd
* \cgalParamBegin{dry_run}
* a Boolean parameter. If set to `true`, the mesh will not be altered, but the number
* of components that would be removed is returned. The default value is `false`.
* \cgalParamEnd
* \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type `face_descriptor`.
* When using the "dry run" mode (see parameter `dry_run`), faces that would be removed by the
* algorithm can be collected with this output iterator.
* \cgalParamEnd
* \cgalNamedParamsEnd
*
* \pre If a face size property map is passed by the user, `ThresholdValueType` must be the same
@ -418,34 +498,54 @@ std::size_t keep_large_connected_components(PolygonMesh& pmesh,
CGAL_static_assertion((std::is_convertible<ThresholdValueType, Face_size>::value));
typedef typename internal_np::Lookup_named_param_def<internal_np::output_iterator_t,
NamedParameters,
Emptyset_iterator>::type Output_iterator;
FaceSizeMap face_size_pmap = choose_parameter(get_parameter(np, internal_np::face_size_map),
Constant_property_map<face_descriptor, std::size_t>(1));
const bool dry_run = choose_parameter(get_parameter(np, internal_np::dry_run), false);
Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator), Emptyset_iterator());
// vector_property_map
boost::vector_property_map<std::size_t, FaceIndexMap> face_cc(fim);
std::size_t num = connected_components(pmesh, face_cc, np);
std::vector<Face_size> component_size(num);
for(std::size_t i=0; i<num; ++i)
component_size[i] = Face_size(0);
std::vector<Face_size> component_size(num, 0);
for(face_descriptor f : faces(pmesh))
component_size[face_cc[f]] += get(face_size_pmap, f);
const Face_size thresh = threshold_value;
std::vector<bool> is_to_be_kept(num, false);
std::size_t res = 0;
std::vector<std::size_t> cc_to_keep;
for(std::size_t i=0; i<num; ++i)
{
if(component_size[i] >= thresh)
cc_to_keep.push_back(i);
{
is_to_be_kept[i] = true;
++res;
}
}
keep_connected_components(pmesh, cc_to_keep, face_cc, np);
if(dry_run)
{
for(face_descriptor f : faces(pmesh))
if(!is_to_be_kept[face_cc[f]])
*out++ = f;
}
else
{
std::vector<std::size_t> ccs_to_keep;
for(std::size_t i=0; i<num; ++i)
if(is_to_be_kept[i])
ccs_to_keep.push_back(i);
return num - cc_to_keep.size();
keep_connected_components(pmesh, ccs_to_keep, face_cc, np);
}
return num - res;
}
template <typename PolygonMesh>
std::size_t keep_large_connected_components(PolygonMesh& pmesh,

View File

@ -326,7 +326,8 @@ face_area(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
halfedge_descriptor hd = halfedge(f, tmesh);
halfedge_descriptor nhd = next(hd, tmesh);
typename GetGeomTraits<TriangleMesh, CGAL_PMP_NP_CLASS>::type traits;
typedef typename GetGeomTraits<TriangleMesh, CGAL_PMP_NP_CLASS>::type GT;
GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
return approximate_sqrt(traits.compute_squared_area_3_object()(get(vpm, source(hd, tmesh)),
get(vpm, target(hd, tmesh)),

View File

@ -29,8 +29,10 @@
#include <CGAL/boost/graph/selection.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Polygon_mesh_processing/shape_predicates.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
@ -60,6 +62,284 @@
namespace CGAL {
namespace Polygon_mesh_processing {
/// \ingroup PMP_repairing_grp
/// removes the isolated vertices from any polygon mesh.
/// A vertex is considered isolated if it is not incident to any simplex
/// of higher dimension.
///
/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`
///
/// @param pmesh the polygon mesh to be repaired
///
/// @return number of removed isolated vertices
///
template <class PolygonMesh>
std::size_t remove_isolated_vertices(PolygonMesh& pmesh)
{
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
std::vector<vertex_descriptor> to_be_removed;
for(vertex_descriptor v : vertices(pmesh))
{
if (CGAL::halfedges_around_target(v, pmesh).first
== CGAL::halfedges_around_target(v, pmesh).second)
to_be_removed.push_back(v);
}
std::size_t nb_removed = to_be_removed.size();
for(vertex_descriptor v : to_be_removed)
{
remove_vertex(v, pmesh);
}
return nb_removed;
}
/// \ingroup PMP_repairing_grp
///
/// removes connected components whose area or volume is under a certain threshold value.
///
/// Thresholds are provided via \ref pmp_namedparameters "Named Parameters". (see below).
/// If thresholds are not provided by the user, default values are computed as follows:
/// - the area threshold is taken as the square of one percent of the length of the diagonal
/// of the bounding box of the mesh.
/// - the volume threshold is taken as the third power of one percent of the length of the diagonal
/// of the bounding box of the mesh.
///
/// The area and volume of a connected component will always be positive values (regardless
/// of the orientation of the mesh).
///
/// As a consequence of the last sentence, the area or volume criteria can be disabled
/// by passing zero (`0`) as threshold value.
///
/// Property maps for `CGAL::face_index_t` and `CGAL::vertex_index_t`
/// must be either available as internal property maps
/// to `tmesh` or provided as \ref pmp_namedparameters "Named Parameters".
///
/// \tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph`
/// \tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
///
/// \param tmesh the triangulated polygon mesh
/// \param np optional \ref pmp_namedparameters "Named Parameters", amongst those described below
///
/// \cgalNamedParamsBegin
/// \cgalParamBegin{area_threshold} a fixed value such that only connected components whose area is
/// larger than this value are kept \cgalParamEnd
/// \cgalParamBegin{volume_threshold} a fixed value such that only connected components whose volume is
/// larger than this value are kept (only applies to closed connected components) \cgalParamEnd
/// \cgalParamBegin{edge_is_constrained_map} a property map containing the constrained-or-not status of each edge of `pmesh` \cgalParamEnd
/// \cgalParamBegin{face_index_map} a property map containing the index of each face of `tmesh` \cgalParamEnd
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`.
/// If this parameter is omitted, an internal property map for
/// `CGAL::vertex_point_t` should be available in `TriangleMesh` \cgalParamEnd
/// \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel` \cgalParamEnd
/// \cgalParamBegin{dry_run} a Boolean parameter. If set to `true`, the mesh will not be altered,
/// but the number of components that would be removed is returned. The default value is `false`.\cgalParamEnd
/// \cgalParamBegin{output_iterator} a model of `OutputIterator` with value type `face_descriptor`.
/// When using the "dry run" mode (see parameter `dry_run`), faces
/// that would be removed by the algorithm can be collected with this output iterator. \cgalParamEnd
/// \cgalNamedParamsEnd
///
/// \return the number of connected components removed (ignoring isolated vertices).
///
template <typename TriangleMesh,
typename NamedParameters>
std::size_t remove_connected_components_of_negligible_size(TriangleMesh& tmesh,
const NamedParameters& np)
{
using parameters::choose_parameter;
using parameters::is_default_parameter;
using parameters::get_parameter;
typedef typename boost::graph_traits<TriangleMesh>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type GT;
typedef typename GT::FT FT;
const GT traits = choose_parameter(get_parameter(np, internal_np::vertex_point), GT());
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::const_type VPM;
typedef typename boost::property_traits<VPM>::value_type Point_3;
const VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, tmesh));
typedef typename GetFaceIndexMap<TriangleMesh, NamedParameters>::type FaceIndexMap;
FaceIndexMap fim = choose_parameter(get_parameter(np, internal_np::face_index),
get_property_map(boost::face_index, tmesh));
FT area_threshold = choose_parameter(get_parameter(np, internal_np::area_threshold), FT(-1));
FT volume_threshold = choose_parameter(get_parameter(np, internal_np::volume_threshold), FT(-1));
// If no threshold is provided, compute it as a % of the bbox
const bool is_default_area_threshold = is_default_parameter(get_parameter(np, internal_np::area_threshold));
const bool is_default_volume_threshold = is_default_parameter(get_parameter(np, internal_np::volume_threshold));
const bool dry_run = choose_parameter(get_parameter(np, internal_np::dry_run), false);
typedef typename internal_np::Lookup_named_param_def<internal_np::output_iterator_t,
NamedParameters,
Emptyset_iterator>::type Output_iterator;
Output_iterator out = choose_parameter(get_parameter(np, internal_np::output_iterator), Emptyset_iterator());
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << "default threshold? " << is_default_area_threshold << " " << is_default_volume_threshold << std::endl;
#endif
FT bbox_diagonal = FT(0), threshold_value = FT(0);
if(is_default_area_threshold || is_default_volume_threshold)
{
if(is_empty(tmesh))
return 0;
const Bbox_3 bb = bbox(tmesh, np);
bbox_diagonal = FT(CGAL::sqrt(CGAL::square(bb.xmax() - bb.xmin()) +
CGAL::square(bb.ymax() - bb.ymin()) +
CGAL::square(bb.zmax() - bb.zmin())));
threshold_value = bbox_diagonal / FT(100); // default filter is 1%
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << "bb xmin xmax: " << bb.xmin() << " " << bb.xmax() << std::endl;
std::cout << "bb ymin ymax: " << bb.ymin() << " " << bb.ymax() << std::endl;
std::cout << "bb zmin zmax: " << bb.zmin() << " " << bb.zmax() << std::endl;
std::cout << "bbox_diagonal: " << bbox_diagonal << std::endl;
std::cout << "threshold_value: " << threshold_value << std::endl;
#endif
}
if(is_default_area_threshold)
area_threshold = CGAL::square(threshold_value);
if(is_default_volume_threshold)
volume_threshold = CGAL::square(threshold_value);
const bool use_areas = (is_default_area_threshold || area_threshold > 0);
const bool use_volumes = (is_default_volume_threshold || volume_threshold > 0);
if(!use_areas && !use_volumes)
return 0;
// Compute the connected components only once
boost::vector_property_map<std::size_t, FaceIndexMap> face_cc(fim);
std::size_t num = connected_components(tmesh, face_cc, np);
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << num << " different connected components" << std::endl;
#endif
if(!dry_run)
CGAL::Polygon_mesh_processing::remove_isolated_vertices(tmesh);
// Compute CC-wide and total areas/volumes
FT total_area = 0;
std::vector<FT> component_areas(num, 0);
if(use_areas)
{
for(face_descriptor f : faces(tmesh))
{
const FT fa = face_area(f, tmesh, np);
component_areas[face_cc[f]] += fa;
total_area += fa;
}
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << "area threshold: " << area_threshold << std::endl;
std::cout << "total area: " << total_area << std::endl;
#endif
}
// Volumes make no sense for CCs that are not closed
std::vector<bool> cc_closeness(num, true);
std::vector<FT> component_volumes(num);
if(use_volumes)
{
for(halfedge_descriptor h : halfedges(tmesh))
{
if(is_border(h, tmesh))
cc_closeness[face_cc[face(opposite(h, tmesh), tmesh)]] = false;
}
typename GT::Compute_volume_3 cv3 = traits.compute_volume_3_object();
Point_3 origin(0, 0, 0);
for(face_descriptor f : faces(tmesh))
{
const std::size_t i = face_cc[f];
if(!cc_closeness[i])
continue;
const FT fv = cv3(origin,
get(vpm, target(halfedge(f, tmesh), tmesh)),
get(vpm, target(next(halfedge(f, tmesh), tmesh), tmesh)),
get(vpm, target(prev(halfedge(f, tmesh), tmesh), tmesh)));
component_volumes[i] += fv;
}
// negative volume means the CC was oriented inward
FT total_volume = 0;
for(std::size_t i=0; i<num; ++i)
{
component_volumes[i] = CGAL::abs(component_volumes[i]);
total_volume += component_volumes[i];
}
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << "volume threshold: " << volume_threshold << std::endl;
std::cout << "total volume: " << total_volume << std::endl;
#endif
}
std::size_t res = 0;
std::vector<bool> is_to_be_removed(num, false);
for(std::size_t i=0; i<num; ++i)
{
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << "CC " << i << " has area: " << component_areas[i]
<< " and volume: " << component_volumes[i] << std::endl;
#endif
if((use_volumes && cc_closeness[i] && component_volumes[i] <= volume_threshold) ||
(use_areas && component_areas[i] <= area_threshold))
{
is_to_be_removed[i] = true;
++res;
}
}
#ifdef CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
std::cout << "Removing " << res << " CCs" << std::endl;
#endif
if(dry_run)
{
for(face_descriptor f : faces(tmesh))
if(is_to_be_removed[face_cc[f]])
*out++ = f;
}
else
{
std::vector<std::size_t> ccs_to_remove;
for(std::size_t i=0; i<num; ++i)
if(is_to_be_removed[i])
ccs_to_remove.push_back(i);
remove_connected_components(tmesh, ccs_to_remove, face_cc, np);
CGAL_expensive_postcondition(is_valid_polygon_mesh(tmesh));
}
return res;
}
template <typename TriangleMesh>
std::size_t remove_connected_components_of_negligible_size(TriangleMesh& tmesh)
{
return remove_connected_components_of_negligible_size(tmesh, parameters::all_default());
}
namespace debug{
template <class TriangleMesh, class VertexPointMap>
@ -2368,37 +2648,6 @@ std::size_t duplicate_non_manifold_vertices(PolygonMesh& pm)
return duplicate_non_manifold_vertices(pm, parameters::all_default());
}
/// \ingroup PMP_repairing_grp
/// removes the isolated vertices from any polygon mesh.
/// A vertex is considered isolated if it is not incident to any simplex
/// of higher dimension.
///
/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph`
///
/// @param pmesh the polygon mesh to be repaired
///
/// @return number of removed isolated vertices
///
template <class PolygonMesh>
std::size_t remove_isolated_vertices(PolygonMesh& pmesh)
{
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
std::vector<vertex_descriptor> to_be_removed;
for(vertex_descriptor v : vertices(pmesh))
{
if (CGAL::halfedges_around_target(v, pmesh).first
== CGAL::halfedges_around_target(v, pmesh).second)
to_be_removed.push_back(v);
}
std::size_t nb_removed = to_be_removed.size();
for(vertex_descriptor v : to_be_removed)
{
remove_vertex(v, pmesh);
}
return nb_removed;
}
/// \cond SKIP_IN_MANUAL
template <class TriangleMesh, class face_descriptor, class VertexPointMap>
std::pair< bool, bool >

View File

@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.1...3.15)
project( Polygon_mesh_processing_Tests )
# CGAL and its components
find_package( CGAL QUIET COMPONENTS )
find_package( CGAL QUIET COMPONENTS Core)
if ( NOT CGAL_FOUND )
@ -14,6 +14,8 @@ if ( NOT CGAL_FOUND )
endif()
include(${CGAL_USE_FILE})
# Boost and its components
find_package( Boost REQUIRED )

View File

@ -45,6 +45,19 @@ void mesh_with_id(const char* argv1, const bool save_output)
assert(num == 3);
std::cerr << "The graph has " << num << " connected components (face connectivity)" << std::endl;
std::size_t nb_faces = num_faces(sm);
std::vector<face_descriptor> faces_to_remove; // faces that would be removed but are not because we're doing a dry run
std::size_t nb_to_remove = PMP::keep_large_connected_components(sm, 1000,
CGAL::parameters::face_size_map(
CGAL::Constant_property_map<face_descriptor, std::size_t>(1))
.dry_run(true)
.output_iterator(std::back_inserter(faces_to_remove)));
assert(!faces_to_remove.empty());
if (strcmp(argv1, "data/blobby_3cc.off") == 0)
{
assert(nb_to_remove == 1);
assert(num_faces(sm) == nb_faces);
}
PMP::keep_largest_connected_components(sm, 2,
CGAL::parameters::face_size_map(

View File

@ -161,8 +161,26 @@ void test_CC_with_area_size_map(Mesh sm,
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
Face_descriptor_area_functor<Mesh, Kernel> f(sm, k);
std::vector<face_descriptor> faces_to_remove; // faces that would be removed but are not because we're doing a dry run
std::size_t nv = num_vertices(sm);
std::size_t num = PMP::internal::number_of_connected_components(sm);
std::cout << "We keep the " << 2 << " largest components" << std::endl;
std::size_t res = PMP::keep_largest_connected_components(sm, 2,
PMP::parameters::face_size_map(CGAL::internal::boost_::make_function_property_map<face_descriptor>(f))
.dry_run(true)
.output_iterator(std::back_inserter(faces_to_remove)));
// didn't actually remove anything
assert(PMP::internal::number_of_connected_components(sm) == num);
assert(num_vertices(sm) == nv);
if(num > 2)
{
assert(res == num - 2);
assert(!faces_to_remove.empty());
}
PMP::keep_largest_connected_components(sm, 2,
PMP::parameters::face_size_map(
CGAL::internal::boost_::make_function_property_map<face_descriptor>(f)));
@ -183,6 +201,12 @@ void test_CC_with_area_size_map(Mesh sm,
CGAL::parameters::face_size_map(
CGAL::internal::boost_::make_function_property_map<face_descriptor>(f)));
assert(vertices(m).size() == 3);
PMP::keep_largest_connected_components(m, 1);
assert(PMP::internal::number_of_connected_components(m) == 1);
PMP::keep_largest_connected_components(m, 0);
assert(is_empty(m));
assert(PMP::internal::number_of_connected_components(m) == 0);
}
}

View File

@ -0,0 +1,15 @@
OFF
7 6 0
0.50085999554530469 0.98935974982034269 0.054777016186685679
0.51086414037695982 0.0074532224578913869 0.0098759303387234813
0.23667027533904861 -0.19236191791372245 0.078118737677961653
0.49890739640011506 0.47147692553082188 0.51901846156493603
0.5 0.5 0
0.8400145559724278 0.28990007922508693 -0.53104077094013602
-0.011501240589425327 0.99837637926383715 0.011228717925938695
3 4 5 0
3 1 4 3
3 3 4 6
3 4 0 6
3 1 2 4
3 2 5 4

View File

@ -0,0 +1,371 @@
OFF
141 228 0
-1 -1 1
1 -1 1
1 -1 -1
-1 -1 -1
-1 1 -1
-1 1 1
1 1 1
1 1 -1
-2 1 0
-2 0 -1.0000000000000001e-05
-2.0000100000000001 0 -1.2246467991473532e-21
-2 0 1.0000000000000001e-05
-1.9999899999999999 0 0
-2 0 0
0.066195740892434629 9.7645929666223047e-06 3.4984150593572543
6.123233995736766e-17 0 2
-1 0 3
-1.8369701987210297e-16 0 4
1 0 3
0 0 3
0 4 0
0 4.0000001000000003 0
0 4.0000001999999997 0
1.0000000000000002e-06 4.0000001000000003 0
0 4.0000003 0
1.0000000000000002e-06 4.0000001999999997 0
0 4.0000004000000002 0
1.0000000000000002e-06 4.0000003 0
0 4.0000005000000005 0
1.0000000000000002e-06 4.0000004000000002 0
0 4.0000005999999999 0
1.0000000000000002e-06 4.0000005000000005 0
0 4.0000007000000002 0
1.0000000000000002e-06 4.0000005999999999 0
0 4.0000008000000005 0
1.0000000000000002e-06 4.0000007000000002 0
0 4.0000008999999999 0
1.0000000000000002e-06 4.0000008000000005 0
0 4.0000010000000001 0
1.0000000000000002e-06 4.0000008999999999 0
1.0000000000000002e-06 4.0000010000000001 0
1.0000000000000002e-06 4 0
2.0000000000000003e-06 4.0000001000000003 0
2.0000000000000003e-06 4.0000001999999997 0
2.0000000000000003e-06 4.0000003 0
2.0000000000000003e-06 4.0000004000000002 0
2.0000000000000003e-06 4.0000005000000005 0
2.0000000000000003e-06 4.0000005999999999 0
2.0000000000000003e-06 4.0000007000000002 0
2.0000000000000003e-06 4.0000008000000005 0
2.0000000000000003e-06 4.0000008999999999 0
2.0000000000000003e-06 4.0000010000000001 0
2.0000000000000003e-06 4 0
3.0000000000000005e-06 4.0000001000000003 0
3.0000000000000005e-06 4.0000001999999997 0
3.0000000000000005e-06 4.0000003 0
3.0000000000000005e-06 4.0000004000000002 0
3.0000000000000005e-06 4.0000005000000005 0
3.0000000000000005e-06 4.0000005999999999 0
3.0000000000000005e-06 4.0000007000000002 0
3.0000000000000005e-06 4.0000008000000005 0
3.0000000000000005e-06 4.0000008999999999 0
3.0000000000000005e-06 4.0000010000000001 0
3.0000000000000005e-06 4 0
4.0000000000000007e-06 4.0000001000000003 0
4.0000000000000007e-06 4.0000001999999997 0
4.0000000000000007e-06 4.0000003 0
4.0000000000000007e-06 4.0000004000000002 0
4.0000000000000007e-06 4.0000005000000005 0
4.0000000000000007e-06 4.0000005999999999 0
4.0000000000000007e-06 4.0000007000000002 0
4.0000000000000007e-06 4.0000008000000005 0
4.0000000000000007e-06 4.0000008999999999 0
4.0000000000000007e-06 4.0000010000000001 0
4.0000000000000007e-06 4 0
5.0000000000000004e-06 4.0000001000000003 0
5.0000000000000004e-06 4.0000001999999997 0
5.0000000000000004e-06 4.0000003 0
5.0000000000000004e-06 4.0000004000000002 0
5.0000000000000004e-06 4.0000005000000005 0
5.0000000000000004e-06 4.0000005999999999 0
5.0000000000000004e-06 4.0000007000000002 0
5.0000000000000004e-06 4.0000008000000005 0
5.0000000000000004e-06 4.0000008999999999 0
5.0000000000000004e-06 4.0000010000000001 0
5.0000000000000004e-06 4 0
6.000000000000001e-06 4.0000001000000003 0
6.000000000000001e-06 4.0000001999999997 0
6.000000000000001e-06 4.0000003 0
6.000000000000001e-06 4.0000004000000002 0
6.000000000000001e-06 4.0000005000000005 0
6.000000000000001e-06 4.0000005999999999 0
6.000000000000001e-06 4.0000007000000002 0
6.000000000000001e-06 4.0000008000000005 0
6.000000000000001e-06 4.0000008999999999 0
6.000000000000001e-06 4.0000010000000001 0
6.000000000000001e-06 4 0
7.0000000000000007e-06 4.0000001000000003 0
7.0000000000000007e-06 4.0000001999999997 0
7.0000000000000007e-06 4.0000003 0
7.0000000000000007e-06 4.0000004000000002 0
7.0000000000000007e-06 4.0000005000000005 0
7.0000000000000007e-06 4.0000005999999999 0
7.0000000000000007e-06 4.0000007000000002 0
7.0000000000000007e-06 4.0000008000000005 0
7.0000000000000007e-06 4.0000008999999999 0
7.0000000000000007e-06 4.0000010000000001 0
7.0000000000000007e-06 4 0
8.0000000000000013e-06 4.0000001000000003 0
8.0000000000000013e-06 4.0000001999999997 0
8.0000000000000013e-06 4.0000003 0
8.0000000000000013e-06 4.0000004000000002 0
8.0000000000000013e-06 4.0000005000000005 0
8.0000000000000013e-06 4.0000005999999999 0
8.0000000000000013e-06 4.0000007000000002 0
8.0000000000000013e-06 4.0000008000000005 0
8.0000000000000013e-06 4.0000008999999999 0
8.0000000000000013e-06 4.0000010000000001 0
8.0000000000000013e-06 4 0
9.0000000000000002e-06 4.0000001000000003 0
9.0000000000000002e-06 4.0000001999999997 0
9.0000000000000002e-06 4.0000003 0
9.0000000000000002e-06 4.0000004000000002 0
9.0000000000000002e-06 4.0000005000000005 0
9.0000000000000002e-06 4.0000005999999999 0
9.0000000000000002e-06 4.0000007000000002 0
9.0000000000000002e-06 4.0000008000000005 0
9.0000000000000002e-06 4.0000008999999999 0
9.0000000000000002e-06 4.0000010000000001 0
9.0000000000000002e-06 4 0
1.0000000000000001e-05 4 0
1.0000000000000001e-05 4.0000001000000003 0
1.0000000000000001e-05 4.0000001999999997 0
1.0000000000000001e-05 4.0000003 0
1.0000000000000001e-05 4.0000004000000002 0
1.0000000000000001e-05 4.0000005000000005 0
1.0000000000000001e-05 4.0000005999999999 0
1.0000000000000001e-05 4.0000007000000002 0
1.0000000000000001e-05 4.0000008000000005 0
1.0000000000000001e-05 4.0000008999999999 0
1.0000000000000001e-05 4.0000010000000001 0
3 4 5 6
3 0 3 2
3 1 2 7
3 0 1 6
3 3 0 5
3 2 3 4
3 6 7 4
3 2 1 0
3 7 6 1
3 6 5 0
3 5 4 3
3 4 7 2
3 9 8 12
3 10 8 9
3 11 8 10
3 12 8 11
3 12 13 9
3 9 13 10
3 10 13 11
3 11 13 12
3 15 14 18
3 16 14 15
3 17 14 16
3 18 14 17
3 18 19 15
3 15 19 16
3 16 19 17
3 17 19 18
3 21 20 41
3 21 41 23
3 22 21 23
3 22 23 25
3 24 22 25
3 24 25 27
3 26 24 27
3 26 27 29
3 28 26 29
3 28 29 31
3 30 28 31
3 30 31 33
3 32 30 33
3 32 33 35
3 34 32 35
3 34 35 37
3 36 34 37
3 36 37 39
3 38 36 39
3 38 39 40
3 23 41 52
3 23 52 42
3 25 23 42
3 25 42 43
3 27 25 43
3 27 43 44
3 29 27 44
3 29 44 45
3 31 29 45
3 31 45 46
3 33 31 46
3 33 46 47
3 35 33 47
3 35 47 48
3 37 35 48
3 37 48 49
3 39 37 49
3 39 49 50
3 40 39 50
3 40 50 51
3 42 52 63
3 42 63 53
3 43 42 53
3 43 53 54
3 44 43 54
3 44 54 55
3 45 44 55
3 45 55 56
3 46 45 56
3 46 56 57
3 47 46 57
3 47 57 58
3 48 47 58
3 48 58 59
3 49 48 59
3 49 59 60
3 50 49 60
3 50 60 61
3 51 50 61
3 51 61 62
3 53 63 74
3 53 74 64
3 54 53 64
3 54 64 65
3 55 54 65
3 55 65 66
3 56 55 66
3 56 66 67
3 57 56 67
3 57 67 68
3 58 57 68
3 58 68 69
3 59 58 69
3 59 69 70
3 60 59 70
3 60 70 71
3 61 60 71
3 61 71 72
3 62 61 72
3 62 72 73
3 64 74 85
3 64 85 75
3 65 64 75
3 65 75 76
3 66 65 76
3 66 76 77
3 67 66 77
3 67 77 78
3 68 67 78
3 68 78 79
3 69 68 79
3 69 79 80
3 70 69 80
3 70 80 81
3 71 70 81
3 71 81 82
3 72 71 82
3 72 82 83
3 73 72 83
3 73 83 84
3 75 85 96
3 75 96 86
3 76 75 86
3 76 86 87
3 77 76 87
3 77 87 88
3 78 77 88
3 78 88 89
3 79 78 89
3 79 89 90
3 80 79 90
3 80 90 91
3 81 80 91
3 81 91 92
3 82 81 92
3 82 92 93
3 83 82 93
3 83 93 94
3 84 83 94
3 84 94 95
3 86 96 107
3 86 107 97
3 87 86 97
3 87 97 98
3 88 87 98
3 88 98 99
3 89 88 99
3 89 99 100
3 90 89 100
3 90 100 101
3 91 90 101
3 91 101 102
3 92 91 102
3 92 102 103
3 93 92 103
3 93 103 104
3 94 93 104
3 94 104 105
3 95 94 105
3 95 105 106
3 97 107 118
3 97 118 108
3 98 97 108
3 98 108 109
3 99 98 109
3 99 109 110
3 100 99 110
3 100 110 111
3 101 100 111
3 101 111 112
3 102 101 112
3 102 112 113
3 103 102 113
3 103 113 114
3 104 103 114
3 104 114 115
3 105 104 115
3 105 115 116
3 106 105 116
3 106 116 117
3 108 118 129
3 108 129 119
3 109 108 119
3 109 119 120
3 110 109 120
3 110 120 121
3 111 110 121
3 111 121 122
3 112 111 122
3 112 122 123
3 113 112 123
3 113 123 124
3 114 113 124
3 114 124 125
3 115 114 125
3 115 125 126
3 116 115 126
3 116 126 127
3 117 116 127
3 117 127 128
3 119 129 130
3 119 130 131
3 120 119 131
3 120 131 132
3 121 120 132
3 121 132 133
3 122 121 133
3 122 133 134
3 123 122 134
3 123 134 135
3 124 123 135
3 124 135 136
3 125 124 136
3 125 136 137
3 126 125 137
3 126 137 138
3 127 126 138
3 127 138 139
3 128 127 139
3 128 139 140

View File

@ -1,62 +1,165 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
// #define CGAL_PMP_COMPUTE_NORMAL_DEBUG
#include <CGAL/Timer.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <iostream>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic;
typedef CGAL::Exact_predicates_exact_constructions_kernel Epec;
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
typedef CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt EPECK;
typedef CGAL::Surface_mesh<EPICK::Point_3> EPICK_SM;
typedef CGAL::Surface_mesh<EPECK::Point_3> EPECK_SM;
namespace PMP = CGAL::Polygon_mesh_processing;
template <typename K, typename Mesh, typename VertexNormalPmap, typename FaceNormalPmap>
void test(const Mesh& mesh,
const VertexNormalPmap& vnormals,
const FaceNormalPmap& fnormals)
{
typedef typename K::Vector_3 Vector;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef typename CGAL::GetVertexPointMap<Mesh>::const_type VPMap;
VPMap vpmap = get_const_property_map(CGAL::vertex_point, mesh);
assert(!is_empty(mesh));
const vertex_descriptor first_vertex = *(vertices(mesh).begin());
const face_descriptor first_face = *(faces(mesh).begin());
PMP::compute_face_normals(mesh, fnormals);
PMP::compute_face_normals(mesh, fnormals, PMP::parameters::vertex_point_map(vpmap));
PMP::compute_face_normals(mesh, fnormals, CGAL::parameters::vertex_point_map(vpmap)
.geom_traits(K()));
Vector f0n = PMP::compute_face_normal(first_face, mesh);
assert(f0n == get(fnormals, first_face));
PMP::compute_face_normal(first_face, mesh, PMP::parameters::vertex_point_map(vpmap));
PMP::compute_vertex_normals(mesh, vnormals);
PMP::compute_vertex_normals(mesh, vnormals, PMP::parameters::vertex_point_map(vpmap));
PMP::compute_vertex_normals(mesh, vnormals, CGAL::parameters::vertex_point_map(vpmap)
.geom_traits(K()));
Vector v0n = PMP::compute_vertex_normal(first_vertex, mesh);
assert(v0n == get(vnormals, first_vertex));
v0n = PMP::compute_vertex_normal(first_vertex, mesh, PMP::parameters::vertex_point_map(vpmap)
.face_normal_map(fnormals));
std::cout.precision(17);
assert(v0n == get(vnormals, first_vertex));
PMP::compute_normals(mesh, vnormals, fnormals);
PMP::compute_normals(mesh, vnormals, fnormals, PMP::parameters::vertex_point_map(vpmap));
PMP::compute_normals(mesh, vnormals, fnormals, CGAL::parameters::vertex_point_map(vpmap)
.geom_traits(K()));
for(vertex_descriptor v : vertices(mesh)) {
assert(get(vnormals, v) != CGAL::NULL_VECTOR);
}
for(face_descriptor f : faces(mesh)) {
assert(get(fnormals, f) != CGAL::NULL_VECTOR);
}
}
template<typename K>
void test_normals(const char* file_name)
void test_SM(const char* file_name)
{
typedef typename K::Point_3 Point;
typedef typename K::Vector_3 Vector;
typedef CGAL::Surface_mesh<Point> Surface_mesh;
typedef typename boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Surface_mesh>::face_descriptor face_descriptor;
typedef CGAL::Surface_mesh<typename K::Point_3> SM;
typedef typename boost::graph_traits<SM>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<SM>::face_descriptor face_descriptor;
Surface_mesh mesh;
typedef typename K::Vector_3 Vector;
std::cout << "Test with Surface_mesh, and kernel: " << typeid(K).name() << std::endl;
SM mesh;
std::ifstream input(file_name);
if (!(input >> mesh)){
std::cerr << "Error: cannot read Surface_mesh : " << file_name << "\n";
if(!(input >> mesh))
{
std::cerr << "Error: cannot read " << file_name << " as a Surface_mesh\n";
assert(false);
}
typename Surface_mesh::template Property_map<face_descriptor, Vector> fnormals;
bool created;
boost::tie(fnormals, created) = mesh.template add_property_map<face_descriptor,Vector>("f:normals",Vector(0,0,0));
CGAL::Polygon_mesh_processing::compute_face_normals(mesh, fnormals);
CGAL::Polygon_mesh_processing::compute_face_normals(mesh, fnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()));
CGAL::Polygon_mesh_processing::compute_face_normals(mesh, fnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).geom_traits(K()));
typename SM::template Property_map<vertex_descriptor, Vector> vnormals;
vnormals = mesh.template add_property_map<vertex_descriptor, Vector>("v:normals", CGAL::NULL_VECTOR).first;
typename SM::template Property_map<face_descriptor, Vector> fnormals;
fnormals = mesh.template add_property_map<face_descriptor, Vector>("f:normals", CGAL::NULL_VECTOR).first;
typename Surface_mesh:: template Property_map<vertex_descriptor,Vector> vnormals;
test<K>(mesh, vnormals, fnormals);
}
boost::tie(vnormals, created) = mesh.template add_property_map<vertex_descriptor,Vector>("v:normals",Vector(0,0,0));
CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, vnormals);
CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, vnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()));
CGAL::Polygon_mesh_processing::compute_vertex_normals(mesh, vnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).geom_traits(K()));
template<typename K>
void test_Polyhedron(const char* file_name)
{
typedef CGAL::Polyhedron_3<K> Polyhedron;
typedef typename boost::graph_traits<Polyhedron>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Polyhedron>::face_descriptor face_descriptor;
CGAL::Polygon_mesh_processing::compute_normals(mesh, vnormals, fnormals);
CGAL::Polygon_mesh_processing::compute_normals(mesh, vnormals, fnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()));
CGAL::Polygon_mesh_processing::compute_normals(mesh, vnormals, fnormals,
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(mesh.points()).geom_traits(K()));
typedef typename K::Vector_3 Vector;
std::cout << "Test with Polyhedron, and kernel: " << typeid(K).name() << std::endl;
Polyhedron mesh;
std::ifstream input(file_name);
if(!(input >> mesh))
{
std::cerr << "Error: cannot read " << file_name << " as a Polyhedron\n";
assert(false);
}
typedef std::map<vertex_descriptor, Vector> VertexNormalMap;
typedef boost::associative_property_map<VertexNormalMap> VertexNormalPMap;
typedef std::map<face_descriptor, Vector> FaceNormalMap;
typedef boost::associative_property_map<FaceNormalMap> FaceNormalPMap;
VertexNormalMap vn_map;
FaceNormalMap fn_map;
for(vertex_descriptor v : vertices(mesh))
vn_map[v] = CGAL::NULL_VECTOR;
for(face_descriptor f : faces(mesh))
fn_map[f] = CGAL::NULL_VECTOR;
VertexNormalPMap vnormals(vn_map);
FaceNormalPMap fnormals(fn_map);
test<K>(mesh, vnormals, fnormals);
}
void test(const char* filename)
{
std::cout << "test " << filename << "..." << std::endl;
// EPECK disabled because it takes too long for the testsuite due to sq roots comparisons,
// but it passed.
test_SM<EPICK>(filename);
// test_SM<EPECK>(filename);
test_Polyhedron<EPICK>(filename);
// test_Polyhedron<EPECK>(filename);
}
int main()
{
test_normals<Epic>("data/elephant.off");
test_normals<Epec>("data/elephant.off");
std::cout.precision(17);
CGAL::Set_ieee_double_precision pfr;
test("data/elephant.off");
test("data/folded_star.off");
test("data/joint_refined.off");
test("data/mannequin-devil.off");
test("data/U.off");
std::cerr << "All done." << std::endl;
return EXIT_SUCCESS;

View File

@ -1,8 +1,12 @@
#define CGAL_PMP_DEBUG_SMALL_CC_REMOVAL
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/repair.h>
#include <iostream>
@ -14,12 +18,10 @@
//
namespace PMP = CGAL::Polygon_mesh_processing;
namespace CP = CGAL::parameters;
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
typedef CGAL::Surface_mesh<EPICK::Point_3> Surface_mesh;
typedef CGAL::Polyhedron_3<EPICK> Polyhedron;
template <typename K, typename EdgeRange, typename FaceRange, typename Mesh>
void detect_degeneracies(const EdgeRange& edge_range,
const FaceRange& face_range,
@ -34,10 +36,10 @@ void detect_degeneracies(const EdgeRange& edge_range,
std::set<edge_descriptor> dedges;
PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()));
PMP::degenerate_edges(edge_range, mesh, std::inserter(dedges, dedges.begin()));
PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()), CGAL::parameters::all_default());
PMP::degenerate_edges(mesh, std::inserter(dedges, dedges.end()), CP::all_default());
dedges.clear();
PMP::degenerate_edges(edge_range, mesh, std::inserter(dedges, dedges.begin()), CGAL::parameters::all_default());
PMP::degenerate_edges(edge_range, mesh, std::inserter(dedges, dedges.begin()), CP::all_default());
std::cout << "\t" << dedges.size() << " degenerate edges vs " << expected_dedges_n << std::endl;
assert(dedges.size() == expected_dedges_n);
@ -45,10 +47,10 @@ void detect_degeneracies(const EdgeRange& edge_range,
std::vector<face_descriptor> dfaces;
PMP::degenerate_faces(mesh, std::back_inserter(dfaces));
PMP::degenerate_faces(face_range, mesh, std::back_inserter(dfaces));
PMP::degenerate_faces(mesh, std::back_inserter(dfaces), CGAL::parameters::all_default());
PMP::degenerate_faces(mesh, std::back_inserter(dfaces), CP::all_default());
dfaces.clear();
PMP::degenerate_faces(face_range, mesh, std::back_inserter(dfaces), CGAL::parameters::all_default());
PMP::degenerate_faces(face_range, mesh, std::back_inserter(dfaces), CP::all_default());
std::cout << "\t" << dfaces.size() << " degenerate faces vs " << expected_dfaces_n << std::endl;
assert(dfaces.size() == expected_dfaces_n);
}
@ -99,7 +101,7 @@ bool remove_dedges(const std::vector<std::size_t>& edges_selection_ids,
for(std::size_t edge_id : edges_selection_ids)
edge_range.push_back(all_edges[edge_id]);
return CGAL::Polygon_mesh_processing::remove_degenerate_edges(edge_range, mesh, CGAL::parameters::all_default());
return CGAL::Polygon_mesh_processing::remove_degenerate_edges(edge_range, mesh, CP::all_default());
}
template <typename Mesh>
@ -115,11 +117,11 @@ bool remove_dfaces(const std::vector<std::size_t>& faces_selection_ids,
for(std::size_t face_id : faces_selection_ids)
face_range.push_back(all_faces[face_id]);
return CGAL::Polygon_mesh_processing::remove_degenerate_faces(face_range, mesh, CGAL::parameters::all_default());
return CGAL::Polygon_mesh_processing::remove_degenerate_faces(face_range, mesh, CP::all_default());
}
template <typename K, typename Mesh>
void test(const char* filename,
void remove_degeneracies(const char* filename,
const std::vector<std::size_t>& edges_selection_ids,
const std::vector<std::size_t>& faces_selection_ids,
const std::size_t expected_all_degen_edges_n,
@ -129,7 +131,7 @@ void test(const char* filename,
const std::size_t expected_post_removal_degen_edges_n,
const std::size_t expected_post_removal_degen_faces_n)
{
std::cout << " test file: " << filename << std::endl;
std::cout << " remove_degeneracies, file: " << filename << std::endl;
std::ifstream input(filename);
Mesh mesh;
@ -149,12 +151,12 @@ void test(const char* filename,
// Complete remove
std::cout << " Remove all..." << std::endl;
mesh = mesh_cpy;
/* bool all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_edges(mesh, CGAL::parameters::all_default());
/* bool all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_edges(mesh, CP::all_default());
//assert(all_removed);
assert(CGAL::is_valid_polygon_mesh(mesh));
mesh = mesh_cpy;
/* all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh, CGAL::parameters::all_default());
/* all_removed = */ CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh, CP::all_default());
// assert(all_removed);
assert(CGAL::is_valid_polygon_mesh(mesh));
@ -179,69 +181,177 @@ void test(const char* filename,
std::cout << " Done" << std::endl;
}
template <typename Mesh>
void initialize_IDs(const Mesh&) { }
template <typename Kernel>
void initialize_IDs(const CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3>& mesh)
{
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Mesh;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
int i=0;
for(vertex_descriptor v : vertices(mesh))
v->id() = i++;
i=0;
for(face_descriptor f : faces(mesh))
f->id() = i++;
}
template <typename K, typename Mesh>
void remove_negligible_connected_components(const char* filename)
{
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
std::cout << " remove negligible CCs, file: " << filename << std::endl;
std::ifstream input(filename);
Mesh mesh, mesh_cpy;
if (!input || !(input >> mesh) || mesh.is_empty())
{
std::cerr << filename << " is not a valid off file.\n";
exit(1);
}
mesh_cpy = mesh;
initialize_IDs(mesh);
initialize_IDs(mesh_cpy);
std::size_t ini_nv = num_vertices(mesh);
std::size_t ini_nf = num_faces(mesh);
std::cout << "before: " << ini_nv << " nv & " << ini_nf << " nf" << std::endl;
// negative thresholds --> doesn't remove anything
std::cout << "---------\nnull or negative threshold, nothing happens..." << std::endl;
std::size_t res = PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(-1e15)
.volume_threshold(0));
assert(PMP::internal::number_of_connected_components(mesh) == 4);
assert(num_vertices(mesh) == ini_nv);
assert(num_faces(mesh) == ini_nf);
// threshold too small, doesn't remove anything
std::cout << "---------\ntiny threshold, nothing happens..." << std::endl;
PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(1e-15)
.volume_threshold(1e-15));
assert(PMP::internal::number_of_connected_components(mesh) == 4);
assert(num_vertices(mesh) == ini_nv);
assert(num_faces(mesh) == ini_nf);
// that removes the CCs with small volumes
std::cout << "---------\nremove small volumes..." << std::endl;
res = PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(1e-15)
.volume_threshold(0.1));
std::cout << "res: " << res << std::endl;
initialize_IDs(mesh);
assert(PMP::internal::number_of_connected_components(mesh) == 2);
// that removes the open CC with a small area
std::cout << "---------\nremove small areas..." << std::endl;
PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(20));
initialize_IDs(mesh);
assert(PMP::internal::number_of_connected_components(mesh) == 1);
// Remove everything with a too-large value
std::cout << "---------\nremove everything..." << std::endl;
PMP::remove_connected_components_of_negligible_size(mesh, CP::area_threshold(1e15));
assert(is_empty(mesh));
// Could also have used default paramaters, which does the job by itself
std::cout << "---------\ndefault values..." << std::endl;
std::vector<face_descriptor> faces_to_be_removed;
std::size_t nb_to_be_rm = PMP::remove_connected_components_of_negligible_size(
mesh_cpy, CP::dry_run(true)
.output_iterator(std::back_inserter(faces_to_be_removed)));
assert(nb_to_be_rm == 3);
assert(PMP::internal::number_of_connected_components(mesh_cpy) == 4); // a dry run does not remove anything
assert(faces_to_be_removed.size() == 216); // sum of #faces of the small CCs
assert(nb_to_be_rm == PMP::remove_connected_components_of_negligible_size(mesh_cpy));
assert(PMP::internal::number_of_connected_components(mesh_cpy) == 1);
}
template <typename K, typename Mesh>
void test()
{
test<K, Mesh>("data_degeneracies/degtri_2dt_1edge_split_twice.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_2dt_1edge_split_twice.off",
std::initializer_list<std::size_t>({0, 1, 4, 3}), // edge selection
std::initializer_list<std::size_t>({0}), // face selection
0, 2, // expected number of degenerate edges/faces in the complete mesh
0, 1, // expected number of degenerate edges/faces in the selection
0, 0); // expected number of degenerate edges/faces in the mesh after partial removal
test<K, Mesh>("data_degeneracies/degtri_four.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_four.off",
std::initializer_list<std::size_t>({1}),
std::initializer_list<std::size_t>({3}),
0, 1, 0, 0, 0, 1);
test<K, Mesh>("data_degeneracies/degtri_four-2.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_four-2.off",
std::initializer_list<std::size_t>({2}),
std::initializer_list<std::size_t>({3}),
0, 1, 0, 0, 0, 1);
test<K, Mesh>("data_degeneracies/degtri_on_border.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_on_border.off",
std::initializer_list<std::size_t>({2}),
std::initializer_list<std::size_t>({0}),
0, 1, 0, 1, 0, 0);
test<K, Mesh>("data_degeneracies/degtri_three.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_three.off",
std::initializer_list<std::size_t>({2}),
std::initializer_list<std::size_t>({1}),
0, 1, 0, 0, 0, 1);
test<K, Mesh>("data_degeneracies/degtri_single.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_single.off",
std::initializer_list<std::size_t>({0, 1, 2}),
std::initializer_list<std::size_t>({0}),
0, 1, 0, 1, 0, 0);
test<K, Mesh>("data_degeneracies/degtri_nullface.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_nullface.off",
std::initializer_list<std::size_t>({3, 6, 7}),
std::initializer_list<std::size_t>({0, 1, 2}),
3, 4, 1, 2, 0, 0);
test<K, Mesh>("data_degeneracies/trihole.off",
remove_degeneracies<K, Mesh>("data_degeneracies/trihole.off",
std::initializer_list<std::size_t>({12}),
std::initializer_list<std::size_t>({4, 5}),
1, 3, 1, 2, 0, 0);
test<K, Mesh>("data_degeneracies/degtri_sliding.off",
remove_degeneracies<K, Mesh>("data_degeneracies/degtri_sliding.off",
std::initializer_list<std::size_t>({2}),
std::initializer_list<std::size_t>({2, 4}),
0, 4, 0, 2, 0, 0);
test<K, Mesh>("data_degeneracies/fused_vertices.off",
remove_degeneracies<K, Mesh>("data_degeneracies/fused_vertices.off",
std::initializer_list<std::size_t>({5, 10, 13, 15, 27, 45}),
std::initializer_list<std::size_t>({1, 3, 5, 10, 19}),
6, 7, 2, 4, 3, 3);
remove_negligible_connected_components<K, Mesh>("data_degeneracies/small_ccs.off");
}
int main()
template <typename Kernel>
void test()
{
typedef typename Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_with_ID;
std::cout << "EPICK SM TESTS" << std::endl;
test<EPICK, Surface_mesh>();
test<Kernel, Surface_mesh>();
std::cout << "EPICK POLYHEDRON TESTS" << std::endl;
test<EPICK, Polyhedron>();
test<Kernel, Polyhedron_with_ID>();
}
int main(int /*argc*/, char** /*argv*/)
{
test<EPICK>();
std::cout << "Done" << std::endl;
return EXIT_SUCCESS;
}

View File

@ -38,7 +38,7 @@
#include <QSpinBox>
#include <stdexcept>
#include <fstream>
#include <QTime>
#include <QElapsedTimer>
#include <QWidgetAction>
#include <QJsonArray>
#include <QSequentialIterable>
@ -451,7 +451,7 @@ void filterMenuOperations(QMenu* menu, QString filter, bool keep_from_here)
action->setVisible(!(submenu->isEmpty()));
}
else if(action->text().contains(filter, Qt::CaseInsensitive)){
else if(action->text().remove("&").contains(filter, Qt::CaseInsensitive)){
//menu->addAction(action);
addActionToMenu(action, menu);
}
@ -491,7 +491,7 @@ void MainWindow::filterOperations(bool)
Q_FOREACH(const PluginNamePair& p, plugins) {
Q_FOREACH(QAction* action, p.first->actions()) {
action->setVisible( p.first->applicable(action)
&& (action->text().contains(filter, Qt::CaseInsensitive)
&& (action->text().remove("&").contains(filter, Qt::CaseInsensitive)
|| action->property("subMenuName")
.toString().contains(filter, Qt::CaseInsensitive)));
}
@ -1197,6 +1197,10 @@ void MainWindow::open(QString filename)
selected_items << io_plugin->name();
}
}
//if no plugin is correct, offer them all.
for(CGAL::Three::Polyhedron_demo_io_plugin_interface* io_plugin : io_plugins) {
all_items << io_plugin->name();
}
}
else
selected_items << *dfs_it;
@ -1477,11 +1481,11 @@ void MainWindow::showSceneContextMenu(int selectedItemIndex,
this, SLOT(reloadItem()));
}
QAction* saveas = menu->addAction(tr("&Save as..."));
saveas->setData(qVariantFromValue((void*)item));
saveas->setData(QVariant::fromValue((void*)item));
connect(saveas, SIGNAL(triggered()),
this, SLOT(on_actionSaveAs_triggered()));
QAction* showobject = menu->addAction(tr("&Zoom to this Object"));
showobject->setData(qVariantFromValue((void*)item));
showobject->setData(QVariant::fromValue((void*)item));
connect(showobject, SIGNAL(triggered()),
this, SLOT(viewerShowObject()));
@ -1804,7 +1808,12 @@ void MainWindow::readSettings()
viewer->setFastDrawing(settings.value("quick_camera_mode", true).toBool());
scene->enableVisibilityRecentering(settings.value("offset_update", false).toBool());
viewer->textRenderer()->setMax(settings.value("max_text_items", 10000).toInt());
viewer->setTotalPass(settings.value("transparency_pass_number", 4).toInt());
int val = settings.value("transparency_pass_number", 4).toInt();
if (val < 4 ) {
val = 4;
settings.setValue("transparency_pass_number", 4);
}
viewer->setTotalPass(val);
CGAL::Three::Three::s_defaultSMRM = CGAL::Three::Three::modeFromName(
settings.value("default_sm_rm", "flat+edges").toString());
CGAL::Three::Three::s_defaultPSRM = CGAL::Three::Three::modeFromName(
@ -3173,9 +3182,9 @@ void SubViewer::lookat()
if (viewer->camera()->frame()->isSpinning())
viewer->camera()->frame()->stopSpinning();
mw->viewerShow(viewer,
(float)dialog.get_x(),
(float)dialog.get_y(),
(float)dialog.get_z());
(float)dialog.get_x() + viewer->offset().x,
(float)dialog.get_y() + viewer->offset().y,
(float)dialog.get_z() + viewer->offset().z);
}
}

View File

@ -27,7 +27,7 @@
#include <CGAL/bounding_box.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
@ -1241,7 +1241,7 @@ void Polyhedron_demo_cut_plugin::computeIntersection()
Simple_kernel::Plane_3 plane(n[0], n[1], n[2], - n * pos);
//std::cerr << plane << std::endl;
edges_item->edges.clear();
QTime time;
QElapsedTimer time;
time.start();
bool does_intersect = false;
for(Facet_sm_trees::iterator it = facet_sm_trees.begin(); it != facet_sm_trees.end(); ++it)

View File

@ -8,7 +8,7 @@
#include <QMenu>
#include <QMainWindow>
#include <QApplication>
#include <QTime>
#include <QElapsedTimer>
#include <QMessageBox>
using namespace CGAL::Three;
class Polyhedron_demo_nef_plugin :
@ -115,7 +115,7 @@ Polyhedron_demo_nef_plugin::on_actionToNef_triggered()
}
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
QElapsedTimer time;
time.start();
std::cerr << "Convert facegraph to nef polyhedron...";
@ -146,7 +146,7 @@ Polyhedron_demo_nef_plugin::on_actionConvexDecomposition_triggered()
: qobject_cast<Scene_nef_polyhedron_item*>(scene->item(index));
QApplication::restoreOverrideCursor();
if(item) {
QTime time;
QElapsedTimer time;
time.start();
std::cerr << "Convex decomposition...";
@ -188,7 +188,7 @@ Polyhedron_demo_nef_plugin::on_actionToPoly_triggered()
if(item)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
QElapsedTimer time;
time.start();
std::cerr << "Convert nef polyhedron to facegraph...";
@ -277,7 +277,7 @@ void Polyhedron_demo_nef_plugin::boolean_operation(const Boolean_operation opera
// perform Boolean operation
std::cout << "Boolean operation...";
QTime time;
QElapsedTimer time;
time.start();
switch(operation)
{

View File

@ -1,4 +1,4 @@
#include <QTime>
#include <QElapsedTimer>
#include <QApplication>
#include <QAction>
#include <QMainWindow>
@ -74,7 +74,7 @@ void Polyhedron_demo_convex_hull_plugin::on_actionConvexHull_triggered()
// wait cursor
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
QElapsedTimer time;
time.start();
std::cout << "Convex hull...";

View File

@ -80,6 +80,7 @@ endif()
find_path(3MF_INCLUDE_DIR
NAMES Model/COM/NMR_DLLInterfaces.h
PATH_SUFFIXES lib3mf
DOC "Path to lib3MF headers"
)
find_library(3MF_LIBRARIES NAMES 3MF DOC "Path to the lib3MF library")

View File

@ -35,7 +35,7 @@
#include <CGAL/boost/graph/Euler_operations.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
@ -264,14 +264,14 @@ private:
typedef CGAL::Delaunay_mesh_size_criteria_2<CDT> Criteria;
typedef CGAL::Delaunay_mesher_2<CDT, Criteria> Mesher;
QTime time; // global timer
QElapsedTimer time; // global timer
time.start();
std::cout << " Building Constrained_Delaunay_triangulation_2..."
<< std::flush;
CDT cdt;
QTime ltime; //local timer
QElapsedTimer ltime; //local timer
ltime.start();
double constant_coordinate =
polylines_items.back()->polylines.back().back()[constant_coordinate_index];

View File

@ -708,9 +708,9 @@ private:
Volume_plane<y_tag> *y_item = new Volume_plane<y_tag>(img->image()->tx,img->image()->ty, img->image()->tz);
Volume_plane<z_tag> *z_item = new Volume_plane<z_tag>(img->image()->tx,img->image()->ty, img->image()->tz);
x_item->setProperty("img",qVariantFromValue((void*)seg_img));
y_item->setProperty("img",qVariantFromValue((void*)seg_img));
z_item->setProperty("img",qVariantFromValue((void*)seg_img));
x_item->setProperty("img",QVariant::fromValue((void*)seg_img));
y_item->setProperty("img",QVariant::fromValue((void*)seg_img));
z_item->setProperty("img",QVariant::fromValue((void*)seg_img));
x_item->setColor(QColor("red"));
y_item->setColor(QColor("green"));

View File

@ -16,7 +16,7 @@
#include "config.h"
#include <QTime>
#include <QElapsedTimer>
#include <QApplication>
#include "Meshing_thread.h"
@ -52,7 +52,7 @@ void
Meshing_thread::
run()
{
QTime timer;
QElapsedTimer timer;
timer.start();
CGAL::Three::Three::CursorScopeGuard guard(Qt::BusyCursor);
f_->launch();

View File

@ -16,7 +16,7 @@
#include "config_mesh_3.h"
#include <QTime>
#include <QElapsedTimer>
#include <QTimer>
#include "Optimizer_thread.h"
#include "Scene_c3t3_item.h"
@ -47,7 +47,7 @@ void
Optimizer_thread::
run()
{
QTime timer;
QElapsedTimer timer;
timer.start();
//SEGFAULT
rc_ = f_->launch();

View File

@ -91,7 +91,8 @@ public :
//get the references
this->scene = scene_interface;
this->messages = mi;
plane = NULL;
plane = nullptr;
clipper_item = nullptr;
//creates and link the actions
actionClipPolyhedra = new QAction("Clip Polyhedra With Plane", mw);
actionClipPolyhedra->setProperty("subMenuName","Polygon Mesh Processing/Corefinement");

View File

@ -14,7 +14,7 @@
#include <QMenu>
#include <QMainWindow>
#include <QApplication>
#include <QTime>
#include <QElapsedTimer>
#include <QMessageBox>
typedef Scene_surface_mesh_item Scene_facegraph_item;

View File

@ -21,7 +21,7 @@
#include <QDockWidget>
#include <QDialog>
#include <QApplication>
#include <QTime>
#include <QElapsedTimer>
#include <QMessageBox>
#include "ui_Transformation_widget.h"

View File

@ -14,7 +14,7 @@ typedef Scene_surface_mesh_item Scene_facegraph_item;
#include <CGAL/Polygon_mesh_processing/fair.h>
#include <CGAL/Polygon_mesh_processing/refine.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>

View File

@ -18,7 +18,7 @@
#include <CGAL/Timer.h>
#include <CGAL/iterator.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>

View File

@ -23,7 +23,7 @@
#include <boost/unordered_set.hpp>
#include <CGAL/property_map.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
@ -341,7 +341,7 @@ public Q_SLOTS:
// wait cursor
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
QElapsedTimer time;
time.start();
typedef boost::graph_traits<FaceGraph>::edge_descriptor edge_descriptor;
@ -699,7 +699,7 @@ public Q_SLOTS:
detect_and_split_duplicates(selection, edges_to_protect, target_length);
#ifdef CGAL_LINKED_WITH_TBB
QTime time;
QElapsedTimer time;
time.start();
tbb::parallel_for(
@ -715,7 +715,7 @@ public Q_SLOTS:
target_length, nb_iter, protect, smooth_features);
for(Scene_facegraph_item* poly_item : selection)
{
QTime time;
QElapsedTimer time;
time.start();
remesher(poly_item, edges_to_protect[poly_item->polyhedron()]);

View File

@ -14,7 +14,7 @@
#include <QApplication>
#include <QMainWindow>
#include <QInputDialog>
#include <QTime>
#include <QElapsedTimer>
#include <QMessageBox>
#include <Eigen/Sparse>
@ -360,7 +360,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionSegment()
if (num_vertices(item->skeleton_curve)==0 ) { QApplication::restoreOverrideCursor(); return;}
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
QElapsedTimer time;
time.start();
// init the polyhedron simplex indices
@ -453,7 +453,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionConvert_to_me
if ( !is_mesh_valid(pMesh) ) return;
QTime time;
QElapsedTimer time;
time.start();
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -491,7 +491,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionContract()
return;
}
QTime time;
QElapsedTimer time;
time.start();
std::cout << "Contract...\n";
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -516,7 +516,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionCollapse()
return;
}
QTime time;
QElapsedTimer time;
time.start();
std::cout << "Collapse...\n";
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -542,7 +542,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionSplit()
return;
}
QTime time;
QElapsedTimer time;
time.start();
std::cout << "Split...\n";
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -567,7 +567,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionDegeneracy()
return;
}
QTime time;
QElapsedTimer time;
time.start();
std::cout << "Detect degeneracy...\n";
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -618,7 +618,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionRun()
return;
}
QTime time;
QElapsedTimer time;
time.start();
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -741,7 +741,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionSkeletonize()
return;
}
QTime time;
QElapsedTimer time;
time.start();
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -802,7 +802,7 @@ void Polyhedron_demo_mean_curvature_flow_skeleton_plugin::on_actionConverge()
return;
}
QTime time;
QElapsedTimer time;
time.start();
QApplication::setOverrideCursor(Qt::WaitCursor);

View File

@ -16,7 +16,7 @@
#include <CGAL/bounding_box.h>
#include <CGAL/Polygon_mesh_slicer.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
@ -287,7 +287,7 @@ void Polyhedron_demo_polyhedron_slicer_plugin::on_Generate_button_clicked()
if(!new_polyline_item_for_polylines)
{
Scene_polylines_item* new_polylines_item = new Scene_polylines_item();
QTime time; time.start();
QElapsedTimer time; time.start();
// call algorithm and fill polylines in polylines_item
intersection_of_plane_Polyhedra_3_using_AABB_wrapper(*smesh, planes, plane_positions, new_polylines_item->polylines);
// set names etc and print timing
@ -301,7 +301,7 @@ void Polyhedron_demo_polyhedron_slicer_plugin::on_Generate_button_clicked()
scene->addItem(new_polylines_item);
}
else {
QTime time; time.start();
QElapsedTimer time; time.start();
std::list<std::vector<Epic_kernel::Point_3> > polylines;
// call algorithm and fill polylines in polylines_item
intersection_of_plane_Polyhedra_3_using_AABB_wrapper(*smesh, planes, plane_positions, polylines);

View File

@ -16,7 +16,7 @@
#include <boost/graph/graph_traits.hpp>
#include <CGAL/property_map.h>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
@ -94,7 +94,7 @@ public Q_SLOTS:
// wait cursor
QApplication::setOverrideCursor(Qt::WaitCursor);
QTime time;
QElapsedTimer time;
time.start();
std::cout << "Perturbation..." << std::endl;

View File

@ -17,7 +17,7 @@
#include "ui_Smoothing_plugin.h"
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>

View File

@ -15,7 +15,7 @@
#include <QMenu>
#include <QMainWindow>
#include <QApplication>
#include <QTime>
#include <QElapsedTimer>
#include <QMessageBox>
typedef Scene_surface_mesh_item Scene_face_graph_item;
@ -130,7 +130,7 @@ void Polyhedron_demo_intersection_plugin::intersectionSurfaces()
Scene_polylines_item* new_item = new Scene_polylines_item();
// perform Boolean operation
QTime time;
QElapsedTimer time;
time.start();
try{
@ -193,7 +193,7 @@ void Polyhedron_demo_intersection_plugin::intersectionPolylines()
Scene_points_with_normal_item* new_point_item = new Scene_points_with_normal_item();
Scene_polylines_item* new_pol_item = new Scene_polylines_item();
// perform Boolean operation
QTime time;
QElapsedTimer time;
time.start();
std::vector<Polyline_3> polyA, polyB;
Q_FOREACH(const Polyline_3& poly, itemA->polylines)
@ -289,7 +289,7 @@ void Polyhedron_demo_intersection_plugin::intersectionSurfacePolyline()
Scene_points_with_normal_item* new_point_item = new Scene_points_with_normal_item();
Scene_polylines_item* new_pol_item = new Scene_polylines_item();
// perform Boolean operation
QTime time;
QElapsedTimer time;
time.start();
Scene_face_graph_item::Face_graph tm = *itemA->face_graph();
std::vector<face_descriptor> Afaces;

View File

@ -1,4 +1,4 @@
#include <QTime>
#include <QElapsedTimer>
#include <QApplication>
#include <QAction>
#include <QList>

View File

@ -1,4 +1,4 @@
#include <QTime>
#include <QElapsedTimer>
#include <QApplication>
#include <QMainWindow>
#include <QAction>
@ -81,7 +81,7 @@ template<class FaceGraphItem>
void Polyhedron_demo_subdivision_methods_plugin::apply_loop(FaceGraphItem* item, int nb_steps)
{
typename FaceGraphItem::Face_graph* graph = item->face_graph();
QTime time;
QElapsedTimer time;
time.start();
CGAL::Three::Three::information("Loop subdivision...");
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -113,7 +113,7 @@ void Polyhedron_demo_subdivision_methods_plugin::apply_catmullclark(FaceGraphIte
{
typename FaceGraphItem::Face_graph* graph = item->face_graph();
if(!graph) return;
QTime time;
QElapsedTimer time;
time.start();
CGAL::Three::Three::information("Catmull-Clark subdivision...");
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -143,7 +143,7 @@ void Polyhedron_demo_subdivision_methods_plugin::apply_sqrt3(FaceGraphItem* item
{
typename FaceGraphItem::Face_graph* graph = item->face_graph();
if(!graph) return;
QTime time;
QElapsedTimer time;
time.start();
CGAL::Three::Three::information("Sqrt-3 subdivision...");
QApplication::setOverrideCursor(Qt::WaitCursor);
@ -175,7 +175,7 @@ void Polyhedron_demo_subdivision_methods_plugin::apply_doosabin(FaceGraphItem* i
{
typename FaceGraphItem::Face_graph* graph = item->face_graph();
if(!graph) return;
QTime time;
QElapsedTimer time;
time.start();
CGAL::Three::Three::information("Doo-Sabin subdivision...");
QApplication::setOverrideCursor(Qt::WaitCursor);

View File

@ -9,7 +9,7 @@
#include <QApplication>
#include <QMainWindow>
#include <QInputDialog>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QDebug>
#include <QObject>
@ -196,7 +196,7 @@ void Polyhedron_demo_mesh_plane_detection_plugin::on_actionPlaneDetection_trigge
if(dialog.exec() == QDialog::Rejected)
return;
QTime time;
QElapsedTimer time;
time.start();
std::cerr << "Detecting planes... ";
QApplication::setOverrideCursor(Qt::WaitCursor);

View File

@ -10,7 +10,7 @@
#include <QApplication>
#include <QMainWindow>
#include <QInputDialog>
#include <QTime>
#include <QElapsedTimer>
#include <QAction>
#include <QDebug>
#include <QObject>
@ -211,7 +211,7 @@ void Polyhedron_demo_mesh_segmentation_plugin::apply_SDF_button_clicked(Facegrap
typename boost::property_map<Facegraph, CGAL::face_index_t>::type fidmap =
get(CGAL::face_index, *pair->first->face_graph());
FaceGraph_with_id_to_vector_property_map<Facegraph, double> sdf_pmap(&pair->second, fidmap);
QTime time;
QElapsedTimer time;
time.start();
std::pair<double, double> min_max_sdf = sdf_values(*(pair->first->face_graph()), sdf_pmap, cone_angle, number_of_rays);
std::cout << "ok (" << time.elapsed() << " ms)" << std::endl;
@ -284,7 +284,7 @@ void Polyhedron_demo_mesh_segmentation_plugin::apply_Partition_button_clicked(Fa
QApplication::setOverrideCursor(Qt::WaitCursor);
}
check_and_set_ids(pair->first->face_graph());
QTime time;
QElapsedTimer time;
time.start();
typename boost::property_map<Facegraph, CGAL::face_index_t>::type fidmap =
get(CGAL::face_index, *pair->first->face_graph());

Some files were not shown because too many files have changed in this diff Show More