]> OCCT Git - occt.git/commitdiff
0032182: Visualization - add Select3D_SensitiveSphere
authormkrylova <mkrylova@opencascade.com>
Wed, 17 Mar 2021 14:38:00 +0000 (17:38 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 24 Jun 2021 16:52:25 +0000 (19:52 +0300)
- created Select3D_SensitiveSphere class
- implemented interfaces for intersection methods
- added tests

25 files changed:
src/Select3D/FILES
src/Select3D/Select3D_SensitiveSphere.cxx [new file with mode: 0644]
src/Select3D/Select3D_SensitiveSphere.hxx [new file with mode: 0644]
src/SelectBasics/SelectBasics_SelectingVolumeManager.hxx
src/SelectMgr/SelectMgr_AxisIntersector.cxx
src/SelectMgr/SelectMgr_AxisIntersector.hxx
src/SelectMgr/SelectMgr_BaseFrustum.cxx
src/SelectMgr/SelectMgr_BaseFrustum.hxx
src/SelectMgr/SelectMgr_BaseIntersector.cxx
src/SelectMgr/SelectMgr_BaseIntersector.hxx
src/SelectMgr/SelectMgr_Frustum.hxx
src/SelectMgr/SelectMgr_Frustum.lxx
src/SelectMgr/SelectMgr_RectangularFrustum.cxx
src/SelectMgr/SelectMgr_RectangularFrustum.hxx
src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx
src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx
src/SelectMgr/SelectMgr_TriangularFrustum.cxx
src/SelectMgr/SelectMgr_TriangularFrustum.hxx
src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx
src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx
src/StdSelect/StdSelect_BRepSelectionTool.cxx
tests/vselect/clipping/bug30777
tests/vselect/sphere/check_depth [new file with mode: 0644]
tests/vselect/sphere/detecting [new file with mode: 0644]
tests/vselect/sphere/polygon_selection [new file with mode: 0644]

index 24e8443be997542d6059d03a1ee37bf7d60f29f1..d779a8c3220a3a4b0d0585f8d1c7653e2d834c56 100755 (executable)
@@ -29,6 +29,8 @@ Select3D_SensitiveSegment.cxx
 Select3D_SensitiveSegment.hxx
 Select3D_SensitiveSet.cxx
 Select3D_SensitiveSet.hxx
+Select3D_SensitiveSphere.cxx
+Select3D_SensitiveSphere.hxx
 Select3D_SensitiveTriangle.cxx
 Select3D_SensitiveTriangle.hxx
 Select3D_SensitiveTriangulation.cxx
diff --git a/src/Select3D/Select3D_SensitiveSphere.cxx b/src/Select3D/Select3D_SensitiveSphere.cxx
new file mode 100644 (file)
index 0000000..b289ca3
--- /dev/null
@@ -0,0 +1,80 @@
+// Created on: 2021-03-04
+// Created by: Maria KRYLOVA
+// Copyright (c) 2021 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.
+
+#include <Select3D_SensitiveSphere.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveSphere, Select3D_SensitiveEntity)
+
+// ==================================================
+// Function: Select3D_SensitiveSphere
+// Purpose :
+// ==================================================
+Select3D_SensitiveSphere::Select3D_SensitiveSphere (const Handle(SelectMgr_EntityOwner)& theOwnerId,
+                                                    const gp_Pnt& theCenter,
+                                                    const Standard_Real theRadius)
+: Select3D_SensitiveEntity (theOwnerId),
+  myCenter (theCenter),
+  myRadius (theRadius)
+{
+}
+
+// ==================================================
+// Function: Mathes
+// Purpose :
+// ==================================================
+Standard_Boolean Select3D_SensitiveSphere::Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                    SelectBasics_PickResult& thePickResult)
+{
+  if (theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
+  {
+    if (!theMgr.IsOverlapAllowed())
+    {
+      Standard_Boolean isInside = Standard_True;
+      return theMgr.OverlapsSphere (myCenter, myRadius, &isInside) && isInside;
+    }
+    else
+    {
+      return theMgr.OverlapsSphere (myCenter, myRadius, NULL);
+    }
+  }
+  if (!theMgr.OverlapsSphere (myCenter, myRadius, thePickResult))
+  {
+    return Standard_False;
+  }
+
+  thePickResult.SetDistToGeomCenter (theMgr.DistToGeometryCenter (myCenter));
+  return Standard_True;
+}
+
+// ==================================================
+// Function: GetConnected
+// Purpose :
+// ==================================================
+Handle(Select3D_SensitiveEntity) Select3D_SensitiveSphere::GetConnected()
+{
+  Handle(Select3D_SensitiveEntity) aNewEntity = new Select3D_SensitiveSphere (myOwnerId, myCenter, myRadius);
+  return aNewEntity;
+}
+
+// ==================================================
+// Function: BoundingBox
+// Purpose :
+// ==================================================
+Select3D_BndBox3d Select3D_SensitiveSphere::BoundingBox()
+{
+  const SelectMgr_Vec3 aMinPnt = SelectMgr_Vec3 (myCenter.X() - myRadius, myCenter.Y() - myRadius, myCenter.Z() - myRadius);
+  const SelectMgr_Vec3 aMaxPnt = SelectMgr_Vec3 (myCenter.X() + myRadius, myCenter.Y() + myRadius, myCenter.Z() + myRadius);
+  return Select3D_BndBox3d (aMinPnt, aMaxPnt);
+}
diff --git a/src/Select3D/Select3D_SensitiveSphere.hxx b/src/Select3D/Select3D_SensitiveSphere.hxx
new file mode 100644 (file)
index 0000000..9a976c6
--- /dev/null
@@ -0,0 +1,63 @@
+// Created on: 2021-03-04
+// Created by: Maria KRYLOVA
+// Copyright (c) 2021 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 _Select3D_SensitiveSphere_HeaderFile
+#define _Select3D_SensitiveSphere_HeaderFile
+
+#include <Select3D_SensitiveEntity.hxx>
+
+//! A framework to define selection by a sensitive sphere.
+class Select3D_SensitiveSphere : public Select3D_SensitiveEntity
+{
+  DEFINE_STANDARD_RTTIEXT(Select3D_SensitiveSphere, Select3D_SensitiveEntity)
+public:
+
+  //! Constructs a sensitive sphere object defined by the owner theOwnerId,
+  //! the center of the sphere and it's radius.
+  Standard_EXPORT Select3D_SensitiveSphere (const Handle(SelectMgr_EntityOwner)& theOwnerId,
+                                            const gp_Pnt& theCenter,
+                                            const Standard_Real theRadius);
+
+  //! Returns the radius of the sphere
+  Standard_Real Radius() const { return myRadius; }
+
+public:
+
+  //! Checks whether the sphere overlaps current selecting volume
+  Standard_EXPORT virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                    SelectBasics_PickResult& thePickResult) Standard_OVERRIDE;
+
+  //! Returns the copy of this
+  Standard_EXPORT virtual Handle(Select3D_SensitiveEntity) GetConnected() Standard_OVERRIDE;
+
+  //! Returns bounding box of the sphere.
+  //! If location transformation is set, it will be applied
+  Standard_EXPORT virtual Select3D_BndBox3d BoundingBox() Standard_OVERRIDE;
+
+  //! Always returns Standard_False
+  virtual Standard_Boolean ToBuildBVH() const Standard_OVERRIDE { return Standard_False; }
+
+  //! Returns the amount of points
+  virtual Standard_Integer NbSubElements() const Standard_OVERRIDE { return 1; }
+
+  //! Returns center of the sphere with transformation applied
+  virtual gp_Pnt CenterOfGeometry() const Standard_OVERRIDE { return myCenter; };
+
+protected:
+  gp_Pnt        myCenter;
+  Standard_Real myRadius;
+};
+
+#endif // _Select3D_SensitiveSphere_HeaderFile
index 68aaaab90c1a94eed6d1b9d3c9fd6f2047abe995..324d18958e6e79949bc0864e789eb386a050e35f 100644 (file)
@@ -85,6 +85,18 @@ public:
                                              Standard_Integer theSensType,
                                              SelectBasics_PickResult& thePickResult) const = 0;
 
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                           const Standard_Real theRadius,
+                                           SelectBasics_PickResult& thePickResult) const = 0;
+
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                           const Standard_Real theRadius,
+                                           Standard_Boolean* theInside = NULL) const = 0;
+
 public:
 
   //! Calculates distance from 3d projection of user-defined selection point
