0026479: Visualization, TKOpenGl - do not implicitly turn off stereo in OpenGl_Worksp...
[occt.git] / src / NCollection / NCollection_CellFilterNDim.hxx
CommitLineData
4b65fc77 1// Created on: 2015-06-17
2// Created by: Alexander Malyshev
3// Copyright (c) 2007-2015 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#ifndef NCollection_CellFilterNDim_HeaderFile
17#define NCollection_CellFilterNDim_HeaderFile
18
19#include <NCollection_CellFilter.hxx>
20#include <Standard_Real.hxx>
21#include <NCollection_List.hxx>
22#include <NCollection_Map.hxx>
23#include <NCollection_DataMap.hxx>
24#include <NCollection_IncAllocator.hxx>
25#include <NCollection_TypeDef.hxx>
26#include <NCollection_Array1.hxx>
27
28/**
29 * A data structure for sorting geometric objects (called targets) in
30 * n-dimensional space into cells, with associated algorithm for fast checking
31 * of coincidence (overlapping, intersection, etc.) with other objects
32 * (called here bullets).
33 *
34 * Purpose of this class is to add possibility to work with CellFilter with unknown
35 dimension count at compilation time.
36 *
37 * For more details look at base class NCollection_CellFilter.
38 *
39 */
40
41template <class Inspector> class NCollection_CellFilterNDim
42{
43public:
44 typedef TYPENAME Inspector::Target Target;
45 typedef TYPENAME Inspector::Point Point;
46
47public:
48
49 //! Constructor; initialized by dimension count and cell size.
50 //!
51 //! Note: the cell size must be ensured to be greater than
52 //! maximal co-ordinate of the involved points divided by INT_MAX,
53 //! in order to avoid integer overflow of cell index.
54 //!
55 //! By default cell size is 0, which is invalid; thus if default
56 //! constructor is used, the tool must be initialized later with
57 //! appropriate cell size by call to Reset()
58 NCollection_CellFilterNDim (const Standard_Integer theDim,
59 const Standard_Real theCellSize = 0,
60 const Handle(NCollection_IncAllocator)& theAlloc = 0)
61 : myCellSize(0, theDim - 1)
62 {
63 myDim = theDim;
64 Reset (theCellSize, theAlloc);
65 }
66
67 //! Constructor; initialized by dimension count and cell sizes along each dimension.
68 //! Note: the cell size in each dimension must be ensured to be greater than
69 //! maximal co-ordinate of the involved points by this dimension divided by INT_MAX,
70 //! in order to avoid integer overflow of cell index.
71 NCollection_CellFilterNDim (const Standard_Integer theDim,
72 const NCollection_Array1<Standard_Real> theCellSize,
73 const Handle(NCollection_IncAllocator)& theAlloc = 0)
74 : myCellSize(0, theDim - 1)
75 {
76 myDim = theDim;
77 Reset (theCellSize, theAlloc);
78 }
79
80 //! Clear the data structures, set new cell size and allocator
81 void Reset (Standard_Real theCellSize,
82 const Handle(NCollection_IncAllocator)& theAlloc=0)
83 {
84 for (int i=0; i < myDim; i++)
85 myCellSize(i) = theCellSize;
86 resetAllocator ( theAlloc );
87 }
88
89 //! Clear the data structures and set new cell sizes and allocator
90 void Reset (NCollection_Array1<Standard_Real> theCellSize,
91 const Handle(NCollection_IncAllocator)& theAlloc=0)
92 {
93 myCellSize = theCellSize;
94 resetAllocator ( theAlloc );
95 }
96
97 //! Adds a target object for further search at a point (into only one cell)
98 void Add (const Target& theTarget, const Point &thePnt)
99 {
100 Cell aCell (thePnt, myCellSize);
101 add (aCell, theTarget);
102 }
103
104 //! Adds a target object for further search in the range of cells
105 //! defined by two points (the first point must have all co-ordinates equal or
106 //! less than the same co-ordinate of the second point)
107 void Add (const Target& theTarget,
108 const Point &thePntMin, const Point &thePntMax)
109 {
110 // get cells range by minimal and maximal co-ordinates
111 Cell aCellMin (thePntMin, myCellSize);
112 Cell aCellMax (thePntMax, myCellSize);
113 Cell aCell = aCellMin;
114 // add object recursively into all cells in range
115 iterateAdd (myDim-1, aCell, aCellMin, aCellMax, theTarget);
116 }
117
118 //! Find a target object at a point and remove it from the structures.
119 //! For usage of this method "operator ==" should be defined for Target.
120 void Remove (const Target& theTarget, const Point &thePnt)
121 {
122 Cell aCell (thePnt, myCellSize);
123 remove (aCell, theTarget);
124 }
125
126 //! Find a target object in the range of cells defined by two points and
127 //! remove it from the structures
128 //! (the first point must have all co-ordinates equal or
129 //! less than the same co-ordinate of the second point).
130 //! For usage of this method "operator ==" should be defined for Target.
131 void Remove (const Target& theTarget,
132 const Point &thePntMin, const Point &thePntMax)
133 {
134 // get cells range by minimal and maximal co-ordinates
135 Cell aCellMin (thePntMin, myCellSize);
136 Cell aCellMax (thePntMax, myCellSize);
137 Cell aCell = aCellMin;
138 // remove object recursively from all cells in range
139 iterateRemove (myDim-1, aCell, aCellMin, aCellMax, theTarget);
140 }
141
142 //! Inspect all targets in the cell corresponding to the given point
143 void Inspect (const Point& thePnt, Inspector &theInspector)
144 {
145 Cell aCell (thePnt, myCellSize);
146 inspect (aCell, theInspector);
147 }
148
149 //! Inspect all targets in the cells range limited by two given points
150 //! (the first point must have all co-ordinates equal or
151 //! less than the same co-ordinate of the second point)
152 void Inspect (const Point& thePntMin, const Point& thePntMax,
153 Inspector &theInspector)
154 {
155 // get cells range by minimal and maximal co-ordinates
156 Cell aCellMin (thePntMin, myCellSize);
157 Cell aCellMax (thePntMax, myCellSize);
158 Cell aCell = aCellMin;
159 // inspect object recursively into all cells in range
160 iterateInspect (myDim-1, aCell,
161 aCellMin, aCellMax, theInspector);
162 }
163
164#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
165public: // work-around against obsolete SUN WorkShop 5.3 compiler
166#else
167protected:
168#endif
169
170 /**
171 * Auxiliary class for storing points belonging to the cell as the list
172 */
173 struct ListNode
174 {
175 ListNode()
176 {
177 // Empty constructor is forbidden.
178 Standard_NoSuchObject::Raise("NCollection_CellFilterNDim::ListNode()");
179 }
180
181 Target Object;
182 ListNode *Next;
183 };
184
185 /**
186 * Auxilary structure representing a cell in the space.
187 * Cells are stored in the map, each cell contains list of objects
188 * that belong to that cell.
189 */
190 struct Cell
191 {
192 public:
193
194 //! Constructor; computes cell indices
195 Cell (const Point& thePnt,
196 const NCollection_Array1<Standard_Real> theCellSize)
197 : index(0, theCellSize.Size() - 1),
198 Objects(0)
199 {
200 for (int i=0; i < theCellSize.Size(); i++)
201 {
202 Standard_Real val = (Standard_Real)(Inspector::Coord(i, thePnt) / theCellSize(i));
203 //If the value of index is greater than
204 //INT_MAX it is decreased correspondingly for the value of INT_MAX. If the value
205 //of index is less than INT_MIN it is increased correspondingly for the absolute
206 //value of INT_MIN.
207 index(i) = long((val > INT_MAX - 1) ? fmod(val, (Standard_Real) INT_MAX)
208 : (val < INT_MIN + 1) ? fmod(val, (Standard_Real) INT_MIN)
209 : val);
210 }
211 }
212
213 //! Copy constructor: ensure that list is not deleted twice
214 Cell (const Cell& theOther)
215 : index(0, theOther.index.Size() - 1)
216 {
217 (*this) = theOther;
218 }
219
220 //! Assignment operator: ensure that list is not deleted twice
221 void operator = (const Cell& theOther)
222 {
223 index = theOther.index;
224 Objects = theOther.Objects;
225 ((Cell&)theOther).Objects = 0;
226 }
227
228 //! Destructor; calls destructors for targets contained in the list
229 ~Cell ()
230 {
231 for ( ListNode* aNode = Objects; aNode; aNode = aNode->Next )
232 aNode->Object.~Target();
233 // note that list nodes need not to be freed, since IncAllocator is used
234 Objects = 0;
235 }
236
237 //! Compare cell with other one
238 Standard_Boolean IsEqual (const Cell& theOther) const
239 {
240 Standard_Integer myDim = theOther.index.Size();
241 for (int i=0; i < myDim; i++)
242 if ( index(i) != theOther.index(i) ) return Standard_False;
243 return Standard_True;
244 }
245
246 //! Compute hash code
247 Standard_Integer HashCode (const Standard_Integer theUpper) const
248 {
249 // number of bits per each dimension in the hash code
250 Standard_Integer myDim = index.Size();
251 const Standard_Size aShiftBits = (BITS(long)-1) / myDim;
252 long aCode=0;
253 for (int i=0; i < myDim; i++)
254 aCode = ( aCode << aShiftBits ) ^ index(i);
255 return (unsigned)aCode % theUpper;
256 }
257
258 public:
259 NCollection_Array1<long> index;
260 ListNode *Objects;
261 };
262
263 // definition of global functions is needed for map
264 friend Standard_Integer HashCode (const Cell &aCell, const Standard_Integer theUpper)
265 { return aCell.HashCode(theUpper); }
266 friend Standard_Boolean IsEqual (const Cell &aCell1, const Cell &aCell2)
267 { return aCell1.IsEqual(aCell2); }
268
269protected:
270
271 //! Reset allocator to the new one
272 void resetAllocator (const Handle(NCollection_IncAllocator)& theAlloc)
273 {
274 if ( theAlloc.IsNull() )
275 myAllocator = new NCollection_IncAllocator;
276 else
277 myAllocator = theAlloc;
278 myCells.Clear ( myAllocator );
279 }
280
281 //! Add a new target object into the specified cell
282 void add (const Cell& theCell, const Target& theTarget)
283 {
284 // add a new cell or get reference to existing one
285 Cell& aMapCell = (Cell&)myCells.Added (theCell);
286
287 // create a new list node and add it to the beginning of the list
288 ListNode* aNode = (ListNode*)myAllocator->Allocate(sizeof(ListNode));
289 new (&aNode->Object) Target (theTarget);
290 aNode->Next = aMapCell.Objects;
291 aMapCell.Objects = aNode;
292 }
293
294 //! Internal addition function, performing iteration for adjacent cells
295 //! by one dimension; called recursively to cover all dimensions
296 void iterateAdd (int idim, Cell &theCell,
297 const Cell& theCellMin, const Cell& theCellMax,
298 const Target& theTarget)
299 {
300 int start = theCellMin.index(idim);
301 int end = theCellMax.index(idim);
302 for (int i=start; i <= end; i++) {
303 theCell.index(idim) = i;
304 if ( idim ) // recurse
305 iterateAdd (idim-1, theCell, theCellMin, theCellMax, theTarget);
306 else // add to this cell
307 add (theCell, theTarget);
308 }
309 }
310
311 //! Remove the target object from the specified cell
312 void remove (const Cell& theCell, const Target& theTarget)
313 {
314 // check if any objects are recorded in that cell
315 if ( ! myCells.Contains (theCell) )
316 return;
317
318 // iterate by objects in the cell and check each
319 Cell& aMapCell = (Cell&)myCells.Added (theCell);
320 ListNode* aNode = aMapCell.Objects;
321 ListNode* aPrev = NULL;
322 while (aNode)
323 {
324 ListNode* aNext = aNode->Next;
325 if (Inspector::IsEqual (aNode->Object, theTarget))
326 {
327 aNode->Object.~Target();
328 (aPrev ? aPrev->Next : aMapCell.Objects) = aNext;
329 // note that aNode itself need not to be freed, since IncAllocator is used
330 }
331 else
332 aPrev = aNode;
333 aNode = aNext;
334 }
335 }
336
337 //! Internal removal function, performing iteration for adjacent cells
338 //! by one dimension; called recursively to cover all dimensions
339 void iterateRemove (int idim, Cell &theCell,
340 const Cell& theCellMin, const Cell& theCellMax,
341 const Target& theTarget)
342 {
343 int start = theCellMin.index(idim);
344 int end = theCellMax.index(idim);
345 for (int i=start; i <= end; i++) {
346 theCell.index(idim) = i;
347 if ( idim ) // recurse
348 iterateRemove (idim-1, theCell, theCellMin, theCellMax, theTarget);
349 else // remove from this cell
350 remove (theCell, theTarget);
351 }
352 }
353
354 //! Inspect the target objects in the specified cell.
355 void inspect (const Cell& theCell, Inspector& theInspector)
356 {
357 // check if any objects are recorded in that cell
358 if ( ! myCells.Contains (theCell) )
359 return;
360
361 // iterate by objects in the cell and check each
362 Cell& aMapCell = (Cell&)myCells.Added (theCell);
363 ListNode* aNode = aMapCell.Objects;
364 ListNode* aPrev = NULL;
365 while(aNode) {
366 ListNode* aNext = aNode->Next;
367 NCollection_CellFilter_Action anAction =
368 theInspector.Inspect (aNode->Object);
369 // delete items requested to be purged
370 if ( anAction == CellFilter_Purge ) {
371 aNode->Object.~Target();
372 (aPrev ? aPrev->Next : aMapCell.Objects) = aNext;
373 // note that aNode itself need not to be freed, since IncAllocator is used
374 }
375 else
376 aPrev = aNode;
377 aNode = aNext;
378 }
379 }
380
381 //! Inspect the target objects in the specified range of the cells
382 void iterateInspect (int idim, Cell &theCell,
383 const Cell& theCellMin, const Cell& theCellMax,
384 Inspector& theInspector)
385 {
386 int start = theCellMin.index(idim);
387 int end = theCellMax.index(idim);
388 for (int i=start; i <= end; i++) {
389 theCell.index(idim) = i;
390 if ( idim ) // recurse
391 iterateInspect (idim-1, theCell, theCellMin, theCellMax, theInspector);
392 else // inspect this cell
393 inspect (theCell, theInspector);
394 }
395 }
396
397protected:
398 Standard_Integer myDim;
399 Handle(NCollection_BaseAllocator) myAllocator;
400 NCollection_Map<Cell> myCells;
401 NCollection_Array1<Standard_Real> myCellSize;
402};
403
404#endif