Automatically determine the correct typedefs for an ambient dimension using template specializations & SFINAE

This commit is contained in:
JacksonCampolattaro 2023-09-07 17:19:04 +02:00
parent 750ca578a8
commit ea59877c19
7 changed files with 225 additions and 45 deletions

View File

@ -12,7 +12,7 @@ typedef CGAL::Epick_d<Dimension> Kernel;
typedef Kernel::Point_d Point_d; typedef Kernel::Point_d Point_d;
typedef std::vector<Point_d> Point_vector; typedef std::vector<Point_d> Point_vector;
typedef CGAL::Orthtree_traits_point_d<Kernel, Dimension, Point_vector> Traits; typedef CGAL::Orthtree_traits_point<Kernel, Point_vector> Traits;
typedef CGAL::Orthtree<Traits> Orthtree; typedef CGAL::Orthtree<Traits> Orthtree;
int main() int main()

View File

@ -4,7 +4,7 @@
#include <CGAL/Dimension.h> #include <CGAL/Dimension.h>
#include <CGAL/Orthtree.h> #include <CGAL/Orthtree.h>
#include <CGAL/Orthtree_traits_2_base.h> #include <CGAL/Orthtree_traits_base_for_dimension.h>
using Kernel = CGAL::Simple_cartesian<double>; using Kernel = CGAL::Simple_cartesian<double>;
@ -13,15 +13,15 @@ namespace CGAL {
struct empty_type { struct empty_type {
}; };
template <typename K> template <typename K, typename DimensionTag>
struct Orthtree_traits_empty_2 : public Orthtree_traits_2_base<K> { struct Orthtree_traits_empty : public Orthtree_traits_base_for_dimension<K, DimensionTag> {
using Self = Orthtree_traits_empty_2<K>; using Self = Orthtree_traits_empty<K, DimensionTag>;
using Tree = Orthtree<Self>; using Tree = Orthtree<Self>;
using Node_data = std::array<empty_type, 0>; using Node_data = std::array<empty_type, 0>;
Orthtree_traits_empty_2(typename Self::Bbox_d bbox) : m_bbox(bbox) {}; Orthtree_traits_empty(typename Self::Bbox_d bbox) : m_bbox(bbox) {};
auto root_node_bbox_object() const { auto root_node_bbox_object() const {
return [&]() -> typename Self::Bbox_d { return m_bbox; }; return [&]() -> typename Self::Bbox_d { return m_bbox; };
@ -40,7 +40,7 @@ private:
}; };
} }
using EmptyQuadtree = CGAL::Orthtree<CGAL::Orthtree_traits_empty_2<Kernel>>; using EmptyQuadtree = CGAL::Orthtree<CGAL::Orthtree_traits_empty<Kernel, CGAL::Dimension_tag<2>>>;
int main() { int main() {

View File

@ -43,7 +43,7 @@ template <
#ifdef DOXYGEN_RUNNING #ifdef DOXYGEN_RUNNING
class Octree; class Octree;
#else #else
using Octree = Orthtree<Orthtree_traits_point_3<GeomTraits, PointRange, PointMap>>; using Octree = Orthtree<Orthtree_traits_point<GeomTraits, PointRange, PointMap, Dimension_tag<3>>>;
#endif #endif
} // namespace CGAL } // namespace CGAL

View File

@ -0,0 +1,196 @@
// Copyright (c) 2023 INRIA (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Jackson Campolattaro
#ifndef ORTHTREE_EXAMPLES_ORTHTREE_TRAITS_BASE_FOR_DIMENSION_H
#define ORTHTREE_EXAMPLES_ORTHTREE_TRAITS_BASE_FOR_DIMENSION_H
#include <CGAL/license/Orthtree.h>
#include <CGAL/Dimension.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/Point_set_2.h>
#include <CGAL/Orthtree/Cartesian_ranges.h>
namespace CGAL {
template <typename K, typename DimensionTag>
struct Orthtree_traits_base_for_dimension;
template <typename K, typename DimensionTag>
struct Orthtree_traits_base_for_dimension {
/// \name Types
/// @{
using Dimension = DimensionTag;
using FT = typename K::FT;
using Point_d = typename K::Point_d;
using Bbox_d = typename K::Iso_box_d;
using Sphere_d = typename K::Sphere_d;
using Cartesian_const_iterator_d = typename K::Cartesian_const_iterator_d;
/*!
Adjacency type.
\note This type is used to identify adjacency directions with
easily understandable keywords (left, right, up, etc.) and is thus
mainly useful for `Orthtree_traits_2` and `Orthtree_traits_3`. In
higher dimensions, such keywords do not exist and this type is
simply an integer. Conversions from this integer to bitsets still
work but do not provide any easier API for adjacency selection.
*/
using Adjacency = int;
/// @}
/// \name Operations
/// @{
auto construct_point_d_object() const {
return [](auto... Args) -> Point_d {
std::initializer_list<FT> args_list{Args...};
return Point_d{args_list.size(), args_list.begin(), args_list.end()};
};
}
/// @}
};
template <typename K>
struct Orthtree_traits_base_for_dimension<K, Dimension_tag<2>> {
/// \name Types
/// @{
using Dimension = Dimension_tag<2>;
using FT = typename K::FT;
using Point_d = typename K::Point_2;
using Bbox_d = typename K::Iso_rectangle_2;
using Sphere_d = typename K::Circle_2;
using Cartesian_const_iterator_d = typename K::Cartesian_const_iterator_2;
/*!
* \brief Two directions along each axis in Cartesian space, relative to a node.
*
* Directions are mapped to numbers as 2-bit integers.
*
* The first bit indicates the axis (0 = x, 1 = y),
* the second bit indicates the direction along that axis (0 = -, 1 = +).
*
* The following diagram may be a useful reference:
*
* 3 *
* |
* | y+
* | *
* 0 *------+------* 1 |
* | |
* | +-----* x+
* |
* * 2
*
* This lookup table may also be helpful:
*
* | Direction | bitset | number | Enum |
* | --------- | ------ | ------ | ----- |
* | `-x` | 00 | 0 | LEFT |
* | `+x` | 01 | 1 | RIGHT |
* | `-y` | 10 | 2 | DOWN |
* | `+y` | 11 | 3 | UP |
*/
enum Adjacency {
LEFT,
RIGHT,
DOWN,
UP
};
/// @}
/// \name Operations
/// @{
auto construct_point_d_object() const {
return [](const FT& x, const FT& y) -> Point_d {
return {x, y};
};
}
/// @}
};
template <typename K>
struct Orthtree_traits_base_for_dimension<K, Dimension_tag<3>> {
/// \name Types
/// @{
using GeomTraits = K;
using Dimension = Dimension_tag<3>;
using FT = typename K::FT;
using Point_d = typename K::Point_3;
using Bbox_d = typename K::Iso_cuboid_3;
using Sphere_d = typename K::Sphere_3;
using Cartesian_const_iterator_d = typename K::Cartesian_const_iterator_3;
/*!
* \brief Two directions along each axis in Cartesian space, relative to a node.
*
* Directions are mapped to numbers as 3-bit integers,
* though the numbers 6 and 7 are not used because there are only 6 different directions.
*
* The first two bits indicate the axis (00 = x, 01 = y, 10 = z),
* the third bit indicates the direction along that axis (0 = -, 1 = +).
*
* The following diagram may be a useful reference:
*
* 3 *
* | * 5
* | / y+
* |/ * z+
* 0 *------+------* 1 | *
* /| |/
* / | +-----* x+
* 4 * |
* * 2
*
* This lookup table may also be helpful:
*
* | Direction | bitset | number | Enum |
* | --------- | ------ | ------ | ----- |
* | `-x` | 000 | 0 | LEFT |
* | `+x` | 001 | 1 | RIGHT |
* | `-y` | 010 | 2 | DOWN |
* | `+y` | 011 | 3 | UP |
* | `-z` | 100 | 4 | BACK |
* | `+z` | 101 | 5 | FRONT |
*/
enum Adjacency {
LEFT,
RIGHT,
DOWN,
UP,
BACK,
FRONT
};
/// \cond SKIP_IN_MANUAL
enum Child {
LEFT_BOTTOM_BACK,
RIGHT_BOTTOM_BACK,
LEFT_TOP_BACK,
RIGHT_TOP_BACK,
LEFT_BOTTOM_FRONT,
RIGHT_BOTTOM_FRONT,
LEFT_TOP_FRONT,
RIGHT_TOP_FRONT
};
/// \endcond
/// @}
/// \name Operations
/// @{
auto construct_point_d_object() const {
return [](const FT& x, const FT& y, const FT& z) -> Point_d {
return {x, y, z};
};
}
/// @}
};
}
#endif //ORTHTREE_EXAMPLES_ORTHTREE_TRAITS_BASE_FOR_DIMENSION_H

View File

@ -15,7 +15,7 @@
#include <CGAL/license/Orthtree.h> #include <CGAL/license/Orthtree.h>
#include <CGAL/Orthtree_traits_3_base.h> #include <CGAL/Orthtree_traits_base_for_dimension.h>
#include <CGAL/Dimension.h> #include <CGAL/Dimension.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
@ -23,8 +23,15 @@
namespace CGAL { namespace CGAL {
template <class PolygonMesh, class VPM> template <class PolygonMesh, class VPM>
struct Orthtree_traits_face_graph struct Orthtree_traits_face_graph : public Orthtree_traits_base_for_dimension<
: public Orthtree_traits_3_base<typename Kernel_traits<typename boost::property_traits<VPM>::value_type>::type> { typename Kernel_traits<typename boost::property_traits<VPM>::value_type>::type,
Dimension_tag<3>
// todo: it should be possible to determine the ambient dimension automatically, but this isn't working
// Ambient_dimension<
// typename boost::property_traits<VPM>::value_type,
// typename Kernel_traits<typename boost::property_traits<VPM>::value_type>::type
// >
> {
Orthtree_traits_face_graph(const PolygonMesh& pm, VPM vpm) Orthtree_traits_face_graph(const PolygonMesh& pm, VPM vpm)
: m_pm(pm), m_vpm(vpm) {} : m_pm(pm), m_vpm(vpm) {}
@ -110,8 +117,9 @@ struct Orthtree_traits_face_graph
if (tree.data(ni).empty()) return false; if (tree.data(ni).empty()) return false;
Bbox_d bb = tree.bbox(ni); Bbox_d bb = tree.bbox(ni);
//TODO: we should get better version to get guarantees // TODO: we should get better version to get guarantees
// TODO: as long as the bbox is cubic you can use depth and initial size to conclude. // TODO: as long as the bbox is cubic you can use depth and initial size to conclude.
// todo (jackson): bbox is _not_ guaranteed to be cubic now, this may break in some very niche cases
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
if ((bb.max()[i] - bb.min()[i]) < 2 * m_min_extent) if ((bb.max()[i] - bb.min()[i]) < 2 * m_min_extent)
return false; return false;

View File

@ -19,9 +19,7 @@
#include <CGAL/Point_set_2.h> #include <CGAL/Point_set_2.h>
#include <CGAL/Orthtree/Cartesian_ranges.h> #include <CGAL/Orthtree/Cartesian_ranges.h>
#include <CGAL/Orthtree_traits_2_base.h> #include <CGAL/Orthtree_traits_base_for_dimension.h>
#include <CGAL/Orthtree_traits_3_base.h>
#include <CGAL/Orthtree_traits_d_base.h>
namespace CGAL { namespace CGAL {
@ -78,16 +76,19 @@ void reassign_points(
template < template <
typename GeomTraits, typename GeomTraits,
typename PointSet, typename PointSet,
typename PointMap, typename PointMap = Identity_property_map<typename std::iterator_traits<typename PointSet::iterator>::value_type>,
typename OrthtreeTraitsDimensionBase typename DimensionTag = Ambient_dimension<
typename std::iterator_traits<typename PointSet::iterator>::value_type,
GeomTraits
>
> >
struct Orthtree_traits_point : public OrthtreeTraitsDimensionBase { struct Orthtree_traits_point : public Orthtree_traits_base_for_dimension<GeomTraits, DimensionTag> {
public: public:
/// \name Types /// \name Types
/// @{ /// @{
using Self = Orthtree_traits_point<GeomTraits, PointSet, PointMap, OrthtreeTraitsDimensionBase>; using Self = Orthtree_traits_point<GeomTraits, PointSet, PointMap, DimensionTag>;
using Tree = Orthtree<Self>; using Tree = Orthtree<Self>;
using Node_data = boost::iterator_range<typename PointSet::iterator>; using Node_data = boost::iterator_range<typename PointSet::iterator>;
@ -163,31 +164,6 @@ private:
}; };
template <
typename GeomTraits,
typename PointSet,
typename PointMap = Identity_property_map<typename GeomTraits::Point_2>
>
using Orthtree_traits_point_2 =
Orthtree_traits_point<GeomTraits, PointSet, PointMap, Orthtree_traits_2_base<GeomTraits>>;
template <
typename GeomTraits,
typename PointSet,
typename PointMap = Identity_property_map<typename GeomTraits::Point_3>
>
using Orthtree_traits_point_3 =
Orthtree_traits_point<GeomTraits, PointSet, PointMap, Orthtree_traits_3_base<GeomTraits>>;
template <
typename GeomTraits,
typename DimensionTag,
typename PointSet,
typename PointMap = Identity_property_map<typename GeomTraits::Point_d>
>
using Orthtree_traits_point_d =
Orthtree_traits_point<GeomTraits, PointSet, PointMap, Orthtree_traits_d_base<GeomTraits, DimensionTag>>;
} }

View File

@ -41,7 +41,7 @@ template <typename GeomTraits, typename PointRange,
#ifdef DOXYGEN_RUNNING #ifdef DOXYGEN_RUNNING
class Quadtree; class Quadtree;
#else #else
using Quadtree = Orthtree<Orthtree_traits_point_2<GeomTraits, PointRange, PointMap>>; using Quadtree = Orthtree<Orthtree_traits_point<GeomTraits, PointRange, PointMap, Dimension_tag<2>>>;
#endif #endif
} // namespace CGAL } // namespace CGAL