index c6514cebeafc5be809a0504be1ad2cc27b029aa9..7cc2e9f2a25cb7270edf3b760790c07681871675 100644 (file)
@@ -495,6 +495,58 @@ Standard_Boolean SelectMgr_AxisIntersector::OverlapsTriangle (const gp_Pnt& theP
      && !theClipRange.IsClipped (thePickResult.Depth());
 }
 
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCenter,
+                                                            const Standard_Real theRadius,
+                                                            Standard_Boolean* theInside) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
+    "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
+  (void )theInside;
+  Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
+  if (!RaySphereIntersection (theCenter, theRadius, myAxis.Location(), myAxis.Direction(), aTimeEnter, aTimeLeave))
+  {
+    return Standard_False;
+  }
+  if (theInside != NULL)
+  {
+    *theInside &= (aTimeEnter >= 0.0);
+  }
+  return Standard_True;
+}
+
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCenter,
+                                                            const Standard_Real theRadius,
+                                                            const SelectMgr_ViewClipRange& theClipRange,
+                                                            SelectBasics_PickResult& thePickResult) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
+    "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
+  Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
+  if (!RaySphereIntersection (theCenter, theRadius, myAxis.Location(), myAxis.Direction(), aTimeEnter, aTimeLeave))
+  {
+    return Standard_False;
+  }
+
+  Standard_Real aDepth = 0.0;
+  Bnd_Range aRange (Max (aTimeEnter, 0.0), aTimeLeave);
+  aRange.GetMin (aDepth);
+  if (!theClipRange.GetNearestDepth (aRange, aDepth))
+  {
+    return Standard_False;
+  }
+
+  thePickResult.SetDepth (aDepth);
+  return Standard_True;
+}
+
 //=======================================================================
 // function : GetNearPnt
 // purpose  :
index 9b2b5da961f7ab6d85fa98859d4db678b8738e28..5de38f3646943694e0525b101d9ea1cb039e7404 100644 (file)
@@ -98,6 +98,19 @@ public:
                                                              const SelectMgr_ViewClipRange& theClipRange,
                                                              SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
 
+  //! Intersection test between defined axis and given sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
+
+  //! Intersection test between defined axis and given sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           const SelectMgr_ViewClipRange& theClipRange,
+                                                           SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
 public:
 
   //! Measures distance between start axis point and given point theCOG.
