Merge pull request #8052 from afabri/Polygon-exact_area-GF

Polygon: Avoid stackoverflow when summing exact numbers
This commit is contained in:
Laurent Rineau 2024-03-22 08:59:08 +01:00
commit 8cab90ed8b
6 changed files with 48 additions and 10 deletions

View File

@ -108,11 +108,26 @@ template<class T>inline std::enable_if_t<std::is_arithmetic<T>::value||std::is_e
template<class T>inline std::enable_if_t<std::is_arithmetic<T>::value||std::is_enum<T>::value, T> exact (T d){return d;}
template<class T>inline std::enable_if_t<std::is_arithmetic<T>::value||std::is_enum<T>::value, int> depth(T){return -1;}
template<class T>inline std::enable_if_t<std::is_arithmetic<T>::value, Quotient<T>> approx(Quotient<T> d){return d;}
template<class T>inline std::enable_if_t<std::is_arithmetic<T>::value, Quotient<T>> exact (Quotient<T> d){return d;}
template<class T>inline std::enable_if_t<std::is_arithmetic<T>::value, int> depth(Quotient<T>){return -1;}
// For tag classes: Return_base_tag, Homogeneous_tag, Null_vector, Origin
template<class T>inline std::enable_if_t<std::is_empty<T>::value, T> exact(T){return {};}
template<class T>inline std::enable_if_t<std::is_empty<T>::value, T> approx(T){return {};}
template<class T>inline std::enable_if_t<std::is_empty<T>::value, int> depth(T){return -1;}
namespace internal{
template <typename AT, typename ET, typename E2A>
struct Evaluate<Lazy<AT,ET,E2A>>
{
void operator()(const Lazy<AT,ET,E2A>& l)
{
exact(l);
}
};
} // internal namespace
// For an iterator, exact/approx applies to the objects it points to
template <class T, class=std::enable_if_t<is_iterator_type<T,std::input_iterator_tag>::value>>
auto exact(T const& t) {return make_transforming_iterator(t,[](auto const&u)->decltype(auto){return CGAL::exact(u);});}

View File

@ -25,6 +25,8 @@
#include <CGAL/squared_distance_3.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/number_utils.h>
#include <CGAL/Default.h>
#ifdef CGAL_EIGEN3_ENABLED
#include <CGAL/Eigen_solver_traits.h>
#endif

View File

@ -4,7 +4,6 @@ Cartesian_kernel
Circulator
Distance_2
Distance_3
Filtered_kernel
Heat_method_3
Installation
Interval_support

View File

@ -266,6 +266,17 @@ class Is_valid
};
};
namespace internal
{
// utility class to be used for calling exact(Lazy) when doing accumulation with EPECK
template <class NT>
struct Evaluate
{
void operator()(const NT&)
{}
};
} // internal namespace
} //namespace CGAL
#endif // CGAL_UTILS_CLASSES_H

View File

@ -25,6 +25,7 @@
#include <CGAL/enum.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Polygon_2/polygon_assertions.h>
#include <CGAL/utils_classes.h>
///
namespace CGAL {
@ -142,6 +143,7 @@ area_2( ForwardIterator first, ForwardIterator last,
const PolygonTraits& traits)
{
typedef typename PolygonTraits::FT FT;
internal::Evaluate<FT> evaluate;
result = FT(0);
// check if the polygon is empty
if (first == last) return;
@ -153,6 +155,7 @@ area_2( ForwardIterator first, ForwardIterator last,
ForwardIterator third = second;
while (++third != last) {
result = result + compute_area_2(*first, *second, *third);
evaluate(result);
second = third;
}
}
@ -179,6 +182,7 @@ polygon_area_2( ForwardIterator first, ForwardIterator last,
const PolygonTraits& traits)
{
typedef typename PolygonTraits::FT FT;
internal::Evaluate<FT> evaluate;
FT result = FT(0);
// check if the polygon is empty
if (first == last) return result;
@ -190,6 +194,7 @@ polygon_area_2( ForwardIterator first, ForwardIterator last,
ForwardIterator third = second;
while (++third != last) {
result = result + compute_area_2(*first, *second, *third);
evaluate(result);
second = third;
}
return result;

View File

@ -23,9 +23,7 @@
#include <CGAL/boost/graph/properties.h>
#include <CGAL/Named_function_parameters.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Lazy.h> // needed for CGAL::exact(FT)/CGAL::exact(Lazy_exact_nt<T>)
#include <CGAL/utils_classes.h>
#include <boost/container/small_vector.hpp>
#include <boost/graph/graph_traits.hpp>
@ -261,12 +259,14 @@ face_border_length(typename boost::graph_traits<PolygonMesh>::halfedge_descripto
const PolygonMesh& pmesh,
const NamedParameters& np = parameters::default_values())
{
typename GetGeomTraits<PolygonMesh, NamedParameters>::type::FT result = 0;
using FT = typename GetGeomTraits<PolygonMesh, NamedParameters>::type::FT;
::CGAL::internal::Evaluate<FT> evaluate;
FT result = 0;
for(typename boost::graph_traits<PolygonMesh>::halfedge_descriptor haf : halfedges_around_face(h, pmesh))
{
result += edge_length(haf, pmesh, np);
exact(result);
evaluate(result);
}
return result;
@ -559,11 +559,14 @@ area(FaceRange face_range,
{
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
typename GetGeomTraits<TriangleMesh, CGAL_NP_CLASS>::type::FT result = 0;
using FT = typename GetGeomTraits<TriangleMesh, CGAL_NP_CLASS>::type::FT;
FT result = 0;
::CGAL::internal::Evaluate<FT> evaluate;
for(face_descriptor f : face_range)
{
result += face_area(f, tmesh, np);
exact(result);
evaluate(result);
}
return result;
@ -676,7 +679,10 @@ volume(const TriangleMesh& tmesh,
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
typename GetGeomTraits<TriangleMesh, CGAL_NP_CLASS>::type::FT volume = 0;
using FT = typename GetGeomTraits<TriangleMesh, CGAL_NP_CLASS>::type::FT;
::CGAL::internal::Evaluate<FT> evaluate;
FT volume = 0;
typename CGAL::Kernel_traits<typename property_map_value<TriangleMesh,
CGAL::vertex_point_t>::type>::Kernel::Compute_volume_3 cv3;
@ -686,7 +692,7 @@ volume(const TriangleMesh& tmesh,
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)));
exact(volume);
evaluate(volume);
}
return volume;