Allow lambdas (or other callables) as MeshDomainField_3

That patch uses C++11 `<type_traits>`, and
`boost::callable_traits::is_invocable` that is available only since
1.66. If Boost<1.66, then the previous behavior (testing
`Sizing_field::FT`) is kept.

Fix issue https://github.com/CGAL/cgal/issues/3005
This commit is contained in:
Laurent Rineau 2019-05-22 15:24:55 +02:00
parent 268cb59ce1
commit 22d6d9ebd8
5 changed files with 132 additions and 103 deletions

View File

@ -0,0 +1,66 @@
// Copyright (c) 2019 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Laurent Rineau
//
//******************************************************************************
// File Description :
// Mesh_facet_criteria_3 class.
//******************************************************************************
#ifndef CGAL_MESH_3_IS_MESH_DOMAIN_FIELD_3_H
#define CGAL_MESH_3_IS_MESH_DOMAIN_FIELD_3_H
#include <CGAL/license/Mesh_3.h>
#include <boost/config.hpp>
#if BOOST_VERSION >= 106600
# include <boost/callable_traits/is_invocable.hpp>
#else
# include <boost/mpl/has_xxx.hpp>
#endif
#include <CGAL/tags.h>
namespace CGAL {
namespace Mesh_3 {
#if BOOST_VERSION >= 106600
template <typename Tr, typename Type>
struct Is_mesh_domain_field_3 :
public CGAL::Boolean_tag
<
boost::callable_traits::is_invocable_r<
typename Tr::FT,
Type,
typename Tr::Bare_point,
int,
typename Tr::Vertex::Index
>::value
>
{};
#else // Boost before 1.66
BOOST_MPL_HAS_XXX_TRAIT_DEF(FT)
template <typename Tr, typename Type>
struct Is_mesh_domain_field_3 : public Boolean_tag<has_FT<Type>::value>
{};
#endif // Boost before 1.66
} // end namespace Mesh_3
} // end namespace CGAL
#endif // CGAL_MESH_3_IS_MESH_DOMAIN_FIELD_3_H

View File