index 51036600a04cae5a0bffbe6098b1979b5a2eee36..f7cca23b144b033dd36a014436a629b479134f20 100644 (file)
@@ -99,6 +99,49 @@ void SelectMgr_BaseFrustum::SetBuilder (const Handle(SelectMgr_FrustumBuilder)&
   }
 }
 
+//=======================================================================
+// function : IsBoundariesIntersectSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_BaseFrustum::IsBoundaryIntersectSphere (const gp_Pnt& theCenter,
+                                                                   const Standard_Real theRadius,
+                                                                   const gp_Dir& thePlaneNormal,
+                                                                   const TColgp_Array1OfPnt& theBoundaries,
+                                                                   Standard_Boolean& theBoundaryInside) const
+{
+  for (Standard_Integer anIdx = theBoundaries.Lower(); anIdx < theBoundaries.Upper(); ++anIdx)
+  {
+    const Standard_Integer aNextIdx = ((anIdx + 1) == theBoundaries.Upper()) ? theBoundaries.Lower() : (anIdx + 1);
+    const gp_Pnt aPnt1 = theBoundaries.Value (anIdx);
+    const gp_Pnt aPnt2 = theBoundaries.Value (aNextIdx);
+    if (aPnt1.Distance (aPnt2) < Precision::Confusion())
+    {
+      continue;
+    }
+
+    // Projections of the points on the plane
+    const gp_Pnt aPntProj1 = aPnt1.XYZ() - thePlaneNormal.XYZ() * aPnt1.XYZ().Dot (thePlaneNormal.XYZ());
+    const gp_Pnt aPntProj2 = aPnt2.XYZ() - thePlaneNormal.XYZ() * aPnt2.XYZ().Dot (thePlaneNormal.XYZ());
+    if (aPntProj1.Distance (theCenter) < theRadius || aPntProj2.Distance (theCenter) < theRadius) // polygon intersects the sphere
+    {
+      theBoundaryInside = Standard_True;
+      return Standard_True;
+    }
+
+    gp_Dir aRayDir (gp_Vec (aPntProj1, aPntProj2));
+    Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
+    if (RaySphereIntersection (theCenter, theRadius, aPntProj1, aRayDir, aTimeEnter, aTimeLeave))
+    {
+      if ((aTimeEnter > 0 && aTimeEnter < aPntProj1.Distance (aPntProj2))
+       || (aTimeLeave > 0 && aTimeLeave < aPntProj1.Distance (aPntProj2)))
+      {
+        return Standard_True; // polygon crosses  the sphere
+      }
+    }
+  }
+  return Standard_False;
+}
+
 //=======================================================================
 //function : DumpJson
 //purpose  : 
index 0c9c3b2b35874783f411be6b414b1331858f4b32..ea428a1df45742be89ed56b14f536f2f2dcd03d4 100644 (file)
@@ -54,6 +54,13 @@ public:
                                             const Standard_Real theWidth,
                                             const Standard_Real theHeight) Standard_OVERRIDE;
 
+  //! Checks whether the boundary of the current volume selection intersects with a sphere or are there it's boundaries lying inside the sphere
+  Standard_EXPORT Standard_Boolean IsBoundaryIntersectSphere (const gp_Pnt& theCenter,
+                                                              const Standard_Real theRadius,
+                                                              const gp_Dir& thePlaneNormal,
+                                                              const TColgp_Array1OfPnt& theBoundaries,
+                                                              Standard_Boolean& theBoundaryInside) const;
+
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
 
index 53db9740d1f0c4fd23ff76346a16ff672d19aaa4..6b7e81cd5de5a0191ec68fa1981b91d9e8a333b9 100644 (file)
@@ -122,6 +122,48 @@ const gp_Pnt2d& SelectMgr_BaseIntersector::GetMousePosition() const
   return aPnt;
 }
 
+//=======================================================================
+// function : RaySphereIntersection
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_BaseIntersector::RaySphereIntersection (const gp_Pnt& theCenter,
+                                                                   const Standard_Real theRadius,
+                                                                   const gp_Pnt& theLoc,
+                                                                   const gp_Dir& theRayDir,
+                                                                   Standard_Real& theTimeEnter,
+                                                                   Standard_Real& theTimeLeave) const
+{
+  // to find the intersection of the ray (theLoc, theRayDir) and sphere with theCenter(x0, y0, z0) and theRadius(R), you need to solve the equation
+  // (x' - x0)^2 + (y' - y0)^2 + (z' - z0)^2 = R^2, where P(x',y',z') = theLoc(x,y,z) + theRayDir(vx,vy,vz) * T
+  // at the end of solving, you receive a square equation with respect to T
+  // T^2 * (vx^2 + vy^2 + vz^2) + 2 * T * (vx*(x - x0) + vy*(y - y0) + vz*(z - z0)) + ((x-x0)^2 + (y-y0)^2 + (z-z0)^2 -R^2) = 0 (= A*T^2 + K*T + C)
+  // and find T by discriminant D = K^2 - A*C
+  const Standard_Real anA = theRayDir.Dot (theRayDir);
+  const Standard_Real aK = theRayDir.X() * (theLoc.X() - theCenter.X())
+                         + theRayDir.Y() * (theLoc.Y() - theCenter.Y())
+                         + theRayDir.Z() * (theLoc.Z() - theCenter.Z());
+  const Standard_Real aC = theLoc.Distance (theCenter) * theLoc.Distance (theCenter) - theRadius * theRadius;
+  const Standard_Real aDiscr = aK * aK - anA * aC;
+  if (aDiscr < 0)
+  {
+    return Standard_False;
+  }
+
+  const Standard_Real aTime1 = (-aK - Sqrt (aDiscr)) / anA;
+  const Standard_Real aTime2 = (-aK + Sqrt (aDiscr)) / anA;
+  if (Abs (aTime1) < Abs (aTime2))
+  {
+    theTimeEnter = aTime1;
+    theTimeLeave = aTime2;
+  }
+  else
+  {
+    theTimeEnter = aTime2;
+    theTimeLeave = aTime1;
+  }
+  return Standard_True;
+}
+
 //=======================================================================
 // function : DistToGeometryCenter
 // purpose  :
index e69f19bd62dbbc53f78a1c4d042c942ff3e5790b..90130404973bda184c718cbdc23306bd56468ee9 100644 (file)
@@ -168,6 +168,19 @@ public:
                                              const SelectMgr_ViewClipRange& theClipRange,
                                              SelectBasics_PickResult& thePickResult) const = 0;
 
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           Standard_Boolean* theInside = NULL) const = 0;
+
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           const SelectMgr_ViewClipRange& theClipRange,
+                                                           SelectBasics_PickResult& thePickResult) const = 0;
+
 public:
 
   //! Measures distance between 3d projection of user-picked
@@ -184,6 +197,15 @@ public:
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
 
+  //! Checks whether the ray that starts at the point theLoc and directs with the direction theRayDir intersects
+  //! with the sphere with center at theCenter and radius TheRadius
+  Standard_EXPORT virtual Standard_Boolean RaySphereIntersection (const gp_Pnt& theCenter,
+                                                                  const Standard_Real theRadius,
+                                                                  const gp_Pnt& theLoc,
+                                                                  const gp_Dir& theRayDir,
+                                                                  Standard_Real& theTimeEnter,
+                                                                  Standard_Real& theTimeLeave) const;
+
   DEFINE_STANDARD_RTTIEXT(SelectMgr_BaseIntersector,Standard_Transient)
 
 protected:
index 8b49b30ed0f53d253cb981750a34ff01a6068bbd..5b635b9acb6d4b0ef2ddbc99254b62f2fa3d6bf6 100644 (file)
@@ -88,6 +88,11 @@ protected:
                                        const gp_Pnt& thePnt3,
                                        gp_Vec& theNormal) const;
 
+  //! Intersection test between defined volume and given sphere
+  Standard_Boolean hasSphereOverlap (const gp_Pnt& thePnt1,
+                                     const Standard_Real theRadius,
+                                     Standard_Boolean* theInside = NULL) const;
+
 private:
 
   //! Checks if AABB and frustum are separated along the given axis
index c5e38a2d39016e903fc6b37cf9a7e643b5813906..4357516dea8e8603a1f209a30fd5a5068de23bfc 100644 (file)
@@ -459,10 +459,63 @@ Standard_Boolean SelectMgr_Frustum<N>::hasTriangleOverlap (const gp_Pnt& thePnt1
       }
     }
   }
-
   return Standard_True;
 }
 
+// =======================================================================
+// function : hasSphereOverlap
+// purpose  :
+// =======================================================================
+template <int N>
+Standard_Boolean SelectMgr_Frustum<N>::hasSphereOverlap (const gp_Pnt& thePnt,
+                                                         const Standard_Real theRadius,
+                                                         Standard_Boolean* theInside) const
+{
+  Standard_Boolean isOverlapFull = Standard_True;
+  const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
+  for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N; aPlaneIdx += anIncFactor)
+  {
+    const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
+    const Standard_Real aNormVecLen = Sqrt (aPlane.Dot (aPlane));
+    const Standard_Real aCenterProj = aPlane.Dot (thePnt.XYZ()) / aNormVecLen;
+    const Standard_Real aMaxDist = myMaxVertsProjections[aPlaneIdx] / aNormVecLen;
+    const Standard_Real aMinDist = myMinVertsProjections[aPlaneIdx] / aNormVecLen;
+    if (aCenterProj > (aMaxDist + theRadius)
+     || aCenterProj < (aMinDist - theRadius))
+    {
+      return Standard_False; // fully separated
+    }
+    else if (theInside)
+    {
+      *theInside &= aCenterProj >= (aMinDist + theRadius)
+                 && aCenterProj <= (aMaxDist - theRadius);
+    }
+    isOverlapFull &= aCenterProj >= (aMinDist + theRadius)
+                  && aCenterProj <= (aMaxDist - theRadius);
+  }
+  if (theInside || isOverlapFull)
+  {
+    return Standard_True;
+  }
+  const gp_Vec aVecPlane1 (myVertices[0], myVertices[2]);
+  const gp_Vec aVecPlane2 (myVertices[0], myVertices[2 * N - 2]);
+  if (aVecPlane1.IsParallel (aVecPlane2, Precision::Angular()))
+  {
+    return Standard_False;
+  }
+  const gp_Dir aNorm (aVecPlane1.Crossed (aVecPlane2));
+  gp_Pnt aBoundariesCArr[5];
+  NCollection_Array1<gp_Pnt> aBoundaries (aBoundariesCArr[0], 0, N);
+  for (Standard_Integer anIdx = 0; anIdx < N * 2; anIdx += 2)
+  {
+    aBoundaries.SetValue (anIdx / 2, myVertices[anIdx]);
+  }
+  // distance from point(x,y,z) to plane(A,B,C,D) d = | Ax + By + Cz + D | / sqrt (A^2 + B^2 + C^2) = aPnt.Dot (Norm) / 1
+  const gp_Pnt aCenterProj = thePnt.XYZ() - aNorm.XYZ() * thePnt.XYZ().Dot (aNorm.XYZ());
+  Standard_Boolean isBoundaryInside = Standard_False;
+  return IsBoundaryIntersectSphere (aCenterProj, theRadius, aNorm, aBoundaries, isBoundaryInside);
+}
+
 //=======================================================================
 //function : DumpJson
 //purpose  : 
