0031511: Point Cloud Rendering, Volume Rendering - reuse Graphic3d_CullingTool
[occt.git] / src / Graphic3d / Graphic3d_Layer.cxx
1 // Copyright (c) 2011-2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <Graphic3d_Layer.hxx>
15
16 #include <Graphic3d_CStructure.hxx>
17 #include <Graphic3d_CullingTool.hxx>
18
19 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Layer, Standard_Transient)
20
21 // =======================================================================
22 // function : Graphic3d_Layer
23 // purpose  :
24 // =======================================================================
25 Graphic3d_Layer::Graphic3d_Layer (Graphic3d_ZLayerId theId,
26                                   Standard_Integer theNbPriorities,
27                                   const Handle(Select3D_BVHBuilder3d)& theBuilder)
28 : myArray                     (0, theNbPriorities - 1),
29   myNbStructures              (0),
30   myNbStructuresNotCulled     (0),
31   myLayerId                   (theId),
32   myBVHPrimitivesTrsfPers     (theBuilder),
33   myBVHIsLeftChildQueuedFirst (Standard_True),
34   myIsBVHPrimitivesNeedsReset (Standard_False)
35 {
36   myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
37 }
38
39 // =======================================================================
40 // function : ~Graphic3d_Layer
41 // purpose  :
42 // =======================================================================
43 Graphic3d_Layer::~Graphic3d_Layer()
44 {
45   //
46 }
47
48 // =======================================================================
49 // function : Add
50 // purpose  :
51 // =======================================================================
52 void Graphic3d_Layer::Add (const Graphic3d_CStructure* theStruct,
53                            Standard_Integer thePriority,
54                            Standard_Boolean isForChangePriority)
55 {
56   const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1);
57   if (theStruct == NULL)
58   {
59     return;
60   }
61
62   myArray (anIndex).Add (theStruct);
63   if (theStruct->IsAlwaysRendered())
64   {
65     theStruct->MarkAsNotCulled();
66     if (!isForChangePriority)
67     {
68       myAlwaysRenderedMap.Add (theStruct);
69     }
70   }
71   else if (!isForChangePriority)
72   {
73     if (theStruct->TransformPersistence().IsNull())
74     {
75       myBVHPrimitives.Add (theStruct);
76     }
77     else
78     {
79       myBVHPrimitivesTrsfPers.Add (theStruct);
80     }
81   }
82   ++myNbStructures;
83 }
84
85 // =======================================================================
86 // function : Remove
87 // purpose  :
88 // =======================================================================
89 bool Graphic3d_Layer::Remove (const Graphic3d_CStructure* theStruct,
90                               Standard_Integer& thePriority,
91                               Standard_Boolean isForChangePriority)
92 {
93   if (theStruct == NULL)
94   {
95     thePriority = -1;
96     return false;
97   }
98
99   const Standard_Integer aNbPriorities = myArray.Length();
100   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
101   {
102     Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
103     const Standard_Integer anIndex = aStructures.FindIndex (theStruct);
104     if (anIndex == 0)
105     {
106       continue;
107     }
108
109     aStructures.Swap (anIndex, aStructures.Size());
110     aStructures.RemoveLast();
111
112     if (!isForChangePriority)
113     {
114       Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered();
115       if (!isAlwaysRend)
116       {
117         if (!myBVHPrimitives.Remove (theStruct))
118         {
119           if (!myBVHPrimitivesTrsfPers.Remove (theStruct))
120           {
121             isAlwaysRend = Standard_True;
122           }
123         }
124       }
125       if (isAlwaysRend)
126       {
127         const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct);
128         if (anIndex2 != 0)
129         {
130           myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2);
131           myAlwaysRenderedMap.RemoveLast();
132         }
133       }
134     }
135     --myNbStructures;
136     thePriority = aPriorityIter;
137     return true;
138   }
139
140   thePriority = -1;
141   return false;
142 }
143
144 // =======================================================================
145 // function : InvalidateBVHData
146 // purpose  :
147 // =======================================================================
148 void Graphic3d_Layer::InvalidateBVHData()
149 {
150   myIsBVHPrimitivesNeedsReset = Standard_True;
151 }
152
153 //! Calculate a finite bounding box of infinite object as its middle point.
154 inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
155 {
156   // bounding borders of infinite line has been calculated as own point in center of this line
157   const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin();
158   return aDiagVec.SquareModulus() >= 500000.0 * 500000.0
159        ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5)
160        : Graphic3d_BndBox3d();
161 }
162
163 //! Return true if at least one vertex coordinate out of float range.
164 inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox)
165 {
166   return Abs (theBndBox.CornerMax().x()) >= ShortRealLast()
167       || Abs (theBndBox.CornerMax().y()) >= ShortRealLast()
168       || Abs (theBndBox.CornerMax().z()) >= ShortRealLast()
169       || Abs (theBndBox.CornerMin().x()) >= ShortRealLast()
170       || Abs (theBndBox.CornerMin().y()) >= ShortRealLast()
171       || Abs (theBndBox.CornerMin().z()) >= ShortRealLast();
172 }
173
174 // =======================================================================
175 // function : BoundingBox
176 // purpose  :
177 // =======================================================================
178 Bnd_Box Graphic3d_Layer::BoundingBox (Standard_Integer theViewId,
179                                       const Handle(Graphic3d_Camera)& theCamera,
180                                       Standard_Integer theWindowWidth,
181                                       Standard_Integer theWindowHeight,
182                                       Standard_Boolean theToIncludeAuxiliary) const
183 {
184   updateBVH();
185
186   const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1;
187   const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
188   const Graphic3d_Mat4d& aWorldViewMat  = theCamera->OrientationMatrix();
189   if (myIsBoundingBoxNeedsReset[aBoxId])
190   {
191     // Recompute layer bounding box
192     myBoundingBox[aBoxId].SetVoid();
193
194     for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
195     {
196       const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
197       for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
198       {
199         const Graphic3d_CStructure* aStructure = aStructIter.Value();
200         if (!aStructure->IsVisible (theViewId))
201         {
202           continue;
203         }
204
205         // "FitAll" operation ignores object with transform persistence parameter
206         // but adds transform persistence point in a bounding box of layer (only zoom pers. objects).
207         if (!aStructure->TransformPersistence().IsNull())
208         {
209           if (!theToIncludeAuxiliary
210             && aStructure->TransformPersistence()->IsZoomOrRotate())
211           {
212             const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint();
213             myBoundingBox[aBoxId].Add (anAnchor);
214             continue;
215           }
216           // Panning and 2d persistence apply changes to projection or/and its translation components.
217           // It makes them incompatible with z-fitting algorithm. Ignored by now.
218           else if (!theToIncludeAuxiliary
219                  || aStructure->TransformPersistence()->IsTrihedronOr2d())
220           {
221             continue;
222           }
223         }
224
225         Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
226         if (!aBox.IsValid())
227         {
228           continue;
229         }
230
231         if (aStructure->IsInfinite
232         && !theToIncludeAuxiliary)
233         {
234           // include center of infinite object
235           aBox = centerOfinfiniteBndBox (aBox);
236         }
237
238         if (!aStructure->TransformPersistence().IsNull())
239         {
240           aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
241         }
242
243         // skip too big boxes to prevent float overflow at camera parameters calculation
244         if (aBox.IsValid()
245         && !isInfiniteBndBox (aBox))
246         {
247           myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
248           myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
249         }
250       }
251     }
252
253     myIsBoundingBoxNeedsReset[aBoxId] = false;
254   }
255
256   Bnd_Box aResBox = myBoundingBox[aBoxId];
257   if (!theToIncludeAuxiliary
258     || myAlwaysRenderedMap.IsEmpty())
259   {
260     return aResBox;
261   }
262
263   // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit
264   for (NCollection_IndexedMap<const Graphic3d_CStructure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next())
265   {
266     const Graphic3d_CStructure* aStructure = aStructIter.Value();
267     if (!aStructure->IsVisible (theViewId))
268     {
269       continue;
270     }
271     else if (aStructure->TransformPersistence().IsNull()
272          || !aStructure->TransformPersistence()->IsTrihedronOr2d())
273     {
274       continue;
275     }
276
277     Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
278     if (!aBox.IsValid())
279     {
280       continue;
281     }
282
283     aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
284     if (aBox.IsValid()
285     && !isInfiniteBndBox (aBox))
286     {
287       aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z()));
288       aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z()));
289     }
290   }
291
292   return aResBox;
293 }
294
295 // =======================================================================
296 // function : considerZoomPersistenceObjects
297 // purpose  :
298 // =======================================================================
299 Standard_Real Graphic3d_Layer::considerZoomPersistenceObjects (Standard_Integer theViewId,
300                                                                const Handle(Graphic3d_Camera)& theCamera,
301                                                                Standard_Integer theWindowWidth,
302                                                                Standard_Integer theWindowHeight) const
303 {
304   if (NbOfTransformPersistenceObjects() == 0)
305   {
306     return 1.0;
307   }
308
309   const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix();
310   const Graphic3d_Mat4d& aWorldViewMat  = theCamera->OrientationMatrix();
311   Standard_Real          aMaxCoef       = -std::numeric_limits<double>::max();
312
313   for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
314   {
315     const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
316     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
317     {
318       const Graphic3d_CStructure* aStructure = aStructIter.Value();
319       if (!aStructure->IsVisible (theViewId)
320        ||  aStructure->TransformPersistence().IsNull()
321        || !aStructure->TransformPersistence()->IsZoomOrRotate())
322       {
323         continue;
324       }
325
326       Graphic3d_BndBox3d aBox = aStructure->BoundingBox();
327       if (!aBox.IsValid())
328       {
329         continue;
330       }
331
332       aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox);
333
334       const BVH_Vec3d&       aCornerMin           = aBox.CornerMin();
335       const BVH_Vec3d&       aCornerMax           = aBox.CornerMax();
336       const Standard_Integer aNbOfPoints          = 8;
337       const gp_Pnt           aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()),
338                                                       gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()),
339                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()),
340                                                       gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()),
341                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()),
342                                                       gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()),
343                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()),
344                                                       gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) };
345       gp_Pnt aConvertedPoints[aNbOfPoints];
346       Standard_Real aConvertedMinX =  std::numeric_limits<double>::max();
347       Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max();
348       Standard_Real aConvertedMinY =  std::numeric_limits<double>::max();
349       Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max();
350       for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx)
351       {
352         aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]);
353
354         aConvertedMinX          = Min (aConvertedMinX, aConvertedPoints[anIdx].X());
355         aConvertedMaxX          = Max (aConvertedMaxX, aConvertedPoints[anIdx].X());
356
357         aConvertedMinY          = Min (aConvertedMinY, aConvertedPoints[anIdx].Y());
358         aConvertedMaxY          = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y());
359       }
360
361       const Standard_Boolean isBigObject  = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0)  // width  of zoom pers. object greater than width  of window
362                                          || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window
363       const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0)
364                                               && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0)
365                                               && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0)
366                                               && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0);
367       if (isBigObject || isAlreadyInScreen)
368       {
369         continue;
370       }
371
372       const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint();
373       gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint);
374       aConvertedTPPoint.SetZ (0.0);
375
376       if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion())
377       {
378         continue;
379       }
380
381       Standard_Real aShiftX = 0.0;
382       if (aConvertedMinX < -1.0)
383       {
384         aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX));
385       }
386       else if (aConvertedMaxX > 1.0)
387       {
388         aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0));
389       }
390
391       Standard_Real aShiftY = 0.0;
392       if (aConvertedMinY < -1.0)
393       {
394         aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY));
395       }
396       else if (aConvertedMaxY > 1.0)
397       {
398         aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0));
399       }
400
401       const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX;
402       const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY;
403       if (aDifX > Precision::Confusion())
404       {
405         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX);
406       }
407       if (aDifY > Precision::Confusion())
408       {
409         aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY);
410       }
411     }
412   }
413
414   return (aMaxCoef > 0.0) ? aMaxCoef : 1.0;
415 }
416
417 // =======================================================================
418 // function : updateBVH
419 // purpose  :
420 // =======================================================================
421 void Graphic3d_Layer::updateBVH() const
422 {
423   if (!myIsBVHPrimitivesNeedsReset)
424   {
425     return;
426   }
427
428   myBVHPrimitives.Clear();
429   myBVHPrimitivesTrsfPers.Clear();
430   myAlwaysRenderedMap.Clear();
431   myIsBVHPrimitivesNeedsReset = Standard_False;
432   for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
433   {
434     const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
435     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
436     {
437       const Graphic3d_CStructure* aStruct = aStructIter.Value();
438       if (aStruct->IsAlwaysRendered())
439       {
440         aStruct->MarkAsNotCulled();
441         myAlwaysRenderedMap.Add (aStruct);
442       }
443       else if (aStruct->TransformPersistence().IsNull())
444       {
445         myBVHPrimitives.Add (aStruct);
446       }
447       else
448       {
449         myBVHPrimitivesTrsfPers.Add (aStruct);
450       }
451     }
452   }
453 }
454
455 namespace
456 {
457   //! This structure describes the node in BVH
458   struct NodeInStack
459   {
460     NodeInStack (Standard_Integer theId = 0,
461                  Standard_Boolean theIsFullInside = false) : Id (theId), IsFullInside (theIsFullInside) {}
462
463     Standard_Integer Id;           //!< node identifier
464     Standard_Boolean IsFullInside; //!< if the node is completely inside
465   };
466 }
467
468 // =======================================================================
469 // function : UpdateCulling
470 // purpose  :
471 // =======================================================================
472 void Graphic3d_Layer::UpdateCulling (Standard_Integer theViewId,
473                                      const Graphic3d_CullingTool& theSelector,
474                                      const Graphic3d_RenderingParams::FrustumCulling theFrustumCullingState)
475 {
476   updateBVH();
477
478   myNbStructuresNotCulled = myNbStructures;
479   if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_NoUpdate)
480   {
481     Standard_Boolean toTraverse = (theFrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On);
482     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next())
483     {
484       const Graphic3d_CStructure* aStruct = aStructIter.Value();
485       aStruct->SetCulled (toTraverse);
486     }
487     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next())
488     {
489       const Graphic3d_CStructure* aStruct = aStructIter.Value();
490       aStruct->SetCulled (toTraverse);
491     }
492   }
493
494   if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_On)
495   {
496     return;
497   }
498   if (myBVHPrimitives        .Size() == 0
499    && myBVHPrimitivesTrsfPers.Size() == 0)
500   {
501     return;
502   }
503
504   myNbStructuresNotCulled = myAlwaysRenderedMap.Extent();
505   Graphic3d_CullingTool::CullingContext aCullCtx;
506   theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance());
507   theSelector.SetCullingSize    (aCullCtx, myLayerSettings.CullingSize());
508   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
509   {
510     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
511     opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
512     if (isTrsfPers)
513     {
514       if (myBVHPrimitivesTrsfPers.Size() == 0)
515         continue;
516
517       const Graphic3d_Mat4d& aProjection            = theSelector.ProjectionMatrix();
518       const Graphic3d_Mat4d& aWorldView             = theSelector.WorldViewMatrix();
519       const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState();
520       const Standard_Integer aViewportWidth         = theSelector.ViewportWidth();
521       const Standard_Integer aViewportHeight        = theSelector.ViewportHeight();
522
523       aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
524     }
525     else
526     {
527       if (myBVHPrimitives.Size() == 0)
528         continue;
529
530       aBVHTree = myBVHPrimitives.BVH();
531     }
532
533     const bool toCheckFullInside = true;
534     NodeInStack aNode (0, toCheckFullInside); // a root node
535     if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0), toCheckFullInside ? &aNode.IsFullInside : NULL))
536     {
537       continue;
538     }
539
540     NodeInStack aStack[BVH_Constants_MaxTreeDepth];
541     Standard_Integer aHead = -1;
542     for (;;)
543     {
544       if (!aBVHTree->IsOuter (aNode.Id))
545       {
546         NodeInStack aLeft (aBVHTree->Child<0> (aNode.Id), toCheckFullInside);
547         NodeInStack aRight(aBVHTree->Child<1> (aNode.Id), toCheckFullInside);
548         bool isLeftChildIn = true, isRightChildIn = true;
549         if (aNode.IsFullInside)
550         {
551           // small size should be always checked
552           isLeftChildIn  = !theSelector.IsTooSmall (aCullCtx, aBVHTree->MinPoint (aLeft.Id),  aBVHTree->MaxPoint (aLeft.Id));
553           isRightChildIn = !theSelector.IsTooSmall (aCullCtx, aBVHTree->MinPoint (aRight.Id), aBVHTree->MaxPoint (aRight.Id));
554         }
555         else
556         {
557           isLeftChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeft.Id),  aBVHTree->MaxPoint (aLeft.Id), toCheckFullInside ? &aLeft.IsFullInside : NULL);
558           if (!isLeftChildIn)
559           {
560             aLeft.IsFullInside = false;
561           }
562
563           isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRight.Id), aBVHTree->MaxPoint (aRight.Id), toCheckFullInside ? &aRight.IsFullInside : NULL);
564           if (!isRightChildIn)
565           {
566             aRight.IsFullInside = false;
567           }
568         }
569
570         if (isLeftChildIn
571          && isRightChildIn)
572         {
573           aNode = myBVHIsLeftChildQueuedFirst ? aLeft : aRight;
574           aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRight : aLeft;
575           myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst;
576         }
577         else if (isLeftChildIn
578               || isRightChildIn)
579         {
580           aNode = isLeftChildIn ? aLeft : aRight;
581         }
582         else
583         {
584           if (aHead < 0)
585           {
586             break;
587           }
588
589           aNode = aStack[aHead--];
590         }
591       }
592       else
593       {
594         const Standard_Integer aStartIdx = aBVHTree->BegPrimitive (aNode.Id);
595         const Standard_Integer anEndIdx  = aBVHTree->EndPrimitive (aNode.Id);
596         for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx)
597         {
598           const Graphic3d_CStructure* aStruct = isTrsfPers
599                                               ? myBVHPrimitivesTrsfPers.GetStructureById (anIdx)
600                                               : myBVHPrimitives.GetStructureById (anIdx);
601           if (aStruct->IsVisible (theViewId))
602           {
603             aStruct->MarkAsNotCulled();
604             ++myNbStructuresNotCulled;
605           }
606         }
607         if (aHead < 0)
608         {
609           break;
610         }
611
612         aNode = aStack[aHead--];
613       }
614     }
615   }
616 }
617
618 // =======================================================================
619 // function : Append
620 // purpose  :
621 // =======================================================================
622 Standard_Boolean Graphic3d_Layer::Append (const Graphic3d_Layer& theOther)
623 {
624   // the source priority list shouldn't have more priorities
625   const Standard_Integer aNbPriorities = theOther.NbPriorities();
626   if (aNbPriorities > NbPriorities())
627   {
628     return Standard_False;
629   }
630
631   // add all structures to destination priority list
632   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
633   {
634     const Graphic3d_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter);
635     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
636     {
637       Add (aStructIter.Value(), aPriorityIter);
638     }
639   }
640
641   return Standard_True;
642 }
643
644 //=======================================================================
645 //function : SetLayerSettings
646 //purpose  :
647 //=======================================================================
648 void Graphic3d_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings)
649 {
650   const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution());
651   myLayerSettings = theSettings;
652   if (!toUpdateTrsf)
653   {
654     return;
655   }
656
657   for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
658   {
659     Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue();
660     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
661     {
662       Graphic3d_CStructure* aStructure = const_cast<Graphic3d_CStructure* >(aStructIter.Value());
663       aStructure->updateLayerTransformation();
664     }
665   }
666 }
667
668 // =======================================================================
669 // function : DumpJson
670 // purpose  :
671 // =======================================================================
672 void Graphic3d_Layer::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
673 {
674   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
675
676   OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, this)
677   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLayerId)
678   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbStructures)
679   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbStructuresNotCulled)
680
681   const Standard_Integer aNbPriorities = myArray.Length();
682   for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter)
683   {
684     const Graphic3d_IndexedMapOfStructure& aStructures = myArray (aPriorityIter);
685     for (Graphic3d_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
686     {
687       const Graphic3d_CStructure* aStructure = aStructIter.Value();
688       OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, aStructure)
689     }
690   }
691
692   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myLayerSettings)
693
694   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myBVHIsLeftChildQueuedFirst)
695   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBVHPrimitivesNeedsReset)
696   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBoundingBoxNeedsReset[0])
697   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsBoundingBoxNeedsReset[1])
698
699   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBoundingBox[0])
700   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBoundingBox[1])
701 }