From 50d06d8fcf54bdf9e3cd5ef99464f01848e355f6 Mon Sep 17 00:00:00 2001 From: duv Date: Wed, 25 May 2016 17:00:59 +0300 Subject: [PATCH] 0027374: Visualization - optimize management of the scene bounding box OpenGl_View now caches bounding boxes per Z-layer (instead of bounding box of entire scene in Graphic3d_CView). Redundant invalidation of cached scene bounding box is now avoided in case when new presentation attributes are assigned to the graphic structure. Add a new methods ConsiderZoomPersistenceObjects() and considerZoomPersistenceObjects() in the Graphic3d_CView, OpenGl_View and OpenGl_Layer classes. Call ConsiderZoomPersistenceObjects() in the V3d_View::FitMinMax method. std::numeric_limits::lowest() fix --- src/Graphic3d/Graphic3d_CView.cxx | 102 +++++++- src/Graphic3d/Graphic3d_CView.hxx | 56 ++-- src/Graphic3d/Graphic3d_Structure.cxx | 15 +- src/Graphic3d/Graphic3d_Structure.hxx | 6 +- src/Graphic3d/Graphic3d_StructureManager.cxx | 5 +- src/Graphic3d/Graphic3d_StructureManager.hxx | 6 +- src/OpenGl/OpenGl_Layer.cxx | 254 ++++++++++++++++++- src/OpenGl/OpenGl_Layer.hxx | 34 ++- src/OpenGl/OpenGl_LayerList.hxx | 3 + src/OpenGl/OpenGl_View.cxx | 87 +++++++ src/OpenGl/OpenGl_View.hxx | 23 ++ src/V3d/V3d_View.cxx | 6 +- tests/bugs/vis/bug27374 | 20 ++ 13 files changed, 558 insertions(+), 59 deletions(-) create mode 100644 tests/bugs/vis/bug27374 diff --git a/src/Graphic3d/Graphic3d_CView.cxx b/src/Graphic3d/Graphic3d_CView.cxx index 6b8617ec97..f9125a7ef6 100644 --- a/src/Graphic3d/Graphic3d_CView.cxx +++ b/src/Graphic3d/Graphic3d_CView.cxx @@ -17,6 +17,29 @@ IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_CView,Graphic3d_DataStructureManager) +namespace +{ + static const int THE_DEFAULT_LAYERS[] = { Graphic3d_ZLayerId_Top, + Graphic3d_ZLayerId_Topmost, + Graphic3d_ZLayerId_BotOSD, + Graphic3d_ZLayerId_TopOSD }; + + static const int THE_NB_DEFAULT_LAYERS = sizeof(THE_DEFAULT_LAYERS) / sizeof(*THE_DEFAULT_LAYERS); + + void combineBox (Bnd_Box& aCombined, const Graphic3d_BndBox4f& theBox) + { + if (theBox.IsValid()) + { + aCombined.Add (gp_Pnt (theBox.CornerMin().x(), + theBox.CornerMin().y(), + theBox.CornerMin().z())); + aCombined.Add (gp_Pnt (theBox.CornerMax().x(), + theBox.CornerMax().y(), + theBox.CornerMax().z())); + } + } +} + //======================================================================= //function : Constructor //purpose : @@ -349,9 +372,11 @@ void Graphic3d_CView::ReCompute (const Handle(Graphic3d_Structure)& theStruct) // function : Update // purpose : // ======================================================================= -void Graphic3d_CView::Update (const Aspect_TypeOfUpdate theUpdateMode) +void Graphic3d_CView::Update (const Aspect_TypeOfUpdate theUpdateMode, + const Graphic3d_ZLayerId theLayerId) { - myMinMax.Invalidate(); + InvalidateZLayerBoundingBox (theLayerId); + if (theUpdateMode == Aspect_TOU_ASAP) { Compute(); @@ -409,13 +434,68 @@ void Graphic3d_CView::DisplayedStructures (Graphic3d_MapOfStructure& theStructur // ======================================================================= Bnd_Box Graphic3d_CView::MinMaxValues (const Standard_Boolean theToIgnoreInfiniteFlag) const { - if (myMinMax.IsOutdated (theToIgnoreInfiniteFlag)) + Bnd_Box aResult; + + if (!IsDefined()) { - myMinMax.BoundingBox (theToIgnoreInfiniteFlag) = MinMaxValues (myStructsDisplayed, theToIgnoreInfiniteFlag); - myMinMax.IsOutdated (theToIgnoreInfiniteFlag) = Standard_False; + return aResult; } - return myMinMax.BoundingBox (theToIgnoreInfiniteFlag); + Handle(Graphic3d_Camera) aCamera = Camera(); + Standard_Integer aWinWidth = 0; + Standard_Integer aWinHeight = 0; + + Window()->Size (aWinWidth, aWinHeight); + + for (Standard_Integer aLayer = 0; aLayer < THE_NB_DEFAULT_LAYERS; ++aLayer) + { + Graphic3d_BndBox4f aBox = ZLayerBoundingBox (THE_DEFAULT_LAYERS[aLayer], + aCamera, + aWinWidth, + aWinHeight, + theToIgnoreInfiniteFlag); + combineBox (aResult, aBox); + } + + Standard_Integer aMaxZLayer = ZLayerMax(); + for (Standard_Integer aLayerId = Graphic3d_ZLayerId_Default; aLayerId <= aMaxZLayer; ++aLayerId) + { + Graphic3d_BndBox4f aBox = ZLayerBoundingBox (aLayerId, aCamera, aWinWidth, aWinHeight, theToIgnoreInfiniteFlag); + combineBox (aResult, aBox); + } + + return aResult; +} + +// ======================================================================= +// function : ConsiderZoomPersistenceObjects +// purpose : +// ======================================================================= +Standard_Real Graphic3d_CView::ConsiderZoomPersistenceObjects() +{ + if (!IsDefined()) + { + return 1.0; + } + + Handle(Graphic3d_Camera) aCamera = Camera(); + Standard_Integer aWinWidth = 0; + Standard_Integer aWinHeight = 0; + + Window()->Size (aWinWidth, aWinHeight); + + Standard_Real aMaxCoef = 1.0; + for (Standard_Integer aLayer = 0; aLayer < THE_NB_DEFAULT_LAYERS; ++aLayer) + { + aMaxCoef = Max (aMaxCoef, considerZoomPersistenceObjects (THE_DEFAULT_LAYERS[aLayer], aCamera, aWinWidth, aWinHeight, Standard_False)); + } + + for (Standard_Integer aLayer = Graphic3d_ZLayerId_Default; aLayer <= ZLayerMax(); ++aLayer) + { + aMaxCoef = Max (aMaxCoef, considerZoomPersistenceObjects (aLayer, aCamera, aWinWidth, aWinHeight, Standard_False)); + } + + return aMaxCoef; } // ======================================================================= @@ -672,7 +752,7 @@ void Graphic3d_CView::Display (const Handle(Graphic3d_Structure)& theStructure, theStructure->CalculateBoundBox(); displayStructure (theStructure->CStructure(), theStructure->DisplayPriority()); - Update (theUpdateMode); + Update (theUpdateMode, theStructure->GetZLayer()); return; } else if (anAnswer != Graphic3d_TOA_COMPUTE) @@ -693,7 +773,7 @@ void Graphic3d_CView::Display (const Handle(Graphic3d_Structure)& theStructure, } displayStructure (anOldStruct->CStructure(), theStructure->DisplayPriority()); - Update (theUpdateMode); + Update (theUpdateMode, anOldStruct->GetZLayer()); return; } else @@ -716,7 +796,7 @@ void Graphic3d_CView::Display (const Handle(Graphic3d_Structure)& theStructure, const Handle(Graphic3d_Structure)& aNewStruct = myStructsComputed.Value (aNewIndex); myStructsComputed.SetValue (anIndex, aNewStruct); displayStructure (aNewStruct->CStructure(), theStructure->DisplayPriority()); - Update (theUpdateMode); + Update (theUpdateMode, aNewStruct->GetZLayer()); return; } else @@ -807,7 +887,7 @@ void Graphic3d_CView::Display (const Handle(Graphic3d_Structure)& theStructure, myStructsDisplayed.Add (theStructure); displayStructure (aStruct->CStructure(), theStructure->DisplayPriority()); - Update (theUpdateMode); + Update (theUpdateMode, aStruct->GetZLayer()); } // ======================================================================= @@ -851,7 +931,7 @@ void Graphic3d_CView::Erase (const Handle(Graphic3d_Structure)& theStructure, } } myStructsDisplayed.Remove (theStructure); - Update (theUpdateMode); + Update (theUpdateMode, theStructure->GetZLayer()); } // ======================================================================= diff --git a/src/Graphic3d/Graphic3d_CView.hxx b/src/Graphic3d/Graphic3d_CView.hxx index 451b9c3002..94913a7238 100644 --- a/src/Graphic3d/Graphic3d_CView.hxx +++ b/src/Graphic3d/Graphic3d_CView.hxx @@ -108,8 +108,10 @@ public: //! Computes the new presentation of the structure displayed in this view with the type Graphic3d_TOS_COMPUTED. Standard_EXPORT void ReCompute (const Handle(Graphic3d_Structure)& theStructure); - //! Updates screen in function of modifications of the structures. - Standard_EXPORT void Update (const Aspect_TypeOfUpdate theUpdateMode); + //! Updates screen in function of modifications of the structures + //! and invalidates bounding box of specified ZLayerId. + Standard_EXPORT void Update (const Aspect_TypeOfUpdate theUpdateMode, + const Graphic3d_ZLayerId theLayerId = Graphic3d_ZLayerId_UNKNOWN); //! Returns Standard_True if one of the structures displayed in the view contains Polygons, Triangles or Quadrangles. Standard_EXPORT Standard_Boolean ContainsFacet() const; @@ -134,8 +136,7 @@ public: Standard_EXPORT Standard_Boolean IsComputed (const Standard_Integer theStructId, Handle(Graphic3d_Structure)& theComputedStruct) const; - //! Returns the coordinates of the boundary box of all - //! structures displayed in the view. + //! Returns the bounding box of all structures displayed in the view. //! If is TRUE, then the boundary box //! also includes minimum and maximum limits of graphical elements //! forming parts of infinite structures. @@ -336,6 +337,20 @@ public: //! ID for the structure. virtual void AddZLayer (const Graphic3d_ZLayerId theLayerId) = 0; + //! Returns the maximum Z layer ID. + //! First layer ID is Graphic3d_ZLayerId_Default, last ID is ZLayerMax(). + virtual Standard_Integer ZLayerMax() const = 0; + + //! Returns the bounding box of all structures displayed in the Z layer. + virtual void InvalidateZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId) const = 0; + + //! Returns the bounding box of all structures displayed in the Z layer. + virtual Graphic3d_BndBox4f ZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const = 0; + //! Remove Z layer from the specified view. All structures //! displayed at the moment in layer will be displayed in default layer //! ( the bottom-level z layer ). To unset layer ID from associated @@ -346,6 +361,9 @@ public: virtual void SetZLayerSettings (const Graphic3d_ZLayerId theLayerId, const Graphic3d_ZLayerSettings& theSettings) = 0; + //! Returns zoom-scale factor. + Standard_EXPORT Standard_Real ConsiderZoomPersistenceObjects(); + //! Returns pointer to an assigned framebuffer object. virtual Handle(Standard_Transient) FBO() const = 0; @@ -522,29 +540,12 @@ private: virtual void changePriority (const Handle(Graphic3d_CStructure)& theCStructure, const Standard_Integer theNewPriority) = 0; -protected: - - struct CachedMinMax - { - CachedMinMax() { Invalidate(); } - - Bnd_Box& BoundingBox (const Standard_Boolean theToIgnoreInfiniteFlag) - { - return !theToIgnoreInfiniteFlag ? myBoundingBox[0] : myBoundingBox[1]; - } - Standard_Boolean& IsOutdated (const Standard_Boolean theToIgnoreInfiniteFlag) - { - return !theToIgnoreInfiniteFlag ? myIsOutdated[0] : myIsOutdated[1]; - } - void Invalidate() - { - myIsOutdated[0] = Standard_True; - myIsOutdated[1] = Standard_True; - } - - Standard_Boolean myIsOutdated [2]; - Bnd_Box myBoundingBox[2]; - }; + //! Returns zoom-scale factor. + virtual Standard_Real considerZoomPersistenceObjects (const Graphic3d_ZLayerId theLayerId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const = 0; protected: @@ -559,7 +560,6 @@ protected: Standard_Boolean myIsActive; Standard_Boolean myIsRemoved; Graphic3d_TypeOfVisualization myVisualization; - mutable CachedMinMax myMinMax; private: diff --git a/src/Graphic3d/Graphic3d_Structure.cxx b/src/Graphic3d/Graphic3d_Structure.cxx index 92a95a0dd4..99cf4edd14 100644 --- a/src/Graphic3d/Graphic3d_Structure.cxx +++ b/src/Graphic3d/Graphic3d_Structure.cxx @@ -123,7 +123,7 @@ void Graphic3d_Structure::Clear (const Standard_Boolean theWithDestruction) myCStructure->ContainsFacet = 0; myStructureManager->Clear (this, theWithDestruction); - Update(); + Update (true); } //======================================================================= @@ -363,7 +363,7 @@ void Graphic3d_Structure::SetVisible (const Standard_Boolean theValue) myCStructure->visible = isVisible; myCStructure->OnVisibilityChanged(); - Update(); + Update (true); } //============================================================================= @@ -1385,7 +1385,7 @@ void Graphic3d_Structure::Connect (const Handle(Graphic3d_Structure)& theStructu GraphicConnect (theStructure); myStructureManager->Connect (this, theStructure); - Update(); + Update (true); } else // Graphic3d_TOC_ANCESTOR { @@ -1422,7 +1422,7 @@ void Graphic3d_Structure::Disconnect (const Handle(Graphic3d_Structure)& theStru myStructureManager->Disconnect (this, theStructure); CalculateBoundBox(); - Update(); + Update (true); } else if (RemoveAncestor (aStructure)) { @@ -1562,7 +1562,7 @@ void Graphic3d_Structure::SetTransform (const TColStd_Array2OfReal& theMat myCStructure->UpdateTransformation(); myStructureManager->SetTransform (this, aNewTrsf); - Update(); + Update (true); } //============================================================================= @@ -1986,14 +1986,15 @@ void Graphic3d_Structure::PrintNetwork (const Handle(Graphic3d_Structure)& theSt //function : Update //purpose : //============================================================================= -void Graphic3d_Structure::Update() const +void Graphic3d_Structure::Update (const bool theUpdateLayer) const { if (IsDeleted()) { return; } - myStructureManager->Update (myStructureManager->UpdateMode()); + myStructureManager->Update (myStructureManager->UpdateMode(), + theUpdateLayer ? myCStructure->ZLayer() : Graphic3d_ZLayerId_UNKNOWN); } //============================================================================= diff --git a/src/Graphic3d/Graphic3d_Structure.hxx b/src/Graphic3d/Graphic3d_Structure.hxx index 6e0b80eac3..cdad89fe26 100644 --- a/src/Graphic3d/Graphic3d_Structure.hxx +++ b/src/Graphic3d/Graphic3d_Structure.hxx @@ -532,9 +532,9 @@ private: //! Returns the manager to which is associated. Standard_EXPORT Handle(Graphic3d_StructureManager) StructureManager() const; - //! Calls the Update method of the StructureManager which - //! contains the Structure . - Standard_EXPORT void Update() const; + //! Calls the Update method of the StructureManager which contains the Structure . + //! If theUpdateLayer is true then invalidates bounding box of ZLayer. + Standard_EXPORT void Update (const bool theUpdateLayer = false) const; //! Updates the c structure associated to . Standard_EXPORT void UpdateStructure (const Handle(Graphic3d_AspectLine3d)& CTXL, const Handle(Graphic3d_AspectText3d)& CTXT, const Handle(Graphic3d_AspectMarker3d)& CTXM, const Handle(Graphic3d_AspectFillArea3d)& CTXF); diff --git a/src/Graphic3d/Graphic3d_StructureManager.cxx b/src/Graphic3d/Graphic3d_StructureManager.cxx index a32ab8f5e0..7af7a77cc0 100644 --- a/src/Graphic3d/Graphic3d_StructureManager.cxx +++ b/src/Graphic3d/Graphic3d_StructureManager.cxx @@ -83,11 +83,12 @@ Aspect_TypeOfUpdate Graphic3d_StructureManager::UpdateMode() const // function : Update // purpose : // ======================================================================== -void Graphic3d_StructureManager::Update (const Aspect_TypeOfUpdate theMode) const +void Graphic3d_StructureManager::Update (const Aspect_TypeOfUpdate theMode, + const Graphic3d_ZLayerId theLayerId) const { for (Graphic3d_IndexedMapOfView::Iterator aViewIt (myDefinedViews); aViewIt.More(); aViewIt.Next()) { - aViewIt.Value()->Update (theMode); + aViewIt.Value()->Update (theMode, theLayerId); } } diff --git a/src/Graphic3d/Graphic3d_StructureManager.hxx b/src/Graphic3d/Graphic3d_StructureManager.hxx index a0bf0ba230..cba5c9873c 100644 --- a/src/Graphic3d/Graphic3d_StructureManager.hxx +++ b/src/Graphic3d/Graphic3d_StructureManager.hxx @@ -109,8 +109,10 @@ public: //! TOU_WAIT on demand (Update) Standard_EXPORT Aspect_TypeOfUpdate UpdateMode() const; - //! Updates screen in function of modifications of the structures. - Standard_EXPORT virtual void Update (const Aspect_TypeOfUpdate theMode = Aspect_TOU_ASAP) const; + //! Updates screen in function of modifications of the structures + //! and invalidates bounding box of specified ZLayerId. + Standard_EXPORT virtual void Update (const Aspect_TypeOfUpdate theMode = Aspect_TOU_ASAP, + const Graphic3d_ZLayerId theLayerId = Graphic3d_ZLayerId_UNKNOWN) const; //! Deletes and erases the 3D structure manager. Standard_EXPORT virtual void Remove(); diff --git a/src/OpenGl/OpenGl_Layer.cxx b/src/OpenGl/OpenGl_Layer.cxx index 55a51b8158..9a5c2de1a7 100644 --- a/src/OpenGl/OpenGl_Layer.cxx +++ b/src/OpenGl/OpenGl_Layer.cxx @@ -26,12 +26,12 @@ // purpose : // ======================================================================= OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities) -: myArray (0, theNbPriorities - 1), - myNbStructures (0), +: myArray (0, theNbPriorities - 1), + myNbStructures (0), myBVHIsLeftChildQueuedFirst (Standard_True), myIsBVHPrimitivesNeedsReset (Standard_False) { - // + myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true; } // ======================================================================= @@ -123,11 +123,257 @@ bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct, // function : InvalidateBVHData // purpose : // ======================================================================= -void OpenGl_Layer::InvalidateBVHData() +void OpenGl_Layer::InvalidateBVHData() const { myIsBVHPrimitivesNeedsReset = Standard_True; } +// ======================================================================= +// function : BoundingBox +// purpose : +// ======================================================================= +const Graphic3d_BndBox4f& OpenGl_Layer::BoundingBox (const Standard_Integer theViewId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const +{ + const Standard_Integer aBoxId = theToIgnoreInfiniteFlag == 0 ? 0 : 1; + + if (myIsBoundingBoxNeedsReset[aBoxId]) + { + // Recompute layer bounding box + myBoundingBox[aBoxId].Clear(); + + const Standard_Integer aNbPriorities = myArray.Length(); + for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) + { + const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); + for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx) + { + const OpenGl_Structure* aStructure = aStructures.FindKey (aStructIdx); + if (!aStructure->IsVisible()) + { + continue; + } + else if (!aStructure->ViewAffinity.IsNull() + && !aStructure->ViewAffinity->IsVisible (theViewId)) + { + continue; + } + + // "FitAll" operation ignores object with transform persistence parameter + // but adds transform persistence point in a bounding box of layer (only zoom pers. objects). + if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None) + { + if (!theToIgnoreInfiniteFlag && (aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers)) + { + if (!theCamera->IsOrthographic()) + { + continue; + } + + BVH_Vec4f aTPPoint (static_cast (aStructure->TransformPersistence.Point.x()), + static_cast (aStructure->TransformPersistence.Point.y()), + static_cast (aStructure->TransformPersistence.Point.z()), + 1.0f); + + myBoundingBox[aBoxId].Combine (aTPPoint); + continue; + } + // Panning and 2d persistence apply changes to projection or/and its translation components. + // It makes them incompatible with z-fitting algorithm. Ignored by now. + else if (!theToIgnoreInfiniteFlag + || (aStructure->TransformPersistence.Flags & Graphic3d_TMF_2d) + || (aStructure->TransformPersistence.Flags & Graphic3d_TMF_PanPers) + || (aStructure->TransformPersistence.Flags & Graphic3d_TMF_TriedronPers)) + { + continue; + } + } + + Graphic3d_BndBox4f aBox = aStructure->BoundingBox(); + + if (aStructure->IsInfinite + && !theToIgnoreInfiniteFlag) + { + const Graphic3d_Vec4 aDiagVec = aBox.CornerMax() - aBox.CornerMin(); + if (aDiagVec.xyz().SquareModulus() >= 500000.0f * 500000.0f) + { + // bounding borders of infinite line has been calculated as own point in center of this line + aBox = Graphic3d_BndBox4f ((aBox.CornerMin() + aBox.CornerMax()) * 0.5f); + } + else + { + aBox = Graphic3d_BndBox4f (Graphic3d_Vec4 (ShortRealFirst(), ShortRealFirst(), ShortRealFirst(), 1.0f), + Graphic3d_Vec4 (ShortRealLast(), ShortRealLast(), ShortRealLast(), 1.0f)); + } + } + + if (aStructure->TransformPersistence.Flags != Graphic3d_TMF_None) + { + const Graphic3d_Mat4& aProjectionMat = theCamera->ProjectionMatrixF(); + const Graphic3d_Mat4& aWorldViewMat = theCamera->OrientationMatrixF(); + + aStructure->TransformPersistence.Apply (aProjectionMat, + aWorldViewMat, + theWindowWidth, + theWindowHeight, + aBox); + } + + // To prevent float overflow at camera parameters calculation and further + // rendering, bounding boxes with at least one vertex coordinate out of + // float range are skipped by view fit algorithms + if (Abs (aBox.CornerMax().x()) >= ShortRealLast() + || Abs (aBox.CornerMax().y()) >= ShortRealLast() + || Abs (aBox.CornerMax().z()) >= ShortRealLast() + || Abs (aBox.CornerMin().x()) >= ShortRealLast() + || Abs (aBox.CornerMin().y()) >= ShortRealLast() + || Abs (aBox.CornerMin().z()) >= ShortRealLast()) + { + continue; + } + + myBoundingBox[aBoxId].Combine (aBox); + } + } + + myIsBoundingBoxNeedsReset[aBoxId] = false; + } + + return myBoundingBox[aBoxId]; +} + +// ======================================================================= +// function : considerZoomPersistenceObjects +// purpose : +// ======================================================================= +Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer theViewId, + const Handle(Graphic3d_Camera)& theCamera, + Standard_Integer theWindowWidth, + Standard_Integer theWindowHeight, + Standard_Boolean /*theToIgnoreInfiniteFlag*/) const +{ + if (NbOfTransformPersistenceObjects() == 0) + { + return 1.0; + } + + const Standard_Integer aNbPriorities = myArray.Length(); + const Graphic3d_Mat4& aProjectionMat = theCamera->ProjectionMatrixF(); + const Graphic3d_Mat4& aWorldViewMat = theCamera->OrientationMatrixF(); + Standard_Real aMaxCoef = -std::numeric_limits::max(); + + for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) + { + const OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); + for (Standard_Integer aStructIdx = 1; aStructIdx <= aStructures.Size(); ++aStructIdx) + { + OpenGl_Structure* aStructure = const_cast (aStructures.FindKey (aStructIdx)); + if (!aStructure->IsVisible()) + { + continue; + } + else if (!aStructure->ViewAffinity.IsNull() + && !aStructure->ViewAffinity->IsVisible (theViewId)) + { + continue; + } + + if (!(aStructure->TransformPersistence.Flags & Graphic3d_TMF_ZoomPers)) + { + continue; + } + + Graphic3d_BndBox4f aBox = aStructure->BoundingBox(); + aStructure->TransformPersistence.Apply (aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); + + const BVH_Vec4f& aCornerMin = aBox.CornerMin(); + const BVH_Vec4f& aCornerMax = aBox.CornerMax(); + const Standard_Integer aNbOfPoints = 8; + const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()), + gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()), + gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()), + gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()), + gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()), + gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()), + gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()), + gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) }; + gp_Pnt aConvertedPoints[aNbOfPoints]; + Standard_Real aConvertedMinX = std::numeric_limits::max(); + Standard_Real aConvertedMaxX = -std::numeric_limits::max(); + Standard_Real aConvertedMinY = std::numeric_limits::max(); + Standard_Real aConvertedMaxY = -std::numeric_limits::max(); + for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx) + { + aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]); + + aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X()); + aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X()); + + aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y()); + aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y()); + } + + const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window + || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window + const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0) + && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0) + && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0) + && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0); + if (isBigObject || isAlreadyInScreen) + { + continue; + } + + const gp_Pnt aTPPoint (aStructure->TransformPersistence.Point.x(), + aStructure->TransformPersistence.Point.y(), + aStructure->TransformPersistence.Point.z()); + gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint); + aConvertedTPPoint.SetZ (0.0); + + if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion()) + { + continue; + } + + Standard_Real aShiftX = 0.0; + if (aConvertedMinX < -1.0) + { + aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX)); + } + else if (aConvertedMaxX > 1.0) + { + aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0)); + } + + Standard_Real aShiftY = 0.0; + if (aConvertedMinY < -1.0) + { + aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY)); + } + else if (aConvertedMaxY > 1.0) + { + aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0)); + } + + const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX; + const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY; + if (aDifX > Precision::Confusion()) + { + aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX); + } + if (aDifY > Precision::Confusion()) + { + aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY); + } + } + } + + return (aMaxCoef > 0.0) ? aMaxCoef : 1.0; +} + // ======================================================================= // function : renderAll // purpose : diff --git a/src/OpenGl/OpenGl_Layer.hxx b/src/OpenGl/OpenGl_Layer.hxx index eda05729cd..a6eddd279f 100644 --- a/src/OpenGl/OpenGl_Layer.hxx +++ b/src/OpenGl/OpenGl_Layer.hxx @@ -92,12 +92,38 @@ public: //! Marks BVH tree for given priority list as dirty and //! marks primitive set for rebuild. - void InvalidateBVHData(); + void InvalidateBVHData() const; + + //! Marks cached bounding box as obsolete. + void InvalidateBoundingBox() const + { + myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true; + } + + //! Returns layer bounding box. + const Graphic3d_BndBox4f& BoundingBox (const Standard_Integer theViewId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const; + + //! Returns zoom-scale factor. + Standard_Real considerZoomPersistenceObjects (const Standard_Integer theViewId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const; // Render all structures. void Render (const Handle(OpenGl_Workspace)& theWorkspace, const OpenGl_GlobalLayerSettings& theDefaultSettings) const; + //! Returns number of transform persistence objects. + Standard_Integer NbOfTransformPersistenceObjects() const + { + return myBVHPrimitivesTrsfPers.Size(); + } + protected: //! Traverses through BVH tree to determine which structures are in view volume. @@ -132,6 +158,12 @@ private: //! Defines if the primitive set for BVH is outdated. mutable Standard_Boolean myIsBVHPrimitivesNeedsReset; + //! Defines if the cached bounding box is outdated. + mutable bool myIsBoundingBoxNeedsReset[2]; + + //! Cached layer bounding box. + mutable Graphic3d_BndBox4f myBoundingBox[2]; + public: DEFINE_STANDARD_ALLOC diff --git a/src/OpenGl/OpenGl_LayerList.hxx b/src/OpenGl/OpenGl_LayerList.hxx index ec05a3ed46..d54bbe4b59 100644 --- a/src/OpenGl/OpenGl_LayerList.hxx +++ b/src/OpenGl/OpenGl_LayerList.hxx @@ -95,6 +95,9 @@ public: //! Returns the set of OpenGL Z-layers. const OpenGl_SequenceOfLayers& Layers() const { return myLayers; } + //! Returns the map of Z-layer IDs to indexes. + const OpenGl_LayerSeqIds& LayerIDs() const { return myLayerIds; } + //! Marks BVH tree for given priority list as dirty and //! marks primitive set for rebuild. void InvalidateBVHData (const Graphic3d_ZLayerId theLayerId); diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index 7d2b9b6952..3e1a7dab59 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -521,6 +521,91 @@ void OpenGl_View::SetZLayerSettings (const Graphic3d_ZLayerId theLayerId, myZLayers.SetLayerSettings (theLayerId, theSettings); } +//======================================================================= +//function : ZLayerMax +//purpose : +//======================================================================= +Standard_Integer OpenGl_View::ZLayerMax() const +{ + Standard_Integer aLayerMax = Graphic3d_ZLayerId_Default; + for (OpenGl_LayerSeqIds::Iterator aMapIt(myZLayers.LayerIDs()); aMapIt.More(); aMapIt.Next()) + { + aLayerMax = Max (aLayerMax, aMapIt.Value()); + } + + return aLayerMax; +} + +//======================================================================= +//function : InvalidateZLayerBoundingBox +//purpose : +//======================================================================= +void OpenGl_View::InvalidateZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId) const +{ + if (myZLayers.LayerIDs().IsBound (theLayerId)) + { + myZLayers.Layer (theLayerId).InvalidateBoundingBox(); + } + else + { + for (Standard_Integer aLayerId = Graphic3d_ZLayerId_Default; aLayerId < ZLayerMax(); ++aLayerId) + { + if (myZLayers.LayerIDs().IsBound (aLayerId)) + { + const OpenGl_Layer& aLayer = myZLayers.Layer (aLayerId); + if (aLayer.NbOfTransformPersistenceObjects() > 0) + { + aLayer.InvalidateBoundingBox(); + } + } + } + } +} + +//======================================================================= +//function : ZLayerBoundingBox +//purpose : +//======================================================================= +Graphic3d_BndBox4f OpenGl_View::ZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const +{ + if (myZLayers.LayerIDs().IsBound (theLayerId)) + { + return myZLayers.Layer (theLayerId).BoundingBox (Identification(), + theCamera, + theWindowWidth, + theWindowHeight, + theToIgnoreInfiniteFlag); + } + + return Graphic3d_BndBox4f(); +} + +//======================================================================= +//function : considerZoomPersistenceObjects +//purpose : +//======================================================================= +Standard_Real OpenGl_View::considerZoomPersistenceObjects (const Graphic3d_ZLayerId theLayerId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const +{ + if (myZLayers.LayerIDs().IsBound (theLayerId) && theCamera->IsOrthographic()) + { + return myZLayers.Layer (theLayerId).considerZoomPersistenceObjects (Identification(), + theCamera, + theWindowWidth, + theWindowHeight, + theToIgnoreInfiniteFlag); + } + + return 1.0; +} + //======================================================================= //function : FBO //purpose : @@ -742,6 +827,8 @@ void OpenGl_View::changeZLayer (const Handle(Graphic3d_CStructure)& theStructure const Graphic3d_ZLayerId anOldLayer = theStructure->ZLayer(); const OpenGl_Structure* aStruct = reinterpret_cast (theStructure.operator->()); myZLayers.ChangeLayer (aStruct, anOldLayer, theNewLayerId); + Update (Aspect_TOU_WAIT, anOldLayer); + Update (Aspect_TOU_WAIT, theNewLayerId); } //======================================================================= diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index 0b35e2ce35..efa355add3 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -231,6 +231,22 @@ public: Standard_EXPORT virtual void SetZLayerSettings (const Graphic3d_ZLayerId theLayerId, const Graphic3d_ZLayerSettings& theSettings) Standard_OVERRIDE; + //! Returns the maximum Z layer ID. + //! First layer ID is Graphic3d_ZLayerId_Default, last ID is ZLayerMax(). + Standard_EXPORT virtual Standard_Integer ZLayerMax() const Standard_OVERRIDE; + + //! Returns the bounding box of all structures displayed in the Z layer. + //! Never fails. If Z layer does not exist nothing happens. + Standard_EXPORT virtual void InvalidateZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId) const Standard_OVERRIDE; + + //! Returns the bounding box of all structures displayed in the Z layer. + //! Never fails. If Z layer does not exist the empty box is returned. + Standard_EXPORT virtual Graphic3d_BndBox4f ZLayerBoundingBox (const Graphic3d_ZLayerId theLayerId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const Standard_OVERRIDE; + //! Returns pointer to an assigned framebuffer object. Standard_EXPORT virtual Handle(Standard_Transient) FBO() const Standard_OVERRIDE; @@ -528,6 +544,13 @@ private: Standard_EXPORT virtual void changePriority (const Handle(Graphic3d_CStructure)& theCStructure, const Standard_Integer theNewPriority) Standard_OVERRIDE; + //! Returns zoom-scale factor. + Standard_EXPORT virtual Standard_Real considerZoomPersistenceObjects (const Graphic3d_ZLayerId theLayerId, + const Handle(Graphic3d_Camera)& theCamera, + const Standard_Integer theWindowWidth, + const Standard_Integer theWindowHeight, + const Standard_Boolean theToIgnoreInfiniteFlag) const Standard_OVERRIDE; + private: //! Copy content of Back buffer to the Front buffer. diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx index 49a9860071..9f7bed1730 100644 --- a/src/V3d/V3d_View.cxx +++ b/src/V3d/V3d_View.cxx @@ -3257,7 +3257,11 @@ Standard_Boolean V3d_View::FitMinMax (const Handle(Graphic3d_Camera)& theCamera, aViewSizeYv = aViewSizeZv; } - Scale (theCamera, aViewSizeXv * (1.0 + theMargin), aViewSizeYv * (1.0 + theMargin)); + Scale (theCamera, aViewSizeXv, aViewSizeYv); + + const Standard_Real aZoomCoef = myView->ConsiderZoomPersistenceObjects(); + + Scale (theCamera, theCamera->ViewDimensions().X() * (aZoomCoef + theMargin), theCamera->ViewDimensions().Y() * (aZoomCoef + theMargin)); return Standard_True; } diff --git a/tests/bugs/vis/bug27374 b/tests/bugs/vis/bug27374 new file mode 100644 index 0000000000..008e1ce62e --- /dev/null +++ b/tests/bugs/vis/bug27374 @@ -0,0 +1,20 @@ +puts "========" +puts "OCC27374" +puts "========" +puts "" +################################################################################ +puts "Visualization - add support zoom persistence objects for FitAll operation" +################################################################################ + +vinit +vclear + +box b0 30 0 0 3 3 3 +box b1 -30 -30 30 10 20 30 +box b2 30 0 30 100 100 100 +vdisplay b0 +vdisplay b1 -trsfPers zoom -perspos 10 0 0 +vdisplay b2 -trsfPers zoom -perspos 40 0 30 +vfit + +vdump $imagedir/${casename}.png