index da122c385ca980396f98d293d4302115d3cf14d1..c47f770bf3bc09bf6b7f32ee9a616781be7dd83c 100644 (file)
@@ -16,6 +16,7 @@
 #include <SelectMgr_RectangularFrustum.hxx>
 
 #include <BVH_Tools.hxx>
+#include <gp_Pln.hxx>
 #include <NCollection_Vector.hxx>
 #include <Poly_Array1OfTriangle.hxx>
 #include <SelectMgr_FrustumBuilder.hxx>
@@ -752,6 +753,53 @@ const gp_Pnt2d& SelectMgr_RectangularFrustum::GetMousePosition() const
   return base_type::GetMousePosition();
 }
 
+// =======================================================================
+// function : OverlapsSphere
+// purpose  :
+// =======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& theCenter,
+                                                               const Standard_Real theRadius,
+                                                               const SelectMgr_ViewClipRange& theClipRange,
+                                                               SelectBasics_PickResult& thePickResult) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
+    "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
+  if (!hasSphereOverlap (theCenter, theRadius))
+  {
+    return Standard_False;
+  }
+
+  Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
+  if (!RaySphereIntersection (theCenter, theRadius, myNearPickedPnt, myViewRayDir, aTimeEnter, aTimeLeave))
+  {
+    return Standard_False;
+  }
+
+  thePickResult.SetDepth (aTimeEnter * myScale);
+  if (theClipRange.IsClipped (thePickResult.Depth()))
+  {
+    thePickResult.SetDepth (aTimeLeave * myScale);
+  }
+  gp_Pnt aPntOnSphere (myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * thePickResult.Depth());
+  gp_Vec aNormal (aPntOnSphere.XYZ() - theCenter.XYZ());
+  thePickResult.SetPickedPoint (aPntOnSphere);
+  thePickResult.SetSurfaceNormal (aNormal);
+  return !theClipRange.IsClipped (thePickResult.Depth());
+}
+
+// =======================================================================
+// function : OverlapsSphere
+// purpose  :
+// =======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::OverlapsSphere (const gp_Pnt& theCenter,
+                                                               const Standard_Real theRadius,
+                                                               Standard_Boolean* theInside) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
+    "Error! SelectMgr_RectangularFrustum::Overlaps() should be called after selection frustum initialization");
+  return hasSphereOverlap (theCenter, theRadius, theInside);
+}
+
 // =======================================================================
 // function : DistToGeometryCenter
 // purpose  : Measures distance between 3d projection of user-picked
index 02ace895aee6d4a265b8f2965005e9cfc37823c9..145f1d072a9d2a5d2422f2df932218ff483cbcb4 100644 (file)
@@ -133,6 +133,17 @@ public:
                                                              const SelectMgr_ViewClipRange& theClipRange,
                                                              SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
 
+  //! Intersection test between defined volume and given sphere
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           const SelectMgr_ViewClipRange& theClipRange,
+                                                           SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Intersection test between defined volume and given sphere
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           Standard_Boolean* theInside) const Standard_OVERRIDE;
+
   //! Measures distance between 3d projection of user-picked
   //! screen point and given point theCOG.
   //! It makes sense only for frustums built on a single point.
index 6f0e97e11706a09e6746e36b15ddc3f3c0afd4e3..8ecc30fa9297f55186d056a3d8cbe75d3fcbfe9c 100644 (file)
@@ -388,6 +388,36 @@ Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsTriangle (const gp_Pn
                                                     myViewClipRange, thePickResult);
 }
 
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsSphere (const gp_Pnt& theCenter,
+                                                                   const Standard_Real theRadius,
+                                                                   SelectBasics_PickResult& thePickResult) const
+{
+  if (myActiveSelectingVolume.IsNull())
+  {
+    return Standard_False;
+  }
+  return myActiveSelectingVolume->OverlapsSphere (theCenter, theRadius, myViewClipRange, thePickResult);
+}
+
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsSphere (const gp_Pnt& theCenter,
+                                                                   const Standard_Real theRadius,
+                                                                   Standard_Boolean* theInside) const
+{
+  if (myActiveSelectingVolume.IsNull())
+  {
+    return Standard_False;
+  }
+  return myActiveSelectingVolume->OverlapsSphere (theCenter, theRadius, theInside);
+}
+
 //=======================================================================
 // function : DistToGeometryCenter
 // purpose  : Measures distance between 3d projection of user-picked
index 67f96590090f0bff8d85c66a72f72424f7554d36..992a1c834f562e935da9d33d50fd9a52a2af2fae 100644 (file)
@@ -152,6 +152,16 @@ public:
                                                               Standard_Integer theSensType,
                                                               SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
 
+  //! Intersection test between defined volume and given sphere
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Intersection test between defined volume and given sphere
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
+
   //! Measures distance between 3d projection of user-picked
   //! screen point and given point theCOG
   Standard_EXPORT virtual Standard_Real DistToGeometryCenter (const gp_Pnt& theCOG) const Standard_OVERRIDE;
