00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef NL_QUAD_GRID_H
00025 #define NL_QUAD_GRID_H
00026
00027 #include "nel/misc/debug.h"
00028 #include "nel/misc/vector.h"
00029 #include "nel/misc/vector_2f.h"
00030 #include "nel/misc/plane.h"
00031 #include "nel/misc/matrix.h"
00032 #include "nel/misc/block_memory.h"
00033 #include "nel/misc/object_vector.h"
00034 #include "nel/misc/common.h"
00035 #include "nel/misc/polygon.h"
00036 #include "nel/misc/grid_traversal.h"
00037
00038 #include <vector>
00039 #include <map>
00040
00041 namespace NL3D
00042 {
00043
00044
00045 using NLMISC::CVector;
00046
00047
00048
00049 #define NL3D_QUAD_GRID_ALLOC_BLOCKSIZE 16
00050
00051
00052
00053 class CQuadGridBase
00054 {
00055 protected:
00056 static NLMISC::CPolygon2D _ScaledPoly;
00057 static NLMISC::CPolygon2D::TRasterVect _PolyBorders;
00058 static std::vector<uint> _AlreadySelected;
00059
00060
00061 static uint _SelectStamp;
00062 };
00063
00064
00087 template<class T> class CQuadGrid : public CQuadGridBase
00088 {
00089 public:
00091 class CIterator;
00092 friend class CIterator;
00093
00094 public:
00095 typedef std::vector<uint> TSelectionShape;
00096
00098 CQuadGrid(uint memoryBlockSize= NL3D_QUAD_GRID_ALLOC_BLOCKSIZE);
00099
00101 ~CQuadGrid();
00102
00103
00104 CQuadGrid<T> &operator=(const CQuadGrid<T> &o);
00105
00106
00107 CQuadGrid(const CQuadGrid<T> &o);
00108
00110
00111
00126 void changeBase(const NLMISC::CMatrix& base);
00127
00134 void create(uint size, float eltSize);
00135
00136
00137 const NLMISC::CMatrix &getBasis() const {return _ChangeBasis;}
00138 uint getSize() const {return _Size;}
00139 float getEltSize() const {return _EltSize;}
00141
00143
00144
00147 void clear();
00148
00156 CIterator erase(CIterator it);
00157
00183 CIterator insert(const NLMISC::CVector &bboxmin, const NLMISC::CVector &bboxmax, const T &val);
00185
00186
00188
00189
00192 void clearSelection();
00193
00197 void selectAll();
00198
00205 void select(const NLMISC::CVector &bboxmin, const NLMISC::CVector &bboxmax);
00206
00207
00208 void selectRay(const NLMISC::CVector &rayStart, const NLMISC::CVector &rayEnd);
00209
00213 void buildSelectionShape(TSelectionShape &dest, const NLMISC::CPolygon2D &poly) const;
00214
00217 void select(const TSelectionShape &shape);
00218
00219
00223 CIterator begin();
00224
00228 CIterator end();
00230
00231
00232
00233
00234
00235
00236
00237 private:
00238 class CNode;
00239
00243 class CQuadNode
00244 {
00245 public:
00246 CQuadNode *Prev,*Next;
00247 CNode *Node;
00248
00249 CQuadNode() : Prev(NULL), Next(NULL), Node(NULL) {}
00250
00251
00252 void initRoot()
00253 {
00254 Prev= this;
00255 Next= this;
00256 Node= NULL;
00257 }
00258 };
00259
00262 class CBaseNode
00263 {
00264 public:
00265 CBaseNode *Prev,*Next;
00266 bool Selected;
00267 CBaseNode() {Prev= Next= NULL;}
00268 };
00269
00272 class CNode : public CBaseNode
00273 {
00274 public:
00275 T Elt;
00276
00277 NLMISC::CObjectVector<CQuadNode> QuadNodes;
00278 };
00279
00280 private:
00281 std::vector<CQuadNode> _Grid;
00282 sint _Size;
00283 sint _SizePower;
00284 float _EltSize;
00285 NLMISC::CMatrix _ChangeBasis;
00286
00287 CBaseNode _SelectedList;
00288 CBaseNode _UnSelectedList;
00289
00290 NLMISC::CBlockMemory<CNode> _NodeBlockMemory;
00291
00292
00293 private:
00294
00295
00296
00297 void initCons();
00298
00299
00300 void linkToRoot(CBaseNode &root, CBaseNode *ptr)
00301 {
00302 ptr->Prev= &root;
00303 ptr->Next= root.Next;
00304 ptr->Prev->Next= ptr;
00305 if(ptr->Next)
00306 ptr->Next->Prev= ptr;
00307 }
00308
00309 void initSelectStamps() const
00310 {
00311 if (_AlreadySelected.size() < _Grid.size())
00312 {
00313 _AlreadySelected.resize(_Grid.size(), _SelectStamp);
00314 }
00315 ++ _SelectStamp;
00316 if (_SelectStamp == 0)
00317 {
00318 std::fill(_AlreadySelected.begin(), _AlreadySelected.end(), (uint) ~0);
00319 }
00320 }
00321
00322
00323 void selectQuads(CVector bmin, CVector bmax, sint &x0, sint &x1, sint &y0, sint &y1)
00324 {
00325 CVector bminp, bmaxp;
00326 bminp= bmin;
00327 bmaxp= bmax;
00328 bmin.minof(bminp, bmaxp);
00329 bmax.maxof(bminp, bmaxp);
00330 bmin/= _EltSize;
00331 bmax/= _EltSize;
00332 x0= (sint)(floor(bmin.x));
00333 x1= (sint)(ceil(bmax.x));
00334 y0= (sint)(floor(bmin.y));
00335 y1= (sint)(ceil(bmax.y));
00336
00337
00338 if(x0==x1)
00339 x1++;
00340 if(y0==y1)
00341 y1++;
00342
00343
00344 if(x1-x0>=_Size)
00345 x0=0, x1= _Size;
00346 else
00347 {
00348 x0&= _Size-1;
00349 x1&= _Size-1;
00350 if(x1<=x0)
00351 x1+=_Size;
00352 }
00353 if(y1-y0>=_Size)
00354 y0=0, y1= _Size;
00355 else
00356 {
00357 y0&= _Size-1;
00358 y1&= _Size-1;
00359 if(y1<=y0)
00360 y1+=_Size;
00361 }
00362 }
00363
00364
00365 void addToSelection(CNode *ptr)
00366 {
00367
00368 if(!ptr->Selected)
00369 {
00370
00371 ptr->Prev->Next= ptr->Next;
00372 if(ptr->Next)
00373 ptr->Next->Prev= ptr->Prev;
00374
00375
00376 linkToRoot(_SelectedList, ptr);
00377
00378
00379 ptr->Selected= true;
00380 }
00381 }
00382
00383
00384 void addQuadNodeToSelection(CQuadNode &quad)
00385 {
00386
00387 nlassert(quad.Node==NULL);
00388 CQuadNode *qn= quad.Next;
00389
00390 while(qn!=&quad)
00391 {
00392 nlassert(qn->Node);
00393 addToSelection(qn->Node);
00394 qn= qn->Next;
00395 }
00396 }
00397
00398
00399 public:
00400
00401 class const_iterator
00402 {
00403 public:
00404 const_iterator() {_Ptr=NULL;}
00405 const_iterator(CNode *p) : _Ptr(p) {}
00406 const_iterator(const CIterator& x) : _Ptr(x._Ptr) {}
00407
00408 const T& operator*() const
00409 {return _Ptr->Elt; }
00410
00411
00412
00413 const_iterator& operator++()
00414 {_Ptr = (CNode*)(_Ptr->Next); return (*this); }
00415 const_iterator operator++(int)
00416 {const_iterator tmp = *this; ++*this; return (tmp); }
00417 const_iterator& operator--()
00418 {_Ptr = (CNode*)(_Ptr->Prev); return (*this); }
00419 const_iterator operator--(int)
00420 {const_iterator tmp = *this; --*this; return (tmp); }
00421 bool operator==(const const_iterator& x) const
00422 {return (_Ptr == x._Ptr); }
00423 bool operator!=(const const_iterator& x) const
00424 {return (!(*this == x)); }
00425 protected:
00426 CNode *_Ptr;
00427 friend class CQuadGrid<T>;
00428 friend class CIterator;
00429 };
00430
00431
00432 class CIterator : public const_iterator
00433 {
00434 public:
00435 CIterator() {this->_Ptr=NULL;}
00436 CIterator(CNode *p) : const_iterator(p) {}
00437 T& operator*() const
00438 {return this->_Ptr->Elt; }
00439
00440
00441
00442 CIterator& operator++()
00443 {this->_Ptr = (CNode*)(this->_Ptr->Next); return (*this); }
00444 CIterator operator++(int)
00445 {CIterator tmp = *this; ++*this; return (tmp); }
00446 CIterator& operator--()
00447 {this->_Ptr = (CNode*)(this->_Ptr->Prev); return (*this); }
00448 CIterator operator--(int)
00449 {CIterator tmp = *this; --*this; return (tmp); }
00450 bool operator==(const const_iterator& x) const
00451 {return (this->_Ptr == x._Ptr); }
00452 bool operator!=(const const_iterator& x) const
00453 {return (!(*this == x)); }
00454 protected:
00455 friend class CQuadGrid<T>;
00456 };
00457
00458
00459 };
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 template<class T> CQuadGrid<T>::CQuadGrid(uint memoryBlockSize) :
00480 _NodeBlockMemory(memoryBlockSize)
00481 {
00482 initCons();
00483 }
00484
00485 template<class T> CQuadGrid<T>::CQuadGrid(const CQuadGrid<T> &o) : _NodeBlockMemory(o._NodeBlockMemory)
00486 {
00487
00488
00489 initCons();
00490
00491 operator=(o);
00492 }
00493
00494 template<class T> void CQuadGrid<T>::initCons()
00495 {
00496 _ChangeBasis.identity();
00497
00498 create(16, 1);
00499 }
00500
00501 template<class T> CQuadGrid<T> &CQuadGrid<T>::operator=(const CQuadGrid<T> &o)
00502 {
00503
00504 if(this==&o)
00505 return *this;
00506
00507
00508 create(o._Size, o._EltSize);
00509 nlassert(_Grid.size()==o._Grid.size());
00510 nlassert(_SelectedList.Next==NULL);
00511 nlassert(_UnSelectedList.Next==NULL);
00512
00513
00514 _ChangeBasis= o._ChangeBasis;
00515
00516
00517 std::map<const CNode*, CNode *> srcNodeToDestNode;
00518 std::map<const CNode*, uint> srcNodeToIndexInQuadNodes;
00519
00520 for(uint i=0;i<_Grid.size();i++)
00521 {
00522 const CQuadNode &quadSrcRoot= o._Grid[i];
00523 CQuadNode &quadDstRoot= _Grid[i];
00524 const CQuadNode *quadSrcCur= quadSrcRoot.Next;
00525
00526 while(quadSrcCur!=&quadSrcRoot)
00527 {
00528 const CNode *srcNode= quadSrcCur->Node;
00529 nlassert(srcNode);
00530
00531
00532 CNode *dstNode= NULL;
00533 typename std::map<const CNode*, CNode *>::iterator it= srcNodeToDestNode.find(srcNode);
00534 if(it!=srcNodeToDestNode.end())
00535 {
00536 dstNode= it->second;
00537 }
00538
00539 else
00540 {
00541
00542 dstNode=_NodeBlockMemory.allocate();
00543 dstNode->Elt= srcNode->Elt;
00544 dstNode->QuadNodes.resize(srcNode->QuadNodes.size());
00545
00546
00547 linkToRoot(_UnSelectedList, dstNode);
00548
00549 dstNode->Selected= false;
00550
00551
00552 srcNodeToDestNode[srcNode]= dstNode;
00553
00554
00555 srcNodeToIndexInQuadNodes[srcNode]= 0;
00556 }
00557
00558
00559 uint index= srcNodeToIndexInQuadNodes[srcNode]++;
00560 nlassert(index<dstNode->QuadNodes.size());
00561 CQuadNode &quadDstCur= dstNode->QuadNodes[index];
00562
00563
00564 quadDstCur.Node= dstNode;
00565
00566 quadDstCur.Next= &quadDstRoot;
00567 quadDstCur.Prev= quadDstRoot.Prev;
00568 quadDstRoot.Prev->Next= &quadDstCur;
00569 quadDstRoot.Prev= &quadDstCur;
00570
00571
00572
00573 quadSrcCur= quadSrcCur->Next;
00574 }
00575 }
00576
00577 return *this;
00578 }
00579
00580 template<class T> CQuadGrid<T>::~CQuadGrid()
00581 {
00582 clear();
00583 _Grid.clear();
00584 }
00585
00586 template<class T> void CQuadGrid<T>::changeBase(const NLMISC::CMatrix& base)
00587 {
00588 _ChangeBasis= base;
00589 }
00590
00591 template<class T> void CQuadGrid<T>::create(uint size, float eltSize)
00592 {
00593
00594 clear();
00595 _Grid.clear();
00596
00597
00598 nlassert(NLMISC::isPowerOf2(size));
00599 nlassert(size<=32768);
00600 _SizePower= NLMISC::getPowerOf2(size);
00601 _Size=1<<_SizePower;
00602 _Grid.resize(_Size*_Size);
00603
00604 for(uint i=0;i<_Grid.size();i++)
00605 _Grid[i].initRoot();
00606
00607 nlassert(eltSize>0);
00608 _EltSize= eltSize;
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618 template<class T> void CQuadGrid<T>::clear()
00619 {
00620 CIterator it;
00621 selectAll();
00622 while( (it=begin())!=end())
00623 {
00624 erase(it);
00625 }
00626
00627
00628 _SelectedList.Next= NULL;
00629 _UnSelectedList.Next= NULL;
00630 }
00631
00632 template<class T> typename CQuadGrid<T>::CIterator CQuadGrid<T>::erase(typename CQuadGrid<T>::CIterator it)
00633 {
00634 CNode *ptr= it._Ptr;
00635
00636 if(!ptr)
00637 return end();
00638
00639
00640
00641 for(uint i=0;i<ptr->QuadNodes.size();i++)
00642 {
00643 CQuadNode &qn= ptr->QuadNodes[i];
00644
00645 qn.Next->Prev= qn.Prev;
00646 qn.Prev->Next= qn.Next;
00647 }
00648 ptr->QuadNodes.clear();
00649
00650
00651
00652
00653
00654 CBaseNode *next= NULL;
00655 next= ptr->Next;
00656 if(next)
00657 next->Prev=ptr->Prev;
00658 ptr->Prev->Next= next;
00659
00660 if(!ptr->Selected)
00661 next= NULL;
00662
00663 _NodeBlockMemory.free(ptr);
00664
00665
00666 return CIterator((CNode*)next);
00667 }
00668
00669 template<class T> typename CQuadGrid<T>::CIterator CQuadGrid<T>::insert(const NLMISC::CVector &bboxmin, const NLMISC::CVector &bboxmax, const T &val)
00670 {
00671 CVector bmin,bmax;
00672 bmin= _ChangeBasis*bboxmin;
00673 bmax= _ChangeBasis*bboxmax;
00674
00675
00676 CNode *ptr= _NodeBlockMemory.allocate();
00677 ptr->Elt= val;
00678
00679 linkToRoot(_UnSelectedList, ptr);
00680
00681 ptr->Selected= false;
00682
00683
00684
00685
00686 sint x0,y0;
00687 sint x1,y1;
00688 selectQuads(bmin, bmax, x0,x1, y0,y1);
00689
00690
00691 sint wn= x1-x0;
00692 sint hn= y1-y0;
00693 nlassert(wn>0 && hn>0);
00694
00695
00696 ptr->QuadNodes.resize(wn*hn);
00697
00698
00699
00700 sint x,y;
00701 for(y= y0;y<y1;y++)
00702 {
00703 sint xg,yg;
00704 sint xn,yn;
00705 yg= y &(_Size-1);
00706 yn= y-y0;
00707 for(x= x0;x<x1;x++)
00708 {
00709 xg= x &(_Size-1);
00710 xn= x-x0;
00711 CQuadNode &quadRoot= _Grid[(yg<<_SizePower)+xg];
00712 CQuadNode &quadNew= ptr->QuadNodes[yn*wn+xn];
00713
00714 quadNew.Node= ptr;
00715
00716 quadNew.Next= &quadRoot;
00717 quadNew.Prev= quadRoot.Prev;
00718 quadRoot.Prev->Next= &quadNew;
00719 quadRoot.Prev= &quadNew;
00720 }
00721 }
00722
00723 return CIterator(ptr);
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733 template<class T> void CQuadGrid<T>::clearSelection()
00734 {
00735 CBaseNode *ptr= _SelectedList.Next;
00736 while(ptr)
00737 {
00738
00739 CBaseNode *nextSelected= ptr->Next;
00740
00741
00742 linkToRoot(_UnSelectedList, ptr);
00743
00744
00745 ptr->Selected= false;
00746
00747
00748 ptr= nextSelected;
00749 }
00750
00751
00752 _SelectedList.Next= NULL;
00753 }
00754
00755 template<class T> void CQuadGrid<T>::selectAll()
00756 {
00757
00758
00759 CBaseNode *ptr= _UnSelectedList.Next;
00760 while(ptr)
00761 {
00762
00763 CBaseNode *nextUnSelected= ptr->Next;
00764
00765
00766 linkToRoot(_SelectedList, ptr);
00767
00768
00769 ptr->Selected= true;
00770
00771
00772 ptr= nextUnSelected;
00773 }
00774
00775
00776 _UnSelectedList.Next= NULL;
00777 }
00778
00779 template<class T> void CQuadGrid<T>::select(const NLMISC::CVector &bboxmin, const NLMISC::CVector &bboxmax)
00780 {
00781 CVector bmin,bmax;
00782 bmin= _ChangeBasis*bboxmin;
00783 bmax= _ChangeBasis*bboxmax;
00784
00785 clearSelection();
00786
00787
00788 sint x0,y0;
00789 sint x1,y1;
00790 selectQuads(bmin, bmax, x0,x1, y0,y1);
00791
00792 sint x,y;
00793 for(y= y0;y<y1;y++)
00794 {
00795 sint xe,ye;
00796 ye= y &(_Size-1);
00797 for(x= x0;x<x1;x++)
00798 {
00799 xe= x &(_Size-1);
00800 CQuadNode &quad= _Grid[(ye<<_SizePower)+xe];
00801 addQuadNodeToSelection(quad);
00802 }
00803 }
00804
00805 }
00806
00807
00808 template<class T> void CQuadGrid<T>::buildSelectionShape(TSelectionShape &dest, const NLMISC::CPolygon2D &poly) const
00809 {
00810 dest.clear();
00811 sint minY;
00812 uint numVerts = poly.Vertices.size();
00813 _ScaledPoly.Vertices.resize(numVerts);
00814 nlassert(_EltSize != 0.f);
00815 float invScale = 1.f / _EltSize;
00816 for(uint k = 0; k < numVerts; ++k)
00817 {
00818 CVector xformPos = _ChangeBasis * CVector(poly.Vertices[k]);
00819 _ScaledPoly.Vertices[k].set(poly.Vertices[k].x * invScale, poly.Vertices[k].y * invScale);
00820 }
00821 _ScaledPoly.computeOuterBorders(_PolyBorders, minY);
00822 if (_PolyBorders.empty()) return;
00823 initSelectStamps();
00824 sint numSegs = _PolyBorders.size();
00825 for (sint y = 0; y < numSegs; ++y)
00826 {
00827 sint currIndex = ((minY + y) & (_Size - 1)) << _SizePower;
00828 for (sint x = _PolyBorders[y].first; x <= _PolyBorders[y].second; ++x)
00829 {
00830 sint currX = x & (_Size - 1);
00831 uint index = (uint) (currX + currIndex);
00832 if (_AlreadySelected[index] != _SelectStamp)
00833 {
00834 _AlreadySelected[index] = _SelectStamp;
00835
00836 dest.push_back(index);
00837 }
00838 }
00839 }
00840 }
00841
00842
00843 template<class T> void CQuadGrid<T>::select(const TSelectionShape &shape)
00844 {
00845 clearSelection();
00846 for (TSelectionShape::const_iterator it = shape.begin(); it != shape.end(); ++it)
00847 {
00848 addQuadNodeToSelection(_Grid[*it]);
00849 }
00850 }
00851
00852
00853 template<class T>
00854 void CQuadGrid<T>::selectRay(const NLMISC::CVector &rayStart, const NLMISC::CVector &rayEnd)
00855 {
00856 clearSelection();
00857 CVector localRayStart = _ChangeBasis * rayStart;
00858 CVector localRayEnd = _ChangeBasis * rayEnd;
00859 float invScale = 1.f / _EltSize;
00860 NLMISC::CVector2f localRayStart2f(localRayStart.x * invScale, localRayStart.y * invScale);
00861 NLMISC::CVector2f localRayEnd2f(localRayEnd.x * invScale, localRayEnd.y * invScale);
00862 NLMISC::CVector2f localRayDir = localRayEnd2f - localRayStart2f;
00863 initSelectStamps();
00864 sint x, y;
00865 NLMISC::CGridTraversal::startTraverse(localRayStart2f, x, y);
00866 do
00867 {
00868 uint index = (x & (_Size - 1)) + ((y & (_Size - 1)) << _SizePower);
00869 if (_AlreadySelected[index] != _SelectStamp)
00870 {
00871 _AlreadySelected[index] = _SelectStamp;
00872 addQuadNodeToSelection(_Grid[index]);
00873 }
00874 }
00875 while (NLMISC::CGridTraversal::traverse(localRayStart2f, localRayDir, x, y));
00876 }
00877
00878
00879
00880 template<class T> typename CQuadGrid<T>::CIterator CQuadGrid<T>::begin()
00881 {
00882 return CIterator((CNode*)(_SelectedList.Next));
00883 }
00884
00885 template<class T> typename CQuadGrid<T>::CIterator CQuadGrid<T>::end()
00886 {
00887 return CIterator(NULL);
00888 }
00889
00890
00891 }
00892
00893
00894 #endif // NL_QUAD_GRID_H
00895
00896