Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:47:42

0001 // Created on: 2007-05-26
0002 // Created by: Andrey BETENEV
0003 // Copyright (c) 2007-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #ifndef NCollection_CellFilter_HeaderFile
0017 #define NCollection_CellFilter_HeaderFile
0018 
0019 #include <NCollection_LocalArray.hxx>
0020 #include <NCollection_Array1.hxx>
0021 #include <NCollection_Map.hxx>
0022 #include <NCollection_IncAllocator.hxx>
0023 #include <NCollection_TypeDef.hxx>
0024 
0025 //! Auxiliary enumeration serving as responce from method Inspect
0026 enum NCollection_CellFilter_Action 
0027 {
0028   CellFilter_Keep  = 0, //!< Target is needed and should be kept
0029   CellFilter_Purge = 1  //!< Target is not needed and can be removed from the current cell
0030 };
0031 
0032 /**
0033  * A data structure for sorting geometric objects (called targets) in 
0034  * n-dimensional space into cells, with associated algorithm for fast checking 
0035  * of coincidence (overlapping, intersection, etc.) with other objects 
0036  * (called here bullets).
0037  *
0038  * Description
0039  * 
0040  * The algorithm is based on hash map, thus it has linear time of initialization 
0041  * (O(N) where N is number of cells covered by added targets) and constant-time 
0042  * search for one bullet (more precisely, O(M) where M is number of cells covered 
0043  * by the bullet).
0044  *
0045  * The idea behind the algorithm is to separate each coordinate of the space
0046  * into equal-size cells. Note that this works well when cell size is 
0047  * approximately equal to the characteristic size of the involved objects 
0048  * (targets and bullets; including tolerance eventually used for coincidence 
0049  * check). 
0050  *
0051  * Usage
0052  *
0053  * The target objects to be searched are added to the tool by methods Add(); 
0054  * each target is classified as belonging to some cell(s). The data on cells 
0055  * (list of targets found in each one) are stored in the hash map with key being 
0056  * cumulative index of the cell by all coordinates.
0057  * Thus the time needed to find targets in some cell is O(1) * O(number of 
0058  * targets in the cell).
0059  *
0060  * As soon as all the targets are added, the algorithm is ready to check for 
0061  * coincidence.
0062  * To find the targets coincident with any given bullet, it checks all the 
0063  * candidate targets in the cell(s) covered by the bullet object 
0064  * (methods Inspect()).
0065  *
0066  * The methods Add() and Inspect() have two flavours each: one accepts
0067  * single point identifying one cell, another accept two points specifying
0068  * the range of cells. It should be noted that normally at least one of these
0069  * methods is called as for range of cells: either due to objects having non-
0070  * zero size, or in order to account for the tolerance when objects are points.
0071  *
0072  * The set of targets can be modified during the process: new targets can be
0073  * added by Add(), existing targets can be removed by Remove().
0074  *
0075  * Implementation
0076  *
0077  * The algorithm is implemented as template class, thus it is capable to 
0078  * work with objects of any type. The only argument of the template should be 
0079  * the specific class providing all necessary features required by the 
0080  * algorithm:
0081  *
0082  * - typedef "Target" defining type of target objects.
0083  *   This type must have copy constructor
0084  *
0085  * - typedef "Point" defining type of geometrical points used 
0086  *
0087  * - enum Dimension whose value must be dimension of the point
0088  *
0089  * - method Coord() returning value of the i-th coordinate of the point:
0090  *
0091  *   static Standard_Real Coord (int i, const Point& thePnt);
0092  *
0093  *   Note that index i is from 0 to Dimension-1.
0094  *
0095  * - method IsEqual() used by Remove() to identify objects to be removed:
0096  *
0097  *   Standard_Boolean IsEqual (const Target& theT1, const Target& theT2);
0098  *
0099  * - method Inspect() performing necessary actions on the candidate target 
0100  *   object (usially comparison with the currently checked bullet object):
0101  *
0102  *   NCollection_CellFilter_Action Inspect (const Target& theObject);
0103  *
0104  *   The returned value can be used to command CellFilter
0105  *   to remove the inspected item from the current cell; this allows
0106  *   to exclude the items that has been processed and are not needed any 
0107  *   more in further search (for better performance).
0108  *
0109  *   Note that method Inspect() can be const and/or virtual.
0110  */
0111 
0112 template <class Inspector> class NCollection_CellFilter
0113 {
0114 public:
0115   typedef TYPENAME Inspector::Target Target;
0116   typedef TYPENAME Inspector::Point  Point;
0117 
0118 public:
0119 
0120   //! Constructor; initialized by dimension count and cell size.
0121   //!
0122   //! Note: the cell size must be ensured to be greater than
0123   //! maximal coordinate of the involved points divided by INT_MAX,
0124   //! in order to avoid integer overflow of cell index.
0125   //! 
0126   //! By default cell size is 0, which is invalid; thus if default
0127   //! constructor is used, the tool must be initialized later with
0128   //! appropriate cell size by call to Reset()
0129   //! Constructor when dimension count is unknown at compilation time.
0130   NCollection_CellFilter (const Standard_Integer theDim,
0131                           const Standard_Real theCellSize = 0,
0132                           const Handle(NCollection_IncAllocator)& theAlloc = 0)
0133   : myCellSize(0, theDim - 1)
0134   {
0135     myDim = theDim;
0136     Reset (theCellSize, theAlloc);
0137   }
0138 
0139   //! Constructor when dimenstion count is known at compilation time.
0140   NCollection_CellFilter (const Standard_Real theCellSize = 0,
0141                           const Handle(NCollection_IncAllocator)& theAlloc = 0)
0142   : myCellSize(0, Inspector::Dimension - 1)
0143   {
0144     myDim = Inspector::Dimension;
0145     Reset (theCellSize, theAlloc);
0146   }
0147 
0148   //! Clear the data structures, set new cell size and allocator
0149   void Reset (Standard_Real theCellSize, 
0150               const Handle(NCollection_IncAllocator)& theAlloc=0)
0151   {
0152     for (int i=0; i < myDim; i++)
0153       myCellSize(i) = theCellSize;
0154     resetAllocator ( theAlloc );
0155   }
0156 
0157   //! Clear the data structures and set new cell sizes and allocator
0158   void Reset (NCollection_Array1<Standard_Real>& theCellSize, 
0159               const Handle(NCollection_IncAllocator)& theAlloc=0)
0160   {
0161     myCellSize = theCellSize;
0162     resetAllocator ( theAlloc );
0163   }
0164   
0165   //! Adds a target object for further search at a point (into only one cell)
0166   void Add (const Target& theTarget, const Point &thePnt)
0167   {
0168     Cell aCell (thePnt, myCellSize);
0169     add (aCell, theTarget);
0170   }
0171 
0172   //! Adds a target object for further search in the range of cells 
0173   //! defined by two points (the first point must have all coordinates equal or
0174   //! less than the same coordinate of the second point)
0175   void Add (const Target& theTarget, 
0176         const Point &thePntMin, const Point &thePntMax)
0177   {
0178     // get cells range by minimal and maximal coordinates
0179     Cell aCellMin (thePntMin, myCellSize);
0180     Cell aCellMax (thePntMax, myCellSize);
0181     Cell aCell = aCellMin;
0182     // add object recursively into all cells in range
0183     iterateAdd (myDim-1, aCell, aCellMin, aCellMax, theTarget);
0184   }
0185 
0186   //! Find a target object at a point and remove it from the structures.
0187   //! For usage of this method "operator ==" should be defined for Target.
0188   void Remove (const Target& theTarget, const Point &thePnt)
0189   {
0190     Cell aCell (thePnt, myCellSize);
0191     remove (aCell, theTarget);
0192   }
0193 
0194   //! Find a target object in the range of cells defined by two points and
0195   //! remove it from the structures
0196   //! (the first point must have all coordinates equal or
0197   //! less than the same coordinate of the second point).
0198   //! For usage of this method "operator ==" should be defined for Target.
0199   void Remove (const Target& theTarget, 
0200                const Point &thePntMin, const Point &thePntMax)
0201   {
0202     // get cells range by minimal and maximal coordinates
0203     Cell aCellMin (thePntMin, myCellSize);
0204     Cell aCellMax (thePntMax, myCellSize);
0205     Cell aCell = aCellMin;
0206     // remove object recursively from all cells in range
0207     iterateRemove (myDim-1, aCell, aCellMin, aCellMax, theTarget);
0208   }
0209 
0210   //! Inspect all targets in the cell corresponding to the given point
0211   void Inspect (const Point& thePnt, Inspector &theInspector) 
0212   {
0213     Cell aCell (thePnt, myCellSize);
0214     inspect (aCell, theInspector);
0215   }
0216 
0217   //! Inspect all targets in the cells range limited by two given points
0218   //! (the first point must have all coordinates equal or
0219   //! less than the same coordinate of the second point)
0220   void Inspect (const Point& thePntMin, const Point& thePntMax, 
0221                 Inspector &theInspector) 
0222   {
0223     // get cells range by minimal and maximal coordinates
0224     Cell aCellMin (thePntMin, myCellSize);
0225     Cell aCellMax (thePntMax, myCellSize);
0226     Cell aCell = aCellMin;
0227     // inspect object recursively into all cells in range
0228     iterateInspect (myDim-1, aCell, 
0229                     aCellMin, aCellMax, theInspector);
0230   }
0231 
0232 #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
0233 public: // work-around against obsolete SUN WorkShop 5.3 compiler
0234 #else
0235 protected:
0236 #endif
0237  
0238   /**
0239    * Auxiliary class for storing points belonging to the cell as the list
0240    */
0241   struct ListNode
0242   {
0243     ListNode()
0244     {
0245       // Empty constructor is forbidden.
0246       throw Standard_NoSuchObject("NCollection_CellFilter::ListNode()");
0247     }
0248 
0249     Target Object;
0250     ListNode *Next;
0251   };
0252 
0253   //! Cell index type.
0254   typedef Standard_Integer Cell_IndexType;
0255 
0256   /**
0257    * Auxiliary structure representing a cell in the space.
0258    * Cells are stored in the map, each cell contains list of objects 
0259    * that belong to that cell.
0260    */
0261   struct Cell
0262   {
0263   public:
0264 
0265     //! Constructor; computes cell indices
0266     Cell (const Point& thePnt, 
0267           const NCollection_Array1<Standard_Real>& theCellSize)
0268       : index(theCellSize.Size()),
0269         Objects(0)
0270     {
0271       for (int i = 0; i < theCellSize.Size(); i++)
0272       {
0273           Standard_Real aVal = (Standard_Real)(Inspector::Coord(i, thePnt) / theCellSize(theCellSize.Lower() + i));
0274           //If the value of index is greater than
0275           //INT_MAX it is decreased correspondingly for the value of INT_MAX. If the value
0276           //of index is less than INT_MIN it is increased correspondingly for the absolute
0277           //value of INT_MIN.
0278           index[i] = Cell_IndexType((aVal > INT_MAX - 1) ? fmod(aVal, (Standard_Real) INT_MAX)
0279                                                          : (aVal < INT_MIN + 1) ? fmod(aVal, (Standard_Real) INT_MIN)
0280                                                                                 : aVal);
0281       }
0282     }
0283 
0284     //! Copy constructor: ensure that list is not deleted twice
0285     Cell (const Cell& theOther)
0286       : index(theOther.index.Size())
0287     {
0288       (*this) = theOther;
0289     }
0290 
0291     //! Assignment operator: ensure that list is not deleted twice
0292     void operator = (const Cell& theOther)
0293     {
0294       Standard_Integer aDim = Standard_Integer(theOther.index.Size());
0295       for(Standard_Integer anIdx = 0; anIdx < aDim; anIdx++)
0296         index[anIdx] = theOther.index[anIdx];
0297 
0298       Objects = theOther.Objects;
0299       ((Cell&)theOther).Objects = 0;
0300     }
0301 
0302     //! Destructor; calls destructors for targets contained in the list
0303     ~Cell ()
0304     {
0305       for ( ListNode* aNode = Objects; aNode; aNode = aNode->Next )
0306         aNode->Object.~Target();
0307       // note that list nodes need not to be freed, since IncAllocator is used
0308       Objects = 0;
0309     }
0310 
0311     //! Compare cell with other one
0312     Standard_Boolean IsEqual (const Cell& theOther) const
0313     {
0314       Standard_Integer aDim = Standard_Integer(theOther.index.Size());
0315       for (int i=0; i < aDim; i++) 
0316         if ( index[i] != theOther.index[i] ) return Standard_False;
0317       return Standard_True;
0318     }
0319 
0320     //! Returns hash code for this cell, in the range [1, theUpperBound]
0321     //! @param theUpperBound the upper bound of the range a computing hash code must be within
0322     //! @return a computed hash code, in the range [1, theUpperBound]
0323     Standard_Integer HashCode (const Standard_Integer theUpperBound) const
0324     {
0325       // number of bits per each dimension in the hash code
0326       const std::size_t aDim       = index.Size();
0327       const std::size_t aShiftBits = (BITS (Cell_IndexType) - 1) / aDim;
0328       std::size_t       aCode      = 0;
0329 
0330       for (std::size_t i = 0; i < aDim; ++i)
0331       {
0332         aCode = (aCode << aShiftBits) ^ std::size_t(index[i]);
0333       }
0334 
0335       return ::HashCode(aCode, theUpperBound);
0336     }
0337 
0338   public:
0339     NCollection_LocalArray<Cell_IndexType, 10> index;
0340     ListNode *Objects;
0341   };
0342   
0343   //! Returns hash code for the given cell, in the range [1, theUpperBound]
0344   //! @param theCell the cell object which hash code is to be computed
0345   //! @param theUpperBound the upper bound of the range a computing hash code must be within
0346   //! @return a computed hash code, in the range [1, theUpperBound]
0347   friend Standard_Integer HashCode (const Cell& theCell, const Standard_Integer theUpperBound)
0348   {
0349     return theCell.HashCode (theUpperBound);
0350   }
0351 
0352   friend Standard_Boolean IsEqual (const Cell &aCell1, const Cell &aCell2)
0353   { return aCell1.IsEqual(aCell2); }
0354 
0355 protected:
0356 
0357   //! Reset allocator to the new one
0358   void resetAllocator (const Handle(NCollection_IncAllocator)& theAlloc)
0359   {
0360     if ( theAlloc.IsNull() )
0361       myAllocator = new NCollection_IncAllocator;
0362     else 
0363       myAllocator = theAlloc;
0364     myCells.Clear ( myAllocator );
0365   }
0366   
0367   //! Add a new target object into the specified cell
0368   void add (const Cell& theCell, const Target& theTarget)
0369   {
0370     // add a new cell or get reference to existing one
0371     Cell& aMapCell = (Cell&)myCells.Added (theCell);
0372 
0373     // create a new list node and add it to the beginning of the list
0374     ListNode* aNode = (ListNode*)myAllocator->Allocate(sizeof(ListNode));
0375     new (&aNode->Object) Target (theTarget);
0376     aNode->Next = aMapCell.Objects;
0377     aMapCell.Objects = aNode;
0378   }
0379 
0380   //! Internal addition function, performing iteration for adjacent cells
0381   //! by one dimension; called recursively to cover all dimensions
0382   void iterateAdd (int idim, Cell &theCell, 
0383            const Cell& theCellMin, const Cell& theCellMax, 
0384                    const Target& theTarget)
0385   {
0386     const Cell_IndexType aStart = theCellMin.index[idim];
0387     const Cell_IndexType anEnd  = theCellMax.index[idim];
0388     for (Cell_IndexType i = aStart; i <= anEnd; ++i)
0389     {
0390       theCell.index[idim] = i;
0391       if ( idim ) // recurse
0392       {
0393         iterateAdd (idim-1, theCell, theCellMin, theCellMax, theTarget);
0394       }
0395       else // add to this cell
0396       {
0397         add (theCell, theTarget);
0398       }
0399     }
0400   }
0401   
0402   //! Remove the target object from the specified cell
0403   void remove (const Cell& theCell, const Target& theTarget)
0404   {
0405     // check if any objects are recorded in that cell
0406     if ( ! myCells.Contains (theCell) ) 
0407       return;
0408 
0409     // iterate by objects in the cell and check each
0410     Cell& aMapCell = (Cell&)myCells.Added (theCell);
0411     ListNode* aNode = aMapCell.Objects;
0412     ListNode* aPrev = NULL;
0413     while (aNode)
0414     {
0415       ListNode* aNext = aNode->Next;
0416       if (Inspector::IsEqual (aNode->Object, theTarget))
0417       {
0418         aNode->Object.~Target();
0419         (aPrev ? aPrev->Next : aMapCell.Objects) = aNext;
0420         // note that aNode itself need not to be freed, since IncAllocator is used
0421       }
0422       else
0423         aPrev = aNode;
0424       aNode = aNext;
0425     }
0426   }
0427 
0428   //! Internal removal function, performing iteration for adjacent cells
0429   //! by one dimension; called recursively to cover all dimensions
0430   void iterateRemove (int idim, Cell &theCell, 
0431                       const Cell& theCellMin, const Cell& theCellMax, 
0432                       const Target& theTarget)
0433   {
0434     const Cell_IndexType aStart = theCellMin.index[idim];
0435     const Cell_IndexType anEnd  = theCellMax.index[idim];
0436     for (Cell_IndexType i = aStart; i <= anEnd; ++i)
0437     {
0438       theCell.index[idim] = i;
0439       if ( idim ) // recurse
0440       {
0441         iterateRemove (idim-1, theCell, theCellMin, theCellMax, theTarget);
0442       }
0443       else // remove from this cell
0444       {
0445         remove (theCell, theTarget);
0446       }
0447     }
0448   }
0449 
0450   //! Inspect the target objects in the specified cell.
0451   void inspect (const Cell& theCell, Inspector& theInspector) 
0452   {
0453     // check if any objects are recorded in that cell
0454     if ( ! myCells.Contains (theCell) ) 
0455       return;
0456 
0457     // iterate by objects in the cell and check each
0458     Cell& aMapCell = (Cell&)myCells.Added (theCell);
0459     ListNode* aNode = aMapCell.Objects;
0460     ListNode* aPrev = NULL;
0461     while(aNode) {
0462       ListNode* aNext = aNode->Next;
0463       NCollection_CellFilter_Action anAction = 
0464         theInspector.Inspect (aNode->Object);
0465       // delete items requested to be purged
0466       if ( anAction == CellFilter_Purge ) {
0467         aNode->Object.~Target();
0468         (aPrev ? aPrev->Next : aMapCell.Objects) = aNext;
0469         // note that aNode itself need not to be freed, since IncAllocator is used
0470       }
0471       else
0472         aPrev = aNode;
0473       aNode = aNext;      
0474     }
0475   }
0476 
0477   //! Inspect the target objects in the specified range of the cells
0478   void iterateInspect (int idim, Cell &theCell, 
0479                    const Cell& theCellMin, const Cell& theCellMax, 
0480                        Inspector& theInspector) 
0481   {
0482     const Cell_IndexType aStart = theCellMin.index[idim];
0483     const Cell_IndexType anEnd  = theCellMax.index[idim];
0484     for (Cell_IndexType i = aStart; i <= anEnd; ++i)
0485     {
0486       theCell.index[idim] = i;
0487       if ( idim ) // recurse
0488       {
0489         iterateInspect (idim-1, theCell, theCellMin, theCellMax, theInspector);
0490       }
0491       else // inspect this cell
0492       {
0493         inspect (theCell, theInspector);
0494       }
0495     }
0496   }
0497 
0498 protected:
0499   Standard_Integer myDim;
0500   Handle(NCollection_BaseAllocator) myAllocator;
0501   NCollection_Map<Cell>             myCells;
0502   NCollection_Array1<Standard_Real> myCellSize;
0503 };
0504 
0505 /**
0506  * Base class defining part of the Inspector interface 
0507  * for CellFilter algorithm, working with gp_XYZ points in 3d space
0508  */
0509 
0510 class gp_XYZ;
0511 struct NCollection_CellFilter_InspectorXYZ
0512 {
0513   //! Points dimension
0514   enum { Dimension = 3 };
0515 
0516   //! Points type
0517   typedef gp_XYZ Point;
0518 
0519   //! Access to coordinate
0520   static Standard_Real Coord (int i, const Point &thePnt) { return thePnt.Coord(i+1); }
0521   
0522   //! Auxiliary method to shift point by each coordinate on given value;
0523   //! useful for preparing a points range for Inspect with tolerance
0524   Point Shift (const Point& thePnt, Standard_Real theTol) const 
0525   { return Point (thePnt.X() + theTol, thePnt.Y() + theTol, thePnt.Z() + theTol); }
0526 };
0527 
0528 /**
0529  * Base class defining part of the Inspector interface 
0530  * for CellFilter algorithm, working with gp_XY points in 2d space
0531  */
0532 
0533 class gp_XY;
0534 struct NCollection_CellFilter_InspectorXY
0535 {
0536   //! Points dimension
0537   enum { Dimension = 2 };
0538 
0539   //! Points type
0540   typedef gp_XY Point;
0541 
0542   //! Access to coordinate
0543   static Standard_Real Coord (int i, const Point &thePnt) { return thePnt.Coord(i+1); }
0544 
0545   //! Auxiliary method to shift point by each coordinate on given value;
0546   //! useful for preparing a points range for Inspect with tolerance
0547   Point Shift (const Point& thePnt, Standard_Real theTol) const 
0548   { return Point (thePnt.X() + theTol, thePnt.Y() + theTol); }
0549 };
0550 
0551 #endif