mirror of https://github.com/CGAL/cgal
bbox developed to package Bounding_box_d
This commit is contained in:
parent
5c20f9ff39
commit
0fb5698b5d
|
|
@ -1 +0,0 @@
|
|||
Andreas Meyer <ameyer@mpi-sb.mpg.de>
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef TIMER_HXX
|
||||
#define TIMER_HXX
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
struct Timer
|
||||
{
|
||||
public:
|
||||
struct timeval t1,t2;
|
||||
|
||||
double t;
|
||||
|
||||
void start()
|
||||
{
|
||||
gettimeofday (&t1, NULL);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
gettimeofday (&t2, NULL);
|
||||
t = (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec) / 1000000.0;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
t = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
#include "bbox.h"
|
||||
#include <bbox/box_traits.h>
|
||||
|
||||
#include <bbox/all_pairs.h>
|
||||
#include <bbox/one_way_scan.h>
|
||||
|
||||
// enable invariant checking
|
||||
#define SEGMENT_TREE_CHECK_INVARIANTS 1
|
||||
#include <bbox/segment_tree.h>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef Bbox_3< int > Box;
|
||||
typedef Bbox_3_Adapter< Box > BoxAdapter;
|
||||
typedef Default_Box_Traits< BoxAdapter > Traits;
|
||||
typedef vector< Box > BoxContainer;
|
||||
typedef pair< Box, Box > BoxPair;
|
||||
typedef vector< BoxPair > ResultContainer;
|
||||
|
||||
|
||||
static void readBoxesFromFile( FILE *infile, BoxContainer& boxes )
|
||||
{
|
||||
int numBoxes, numDim;
|
||||
int numMatched;
|
||||
int boxNum, dim;
|
||||
|
||||
fscanf(infile, "%d %d\n", &numBoxes, &numDim);
|
||||
vector< int > lo( numDim ), hi( numDim );
|
||||
/* Read boxes */
|
||||
for(boxNum = 0; boxNum < numBoxes; boxNum++) {
|
||||
for(dim = 0; dim < numDim; dim++)
|
||||
fscanf( infile, "[%d, %d) ", &lo[dim], &hi[dim] );
|
||||
boxes.push_back( Box( lo[0], lo[1], lo[2], hi[0], hi[1], hi[2] ) );
|
||||
fscanf(infile, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
//cout << a << endl << b << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class Storage >
|
||||
struct StorageCallback {
|
||||
unsigned int counter;
|
||||
Storage& storage;
|
||||
StorageCallback( 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 ) );
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
operator==( const Box& a, const Box& b ) {
|
||||
for( unsigned int dim = 0; dim < 3; ++dim )
|
||||
if( Traits::get_lo( a, dim ) != Traits::get_lo( b, dim ) ||
|
||||
Traits::get_hi( a, dim ) != Traits::get_hi( b, dim ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==( const BoxPair& a, const BoxPair& b ) {
|
||||
return( a.first == b.first && a.second == b.second ||
|
||||
a.first == b.second && a.second == b.first );
|
||||
}
|
||||
|
||||
template< class Storage >
|
||||
unsigned int countMissingItems( Storage& a, Storage& b ) {
|
||||
unsigned int missing = 0;
|
||||
for( typename Storage::iterator it = a.begin(); it != a.end(); ++it ) {
|
||||
if( find( b.begin(), b.end(), *it ) == b.end() ) {
|
||||
++missing;
|
||||
//cout << it->first << it->second << endl;
|
||||
}
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
template< class Storage >
|
||||
unsigned int countDuplicates( Storage& storage ) {
|
||||
unsigned int counter = 0;
|
||||
typedef typename Storage::iterator IT;
|
||||
for( IT it = storage.begin(); it != storage.end(); ++it )
|
||||
for( IT it2 = it; it2 != storage.end(); ++it2 )
|
||||
if( it != it2 && *it == *it2 ) {
|
||||
//cout << it->first.num() << " <-> "
|
||||
// << it->second.num() << endl;
|
||||
++counter;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void
|
||||
test( const char* filename1, const char* filename2 )
|
||||
{
|
||||
BoxContainer boxes1, boxes2;
|
||||
ResultContainer result_all_pairs, result_tree;
|
||||
FILE *infile1, *infile2;
|
||||
infile1 = fopen( filename1, "r");
|
||||
infile2 = fopen( filename2, "r");
|
||||
|
||||
readBoxesFromFile( infile1, boxes1 );
|
||||
readBoxesFromFile( infile2, boxes2 );
|
||||
|
||||
cout << endl;
|
||||
StorageCallback< ResultContainer >
|
||||
callback1( result_all_pairs ),
|
||||
callback2( result_tree );
|
||||
|
||||
cout << "all pairs ...... " << flush;
|
||||
Timer timer;
|
||||
timer.start();
|
||||
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;
|
||||
|
||||
cout << "segment tree ... " << flush;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
unsigned int n = boxes1.size();
|
||||
Traits::cutoff = n < 2000 ? 6 : n / 100;
|
||||
segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits(), 2 );
|
||||
timer.stop();
|
||||
cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." <<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 "
|
||||
<< duplicates << " duplicate intersections in tree result."
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
cout << "--- passed --- " << endl;
|
||||
fclose( infile1 );
|
||||
fclose( infile2 );
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char ** argv ) {
|
||||
for( unsigned int n = 1; n <= 6; ++n ) {
|
||||
stringstream file1, file2;
|
||||
file1 << "test" << n << "_set1.box" << ends;
|
||||
file2 << "test" << n << "_set2.box" << ends;
|
||||
test( file1.str().c_str(), file2.str().c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
#ifndef CGAL_BBOX_3_ADAPTER_H
|
||||
#define CGAL_BBOX_3_ADAPTER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
/*
|
||||
class Bbox_3
|
||||
{
|
||||
double x_lo, y_lo, z_lo;
|
||||
double x_hi, y_hi, z_hi;
|
||||
public:
|
||||
Bbox_3(double x_lo, double y_lo, double z_lo,
|
||||
double x_hi, double y_hi, double z_hi)
|
||||
: x_lo( x_lo ), y_lo( y_lo ), z_lo( z_lo ),
|
||||
x_hi( x_hi ), y_hi( y_hi ), z_hi( z_hi )
|
||||
{}
|
||||
|
||||
double xlo() const { return x_lo; }
|
||||
double ylo() const { return y_lo; }
|
||||
double zlo() const { return z_lo; }
|
||||
double xhi() const { return x_hi; }
|
||||
double yhi() const { return y_hi; }
|
||||
double zhi() const { return z_hi; }
|
||||
|
||||
Bbox_3 operator+(const Bbox_3& b) const {
|
||||
return Bbox_3(std::lo( xlo(), b.xlo() ),
|
||||
std::lo( ylo(), b.ylo() ),
|
||||
std::lo( zlo(), b.zlo() ),
|
||||
std::hi( xhi(), b.xhi() ),
|
||||
std::hi( yhi(), b.yhi() ),
|
||||
std::hi( zhi(), b.zhi() ));
|
||||
}
|
||||
};
|
||||
|
||||
class Bbox_3_Adapter : public Bbox_3 {
|
||||
public:
|
||||
Bbox_3_Adapter( double x_lo, double y_lo, double z_lo,
|
||||
double x_hi, double y_hi, double z_hi )
|
||||
: Bbox_3( x_lo, y_lo, z_lo, x_hi, y_hi, z_hi )
|
||||
{}
|
||||
|
||||
double get_lo( unsigned int n ) const {
|
||||
switch( n ) {
|
||||
case 0: return xlo();
|
||||
case 1: return ylo();
|
||||
case 2: return zlo();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
double get_hi( unsigned int n ) const {
|
||||
switch( n ) {
|
||||
case 0: return xhi();
|
||||
case 1: return yhi();
|
||||
case 2: return zhi();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
template< class T >
|
||||
class Bbox_3
|
||||
{
|
||||
T __lo[3], __hi[3];
|
||||
unsigned int __num;
|
||||
public:
|
||||
typedef T NumberType;
|
||||
|
||||
Bbox_3() {}
|
||||
Bbox_3( T x_lo, T y_lo, T z_lo,
|
||||
T x_hi, T y_hi, T z_hi )
|
||||
{
|
||||
__lo[0]= x_lo; __lo[1]= y_lo; __lo[2]= z_lo;
|
||||
__hi[0]= x_hi; __hi[1]= y_hi; __hi[2]= z_hi;
|
||||
__num = getCounter();
|
||||
}
|
||||
|
||||
static unsigned int getCounter( bool reset = false ) {
|
||||
static unsigned int counter = 0;
|
||||
if( reset )
|
||||
counter = 0;
|
||||
else
|
||||
++counter;
|
||||
return counter;
|
||||
}
|
||||
|
||||
T lo( unsigned int dim ) const { return __lo[dim]; }
|
||||
T hi( unsigned int dim ) const { return __hi[dim]; }
|
||||
unsigned int num() const { return __num; }
|
||||
//unsigned int num() const { return (unsigned int )this; }
|
||||
};
|
||||
|
||||
template< class _Box >
|
||||
struct Bbox_3_Adapter {
|
||||
typedef _Box Box;
|
||||
typedef typename _Box::NumberType NumberType;
|
||||
|
||||
static NumberType get_lo( const Box& b, unsigned int dim )
|
||||
{ return b.lo( dim ); }
|
||||
|
||||
static NumberType get_hi( const Box& b, unsigned int dim )
|
||||
{ return b.hi( dim ); }
|
||||
|
||||
static unsigned int get_num( const Box& b )
|
||||
{ return b.num(); }
|
||||
};
|
||||
|
||||
template< class _Box >
|
||||
struct Bbox_3_Pointer_Adapter {
|
||||
typedef _Box* Box;
|
||||
typedef typename _Box::NumberType NumberType;
|
||||
|
||||
static NumberType get_lo( const Box b, unsigned int dim )
|
||||
{ return b->lo( dim ); }
|
||||
|
||||
static NumberType get_hi( const Box b, unsigned int dim )
|
||||
{ return b->hi( dim ); }
|
||||
|
||||
static unsigned int get_num( const Box b )
|
||||
{ return b->num(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef CGAL_BBOX_ALL_PAIRS_H
|
||||
#define CGAL_BBOX_ALL_PAIRS_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
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, int last_dim,
|
||||
bool in_order = true )
|
||||
{
|
||||
for( RandomAccessIter p = p_begin; p != p_end; ++p ) {
|
||||
for( RandomAccessIter i = i_begin; i != i_end; ++i ) {
|
||||
bool does_intersect = true;
|
||||
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:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#ifndef CGAL_BBOX_BOX_TRAITS_H
|
||||
#define CGAL_BBOX_BOX_TRAITS_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
// 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< class BoxAdapter >
|
||||
struct Default_Box_Traits : public BoxAdapter {
|
||||
typedef typename BoxAdapter::Box Box;
|
||||
typedef typename BoxAdapter::NumberType NumberType;
|
||||
typedef Default_Box_Traits< BoxAdapter > Traits;
|
||||
|
||||
static unsigned int cutoff;
|
||||
|
||||
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 ); }
|
||||
};
|
||||
|
||||
class Lo_Less : public std::unary_function< Box, bool > {
|
||||
NumberType value;
|
||||
unsigned int dim;
|
||||
public:
|
||||
Lo_Less( NumberType 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;
|
||||
unsigned int dim;
|
||||
public:
|
||||
Hi_Greater( NumberType value, unsigned int dim )
|
||||
: value( value ), dim( dim ) {}
|
||||
bool operator() ( const Box& box ) const
|
||||
{ return get_hi( box, dim ) > value; }
|
||||
};
|
||||
|
||||
// lambda( box ).(get_lo(box,dim) < lo && get_hi(box,dim) > hi ) )
|
||||
class Interval_Spanning_Predicate : public std::unary_function<Box,bool> {
|
||||
NumberType lo, hi;
|
||||
unsigned int dim;
|
||||
public:
|
||||
Interval_Spanning_Predicate( NumberType lo, NumberType hi,
|
||||
unsigned int dim )
|
||||
: lo( lo ), hi( hi ), dim( dim ) {}
|
||||
// returns true <=> box spans [lo,hi) in dimension dim
|
||||
bool operator() ( const Box& box ) const
|
||||
{ return get_lo( box, dim ) < lo && get_hi( box, dim ) > hi; }
|
||||
};
|
||||
|
||||
static bool is_lo_less_lo( const Box& a, const Box& b, unsigned int dim ) {
|
||||
return get_lo(a,dim) < get_lo(b,dim) ||
|
||||
get_lo(a,dim) == get_lo(b,dim) && get_num(a) < get_num(b);
|
||||
}
|
||||
|
||||
static bool is_lo_less_hi( const Box& a, const Box& b, unsigned int dim )
|
||||
{ return get_lo(a,dim ) < get_hi(b,dim); }
|
||||
|
||||
static bool does_intersect ( const Box& a, const Box& b, unsigned int dim )
|
||||
{ return get_hi(a,dim) > get_lo(b,dim) && get_hi(b,dim) > get_lo(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; }
|
||||
};
|
||||
|
||||
template< class BoxAdapter >
|
||||
unsigned int
|
||||
Default_Box_Traits<BoxAdapter>::cutoff = 3000;
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,63 +0,0 @@
|
|||
#ifndef CGAL_BBOX_MODIFIED_TWO_WAY_SCAN_H
|
||||
#define CGAL_BBOX_MODIFIED_TWO_WAY_SCAN_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
template< class RandomAccessIter,
|
||||
class Callback,
|
||||
class Traits >
|
||||
void modified_two_way_scan( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback, Traits traits, unsigned int last_dim,
|
||||
bool in_order = true )
|
||||
{
|
||||
typedef typename Traits::Compare Compare;
|
||||
|
||||
std::sort( p_begin, p_end, Compare( 0 ) );
|
||||
std::sort( i_begin, i_end, Compare( 0 ) );
|
||||
|
||||
// for each box viewed as interval i
|
||||
while( i_begin != i_end && p_begin != p_end ) {
|
||||
if( Traits::is_lo_less_lo( *i_begin, *p_begin, 0 ) ) {
|
||||
for( RandomAccessIter p = p_begin;
|
||||
p != p_end && Traits::is_lo_less_hi( *p, *i_begin, 0 );
|
||||
++p )
|
||||
{
|
||||
for( unsigned int dim = 1; dim <= last_dim; ++dim )
|
||||
if( !Traits::does_intersect( *p, *i_begin, dim ) )
|
||||
goto no_intersection1;
|
||||
if( Traits::contains_lo_point( *i_begin, *p, last_dim ) ) {
|
||||
if( in_order )
|
||||
callback( *p, *i_begin );
|
||||
else
|
||||
callback( *i_begin, *p );
|
||||
}
|
||||
no_intersection1:
|
||||
;
|
||||
}
|
||||
++i_begin;
|
||||
} else {
|
||||
for( RandomAccessIter i = i_begin;
|
||||
i != i_end && Traits::is_lo_less_hi( *i, *p_begin, 0 );
|
||||
++i )
|
||||
{
|
||||
for( unsigned int dim = 1; dim <= last_dim; ++dim )
|
||||
if( !Traits::does_intersect( *p_begin, *i, dim ) )
|
||||
goto no_intersection2;
|
||||
if( Traits::contains_lo_point( *i, *p_begin, last_dim ) ) {
|
||||
if( in_order )
|
||||
callback( *p_begin, *i );
|
||||
else
|
||||
callback( *i, *p_begin );
|
||||
}
|
||||
no_intersection2:
|
||||
;
|
||||
}
|
||||
++p_begin;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#ifndef CGAL_BBOX_ONE_WAY_SCAN_H
|
||||
#define CGAL_BBOX_ONE_WAY_SCAN_H
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
template< class RandomAccessIter, class Callback, class Traits >
|
||||
void one_way_scan( RandomAccessIter p_begin, RandomAccessIter p_end,
|
||||
RandomAccessIter i_begin, RandomAccessIter i_end,
|
||||
Callback& callback, Traits traits, unsigned int last_dim,
|
||||
bool in_order = true )
|
||||
{
|
||||
typedef typename Traits::Compare Compare;
|
||||
std::sort( p_begin, p_end, Compare( 0 ) );
|
||||
std::sort( i_begin, i_end, Compare( 0 ) );
|
||||
|
||||
// for each box viewed as interval i
|
||||
for( RandomAccessIter i = i_begin; i != i_end; ++i ) {
|
||||
// look for the first box b with i.min <= p.min
|
||||
for( ; p_begin != p_end && Traits::is_lo_less_lo( *p_begin, *i, 0 );
|
||||
++p_begin );
|
||||
|
||||
// look for all boxes with p.min < i.max
|
||||
for( RandomAccessIter p = p_begin;
|
||||
p != p_end && Traits::is_lo_less_hi( *p, *i, 0 );
|
||||
++p )
|
||||
{
|
||||
for( unsigned int dim = 1; 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:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
#ifndef CGAL_BBOX_SEGMENT_TREE_H
|
||||
#define CGAL_BBOX_SEGMENT_TREE_H
|
||||
|
||||
#include <bbox/one_way_scan.h>
|
||||
#include <bbox/modified_two_way_scan.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef USE_MY_NUMERIC_LIMITS
|
||||
#include <bbox/limits>
|
||||
#else
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
template< class RandomAccessIter, class Traits >
|
||||
RandomAccessIter
|
||||
median_of_three( RandomAccessIter a, RandomAccessIter b, RandomAccessIter c,
|
||||
Traits traits, unsigned int dim )
|
||||
{
|
||||
if( Traits::is_lo_less_lo( *a, *b, dim ) )
|
||||
if( Traits::is_lo_less_lo( *b, *c, dim ) )
|
||||
return b;
|
||||
else if( Traits::is_lo_less_lo( *a, *c, dim ) )
|
||||
return c;
|
||||
else
|
||||
return a;
|
||||
else if( Traits::is_lo_less_lo( *a, *c, dim ) )
|
||||
return a;
|
||||
else if( Traits::is_lo_less_lo( *b, *c, dim ) )
|
||||
return c;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Traits >
|
||||
RandomAccessIter
|
||||
iterative_radon( RandomAccessIter begin, RandomAccessIter end,
|
||||
Traits traits, unsigned int dim, int num_levels )
|
||||
{
|
||||
if( num_levels < 0 )
|
||||
return begin + lrand48() % std::distance( begin, end );
|
||||
|
||||
return median_of_three(
|
||||
iterative_radon( begin, end, traits, dim, num_levels - 1 ),
|
||||
iterative_radon( begin, end, traits, dim, num_levels - 1 ),
|
||||
iterative_radon( begin, end, traits, dim, num_levels - 1 ),
|
||||
traits, dim );
|
||||
}
|
||||
|
||||
// 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 >
|
||||
RandomAccessIter
|
||||
split_points( RandomAccessIter begin, RandomAccessIter end, 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 ) );
|
||||
}
|
||||
|
||||
|
||||
//#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
static int level = -1;
|
||||
#define DUMP(msg) { \
|
||||
for( unsigned int i = level; i; --i ) \
|
||||
std::cout << " "; \
|
||||
std::cout << msg; \
|
||||
}
|
||||
#else
|
||||
#define DUMP(msg) ;
|
||||
#endif
|
||||
|
||||
|
||||
template< class ForwardIter, class Traits >
|
||||
void dump_points( ForwardIter begin, ForwardIter end, Traits traits,
|
||||
unsigned int dim ) {
|
||||
while( begin != end ) {
|
||||
std::cout << Traits::get_lo( *begin, dim ) << " ";
|
||||
++begin;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template< class ForwardIter, class Traits >
|
||||
void dump_intervals( ForwardIter begin, ForwardIter end, Traits traits,
|
||||
unsigned int dim ) {
|
||||
while( begin != end ) {
|
||||
std::cout << "[" << Traits::get_lo( *begin, dim ) << ","
|
||||
<< Traits::get_hi( *begin, dim ) << ") ";
|
||||
++begin;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template< class ForwardIter, class Traits >
|
||||
void dump_box_numbers( ForwardIter begin, ForwardIter end, Traits traits ) {
|
||||
while( begin != end ) {
|
||||
std::cout << Traits::get_num( *begin ) << " ";
|
||||
++begin;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
struct Counter {
|
||||
T& value;
|
||||
Counter( T& value ) : value( value ) { ++value; }
|
||||
~Counter() { --value; }
|
||||
};
|
||||
|
||||
template< class RandomAccessIter, class Callback, class T, class 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 )
|
||||
{
|
||||
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;
|
||||
|
||||
#if DEBUG
|
||||
Counter<int> bla( level );
|
||||
//DUMP("----------------===========[ new node ]============-------------")
|
||||
DUMP("range: [" << lo << "," << hi << ") dim " << dim << std::endl )
|
||||
DUMP("intervals: " )
|
||||
dump_box_numbers( i_begin, i_end, traits );
|
||||
//dump_intervals( i_begin, i_end, traits, dim );
|
||||
DUMP("points: " )
|
||||
dump_box_numbers( p_begin, p_end, traits );
|
||||
//dump_points( p_begin, p_end, traits, dim );
|
||||
#endif
|
||||
|
||||
#if SEGMENT_TREE_CHECK_INVARIANTS
|
||||
// first: each point is inside segment [lo,hi)
|
||||
for( RandomAccessIter it = p_begin; it != p_end; ++it ) {
|
||||
assert( Traits::get_lo( *it, dim ) < hi );
|
||||
assert( Traits::get_lo( *it, dim ) >= lo );
|
||||
}
|
||||
// second: each interval intersects segment [lo,hi)
|
||||
for( RandomAccessIter it = i_begin; it != i_end; ++it ) {
|
||||
assert( Traits::get_lo( *it, dim ) < hi );
|
||||
assert( Traits::get_hi( *it, dim ) > lo );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( p_begin == p_end || i_begin == i_end || lo >= hi )
|
||||
return;
|
||||
|
||||
if( dim == 0 ) {
|
||||
DUMP( "dim = 0. scanning ... " << std::endl )
|
||||
one_way_scan( p_begin, p_end, i_begin, i_end,
|
||||
callback, traits, dim, in_order );
|
||||
return;
|
||||
}
|
||||
|
||||
if( (unsigned int)std::distance( p_begin, p_end ) < Traits::get_cutoff() ||
|
||||
(unsigned int)std::distance( i_begin, i_end ) < Traits::get_cutoff() )
|
||||
{
|
||||
DUMP( "scanning ... " << std::endl )
|
||||
modified_two_way_scan( p_begin, p_end, i_begin, i_end,
|
||||
callback, traits, dim, in_order );
|
||||
return;
|
||||
}
|
||||
|
||||
RandomAccessIter i_span_end =
|
||||
lo == std::numeric_limits< T >::min() ||
|
||||
hi == std::numeric_limits< T >::max() ? i_begin :
|
||||
std::partition( i_begin, i_end, Spanning( lo, hi, dim ) );
|
||||
|
||||
if( i_begin != i_span_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,
|
||||
std::numeric_limits< T >::min(),
|
||||
std::numeric_limits< T >::max(),
|
||||
callback, traits, dim - 1, in_order );
|
||||
segment_tree( i_begin, i_span_end, p_begin, p_end,
|
||||
std::numeric_limits< T >::min(),
|
||||
std::numeric_limits< T >::max(),
|
||||
callback, traits, dim - 1, !in_order );
|
||||
}
|
||||
|
||||
T mi;
|
||||
RandomAccessIter p_mid = split_points( p_begin, p_end, traits, dim, mi );
|
||||
|
||||
if( p_mid == p_begin || p_mid == p_end ) {
|
||||
DUMP( "unable to split points! ")
|
||||
//dump_points( p_begin, p_end, traits, dim );
|
||||
DUMP( "performing modified two_way_san ... " << std::endl )
|
||||
modified_two_way_scan( p_begin, p_end, i_span_end, i_end,
|
||||
callback, traits, dim, in_order );
|
||||
return;
|
||||
}
|
||||
|
||||
RandomAccessIter i_mid;
|
||||
// separate left intervals.
|
||||
// left intervals have a low point strictly less than mi
|
||||
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 );
|
||||
// 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, unsigned int dim )
|
||||
{
|
||||
typedef typename Traits::NumberType T;
|
||||
segment_tree( p_begin, p_end, i_begin, i_end,
|
||||
-std::numeric_limits< T >::max(),
|
||||
std::numeric_limits< T >::max(),
|
||||
callback, traits, dim, true );
|
||||
|
||||
segment_tree( i_begin, i_end, p_begin, p_end,
|
||||
-std::numeric_limits< T >::max(),
|
||||
std::numeric_limits< T >::max(),
|
||||
callback, traits, dim, false );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
CXX = g++
|
||||
INCLUDE = -I./include
|
||||
CXXFLAGS = $(INCLUDE) -O1
|
||||
|
||||
random_set_test: random_set_test.cc
|
||||
$(CXX) $(CXXFLAGS) random_set_test.cc -o random_set_test
|
||||
|
||||
automated_test: automated_test.cc
|
||||
$(CXX) $(CXXFLAGS) automated_test.cc -o automated_test
|
||||
|
||||
|
||||
|
||||
|
||||
# $(CXX) -O3 -fomit-frame-pointer -fexpensive-optimizations -falign-functions=4 -malign-double -fprefetch-loop-arrays -march=pentium3 -msse automated_test.cc -o segment_tree
|
||||
# -funroll-loops brings 10 percent slowdown on duron750 (64kb cache)
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
#include "bbox.h"
|
||||
#include <bbox/box_traits.h>
|
||||
|
||||
#include <bbox/one_way_scan.h>
|
||||
|
||||
// enable invariant checking
|
||||
#define SEGMENT_TREE_CHECK_INVARIANTS 1
|
||||
#include <bbox/segment_tree.h>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef double NumberType;
|
||||
typedef Bbox_3< NumberType > Box;
|
||||
typedef Bbox_3_Adapter< Box > BoxAdapter;
|
||||
typedef Default_Box_Traits< BoxAdapter > Traits;
|
||||
typedef vector< Box > BoxContainer;
|
||||
typedef pair< Box, Box > BoxPair;
|
||||
typedef vector< BoxPair > ResultContainer;
|
||||
|
||||
|
||||
static void fill_boxes( unsigned int n, BoxContainer& boxes ) {
|
||||
unsigned int maxEdgeLength = (int) pow(n, (double)2/3);
|
||||
|
||||
for( unsigned int i = 0; i < n; ++i ) {
|
||||
NumberType lo[3], hi[3];
|
||||
for( unsigned int d = 0; d < 3; ++d ) {
|
||||
lo[d] = (NumberType)(drand48() * (n - maxEdgeLength));
|
||||
hi[d] = lo[d] + 1 + (NumberType)(drand48() * maxEdgeLength);
|
||||
}
|
||||
boxes.push_back( Box( lo[0], lo[1], lo[2], hi[0], hi[1], hi[2] ) );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
//cout << a << endl << b << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template< class Storage >
|
||||
struct StorageCallback {
|
||||
unsigned int counter;
|
||||
Storage& storage;
|
||||
StorageCallback( 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 ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
bool
|
||||
operator==( const Box& a, const Box& b ) {
|
||||
for( unsigned int dim = 0; dim < 3; ++dim )
|
||||
if( Traits::get_lo( a, dim ) != Traits::get_lo( b, dim ) ||
|
||||
Traits::get_hi( a, dim ) != Traits::get_hi( b, dim ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==( const BoxPair& a, const BoxPair& b ) {
|
||||
return( a.first == b.first && a.second == b.second ||
|
||||
a.first == b.second && a.second == b.first );
|
||||
}
|
||||
|
||||
template< class Storage >
|
||||
unsigned int countMissingItems( Storage& a, Storage& b ) {
|
||||
unsigned int missing = 0;
|
||||
for( typename Storage::iterator it = a.begin(); it != a.end(); ++it ) {
|
||||
if( find( b.begin(), b.end(), *it ) == b.end() ) {
|
||||
++missing;
|
||||
//cout << it->first << it->second << endl;
|
||||
}
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
template< class Storage >
|
||||
unsigned int countDuplicates( Storage& storage ) {
|
||||
unsigned int counter = 0;
|
||||
typedef typename Storage::iterator IT;
|
||||
for( IT it = storage.begin(); it != storage.end(); ++it )
|
||||
for( IT it2 = it; it2 != storage.end(); ++it2 )
|
||||
if( it != it2 && *it == *it2 ) {
|
||||
//cout << it->first.num() << " <-> "
|
||||
// << it->second.num() << endl;
|
||||
++counter;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void
|
||||
test_n( unsigned int n )
|
||||
{
|
||||
BoxContainer boxes1, boxes2;
|
||||
ResultContainer result_scanner, result_tree;
|
||||
cout << "generating random box sets with size " << n << " ... " << flush;
|
||||
fill_boxes( n, boxes1 );
|
||||
fill_boxes( n, boxes2 );
|
||||
cout << endl;
|
||||
StorageCallback< ResultContainer >
|
||||
callback1( result_scanner ),
|
||||
callback2( result_tree );
|
||||
|
||||
cout << "one way scan ... " << flush;
|
||||
Timer timer;
|
||||
timer.start();
|
||||
one_way_scan( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback1, Traits(), 2 );
|
||||
one_way_scan( boxes2.begin(), boxes2.end(),
|
||||
boxes1.begin(), boxes1.end(), callback1, Traits(), 2 );
|
||||
timer.stop();
|
||||
cout << "got " << callback1.counter << " intersections in "
|
||||
<< timer.t << " seconds."
|
||||
<< endl;
|
||||
|
||||
cout << "segment tree ... " << flush;
|
||||
timer.reset();
|
||||
timer.start();
|
||||
Traits::cutoff = n < 2000 ? 6 : n / 100;
|
||||
//Traits::cutoff = 5;
|
||||
segment_tree( boxes1.begin(), boxes1.end(),
|
||||
boxes2.begin(), boxes2.end(), callback2, Traits(), 2 );
|
||||
timer.stop();
|
||||
cout << "got " << callback2.counter << " intersections in "
|
||||
<< timer.t << " seconds." <<endl;
|
||||
|
||||
if( callback1.counter != callback2.counter ) {
|
||||
unsigned int missing = countMissingItems( result_scanner,
|
||||
result_tree );
|
||||
unsigned int duplicates = countDuplicates( result_tree );
|
||||
cout << "!! failed !! " << missing << " missing and "
|
||||
<< duplicates << " duplicate intersections in tree result."
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
cout << "--- passed --- " << endl;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char ** argv ) {
|
||||
for( unsigned int n = 8; n < 500000; n = (int)(n * 1.3))
|
||||
test_n( n );
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue