mirror of https://github.com/CGAL/cgal
505 lines
14 KiB
C++
505 lines
14 KiB
C++
// Copyright (c) 2002 Utrecht University (The Netherlands).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// 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$
|
|
//
|
|
//
|
|
// Author(s) : Hans Tangelder (<hanst@cs.uu.nl>)
|
|
|
|
#ifndef CGAL_ORTHOGONAL_INCREMENTAL_NEIGHBOR_SEARCH
|
|
#define CGAL_ORTHOGONAL_INCREMENTAL_NEIGHBOR_SEARCH
|
|
|
|
#include <cstring>
|
|
#include <list>
|
|
#include <queue>
|
|
#include <memory>
|
|
#include <CGAL/Kd_tree.h>
|
|
#include <CGAL/Euclidean_distance.h>
|
|
|
|
namespace CGAL {
|
|
|
|
template <class SearchTraits,
|
|
class Distance_= Euclidean_distance<SearchTraits>,
|
|
class Splitter_ = Sliding_midpoint<SearchTraits>,
|
|
class Tree_= Kd_tree<SearchTraits, Splitter_, Tag_true> >
|
|
class Orthogonal_incremental_neighbor_search {
|
|
|
|
public:
|
|
typedef Splitter_ Splitter;
|
|
typedef Tree_ Tree;
|
|
typedef Distance_ Distance;
|
|
typedef typename SearchTraits::Point_d Point_d;
|
|
typedef typename Distance::Query_item Query_item;
|
|
typedef typename SearchTraits::FT FT;
|
|
typedef typename Tree::Point_d_iterator Point_d_iterator;
|
|
typedef typename Tree::Node_handle Node_handle;
|
|
|
|
typedef std::pair<Point_d,FT> Point_with_transformed_distance;
|
|
typedef std::pair<Node_handle,FT> Node_with_distance;
|
|
typedef std::vector<Node_with_distance*> Node_with_distance_vector;
|
|
typedef std::vector<Point_with_transformed_distance*> Point_with_transformed_distance_vector;
|
|
|
|
|
|
|
|
class Iterator_implementation {
|
|
|
|
public:
|
|
|
|
int number_of_neighbours_computed;
|
|
int number_of_internal_nodes_visited;
|
|
int number_of_leaf_nodes_visited;
|
|
int number_of_items_visited;
|
|
|
|
private:
|
|
|
|
Distance Orthogonal_distance_instance;
|
|
|
|
FT multiplication_factor;
|
|
|
|
Query_item query_point;
|
|
|
|
int total_item_number;
|
|
|
|
FT distance_to_root;
|
|
|
|
bool search_nearest_neighbour;
|
|
|
|
FT rd;
|
|
|
|
class Priority_higher {
|
|
public:
|
|
|
|
bool search_nearest;
|
|
|
|
Priority_higher(bool search_the_nearest_neighbour)
|
|
: search_nearest(search_the_nearest_neighbour)
|
|
{}
|
|
|
|
//highest priority is smallest distance
|
|
bool
|
|
operator() (Node_with_distance* n1, Node_with_distance* n2) const
|
|
{
|
|
return (search_nearest) ? (n1->second > n2->second) : (n2->second > n1->second);
|
|
}
|
|
};
|
|
|
|
class Distance_smaller {
|
|
|
|
public:
|
|
|
|
bool search_nearest;
|
|
|
|
Distance_smaller(bool search_the_nearest_neighbour)
|
|
: search_nearest(search_the_nearest_neighbour)
|
|
{}
|
|
|
|
//highest priority is smallest distance
|
|
bool operator() (Point_with_transformed_distance* p1, Point_with_transformed_distance* p2) const
|
|
{
|
|
return (search_nearest) ? (p1->second > p2->second) : (p2->second > p1->second);
|
|
}
|
|
};
|
|
|
|
|
|
std::priority_queue<Node_with_distance*, Node_with_distance_vector,
|
|
Priority_higher> PriorityQueue;
|
|
|
|
public:
|
|
std::priority_queue<Point_with_transformed_distance*, Point_with_transformed_distance_vector,
|
|
Distance_smaller> Item_PriorityQueue;
|
|
|
|
|
|
public:
|
|
|
|
int reference_count;
|
|
|
|
|
|
|
|
// constructor
|
|
Iterator_implementation(Tree& tree, Query_item& q, const Distance& tr,
|
|
FT Eps=FT(0.0), bool search_nearest=true)
|
|
: number_of_neighbours_computed(0), number_of_internal_nodes_visited(0),
|
|
number_of_leaf_nodes_visited(0), number_of_items_visited(0),
|
|
Orthogonal_distance_instance(tr), multiplication_factor(Orthogonal_distance_instance.transformed_distance(FT(1.0)+Eps)),
|
|
query_point(q), total_item_number(tree.size()), search_nearest_neighbour(search_nearest),
|
|
PriorityQueue(Priority_higher(search_nearest)), Item_PriorityQueue(Distance_smaller(search_nearest)),
|
|
reference_count(1)
|
|
|
|
|
|
{
|
|
// if (search_nearest)
|
|
distance_to_root=
|
|
Orthogonal_distance_instance.min_distance_to_rectangle(q,
|
|
tree.bounding_box());
|
|
// else distance_to_root=
|
|
// Orthogonal_Distance_instance->max_distance_to_rectangle(q,
|
|
// tree.bounding_box());
|
|
|
|
Node_with_distance *The_Root = new Node_with_distance(tree.root(),
|
|
distance_to_root);
|
|
PriorityQueue.push(The_Root);
|
|
|
|
// rd is the distance of the top of the priority queue to q
|
|
rd=The_Root->second;
|
|
Compute_the_next_nearest_neighbour();
|
|
}
|
|
|
|
// * operator
|
|
Point_with_transformed_distance&
|
|
operator* () const
|
|
{
|
|
return *(Item_PriorityQueue.top());
|
|
}
|
|
|
|
// prefix operator
|
|
Iterator_implementation&
|
|
operator++()
|
|
{
|
|
Delete_the_current_item_top();
|
|
Compute_the_next_nearest_neighbour();
|
|
return *this;
|
|
}
|
|
|
|
// postfix operator
|
|
Point_with_transformed_distance
|
|
operator++(int)
|
|
{
|
|
Point_with_transformed_distance result = *(Item_PriorityQueue.top());
|
|
++*this;
|
|
return result;
|
|
}
|
|
|
|
// Print statistics of the general priority search process.
|
|
std::ostream&
|
|
statistics (std::ostream& s) const {
|
|
s << "Orthogonal priority search statistics:"
|
|
<< std::endl;
|
|
s << "Number of internal nodes visited:"
|
|
<< number_of_internal_nodes_visited << std::endl;
|
|
s << "Number of leaf nodes visited:"
|
|
<< number_of_leaf_nodes_visited << std::endl;
|
|
s << "Number of items visited:"
|
|
<< number_of_items_visited << std::endl;
|
|
s << "Number of neighbours computed:"
|
|
<< number_of_neighbours_computed << std::endl;
|
|
return s;
|
|
}
|
|
|
|
|
|
//destructor
|
|
~Iterator_implementation()
|
|
{
|
|
while (PriorityQueue.size()>0) {
|
|
Node_with_distance* The_top=PriorityQueue.top();
|
|
PriorityQueue.pop();
|
|
delete The_top;
|
|
}
|
|
while (Item_PriorityQueue.size()>0) {
|
|
Point_with_transformed_distance* The_top=Item_PriorityQueue.top();
|
|
Item_PriorityQueue.pop();
|
|
delete The_top;
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
void
|
|
Delete_the_current_item_top()
|
|
{
|
|
Point_with_transformed_distance* The_item_top=Item_PriorityQueue.top();
|
|
Item_PriorityQueue.pop();
|
|
delete The_item_top;
|
|
}
|
|
|
|
void
|
|
Compute_the_next_nearest_neighbour()
|
|
{
|
|
// compute the next item
|
|
bool next_neighbour_found=false;
|
|
if (!(Item_PriorityQueue.empty())) {
|
|
if (search_nearest_neighbour)
|
|
next_neighbour_found=
|
|
(multiplication_factor*rd > Item_PriorityQueue.top()->second);
|
|
else
|
|
next_neighbour_found=
|
|
(rd < multiplication_factor*Item_PriorityQueue.top()->second);
|
|
}
|
|
typename SearchTraits::Construct_cartesian_const_iterator_d construct_it;
|
|
typename SearchTraits::Cartesian_const_iterator_d query_point_it = construct_it(query_point);
|
|
// otherwise browse the tree further
|
|
while ((!next_neighbour_found) && (!PriorityQueue.empty())) {
|
|
Node_with_distance* The_node_top=PriorityQueue.top();
|
|
Node_handle N= The_node_top->first;
|
|
PriorityQueue.pop();
|
|
delete The_node_top;
|
|
FT copy_rd=rd;
|
|
while (!(N->is_leaf())) { // compute new distance
|
|
number_of_internal_nodes_visited++;
|
|
int new_cut_dim=N->cutting_dimension();
|
|
FT old_off, new_rd;
|
|
FT new_off =
|
|
*(query_point_it + new_cut_dim) -
|
|
N->cutting_value();
|
|
if (new_off < FT(0.0)) {
|
|
old_off=
|
|
*(query_point_it + new_cut_dim)-N->low_value();
|
|
if (old_off>FT(0.0)) old_off=FT(0.0);
|
|
new_rd=
|
|
Orthogonal_distance_instance.new_distance(copy_rd,old_off,new_off,new_cut_dim);
|
|
CGAL_assertion(new_rd >= copy_rd);
|
|
if (search_nearest_neighbour) {
|
|
Node_with_distance *Upper_Child =
|
|
new Node_with_distance(N->upper(), new_rd);
|
|
PriorityQueue.push(Upper_Child);
|
|
N=N->lower();
|
|
}
|
|
else {
|
|
Node_with_distance *Lower_Child =
|
|
new Node_with_distance(N->lower(), copy_rd);
|
|
PriorityQueue.push(Lower_Child);
|
|
N=N->upper();
|
|
copy_rd=new_rd;
|
|
}
|
|
|
|
}
|
|
else { // compute new distance
|
|
old_off= N->high_value() -
|
|
*(query_point_it+new_cut_dim);
|
|
if (old_off>FT(0.0)) old_off=FT(0.0);
|
|
new_rd=Orthogonal_distance_instance.new_distance(copy_rd,old_off,new_off,new_cut_dim);
|
|
CGAL_assertion(new_rd >= copy_rd);
|
|
if (search_nearest_neighbour) {
|
|
Node_with_distance *Lower_Child =
|
|
new Node_with_distance(N->lower(), new_rd);
|
|
PriorityQueue.push(Lower_Child);
|
|
N=N->upper();
|
|
}
|
|
else {
|
|
Node_with_distance *Upper_Child =
|
|
new Node_with_distance(N->upper(), copy_rd);
|
|
PriorityQueue.push(Upper_Child);
|
|
N=N->lower();
|
|
copy_rd=new_rd;
|
|
}
|
|
}
|
|
}
|
|
// n is a leaf
|
|
number_of_leaf_nodes_visited++;
|
|
if (N->size() > 0) {
|
|
for (Point_d_iterator it=N->begin(); it != N->end(); it++) {
|
|
number_of_items_visited++;
|
|
FT distance_to_query_point=
|
|
Orthogonal_distance_instance.transformed_distance(query_point,**it);
|
|
Point_with_transformed_distance *NN_Candidate=
|
|
new Point_with_transformed_distance(**it,distance_to_query_point);
|
|
Item_PriorityQueue.push(NN_Candidate);
|
|
}
|
|
// old top of PriorityQueue has been processed,
|
|
// hence update rd
|
|
|
|
if (!(PriorityQueue.empty())) {
|
|
rd = PriorityQueue.top()->second;
|
|
if (search_nearest_neighbour)
|
|
next_neighbour_found =
|
|
(multiplication_factor*rd >
|
|
Item_PriorityQueue.top()->second);
|
|
else
|
|
next_neighbour_found =
|
|
(multiplication_factor*rd <
|
|
Item_PriorityQueue.top()->second);
|
|
}
|
|
else // priority queue empty => last neighbour found
|
|
{
|
|
next_neighbour_found=true;
|
|
}
|
|
|
|
number_of_neighbours_computed++;
|
|
}
|
|
} // next_neighbour_found or priority queue is empty
|
|
// in the latter case also the item priority quee is empty
|
|
}
|
|
}; // class Iterator_implementaion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class iterator;
|
|
|
|
typedef std::vector<FT> Distance_vector;
|
|
|
|
public:
|
|
|
|
// constructor
|
|
Orthogonal_incremental_neighbor_search(Tree& tree,
|
|
Query_item& q, FT Eps = FT(0.0),
|
|
bool search_nearest=true, const Distance& tr=Distance())
|
|
: start(tree,q,tr,Eps,search_nearest),
|
|
past_the_end()
|
|
{}
|
|
|
|
iterator
|
|
begin()
|
|
{
|
|
return start;
|
|
}
|
|
|
|
iterator
|
|
end()
|
|
{
|
|
return past_the_end;
|
|
}
|
|
|
|
std::ostream&
|
|
statistics(std::ostream& s)
|
|
{
|
|
start.statistics(s);
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
|
|
class iterator {
|
|
|
|
public:
|
|
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef Point_with_transformed_distance value_type;
|
|
typedef Point_with_transformed_distance* pointer;
|
|
typedef const Point_with_transformed_distance& reference;
|
|
typedef std::size_t size_type;
|
|
typedef std::ptrdiff_t difference_type;
|
|
typedef int distance_type;
|
|
|
|
//class Iterator_implementation;
|
|
Iterator_implementation *Ptr_implementation;
|
|
|
|
|
|
public:
|
|
|
|
// default constructor
|
|
iterator()
|
|
: Ptr_implementation(0)
|
|
{}
|
|
|
|
int
|
|
the_number_of_items_visited()
|
|
{
|
|
return Ptr_implementation->number_of_items_visited;
|
|
}
|
|
|
|
// constructor
|
|
iterator(Tree& tree, Query_item& q, const Distance& tr=Distance(), FT eps=FT(0.0),
|
|
bool search_nearest=true)
|
|
: Ptr_implementation(new Iterator_implementation(tree, q, tr, eps, search_nearest))
|
|
{}
|
|
|
|
// copy constructor
|
|
iterator(const iterator& Iter)
|
|
{
|
|
Ptr_implementation = Iter.Ptr_implementation;
|
|
if (Ptr_implementation != 0) Ptr_implementation->reference_count++;
|
|
}
|
|
|
|
const Point_with_transformed_distance&
|
|
operator* () const
|
|
{
|
|
return *(*Ptr_implementation);
|
|
}
|
|
|
|
// prefix operator
|
|
iterator&
|
|
operator++()
|
|
{
|
|
++(*Ptr_implementation);
|
|
return *this;
|
|
}
|
|
|
|
// postfix operator
|
|
iterator
|
|
operator++(int)
|
|
{
|
|
iterator tmp(*this);
|
|
++(*this);
|
|
return tmp;
|
|
}
|
|
|
|
|
|
bool
|
|
operator==(const iterator& It) const
|
|
{
|
|
if (
|
|
((Ptr_implementation == 0) ||
|
|
Ptr_implementation->Item_PriorityQueue.empty()) &&
|
|
((It.Ptr_implementation == 0) ||
|
|
It.Ptr_implementation->Item_PriorityQueue.empty())
|
|
)
|
|
return true;
|
|
// else
|
|
return (Ptr_implementation == It.Ptr_implementation);
|
|
}
|
|
|
|
bool
|
|
operator!=(const iterator& It) const
|
|
{
|
|
return !(*this == It);
|
|
}
|
|
|
|
std::ostream&
|
|
statistics (std::ostream& s)
|
|
{
|
|
Ptr_implementation->statistics(s);
|
|
return s;
|
|
}
|
|
|
|
~iterator()
|
|
{
|
|
if (Ptr_implementation != 0) {
|
|
Ptr_implementation->reference_count--;
|
|
if (Ptr_implementation->reference_count==0) {
|
|
delete Ptr_implementation;
|
|
Ptr_implementation = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}; // class iterator
|
|
|
|
|
|
iterator start;
|
|
iterator past_the_end;
|
|
|
|
|
|
}; // class
|
|
|
|
template <class Traits, class Query_item, class Distance>
|
|
void swap (typename Orthogonal_incremental_neighbor_search<Traits,
|
|
Query_item, Distance>::iterator& x,
|
|
typename Orthogonal_incremental_neighbor_search<Traits,
|
|
Query_item, Distance>::iterator& y)
|
|
{
|
|
typename Orthogonal_incremental_neighbor_search<Traits,
|
|
Query_item, Distance>::iterator::Iterator_implementation
|
|
*tmp = x.Ptr_implementation;
|
|
x.Ptr_implementation = y.Ptr_implementation;
|
|
y.Ptr_implementation = tmp;
|
|
}
|
|
|
|
} // namespace CGAL
|
|
|
|
#endif // CGAL_ORTHOGONAL_INCREMENTAL_NEIGHBOR_SEARCH_H
|