mirror of https://github.com/CGAL/cgal
Bug fix: fix AABB_tree doc and code about preconditions !empty()
The AABB_tree code had several assertions checkinng that the tree was not empty. Those preconditions were not documented. There was several places in the code were it was not really required that the tree is not empty. This patch rationalizes the preconditions: only the function `bbox()` and the queries about distances or closest things now require that the tree is not empty.
This commit is contained in:
parent
3b1ba8ba70
commit
fc3061c822
|
|
@ -169,7 +169,11 @@ namespace CGAL {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the axis-aligned bounding box of the whole tree.
|
/// Returns the axis-aligned bounding box of the whole tree.
|
||||||
const Bounding_box& bbox() const { return root_node()->bbox(); }
|
/// \pre `!empty()`
|
||||||
|
const Bounding_box& bbox() const {
|
||||||
|
CGAL_precondition(!empty());
|
||||||
|
return root_node()->bbox();
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of primitives in the tree.
|
/// Returns the number of primitives in the tree.
|
||||||
size_type size() const { return m_primitives.size(); }
|
size_type size() const { return m_primitives.size(); }
|
||||||
|
|
@ -255,6 +259,7 @@ public:
|
||||||
/// `accelerate_distance_queries()` should be called before the
|
/// `accelerate_distance_queries()` should be called before the
|
||||||
/// first distance query, so that an internal secondary search
|
/// first distance query, so that an internal secondary search
|
||||||
/// structure is build, for improving performance.
|
/// structure is build, for improving performance.
|
||||||
|
/// \pre `!empty()`
|
||||||
FT squared_distance(const Point& query) const;
|
FT squared_distance(const Point& query) const;
|
||||||
|
|
||||||
/// Returns the point in the union of all input primitives which
|
/// Returns the point in the union of all input primitives which
|
||||||
|
|
@ -264,6 +269,7 @@ public:
|
||||||
/// called before the first distance query, so that an internal
|
/// called before the first distance query, so that an internal
|
||||||
/// secondary search structure is build, for improving
|
/// secondary search structure is build, for improving
|
||||||
/// performance.
|
/// performance.
|
||||||
|
/// \pre `!empty()`
|
||||||
Point closest_point(const Point& query) const;
|
Point closest_point(const Point& query) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -273,6 +279,7 @@ public:
|
||||||
/// called before the first distance query, so that an internal
|
/// called before the first distance query, so that an internal
|
||||||
/// secondary search structure is build, for improving
|
/// secondary search structure is build, for improving
|
||||||
/// performance.
|
/// performance.
|
||||||
|
/// \pre `!empty()`
|
||||||
Point_and_primitive_id closest_point_and_primitive(const Point& query) const;
|
Point_and_primitive_id closest_point_and_primitive(const Point& query) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -357,17 +364,20 @@ public:
|
||||||
|
|
||||||
/// Returns the minimum squared distance between the query point
|
/// Returns the minimum squared distance between the query point
|
||||||
/// and all input primitives. The internal KD-tree is not used.
|
/// and all input primitives. The internal KD-tree is not used.
|
||||||
|
/// \pre `!empty()`
|
||||||
FT squared_distance(const Point& query, const Point& hint) const;
|
FT squared_distance(const Point& query, const Point& hint) const;
|
||||||
|
|
||||||
/// Returns the point in the union of all input primitives which
|
/// Returns the point in the union of all input primitives which
|
||||||
/// is closest to the query. In case there are several closest
|
/// is closest to the query. In case there are several closest
|
||||||
/// points, one arbitrarily chosen closest point is returned. The
|
/// points, one arbitrarily chosen closest point is returned. The
|
||||||
/// internal KD-tree is not used.
|
/// internal KD-tree is not used.
|
||||||
|
/// \pre `!empty()`
|
||||||
Point closest_point(const Point& query, const Point& hint) const;
|
Point closest_point(const Point& query, const Point& hint) const;
|
||||||
|
|
||||||
/// Returns a `Point_and_primitive_id` which realizes the
|
/// Returns a `Point_and_primitive_id` which realizes the
|
||||||
/// smallest distance between the query point and all input
|
/// smallest distance between the query point and all input
|
||||||
/// primitives. The internal KD-tree is not used.
|
/// primitives. The internal KD-tree is not used.
|
||||||
|
/// \pre `!empty()`
|
||||||
Point_and_primitive_id closest_point_and_primitive(const Point& query, const Point_and_primitive_id& hint) const;
|
Point_and_primitive_id closest_point_and_primitive(const Point& query, const Point_and_primitive_id& hint) const;
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
@ -397,8 +407,6 @@ public:
|
||||||
{
|
{
|
||||||
if(!empty())
|
if(!empty())
|
||||||
root_node()->template traversal<Traversal_traits,Query>(query, traits, m_primitives.size());
|
root_node()->template traversal<Traversal_traits,Query>(query, traits, m_primitives.size());
|
||||||
else
|
|
||||||
std::cerr << "AABB tree traversal with empty tree" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -526,7 +534,7 @@ public:
|
||||||
{
|
{
|
||||||
clear_nodes();
|
clear_nodes();
|
||||||
|
|
||||||
CGAL_assertion(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_root_node = new Node[m_primitives.size()-1]();
|
||||||
|
|
@ -540,6 +548,7 @@ public:
|
||||||
|
|
||||||
// constructs the tree
|
// constructs the tree
|
||||||
m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), m_primitives.size());
|
m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), m_primitives.size());
|
||||||
|
}
|
||||||
|
|
||||||
// In case the users has switched on the acceletated distance query
|
// In case the users has switched on the acceletated distance query
|
||||||
// data structure with the default arguments, then it has to be
|
// data structure with the default arguments, then it has to be
|
||||||
|
|
@ -575,7 +584,7 @@ public:
|
||||||
template<typename Tr>
|
template<typename Tr>
|
||||||
bool AABB_tree<Tr>::accelerate_distance_queries() const
|
bool AABB_tree<Tr>::accelerate_distance_queries() const
|
||||||
{
|
{
|
||||||
CGAL_assertion(!m_primitives.empty());
|
if(m_primitives.empty()) return true;
|
||||||
#ifdef CGAL_HAS_THREADS
|
#ifdef CGAL_HAS_THREADS
|
||||||
//this ensures that this function will be done once
|
//this ensures that this function will be done once
|
||||||
boost::mutex::scoped_lock scoped_lock(kd_tree_mutex);
|
boost::mutex::scoped_lock scoped_lock(kd_tree_mutex);
|
||||||
|
|
@ -686,6 +695,7 @@ public:
|
||||||
AABB_tree<Tr>::closest_point(const Point& query,
|
AABB_tree<Tr>::closest_point(const Point& query,
|
||||||
const Point& hint) const
|
const Point& hint) const
|
||||||
{
|
{
|
||||||
|
CGAL_precondition(!empty());
|
||||||
typename Primitive::Id hint_primitive = m_primitives[0].id();
|
typename Primitive::Id hint_primitive = m_primitives[0].id();
|
||||||
using namespace CGAL::internal::AABB_tree;
|
using namespace CGAL::internal::AABB_tree;
|
||||||
typedef typename AABB_tree<Tr>::AABB_traits AABBTraits;
|
typedef typename AABB_tree<Tr>::AABB_traits AABBTraits;
|
||||||
|
|
@ -700,6 +710,7 @@ public:
|
||||||
typename AABB_tree<Tr>::Point
|
typename AABB_tree<Tr>::Point
|
||||||
AABB_tree<Tr>::closest_point(const Point& query) const
|
AABB_tree<Tr>::closest_point(const Point& query) const
|
||||||
{
|
{
|
||||||
|
CGAL_precondition(!empty());
|
||||||
const Point_and_primitive_id hint = best_hint(query);
|
const Point_and_primitive_id hint = best_hint(query);
|
||||||
return closest_point(query,hint.first);
|
return closest_point(query,hint.first);
|
||||||
}
|
}
|
||||||
|
|
@ -710,6 +721,7 @@ public:
|
||||||
AABB_tree<Tr>::squared_distance(const Point& query,
|
AABB_tree<Tr>::squared_distance(const Point& query,
|
||||||
const Point& hint) const
|
const Point& hint) const
|
||||||
{
|
{
|
||||||
|
CGAL_precondition(!empty());
|
||||||
const Point closest = this->closest_point(query, hint);
|
const Point closest = this->closest_point(query, hint);
|
||||||
return Tr().squared_distance_object()(query, closest);
|
return Tr().squared_distance_object()(query, closest);
|
||||||
}
|
}
|
||||||
|
|
@ -719,6 +731,7 @@ public:
|
||||||
typename AABB_tree<Tr>::FT
|
typename AABB_tree<Tr>::FT
|
||||||
AABB_tree<Tr>::squared_distance(const Point& query) const
|
AABB_tree<Tr>::squared_distance(const Point& query) const
|
||||||
{
|
{
|
||||||
|
CGAL_precondition(!empty());
|
||||||
const Point closest = this->closest_point(query);
|
const Point closest = this->closest_point(query);
|
||||||
return Tr().squared_distance_object()(query, closest);
|
return Tr().squared_distance_object()(query, closest);
|
||||||
}
|
}
|
||||||
|
|
@ -728,6 +741,7 @@ public:
|
||||||
typename AABB_tree<Tr>::Point_and_primitive_id
|
typename AABB_tree<Tr>::Point_and_primitive_id
|
||||||
AABB_tree<Tr>::closest_point_and_primitive(const Point& query) const
|
AABB_tree<Tr>::closest_point_and_primitive(const Point& query) const
|
||||||
{
|
{
|
||||||
|
CGAL_precondition(!empty());
|
||||||
return closest_point_and_primitive(query,best_hint(query));
|
return closest_point_and_primitive(query,best_hint(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -737,6 +751,7 @@ public:
|
||||||
AABB_tree<Tr>::closest_point_and_primitive(const Point& query,
|
AABB_tree<Tr>::closest_point_and_primitive(const Point& query,
|
||||||
const Point_and_primitive_id& hint) const
|
const Point_and_primitive_id& hint) const
|
||||||
{
|
{
|
||||||
|
CGAL_precondition(!empty());
|
||||||
using namespace CGAL::internal::AABB_tree;
|
using namespace CGAL::internal::AABB_tree;
|
||||||
typedef typename AABB_tree<Tr>::AABB_traits AABBTraits;
|
typedef typename AABB_tree<Tr>::AABB_traits AABBTraits;
|
||||||
Projection_traits<AABBTraits> projection_traits(hint.first,hint.second);
|
Projection_traits<AABBTraits> projection_traits(hint.first,hint.second);
|
||||||
|
|
@ -751,5 +766,5 @@ public:
|
||||||
/***EMACS SETTINGS** */
|
/***EMACS SETTINGS** */
|
||||||
/* Local Variables: */
|
/* Local Variables: */
|
||||||
/* tab-width: 2 */
|
/* tab-width: 2 */
|
||||||
|
/* indent-tabs-mode: t */
|
||||||
/* End: */
|
/* End: */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/AABB_tree.h>
|
||||||
|
#include <CGAL/AABB_traits.h>
|
||||||
|
#include <CGAL/AABB_segment_primitive.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
Tree tree;
|
||||||
|
Plane plane_query(a,b,d);
|
||||||
|
Triangle triangle_query(a,b,c);
|
||||||
|
|
||||||
|
// Test calls to all functions but those who have `!empty()` as
|
||||||
|
// precondition.
|
||||||
|
CGAL::Emptyset_iterator devnull;
|
||||||
|
tree.accelerate_distance_queries();
|
||||||
|
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));
|
||||||
|
//Cannot call tree.bbox();
|
||||||
|
tree.build();
|
||||||
|
tree.clear();
|
||||||
|
//Cannot call tree.closest_*(...)
|
||||||
|
assert(tree.do_intersect(plane_query) == false);
|
||||||
|
assert(tree.do_intersect(triangle_query) == false);
|
||||||
|
assert(tree.empty());
|
||||||
|
//Do not call tree.insert(...)
|
||||||
|
assert(tree.number_of_intersected_primitives(plane_query) == 0);
|
||||||
|
assert(tree.number_of_intersected_primitives(triangle_query) == 0);
|
||||||
|
// Cannot call tree.rebuild(..)
|
||||||
|
assert(tree.size() == 0);
|
||||||
|
// Cannot call tree.squared_distance(..)
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue