vcglib/vcg/space/index/spatial_hashing.h

530 lines
14 KiB
C++

/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.10 2005/09/30 13:14:59 pietroni
added wrapping to functions defined in GridClosest:
- GetClosest
- GetKClosest
- DoRay
Revision 1.9 2005/09/21 14:22:49 pietroni
Added DynamicSpatialHAshTable class
Revision 1.8 2005/09/19 13:35:45 pietroni
use of standard grid interface
use of vector instead of map inside the cell
removed closest iterator
Revision 1.7 2005/06/15 11:44:47 pietroni
minor changes
Revision 1.6 2005/06/01 13:47:59 pietroni
resolved hash code conflicts
Revision 1.5 2005/03/15 09:50:44 ganovelli
there was a debug line, now removed
Revision 1.4 2005/03/14 15:11:18 ganovelli
ClosestK added and other minor changes
Revision 1.3 2005/03/11 15:25:29 ganovelli
added ClosersIterator and other minor changes. Not compatible with the previous version.
Still other modifications to do (temporary commit)
Revision 1.2 2005/02/21 12:13:25 ganovelli
added vcg header
****************************************************************************/
#ifndef VCGLIB_SPATIAL_HASHING
#define VCGLIB_SPATIAL_HASHING
#define P0 73856093
#define P1 19349663
#define P2 83492791
#include <vcg/space/index/grid_util.h>
#include <vcg/space/index/grid_closest.h>
//#include <map>
#include <vector>
#include <algorithm>
#ifdef WIN32
#include <hash_map>
#define STDEXT stdext
#else
#include <ext/hash_map>
#define STDEXT __gnu_cxx
#endif
namespace vcg{
/** Spatial Hash Table
Spatial Hashing as described in
"Optimized Spatial Hashing for Coll ision Detection of Deformable Objects",
Matthias Teschner and Bruno Heidelberger and Matthias Muller and Danat Pomeranets and Markus Gross
*/
template < typename OBJTYPE,class FLT=double>
class SpatialHashTable:public BasicGrid<OBJTYPE,FLT>
{
public:
typedef OBJTYPE ObjType;
typedef ObjType* ObjPtr;
typedef typename ObjType::ScalarType ScalarType;
typedef Point3<ScalarType> CoordType;
typedef typename SpatialHashTable<ObjType,FLT> SpatialHashType;
//typedef typename SpatialHashTable<ObjType,FLT> GridType;
//type of container of pointer to object in a Cell
//typedef typename std::pair<ObjType*,int> EntryType ;
class EntryType : public std::pair<ObjType*,int>
{
public:
EntryType(ObjType* sim,const int &_tempMark)
{
first=sim;
second=_tempMark;
}
ObjType& operator *(){return (*this->first);}
};
typedef typename std::vector<EntryType> CellContainerType;
typedef typename CellContainerType::iterator IteMap;
typedef typename EntryType* CellIterator;
//This Class Identify the cell
struct Cell
{
protected:
///the min and max point corresponding to the cell - used to inverse hashing
//CoordType min;//coordinate min of the cell
//CoordType max;//coordinate max of the cell
Point3i cell_n;//cell number
//iterator to the map element into the cell
//typedef typename CellContainerType::iterator IteMap;
public:
//elements
CellContainerType _entries;
Cell()
{}
Cell(ObjType* sim,Point3i _cell,const int &_tempMark)
{
_entries.push_back(EntryType(sim,_tempMark));
/*min=_min;
max=_max;
assert(min<max);*/
cell_n=_cell;
}
///return the number of elements stored in the cell
int Size()
{return (int)(_entries.size());}
///find the simplex into the cell
bool Find(ObjType* sim,IteMap &I)
{
for (I=_entries.begin();I<_entries.end();I++)
if ((*I).first==sim)
return true;
return false;
}
///update or insert an element into a cell
void Update(ObjType* sim, const int & _tempMark)
{
IteMap I;
if (Find(sim,I))
{///update temporary mark
(*I).second=_tempMark;
}
else
_entries.push_back(EntryType(sim,_tempMark));
////at the end update the temporary mark on the simplex
//_UpdateHMark(sim);
//Assert();
}
/////given an iterator to the instance of the entry in the cell
/////return true if the the entry is valid
/////(using temporary mark).
//bool IsUpdated(IteMap &I)
//{
// if (Use_Mark)
// return ((*I).second >= (*I).first->HMark());
// else
// return true;
//}
/////given an simplex pointer
/////return true if the the entry corripondent to that
/////simplex is valid or not
/////(using temporary mark).
//bool IsUpdated(ObjType* sim)
//{
// if (Use_Mark)
// {
// IteMap I;
// if (Find(sim,I))
// return(IsUpdated(I));
// else
// return false;
// }
// else return true;
//}
Point3i CellN()
{return cell_n;}
bool operator ==(const Cell &h)
{return (cell_n==h.CellN());}
bool operator !=(const Cell &h)
{return ((cell_n!=h.CellN()));}
protected:
virtual void UpdateHMark(ObjType* s){}
}; // end struct Cell
//hash table definition
typedef typename STDEXT::hash_multimap<int,Cell> Htable;
//record of the hash table
typedef typename std::pair<int,Cell> HRecord;
//iterator to the hash table
typedef typename Htable::iterator IteHtable;
SpatialHashTable(){HashSpace=1000;};//default value for hash_space
~SpatialHashTable(){};
int tempMark;
protected:
Htable hash_table;
///number of possible hash code [0...HashSpace]
int HashSpace;
///number of conflicts created
int conflicts;
///insert a new cell
void _InsertNewHentry(ObjType* s,Point3i cell)
{
int h=Hash(cell);
hash_table.insert(HRecord(h,Cell(s,cell,tempMark)));
//Assert();
}
///return true and return the iterator to the cell if exist
bool _IsInHtable(Point3i cell,IteHtable &result)
{
int h=Hash(cell);
int count=hash_table.count(h);
if (count==0)///in this case there is no entry for that key
return false;
else
{
////std::pair<Htable::const_iterator, Htable::const_iterator> p =hash_table.equal_range(h);
std::pair<IteHtable, IteHtable> p =hash_table.equal_range(h);
IteHtable i = p.first;
while((i != p.second)&&((*i).second.CellN()!=cell))++i;
if (i==p.second)///the scan is terminated and we have not found the right cell
{
conflicts++;
return false;
}
else ///we have found the right cell
{
result=i;
return true;
}
}
}
virtual void _UpdateHMark(ObjType* s){}
///insert an element in a specified cell if the cell doesn't exist than
///create it.
void _InsertInCell(ObjType* s,Point3i cell)
{
IteHtable I;
if (!_IsInHtable(cell,I))
_InsertNewHentry(s,cell);
else///there is the entry specified by the iterator I so update only the temporary mark
(*I).second.Update(s,tempMark);
_UpdateHMark(s);
}
// hashing
const int Hash(Point3i p) const
{
return ((p.V(0)*P0 ^ p.V(1)*P1 ^ p.V(2)*P2)%HashSpace);
}
public:
/////We need some extra space for numerical precision.
//template <class Box3Type>
// void SetBBox( const Box3Type & b )
//{
// bbox.Import( b );
// ScalarType t = bbox.Diag()/100.0;
// if(t == 0) t = ScalarType(1e20); // <--- Some doubts on this (Cigno 5/1/04)
// bbox.Offset(t);
// dim = bbox.max - bbox.min;
//}
virtual vcg::Box3i Add( ObjType* s)
{
/*std::vector<Point3i> box;
BoxCells(s->BBox().min,s->BBox().max,box);
for (std::vector<Point3i>::iterator bi=box.begin();bi<box.end();bi++)*/
Box3<ScalarType> b;
s->GetBBox(b);
vcg::Box3i bb;
BoxToIBox(b,bb);
//then insert all the cell of bb
for (int i=bb.min.X();i<=bb.max.X();i++)
for (int j=bb.min.Y();j<=bb.max.Y();j++)
for (int k=bb.min.Z();k<=bb.max.Z();k++)
_InsertInCell(s,vcg::Point3i(i,j,k));
return bb;
}
/// Insert a mesh in the grid.SetBBox() function must be called before
template <class OBJITER>
void Set(const OBJITER & _oBegin, const OBJITER & _oEnd,const Box3x &_bbox=Box3x() )
{
OBJITER i;
Box3<FLT> b;
if(!_bbox.IsNull()) bbox=_bbox;
else
for(i = _oBegin; i!= _oEnd; ++i)
{
(*i).GetBBox(b);
bbox.Add(b);
}
int _size=std::distance<OBJITER>(_oBegin,_oEnd);
dim = bbox.max - bbox.min;
BestDim( _size, dim, siz );
// find voxel size
voxel[0] = dim[0]/siz[0];
voxel[1] = dim[1]/siz[1];
voxel[2] = dim[2]/siz[2];
for(i = _oBegin; i!= _oEnd; ++i)
Add(&(*i));
}
//void Set(ContainerType & s, Point3i _siz)
//{
// siz=_siz;
// // find voxel size
// voxel[0] = dim[0]/siz[0];
// voxel[1] = dim[1]/siz[1];
// voxel[2] = dim[2]/siz[2];
// typename ContainerType::iterator i;
// for(i = s.begin(); i!= s.end(); ++i)
// Add(&(*i));
//}
//
/////initialize the structure HashSpace is one estimation about
/////how many keys the system have to generate in order to obtain as less
/////conflicts as possible
//void Init(CoordType _min,CoordType _max,ScalarType _l,int HashSpace=1000)
//{
// l=_l;
// min=_min;
// max=_max;
// HashSpace=HashSpace;
// tempMark=0;
// conflicts=0;
//}
/*void AddElem( ObjType* s)
{
std::vector<Point3i> box;
BoxCells(s->BBox().min,s->BBox().max,box);
for (std::vector<Point3i>::iterator bi=box.begin();bi<box.end();bi++)
_InsertInCell(s,*bi);
}*/
///return the simplexes of the cell that contain p
void Grid( const Point3d & p, CellIterator & first, CellIterator & last )
{
IteHtable I;
vcg::Point3i _c;
PToIP(p,_c);
Grid(_c,first,last);
}
///return the simplexes on a specified cell
void Grid( int x,int y,int z, CellIterator & first, CellIterator & last )
{
Grid(vcg::Point3i(x,y,z),first,last);
}
///return the simplexes on a specified cell
void Grid( const Point3i & _c, CellIterator & first, CellIterator & last )
{
IteHtable I;
if (_IsInHtable(_c,I))//if there is the cell then
{ ///return pointers to first and last element cell elems
first= &*(*I).second._entries.begin();
last= &*(*I).second._entries.end();
}
else
{ ///return 2 equals pointers
first=&*(*hash_table.begin()).second._entries.begin();
last= &*(*hash_table.begin()).second._entries.begin();
}
}
void getAtCell(Point3i _c,std::vector<ObjType*> & res)
{
IteHtable I;
if (_IsInHtable(_c,I))//if there is the cell then
(*I).second.Elems(res);
}
std::vector<Point3i> Cells(ObjType *s)
{
return BoxCells(s,s->BBox().min,s->BBox().max);
}
/*inline Point3i MinCell()
{
return PointToCell(min);
}
inline Point3i MaxCell()
{
return PointToCell(max);
}*/
///return the number of elemnts in the cell and the iterator to the cell
///if the cell exist
int numElemCell(Point3i _c,IteHtable &I)
{
if (_IsInHtable(_c,I))
return ((*I).second.Size());
else
return 0;
}
///return the number of cell created
int CellNumber()
{return (hash_table.size());}
int Conflicts()
{return conflicts;}
void Clear()
{
hash_table.clear();
}
void SetHashKeySpace(int n)
{
HashSpace=n;
}
void UpdateTmark()
{tempMark++;}
template <class OBJPOINTDISTFUNCTOR, class OBJMARKER>
ObjPtr GetClosest(OBJPOINTDISTFUNCTOR & _getPointDistance, OBJMARKER & _marker,
const CoordType & _p, const ScalarType & _maxDist,ScalarType & _minDist, CoordType & _closestPt)
{
return (vcg::GridClosest<SpatialHashType,OBJPOINTDISTFUNCTOR,OBJMARKER>(*this,_getPointDistance,_marker, _p,_maxDist,_minDist,_closestPt));
}
template <class OBJPOINTDISTFUNCTOR, class OBJMARKER, class OBJPTRCONTAINER,class DISTCONTAINER, class POINTCONTAINER>
unsigned int GetKClosest(OBJPOINTDISTFUNCTOR & _getPointDistance,OBJMARKER & _marker,
const unsigned int _k, const CoordType & _p, const ScalarType & _maxDist,OBJPTRCONTAINER & _objectPtrs,
DISTCONTAINER & _distances, POINTCONTAINER & _points)
{
return (vcg::GridGetKClosest<SpatialHashType,
OBJPOINTDISTFUNCTOR,OBJMARKER,OBJPTRCONTAINER,DISTCONTAINER,POINTCONTAINER>(*this,_getPointDistance,_marker,_k,_p,_maxDist,_objectPtrs,_distances,_points));
}
template <class OBJRAYISECTFUNCTOR, class OBJMARKER>
ObjPtr DoRay(OBJRAYISECTFUNCTOR & _rayIntersector, OBJMARKER & _marker, const Ray3<ScalarType> & _ray, const ScalarType & _maxDist, ScalarType & _t)
{
return(vcg::GridDoRay<SpatialHashType,OBJRAYISECTFUNCTOR,OBJMARKER>(*this,_rayIntersector,_marker,_ray,_maxDist,_t));
}
}; // end class
/** Spatial Hash Table Dynamic
Update the Hmark value on the simplex for dynamic updating of contents of the cell.
The simplex must have the HMark() function.
*/
template < typename ContainerType,class FLT=double>
class DynamicSpatialHashTable:SpatialHashTable<ContainerType,FLT>
{
void _UpdateHMark(ObjType* s){s->HMark()=tempMark;}
};
}// end namespace
#undef P0
#undef P1
#undef P2
#endif