@ -27,6 +27,14 @@
#include <CGAL/Mesh_3/mesh_standard_cell_criteria.h>
#include <CGAL/Mesh_3/Is_mesh_domain_field_3.h>
#include <boost/config.hpp>
#if BOOST_VERSION >= 106600
# include <boost/callable_traits/is_invocable.hpp>
#endif
#include <type_traits>
namespace CGAL {
@ -65,13 +73,16 @@ public:
init_radius_edge(radius_edge_bound);
}
// Nb: SFINAE (dummy) to avoid wrong matches with built-in numerical types
// Nb: SFINAE to avoid wrong matches with built-in numerical types
// as int.
template <typename Sizing_field>
Mesh_cell_criteria_3(const FT& radius_edge_bound,
const Sizing_field& radius_bound,
typename Sizing_field::FT /*dummy*/ = 0)
{
typename std::enable_if<
Mesh_3::Is_mesh_domain_field_3<Tr,Sizing_field>::value
>::type* = 0
)
{
init_radius(radius_bound);
if ( FT(0) != radius_edge_bound )

View File

@ -30,7 +30,8 @@
#include <CGAL/Mesh_constant_domain_field_3.h>
#include <boost/type_traits.hpp>
#include <CGAL/Mesh_3/Is_mesh_domain_field_3.h>
#include <type_traits>
namespace CGAL {
namespace Mesh_3 {
@ -55,24 +56,22 @@ namespace internal {
virtual Sizing_field_interface* clone() const = 0;
};
template < typename Sizing_field >
template < typename Sizing_field,
typename FT,
typename Point_3,
typename Index>
struct Sizing_field_container
: public Sizing_field_interface < typename Sizing_field::FT,
typename Sizing_field::Point_3,
typename Sizing_field::Index >
: public Sizing_field_interface < FT,
Point_3,
Index >
{
typedef Sizing_field_interface <
typename Sizing_field::FT,
typename Sizing_field::Point_3,
typename Sizing_field::Index > Base;
typedef Sizing_field_container<Sizing_field> Self;
typedef Sizing_field_interface < FT,
Point_3,
Index > Base;
typedef Sizing_field_container<Sizing_field, FT, Point_3, Index> Self;
public:
typedef typename Base::FT FT;
typedef typename Base::Point_3 Point_3;
typedef typename Base::Index Index;
Sizing_field_container(const Sizing_field& s) : s_(s) {}
virtual ~Sizing_field_container() {}
@ -109,23 +108,25 @@ public:
/// Constructors
Mesh_edge_criteria_3(const FT& value)
: p_size_(new Mesh_3::internal::Sizing_field_container<
Mesh_constant_domain_field_3<Gt,Index> >(value))
Mesh_constant_domain_field_3<Gt,Index> ,
FT,
Point_3,
Index>(value))
{}
// Nb: SFINAE (dummy) to avoid wrong matches with built-in numerical types
// Nb: SFINAE to avoid wrong matches with built-in numerical types
// as int.
template < typename Sizing_field >
Mesh_edge_criteria_3(const Sizing_field& size,
typename Sizing_field::FT /*dummy*/ = 0 )
Mesh_edge_criteria_3
(
const Sizing_field& size,
typename std::enable_if<Mesh_3::Is_mesh_domain_field_3<Tr, Sizing_field>::value>::type* = 0
)
{
CGAL_static_assertion((boost::is_same<typename Sizing_field::FT,
FT>::value));
CGAL_static_assertion((boost::is_same<typename Sizing_field::Point_3,
Point_3>::value));
CGAL_static_assertion((boost::is_same<typename Sizing_field::Index,
Index>::value));
p_size_ = new Mesh_3::internal::Sizing_field_container<Sizing_field>(size);
p_size_ = new Mesh_3::internal::Sizing_field_container<Sizing_field,
FT,
Point_3,
Index>(size);
}
Mesh_edge_criteria_3(const Self& rhs)

View File

@ -32,6 +32,7 @@
#include <CGAL/Mesh_3/mesh_standard_facet_criteria.h>
#include <CGAL/Mesh_facet_topology.h>
#include <CGAL/Mesh_3/Is_mesh_domain_field_3.h>
namespace CGAL {
@ -59,83 +60,21 @@ public:
/**
* @brief Constructor
*/
Mesh_facet_criteria_3(const FT& angle_bound,
const FT& radius_bound,
const FT& distance_bound,
const Mesh_facet_topology topology =
FACET_VERTICES_ON_SURFACE)
{
if ( FT(0) != angle_bound )
init_aspect(angle_bound);
if ( FT(0) != radius_bound )
init_radius_bound(radius_bound);
if ( FT(0) != distance_bound )
init_distance_bound(distance_bound);
init_topo(topology);
}
// Nb: SFINAE (dummy) to avoid wrong matches with built-in numerical types
// as int.
template < typename Sizing_field >
Mesh_facet_criteria_3(const FT& angle_bound,
const Sizing_field& radius_bound,
const FT& distance_bound,
const Mesh_facet_topology topology =
FACET_VERTICES_ON_SURFACE,
typename Sizing_field::FT /*dummy*/ = 0)
{
if ( FT(0) != angle_bound )
init_aspect(angle_bound);
init_radius_field(radius_bound);
if ( FT(0) != distance_bound )
init_distance_bound(distance_bound);
init_topo(topology);
}
// Nb: SFINAE (dummy) to avoid wrong matches with built-in numerical types
// as int.
template < typename Sizing_field >
Mesh_facet_criteria_3(const FT& angle_bound,
const FT& radius_bound,
const Sizing_field& distance_bound,
const Mesh_facet_topology topology =
FACET_VERTICES_ON_SURFACE,
typename Sizing_field::FT /*dummy*/ = 0)
{
if ( FT(0) != angle_bound )
init_aspect(angle_bound);
if ( FT(0) != radius_bound )
init_radius_bound(radius_bound);
init_distance_field(distance_bound);
init_topo(topology);
}
// Nb: SFINAE (dummy) to avoid wrong matches with built-in numerical types
// as int.
template < typename Sizing_field, typename Sizing_field2 >
Mesh_facet_criteria_3(const FT& angle_bound,
const Sizing_field & radius_bound,
const Sizing_field2& distance_bound,
const Mesh_facet_topology topology =
FACET_VERTICES_ON_SURFACE,
typename Sizing_field::FT /*dummy*/ = 0,
typename Sizing_field2::FT /*dummy*/ = 0)
FACET_VERTICES_ON_SURFACE)
{
if ( FT(0) != angle_bound )
init_aspect(angle_bound);
init_radius_field(radius_bound);
init_radius(radius_bound,
Mesh_3::Is_mesh_domain_field_3<Tr, Sizing_field>());
init_distance_field(distance_bound);
init_distance(distance_bound,
Mesh_3::Is_mesh_domain_field_3<Tr, Sizing_field2>());
init_topo(topology);
}
@ -169,27 +108,29 @@ private:
criteria_.add(new Aspect_criterion(angle_bound));
}
void init_radius_bound(const FT& radius_bound)
void init_radius(const FT& radius_bound, Tag_false)
{
if(FT(0) == radius_bound) return;
typedef Mesh_3::Uniform_size_criterion<Tr,Visitor> Uniform_size_criterion;
criteria_.add(new Uniform_size_criterion(radius_bound));
}
template <typename Sizing_field>
void init_radius_field(const Sizing_field& radius_bound)
void init_radius(const Sizing_field& radius_bound, Tag_true)
{
typedef Mesh_3::Variable_size_criterion<Tr,Visitor,Sizing_field> Variable_size_criterion;
criteria_.add(new Variable_size_criterion(radius_bound));
}
void init_distance_bound(const FT& distance_bound)
void init_distance(const FT& distance_bound, Tag_false)
{
if(FT(0) == distance_bound) return;
typedef Mesh_3::Uniform_curvature_size_criterion<Tr,Visitor> Criterion;
criteria_.add(new Criterion(distance_bound));
}
template <typename Sizing_field>
void init_distance_field(const Sizing_field& distance_bound)
void init_distance(const Sizing_field& distance_bound, Tag_true)
{
typedef Mesh_3::Variable_curvature_size_criterion<Tr,
Visitor,

View File

@ -7,6 +7,8 @@
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/make_mesh_3.h>
#include <boost/version.hpp>
// Domain
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::FT FT;
@ -42,7 +44,14 @@ FT capsule_function(const Point& p)
else if(z < FT(-5)) return base+CGAL::square(z+5);
else return base;
}
#if BOOST_VERSION >= 106600
auto field = [](const Point& p, const int, const Mesh_domain::Index)
{
if(p.z() > 2) return 0.025;
if(p.z() < -3) return 0.01;
else return 1.;
};
#else
struct Field {
typedef ::FT FT;
@ -52,6 +61,7 @@ struct Field {
else return 1;
}
} field;
#endif
int main()
{