index d7c10ee087a4802f933f88f88fee8c2c75b2547d..6f458b033b84f3b536085345e7a4cca039a7d6e8 100644 (file)
@@ -16,6 +16,7 @@
 #include <SelectMgr_TriangularFrustum.hxx>
 
 #include <SelectMgr_FrustumBuilder.hxx>
+#include <SelectMgr_ViewClipRange.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_TriangularFrustum, Standard_Transient)
 
@@ -301,6 +302,33 @@ Standard_Boolean SelectMgr_TriangularFrustum::OverlapsTriangle (const gp_Pnt& th
   return Standard_True;
 }
 
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustum::OverlapsSphere (const gp_Pnt& theCenter,
+                                                              const Standard_Real theRadius,
+                                                              Standard_Boolean* theInside) const
+{
+  (void) theInside;
+  return hasBoxOverlap (SelectMgr_Vec3 (theCenter.X() - theRadius, theCenter.Y() - theRadius, theCenter.Z() - theRadius),
+                        SelectMgr_Vec3 (theCenter.X() + theRadius, theCenter.Y() + theRadius, theCenter.Z() + theRadius), NULL);
+}
+
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustum::OverlapsSphere (const gp_Pnt& theCenter,
+                                                              const Standard_Real theRadius,
+                                                              const SelectMgr_ViewClipRange& theClipRange,
+                                                              SelectBasics_PickResult& thePickResult) const
+{
+  (void )theClipRange;
+  (void )thePickResult;
+  return hasSphereOverlap (theCenter, theRadius);
+}
+
 // =======================================================================
 // function : Clear
 // purpose  : Nullifies the handle for corresponding builder instance to prevent
index 18ae7487e3abe2f0a2fdd4082ffe600fa8564e59..0719132ef5f59670b0fa155f9d3308b005ee272c 100644 (file)
@@ -104,6 +104,19 @@ public: //! @name SAT Tests for different objects
                                                              const SelectMgr_ViewClipRange& theClipRange,
                                                              SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
 
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           const SelectMgr_ViewClipRange& theClipRange,
+                                                           SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
 public:
 
   //! Nullifies the handle to corresponding builder instance to prevent memory leaks
index db281fe97be588cc13e1ae2022a2659b098843a3..f8ed8857f0bda28afd7a799ebf4b8ae958b316d4 100644 (file)
@@ -389,6 +389,115 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsTriangle (const gp_Pnt&
   return Standard_False;
 }
 
