mirror of https://github.com/CGAL/cgal
*** empty log message ***
This commit is contained in:
parent
a7e298e9b8
commit
fec021a5ea
|
|
@ -1,4 +1,3 @@
|
|||
%\begin{twocolumn}
|
||||
\chapter*{Bounding Box Intersection}
|
||||
|
||||
\section*{Introduction}
|
||||
|
|
@ -44,78 +43,78 @@ class.
|
|||
|
||||
There has to be an arbitrary fixed order between boxes, for example by
|
||||
assigning unique numbers to each box. If boxes are allocated on the
|
||||
heap, also the memory location could define such an order. (explain
|
||||
why?)
|
||||
heap, also the memory location could define such an order.
|
||||
|
||||
The default bounding box
|
||||
The default bounding box
|
||||
\begin{itemize}
|
||||
\item provides a standard bounding box implementation with number type and
|
||||
dimension template parameter
|
||||
|
||||
\texttt{template< class T, unsigned int DIM > struct Default\_Bbox\_d;}
|
||||
\item provides a unique numbering
|
||||
\item implements a standard bounding box
|
||||
\item is generic in terms of number type and dimension: \\
|
||||
\texttt{template< class T, unsigned int DIM > struct Default\_box\_d}
|
||||
\item provides unique numbering
|
||||
\item can be used as a base class to derive a user defined box with
|
||||
additional information, for example, an exact geometric primitive
|
||||
that was approximated with the bounding box.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\subsection*{Box Adapter}
|
||||
Bounding box access is exclusively done using a box adapter. This adapter hides the specific interface a box may have. A model of a box adapter has to provide
|
||||
Bounding box access is exclusively done using a box adapter. This adapter hides the specific interface a box may have. A model of a box adapter may look as follows:
|
||||
\begin{ccExampleCode}
|
||||
typedef ... Box
|
||||
typedef ... NumberType
|
||||
static NumberType get_lo( const Box& b, unsigned int dim )
|
||||
static NumberType get_hi( const Box& b, unsigned int dim )
|
||||
static unsigned int get_num( const Box& b )
|
||||
static unsigned int get_dim()
|
||||
template< class Box_ >
|
||||
struct Default_box_d_adapter {
|
||||
typedef Box_ Box;
|
||||
typedef typename Box::Number_type Number_type;
|
||||
|
||||
static Number_type get_lo( const Box& b, unsigned int dim )
|
||||
{ return b.get_lo( dim ); }
|
||||
|
||||
static Number_type get_hi( const Box& b, unsigned int dim )
|
||||
{ return b.get_hi( dim ); }
|
||||
|
||||
static unsigned int get_num( const Box& b )
|
||||
{ return b.get_num(); }
|
||||
|
||||
static unsigned int get_dim()
|
||||
{ return Box::get_dim(); }
|
||||
};
|
||||
\end{ccExampleCode}
|
||||
|
||||
This specific example of a box adapter is tailored for box classes that implement the default bounding box given above. If another implementation of box classes is used that (for example) does not allow access via dimension indices directly, a custom box adapter has to be written that translates dimension indices to whatever method invocations needed.
|
||||
|
||||
Box adapter requirements:
|
||||
\begin{itemize}
|
||||
\item the type of \texttt{Box} can be either a pointer or a plain structure
|
||||
\item \texttt{NumberType} must be the same type as for the
|
||||
\texttt{BoundingBox}
|
||||
\item \texttt{get\_lo} and \texttt{get\_hi} return the vector
|
||||
components of dimension \texttt{dim}, where the first dimension has
|
||||
the index zero
|
||||
\item \texttt{get\_num} returns the unique number of that box
|
||||
%\item NumberType specifies the underlying number type. \texttt{std::numeric_limits< NumberType >} must be defined (for basic types like int, double there exist defaults)
|
||||
\item The type of \texttt{Box} can be either a pointer or a plain structure.
|
||||
\item \texttt{Number\_type} must be the same type as for the \texttt{BoundingBox}. In the example above, \texttt{Number\_type} is just propagated.
|
||||
\item \texttt{get\_lo} and \texttt{get\_hi} return the vector components of dimension \texttt{dim}, where the first dimension has the index zero.
|
||||
\item \texttt{get\_num} returns the unique number of that box. Note that the return type is not constrained to \texttt{unsigned int}. Instead, it can be anything for which both \texttt{==} and \texttt{<} operators are defined.
|
||||
\end{itemize}
|
||||
|
||||
A default box adapter is given that builds up on the default bounding box:
|
||||
|
||||
\texttt{template< class BOX > struct Default\_Bbox\_d\_Adapter}
|
||||
|
||||
\subsection*{Box Traits}
|
||||
|
||||
A traits class is required to specify predicates between boxes. It
|
||||
also propagates number type, box type, dimension and some other
|
||||
parameters from the box adapter. (eigentlich muss der user nur box
|
||||
adapter anpassen. traits -> verstecken als predicates, adapter ->
|
||||
aufteilen in adapter und traits?)
|
||||
The box traits class specifies predicates between boxes. It propagates number type, box type, dimension and all other fields from the box adapter to the actual implementation of bounding box intersection. Some of the predicates it defines are:
|
||||
|
||||
\begin{itemize}
|
||||
\item defines predicates on boxes, eg.
|
||||
\begin{itemize}
|
||||
\item one interval contains the starting point of another
|
||||
\item interval starting point less than another intervals starting point
|
||||
\item open/closed box behavior decided here
|
||||
\end{itemize}
|
||||
\item box access relies on \ccc{BoxAdapter}
|
||||
\item default traits class provided. Most users probably dont want to override the default traits class.
|
||||
\item \texttt{template< class BoxAdapter, bool closed > struct Default\_Box\_Traits}
|
||||
\item \texttt{bool contains\_lo\_point(Box interval, Box point, int dim)}: regard the first box in dimension \texttt{dim} as an interval, and the second as a point being the low point of an interval. Returns true iff \texttt{interval} contains \texttt{point}.
|
||||
\item \texttt{bool is\_lo\_less\_lo(Box a, Box b, int dim)}: interval starting point less than another intervals starting point (wrt. dimension \texttt{dim})
|
||||
\item a binary predicate object \texttt{class Compare} that compares two boxes using the predicate \texttt{is\_lo\_less\_lo}.
|
||||
\end{itemize}
|
||||
|
||||
Usually, the default predicates need not be changed. Detailed requirements for box traits can be found in the reference. The default implementation of box predicates is a template with two parameters:
|
||||
|
||||
\texttt{template< class BoxAdapter, bool closed > struct Default\_Box\_Traits}
|
||||
|
||||
Box access is required inside the predefined predicates, therefore a box adapter has to be given to the traits class. The boolean constant \texttt{closed} chooses between closed and half open box interpretation.
|
||||
|
||||
|
||||
\subsection*{Usage}
|
||||
First, for each geometric primitive, a bounding box has to be computed. Any bounding box class can be used, as long as a box adapter exists for it. The bounding box sets have to be supplied to the algorithm by pairs of \ccc{Random Access Iterators}. While checking, each bounding box intersection is reported to a callback as two box references.
|
||||
First, for each geometric primitive, a bounding box has to be computed. Any bounding box class can be used, as long as a box adapter exists for it. The bounding box sets have to be supplied to the algorithm by pairs of \ccc{Random Access Iterators}. While checking, each bounding box intersection is written to an output iterator as two box references.
|
||||
|
||||
If the used box class is derived from the default bounding box (or at least has the same fields), there is no need to specify a box adapter. When no box adapter is given, it is assumed that the default box adapter can be used to access the supplied boxes.
|
||||
|
||||
|
||||
\begin{itemize}
|
||||
\item intersection algo expects input iterators, an output iterator and a traits class
|
||||
\item runtime $O(n\log^{d}n+k)$ where n is the number of boxes, d is dimension and k is number of intersections
|
||||
\item runtime $O(n\log^{d-1}n+k)$ where n is the number of boxes, d is dimension (starting with one) and k is number of intersections
|
||||
\item space requirement $O(n)$ where n is number of boxes. no new space is allocated. instead, user provided box iterators are reused.
|
||||
\item some fine-tuning required for last percent of performance (cutoff parameter)
|
||||
\item segment tree has some overhead. if callback runtime is low, better use scanning for lower numbers of boxes. \cgal uses exact arithmetic -> may slow down the computation inside the callbacks -> segment tree faster even for low numbers of boxes.
|
||||
\item segment tree has some overhead. if callback runtime is low, better use scanning for lower numbers of boxes. \cgal uses exact arithmetic. may slow down the computation inside the callbacks. segment tree faster even for low numbers of boxes.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
|
|
@ -134,7 +133,5 @@ Here, a bounding box is a cube. This saves some space, at the expense of precisi
|
|||
|
||||
\ccIncludeExampleCode{../../examples/Box_intersection_d/customadapter.cc}
|
||||
|
||||
%\end{twocolumn}
|
||||
|
||||
|
||||
%% EOF %%
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace CGAL;
|
||||
|
||||
struct Primitive {
|
||||
float f;
|
||||
Primitive() : f( drand48() ) {}
|
||||
|
|
@ -14,7 +11,7 @@ struct Primitive {
|
|||
{ return f * other->f > 0.6f; }
|
||||
};
|
||||
|
||||
struct Box : public UniqueNumbers
|
||||
struct Box : public CGAL::Box_intersection_d::Unique_numbers
|
||||
{
|
||||
Primitive *primitive;
|
||||
float lo[3], size;
|
||||
|
|
@ -25,41 +22,38 @@ struct Box : public UniqueNumbers
|
|||
}
|
||||
};
|
||||
|
||||
struct BoxAdapter {
|
||||
struct Box_traits {
|
||||
typedef ::Box Box;
|
||||
typedef float NumberType;
|
||||
typedef float Number_type;
|
||||
|
||||
static NumberType get_lo( const Box& b, unsigned int dim )
|
||||
static Number_type get_lo( const Box& b, unsigned int dim )
|
||||
{ return b.lo[ dim ]; }
|
||||
|
||||
static NumberType get_hi( const Box& b, unsigned int dim )
|
||||
static Number_type get_hi( const Box& b, unsigned int dim )
|
||||
{ return b.lo[ dim ] + b.size; }
|
||||
|
||||
static unsigned int get_num( const Box& b )
|
||||
{ return b.num(); }
|
||||
{ return b.get_num(); }
|
||||
|
||||
static unsigned int get_dim() { return 3; }
|
||||
};
|
||||
|
||||
typedef vector< Box > BoxContainer;
|
||||
typedef Default_Box_Traits< BoxAdapter, true > Traits;
|
||||
|
||||
void fill_boxes( unsigned int n, BoxContainer &boxes ) {
|
||||
void fill_boxes( unsigned int n, std::vector<Box> &boxes ) {
|
||||
for( unsigned int i = 0; i < n; ++i )
|
||||
boxes.push_back( Box( new Primitive() ) );
|
||||
}
|
||||
|
||||
void callback( const Box &a, const Box &b ) {
|
||||
if( a.primitive->intersect( b.primitive ) )
|
||||
cout << "intersection between box "
|
||||
<< a.num() << " and " << b.num() << endl;
|
||||
std::cout << "intersection between box "
|
||||
<< a.get_num() << " and " << b.get_num() << std::endl;
|
||||
};
|
||||
|
||||
int main() {
|
||||
BoxContainer boxes1, boxes2;
|
||||
std::vector<Box> boxes1, boxes2;
|
||||
fill_boxes( 100, boxes1 );
|
||||
fill_boxes( 100, boxes2 );
|
||||
segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback, Traits() );
|
||||
box_intersection_d( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback, Box_traits() );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace CGAL;
|
||||
|
||||
struct Primitive {
|
||||
double f;
|
||||
Primitive() : f( drand48() ) {}
|
||||
|
|
@ -14,37 +11,33 @@ struct Primitive {
|
|||
{ return f * other->f > 0.6; }
|
||||
};
|
||||
|
||||
struct Box : public Default_Bbox_d< double, 3 >
|
||||
struct Box : public CGAL::Default_box_d< double, 3 >
|
||||
{
|
||||
Primitive *primitive;
|
||||
Box( Primitive *p ) : primitive( p ) {
|
||||
for( unsigned int d = 0; d < 3; ++d ) {
|
||||
_lo[d] = 10.0 * drand48();
|
||||
_hi[d] = _lo[d] + 1.0 + drand48();
|
||||
lo[d] = 10.0 * drand48();
|
||||
hi[d] = lo[d] + 1.0 + drand48();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef vector< Box > BoxContainer;
|
||||
typedef Default_Bbox_d_Adapter< Box > BoxAdapter;
|
||||
typedef Default_Box_Traits< BoxAdapter, true > Traits;
|
||||
|
||||
void fill_boxes( unsigned int n, BoxContainer &boxes ) {
|
||||
void fill_boxes( unsigned int n, std::vector< Box >& boxes ) {
|
||||
for( unsigned int i = 0; i < n; ++i )
|
||||
boxes.push_back( Box( new Primitive() ) );
|
||||
}
|
||||
|
||||
void callback( const Box &a, const Box &b ) {
|
||||
if( a.primitive->intersect( b.primitive ) )
|
||||
cout << "intersection between box "
|
||||
<< a.num() << " and " << b.num() << endl;
|
||||
std::cout << "intersection between box "
|
||||
<< a.get_num() << " and " << b.get_num() << std::endl;
|
||||
};
|
||||
|
||||
int main() {
|
||||
BoxContainer boxes1, boxes2;
|
||||
std::vector< Box > boxes1, boxes2;
|
||||
fill_boxes( 100, boxes1 );
|
||||
fill_boxes( 100, boxes2 );
|
||||
segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback, Traits() );
|
||||
box_intersection_d( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,9 @@
|
|||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace CGAL;
|
||||
typedef CGAL::Default_box_d< double, 3 > Box;
|
||||
|
||||
typedef Default_Bbox_d< double, 3 > Box;
|
||||
typedef Default_Bbox_d_Adapter< Box > BoxAdapter;
|
||||
typedef vector< Box > BoxContainer;
|
||||
typedef Default_Box_Traits< BoxAdapter, true > Traits;
|
||||
|
||||
void fill_boxes( unsigned int n, BoxContainer& boxes ) {
|
||||
void fill_boxes( unsigned int n, std::vector<Box>& boxes ) {
|
||||
double lo[3], hi[3];
|
||||
for( unsigned int i = 0; i < n; ++i ) {
|
||||
for( unsigned int d = 0; d < 3; ++d ) {
|
||||
|
|
@ -24,15 +18,14 @@ void fill_boxes( unsigned int n, BoxContainer& boxes ) {
|
|||
}
|
||||
|
||||
void callback( const Box& a, const Box& b ) {
|
||||
cout << "intersection between box "
|
||||
<< a.num() << " and " << b.num() << endl;
|
||||
std::cout << "intersection between box "
|
||||
<< a.get_num() << " and " << b.get_num() << std::endl;
|
||||
};
|
||||
|
||||
int main() {
|
||||
BoxContainer boxes1, boxes2;
|
||||
fill_boxes( 100, boxes1 );
|
||||
fill_boxes( 100, boxes2 );
|
||||
segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback, Traits() );
|
||||
std::vector<Box> a, b;
|
||||
fill_boxes( 100, a );
|
||||
fill_boxes( 100, b );
|
||||
box_intersection_d( a.begin(), a.end(), b.begin(), b.end(), callback );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef CGAL_BOX_INTERSECTION_D_H
|
||||
#define CGAL_BOX_INTERSECTION_D_H
|
||||
|
||||
#include <CGAL/Box_intersection_d/segment_tree.h>
|
||||
#include <CGAL/Box_intersection_d/box_traits.h>
|
||||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
template< class RandomAccessIter, class Callback >
|
||||
void box_intersection_d( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback,
|
||||
unsigned int cutoff = 10,
|
||||
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE,
|
||||
Box_intersection_d::Topology topology = Box_intersection_d::CLOSED )
|
||||
{
|
||||
typedef typename RandomAccessIter::value_type Box_type;
|
||||
/*typedef typename Box_intersection_d::Select_box_traits< Box_type >::
|
||||
Box_traits Box_traits;*/
|
||||
typedef Default_box_d_traits< Box_type > Box_traits;
|
||||
|
||||
box_intersection_d( p_begin, p_end,
|
||||
i_begin, i_end, callback, Box_traits(), cutoff, setting );
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback, class BoxTraits >
|
||||
void box_intersection_d( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback,
|
||||
BoxTraits box_traits,
|
||||
unsigned int cutoff = 10,
|
||||
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE,
|
||||
Box_intersection_d::Topology topology = Box_intersection_d::CLOSED )
|
||||
{
|
||||
if (topology == Box_intersection_d::CLOSED ) {
|
||||
typedef Default_box_predicate_traits< BoxTraits, true > Traits;
|
||||
box_intersection_d_custom( p_begin, p_end, i_begin, i_end, callback, Traits(), cutoff, setting );
|
||||
} else {
|
||||
typedef Default_box_predicate_traits< BoxTraits, false > Traits;
|
||||
box_intersection_d_custom( p_begin, p_end, i_begin, i_end, callback, Traits(), cutoff, setting );
|
||||
}
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback, class BoxPredicateTraits >
|
||||
void box_intersection_d_custom(
|
||||
RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback,
|
||||
BoxPredicateTraits traits,
|
||||
unsigned int cutoff = 10,
|
||||
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE
|
||||
//typename BoxPredicateTraits::Interval_Spanning_Predicate p = typename BoxPredicateTraits::Interval_Spanning_Predicate()
|
||||
)
|
||||
{
|
||||
typedef BoxPredicateTraits Traits;
|
||||
typedef typename Traits::Number_type NT;
|
||||
const unsigned int dim = Traits::get_dim() - 1;
|
||||
const NT inf = workaround::numeric_limits< NT >::inf();
|
||||
const NT sup = workaround::numeric_limits< NT >::sup();
|
||||
|
||||
segment_tree( p_begin, p_end, i_begin, i_end,
|
||||
inf, sup, callback, traits, cutoff, dim, true );
|
||||
if( setting == Box_intersection_d::BIPARTITE )
|
||||
segment_tree( i_begin, i_end, p_begin, p_end,
|
||||
inf, sup, callback, traits, cutoff, dim, false );
|
||||
}
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -9,19 +9,17 @@ CGAL_BEGIN_NAMESPACE
|
|||
template< class RandomAccessIter, class Callback, class Traits >
|
||||
void all_pairs( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback, Traits traits, unsigned int last_dim,
|
||||
bool in_order = true )
|
||||
Callback& callback, Traits traits, unsigned int last_dim )
|
||||
{
|
||||
for( RandomAccessIter p = p_begin; p != p_end; ++p ) {
|
||||
for( RandomAccessIter i = i_begin; i != i_end; ++i ) {
|
||||
if (Traits::get_num(*p) >= Traits::get_num(*i) )
|
||||
continue;
|
||||
for( unsigned int dim = 0; dim <= last_dim; ++dim )
|
||||
if( !Traits::does_intersect( *p, *i, dim ) )
|
||||
goto no_intersection;
|
||||
if( in_order )
|
||||
callback( *p, *i );
|
||||
else
|
||||
callback( *i, *p );
|
||||
no_intersection:
|
||||
goto no_intersection1;
|
||||
callback( *p, *i );
|
||||
no_intersection1:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,130 +9,147 @@
|
|||
|
||||
CGAL_BEGIN_NAMESPACE
|
||||
|
||||
// trivial default implementations
|
||||
class UniqueNumbers {
|
||||
static unsigned int n;
|
||||
unsigned int i;
|
||||
public:
|
||||
UniqueNumbers() : i( n++ ) {}
|
||||
unsigned int num() const { return i; }
|
||||
};
|
||||
unsigned int UniqueNumbers::n = 0;
|
||||
struct Box_intersection_d {
|
||||
enum Setting { COMPLETE, BIPARTITE };
|
||||
enum Topology { HALF_OPEN, CLOSED };
|
||||
|
||||
template< class T, unsigned int DIM >
|
||||
struct Default_Bbox_d : public UniqueNumbers {
|
||||
typedef T NumberType;
|
||||
Default_Bbox_d() { init(); }
|
||||
Default_Bbox_d( T l[DIM], T h[dim] ) {
|
||||
std::copy( l, l + DIM, _lo );
|
||||
std::copy( h, h + DIM, _hi );
|
||||
|
||||
struct Unique_numbers {
|
||||
Unique_numbers() : i(n++) {}
|
||||
unsigned int get_num() const { return i; }
|
||||
private:
|
||||
static unsigned int n;
|
||||
unsigned int i;
|
||||
};
|
||||
/*
|
||||
template< class Box >
|
||||
struct Select_box_traits {
|
||||
typedef char True;
|
||||
typedef struct { char a[2]; } False;
|
||||
|
||||
template< class T >
|
||||
True is_derived_from_base( typename
|
||||
T::Unique_default_box_d_type_tag_which_does_not_appear_elsewhere=0);
|
||||
template< class T >
|
||||
False is_derived_from_base(...);
|
||||
|
||||
template< bool, typename A, typename B >
|
||||
struct IF { typedef A R; };
|
||||
template<typename A, typename B>
|
||||
struct IF< false, A, B > { typedef B R; };
|
||||
|
||||
typedef typename IF
|
||||
< sizeof(is_derived_from_base<Box>()) == sizeof(True),
|
||||
Default_box_d_traits< Box >,
|
||||
void
|
||||
>::R Box_traits;
|
||||
};*/
|
||||
|
||||
};
|
||||
|
||||
unsigned int Box_intersection_d::Unique_numbers::n = 0;
|
||||
|
||||
template< class NT, unsigned int N >
|
||||
struct Default_box_d : public Box_intersection_d::Unique_numbers {
|
||||
typedef int Unique_default_box_d_type_tag_which_does_not_appear_elsewhere;
|
||||
typedef NT Number_type;
|
||||
Default_box_d() { init(); }
|
||||
Default_box_d( NT l[N], NT h[N] ) {
|
||||
std::copy( l, l + N, lo );
|
||||
std::copy( h, h + N, hi );
|
||||
}
|
||||
|
||||
void init ( bool complete = false ) {
|
||||
T inf = workaround::numeric_limits< T >::inf();
|
||||
T sup = workaround::numeric_limits< T >::sup();
|
||||
NT inf = workaround::numeric_limits< NT >::inf();
|
||||
NT sup = workaround::numeric_limits< NT >::sup();
|
||||
if( !complete )
|
||||
std::swap( inf, sup );
|
||||
std::fill( _lo, _lo + DIM, inf );
|
||||
std::fill( _hi, _lo + DIM, sup );
|
||||
std::fill( lo, lo + N, inf );
|
||||
std::fill( hi, hi + N, sup );
|
||||
}
|
||||
|
||||
void extend( T p[ DIM ] ) {
|
||||
for( unsigned int dim = 0; dim < DIM; ++dim ) {
|
||||
_lo [ DIM ] = std::min( _lo[ DIM ], p[ DIM ] );
|
||||
_hi [ DIM ] = std::max( _hi[ DIM ], p[ DIM ] );
|
||||
void extend( NT p[ N ] ) {
|
||||
for( unsigned int dim = 0; dim < N; ++dim ) {
|
||||
lo[dim] = std::min( lo[dim], p[dim] );
|
||||
hi[dim] = std::max( hi[dim], p[dim] );
|
||||
}
|
||||
}
|
||||
|
||||
T lo( unsigned int dim ) const { return _lo[dim]; }
|
||||
T hi( unsigned int dim ) const { return _hi[dim]; }
|
||||
static unsigned int get_dim() { return DIM; }
|
||||
NT get_lo( unsigned int dim ) const { return lo[dim]; }
|
||||
NT get_hi( unsigned int dim ) const { return hi[dim]; }
|
||||
static unsigned int get_dim() { return N; }
|
||||
protected:
|
||||
T _lo[ DIM ], _hi[ DIM ];
|
||||
NT lo[N], hi[N];
|
||||
};
|
||||
|
||||
template< class BOX >
|
||||
struct Default_Bbox_d_Adapter {
|
||||
typedef BOX Box;
|
||||
typedef typename BOX::NumberType NumberType;
|
||||
|
||||
static NumberType get_lo( const Box& b, unsigned int dim )
|
||||
{ return b.lo( dim ); }
|
||||
template< class Box_ >
|
||||
struct Default_box_d_traits {
|
||||
typedef Box_ Box;
|
||||
typedef typename Box::Number_type Number_type;
|
||||
|
||||
static NumberType get_hi( const Box& b, unsigned int dim )
|
||||
{ return b.hi( dim ); }
|
||||
static Number_type get_lo( const Box& b, unsigned int dim )
|
||||
{ return b.get_lo( dim ); }
|
||||
|
||||
static Number_type get_hi( const Box& b, unsigned int dim )
|
||||
{ return b.get_hi( dim ); }
|
||||
|
||||
static unsigned int get_num( const Box& b )
|
||||
{ return b.num(); }
|
||||
{ return b.get_num(); }
|
||||
|
||||
static unsigned int get_dim() { return Box::get_dim(); }
|
||||
};
|
||||
|
||||
template< class BoxTraits, bool closed >
|
||||
struct Default_box_predicate_traits : public BoxTraits {
|
||||
typedef typename BoxTraits::Box Box;
|
||||
typedef typename BoxTraits::Number_type Number_type;
|
||||
|
||||
// BoxAdapter has to provide following static members:
|
||||
// NumberType get_lo( Box, int dim )
|
||||
// NumberType get_hi( Box, int dim )
|
||||
// unsigned int get_num( Box )
|
||||
// Box may be of type immediate, reference, or pointer
|
||||
template<bool b> struct type_from_bool {};
|
||||
|
||||
template <bool b>
|
||||
struct Type_from_bool {};
|
||||
|
||||
template< class BoxAdapter, bool closed >
|
||||
struct Default_Box_Traits : public BoxAdapter {
|
||||
typedef typename BoxAdapter::Box Box;
|
||||
typedef typename BoxAdapter::NumberType NumberType;
|
||||
typedef Default_Box_Traits< BoxAdapter, closed > Traits;
|
||||
|
||||
static unsigned int cutoff;
|
||||
|
||||
static bool hi_greater ( NumberType hi, NumberType val,
|
||||
Type_from_bool<true> )
|
||||
static bool hi_greater ( Number_type hi, Number_type val, type_from_bool<true> b )
|
||||
{ return hi >= val; }
|
||||
static bool hi_greater ( Number_type hi, Number_type val, type_from_bool<false> b )
|
||||
{ return hi > val; }
|
||||
static bool hi_greater ( Number_type hi, Number_type val )
|
||||
{ return hi_greater(hi, val, type_from_bool<closed>()); }
|
||||
|
||||
static bool hi_greater ( NumberType hi, NumberType val,
|
||||
Type_from_bool<false> )
|
||||
{ return hi > val; }
|
||||
|
||||
static bool hi_greater ( NumberType hi, NumberType val )
|
||||
{ return hi_greater( hi, val, Type_from_bool<closed>()); }
|
||||
|
||||
// cmp dim = \a b -> islolesslo a b dim
|
||||
// cmp dim a b = islolesslo a b dim
|
||||
class Compare : public std::binary_function< Box, Box, bool > {
|
||||
unsigned int dim;
|
||||
public:
|
||||
Compare( unsigned int dim ) : dim( dim ) {}
|
||||
bool operator()( const Box& a, const Box& b ) const
|
||||
{ return Traits::is_lo_less_lo( a, b, dim ); }
|
||||
{ return is_lo_less_lo( a, b, dim ); }
|
||||
};
|
||||
|
||||
// loless val dim = \box -> getlo box dim < val
|
||||
// loless val dim box = getlo box dim < val
|
||||
class Lo_Less : public std::unary_function< Box, bool > {
|
||||
NumberType value;
|
||||
Number_type value;
|
||||
unsigned int dim;
|
||||
public:
|
||||
Lo_Less( NumberType value, unsigned int dim )
|
||||
Lo_Less( Number_type value, unsigned int dim )
|
||||
: value( value ), dim( dim ) {}
|
||||
bool operator() ( const Box& box ) const
|
||||
{ return get_lo( box, dim ) < value; }
|
||||
};
|
||||
|
||||
class Hi_Greater : public std::unary_function< Box, bool > {
|
||||
NumberType value;
|
||||
Number_type value;
|
||||
unsigned int dim;
|
||||
public:
|
||||
Hi_Greater( NumberType value, unsigned int dim )
|
||||
Hi_Greater( Number_type value, unsigned int dim )
|
||||
: value( value ), dim( dim ) {}
|
||||
bool operator() ( const Box& box ) const
|
||||
{ return hi_greater( get_hi( box, dim ), value); }
|
||||
};
|
||||
|
||||
// p lo hi dim = \box -> getlo box dim < lo && gethi box dim > hi
|
||||
// p lo hi dim box = getlo box dim < lo && gethi box dim > hi
|
||||
class Interval_Spanning_Predicate : public std::unary_function<Box,bool> {
|
||||
NumberType lo, hi;
|
||||
Number_type lo, hi;
|
||||
unsigned int dim;
|
||||
public:
|
||||
Interval_Spanning_Predicate( NumberType lo, NumberType hi,
|
||||
Interval_Spanning_Predicate( Number_type lo, Number_type hi,
|
||||
unsigned int dim )
|
||||
: lo( lo ), hi( hi ), dim( dim ) {}
|
||||
// returns true <=> box spans [lo,hi) in dimension dim
|
||||
|
|
@ -152,16 +169,9 @@ struct Default_Box_Traits : public BoxAdapter {
|
|||
{ return is_lo_less_hi( a, b, dim ) && is_lo_less_hi( b, a, dim ); }
|
||||
|
||||
static bool contains_lo_point(const Box& a, const Box& b, unsigned int dim)
|
||||
{ return !is_lo_less_lo( b, a, dim ) && is_lo_less_hi( b, a, dim ); }
|
||||
|
||||
static unsigned int get_cutoff()
|
||||
{ return cutoff; }
|
||||
{ return is_lo_less_lo( a, b, dim ) && is_lo_less_hi( b, a, dim ); }
|
||||
};
|
||||
|
||||
template< class BoxAdapter, bool closed >
|
||||
unsigned int
|
||||
Default_Box_Traits<BoxAdapter,closed>::cutoff = 3000;
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,30 +20,31 @@ CGAL_BEGIN_NAMESPACE
|
|||
|
||||
#define BOX_INTERSECTION_DEBUG 0
|
||||
|
||||
template< class RandomAccessIter, class Traits >
|
||||
template< class RandomAccessIter, class Predicate_traits >
|
||||
RandomAccessIter
|
||||
median_of_three( RandomAccessIter a, RandomAccessIter b, RandomAccessIter c,
|
||||
Traits traits, unsigned int dim )
|
||||
Predicate_traits traits, unsigned int dim )
|
||||
{
|
||||
if( Traits::is_lo_less_lo( *a, *b, dim ) )
|
||||
if( Traits::is_lo_less_lo( *b, *c, dim ) )
|
||||
|
||||
if( Predicate_traits::is_lo_less_lo( *a, *b, dim ) )
|
||||
if( Predicate_traits::is_lo_less_lo( *b, *c, dim ) )
|
||||
return b;
|
||||
else if( Traits::is_lo_less_lo( *a, *c, dim ) )
|
||||
else if( Predicate_traits::is_lo_less_lo( *a, *c, dim ) )
|
||||
return c;
|
||||
else
|
||||
return a;
|
||||
else if( Traits::is_lo_less_lo( *a, *c, dim ) )
|
||||
else if( Predicate_traits::is_lo_less_lo( *a, *c, dim ) )
|
||||
return a;
|
||||
else if( Traits::is_lo_less_lo( *b, *c, dim ) )
|
||||
else if( Predicate_traits::is_lo_less_lo( *b, *c, dim ) )
|
||||
return c;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Traits >
|
||||
template< class RandomAccessIter, class Predicate_traits >
|
||||
RandomAccessIter
|
||||
iterative_radon( RandomAccessIter begin, RandomAccessIter end,
|
||||
Traits traits, unsigned int dim, int num_levels )
|
||||
Predicate_traits traits, unsigned int dim, int num_levels )
|
||||
{
|
||||
if( num_levels < 0 )
|
||||
return begin + lrand48() % std::distance( begin, end );
|
||||
|
|
@ -58,17 +59,17 @@ iterative_radon( RandomAccessIter begin, RandomAccessIter end,
|
|||
// returns iterator for first element in [begin,end) which does not satisfy
|
||||
// the Split_Points_Predicate: [begin,mid) contains only points strictly less
|
||||
// than mi. so, elements from [mid,end) are equal or higher than mi.
|
||||
template< class RandomAccessIter, class Traits, class T >
|
||||
template< class RandomAccessIter, class Predicate_traits, class T >
|
||||
RandomAccessIter
|
||||
split_points( RandomAccessIter begin, RandomAccessIter end, Traits traits,
|
||||
split_points( RandomAccessIter begin, RandomAccessIter end, Predicate_traits traits,
|
||||
int dim, T& mi )
|
||||
{
|
||||
// magic formula
|
||||
int levels = (int)(.91*log(((double)std::distance(begin,end))/137.0)+1);
|
||||
levels = (levels <= 0) ? 1 : levels;
|
||||
RandomAccessIter it = iterative_radon( begin, end, traits, dim, levels );
|
||||
mi = Traits::get_lo( *it, dim );
|
||||
return std::partition( begin, end, typename Traits::Lo_Less( mi, dim ) );
|
||||
mi = Predicate_traits::get_lo( *it, dim );
|
||||
return std::partition( begin, end, typename Predicate_traits::Lo_Less( mi, dim ) );
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -121,17 +122,17 @@ struct Counter {
|
|||
~Counter() { --value; }
|
||||
};
|
||||
|
||||
template< class RandomAccessIter, class Callback, class T, class Traits >
|
||||
template< class RandomAccessIter, class Callback, class T, class Predicate_traits >
|
||||
void segment_tree( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
T lo, T hi,
|
||||
Callback& callback, Traits traits, unsigned int dim,
|
||||
bool in_order )
|
||||
Callback& callback, Predicate_traits traits, unsigned int cutoff,
|
||||
unsigned int dim, bool in_order )
|
||||
{
|
||||
typedef typename Traits::Box Box;
|
||||
typedef typename Traits::Interval_Spanning_Predicate Spanning;
|
||||
typedef typename Traits::Lo_Less Lo_Less;
|
||||
typedef typename Traits::Hi_Greater Hi_Greater;
|
||||
typedef typename Predicate_traits::Box Box;
|
||||
typedef typename Predicate_traits::Interval_Spanning_Predicate Spanning;
|
||||
typedef typename Predicate_traits::Lo_Less Lo_Less;
|
||||
typedef typename Predicate_traits::Hi_Greater Hi_Greater;
|
||||
|
||||
const T inf = workaround::numeric_limits< T >::inf();
|
||||
const T sup = workaround::numeric_limits< T >::sup();
|
||||
|
|
@ -171,8 +172,8 @@ void segment_tree( RandomAccessIter p_begin, RandomAccessIter p_end,
|
|||
return;
|
||||
}
|
||||
|
||||
if( (unsigned int)std::distance( p_begin, p_end ) < Traits::get_cutoff() ||
|
||||
(unsigned int)std::distance( i_begin, i_end ) < Traits::get_cutoff() )
|
||||
if( (unsigned int)std::distance( p_begin, p_end ) < cutoff ||
|
||||
(unsigned int)std::distance( i_begin, i_end ) < cutoff )
|
||||
{
|
||||
DUMP( "scanning ... " << std::endl )
|
||||
modified_two_way_scan( p_begin, p_end, i_begin, i_end,
|
||||
|
|
@ -187,9 +188,9 @@ void segment_tree( RandomAccessIter p_begin, RandomAccessIter p_end,
|
|||
DUMP( "checking spanning intervals ... " << std::endl )
|
||||
// make two calls for roots of segment tree at next level.
|
||||
segment_tree( p_begin, p_end, i_begin, i_span_end, inf, sup,
|
||||
callback, traits, dim - 1, in_order );
|
||||
callback, traits, cutoff, dim - 1, in_order );
|
||||
segment_tree( i_begin, i_span_end, p_begin, p_end, inf, sup,
|
||||
callback, traits, dim - 1, !in_order );
|
||||
callback, traits, cutoff, dim - 1, !in_order );
|
||||
}
|
||||
|
||||
T mi;
|
||||
|
|
@ -210,30 +211,13 @@ void segment_tree( RandomAccessIter p_begin, RandomAccessIter p_end,
|
|||
i_mid = std::partition( i_span_end, i_end, Lo_Less( mi, dim ) );
|
||||
DUMP("->left" << std::endl )
|
||||
segment_tree( p_begin, p_mid, i_span_end, i_mid, lo, mi,
|
||||
callback, traits, dim, in_order );
|
||||
callback, traits, cutoff, dim, in_order );
|
||||
// separate right intervals.
|
||||
// right intervals have a high point strictly higher than mi
|
||||
i_mid = std::partition( i_span_end, i_end, Hi_Greater( mi, dim ) );
|
||||
DUMP("->right"<< std::endl )
|
||||
segment_tree( p_mid, p_end, i_span_end, i_mid, mi, hi,
|
||||
callback, traits, dim, in_order );
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback, class Traits >
|
||||
void segment_tree( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback, Traits traits, bool bipartite = true )
|
||||
{
|
||||
typedef typename Traits::NumberType T;
|
||||
const unsigned int dim = Traits::get_dim() - 1;
|
||||
const T inf = workaround::numeric_limits< T >::inf();
|
||||
const T sup = workaround::numeric_limits< T >::sup();
|
||||
|
||||
segment_tree( p_begin, p_end, i_begin, i_end,
|
||||
inf, sup, callback, traits, dim, true );
|
||||
if( bipartite )
|
||||
segment_tree( i_begin, i_end, p_begin, p_end,
|
||||
inf, sup, callback, traits, dim, false );
|
||||
callback, traits, cutoff, dim, in_order );
|
||||
}
|
||||
|
||||
CGAL_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
//#include "Box_intersection_d.h"
|
||||
#include <CGAL/Box_intersection_d/box_traits.h>
|
||||
// enable invariant checking
|
||||
#define SEGMENT_TREE_CHECK_INVARIANTS 1
|
||||
#include <CGAL/Box_intersection_d.h>
|
||||
|
||||
#include <CGAL/Box_intersection_d/all_pairs.h>
|
||||
#include <CGAL/Box_intersection_d/one_way_scan.h>
|
||||
|
||||
// enable invariant checking
|
||||
#define SEGMENT_TREE_CHECK_INVARIANTS 1
|
||||
#include <CGAL/Box_intersection_d/segment_tree.h>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -19,23 +16,21 @@
|
|||
#include <cmath>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef CGAL::Default_Bbox_d< int, 3 > Box;
|
||||
typedef CGAL::Default_Bbox_d_Adapter< Box > BoxAdapter;
|
||||
typedef CGAL::Default_Box_Traits< BoxAdapter, true > Traits;
|
||||
typedef vector< Box > BoxContainer;
|
||||
typedef pair< Box, Box > BoxPair;
|
||||
typedef vector< BoxPair > ResultContainer;
|
||||
typedef CGAL::Default_box_d< int, 3 > Box;
|
||||
typedef CGAL::Default_box_d_traits< Box > Box_adapter;
|
||||
typedef CGAL::Default_box_predicate_traits< Box_adapter, true > Traits;
|
||||
typedef std::vector< Box > Box_container;
|
||||
typedef std::pair< Box, Box > Box_pair;
|
||||
typedef std::vector< Box_pair > Result_container;
|
||||
|
||||
|
||||
static void readBoxesFromFile( FILE *infile, BoxContainer& boxes )
|
||||
static void readBoxesFromFile( FILE *infile, Box_container& boxes )
|
||||
{
|
||||
int numBoxes, numDim;
|
||||
int boxNum, dim;
|
||||
|
||||
fscanf(infile, "%d %d\n", &numBoxes, &numDim);
|
||||
vector< int > lo( numDim ), hi( numDim );
|
||||
std::vector< int > lo( numDim ), hi( numDim );
|
||||
/* Read boxes */
|
||||
for(boxNum = 0; boxNum < numBoxes; boxNum++) {
|
||||
for(dim = 0; dim < numDim; dim++)
|
||||
|
|
@ -48,7 +43,7 @@ static void readBoxesFromFile( FILE *infile, BoxContainer& boxes )
|
|||
static void assertIntersection( const Box& a, const Box& b ) {
|
||||
for( unsigned int dim = 0; dim < 3; ++dim ) {
|
||||
if( Traits::does_intersect( a, b, dim ) == false ) {
|
||||
cout << "does not intersect!" << endl;
|
||||
std::cout << "does not intersect!" << std::endl;
|
||||
//cout << a << endl << b << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
|
@ -56,14 +51,14 @@ static void assertIntersection( const Box& a, const Box& b ) {
|
|||
}
|
||||
|
||||
template< class Storage >
|
||||
struct StorageCallback {
|
||||
struct Storage_callback {
|
||||
unsigned int counter;
|
||||
Storage& storage;
|
||||
StorageCallback( Storage& storage ) : counter( 0 ), storage( storage ) {}
|
||||
Storage_callback( Storage& storage ) : counter( 0 ), storage( storage ) {}
|
||||
void operator()( const Box& a, const Box& b ) {
|
||||
assertIntersection( a, b );
|
||||
++counter;
|
||||
storage.push_back( make_pair( a, b ) );
|
||||
storage.push_back( std::make_pair( a, b ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +72,7 @@ operator==( const Box& a, const Box& b ) {
|
|||
}
|
||||
|
||||
bool
|
||||
operator==( const BoxPair& a, const BoxPair& b ) {
|
||||
operator==( const Box_pair& a, const Box_pair& b ) {
|
||||
return( a.first == b.first && a.second == b.second ||
|
||||
a.first == b.second && a.second == b.first );
|
||||
}
|
||||
|
|
@ -109,8 +104,8 @@ unsigned int countDuplicates( Storage& storage ) {
|
|||
static void
|
||||
test( const char* filename1, const char* filename2 )
|
||||
{
|
||||
BoxContainer boxes1, boxes2;
|
||||
ResultContainer result_all_pairs, result_tree;
|
||||
Box_container boxes1, boxes2;
|
||||
Result_container result_all_pairs, result_tree;
|
||||
FILE *infile1, *infile2;
|
||||
infile1 = fopen( filename1, "r");
|
||||
infile2 = fopen( filename2, "r");
|
||||
|
|
@ -118,54 +113,54 @@ test( const char* filename1, const char* filename2 )
|
|||
readBoxesFromFile( infile1, boxes1 );
|
||||
readBoxesFromFile( infile2, boxes2 );
|
||||
|
||||
cout << endl;
|
||||
StorageCallback< ResultContainer >
|
||||
std::cout << std::endl;
|
||||
Storage_callback< Result_container >
|
||||
callback1( result_all_pairs ),
|
||||
callback2( result_tree );
|
||||
|
||||
cout << "all pairs ...... " << flush;
|
||||
std::cout << "all pairs ...... " << std::flush;
|
||||
Timer timer;
|
||||
timer.start();
|
||||
CGAL::all_pairs( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback1, Traits(), 2 );
|
||||
timer.stop();
|
||||
cout << "got " << callback1.counter << " intersections in "
|
||||
<< timer.t << " seconds." << endl;
|
||||
std::cout << "got " << callback1.counter << " intersections in "
|
||||
<< timer.t << " seconds." << std::endl;
|
||||
|
||||
|
||||
cout << "one way scan ...... " << flush;
|
||||
std::cout << "one way scan ...... " << std::flush;
|
||||
timer.start();
|
||||
CGAL::one_way_scan( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits(), 2 );
|
||||
CGAL::one_way_scan( boxes2.begin(), boxes2.end(),
|
||||
boxes1.begin(), boxes1.end(), callback2, Traits(), 2 );
|
||||
timer.stop();
|
||||
cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." << endl;
|
||||
std::cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." << std::endl;
|
||||
callback2.counter = 0;
|
||||
result_tree.clear();
|
||||
|
||||
cout << "segment tree ... " << flush;
|
||||
std::cout << "segment tree ... " << std::flush;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
unsigned int n = boxes1.size();
|
||||
Traits::cutoff = n < 2000 ? 6 : n / 100;
|
||||
CGAL::segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits() );
|
||||
const unsigned int n = boxes1.size();
|
||||
const unsigned int cutoff = n < 2000 ? 6 : n / 100;
|
||||
CGAL::box_intersection_d_custom( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits(), cutoff );
|
||||
timer.stop();
|
||||
cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." <<endl;
|
||||
std::cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." << std::endl;
|
||||
|
||||
if( callback1.counter != callback2.counter ) {
|
||||
unsigned int missing = countMissingItems( result_all_pairs,
|
||||
result_tree );
|
||||
unsigned int duplicates = countDuplicates( result_tree );
|
||||
cout << "!! failed !! " << missing << " missing and "
|
||||
std::cout << "!! failed !! " << missing << " missing and "
|
||||
<< duplicates << " duplicate intersections in tree result."
|
||||
<< endl;
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
cout << "--- passed --- " << endl;
|
||||
std::cout << "--- passed --- " << std::endl;
|
||||
fclose( infile1 );
|
||||
fclose( infile2 );
|
||||
}
|
||||
|
|
@ -173,9 +168,9 @@ test( const char* filename1, const char* filename2 )
|
|||
|
||||
int main( int argc, char ** argv ) {
|
||||
for( unsigned int n = 1; n <= 6; ++n ) {
|
||||
stringstream file1, file2;
|
||||
file1 << "data/test" << n << "_set1.box" << ends;
|
||||
file2 << "data/test" << n << "_set2.box" << ends;
|
||||
std::stringstream file1, file2;
|
||||
file1 << "data/test" << n << "_set1.box" << std::ends;
|
||||
file2 << "data/test" << n << "_set2.box" << std::ends;
|
||||
test( file1.str().c_str(), file2.str().c_str() );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include <CGAL/Box_intersection_d/box_traits.h>
|
||||
#include <CGAL/Box_intersection_d/one_way_scan.h>
|
||||
#include <CGAL/Box_intersection_d/all_pairs.h>
|
||||
// enable invariant checking
|
||||
#define SEGMENT_TREE_CHECK_INVARIANTS 1
|
||||
#include <CGAL/Box_intersection_d/segment_tree.h>
|
||||
#include <CGAL/Box_intersection_d.h>
|
||||
// compare segment tree against brute force and simple implementations
|
||||
#include <CGAL/Box_intersection_d/one_way_scan.h>
|
||||
#include <CGAL/Box_intersection_d/all_pairs.h>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
|
|
@ -18,29 +18,29 @@ static unsigned int failed = 0;
|
|||
|
||||
template< class NT, unsigned int DIM, bool CLOSED >
|
||||
struct _test {
|
||||
typedef NT NumberType;
|
||||
typedef CGAL::Default_Bbox_d< NumberType, DIM > Box;
|
||||
typedef CGAL::Default_Bbox_d_Adapter< Box > BoxAdapter;
|
||||
typedef CGAL::Default_Box_Traits< BoxAdapter, CLOSED > Traits;
|
||||
typedef std::vector< Box > BoxContainer;
|
||||
typedef std::pair< Box, Box > BoxPair;
|
||||
typedef std::vector< BoxPair > ResultContainer;
|
||||
typedef NT Number_type;
|
||||
typedef CGAL::Default_box_d< Number_type, DIM > Box;
|
||||
typedef CGAL::Default_box_d_traits< Box > Box_adapter;
|
||||
typedef CGAL::Default_box_predicate_traits< Box_adapter, CLOSED > Traits;
|
||||
typedef std::vector< Box > Box_container;
|
||||
typedef std::pair< Box, Box > Box_pair;
|
||||
typedef std::vector< Box_pair > Result_container;
|
||||
|
||||
|
||||
static void fill_boxes( unsigned int n, BoxContainer& boxes ) {
|
||||
static void fill_boxes( unsigned int n, Box_container& boxes ) {
|
||||
NT maxEdgeLength = (NT) pow(n, (DIM-1.0)/DIM);
|
||||
|
||||
for( unsigned int i = 0; i < n; ++i ) {
|
||||
NumberType lo[DIM], hi[DIM];
|
||||
NT lo[DIM], hi[DIM];
|
||||
for( unsigned int d = 0; d < DIM; ++d ) {
|
||||
lo[d] = (NumberType)(drand48() * (n - maxEdgeLength));
|
||||
hi[d] = (NumberType)(lo[d] + 1 + (drand48() * maxEdgeLength));
|
||||
lo[d] = (NT)(drand48() * (n - maxEdgeLength));
|
||||
hi[d] = (NT)(lo[d] + 1 + (drand48() * maxEdgeLength));
|
||||
}
|
||||
boxes.push_back( Box( &lo[0], &hi[0]) );
|
||||
}
|
||||
}
|
||||
|
||||
static void assertIntersection( const Box& a, const Box& b ) {
|
||||
static void assert_intersection( const Box& a, const Box& b ) {
|
||||
for( unsigned int dim = 0; dim < DIM; ++dim ) {
|
||||
if( Traits::does_intersect( a, b, dim ) == false ) {
|
||||
std::cout << "does not intersect!" << std::endl;
|
||||
|
|
@ -52,18 +52,28 @@ static void assertIntersection( const Box& a, const Box& b ) {
|
|||
|
||||
|
||||
template< class Storage >
|
||||
struct StorageCallback {
|
||||
struct Storage_callback {
|
||||
unsigned int counter;
|
||||
Storage& storage;
|
||||
StorageCallback( Storage& storage ) : counter( 0 ), storage( storage ) {}
|
||||
Storage_callback( Storage& storage ) : counter( 0 ), storage( storage ) {}
|
||||
void operator()( const Box& a, const Box& b ) {
|
||||
assertIntersection( a, b );
|
||||
assert_intersection( a, b );
|
||||
++counter;
|
||||
//storage.push_back( std::make_pair( a, b ) );
|
||||
//std::cout << Traits::get_num( a ) << " " << Traits::get_num( b ) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct Counter_callback {
|
||||
unsigned int counter;
|
||||
Counter_callback() : counter( 0 ) {}
|
||||
void operator()( const Box& a, const Box& b ) {
|
||||
assert_intersection( a, b );
|
||||
++counter;
|
||||
//std::cout << Traits::get_num( a ) << " " << Traits::get_num( b ) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
/*bool
|
||||
operator==( const Box& a, const Box& b ) {
|
||||
for( unsigned int dim = 0; dim < DIM; ++dim )
|
||||
|
|
@ -109,23 +119,34 @@ unsigned int countDuplicates( Storage& storage ) {
|
|||
} */
|
||||
|
||||
static void
|
||||
test_n( unsigned int n, bool bipartite = true )
|
||||
test_n( unsigned int n, CGAL::Box_intersection_d::Setting setting = CGAL::Box_intersection_d::BIPARTITE )
|
||||
{
|
||||
BoxContainer boxes1, boxes2;
|
||||
ResultContainer result_scanner, result_tree;
|
||||
Box_container boxes1, boxes2;
|
||||
//Result_container result_allpairs, result_scanner, result_tree;
|
||||
std::cout << "generating random box sets with size " << n << " ... " << std::flush;
|
||||
fill_boxes( n, boxes1 );
|
||||
bool bipartite = setting == CGAL::Box_intersection_d::BIPARTITE;
|
||||
|
||||
if( bipartite )
|
||||
fill_boxes( n, boxes2 );
|
||||
else
|
||||
boxes2 = boxes1;
|
||||
std::cout << std::endl;
|
||||
StorageCallback< ResultContainer >
|
||||
callback1( result_scanner ),
|
||||
callback2( result_tree );
|
||||
|
||||
std::cout << "one way scan ... " << std::flush;
|
||||
Counter_callback callback0, callback1, callback2;
|
||||
Timer timer;
|
||||
|
||||
if( n < 20000 ) {
|
||||
std::cout << "all pairs ... " << std::flush;
|
||||
timer.start();
|
||||
CGAL::all_pairs( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback0, Traits(), DIM - 1 );
|
||||
timer.stop();
|
||||
std::cout << "got " << callback0.counter << " intersections in "
|
||||
<< timer.t << " seconds."
|
||||
<< std::endl;
|
||||
timer.reset();
|
||||
}
|
||||
std::cout << "one way scan ... " << std::flush;
|
||||
timer.start();
|
||||
CGAL::one_way_scan( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback1, Traits(), DIM - 1 );
|
||||
|
|
@ -134,21 +155,20 @@ test_n( unsigned int n, bool bipartite = true )
|
|||
boxes1.begin(), boxes1.end(), callback1, Traits(), DIM - 1 );
|
||||
timer.stop();
|
||||
std::cout << "got " << callback1.counter << " intersections in "
|
||||
<< timer.t << " seconds."
|
||||
<< std::endl;
|
||||
<< timer.t << " seconds."
|
||||
<< std::endl;
|
||||
|
||||
std::cout << "segment tree ... " << std::flush;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
Traits::cutoff = n < 200 ? 6 : n < 2000 ? 20 : n / 50;
|
||||
//Traits::cutoff = 5;
|
||||
CGAL::segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits(), bipartite );
|
||||
unsigned int cutoff = n < 200 ? 6 : n < 2000 ? 20 : n / 50;
|
||||
CGAL::box_intersection_d_custom( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits(), cutoff, setting );
|
||||
timer.stop();
|
||||
std::cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." << std::endl;
|
||||
|
||||
if( callback1.counter != callback2.counter ) {
|
||||
if( callback1.counter != callback2.counter || n < 20000 && callback0.counter != callback1.counter ) {
|
||||
++failed;
|
||||
/*unsigned int missing = countMissingItems( result_scanner,
|
||||
result_tree );
|
||||
|
|
@ -168,9 +188,9 @@ void operator()() {
|
|||
std::cout << "-------------------------" << std::endl;
|
||||
for( unsigned int n = 8; n < 200000; n = (int)(n * 1.3)) {
|
||||
std::cout << "bipartite case: " << std::endl;
|
||||
test_n( n, true );
|
||||
test_n( n, CGAL::Box_intersection_d::BIPARTITE );
|
||||
std::cout << "complete case: " << std::endl;
|
||||
test_n( n, false );
|
||||
test_n( n, CGAL::Box_intersection_d::COMPLETE );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue