From 8c36926a54dba67191acdb65a13263cc9d0407b5 Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 7 Aug 2020 13:40:47 +0300 Subject: [PATCH] 0031701: Visualization, SelectMgr_ViewerSelector - make depth tolerance configurable SelectMgr_ViewerSelector::SetDepthTolerance() - added property defining depth tolerance type and value. Default value remains the same (SelectMgr_TypeOfDepthTolerance_SensitivityFactor), while new values (SelectMgr_TypeOfDepthTolerance_Uniform, SelectMgr_TypeOfDepthTolerance_UniformPixels) change behavior. AIS_Manipulator - removed obsolete suggestion to use AIS_InteractiveContext::SetPickClosest() for issue fixed long time ago by #0027797. --- src/AIS/AIS_Manipulator.hxx | 3 - src/SelectMgr/FILES | 1 + src/SelectMgr/SelectMgr_SortCriterion.hxx | 104 +++++------------- .../SelectMgr_TypeOfDepthTolerance.hxx | 26 +++++ src/SelectMgr/SelectMgr_ViewerSelector.cxx | 99 ++++++++++------- src/SelectMgr/SelectMgr_ViewerSelector.hxx | 44 +++++--- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 50 +++++++++ 7 files changed, 197 insertions(+), 130 deletions(-) create mode 100644 src/SelectMgr/SelectMgr_TypeOfDepthTolerance.hxx diff --git a/src/AIS/AIS_Manipulator.hxx b/src/AIS/AIS_Manipulator.hxx index 1b5c94fd9d..2aaf315fd1 100644 --- a/src/AIS/AIS_Manipulator.hxx +++ b/src/AIS/AIS_Manipulator.hxx @@ -94,9 +94,6 @@ DEFINE_STANDARD_HANDLE (AIS_Manipulator, AIS_InteractiveObject) //! @endcode //! The last method erases manipulator object. //! @warning -//! On construction an instance of AIS_Manipulator object is bound to Graphic3d_ZLayerId_Topmost layer, -//! so make sure to call for your AIS_InteractiveContext the method MainSelector()->SetPickClosest (Standard_False) -//! otherwise you may notice issues with activation of modes. class AIS_Manipulator : public AIS_InteractiveObject { public: diff --git a/src/SelectMgr/FILES b/src/SelectMgr/FILES index 7e3351c4e1..1d0c16f887 100755 --- a/src/SelectMgr/FILES +++ b/src/SelectMgr/FILES @@ -57,6 +57,7 @@ SelectMgr_TriangularFrustum.hxx SelectMgr_TriangularFrustumSet.cxx SelectMgr_TriangularFrustumSet.hxx SelectMgr_TypeOfBVHUpdate.hxx +SelectMgr_TypeOfDepthTolerance.hxx SelectMgr_TypeOfUpdate.hxx SelectMgr_VectorTypes.hxx SelectMgr_ViewClipRange.cxx diff --git a/src/SelectMgr/SelectMgr_SortCriterion.hxx b/src/SelectMgr/SelectMgr_SortCriterion.hxx index a95383cc96..29fc12b303 100644 --- a/src/SelectMgr/SelectMgr_SortCriterion.hxx +++ b/src/SelectMgr/SelectMgr_SortCriterion.hxx @@ -37,7 +37,6 @@ public: Standard_Integer Priority; //!< selection priority Standard_Integer ZLayerPosition; //!< ZLayer rendering order index, stronger than a depth Standard_Integer NbOwnerMatches; //!< overall number of entities collected for the same owner - Standard_Boolean ToPreferClosest; //!< whether closest object is preferred even if has less priority public: DEFINE_STANDARD_ALLOC @@ -48,18 +47,11 @@ public: MinDist (0.0), Tolerance(0.0), Priority (0), - ZLayerPosition (0), - NbOwnerMatches (0), - ToPreferClosest (Standard_True) {} + ZLayerPosition (0), + NbOwnerMatches (0) {} - //! Comparison operator. - bool operator> (const SelectMgr_SortCriterion& theOther) const { return IsGreater (theOther); } - - //! Comparison operator. - bool operator< (const SelectMgr_SortCriterion& theOther) const { return IsLower (theOther); } - - //! Compare with another item. - bool IsGreater (const SelectMgr_SortCriterion& theOther) const + //! Compare with another item by depth, priority and minDist. + bool IsCloserDepth (const SelectMgr_SortCriterion& theOther) const { // the object within different ZLayer groups can not be compared by depth if (ZLayerPosition != theOther.ZLayerPosition) @@ -67,26 +59,32 @@ public: return ZLayerPosition > theOther.ZLayerPosition; } - if (ToPreferClosest) + // closest object is selected unless difference is within tolerance + if (Abs (Depth - theOther.Depth) > (Tolerance + theOther.Tolerance)) { - // closest object is selected unless difference is within tolerance - if (Abs (Depth - theOther.Depth) > (Tolerance + theOther.Tolerance)) - { - return Depth < theOther.Depth; - } - - // if two objects have similar depth, select the one with higher priority - if (Priority > theOther.Priority) - { - return true; - } - - // if priorities are equal, one closest to the mouse - return Priority == theOther.Priority - && MinDist < theOther.MinDist; + return Depth < theOther.Depth; + } + + // if two objects have similar depth, select the one with higher priority + if (Priority > theOther.Priority) + { + return true; + } + + // if priorities are equal, one closest to the mouse + return Priority == theOther.Priority + && MinDist < theOther.MinDist; + } + + //! Compare with another item using old logic (OCCT version <= 6.3.1) with priority considered preceding depth. + bool IsHigherPriority (const SelectMgr_SortCriterion& theOther) const + { + // the object within different ZLayer groups can not be compared by depth + if (ZLayerPosition != theOther.ZLayerPosition) + { + return ZLayerPosition > theOther.ZLayerPosition; } - // old logic (OCCT version <= 6.3.1) if (Priority > theOther.Priority) { return true; @@ -96,6 +94,7 @@ public: return false; } + //if (Abs (Depth - theOther.Depth) <= (Tolerance + theOther.Tolerance)) if (Abs (Depth - theOther.Depth) <= Precision::Confusion()) { return MinDist < theOther.MinDist; @@ -104,53 +103,6 @@ public: return Depth < theOther.Depth; } - //! Compare with another item. - bool IsLower (const SelectMgr_SortCriterion& theOther) const - { - // the object within different ZLayer groups can not be compared by depth - if (ZLayerPosition != theOther.ZLayerPosition) - { - return ZLayerPosition < theOther.ZLayerPosition; - } - - if (ToPreferClosest) - { - // closest object is selected unless difference is within tolerance - if (ToPreferClosest - && Abs (Depth - theOther.Depth) > (Tolerance + theOther.Tolerance)) - { - return Depth > theOther.Depth; - } - - // if two objects have similar depth, select the one with higher priority - if (Priority < theOther.Priority) - { - return true; - } - - // if priorities are equal, one closest to the mouse - return Priority == theOther.Priority - && MinDist > theOther.MinDist; - } - - // old logic (OCCT version <= 6.3.1) - if (Priority > theOther.Priority) - { - return false; - } - else if (Priority != theOther.Priority) - { - return true; - } - - if (Abs (Depth - theOther.Depth) <= Precision::Confusion()) - { - return MinDist > theOther.MinDist; - } - - return Depth > theOther.Depth; - } - }; #endif // _SelectMgr_SortCriterion_HeaderFile diff --git a/src/SelectMgr/SelectMgr_TypeOfDepthTolerance.hxx b/src/SelectMgr/SelectMgr_TypeOfDepthTolerance.hxx new file mode 100644 index 0000000000..622a2723ed --- /dev/null +++ b/src/SelectMgr/SelectMgr_TypeOfDepthTolerance.hxx @@ -0,0 +1,26 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _SelectMgr_TypeOfDepthTolerance_HeaderFile +#define _SelectMgr_TypeOfDepthTolerance_HeaderFile + +//! Define the type of depth tolerance for considering picked entities to lie on the same depth (distance from eye to entity). +//! @sa SelectMgr_SortCriterion, SelectMgr_ViewerSelector +enum SelectMgr_TypeOfDepthTolerance +{ + SelectMgr_TypeOfDepthTolerance_Uniform, //!< use a predefined tolerance value (defined in 3D world scale) to compare any entities + SelectMgr_TypeOfDepthTolerance_UniformPixels, //!< use a predefined tolerance value (defined in pixels) to compare any entities + SelectMgr_TypeOfDepthTolerance_SensitivityFactor, //!< use sensitivity factor (in pixels) assigned to specific entity +}; + +#endif // _SelectMgr_TypeOfDepthTolerance_HeaderFile diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.cxx b/src/SelectMgr/SelectMgr_ViewerSelector.cxx index 9de41051fe..c1102fba7f 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.cxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.cxx @@ -42,18 +42,28 @@ namespace { public: - CompareResults (const SelectMgr_IndexedDataMapOfOwnerCriterion& theMapOfCriterion) - : myMapOfCriterion (&theMapOfCriterion) - { - } + CompareResults (const SelectMgr_IndexedDataMapOfOwnerCriterion& theMapOfCriterion, + bool theToPreferClosest) + : myMapOfCriterion (&theMapOfCriterion), + myToPreferClosest (theToPreferClosest) {} Standard_Boolean operator() (Standard_Integer theLeft, Standard_Integer theRight) const { - return myMapOfCriterion->FindFromIndex (theLeft) > myMapOfCriterion->FindFromIndex (theRight); + const SelectMgr_SortCriterion& anElemLeft = myMapOfCriterion->FindFromIndex (theLeft); + const SelectMgr_SortCriterion& anElemRight = myMapOfCriterion->FindFromIndex (theRight); + if (myToPreferClosest) + { + return anElemLeft.IsCloserDepth (anElemRight); + } + else + { + return anElemLeft.IsHigherPriority (anElemRight); + } } private: const SelectMgr_IndexedDataMapOfOwnerCriterion* myMapOfCriterion; + bool myToPreferClosest; }; static const Graphic3d_Mat4d SelectMgr_ViewerSelector_THE_IDENTITY_MAT; @@ -114,18 +124,33 @@ void SelectMgr_ViewerSelector::updatePoint3d (SelectMgr_SortCriterion& theCriter } } - if (mySelectingVolumeMgr.Camera().IsNull()) + const Standard_Real aSensFactor = myDepthTolType == SelectMgr_TypeOfDepthTolerance_SensitivityFactor ? theEntity->SensitivityFactor() : myDepthTolerance; + switch (myDepthTolType) { - theCriterion.Tolerance = theEntity->SensitivityFactor() / 33.0; - } - else if (mySelectingVolumeMgr.Camera()->IsOrthographic()) - { - theCriterion.Tolerance = myCameraScale * theEntity->SensitivityFactor(); - } - else - { - const Standard_Real aDistFromEye = Abs ((theCriterion.Point.XYZ() - myCameraEye.XYZ()).Dot (myCameraDir.XYZ())); - theCriterion.Tolerance = aDistFromEye * myCameraScale * theEntity->SensitivityFactor(); + case SelectMgr_TypeOfDepthTolerance_Uniform: + { + theCriterion.Tolerance = myDepthTolerance; + break; + } + case SelectMgr_TypeOfDepthTolerance_UniformPixels: + case SelectMgr_TypeOfDepthTolerance_SensitivityFactor: + { + if (mySelectingVolumeMgr.Camera().IsNull()) + { + // fallback for an arbitrary projection matrix + theCriterion.Tolerance = aSensFactor / 33.0; + } + else if (mySelectingVolumeMgr.Camera()->IsOrthographic()) + { + theCriterion.Tolerance = myCameraScale * aSensFactor; + } + else + { + const Standard_Real aDistFromEye = Abs ((theCriterion.Point.XYZ() - myCameraEye.XYZ()).Dot (myCameraDir.XYZ())); + theCriterion.Tolerance = aDistFromEye * myCameraScale * aSensFactor; + } + break; + } } } @@ -133,14 +158,15 @@ void SelectMgr_ViewerSelector::updatePoint3d (SelectMgr_SortCriterion& theCriter // Function: Initialize // Purpose : //================================================== -SelectMgr_ViewerSelector::SelectMgr_ViewerSelector(): -preferclosest(Standard_True), -myToUpdateTolerance (Standard_True), -myCameraScale (1.0), -myToPrebuildBVH (Standard_False), -myCurRank (0), -myIsLeftChildQueuedFirst (Standard_False), -myEntityIdx (0) +SelectMgr_ViewerSelector::SelectMgr_ViewerSelector() +: myDepthTolerance (0.0), + myDepthTolType (SelectMgr_TypeOfDepthTolerance_SensitivityFactor), + myToPreferClosest (Standard_True), + myToUpdateTolerance (Standard_True), + myCameraScale (1.0), + myToPrebuildBVH (Standard_False), + myCurRank (0), + myIsLeftChildQueuedFirst (Standard_False) { myEntitySetBuilder = new BVH_BinnedBuilder (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth, Standard_True); } @@ -262,7 +288,6 @@ void SelectMgr_ViewerSelector::checkOverlap (const Handle(Select3D_SensitiveEnti aCriterion.Priority = anOwner->Priority(); aCriterion.Depth = aPickResult.Depth(); aCriterion.MinDist = aPickResult.DistToGeomCenter(); - aCriterion.ToPreferClosest = preferclosest; if (SelectMgr_SortCriterion* aPrevCriterion = mystored.ChangeSeek (anOwner)) { @@ -270,7 +295,7 @@ void SelectMgr_ViewerSelector::checkOverlap (const Handle(Select3D_SensitiveEnti aCriterion.NbOwnerMatches = aPrevCriterion->NbOwnerMatches; if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Box) { - if (aCriterion > *aPrevCriterion) + if (aCriterion.IsCloserDepth (*aPrevCriterion)) { updatePoint3d (aCriterion, aPickResult, theEntity, theInversedTrsf, theMgr); *aPrevCriterion = aCriterion; @@ -887,28 +912,27 @@ TCollection_AsciiString SelectMgr_ViewerSelector::Status (const Handle(SelectMgr //======================================================================= //function : SortResult -//purpose : there is a certain number of entities ranged by criteria -// (depth, size, priority, mouse distance from borders or -// CDG of the detected primitive. Parsing : -// maximum priorities . -// then a reasonable compromise between depth and distance... -// finally the ranges are stored in myindexes depending on the parsing. -// so, it is possible to only read +//purpose : //======================================================================= void SelectMgr_ViewerSelector::SortResult() { - if(mystored.IsEmpty()) return; + if (mystored.IsEmpty()) + { + return; + } const Standard_Integer anExtent = mystored.Extent(); - if(myIndexes.IsNull() || anExtent != myIndexes->Length()) + if (myIndexes.IsNull() || anExtent != myIndexes->Length()) + { myIndexes = new TColStd_HArray1OfInteger (1, anExtent); + } TColStd_Array1OfInteger& anIndexArray = myIndexes->ChangeArray1(); for (Standard_Integer anIndexIter = 1; anIndexIter <= anExtent; ++anIndexIter) { anIndexArray.SetValue (anIndexIter, anIndexIter); } - std::sort (anIndexArray.begin(), anIndexArray.end(), CompareResults (mystored)); + std::sort (anIndexArray.begin(), anIndexArray.end(), CompareResults (mystored, myToPreferClosest)); } //======================================================================= @@ -1094,7 +1118,7 @@ void SelectMgr_ViewerSelector::DumpJson (Standard_OStream& theOStream, Standard_ { OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream) - OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, preferclosest) + OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToPreferClosest) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToUpdateTolerance) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, mystored.Extent()) @@ -1122,7 +1146,6 @@ void SelectMgr_ViewerSelector::DumpJson (Standard_OStream& theOStream, Standard_ OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myCurRank) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsLeftChildQueuedFirst) - OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myEntityIdx) OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMapOfObjectSensitives.Extent()) } diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.hxx b/src/SelectMgr/SelectMgr_ViewerSelector.hxx index 405e2adb13..8289c336c7 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.hxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.hxx @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -99,8 +100,7 @@ public: Standard_Integer PixelTolerance() const { return myTolerances.Tolerance(); } //! Sorts the detected entites by priority and distance. - //! to be redefined if other criterion are used... - Standard_EXPORT void SortResult(); + Standard_EXPORT virtual void SortResult(); //! Returns the picked element with the highest priority, //! and which is the closest to the last successful mouse position. @@ -111,13 +111,32 @@ public: : Picked (1); } - //! Set preference of selecting one object for OnePicked() method: - //! - If True, objects with less depth (distance fron the view plane) are - //! preferred regardless of priority (priority is used then to choose among - //! objects with similar depth), - //! - If False, objects with higher priority are preferred regardless of the - //! depth which is used to choose among objects of the same priority. - void SetPickClosest (const Standard_Boolean theToPreferClosest) { preferclosest = theToPreferClosest; } + //! Return the flag determining precedence of picked depth (distance from eye to entity) over entity priority in sorted results; TRUE by default. + //! When flag is TRUE, priority will be considered only if entities have the same depth within the tolerance. + //! When flag is FALSE, entities with higher priority will be in front regardless of their depth (like x-ray). + bool ToPickClosest() const { return myToPreferClosest; } + + //! Set flag determining precedence of picked depth over entity priority in sorted results. + void SetPickClosest (bool theToPreferClosest) { myToPreferClosest = theToPreferClosest; } + + //! Return the type of tolerance for considering two entities having a similar depth (distance from eye to entity); + //! SelectMgr_TypeOfDepthTolerance_SensitivityFactor by default. + SelectMgr_TypeOfDepthTolerance DepthToleranceType() const { return myDepthTolType; } + + //! Return the tolerance for considering two entities having a similar depth (distance from eye to entity). + Standard_Real DepthTolerance() const { return myDepthTolerance; } + + //! Set the tolerance for considering two entities having a similar depth (distance from eye to entity). + //! @param theType [in] type of tolerance value + //! @param theTolerance [in] tolerance value in 3D scale (SelectMgr_TypeOfDepthTolerance_Uniform) + //! or in pixels (SelectMgr_TypeOfDepthTolerance_UniformPixels); + //! value is ignored in case of SelectMgr_TypeOfDepthTolerance_SensitivityFactor + void SetDepthTolerance (SelectMgr_TypeOfDepthTolerance theType, + Standard_Real theTolerance) + { + myDepthTolType = theType; + myDepthTolerance = theTolerance; + } //! Returns the number of detected owners. Standard_Integer NbPicked() const { return mystored.Extent(); } @@ -357,7 +376,9 @@ private: // implementation of deprecated methods protected: - Standard_Boolean preferclosest; + Standard_Real myDepthTolerance; + SelectMgr_TypeOfDepthTolerance myDepthTolType; + Standard_Boolean myToPreferClosest; Standard_Boolean myToUpdateTolerance; SelectMgr_IndexedDataMapOfOwnerCriterion mystored; SelectMgr_SelectingVolumeManager mySelectingVolumeMgr; @@ -372,12 +393,9 @@ protected: Standard_Boolean myToPrebuildBVH; Handle(SelectMgr_BVHThreadPool) myBVHThreadPool; -private: - Handle(TColStd_HArray1OfInteger) myIndexes; Standard_Integer myCurRank; Standard_Boolean myIsLeftChildQueuedFirst; - Standard_Integer myEntityIdx; SelectMgr_MapOfObjectSensitives myMapOfObjectSensitives; }; diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 3b3692fbd3..000537ac57 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -13300,6 +13300,52 @@ static int VSelectionProperties (Draw_Interpretor& theDi, { aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter])); } + else if (anArg == "-preferclosest") + { + bool toPreferClosest = true; + if (anArgIter + 1 < theArgsNb + && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest)) + { + ++anArgIter; + } + aCtx->MainSelector()->SetPickClosest (toPreferClosest); + } + else if ((anArg == "-depthtol" + || anArg == "-depthtolerance") + && anArgIter + 1 < theArgsNb) + { + TCollection_AsciiString aTolType (theArgVec[++anArgIter]); + aTolType.LowerCase(); + if (aTolType == "uniform") + { + if (anArgIter + 1 >= theArgsNb) + { + Message::SendFail() << "Syntax error: wrong number of arguments"; + return 1; + } + aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform, + Draw::Atof (theArgVec[++anArgIter])); + } + else if (aTolType == "uniformpx") + { + if (anArgIter + 1 >= theArgsNb) + { + Message::SendFail() << "Syntax error: wrong number of arguments"; + return 1; + } + aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels, + Draw::Atof (theArgVec[++anArgIter])); + } + else if (aTolType == "sensfactor") + { + aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0); + } + else + { + Message::SendFail() << "Syntax error at '" << aTolType << "'"; + return 1; + } + } else if ((anArg == "-mode" || anArg == "-dispmode") && anArgIter + 1 < theArgsNb) @@ -13429,6 +13475,7 @@ static int VSelectionProperties (Draw_Interpretor& theDi, else { Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'"; + return 1; } } @@ -14898,6 +14945,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\n 'first' to pick first acceptable (default)" "\n 'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)" "\n -pixTol value : sets up pixel tolerance" + "\n -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth" + "\n -depthTol {sensfactor} : use sensitive factor for sorting results by depth" + "\n -preferClosest {0|1} : sets if depth should take precedence over priority while sorting results" "\n -dispMode dispMode : sets display mode for highlighting" "\n -layer ZLayer : sets ZLayer for highlighting" "\n -color {name|r g b} : sets highlight color"