+//=======================================================================
+// function : OverlapsSphere
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsSphere (const gp_Pnt& theCenter,
+                                                                 const Standard_Real theRadius,
+                                                                 Standard_Boolean* /*theInside*/) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Polyline,
+    "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
+  for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value()->OverlapsSphere (theCenter, theRadius, NULL))
+    {
+      // select 3 points of the frustum and build a plane on them
+      Standard_Real aMaxDist1 = 0.0, aMaxDist2 = 0.0;
+      Standard_Integer anIdx1 = myBoundaryPoints.Lower();
+      Standard_Integer anIdx2 = myBoundaryPoints.Lower();
+      Standard_Integer anIdx3 = myBoundaryPoints.Lower();
+      for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx < myBoundaryPoints.Size() / 2 + myBoundaryPoints.Lower(); anIdx++)
+      {
+        if (myBoundaryPoints[anIdx1].Distance (myBoundaryPoints[anIdx]) < Precision::Confusion())
+        {
+          continue;
+        }
+        else if (aMaxDist1 < myBoundaryPoints[anIdx1].Distance (myBoundaryPoints[anIdx]))
+        {
+          if (anIdx2 != anIdx3)
+          {
+            anIdx3 = anIdx2;
+            aMaxDist2 = aMaxDist1;
+          }
+          anIdx2 = anIdx;
+          aMaxDist1 = myBoundaryPoints[anIdx1].Distance (myBoundaryPoints[anIdx]);
+        }
+        else if (aMaxDist2 < myBoundaryPoints[anIdx2].Distance (myBoundaryPoints[anIdx]))
+        {
+          anIdx3 = anIdx;
+          aMaxDist2 = myBoundaryPoints[anIdx2].Distance (myBoundaryPoints[anIdx]);
+        }
+      }
+      gp_Vec aVecPlane1 (myBoundaryPoints[anIdx1], myBoundaryPoints[anIdx2]);
+      gp_Vec aVecPlane2 (myBoundaryPoints[anIdx1], myBoundaryPoints[anIdx3]);
+
+      const gp_Dir aNorm (aVecPlane1.Crossed (aVecPlane2));
+
+      // distance from point(x,y,z) to plane(A,B,C,D) d = | Ax + By + Cz + D | / sqrt (A^2 + B^2 + C^2) = aPnt.Dot (Norm) / 1
+      const gp_Pnt aCenterProj = theCenter.XYZ() - aNorm.XYZ() * theCenter.XYZ().Dot (aNorm.XYZ());
+
+      // If the center of the sphere is inside of the volume projection, then anAngleSum will be equal 2*M_PI
+      Standard_Real anAngleSum = 0.0;
+      TColgp_Array1OfPnt aBoundaries (myBoundaryPoints.Lower(), myBoundaryPoints.Size() / 2 + myBoundaryPoints.Lower());
+
+      for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx < myBoundaryPoints.Size() / 2 + myBoundaryPoints.Lower(); anIdx++)
+      {
+        aBoundaries.SetValue (anIdx, myBoundaryPoints[anIdx]);
+
+        gp_Pnt aPnt1 = myBoundaryPoints.Value (anIdx);
+        gp_Pnt aPnt2 = myBoundaryPoints.Value (anIdx + 1);
+
+        // Projections of the points on the plane
+        gp_Pnt aPntProj1 = aPnt1.XYZ() - aNorm.XYZ() * aPnt1.XYZ().Dot (aNorm.XYZ());
+        gp_Pnt aPntProj2 = aPnt2.XYZ() - aNorm.XYZ() * aPnt2.XYZ().Dot (aNorm.XYZ());
+
+        gp_Vec aVecAngle1 (aCenterProj, aPntProj1);
+        gp_Vec aVecAngle2 (aCenterProj, aPntProj2);
+        anAngleSum += aVecAngle1.Angle (aVecAngle2);
+      }
+      Standard_Boolean isCenterInside = Abs (anAngleSum - 2 * M_PI) < Precision::Confusion();
+      Standard_Boolean isBoundaryInside = Standard_False;
+      Standard_Boolean isIntersectSphereBoundaries = IsBoundaryIntersectSphere (aCenterProj, theRadius, aNorm, aBoundaries, isBoundaryInside);
+
+      if (myToAllowOverlap)
+      {
+        return isIntersectSphereBoundaries
+            || isCenterInside;
+      }
+      else
+      {
+        return !isIntersectSphereBoundaries
+            && isCenterInside
+            && !isBoundaryInside;
+      }
+    }
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+// function : OverlapsSphere
+// purpose :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsSphere (const gp_Pnt& theCenter,
+                                                                 const Standard_Real theRadius,
+                                                                 const SelectMgr_ViewClipRange& theClipRange,
+                                                                 SelectBasics_PickResult& thePickResult) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Polyline,
+    "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
+  for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value()->OverlapsSphere (theCenter, theRadius, theClipRange, thePickResult))
+    {
+      return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
 // =======================================================================
 // function : GetPlanes
 // purpose  :
index 70cfb7a5c8e90c8e3ec7857f8973c3a55ab66552..1618b44d644255204b49ec90c23a24caa6fae98c 100644 (file)
@@ -105,6 +105,19 @@ public:
   //! Calculates the point on a view ray that was detected during the run of selection algo by given depth
   Standard_EXPORT virtual gp_Pnt DetectedPoint (const Standard_Real theDepth) const Standard_OVERRIDE;
 
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by sphere with center theCenter
+  //! and radius theRadius
+  Standard_EXPORT virtual Standard_Boolean OverlapsSphere (const gp_Pnt& theCenter,
+                                                           const Standard_Real theRadius,
+                                                           const SelectMgr_ViewClipRange& theClipRange,
+                                                           SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
   //! Stores plane equation coefficients (in the following form:
   //! Ax + By + Cz + D = 0) to the given vector
   Standard_EXPORT virtual void GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const Standard_OVERRIDE;
index 97793c1464f6a812472c2c6a6ac8fc135d5487f0..8d3a79c15d7ff2b6a09e67506509f14e42da8f9e 100644 (file)
@@ -27,6 +27,7 @@
 #include <GCPnts_TangentialDeflection.hxx>
 #include <GeomAbs_SurfaceType.hxx>
 #include <GeomAdaptor_Curve.hxx>
+#include <Geom_SphericalSurface.hxx>
 #include <gp_Circ.hxx>
 #include <Poly_Array1OfTriangle.hxx>
 #include <Poly_Polygon3D.hxx>
@@ -41,6 +42,7 @@
 #include <Select3D_SensitiveGroup.hxx>
 #include <Select3D_SensitivePoint.hxx>
 #include <Select3D_SensitiveSegment.hxx>
+#include <Select3D_SensitiveSphere.hxx>
 #include <Select3D_SensitiveTriangle.hxx>
 #include <Select3D_SensitiveTriangulation.hxx>
 #include <Select3D_SensitiveWire.hxx>
@@ -572,6 +574,35 @@ Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace (const TopoDS_
   TopLoc_Location aLoc;
   if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (theFace, aLoc))
   {
+    TopLoc_Location aLocSurf;
+    const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (theFace, aLocSurf);
+    if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast (aSurf))
+    {
+      bool isFullSphere = theFace.NbChildren() == 0;
+      if (theFace.NbChildren() == 1)
+      {
+        const TopoDS_Iterator aWireIter (theFace);
+        const TopoDS_Wire& aWire = TopoDS::Wire (aWireIter.Value());
+        if (aWire.NbChildren() == 4)
+        {
+          Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0;
+          for (TopoDS_Iterator anEdgeIter (aWire); anEdgeIter.More(); anEdgeIter.Next())
+          {
+            const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Value());
+            aNbSeamEdges += BRep_Tool::IsClosed (anEdge, theFace);
+            aNbDegenEdges += BRep_Tool::Degenerated (anEdge);
+          }
+          isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2;
+        }
+      }
+      if (isFullSphere)
+      {
+        gp_Sphere aSphere = BRepAdaptor_Surface (theFace).Sphere();
+        Handle(Select3D_SensitiveSphere) aSensSphere = new Select3D_SensitiveSphere (theOwner, aSphere.Position().Axis().Location(), aSphere.Radius());
+        theSensitiveList.Append (aSensSphere);
+        return Standard_True;
+      }
+    }
     Handle(Select3D_SensitiveTriangulation) STG = new Select3D_SensitiveTriangulation (theOwner, aTriangulation, aLoc, theInteriorFlag);
     theSensitiveList.Append (STG);
     return Standard_True;
index bba0f747abcb8c59d3b9576f32ffab57dca3802e..7e43a1686499283827fc2d857f692cad6f8c3e36 100644 (file)
@@ -14,6 +14,6 @@ vclipplane p1 -set s -equation 0 1 0 0
 set p [vmoveto 200 200]
 vpoint pp {*}$p
 vsetcolor pp RED
-checkpoint p $p {-0.34896 9.94397 0.27411} 0.0001
+checkpoint p $p {-0.34896 9.99014 0.27411} 0.0001
 
 vdump ${imagedir}/${casename}.png
diff --git a/tests/vselect/sphere/check_depth b/tests/vselect/sphere/check_depth
new file mode 100644 (file)
index 0000000..6d38a5b
--- /dev/null
@@ -0,0 +1,28 @@
+puts "================================="
+puts "0032182: Visualization - add Select3D_SensitiveSphere"
+puts "Tests depth value returned by Select3D_SenstiveSphere"
+puts "================================="
+
+psphere s 1
+vdisplay -dispMode 1 s
+vfit
+vtop
+set top [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
+checkpoint top_p $top {0.0013453695513163666 -0.0090115971854718303 0.99995849333074871} 0.0001
+vbottom
+set bottom [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
+checkpoint bottom_p $bottom {0.0013453695513163666 0.0090115971854718303 -0.99995849333074871} 0.0001
+vright
+set right [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
+checkpoint right_p $right {0.99995849333074871 0.0013453695513163666 -0.0090115971854718268} 0.0001
+vfront
+set front [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
+checkpoint front_p $front {0.0013453695513163666 -0.99995832904743187 -0.0090115971854718285} 0.01
+vleft
+set left [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
+checkpoint left_p $left {-0.99995817565020639 -0.0013453695513163666 -0.0090115971854718268} 0.0001
diff --git a/tests/vselect/sphere/detecting b/tests/vselect/sphere/detecting
new file mode 100644 (file)
index 0000000..a42120b
--- /dev/null
@@ -0,0 +1,10 @@
+puts "================================="
+puts "0032182: Visualization - add Select3D_SensitiveSphere"
+puts "Tests detecting Select3D_SenstiveSphere"
+puts "================================="
+
+psphere s 1
+vdisplay -dispMode 1 s
+vfit
+vmoveto 300 200
+if { ![string match "*Select3D_SensitiveSphere*" [vstate -entities]] } { puts "Error: sphere should be detected" }
diff --git a/tests/vselect/sphere/polygon_selection b/tests/vselect/sphere/polygon_selection
new file mode 100644 (file)
index 0000000..c1cc47f
--- /dev/null
@@ -0,0 +1,52 @@
+puts "================================="
+puts "0032182: Visualization - add Select3D_SensitiveSphere"
+puts "Tests polygon selection of Select3D_SenstiveSphere"
+puts "================================="
+
+psphere s1 1
+psphere s2 1
+psphere s3 1
+psphere s4 1
+ttranslate s1 2 2 0
+ttranslate s2 2 -2 0
+ttranslate s3 -2 2 0
+ttranslate s4 -2 -2 0
+vdisplay -dispMode 1 s1 s2 s3 s4
+vfit
+vselect 15 200 300 15 585 200 300 385
+if { ![string match "*Selected*" [vstate s1]] ||
+     ![string match "*Selected*" [vstate s2]] ||
+     ![string match "*Selected*" [vstate s3]] ||
+     ![string match "*Selected*" [vstate s4]]} { puts "Error: all spheres should be selected" }
+vtop
+vselect 170 200 300 80 430 200 300 320
+if { [string match "*Selected*" [vstate s1]] ||
+     [string match "*Selected*" [vstate s2]] ||
+     [string match "*Selected*" [vstate s3]] ||
+     [string match "*Selected*" [vstate s4]]} { puts "Error: all spheres should be unselected" }
+vselect 177 78 422 78 422 322 177 322 -allowoverlap 1
+if { ![string match "*Selected*" [vstate s1]] ||
+     ![string match "*Selected*" [vstate s2]] ||
+     ![string match "*Selected*" [vstate s3]] ||
+     ![string match "*Selected*" [vstate s4]]} { puts "Error: all spheres should be selected" }
+vright
+vselect 181 323 289 196 147 85 59 206
+if { [string match "*Selected*" [vstate s1]] ||
+     ![string match "*Selected*" [vstate s2]] ||
+     [string match "*Selected*" [vstate s3]] ||
+     ![string match "*Selected*" [vstate s4]]} { puts "Error: spheres s1 and s3 should be unselected" }
+vselect 131 197 177 156 219 198 179 247
+if { [string match "*Selected*" [vstate s1]] ||
+     [string match "*Selected*" [vstate s2]] ||
+     [string match "*Selected*" [vstate s3]] ||
+     [string match "*Selected*" [vstate s4]]} { puts "Error: all spheres should be unselected" }
+vselect 131 197 177 156 219 198 179 247 -allowoverlap 1
+if { [string match "*Selected*" [vstate s1]] ||
+     ![string match "*Selected*" [vstate s2]] ||
+     [string match "*Selected*" [vstate s3]] ||
+     ![string match "*Selected*" [vstate s4]]} { puts "Error: spheres s1 and s3 should be unselected" }
+vselect 227 147 282 268 367 151 -allowoverlap 1
+if { [string match "*Selected*" [vstate s1]] ||
+     [string match "*Selected*" [vstate s2]] ||
+     [string match "*Selected*" [vstate s3]] ||
+     [string match "*Selected*" [vstate s4]]} { puts "Error: all spheres should be unselected" }