mirror of https://github.com/CGAL/cgal
Update branch from master after trailing whitespaces and tabs removal
This commit is contained in:
commit
c67d093ebf
|
|
@ -5,27 +5,20 @@ cmake_minimum_required(VERSION 3.1...3.15)
|
||||||
project( AABB_traits_benchmark)
|
project( AABB_traits_benchmark)
|
||||||
|
|
||||||
# CGAL and its components
|
# CGAL and its components
|
||||||
find_package( CGAL QUIET)
|
find_package( CGAL REQUIRED )
|
||||||
if ( CGAL_FOUND )
|
|
||||||
include( ${CGAL_USE_FILE} )
|
include( ${CGAL_USE_FILE} )
|
||||||
else ()
|
|
||||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
|
||||||
return()
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# Boost and its components
|
# Boost and its components
|
||||||
find_package( Boost REQUIRED )
|
find_package( Boost REQUIRED )
|
||||||
# include for local directory
|
# include for local directory
|
||||||
if ( NOT Boost_FOUND )
|
|
||||||
message(STATUS "This project requires the Boost library, and will not be compiled.")
|
# google benchmark
|
||||||
return()
|
find_package(benchmark REQUIRED)
|
||||||
endif()
|
|
||||||
|
|
||||||
# include for local package
|
# include for local package
|
||||||
include_directories( BEFORE ../../include )
|
include_directories( BEFORE ../../include )
|
||||||
|
|
||||||
add_executable (test_ test.cpp)
|
# add_executable (test_ test.cpp) // TODO: fix this benchmark
|
||||||
|
add_executable(tree_creation tree_creation.cpp)
|
||||||
|
target_link_libraries(tree_creation benchmark::benchmark)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
#include <CGAL/AABB_tree.h>
|
||||||
|
#include <CGAL/AABB_traits.h>
|
||||||
|
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
typedef CGAL::Simple_cartesian<double> K;
|
||||||
|
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||||
|
typedef CGAL::AABB_face_graph_triangle_primitive<Surface_mesh> Primitive;
|
||||||
|
typedef CGAL::AABB_traits<K, Primitive> Traits;
|
||||||
|
typedef CGAL::AABB_tree<Traits> Tree;
|
||||||
|
typedef K::Segment_3 Segment;
|
||||||
|
typedef K::Point_3 Point_3;
|
||||||
|
|
||||||
|
|
||||||
|
Surface_mesh mesh;
|
||||||
|
|
||||||
|
static void BM_TreeCreation(benchmark::State& state)
|
||||||
|
{
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
benchmark::DoNotOptimize([]() {
|
||||||
|
Tree tree{mesh.faces_begin(), mesh.faces_end(), mesh};
|
||||||
|
tree.build();
|
||||||
|
return 0;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_TreeCreation);
|
||||||
|
|
||||||
|
static void BM_Intersections(benchmark::State& state)
|
||||||
|
{
|
||||||
|
Point_3 p(-0.5, 0.03, 0.04);
|
||||||
|
Point_3 q(-0.5, 0.04, 0.06);
|
||||||
|
|
||||||
|
Tree tree{mesh.faces_begin(), mesh.faces_end(), mesh};
|
||||||
|
tree.accelerate_distance_queries();
|
||||||
|
|
||||||
|
Segment segment_query(p, q);
|
||||||
|
for (auto _ : state)
|
||||||
|
{
|
||||||
|
benchmark::DoNotOptimize([&]() {
|
||||||
|
tree.number_of_intersected_primitives(segment_query);
|
||||||
|
Point_3 point_query(2.0, 2.0, 2.0);
|
||||||
|
Point_3 closest = tree.closest_point(point_query);
|
||||||
|
return 0;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_Intersections);
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
const char* default_file = "data/handle.off";
|
||||||
|
const char* filename = argc > 2? argv[2] : default_file;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ifstream input(filename);
|
||||||
|
input >> mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
::benchmark::Initialize(&argc, argv);
|
||||||
|
::benchmark::RunSpecifiedBenchmarks();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
#ifndef CGAL_AABB_TREE_H
|
#ifndef CGAL_AABB_TREE_H
|
||||||
#define CGAL_AABB_TREE_H
|
#define CGAL_AABB_TREE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <CGAL/license/AABB_tree.h>
|
#include <CGAL/license/AABB_tree.h>
|
||||||
|
|
||||||
#include <CGAL/disable_warnings.h>
|
#include <CGAL/disable_warnings.h>
|
||||||
|
|
@ -61,6 +63,8 @@ namespace CGAL {
|
||||||
// type of the primitives container
|
// type of the primitives container
|
||||||
typedef std::vector<typename AABBTraits::Primitive> Primitives;
|
typedef std::vector<typename AABBTraits::Primitive> Primitives;
|
||||||
|
|
||||||
|
typedef AABB_tree<AABBTraits> Self;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef AABBTraits AABB_traits;
|
typedef AABBTraits AABB_traits;
|
||||||
|
|
||||||
|
|
@ -111,6 +115,14 @@ namespace CGAL {
|
||||||
/// class using `traits`.
|
/// class using `traits`.
|
||||||
AABB_tree(const AABBTraits& traits = AABBTraits());
|
AABB_tree(const AABBTraits& traits = AABBTraits());
|
||||||
|
|
||||||
|
// move constructor and assignment operator
|
||||||
|
AABB_tree(Self&&) noexcept;
|
||||||
|
Self& operator=(Self&&) noexcept;
|
||||||
|
|
||||||
|
// Disabled copy constructor & assignment operator
|
||||||
|
AABB_tree(const Self&) = delete;
|
||||||
|
Self& operator=(const Self&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Builds the datastructure from a sequence of primitives.
|
* @brief Builds the datastructure from a sequence of primitives.
|
||||||
* @param first iterator over first primitive to insert
|
* @param first iterator over first primitive to insert
|
||||||
|
|
@ -477,10 +489,7 @@ public:
|
||||||
// clear nodes
|
// clear nodes
|
||||||
void clear_nodes()
|
void clear_nodes()
|
||||||
{
|
{
|
||||||
if( size() > 1 ) {
|
m_p_nodes.clear();
|
||||||
delete [] m_p_root_node;
|
|
||||||
}
|
|
||||||
m_p_root_node = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// clears internal KD tree
|
// clears internal KD tree
|
||||||
|
|
@ -489,8 +498,7 @@ public:
|
||||||
if ( m_search_tree_constructed )
|
if ( m_search_tree_constructed )
|
||||||
{
|
{
|
||||||
CGAL_assertion( m_p_search_tree!=nullptr );
|
CGAL_assertion( m_p_search_tree!=nullptr );
|
||||||
delete m_p_search_tree;
|
m_p_search_tree.reset();
|
||||||
m_p_search_tree = nullptr;
|
|
||||||
m_search_tree_constructed = false;
|
m_search_tree_constructed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -516,6 +524,20 @@ public:
|
||||||
private:
|
private:
|
||||||
typedef AABB_node<AABBTraits> Node;
|
typedef AABB_node<AABBTraits> Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builds the tree by recursive expansion.
|
||||||
|
* @param first the first primitive to insert
|
||||||
|
* @param last the last primitive to insert
|
||||||
|
* @param range the number of primitive of the range
|
||||||
|
*
|
||||||
|
* [first,last[ is the range of primitives to be added to the tree.
|
||||||
|
*/
|
||||||
|
template<typename ConstPrimitiveIterator>
|
||||||
|
void expand(Node& node,
|
||||||
|
ConstPrimitiveIterator first,
|
||||||
|
ConstPrimitiveIterator beyond,
|
||||||
|
const std::size_t range,
|
||||||
|
const AABBTraits&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// returns a point which must be on one primitive
|
// returns a point which must be on one primitive
|
||||||
|
|
@ -555,8 +577,8 @@ public:
|
||||||
AABBTraits m_traits;
|
AABBTraits m_traits;
|
||||||
// set of input primitives
|
// set of input primitives
|
||||||
Primitives m_primitives;
|
Primitives m_primitives;
|
||||||
// single root node
|
// tree nodes. first node is the root node
|
||||||
Node* m_p_root_node;
|
std::vector<Node> m_p_nodes;
|
||||||
#ifdef CGAL_HAS_THREADS
|
#ifdef CGAL_HAS_THREADS
|
||||||
mutable CGAL_MUTEX internal_tree_mutex;//mutex used to protect const calls inducing build()
|
mutable CGAL_MUTEX internal_tree_mutex;//mutex used to protect const calls inducing build()
|
||||||
mutable CGAL_MUTEX kd_tree_mutex;//mutex used to protect calls to accelerate_distance_queries
|
mutable CGAL_MUTEX kd_tree_mutex;//mutex used to protect calls to accelerate_distance_queries
|
||||||
|
|
@ -572,7 +594,13 @@ public:
|
||||||
#endif
|
#endif
|
||||||
const_cast< AABB_tree<AABBTraits>* >(this)->build();
|
const_cast< AABB_tree<AABBTraits>* >(this)->build();
|
||||||
}
|
}
|
||||||
return m_p_root_node;
|
return std::addressof(m_p_nodes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node& new_node()
|
||||||
|
{
|
||||||
|
m_p_nodes.emplace_back();
|
||||||
|
return m_p_nodes.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Primitive& singleton_data() const {
|
const Primitive& singleton_data() const {
|
||||||
|
|
@ -581,17 +609,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// search KD-tree
|
// search KD-tree
|
||||||
mutable const Search_tree* m_p_search_tree;
|
mutable std::unique_ptr<const Search_tree> m_p_search_tree;
|
||||||
mutable bool m_search_tree_constructed;
|
mutable bool m_search_tree_constructed;
|
||||||
mutable bool m_default_search_tree_constructed; // indicates whether the internal kd-tree should be built
|
mutable bool m_default_search_tree_constructed; // indicates whether the internal kd-tree should be built
|
||||||
bool m_need_build;
|
bool m_need_build;
|
||||||
|
|
||||||
private:
|
|
||||||
// Disabled copy constructor & assignment operator
|
|
||||||
typedef AABB_tree<AABBTraits> Self;
|
|
||||||
AABB_tree(const Self& src);
|
|
||||||
Self& operator=(const Self& src);
|
|
||||||
|
|
||||||
}; // end class AABB_tree
|
}; // end class AABB_tree
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
@ -600,13 +622,32 @@ public:
|
||||||
AABB_tree<Tr>::AABB_tree(const Tr& traits)
|
AABB_tree<Tr>::AABB_tree(const Tr& traits)
|
||||||
: m_traits(traits)
|
: m_traits(traits)
|
||||||
, m_primitives()
|
, m_primitives()
|
||||||
, m_p_root_node(nullptr)
|
, m_p_nodes()
|
||||||
, m_p_search_tree(nullptr)
|
, m_p_search_tree(nullptr)
|
||||||
, m_search_tree_constructed(false)
|
, m_search_tree_constructed(false)
|
||||||
, m_default_search_tree_constructed(true)
|
, m_default_search_tree_constructed(true)
|
||||||
, m_need_build(false)
|
, m_need_build(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
template <typename Tr>
|
||||||
|
typename AABB_tree<Tr>::Self& AABB_tree<Tr>::operator=(Self&& tree) noexcept
|
||||||
|
{
|
||||||
|
m_traits = std::move(tree.m_traits);
|
||||||
|
m_primitives = std::move(tree.m_primitives);
|
||||||
|
m_p_nodes = std::move(tree.m_p_nodes);
|
||||||
|
m_p_search_tree = std::move(tree.m_p_search_tree);
|
||||||
|
m_search_tree_constructed = std::exchange(tree.m_search_tree_constructed, false);
|
||||||
|
m_default_search_tree_constructed = std::exchange(tree.m_default_search_tree_constructed, true);
|
||||||
|
m_need_build = std::exchange(tree.m_need_build, false);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Tr>
|
||||||
|
AABB_tree<Tr>::AABB_tree(Self&& tree) noexcept
|
||||||
|
{
|
||||||
|
*this = std::move(tree);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Tr>
|
template<typename Tr>
|
||||||
template<typename ConstPrimitiveIterator, typename ... T>
|
template<typename ConstPrimitiveIterator, typename ... T>
|
||||||
AABB_tree<Tr>::AABB_tree(ConstPrimitiveIterator first,
|
AABB_tree<Tr>::AABB_tree(ConstPrimitiveIterator first,
|
||||||
|
|
@ -614,7 +655,7 @@ public:
|
||||||
T&& ... t)
|
T&& ... t)
|
||||||
: m_traits()
|
: m_traits()
|
||||||
, m_primitives()
|
, m_primitives()
|
||||||
, m_p_root_node(nullptr)
|
, m_p_nodes()
|
||||||
, m_p_search_tree(nullptr)
|
, m_p_search_tree(nullptr)
|
||||||
, m_search_tree_constructed(false)
|
, m_search_tree_constructed(false)
|
||||||
, m_default_search_tree_constructed(true)
|
, m_default_search_tree_constructed(true)
|
||||||
|
|
@ -670,25 +711,51 @@ public:
|
||||||
m_need_build = true;
|
m_need_build = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Tr>
|
||||||
|
template<typename ConstPrimitiveIterator>
|
||||||
|
void
|
||||||
|
AABB_tree<Tr>::expand(Node& node,
|
||||||
|
ConstPrimitiveIterator first,
|
||||||
|
ConstPrimitiveIterator beyond,
|
||||||
|
const std::size_t range,
|
||||||
|
const Tr& traits)
|
||||||
|
{
|
||||||
|
node.set_bbox(traits.compute_bbox_object()(first, beyond));
|
||||||
|
|
||||||
|
// sort primitives along longest axis aabb
|
||||||
|
traits.split_primitives_object()(first, beyond, node.bbox());
|
||||||
|
|
||||||
|
switch(range)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
node.set_children(*first, *(first+1));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
node.set_children(*first, new_node());
|
||||||
|
expand(node.right_child(), first+1, beyond, 2, traits);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
const std::size_t new_range = range/2;
|
||||||
|
node.set_children(new_node(), new_node());
|
||||||
|
expand(node.left_child(), first, first + new_range, new_range, traits);
|
||||||
|
expand(node.right_child(), first + new_range, beyond, range - new_range, traits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Build the data structure, after calls to insert(..)
|
// Build the data structure, after calls to insert(..)
|
||||||
template<typename Tr>
|
template<typename Tr>
|
||||||
void AABB_tree<Tr>::build()
|
void AABB_tree<Tr>::build()
|
||||||
{
|
{
|
||||||
clear_nodes();
|
clear_nodes();
|
||||||
|
|
||||||
if(m_primitives.size() > 1) {
|
if(m_primitives.size() > 1) {
|
||||||
|
|
||||||
// allocates tree nodes
|
// allocates tree nodes
|
||||||
m_p_root_node = new Node[m_primitives.size()-1]();
|
m_p_nodes.reserve(m_primitives.size()-1);
|
||||||
if(m_p_root_node == nullptr)
|
|
||||||
{
|
|
||||||
std::cerr << "Unable to allocate memory for AABB tree" << std::endl;
|
|
||||||
CGAL_assertion(m_p_root_node != nullptr);
|
|
||||||
m_primitives.clear();
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// constructs the tree
|
// constructs the tree
|
||||||
m_p_root_node->expand(m_primitives.begin(), m_primitives.end(),
|
expand(new_node(), m_primitives.begin(), m_primitives.end(),
|
||||||
m_primitives.size(), m_traits);
|
m_primitives.size(), m_traits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -729,19 +796,11 @@ public:
|
||||||
bool AABB_tree<Tr>::build_kd_tree(ConstPointIterator first,
|
bool AABB_tree<Tr>::build_kd_tree(ConstPointIterator first,
|
||||||
ConstPointIterator beyond) const
|
ConstPointIterator beyond) const
|
||||||
{
|
{
|
||||||
m_p_search_tree = new Search_tree(first, beyond);
|
m_p_search_tree = std::make_unique<const Search_tree>(first, beyond);
|
||||||
m_default_search_tree_constructed = true;
|
m_default_search_tree_constructed = true;
|
||||||
if(m_p_search_tree != nullptr)
|
|
||||||
{
|
|
||||||
m_search_tree_constructed = true;
|
m_search_tree_constructed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << "Unable to allocate memory for accelerating distance queries" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tr>
|
template<typename Tr>
|
||||||
void AABB_tree<Tr>::do_not_accelerate_distance_queries()const
|
void AABB_tree<Tr>::do_not_accelerate_distance_queries()const
|
||||||
|
|
@ -750,7 +809,6 @@ public:
|
||||||
m_default_search_tree_constructed = false;
|
m_default_search_tree_constructed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// constructs the search KD tree from internal primitives
|
// constructs the search KD tree from internal primitives
|
||||||
template<typename Tr>
|
template<typename Tr>
|
||||||
bool AABB_tree<Tr>::accelerate_distance_queries() const
|
bool AABB_tree<Tr>::accelerate_distance_queries() const
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ namespace CGAL {
|
||||||
template<typename AABBTraits>
|
template<typename AABBTraits>
|
||||||
class AABB_node
|
class AABB_node
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
typedef AABB_node<AABBTraits> Self;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename AABBTraits::Bounding_box Bounding_box;
|
typedef typename AABBTraits::Bounding_box Bounding_box;
|
||||||
|
|
||||||
|
|
@ -41,27 +44,15 @@ public:
|
||||||
, m_p_left_child(nullptr)
|
, m_p_left_child(nullptr)
|
||||||
, m_p_right_child(nullptr) { };
|
, m_p_right_child(nullptr) { };
|
||||||
|
|
||||||
/// Non virtual Destructor
|
AABB_node(Self&& node) = default;
|
||||||
/// Do not delete children because the tree hosts and delete them
|
|
||||||
~AABB_node() { };
|
// Disabled copy constructor & assignment operator
|
||||||
|
AABB_node(const Self& src) = delete;
|
||||||
|
Self& operator=(const Self& src) = delete;
|
||||||
|
|
||||||
/// Returns the bounding box of the node
|
/// Returns the bounding box of the node
|
||||||
const Bounding_box& bbox() const { return m_bbox; }
|
const Bounding_box& bbox() const { return m_bbox; }
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Builds the tree by recursive expansion.
|
|
||||||
* @param first the first primitive to insert
|
|
||||||
* @param last the last primitive to insert
|
|
||||||
* @param range the number of primitive of the range
|
|
||||||
*
|
|
||||||
* [first,last[ is the range of primitives to be added to the tree.
|
|
||||||
*/
|
|
||||||
template<typename ConstPrimitiveIterator>
|
|
||||||
void expand(ConstPrimitiveIterator first,
|
|
||||||
ConstPrimitiveIterator beyond,
|
|
||||||
const std::size_t range,
|
|
||||||
const AABBTraits&);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief General traversal query
|
* @brief General traversal query
|
||||||
* @param query the query
|
* @param query the query
|
||||||
|
|
@ -93,8 +84,17 @@ public:
|
||||||
{ return *static_cast<Primitive*>(m_p_left_child); }
|
{ return *static_cast<Primitive*>(m_p_left_child); }
|
||||||
const Primitive& right_data() const
|
const Primitive& right_data() const
|
||||||
{ return *static_cast<Primitive*>(m_p_right_child); }
|
{ return *static_cast<Primitive*>(m_p_right_child); }
|
||||||
|
template <class Left, class Right>
|
||||||
|
void set_children(Left& l, Right& r)
|
||||||
|
{
|
||||||
|
m_p_left_child = static_cast<void*>(std::addressof(l));
|
||||||
|
m_p_right_child = static_cast<void*>(std::addressof(r));
|
||||||
|
}
|
||||||
|
void set_bbox(const Bounding_box& bbox)
|
||||||
|
{
|
||||||
|
m_bbox = bbox;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
Node& left_child() { return *static_cast<Node*>(m_p_left_child); }
|
Node& left_child() { return *static_cast<Node*>(m_p_left_child); }
|
||||||
Node& right_child() { return *static_cast<Node*>(m_p_right_child); }
|
Node& right_child() { return *static_cast<Node*>(m_p_right_child); }
|
||||||
Primitive& left_data() { return *static_cast<Primitive*>(m_p_left_child); }
|
Primitive& left_data() { return *static_cast<Primitive*>(m_p_left_child); }
|
||||||
|
|
@ -109,49 +109,8 @@ private:
|
||||||
void *m_p_left_child;
|
void *m_p_left_child;
|
||||||
void *m_p_right_child;
|
void *m_p_right_child;
|
||||||
|
|
||||||
private:
|
|
||||||
// Disabled copy constructor & assignment operator
|
|
||||||
typedef AABB_node<AABBTraits> Self;
|
|
||||||
AABB_node(const Self& src);
|
|
||||||
Self& operator=(const Self& src);
|
|
||||||
|
|
||||||
}; // end class AABB_node
|
}; // end class AABB_node
|
||||||
|
|
||||||
|
|
||||||
template<typename Tr>
|
|
||||||
template<typename ConstPrimitiveIterator>
|
|
||||||
void
|
|
||||||
AABB_node<Tr>::expand(ConstPrimitiveIterator first,
|
|
||||||
ConstPrimitiveIterator beyond,
|
|
||||||
const std::size_t range,
|
|
||||||
const Tr& traits)
|
|
||||||
{
|
|
||||||
m_bbox = traits.compute_bbox_object()(first, beyond);
|
|
||||||
|
|
||||||
// sort primitives along longest axis aabb
|
|
||||||
traits.split_primitives_object()(first, beyond, m_bbox);
|
|
||||||
|
|
||||||
switch(range)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
m_p_left_child = &(*first);
|
|
||||||
m_p_right_child = &(*(++first));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
m_p_left_child = &(*first);
|
|
||||||
m_p_right_child = static_cast<Node*>(this)+1;
|
|
||||||
right_child().expand(first+1, beyond, 2,traits);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const std::size_t new_range = range/2;
|
|
||||||
m_p_left_child = static_cast<Node*>(this) + 1;
|
|
||||||
m_p_right_child = static_cast<Node*>(this) + new_range;
|
|
||||||
left_child().expand(first, first + new_range, new_range,traits);
|
|
||||||
right_child().expand(first + new_range, beyond, range - new_range,traits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Tr>
|
template<typename Tr>
|
||||||
template<class Traversal_traits, class Query>
|
template<class Traversal_traits, class Query>
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ namespace CGAL
|
||||||
typedef typename CGAL::Orthogonal_k_neighbor_search<TreeTraits> Neighbor_search;
|
typedef typename CGAL::Orthogonal_k_neighbor_search<TreeTraits> Neighbor_search;
|
||||||
typedef typename Neighbor_search::Tree Tree;
|
typedef typename Neighbor_search::Tree Tree;
|
||||||
private:
|
private:
|
||||||
Tree* m_p_tree;
|
Tree m_tree;
|
||||||
|
|
||||||
|
|
||||||
Point_and_primitive_id get_p_and_p(const Point_and_primitive_id& p)
|
Point_and_primitive_id get_p_and_p(const Point_and_primitive_id& p)
|
||||||
|
|
@ -98,30 +98,22 @@ namespace CGAL
|
||||||
public:
|
public:
|
||||||
template <class ConstPointIterator>
|
template <class ConstPointIterator>
|
||||||
AABB_search_tree(ConstPointIterator begin, ConstPointIterator beyond)
|
AABB_search_tree(ConstPointIterator begin, ConstPointIterator beyond)
|
||||||
: m_p_tree(nullptr)
|
: m_tree{}
|
||||||
{
|
{
|
||||||
typedef typename Add_decorated_point<Traits,typename Traits::Primitive::Id>::Point_3 Decorated_point;
|
typedef typename Add_decorated_point<Traits,typename Traits::Primitive::Id>::Point_3 Decorated_point;
|
||||||
std::vector<Decorated_point> points;
|
std::vector<Decorated_point> points;
|
||||||
while(begin != beyond) {
|
while(begin != beyond) {
|
||||||
Point_and_primitive_id pp = get_p_and_p(*begin);
|
Point_and_primitive_id pp = get_p_and_p(*begin);
|
||||||
points.push_back(Decorated_point(pp.first,pp.second));
|
points.emplace_back(pp.first, pp.second);
|
||||||
++begin;
|
++begin;
|
||||||
}
|
}
|
||||||
m_p_tree = new Tree(points.begin(), points.end());
|
m_tree.insert(points.begin(), points.end());
|
||||||
if(m_p_tree != nullptr)
|
m_tree.build();
|
||||||
m_p_tree->build();
|
|
||||||
else
|
|
||||||
std::cerr << "unable to build the search tree!" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~AABB_search_tree() {
|
|
||||||
delete m_p_tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Point_and_primitive_id closest_point(const Point& query) const
|
Point_and_primitive_id closest_point(const Point& query) const
|
||||||
{
|
{
|
||||||
Neighbor_search search(*m_p_tree, query, 1);
|
Neighbor_search search(m_tree, query, 1);
|
||||||
return Point_and_primitive_id(static_cast<Point>(search.begin()->first), search.begin()->first.id());
|
return Point_and_primitive_id(static_cast<Point>(search.begin()->first), search.begin()->first.id());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||||
|
#include <CGAL/AABB_halfedge_graph_segment_primitive.h>
|
||||||
|
#include <CGAL/AABB_segment_primitive.h>
|
||||||
|
#include <CGAL/AABB_traits.h>
|
||||||
|
#include <CGAL/AABB_tree.h>
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/Polyhedron_3.h>
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
#include <CGAL/assertions.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
template <int test_number> auto create_tree();
|
||||||
|
template <int test_number, typename T> void init_tree(T &tree) {}
|
||||||
|
template <int test_number, typename T> bool test_tree(T &tree);
|
||||||
|
template <int test_number> class TestUtils;
|
||||||
|
|
||||||
|
// test 0 is from "aabb_test_singleton_tree"
|
||||||
|
template <> struct TestUtils<0> {
|
||||||
|
typedef CGAL::Simple_cartesian<double> K;
|
||||||
|
typedef K::FT FT;
|
||||||
|
typedef K::Point_3 Point;
|
||||||
|
typedef K::Plane_3 Plane;
|
||||||
|
typedef K::Segment_3 Segment;
|
||||||
|
typedef K::Triangle_3 Triangle;
|
||||||
|
typedef std::vector<Segment>::iterator Iterator;
|
||||||
|
typedef CGAL::AABB_segment_primitive<K, Iterator> Primitive;
|
||||||
|
typedef CGAL::AABB_traits<K, Primitive> Traits;
|
||||||
|
typedef CGAL::AABB_tree<Traits> Tree;
|
||||||
|
|
||||||
|
Point a = {1.0, 0.0, 0.0};
|
||||||
|
Point b = {0.0, 1.0, 0.0};
|
||||||
|
Point c = {0.0, 0.0, 1.0};
|
||||||
|
Point d = {0.0, 0.0, 0.0};
|
||||||
|
std::vector<Segment> segments = {Segment(Point(0, 0, 0), Point(2, 2, 2))};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> auto create_tree<0>() {
|
||||||
|
using T = TestUtils<0>;
|
||||||
|
T utils;
|
||||||
|
return T::Tree(utils.segments.begin(), utils.segments.end());
|
||||||
|
}
|
||||||
|
using Test0Param = decltype(create_tree<0>());
|
||||||
|
template <> bool test_tree<0, Test0Param>(Test0Param &tree) {
|
||||||
|
using T = TestUtils<0>;
|
||||||
|
T utils;
|
||||||
|
|
||||||
|
T::Plane plane_query(utils.a, utils.b, utils.d);
|
||||||
|
T::Triangle triangle_query(utils.a, utils.b, utils.c);
|
||||||
|
|
||||||
|
// Test calls to all functions
|
||||||
|
CGAL::Emptyset_iterator devnull;
|
||||||
|
tree.all_intersections(triangle_query, devnull);
|
||||||
|
tree.all_intersected_primitives(triangle_query, devnull);
|
||||||
|
assert(tree.any_intersected_primitive(triangle_query));
|
||||||
|
assert(tree.any_intersection(triangle_query));
|
||||||
|
const CGAL::Bbox_3 bbox = tree.bbox();
|
||||||
|
assert(bbox == CGAL::Bbox_3(0, 0, 0, 2, 2, 2));
|
||||||
|
tree.clear();
|
||||||
|
tree.insert(utils.segments.begin(), utils.segments.end());
|
||||||
|
tree.build();
|
||||||
|
assert(tree.closest_point(T::Point(-0.1, -0.1, -0.1)) == T::Point(0, 0, 0));
|
||||||
|
assert(tree.closest_point(T::Point(-0.1, -0.1, -0.1), T::Point(0, 0, 0)) ==
|
||||||
|
T::Point(0, 0, 0));
|
||||||
|
assert(tree.closest_point_and_primitive(T::Point(-0.1, -0.1, -0.1)).second ==
|
||||||
|
utils.segments.begin());
|
||||||
|
assert(tree.do_intersect(plane_query) == true);
|
||||||
|
assert(tree.do_intersect(triangle_query) == true);
|
||||||
|
assert(!tree.empty());
|
||||||
|
assert(tree.size() == 1);
|
||||||
|
tree.clear();
|
||||||
|
assert(tree.size() == 0);
|
||||||
|
tree.insert(utils.segments.begin(), utils.segments.end());
|
||||||
|
assert(tree.size() == 1);
|
||||||
|
assert(tree.number_of_intersected_primitives(plane_query) == 1);
|
||||||
|
tree.rebuild(utils.segments.begin(), utils.segments.end());
|
||||||
|
assert(tree.size() == 1);
|
||||||
|
assert(tree.number_of_intersected_primitives(triangle_query) == 1);
|
||||||
|
assert(tree.squared_distance(T::Point(0, 0, 0)) == 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test 1 is from "aabb_test_all_intersected_primitives"
|
||||||
|
template <> struct TestUtils<1> {
|
||||||
|
typedef CGAL::Epick K;
|
||||||
|
typedef K::FT FT;
|
||||||
|
typedef K::Point_3 Point;
|
||||||
|
typedef K::Vector_3 Vector;
|
||||||
|
typedef K::Segment_3 Segment;
|
||||||
|
typedef K::Ray_3 Ray;
|
||||||
|
typedef CGAL::Surface_mesh<CGAL::Point_3<CGAL::Epick>> Mesh;
|
||||||
|
typedef CGAL::AABB_halfedge_graph_segment_primitive<Mesh, CGAL::Default,
|
||||||
|
CGAL::Tag_false>
|
||||||
|
S_Primitive;
|
||||||
|
typedef CGAL::AABB_face_graph_triangle_primitive<Mesh, CGAL::Default,
|
||||||
|
CGAL::Tag_false>
|
||||||
|
T_Primitive;
|
||||||
|
typedef CGAL::AABB_traits<K, T_Primitive> T_Traits;
|
||||||
|
typedef CGAL::AABB_traits<K, S_Primitive> S_Traits;
|
||||||
|
typedef CGAL::AABB_tree<T_Traits> T_Tree;
|
||||||
|
typedef CGAL::AABB_tree<S_Traits> S_Tree;
|
||||||
|
typedef T_Tree::Primitive_id T_Primitive_id;
|
||||||
|
typedef S_Tree::Primitive_id S_Primitive_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> auto create_tree<1>() {
|
||||||
|
using T = TestUtils<1>;
|
||||||
|
|
||||||
|
static CGAL::Surface_mesh<CGAL::Point_3<CGAL::Epick>> m1 = {};
|
||||||
|
static CGAL::Surface_mesh<CGAL::Point_3<CGAL::Epick>> m2 = {};
|
||||||
|
static bool mesh_loaded = false;
|
||||||
|
if (!mesh_loaded) {
|
||||||
|
std::ifstream in("data/cube.off");
|
||||||
|
assert(in);
|
||||||
|
in >> m1;
|
||||||
|
in.close();
|
||||||
|
in.open("data/tetrahedron.off");
|
||||||
|
assert(in);
|
||||||
|
in >> m2;
|
||||||
|
in.close();
|
||||||
|
mesh_loaded = true;
|
||||||
|
}
|
||||||
|
return std::make_pair(T::T_Tree{faces(m1).first, faces(m1).second, m1},
|
||||||
|
T::S_Tree{edges(m2).first, edges(m2).second, m2});
|
||||||
|
}
|
||||||
|
using Test1Param = decltype(create_tree<1>());
|
||||||
|
template <> void init_tree<1, Test1Param>(Test1Param &trees) {
|
||||||
|
trees.first.build();
|
||||||
|
trees.second.build();
|
||||||
|
}
|
||||||
|
template <> bool test_tree<1, Test1Param>(Test1Param &trees) {
|
||||||
|
using T = TestUtils<1>;
|
||||||
|
|
||||||
|
auto &cube_tree = trees.first;
|
||||||
|
auto &tet_tree = trees.second;
|
||||||
|
|
||||||
|
std::list<T::T_Tree::Primitive::Id> t_primitives;
|
||||||
|
std::list<T::S_Tree::Primitive::Id> s_primitives;
|
||||||
|
cube_tree.all_intersected_primitives(tet_tree,
|
||||||
|
std::back_inserter(t_primitives));
|
||||||
|
CGAL_assertion(t_primitives.size() == 6);
|
||||||
|
tet_tree.all_intersected_primitives(cube_tree,
|
||||||
|
std::back_inserter(s_primitives));
|
||||||
|
CGAL_assertion(s_primitives.size() == 6);
|
||||||
|
CGAL_assertion(tet_tree.do_intersect(cube_tree));
|
||||||
|
CGAL_assertion(cube_tree.do_intersect(tet_tree));
|
||||||
|
|
||||||
|
std::vector<T::T_Tree::Primitive::Id> all_primitives;
|
||||||
|
cube_tree.all_intersected_primitives(tet_tree,
|
||||||
|
std::back_inserter(all_primitives));
|
||||||
|
bool found_f5 = false;
|
||||||
|
for (auto prim : all_primitives) {
|
||||||
|
if ((int)prim.first == 5)
|
||||||
|
found_f5 = true;
|
||||||
|
}
|
||||||
|
CGAL_assertion(found_f5);
|
||||||
|
CGAL_USE(found_f5);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int test_number> bool run_test() {
|
||||||
|
// create_tree should return prvalue for guaranteed copy elision
|
||||||
|
auto tree_1 = create_tree<test_number>();
|
||||||
|
init_tree<test_number>(tree_1);
|
||||||
|
auto tree_2 = create_tree<test_number>();
|
||||||
|
init_tree<test_number>(tree_2);
|
||||||
|
auto tree_3 = create_tree<test_number>();
|
||||||
|
init_tree<test_number>(tree_3);
|
||||||
|
|
||||||
|
decltype(tree_1) tree_ctor{std::move(tree_2)};
|
||||||
|
decltype(tree_1) tree_assig{};
|
||||||
|
tree_assig = std::move(tree_3);
|
||||||
|
|
||||||
|
bool normal = test_tree<test_number>(tree_1);
|
||||||
|
bool move_ctor = test_tree<test_number>(tree_ctor);
|
||||||
|
bool move_ass =
|
||||||
|
test_tree<test_number>(tree_assig); // test move assignment operator
|
||||||
|
|
||||||
|
if (!normal)
|
||||||
|
std::cout << "Test " << test_number << "failed on the original tree\n";
|
||||||
|
if (!move_ctor)
|
||||||
|
std::cout << "Test " << test_number << "failed on move constructed tree\n";
|
||||||
|
if (!move_ass)
|
||||||
|
std::cout << "Test " << test_number << "failed on move assigned tree\n";
|
||||||
|
return normal && move_ctor && move_ass;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() { return (run_test<0>() && run_test<1>()) ? 0 : 1; }
|
||||||
|
|
@ -6,6 +6,9 @@ Release History
|
||||||
|
|
||||||
Release date: June 2020
|
Release date: June 2020
|
||||||
|
|
||||||
|
### Add Move Semantics to AABB Trees
|
||||||
|
- Added move constructor and assignment operator to AABB Tree class.
|
||||||
|
|
||||||
### Surface Mesh Topology (new package)
|
### Surface Mesh Topology (new package)
|
||||||
|
|
||||||
- This package allows to compute some topological invariants of
|
- This package allows to compute some topological invariants of
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue