0026159: Visualization - revise tolerance implementation for selection
authorvpa <vpa@opencascade.com>
Wed, 6 May 2015 12:35:36 +0000 (15:35 +0300)
committerabv <abv@opencascade.com>
Fri, 8 May 2015 05:51:48 +0000 (08:51 +0300)
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

15 files changed:
src/AIS/AIS_InteractiveContext.cdl
src/AIS/AIS_InteractiveContext.cxx
src/IVtkOCC/IVtkOCC_ViewerSelector.cxx
src/SelectBasics/SelectBasics_SensitiveEntity.cdl
src/SelectMgr/SelectMgr_BaseFrustum.hxx
src/SelectMgr/SelectMgr_RectangularFrustum.cxx
src/SelectMgr/SelectMgr_RectangularFrustum.hxx
src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx
src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx
src/SelectMgr/SelectMgr_ViewerSelector.cxx
src/SelectMgr/SelectMgr_ViewerSelector.hxx
src/StdSelect/StdSelect_ViewerSelector3d.cxx
src/ViewerTest/ViewerTest.cxx
tests/bugs/vis/bug24564
tests/bugs/vis/bug26159 [new file with mode: 0644]

index 2270226..8026b71 100644 (file)
@@ -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.
 
index 3c3d400..e653481 100644 (file)
@@ -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();
index c3fb9e5..1a17c1b 100644 (file)
@@ -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;
 }
index 02d7d0f..185f60c 100644 (file)
@@ -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
     
index b76bfec..83ce1e6 100644 (file)
@@ -88,6 +88,10 @@ public:
 
   virtual NCollection_Handle<SelectMgr_BaseFrustum> 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<SelectMgr_BaseFrustum> 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<Standard_Real, 3>& theBndBox,
                                      Standard_Real& theDepth);
index 3646f50..2c2f492 100644 (file)
@@ -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,
@@ -512,6 +513,136 @@ NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::Transfor
 }
 
 // =======================================================================
+// 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_BaseFrustum> 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<SelectMgr_BaseFrustum> (aRes);
+}
+
+// =======================================================================
 // function : Overlaps
 // purpose  : Returns true if selecting volume is overlapped by
 //            axis-aligned bounding box with minimum corner at point
index ea9316f..fd41e47 100644 (file)
@@ -45,6 +45,10 @@ public:
   //! Returns a copy of the frustum transformed according to the matrix given
   virtual NCollection_Handle<SelectMgr_BaseFrustum> 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<SelectMgr_BaseFrustum> 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
index c136cfd..a1c46ed 100644 (file)
@@ -49,6 +49,25 @@ SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::Transform (co
 }
 
 //=======================================================================
+// 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  :
 //=======================================================================
index d811ca2..3a13e43 100644 (file)
@@ -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);
index a2d82dc..28a1200 100644 (file)
 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<Standard_Real, Standard_Integer>::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 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()
 {
-  return myLargestKey;
+  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;
 }
 
@@ -186,6 +202,39 @@ void SelectMgr_ViewerSelector::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
 //           entity theEntity overlaps current selecting volume precisely
@@ -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<Handle(Standard_Type), SelectMgr_SelectingVolumeManager> 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"<<endl;
-    cout<<"\tNb Detectes :"<<mystored.Extent()<<endl;
-
-    for(Standard_Integer i=1; i<=mystored.Extent(); i++)
-    {
-      const SelectMgr_SortCriterion& Crit = mystored (myIndexes->Value(i));
-      cout << "\t" << i << " - Prior" << Crit.Priority()
-           << " - prof :" << Crit.Depth()
-           << "  - Dist. :" << Crit.MinDist() << endl;
-    }
-  }
 }
 
 //==================================================
index 5df7321..3f9def3 100644 (file)
@@ -57,23 +57,41 @@ typedef NCollection_DataMap<Handle(SelectMgr_SelectableObject), NCollection_Hand
 typedef NCollection_DataMap<Handle(SelectMgr_EntityOwner), Standard_Integer> SelectMgr_MapOfOwnerDetectedEntities;
 typedef NCollection_DataMap<Handle(SelectMgr_EntityOwner), Standard_Integer>::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<Standard_Real, Standard_Integer> 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);
index b90c897..a8881d8 100644 (file)
@@ -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;
   }
 }
index 9863519..dc78b59 100644 (file)
@@ -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",
index 85f09be..7da16a0 100644 (file)
@@ -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 (file)
index 0000000..08d94f6
--- /dev/null
@@ -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}