From 28ee613b27e67e293218f31762850649d7bda805 Mon Sep 17 00:00:00 2001 From: vpa Date: Wed, 6 May 2015 15:35:36 +0300 Subject: [PATCH] 0026159: Visualization - revise tolerance implementation for selection Max tolerance is now applied to all objects and entities by default; if there is an entity with a lower tolerance, selecting frustum will be recalculated for it. The ability to set sensitivity for each entity individually is moved to protected section of SelectBasics_SensitiveEntity SetPixelTolerance from AIS_InteractiveContext now sets custom tolerance that is applied to all sensitives. Added -unset option to vselprecision command to disable custom tolerances. Test case for issue #26159 --- src/AIS/AIS_InteractiveContext.cdl | 7 +- src/AIS/AIS_InteractiveContext.cxx | 10 +- src/IVtkOCC/IVtkOCC_ViewerSelector.cxx | 4 +- .../SelectBasics_SensitiveEntity.cdl | 11 +- src/SelectMgr/SelectMgr_BaseFrustum.hxx | 4 + .../SelectMgr_RectangularFrustum.cxx | 131 +++++++++++++++ .../SelectMgr_RectangularFrustum.hxx | 7 +- .../SelectMgr_SelectingVolumeManager.cxx | 19 +++ .../SelectMgr_SelectingVolumeManager.hxx | 4 + src/SelectMgr/SelectMgr_ViewerSelector.cxx | 157 ++++++++++++------ src/SelectMgr/SelectMgr_ViewerSelector.hxx | 34 +++- src/StdSelect/StdSelect_ViewerSelector3d.cxx | 6 +- src/ViewerTest/ViewerTest.cxx | 20 ++- tests/bugs/vis/bug24564 | 4 +- tests/bugs/vis/bug26159 | 23 +++ 15 files changed, 362 insertions(+), 79 deletions(-) create mode 100644 tests/bugs/vis/bug26159 diff --git a/src/AIS/AIS_InteractiveContext.cdl b/src/AIS/AIS_InteractiveContext.cdl index 2270226d10..8026b714fc 100644 --- a/src/AIS/AIS_InteractiveContext.cdl +++ b/src/AIS/AIS_InteractiveContext.cdl @@ -429,10 +429,11 @@ is -- aMode provides the selection mode index of the entity aniobj. SetPixelTolerance(me:mutable; - aPrecision: Real from Standard = 4.0); + aPrecision: Real from Standard = 2.0); ---Level: Public - ---Purpose: Define the current selection pixel sensitivity - -- for this context or local context if any one is activated. + ---Purpose: Disables the mechanism of adaptive tolerance calculation in SelectMgr_ViewerSelector and + -- sets the given tolerance for ALL sensitive entities activated. For more information, see + -- SelectMgr_ViewerSelector documentation -- Warning: When a local context is open the sensitivity is apply on it -- instead on the main context. diff --git a/src/AIS/AIS_InteractiveContext.cxx b/src/AIS/AIS_InteractiveContext.cxx index 3c3d400254..e653481028 100644 --- a/src/AIS/AIS_InteractiveContext.cxx +++ b/src/AIS/AIS_InteractiveContext.cxx @@ -1703,6 +1703,7 @@ void AIS_InteractiveContext::redisplayPrsRecModes (const Handle(AIS_InteractiveO { theIObj->Update (aModes.Value(), Standard_False); } + theIObj->UpdateSelection(); theIObj->SetRecomputeOk(); } @@ -2590,7 +2591,10 @@ void AIS_InteractiveContext::UnsetSelectionMode (const Handle(AIS_InteractiveObj //======================================================================= //function : SetPixelTolerance -//purpose : +//purpose : Disables the mechanism of adaptive tolerance calculation in +// SelectMgr_ViewerSelector and sets the given tolerance for ALL +// sensitive entities activated. For more information, see +// SelectMgr_ViewerSelector.hxx //======================================================================= void AIS_InteractiveContext::SetPixelTolerance (const Standard_Real thePrecision) { @@ -2672,8 +2676,8 @@ void AIS_InteractiveContext::InitAttributes() aLineAspect->SetWidth (1.0); aLineAspect->SetTypeOfLine (Aspect_TOL_DASH); - // tolerance to 4 pixels... - SetPixelTolerance(); + // tolerance to 2 pixels... + SetPixelTolerance (2.0); // Customizing the drawer for trihedrons and planes... Handle(Prs3d_DatumAspect) aTrihAspect = myDefaultDrawer->DatumAspect(); diff --git a/src/IVtkOCC/IVtkOCC_ViewerSelector.cxx b/src/IVtkOCC/IVtkOCC_ViewerSelector.cxx index c3fb9e5a22..1a17c1b4b6 100644 --- a/src/IVtkOCC/IVtkOCC_ViewerSelector.cxx +++ b/src/IVtkOCC/IVtkOCC_ViewerSelector.cxx @@ -187,7 +187,7 @@ void IVtkOCC_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theSel theSelection->SetSelectionState (SelectMgr_SOS_Activated); myTolerances.Add (theSelection->Sensitivity()); - mytolerance = myTolerances.Largest(); + mytolerance = myTolerances.Tolerance(); myToUpdateTolerance = Standard_True; } @@ -205,6 +205,6 @@ void IVtkOCC_ViewerSelector::Deactivate (const Handle(SelectMgr_Selection)& theS theSelection->SetSelectionState (SelectMgr_SOS_Deactivated); myTolerances.Decrement (theSelection->Sensitivity()); - mytolerance = myTolerances.Largest(); + mytolerance = myTolerances.Tolerance(); myToUpdateTolerance = Standard_True; } diff --git a/src/SelectBasics/SelectBasics_SensitiveEntity.cdl b/src/SelectBasics/SelectBasics_SensitiveEntity.cdl index 02d7d0fbcb..185f60ca7e 100644 --- a/src/SelectBasics/SelectBasics_SensitiveEntity.cdl +++ b/src/SelectBasics/SelectBasics_SensitiveEntity.cdl @@ -54,11 +54,6 @@ is ---Purpose: Checks whether the sensitive entity is overlapped by -- current selecting volume - SetSensitivityFactor (me : mutable; - theSensFactor :Real from Standard); - ---C++: inline - ---Purpose: Allows to manage the sensitivity of the entity - SensitivityFactor (me) returns Real from Standard; ---C++: inline @@ -83,6 +78,12 @@ is Clear (me : mutable) is deferred; ---Purpose: Clears up all the resources and memory allocated + SetSensitivityFactor (me : mutable; + theSensFactor :Real from Standard) + is protected; + ---C++: inline + ---Purpose: Allows to manage the sensitivity of the entity + fields diff --git a/src/SelectMgr/SelectMgr_BaseFrustum.hxx b/src/SelectMgr/SelectMgr_BaseFrustum.hxx index b76bfec434..83ce1e6443 100644 --- a/src/SelectMgr/SelectMgr_BaseFrustum.hxx +++ b/src/SelectMgr/SelectMgr_BaseFrustum.hxx @@ -88,6 +88,10 @@ public: virtual NCollection_Handle Transform (const gp_Trsf& /*theTrsf*/) { return NULL; } + //! IMPORTANT: Makes sense only for frustum built on a single point! + //! Returns a copy of the frustum resized according to the scale factor given + virtual NCollection_Handle Scale (const Standard_Real /*theScaleFactor*/) { return NULL; } + //! SAT intersection test between defined volume and given axis-aligned box virtual Standard_Boolean Overlaps (const BVH_Box& theBndBox, Standard_Real& theDepth); diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx index 3646f50dc2..2c2f492f73 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx @@ -154,6 +154,7 @@ void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint) myNearPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 0.0); myFarPickedPnt = myBuilder->ProjectPntOnViewPlane (thePoint.X(), thePoint.Y(), 1.0); myViewRayDir = myFarPickedPnt - myNearPickedPnt; + myMousePos = thePoint; // LeftTopNear myVertices[0] = myBuilder->ProjectPntOnViewPlane (thePoint.X() - myPixelTolerance / 2.0, @@ -511,6 +512,136 @@ NCollection_Handle SelectMgr_RectangularFrustum::Transfor return NCollection_Handle (aRes); } +// ======================================================================= +// function : Scale +// purpose : IMPORTANT: Makes sense only for frustum built on a single point! +// Returns a copy of the frustum resized according to the scale factor given +// ======================================================================= +NCollection_Handle SelectMgr_RectangularFrustum::Scale (const Standard_Real theScaleFactor) +{ + SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum(); + + aRes->myNearPickedPnt = myNearPickedPnt; + aRes->myFarPickedPnt = myFarPickedPnt; + aRes->myViewRayDir = myViewRayDir; + + aRes->myIsOrthographic = myIsOrthographic; + + // LeftTopNear + aRes->myVertices[0] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, + myMousePos.Y() + theScaleFactor / 2.0, + 0.0); + // LeftTopFar + aRes->myVertices[1] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, + myMousePos.Y() + theScaleFactor / 2.0, + 1.0); + // LeftBottomNear + aRes->myVertices[2] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, + myMousePos.Y() - theScaleFactor / 2.0, + 0.0); + // LeftBottomFar + aRes->myVertices[3] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() - theScaleFactor / 2.0, + myMousePos.Y() - theScaleFactor / 2.0, + 1.0); + // RightTopNear + aRes->myVertices[4] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, + myMousePos.Y() + theScaleFactor / 2.0, + 0.0); + // RightTopFar + aRes->myVertices[5] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, + myMousePos.Y() + theScaleFactor / 2.0, + 1.0); + // RightBottomNear + aRes->myVertices[6] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, + myMousePos.Y() - theScaleFactor / 2.0, + 0.0); + // RightBottomFar + aRes->myVertices[7] = myBuilder->ProjectPntOnViewPlane (myMousePos.X() + theScaleFactor / 2.0, + myMousePos.Y() - theScaleFactor / 2.0, + 1.0); + // Top + aRes->myPlanes[0] = myBuilder->PlaneEquation (aRes->myVertices[1], + aRes->myVertices[0], + aRes->myVertices[5], + aRes->myVertices[6]); + // Bottom + aRes->myPlanes[1] = myBuilder->PlaneEquation (aRes->myVertices[3], + aRes->myVertices[2], + aRes->myVertices[7], + aRes->myVertices[4]); + // Left + aRes->myPlanes[2] = myBuilder->PlaneEquation (aRes->myVertices[1], + aRes->myVertices[0], + aRes->myVertices[2], + aRes->myVertices[6]); + // Right + aRes->myPlanes[3] = myBuilder->PlaneEquation (aRes->myVertices[5], + aRes->myVertices[4], + aRes->myVertices[6], + aRes->myVertices[2]); + // Near + aRes->myPlanes[4] = myBuilder->PlaneEquation (aRes->myVertices[4], + aRes->myVertices[6], + aRes->myVertices[2], + aRes->myVertices[3]); + // Far + aRes->myPlanes[5] = myBuilder->PlaneEquation (aRes->myVertices[5], + aRes->myVertices[7], + aRes->myVertices[3], + aRes->myVertices[2]); + + for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 6; ++aPlaneIdx) + { + Standard_Real aMax = -DBL_MAX; + Standard_Real aMin = DBL_MAX; + const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx]; + for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) + { + Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]); + aMax = Max (aMax, aProjection); + aMin = Min (aMin, aProjection); + } + aRes->myMaxVertsProjections[aPlaneIdx] = aMax; + aRes->myMinVertsProjections[aPlaneIdx] = aMin; + } + + SelectMgr_Vec3 aDimensions[3] = + { + SelectMgr_Vec3 (1.0, 0.0, 0.0), + SelectMgr_Vec3 (0.0, 1.0, 0.0), + SelectMgr_Vec3 (0.0, 0.0, 1.0) + }; + + for (Standard_Integer aDim = 0; aDim < 3; ++aDim) + { + Standard_Real aMax = -DBL_MAX; + Standard_Real aMin = DBL_MAX; + for (Standard_Integer aVertIdx = 0; aVertIdx < 8; ++aVertIdx) + { + Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]); + aMax = Max (aMax, aProjection); + aMin = Min (aMin, aProjection); + } + aRes->myMaxOrthoVertsProjections[aDim] = aMax; + aRes->myMinOrthoVertsProjections[aDim] = aMin; + } + + // Horizontal + aRes->myEdgeDirs[0] = aRes->myVertices[4] - aRes->myVertices[0]; + // Vertical + aRes->myEdgeDirs[1] = aRes->myVertices[2] - aRes->myVertices[0]; + // LeftLower + aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[3]; + // RightLower + aRes->myEdgeDirs[3] = aRes->myVertices[6] - aRes->myVertices[7]; + // LeftUpper + aRes->myEdgeDirs[4] = aRes->myVertices[0] - aRes->myVertices[1]; + // RightUpper + aRes->myEdgeDirs[5] = aRes->myVertices[4] - aRes->myVertices[5]; + + return NCollection_Handle (aRes); +} + // ======================================================================= // function : Overlaps // purpose : Returns true if selecting volume is overlapped by diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.hxx b/src/SelectMgr/SelectMgr_RectangularFrustum.hxx index ea9316f9ff..fd41e47830 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.hxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.hxx @@ -45,6 +45,10 @@ public: //! Returns a copy of the frustum transformed according to the matrix given virtual NCollection_Handle Transform (const gp_Trsf& theTrsf) Standard_OVERRIDE; + //! IMPORTANT: Makes sense only for frustum built on a single point! + //! Returns a copy of the frustum resized according to the scale factor given + virtual NCollection_Handle Scale (const Standard_Real theScaleFactor) Standard_OVERRIDE; + // SAT Tests for different objects @@ -107,8 +111,9 @@ protected: private: SelectMgr_Vec3 myNearPickedPnt; //!< 3d projection of user-picked selection point onto near view plane - SelectMgr_Vec3 myFarPickedPnt; //!< 3d projection of user-picked selection point onto far view plane + SelectMgr_Vec3 myFarPickedPnt; //!< 3d projection of user-picked selection point onto far view plane SelectMgr_Vec3 myViewRayDir; + gp_Pnt2d myMousePos; //!< Mouse coordinates }; #endif // _SelectMgr_RectangularFrustum_HeaderFile diff --git a/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx b/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx index c136cfd14d..a1c46ed385 100644 --- a/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx +++ b/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx @@ -48,6 +48,25 @@ SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::Transform (co return aMgr; } +//======================================================================= +// function : Scale +// purpose : IMPORTANT: Makes sense only for point selection! +// Returns a copy of the frustum resized according to the scale factor given +//======================================================================= +SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::Scale (const Standard_Real theScaleFactor) +{ + if (myActiveSelectionType != Point) + return SelectMgr_SelectingVolumeManager (Standard_False); + + SelectMgr_SelectingVolumeManager aMgr (Standard_False); + + aMgr.myActiveSelectionType = Point; + + aMgr.mySelectingVolumes[Point] = mySelectingVolumes[Point]->Scale (theScaleFactor); + + return aMgr; +} + //======================================================================= // function : GetActiveSelectionType // purpose : diff --git a/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx b/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx index d811ca25f8..3a13e43bc2 100644 --- a/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx +++ b/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx @@ -40,6 +40,10 @@ public: //! Returns a copy of active frustum transformed according to the matrix given Standard_EXPORT virtual SelectMgr_SelectingVolumeManager Transform (const gp_Trsf& theTrsf); + //! IMPORTANT: Makes sense only for point selection! + //! Returns a copy of the frustum resized according to the scale factor given + Standard_EXPORT virtual SelectMgr_SelectingVolumeManager Scale (const Standard_Real theScaleFactor); + Standard_EXPORT virtual Standard_Integer GetActiveSelectionType() const Standard_OVERRIDE; Standard_EXPORT void SetActiveSelectionType (const SelectionType& theType); diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.cxx b/src/SelectMgr/SelectMgr_ViewerSelector.cxx index a2d82dc953..28a12000fc 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.cxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.cxx @@ -39,28 +39,30 @@ IMPLEMENT_STANDARD_HANDLE (SelectMgr_ViewerSelector, MMgt_TShared) IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_ViewerSelector, MMgt_TShared) -static Standard_Boolean SelectDebugModeOnVS() -{ - static Standard_Integer isDebugMode( -1 ); - if ( isDebugMode < 0 ) { - isDebugMode = 1; - OSD_Environment selectdb("SELDEBUGMODE"); - if ( selectdb.Value().IsEmpty() ) - isDebugMode = 0; - } - return ( isDebugMode != 0 ); -} - +//======================================================================= +// function: SelectMgr_ToleranceMap +// purpose : Sets tolerance values to -1.0 +//======================================================================= SelectMgr_ToleranceMap::SelectMgr_ToleranceMap() { - myLargestKey = -1; + myLargestKey = -1.0; + myCustomTolerance = -1.0; } +//======================================================================= +// function: ~SelectMgr_ToleranceMap +// purpose : +//======================================================================= SelectMgr_ToleranceMap::~SelectMgr_ToleranceMap() { myTolerances.Clear(); } +//======================================================================= +// function: Add +// purpose : Adds the value given to map, checks if the current tolerance value +// should be replaced by theTolerance +//======================================================================= void SelectMgr_ToleranceMap::Add (const Standard_Real& theTolerance) { if (myTolerances.IsBound (theTolerance)) @@ -68,14 +70,8 @@ void SelectMgr_ToleranceMap::Add (const Standard_Real& theTolerance) Standard_Integer& aFreq = myTolerances.ChangeFind (theTolerance); aFreq++; - if (theTolerance == myLargestKey) - return; - - Standard_Integer aMaxFreq = myTolerances.Find (myLargestKey); - if (aFreq >= aMaxFreq) - { - myLargestKey = aFreq == aMaxFreq ? Max (myLargestKey, theTolerance) : theTolerance; - } + if (aFreq == 1 && theTolerance != myLargestKey) + myLargestKey = Max (theTolerance, myLargestKey); } else { @@ -87,14 +83,15 @@ void SelectMgr_ToleranceMap::Add (const Standard_Real& theTolerance) } myTolerances.Bind (theTolerance, 1); - Standard_Integer aMaxFreq = myTolerances.Find (myLargestKey); - if (aMaxFreq <= 1) - { - myLargestKey = aMaxFreq == 1 ? Max (myLargestKey, theTolerance) : theTolerance; - } + myLargestKey = Max (theTolerance, myLargestKey); } } +//======================================================================= +// function: Decrement +// purpose : Decrements a counter of the tolerance given, checks if the current tolerance value +// should be recalculated +//======================================================================= void SelectMgr_ToleranceMap::Decrement (const Standard_Real& theTolerance) { if (myTolerances.IsBound (theTolerance)) @@ -102,24 +99,43 @@ void SelectMgr_ToleranceMap::Decrement (const Standard_Real& theTolerance) Standard_Integer& aFreq = myTolerances.ChangeFind (theTolerance); aFreq--; - if (theTolerance == myLargestKey) + if (Abs (theTolerance - myLargestKey) < Precision::Confusion() && aFreq == 0) { - Standard_Integer aMaxFreq = aFreq; + myLargestKey = 0.0; for (NCollection_DataMap::Iterator anIter (myTolerances); anIter.More(); anIter.Next()) { - if (aMaxFreq <= anIter.Value() && myLargestKey != anIter.Key()) - { - aMaxFreq = anIter.Value(); - myLargestKey = anIter.Key(); - } + if (anIter.Value() != 0) + myLargestKey = Max (myLargestKey, anIter.Key()); } } } } -Standard_Real SelectMgr_ToleranceMap::Largest() +//======================================================================= +// function: Tolerance +// purpose : Returns a current tolerance that must be applied +//======================================================================= +Standard_Real SelectMgr_ToleranceMap::Tolerance() { - return myLargestKey; + return myCustomTolerance < 0.0 ? myLargestKey : myCustomTolerance; +} + +//======================================================================= +// function: SetCustomTolerance +// purpose : Sets tolerance to the given one and disables adaptive checks +//======================================================================= +void SelectMgr_ToleranceMap::SetCustomTolerance (const Standard_Real theTolerance) +{ + myCustomTolerance = theTolerance; +} + +//======================================================================= +// function: ResetDefaults +// purpose : Unsets a custom tolerance and enables adaptive checks +//======================================================================= +void SelectMgr_ToleranceMap::ResetDefaults() +{ + myCustomTolerance = -1.0; } //================================================== @@ -152,7 +168,7 @@ void SelectMgr_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theS theSelection->SetSelectionState (SelectMgr_SOS_Activated); myTolerances.Add (theSelection->Sensitivity()); - mytolerance = myTolerances.Largest(); + mytolerance = myTolerances.Tolerance(); myToUpdateTolerance = Standard_True; } @@ -171,7 +187,7 @@ void SelectMgr_ViewerSelector::Deactivate (const Handle(SelectMgr_Selection)& th theSelection->SetSelectionState (SelectMgr_SOS_Deactivated); myTolerances.Decrement (theSelection->Sensitivity()); - mytolerance = myTolerances.Largest(); + mytolerance = myTolerances.Tolerance(); myToUpdateTolerance = Standard_True; } @@ -185,6 +201,39 @@ void SelectMgr_ViewerSelector::Clear() myMapOfDetected.Clear(); } +//======================================================================= +// function: isToScaleFrustum +// purpose : Checks if the entity given requires to scale current selecting frustum +//======================================================================= +Standard_Boolean SelectMgr_ViewerSelector::isToScaleFrustum (const Handle(SelectBasics_SensitiveEntity)& theEntity) +{ + return mySelectingVolumeMgr.GetActiveSelectionType() == SelectMgr_SelectingVolumeManager::Point + && theEntity->SensitivityFactor() < myTolerances.Tolerance(); +} + +//======================================================================= +// function: scaleAndTransform +// purpose : Applies given scale and transformation matrices to the default selecting volume manager +//======================================================================= +SelectMgr_SelectingVolumeManager SelectMgr_ViewerSelector::scaleAndTransform (const Standard_Real theScale, + const gp_Trsf& theTrsf) +{ + SelectMgr_SelectingVolumeManager aMgr; + + if (theScale > Precision::Angular()) + { + aMgr = mySelectingVolumeMgr.Scale (theScale); + } + + if (theTrsf.Form() != gp_Identity) + { + aMgr = aMgr.GetActiveSelectionType() == SelectMgr_SelectingVolumeManager::Unknown ? + mySelectingVolumeMgr.Transform (theTrsf) : aMgr.Transform (theTrsf); + } + + return aMgr; +} + //======================================================================= // function: checkOverlap // purpose : Internal function that checks if a particular sensitive @@ -202,9 +251,7 @@ void SelectMgr_ViewerSelector::checkOverlap (const Handle(SelectBasics_Sensitive { if (!anOwner.IsNull()) { - Standard_Boolean isPointSelection = - theMgr.GetActiveSelectionType() == SelectMgr_SelectingVolumeManager::Point; - if (HasDepthClipping (anOwner) && isPointSelection) + if (HasDepthClipping (anOwner) && theMgr.GetActiveSelectionType() == SelectMgr_SelectingVolumeManager::Point) { Standard_Boolean isClipped = theMgr.IsClipped (anOwner->Selectable()->GetClipPlanes(), aPickResult.Depth()); @@ -255,6 +302,8 @@ void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_Selectable SelectMgr_SelectingVolumeManager aMgr = theObject->HasTransformation() ? mySelectingVolumeMgr.Transform (theObject->InversedTransformation()) : mySelectingVolumeMgr; + NCollection_DataMap aScaledTrnsfFrustums; + Standard_Integer aNode = 0; // a root node if (!aMgr.Overlaps (aSensitivesTree->MinPoint (0), aSensitivesTree->MaxPoint (0))) @@ -306,7 +355,19 @@ void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_Selectable anEntitySet->GetSensitiveById (anIdx); if (aSensitive->IsActiveForSelection()) { - checkOverlap (aSensitive->BaseSensitive(), anIdx, aMgr); + const Handle(SelectBasics_SensitiveEntity)& anEnt = aSensitive->BaseSensitive(); + SelectMgr_SelectingVolumeManager aTmpMgr = aMgr; + if (isToScaleFrustum (anEnt)) + { + if (!aScaledTrnsfFrustums.IsBound (anEnt->DynamicType())) + { + aScaledTrnsfFrustums.Bind (anEnt->DynamicType(), + scaleAndTransform (anEnt->SensitivityFactor(), theObject->InversedTransformation())); + } + + aTmpMgr = aScaledTrnsfFrustums.Find (anEnt->DynamicType()); + } + checkOverlap (anEnt, anIdx, aTmpMgr); } } if (aHead < 0) @@ -397,20 +458,6 @@ void SelectMgr_ViewerSelector::TraverseSensitives() } SortResult(); - - if (SelectDebugModeOnVS()) - { - cout<<"\tSelectMgr_VS:: Resultat du move"<Value(i)); - cout << "\t" << i << " - Prior" << Crit.Priority() - << " - prof :" << Crit.Depth() - << " - Dist. :" << Crit.MinDist() << endl; - } - } } //================================================== diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.hxx b/src/SelectMgr/SelectMgr_ViewerSelector.hxx index 5df7321793..3f9def378b 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.hxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.hxx @@ -57,23 +57,41 @@ typedef NCollection_DataMap SelectMgr_MapOfOwnerDetectedEntities; typedef NCollection_DataMap::Iterator SelectMgr_MapOfOwnerDetectedEntitiesIterator; +//! An internal class for calculation of current largest tolerance value which will be applied +//! for creation of selecting frustum by default. Each time the selection set is deactivated, +//! maximum tolerance value will be recalculated. If a user enables custom precision using +//! StdSelect_ViewerSelector3d::SetPixelTolerance, it will be applied to all sensitive entities +//! without any checks. class SelectMgr_ToleranceMap { public: + //! Sets tolerance values to -1.0 SelectMgr_ToleranceMap(); Standard_EXPORT ~SelectMgr_ToleranceMap(); + //! Adds the value given to map, checks if the current tolerance value + //! should be replaced by theTolerance Standard_EXPORT void Add (const Standard_Real& theTolerance); + //! Decrements a counter of the tolerance given, checks if the current tolerance value + //! should be recalculated Standard_EXPORT void Decrement (const Standard_Real& theTolerance); - Standard_EXPORT Standard_Real Largest(); + //! Returns a current tolerance that must be applied + Standard_EXPORT Standard_Real Tolerance(); + + //! Sets tolerance to the given one and disables adaptive checks + Standard_EXPORT void SetCustomTolerance (const Standard_Real theTolerance); + + //! Unsets a custom tolerance and enables adaptive checks + Standard_EXPORT void ResetDefaults(); private: NCollection_DataMap myTolerances; Standard_Real myLargestKey; + Standard_Real myCustomTolerance; }; //! A framework to define finding, sorting the sensitive @@ -99,6 +117,13 @@ private: //! SelectMgr_SelectionManager, and manipulate //! the SelectMgr_Selection objects given to them by //! the selection manager. +//! +//! Tolerances are applied to the entities in the following way: +//! 1. tolerance value stored in mytolerance will be used to calculate initial +//! selecting frustum, which will be applied for intersection testing during +//! BVH traverse; +//! 2. if tolerance of sensitive entity is less than mytolerance, the frustum for +//! intersection detection will be resized according to its sensitivity. class SelectMgr_ViewerSelector : public MMgt_TShared { public: @@ -255,6 +280,13 @@ protected: //! Marks all added sensitive entities of all objects as non-selectable void resetSelectionActivationStatus(); + //! Checks if the entity given requires to scale current selecting frustum + Standard_Boolean isToScaleFrustum (const Handle(SelectBasics_SensitiveEntity)& theEntity); + + //! Applies given scale and transformation matrices to the default selecting volume manager + SelectMgr_SelectingVolumeManager scaleAndTransform (const Standard_Real theScale, + const gp_Trsf& theTrsf); + private: void Activate (const Handle(SelectMgr_Selection)& theSelection); diff --git a/src/StdSelect/StdSelect_ViewerSelector3d.cxx b/src/StdSelect/StdSelect_ViewerSelector3d.cxx index b90c8974eb..a8881d8af4 100644 --- a/src/StdSelect/StdSelect_ViewerSelector3d.cxx +++ b/src/StdSelect/StdSelect_ViewerSelector3d.cxx @@ -97,7 +97,11 @@ void StdSelect_ViewerSelector3d::SetPixelTolerance (const Standard_Real theToler { if (mytolerance != theTolerance) { - mytolerance = theTolerance; + if (theTolerance < 0.0) + myTolerances.ResetDefaults(); + else + myTolerances.SetCustomTolerance (theTolerance); + mytolerance = myTolerances.Tolerance(); myToUpdateTolerance = Standard_True; } } diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 98635194a3..dc78b59bd2 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -749,7 +749,7 @@ static int VSelPrecision(Draw_Interpretor& di, Standard_Integer argc, const char { if( argc > 2 ) { - di << "Use: " << argv[0] << " [tolerance_value]\n"; + di << "Wrong parameters! Must be: " << argv[0] << " [-unset] [tolerance]\n"; return 1; } @@ -760,14 +760,20 @@ static int VSelPrecision(Draw_Interpretor& di, Standard_Integer argc, const char if( argc == 1 ) { Standard_Real aPixelTolerance = aContext->PixelTolerance(); - di << "Precision mode : 0 (window)\n"; di << "Pixel tolerance : " << aPixelTolerance << "\n"; } else if (argc == 2) { - - Standard_Integer aPixelTolerance = Draw::Atoi (argv[1]); - aContext->SetPixelTolerance (aPixelTolerance); + TCollection_AsciiString anArg = TCollection_AsciiString (argv[1]); + anArg.LowerCase(); + if (anArg == "-unset") + { + aContext->SetPixelTolerance (-1.0); + } + else + { + aContext->SetPixelTolerance (anArg.RealValue()); + } } return 0; @@ -5275,7 +5281,9 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands) __FILE__,VClearSensi,group); theCommands.Add("vselprecision", - "vselprecision : vselprecision [tolerance_value]", + "vselprecision [-unset] [tolerance_value]" + "\n\t\t Manages selection precision or prints current value if no parameter is passed." + "\n\t\t -unset - restores default selection tolerance behavior, based on individual entity tolerance", __FILE__,VSelPrecision,group); theCommands.Add("vperf", diff --git a/tests/bugs/vis/bug24564 b/tests/bugs/vis/bug24564 index 85f09be384..7da16a0d36 100644 --- a/tests/bugs/vis/bug24564 +++ b/tests/bugs/vis/bug24564 @@ -24,8 +24,8 @@ vfit vtop vaspects -setwidth 5 -vmoveto 199 200 -if { "[vreadpixel 199 200 rgb name]" != "CYAN1" } { +vmoveto 200 200 +if { "[vreadpixel 200 200 rgb name]" != "CYAN1" } { puts "Error : The box is not selectable!" } diff --git a/tests/bugs/vis/bug26159 b/tests/bugs/vis/bug26159 new file mode 100644 index 0000000000..08d94f64ca --- /dev/null +++ b/tests/bugs/vis/bug26159 @@ -0,0 +1,23 @@ +puts "================================================================" +puts "CR26159" +puts "Visualization - revise tolerance implementation for selection." +puts "================================================================" +puts "" + +pload VISUALIZATION MODELING +box b1 1 1 1 1 1 1 +box b2 3 3 3 1 1 1 +box b3 6 6 6 1 1 1 +vdisplay b1 b2 b3 +vfit + +# activate vertex selection +vselmode b1 1 1 + +# check selection tolerance +vmoveto 58 324 +checkcolor 58 324 0 1 1 + +# to print tolerance in case of failure: +puts [vselprecision] +vdump $imagedir/${casename}