]> OCCT Git - occt.git/commitdiff
0032281: Visualization - add Select3D_SensitiveCylinder
authormkrylova <mkrylova@opencascade.com>
Mon, 5 Jul 2021 12:06:50 +0000 (15:06 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 27 Aug 2021 16:09:09 +0000 (19:09 +0300)
- implemented Select3D_SensitiveCylinder class performing an analytical intersection with an untriangulated cone/cylinder
- added tests

32 files changed:
src/Select3D/FILES
src/Select3D/Select3D_SensitiveCylinder.cxx [new file with mode: 0644]
src/Select3D/Select3D_SensitiveCylinder.hxx [new file with mode: 0644]
src/SelectBasics/SelectBasics_SelectingVolumeManager.hxx
src/SelectMgr/SelectMgr_AxisIntersector.cxx
src/SelectMgr/SelectMgr_AxisIntersector.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_SelectionImageFiller.cxx
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
src/StdSelect/StdSelect_TypeOfSelectionImage.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/vselect/cone_cylinder/begin [new file with mode: 0644]
tests/vselect/cone_cylinder/check_depth [new file with mode: 0644]
tests/vselect/cone_cylinder/detecting [new file with mode: 0644]
tests/vselect/cone_cylinder/generate_images [new file with mode: 0644]
tests/vselect/cone_cylinder/polygon_selection [new file with mode: 0644]
tests/vselect/cone_cylinder/rectangle_selection [new file with mode: 0644]
tests/vselect/cone_cylinder/single_click_selection_cone [new file with mode: 0644]
tests/vselect/cone_cylinder/single_click_selection_cylinder [new file with mode: 0644]
tests/vselect/cone_cylinder/single_click_selection_trunc_cone [new file with mode: 0644]
tests/vselect/grids.list

index d779a8c3220a3a4b0d0585f8d1c7653e2d834c56..d0c23b19fde589cc1ba753133fd41da24102ebb5 100755 (executable)
@@ -13,6 +13,8 @@ Select3D_SensitiveCircle.cxx
 Select3D_SensitiveCircle.hxx
 Select3D_SensitiveCurve.cxx
 Select3D_SensitiveCurve.hxx
+Select3D_SensitiveCylinder.cxx
+Select3D_SensitiveCylinder.hxx
 Select3D_SensitiveEntity.cxx
 Select3D_SensitiveEntity.hxx
 Select3D_SensitiveFace.cxx
diff --git a/src/Select3D/Select3D_SensitiveCylinder.cxx b/src/Select3D/Select3D_SensitiveCylinder.cxx
new file mode 100644 (file)
index 0000000..62fe013
--- /dev/null
@@ -0,0 +1,104 @@
+// Created on: 2021-04-19
+// 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_SensitiveCylinder.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveCylinder, Select3D_SensitiveEntity)
+
+//==================================================
+// Function: Select3D_SensitiveSphere
+// Purpose :
+//==================================================
+Select3D_SensitiveCylinder::Select3D_SensitiveCylinder (const Handle(SelectMgr_EntityOwner)& theOwnerId,
+                                                        const Standard_Real theBottomRad,
+                                                        const Standard_Real theTopRad,
+                                                        const Standard_Real    theHeight,
+                                                        const gp_Trsf& theTrsf)
+: Select3D_SensitiveEntity (theOwnerId),
+  myTrsf (theTrsf),
+  myBottomRadius (theBottomRad),
+  myTopRadius (theTopRad),
+  myHeight (theHeight)
+{
+}
+
+//==================================================
+// Function: Matches
+// Purpose :
+//==================================================
+Standard_Boolean Select3D_SensitiveCylinder::Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                      SelectBasics_PickResult& thePickResult)
+{
+  if (theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
+  {
+    if (!theMgr.IsOverlapAllowed())
+    {
+      bool isInside = true;
+      return theMgr.OverlapsCylinder (myBottomRadius, myTopRadius, myHeight, myTrsf, &isInside) && isInside;
+    }
+    else
+    {
+      return theMgr.OverlapsCylinder (myBottomRadius, myTopRadius, myHeight, myTrsf, NULL);
+    }
+  }
+  if (!theMgr.OverlapsCylinder (myBottomRadius, myTopRadius, myHeight, myTrsf, thePickResult))
+  {
+    return false;
+  }
+
+  thePickResult.SetDistToGeomCenter (theMgr.DistToGeometryCenter (CenterOfGeometry()));
+  return true;
+}
+
+//==================================================
+// Function: GetConnected
+// Purpose :
+//==================================================
+Handle(Select3D_SensitiveEntity) Select3D_SensitiveCylinder::GetConnected()
+{
+  Handle(Select3D_SensitiveEntity) aNewEntity = new Select3D_SensitiveCylinder (myOwnerId, myBottomRadius,
+                                                                                myTopRadius, myHeight,
+                                                                                myTrsf);
+  return aNewEntity;
+}
+
+//==================================================
+// Function: BoundingBox
+// Purpose :
+//==================================================
+Select3D_BndBox3d Select3D_SensitiveCylinder::BoundingBox()
+{
+  Standard_Real aMaxRad = Max (myBottomRadius, myTopRadius);
+  gp_Pnt aCenterBottom (0, 0, 0);
+  gp_Pnt aCenterTop (0, 0, myHeight);
+  aCenterBottom.Transform (myTrsf);
+  aCenterTop.Transform (myTrsf);
+  const SelectMgr_Vec3 aMinPnt (Min (aCenterBottom.X(), aCenterTop.X()) - aMaxRad,
+                                Min (aCenterBottom.Y(), aCenterTop.Y()) - aMaxRad,
+                                Min (aCenterBottom.Z(), aCenterTop.Z()) - aMaxRad);
+  const SelectMgr_Vec3 aMaxPnt (Max (aCenterBottom.X(), aCenterTop.X()) + aMaxRad,
+                                Max (aCenterBottom.Y(), aCenterTop.Y()) + aMaxRad,
+                                Max (aCenterBottom.Z(), aCenterTop.Z()) + aMaxRad);
+  return Select3D_BndBox3d (aMinPnt, aMaxPnt);
+}
+
+//==================================================
+// Function: CenterOfGeometry
+// Purpose :
+//==================================================
+gp_Pnt Select3D_SensitiveCylinder::CenterOfGeometry() const
+{
+  return gp_Pnt (0, 0, myHeight / 2).Transformed (myTrsf);
+}
diff --git a/src/Select3D/Select3D_SensitiveCylinder.hxx b/src/Select3D/Select3D_SensitiveCylinder.hxx
new file mode 100644 (file)
index 0000000..533341e
--- /dev/null
@@ -0,0 +1,64 @@
+// Created on: 2021-04-19
+// 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_SensitiveCylinder_HeaderFile
+#define _Select3D_SensitiveCylinder_HeaderFile
+
+#include <Select3D_SensitiveEntity.hxx>
+
+//! A framework to define selection by a sensitive cylinder or cone.
+class Select3D_SensitiveCylinder : public Select3D_SensitiveEntity
+{
+  DEFINE_STANDARD_RTTIEXT (Select3D_SensitiveCylinder, Select3D_SensitiveEntity)
+
+public:
+  //! Constructs a sensitive cylinder object defined by the owner theOwnerId,
+  //! @param[in] theBottomRad cylinder bottom radius
+  //! @param[in] theTopRad    cylinder top radius
+  //! @param[in] theHeight    cylinder height
+  Standard_EXPORT Select3D_SensitiveCylinder (const Handle(SelectMgr_EntityOwner)& theOwnerId,
+                                              const Standard_Real theBottomRad,
+                                              const Standard_Real theTopRad,
+                                              const Standard_Real theHeight,
+                                              const gp_Trsf& theTrsf);
+
+  //! Checks whether the cylinder 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 cylinder.
+  //! 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 cylinder with transformation applied
+  Standard_EXPORT virtual gp_Pnt CenterOfGeometry() const Standard_OVERRIDE;
+
+protected:
+  gp_Trsf       myTrsf;         //!< cylinder transformation to apply
+  Standard_Real myBottomRadius; //!< cylinder bottom radius
+  Standard_Real myTopRadius;    //!< cylinder top radius
+  Standard_Real myHeight;       //!< cylinder height
+};
+
+#endif // _Select3D_SensitiveSphere_HeaderFile
index 324d18958e6e79949bc0864e789eb386a050e35f..60dbadb6989a88af54fb5fe4e7be92c632130b6b 100644 (file)
@@ -97,6 +97,22 @@ public:
                                            const Standard_Real theRadius,
                                            Standard_Boolean* theInside = NULL) const = 0;
 
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                             const Standard_Real theTopRad,
+                                             const Standard_Real theHeight,
+                                             const gp_Trsf& theTrsf,
+                                             SelectBasics_PickResult& thePickResult) const = 0;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                             const Standard_Real theTopRad,
+                                             const Standard_Real theHeight,
+                                             const gp_Trsf& theTrsf,
+                                             Standard_Boolean* theInside = NULL) const = 0;
+
 public:
 
   //! Calculates distance from 3d projection of user-defined selection point
index 7cc2e9f2a25cb7270edf3b760790c07681871675..ec276943810071ef5d501344d9988d4ca9296331 100644 (file)
@@ -547,6 +547,66 @@ Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCen
   return Standard_True;
 }
 
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_AxisIntersector::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                              const Standard_Real theTopRad,
+                                                              const Standard_Real theHeight,
+                                                              const gp_Trsf& theTrsf,
+                                                              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;
+  gp_Trsf aTrsfInv = theTrsf.Inverted();
+  gp_Pnt  aLoc     = myAxis.Location() .Transformed (aTrsfInv);
+  gp_Dir  aRayDir  = myAxis.Direction().Transformed (aTrsfInv);
+  if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
+  {
+    return false;
+  }
+
+  Standard_Real aDepth = 0.0;
+  Bnd_Range aRange (Max (aTimeEnter, 0.0), aTimeLeave);
+  aRange.GetMin (aDepth);
+  if (!theClipRange.GetNearestDepth (aRange, aDepth))
+  {
+    return false;
+  }
+  thePickResult.SetDepth (aDepth);
+  return true;
+}
+
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_AxisIntersector::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                              const Standard_Real theTopRad,
+                                                              const Standard_Real theHeight,
+                                                              const gp_Trsf& theTrsf,
+                                                              Standard_Boolean* theInside)  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;
+  gp_Trsf aTrsfInv = theTrsf.Inverted();
+  gp_Pnt  aLoc     = myAxis.Location() .Transformed (aTrsfInv);
+  gp_Dir  aRayDir  = myAxis.Direction().Transformed (aTrsfInv);
+  if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
+  {
+    return false;
+  }
+  if (theInside != NULL)
+  {
+    *theInside &= (aTimeEnter >= 0.0);
+  }
+  return true;
+}
+
 //=======================================================================
 // function : GetNearPnt
 // purpose  :
index 5de38f3646943694e0525b101d9ea1cb039e7404..543c4e61757050453adb80b73617892cc902d444 100644 (file)
@@ -111,6 +111,23 @@ public:
                                                            const SelectMgr_ViewClipRange& theClipRange,
                                                            SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
 
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             const SelectMgr_ViewClipRange& theClipRange,
+                                                             SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
+
 public:
 
   //! Measures distance between start axis point and given point theCOG.
index 6b7e81cd5de5a0191ec68fa1981b91d9e8a333b9..2ce3de812377288e8fde51864e6c3535e56d186e 100644 (file)
@@ -14,6 +14,9 @@
 #include <SelectMgr_BaseIntersector.hxx>
 
 #include <Graphic3d_Camera.hxx>
+#include <gp_Ax3.hxx>
+
+#include <algorithm>
 
 IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_BaseIntersector, Standard_Transient)
 
@@ -164,6 +167,132 @@ Standard_Boolean SelectMgr_BaseIntersector::RaySphereIntersection (const gp_Pnt&
   return Standard_True;
 }
 
+//=======================================================================
+// function : RayCylinderIntersection
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_BaseIntersector::RayCylinderIntersection (const Standard_Real theBottomRadius,
+                                                                     const Standard_Real theTopRadius,
+                                                                     const Standard_Real theHeight,
+                                                                     const gp_Pnt& theLoc,
+                                                                     const gp_Dir& theRayDir,
+                                                                     Standard_Real& theTimeEnter,
+                                                                     Standard_Real& theTimeLeave) const
+{
+  Standard_Integer aNbIntersections = 0;
+  Standard_Real anIntersections[4] = { RealLast(), RealLast(), RealLast(), RealLast() };
+  //NCollection_Vector<Standard_Real> anIntersections; // vector for all intersections
+  // Check intersections with end faces
+  // point of intersection theRayDir and z = 0
+  if (theRayDir.Z() != 0)
+  {
+    const Standard_Real aTime1 = (0 - theLoc.Z()) / theRayDir.Z();
+    const Standard_Real aX1 = theLoc.X() + theRayDir.X() * aTime1;
+    const Standard_Real anY1 = theLoc.Y() + theRayDir.Y() * aTime1;
+    if (aX1 * aX1 + anY1 * anY1 <= theBottomRadius * theBottomRadius)
+    {
+      anIntersections[aNbIntersections++] = aTime1;
+    }
+    // point of intersection theRayDir and z = theHeight
+    const Standard_Real aTime2 = (theHeight - theLoc.Z()) / theRayDir.Z();
+    const Standard_Real aX2 = theLoc.X() + theRayDir.X() * aTime2;
+    const Standard_Real anY2 = theLoc.Y() + theRayDir.Y() * aTime2;
+    if (aX2 * aX2 + anY2 * anY2 <= theTopRadius * theTopRadius)
+    {
+      anIntersections[aNbIntersections++] = aTime2;
+    }
+  }
+  // ray intersection with cone / truncated cone
+  if (theTopRadius != theBottomRadius)
+  {
+    const Standard_Real aTriangleHeight = Min (theBottomRadius, theTopRadius) * theHeight /
+                                         (Abs (theBottomRadius - theTopRadius));
+    gp_Ax3 aSystem;
+    if (theBottomRadius > theTopRadius)
+    {
+      aSystem.SetLocation (gp_Pnt (0, 0, theHeight + aTriangleHeight));
+      aSystem.SetDirection (-gp::DZ());
+    }
+    else
+    {
+      aSystem.SetLocation (gp_Pnt (0, 0, -aTriangleHeight));
+      aSystem.SetDirection (gp::DZ());
+    }
+    gp_Trsf aTrsfCone;
+    aTrsfCone.SetTransformation (gp_Ax3(), aSystem);
+    const gp_Pnt aPnt (theLoc.Transformed (aTrsfCone));
+    const gp_Dir aDir (theRayDir.Transformed (aTrsfCone));
+    const Standard_Real aMaxRad = Max (theBottomRadius, theTopRadius);
+    const Standard_Real aConeHeight = theHeight + aTriangleHeight;
+
+    // solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
+    const Standard_Real anA = aDir.X() * aDir.X() / (aMaxRad * aMaxRad)
+                            + aDir.Y() * aDir.Y() / (aMaxRad * aMaxRad)
+                            - aDir.Z() * aDir.Z() / (aConeHeight * aConeHeight);
+    const Standard_Real aK = aDir.X() * aPnt.X() / (aMaxRad * aMaxRad)
+                           + aDir.Y() * aPnt.Y() / (aMaxRad * aMaxRad)
+                           - aDir.Z() * aPnt.Z() / (aConeHeight * aConeHeight);
+    const Standard_Real aC = aPnt.X() * aPnt.X() / (aMaxRad * aMaxRad)
+                           + aPnt.Y() * aPnt.Y() / (aMaxRad * aMaxRad)
+                           - aPnt.Z() * aPnt.Z() / (aConeHeight * aConeHeight);
+    Standard_Real aDiscr = aK * aK - anA * aC;
+    if (aDiscr > 0)
+    {
+      const Standard_Real aTimeEnterCone = (-aK - Sqrt (aDiscr)) / anA;
+      const Standard_Real aTimeLeaveCone = (-aK + Sqrt (aDiscr)) / anA;
+      const Standard_Real aZFromRoot1 = aPnt.Z() + aTimeEnterCone * aDir.Z();
+      const Standard_Real aZFromRoot2 = aPnt.Z() + aTimeLeaveCone * aDir.Z();
+
+      if (aZFromRoot1 > aTriangleHeight && aZFromRoot1 < aConeHeight)
+      {
+        anIntersections[aNbIntersections++] = aTimeEnterCone;
+      }
+      if (aZFromRoot2 > aTriangleHeight && aZFromRoot2 < aConeHeight)
+      {
+        anIntersections[aNbIntersections++] = aTimeLeaveCone;
+      }
+    }
+  }
+  else // ray intersection with cylinder
+  {
+    const gp_Pnt2d aLoc2d (theLoc.X(), theLoc.Y());
+    const gp_Vec2d aRayDir2d (theRayDir.X(), theRayDir.Y());
+
+    // solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
+    const Standard_Real anA = aRayDir2d.Dot (aRayDir2d);
+    const Standard_Real aK = aLoc2d.XY().Dot (aRayDir2d.XY());
+    const Standard_Real aC = aLoc2d.XY().Dot (aLoc2d.XY()) - theTopRadius * theTopRadius;
+    const Standard_Real aDiscr = aK * aK - anA * aC;
+    if (aDiscr > 0)
+    {
+      const Standard_Real aRoot1 = (-aK + Sqrt (aDiscr)) / anA;
+      const Standard_Real aRoot2 = (-aK - Sqrt (aDiscr)) / anA;
+      const Standard_Real aZFromRoot1 = theLoc.Z() + aRoot1 * theRayDir.Z();
+      const Standard_Real aZFromRoot2 = theLoc.Z() + aRoot2 * theRayDir.Z();
+      if (aZFromRoot1 > 0 && aZFromRoot1 < theHeight)
+      {
+        anIntersections[aNbIntersections++] = aRoot1;
+      }
+      if (aZFromRoot2 > 0 && aZFromRoot2 < theHeight)
+      {
+        anIntersections[aNbIntersections++] = aRoot2;
+      }
+    }
+  }
+  if (aNbIntersections == 0)
+  {
+    return false;
+  }
+
+  std::sort (anIntersections, anIntersections + aNbIntersections);
+  theTimeEnter = anIntersections[0];
+  if (aNbIntersections > 1)
+  {
+    theTimeLeave = anIntersections[1];
+  }
+  return true;
+}
+
 //=======================================================================
 // function : DistToGeometryCenter
 // purpose  :
index 90130404973bda184c718cbdc23306bd56468ee9..5ab38e9ea9253e333c266638487799469f8ee6c5 100644 (file)
@@ -181,6 +181,23 @@ public:
                                                            const SelectMgr_ViewClipRange& theClipRange,
                                                            SelectBasics_PickResult& thePickResult) const = 0;
 
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                             const Standard_Real theTopRad,
+                                             const Standard_Real theHeight,
+                                             const gp_Trsf& theTrsf,
+                                             const SelectMgr_ViewClipRange& theClipRange,
+                                             SelectBasics_PickResult& thePickResult) const = 0;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                             const Standard_Real theTopRad,
+                                             const Standard_Real theHeight,
+                                             const gp_Trsf& theTrsf,
+                                             Standard_Boolean* theInside = NULL) const = 0;
+
 public:
 
   //! Measures distance between 3d projection of user-picked
@@ -206,6 +223,16 @@ public:
                                                                   Standard_Real& theTimeEnter,
                                                                   Standard_Real& theTimeLeave) const;
 
+  //! Checks whether the ray that starts at the point theLoc and directs with the direction theRayDir intersects
+  //! with the cylinder (or cone) with radiuses theBottomRad and theTopRad and height theHeights
+  Standard_EXPORT virtual Standard_Boolean RayCylinderIntersection (const Standard_Real theBottomRadius,
+                                                                    const Standard_Real theTopRadius,
+                                                                    const Standard_Real theHeight,
+                                                                    const gp_Pnt& theLoc,
+                                                                    const gp_Dir& theRayDir,
+                                                                    Standard_Real& theTimeEnter,
+                                                                    Standard_Real& theTimeLeave) const;
+
   DEFINE_STANDARD_RTTIEXT(SelectMgr_BaseIntersector,Standard_Transient)
 
 protected:
index 5b635b9acb6d4b0ef2ddbc99254b62f2fa3d6bf6..6299db613badc20113d6b4f35e75610d91f993c5 100644 (file)
@@ -93,8 +93,34 @@ protected:
                                      const Standard_Real theRadius,
                                      Standard_Boolean* theInside = NULL) const;
 
+  //! Intersection test between defined volume and given cylinder (or cone).
+  Standard_Boolean hasCylinderOverlap (const Standard_Real theBottomRad,
+                                       const Standard_Real theTopRad,
+                                       const Standard_Real theHeight,
+                                       const gp_Trsf& theTrsf,
+                                       Standard_Boolean* theInside = NULL) const;
+
+  //! Checking whether the point thePnt is inside the shape with borders theVertices.
+  //! thePnt and theVertices lie in the same plane.
+  Standard_Boolean IsDotInside (const gp_Pnt& thePnt,
+                                const TColgp_Array1OfPnt& theVertices) const;
+
 private:
 
+  //! Return true if one segment enclosed between the points thePnt1Seg1 and thePnt2Seg1
+  //! intersects another segment that enclosed between thePnt1Seg2 and thePnt2Seg2.
+  Standard_Boolean isSegmentsIntersect (const gp_Pnt& thePnt1Seg1,
+                                        const gp_Pnt& thePnt2Seg1,
+                                        const gp_Pnt& thePnt1Seg2,
+                                        const gp_Pnt& thePnt2Seg2) const;
+
+  //! Checking whether the borders theVertices of the shape intersect
+  //! the cylinder (or cone) end face with the center theCenter and radius theRadius
+  Standard_Boolean isIntersectCylinderEndFace (const Standard_Real theRad,
+                                               const gp_Pnt& theCenter,
+                                               const gp_Trsf& theTrsf,
+                                               const TColgp_Array1OfPnt& theVertices) const;
+
   //! Checks if AABB and frustum are separated along the given axis
   Standard_Boolean isSeparated (const SelectMgr_Vec3& theBoxMin,
                                 const SelectMgr_Vec3& theBoxMax,
index 4357516dea8e8603a1f209a30fd5a5068de23bfc..07be0d8d99c817f7f3e4b05b33dad44555f89ffe 100644 (file)
@@ -13,6 +13,7 @@
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
+#include <gp_Pln.hxx>
 #include <NCollection_Vector.hxx>
 #include <Poly_Array1OfTriangle.hxx>
 #include <Standard_Assert.hxx>
@@ -147,7 +148,6 @@ Standard_Boolean SelectMgr_Frustum<N>::hasBoxOverlap (const SelectMgr_Vec3& theM
   }
 
   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
-
   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
   {
     const gp_XYZ& aPlane = myPlanes[aPlaneIdx].XYZ();
@@ -207,7 +207,6 @@ template <int N>
 Standard_Boolean SelectMgr_Frustum<N>::hasPointOverlap (const gp_Pnt& thePnt) const
 {
   const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
-
   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < N + 1; aPlaneIdx += anIncFactor)
   {
     const Standard_Real aPointProj = myPlanes[aPlaneIdx].XYZ().Dot (thePnt.XYZ());
@@ -516,6 +515,259 @@ Standard_Boolean SelectMgr_Frustum<N>::hasSphereOverlap (const gp_Pnt& thePnt,
   return IsBoundaryIntersectSphere (aCenterProj, theRadius, aNorm, aBoundaries, isBoundaryInside);
 }
 
+// =======================================================================
+// function : IsDotInside
+// purpose  :
+// =======================================================================
+template<int N>
+Standard_Boolean SelectMgr_Frustum<N>::IsDotInside (const gp_Pnt& thePnt,
+                                                    const TColgp_Array1OfPnt& theVertices) const
+{
+  Standard_Real anAngle = 0.0;
+  for (Standard_Integer aVertIdx = 0; aVertIdx < theVertices.Size(); aVertIdx++)
+  {
+    const gp_Pnt aVert1 = theVertices[aVertIdx];
+    const gp_Pnt aVert2 = (aVertIdx == (theVertices.Size() - 1) ? theVertices[0] : theVertices[aVertIdx + 1]);
+    const gp_Vec aVec1 (thePnt, aVert1);
+    const gp_Vec aVec2 (thePnt, aVert2);
+    anAngle += aVec1.Angle (aVec2);
+  }
+  if (Abs (anAngle - 2.0 * M_PI) < Precision::Angular())
+  {
+    return true;
+  }
+  return false;
+}
+
+// =======================================================================
+// function : isSegmentsIntersect
+// purpose  :
+// =======================================================================
+template<int N>
+Standard_Boolean SelectMgr_Frustum<N>::isSegmentsIntersect (const gp_Pnt& thePnt1Seg1,
+                                                            const gp_Pnt& thePnt2Seg1,
+                                                            const gp_Pnt& thePnt1Seg2,
+                                                            const gp_Pnt& thePnt2Seg2) const
+{
+  const gp_Mat aMatPln (thePnt2Seg1.X() - thePnt1Seg1.X(), thePnt2Seg1.Y() - thePnt1Seg1.Y(), thePnt2Seg1.Z() - thePnt1Seg1.Z(),
+                        thePnt1Seg2.X() - thePnt1Seg1.X(), thePnt1Seg2.Y() - thePnt1Seg1.Y(), thePnt1Seg2.Z() - thePnt1Seg1.Z(),
+                        thePnt2Seg2.X() - thePnt1Seg1.X(), thePnt2Seg2.Y() - thePnt1Seg1.Y(), thePnt2Seg2.Z() - thePnt1Seg1.Z());
+  if (Abs (aMatPln.Determinant()) > Precision::Confusion())
+  {
+    return false;
+  }
+
+  Standard_Real aFst[4] = {thePnt1Seg1.X(), thePnt2Seg1.X(), thePnt1Seg2.X(), thePnt2Seg2.X()};
+  Standard_Real aSnd[4] = {thePnt1Seg1.Y(), thePnt2Seg1.Y(), thePnt1Seg2.Y(), thePnt2Seg2.Y()};
+  if (aFst[0] == aFst[2] && aFst[1] == aFst[3])
+  {
+    aFst[0] = thePnt1Seg1.Z();
+    aFst[1] = thePnt2Seg1.Z();
+    aFst[2] = thePnt1Seg2.Z();
+    aFst[3] = thePnt2Seg2.Z();
+  }
+  if (aSnd[0] == aSnd[2]
+   && aSnd[1] == aSnd[3])
+  {
+    aSnd[0] = thePnt1Seg1.Z();
+    aSnd[1] = thePnt2Seg1.Z();
+    aSnd[2] = thePnt1Seg2.Z();
+    aSnd[3] = thePnt2Seg2.Z();
+  }
+  const gp_Mat2d aMat (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
+                       gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
+
+  const gp_Mat2d aMatU (gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]),
+                        gp_XY (aFst[3] - aFst[2], aSnd[3] - aSnd[2]));
+
+  const gp_Mat2d aMatV (gp_XY (aFst[0] - aFst[1], aSnd[0] - aSnd[1]),
+                        gp_XY (aFst[0] - aFst[2], aSnd[0] - aSnd[2]));
+  if (aMat.Determinant() == 0.0)
+  {
+    return false;
+  }
+
+  const Standard_Real anU = aMatU.Determinant() / aMat.Determinant();
+  const Standard_Real aV  = aMatV.Determinant() / aMat.Determinant();
+  if (anU >= 0.0 && anU <= 1.0
+   && aV  >= 0.0 && aV  <= 1.0)
+  {
+    return true;
+  }
+  return false;
+}
+
+// =======================================================================
+// function : isIntersectCylinderEndFace
+// purpose  :
+// =======================================================================
+template<int N>
+Standard_Boolean SelectMgr_Frustum<N>::isIntersectCylinderEndFace (const Standard_Real theRad,
+                                                                   const gp_Pnt& theCenter,
+                                                                   const gp_Trsf& theTrsf,
+                                                                   const TColgp_Array1OfPnt& theVertices) const
+{
+  const gp_Trsf aTrsfInv = theTrsf.Inverted();
+  const gp_Dir aRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]).Transformed (aTrsfInv);
+  if (aRayDir.Z() == 0.0)
+  {
+    return false;
+  }
+
+  for (Standard_Integer anIdx = theVertices.Lower(); anIdx <= theVertices.Upper(); anIdx++)
+  {
+    const gp_Pnt aPntStart = theVertices.Value (anIdx).Transformed (aTrsfInv);
+    const gp_Pnt aPntFinish = anIdx == theVertices.Upper()
+                            ? theVertices.Value (theVertices.Lower()).Transformed (aTrsfInv)
+                            : theVertices.Value (anIdx + 1).Transformed (aTrsfInv);
+
+    // Project points on the end face plane
+    const Standard_Real aParam1 = (theCenter.Z() - aPntStart.Z()) / aRayDir.Z();
+    const Standard_Real aX1 = aPntStart.X() + aRayDir.X() * aParam1;
+    const Standard_Real anY1 = aPntStart.Y() + aRayDir.Y() * aParam1;
+
+    const Standard_Real aParam2 = (theCenter.Z() - aPntFinish.Z()) / aRayDir.Z();
+    const Standard_Real aX2 = aPntFinish.X() + aRayDir.X() * aParam2;
+    const Standard_Real anY2 = aPntFinish.Y() + aRayDir.Y() * aParam2;
+
+    // Solving quadratic equation anA * T^2 + 2 * aK * T + aC = 0
+    const Standard_Real anA = (aX1 - aX2) * (aX1 - aX2) + (anY1 - anY2) * (anY1 - anY2);
+    const Standard_Real aK = aX1 * (aX2 - aX1) + anY1 * (anY2 - anY1);
+    const Standard_Real aC = aX1 * aX1 + anY1 * anY1 - theRad * theRad;
+
+    const Standard_Real aDiscr = aK * aK - anA * aC;
+    if (aDiscr >= 0.0)
+    {
+      const Standard_Real aT1 = (-aK + Sqrt (aDiscr)) / anA;
+      const Standard_Real aT2 = (-aK - Sqrt (aDiscr)) / anA;
+      if ((aT1 >= 0 && aT1 <= 1) || (aT2 >= 0 && aT2 <= 1))
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+// =======================================================================
+// function : hasCylinderOverlap
+// purpose  :
+// =======================================================================
+template<int N>
+Standard_Boolean SelectMgr_Frustum<N>::hasCylinderOverlap (const Standard_Real theBottomRad,
+                                                           const Standard_Real theTopRad,
+                                                           const Standard_Real theHeight,
+                                                           const gp_Trsf& theTrsf,
+                                                           Standard_Boolean* theInside) const
+{
+  const gp_Dir aCylNorm (gp::DZ().Transformed (theTrsf));
+  const gp_Pnt aBottomCenter (gp::Origin().Transformed (theTrsf));
+  const gp_Pnt aTopCenter = aBottomCenter.XYZ() + aCylNorm.XYZ() * theHeight;
+
+  const gp_Dir aViewRayDir = gp_Dir (myEdgeDirs[N == 4 ? 4 : 0]);
+  const gp_Pln aPln (myVertices[0], aViewRayDir);
+  Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
+  aPln.Coefficients (aCoefA, aCoefB, aCoefC, aCoefD);
+
+  const Standard_Real aTBottom = -(aBottomCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
+  const gp_Pnt aBottomCenterProject (aCoefA * aTBottom + aBottomCenter.X(),
+                                     aCoefB * aTBottom + aBottomCenter.Y(),
+                                     aCoefC * aTBottom + aBottomCenter.Z());
+  const Standard_Real aTTop = -(aTopCenter.XYZ().Dot (aViewRayDir.XYZ()) + aCoefD);
+  const gp_Pnt aTopCenterProject (aCoefA * aTTop + aTopCenter.X(),
+                                  aCoefB * aTTop + aTopCenter.Y(),
+                                  aCoefC * aTTop + aTopCenter.Z());
+  gp_Vec aCylNormProject (0, 0, 0);
+  if (aTopCenterProject.Distance (aBottomCenterProject)  > 0.0)
+  {
+    aCylNormProject = gp_Vec ((aTopCenterProject.XYZ() - aBottomCenterProject.XYZ())
+                             / aTopCenterProject.Distance (aBottomCenterProject));
+  }
+
+  gp_Pnt aPoints[6];
+  const gp_Dir aDirEndFaces = (aCylNorm.IsParallel (aViewRayDir, Precision::Angular()))
+                             ? gp::DY().Transformed (theTrsf)
+                             : aCylNorm.Crossed (aViewRayDir);
+
+  const Standard_Real anAngle = aCylNorm.Angle (aViewRayDir);
+  aPoints[0] = aBottomCenterProject.XYZ() - aCylNormProject.XYZ() * theBottomRad * Abs (Cos (anAngle));
+  aPoints[1] = aBottomCenterProject.XYZ() + aDirEndFaces.XYZ() * theBottomRad;
+  aPoints[2] = aTopCenterProject.XYZ() + aDirEndFaces.XYZ() * theTopRad;
+  aPoints[3] = aTopCenterProject.XYZ() + aCylNormProject.XYZ() * theTopRad * Abs (Cos (anAngle));
+  aPoints[4] = aTopCenterProject.XYZ() - aDirEndFaces.XYZ() * theTopRad;
+  aPoints[5] = aBottomCenterProject.XYZ() - aDirEndFaces.XYZ() * theBottomRad;
+  const TColgp_Array1OfPnt aPointsArr (aPoints[0], 0, 5);
+
+  gp_Pnt aVerticesBuf[N];
+  TColgp_Array1OfPnt aVertices (aVerticesBuf[0], 0, N - 1);
+  const Standard_Integer anIncFactor = (Camera()->IsOrthographic() && N == 4) ? 2 : 1;
+  if (anIncFactor == 2)
+  {
+    const Standard_Integer anIndices[] = { 0, 2, 6, 4 };
+    for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
+    {
+      aVertices.SetValue (anIdx, myVertices[anIndices[anIdx]]);
+    }
+  }
+  else
+  {
+    for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
+    {
+      aVertices.SetValue (anIdx, myVertices[anIdx]);
+    }
+  }
+  for (Standard_Integer anIdx = 0; anIdx < N; anIdx++)
+  {
+    if ((aCylNormProject.Dot (aCylNormProject) == 0.0
+     && aVertices.Value (anIdx).Distance (aPoints[0]) <= Max (theTopRad, theBottomRad))
+     || IsDotInside (aVertices.Value (anIdx), aPointsArr))
+    {
+      if (theInside != NULL)
+      {
+        *theInside = false;
+      }
+      return true;
+    }
+  }
+
+  for (Standard_Integer anIdx = aVertices.Lower(); anIdx <= aVertices.Upper(); anIdx++)
+  {
+    const gp_Pnt aPnt1Seg = aVertices[anIdx];
+    const gp_Pnt aPnt2Seg = (anIdx == aVertices.Upper()) ? aVertices[aVertices.Lower()] : aVertices[anIdx + 1];
+    if (isSegmentsIntersect (aPoints[1], aPoints[2], aPnt1Seg, aPnt2Seg)
+     || isSegmentsIntersect (aPoints[4], aPoints[5], aPnt1Seg, aPnt2Seg)
+     || isSegmentsIntersect (aPoints[4], aPoints[2], aPnt1Seg, aPnt2Seg)
+     || isSegmentsIntersect (aPoints[1], aPoints[5], aPnt1Seg, aPnt2Seg))
+    {
+      if (theInside != NULL)
+      {
+        *theInside = false;
+      }
+      return true;
+    }
+  }
+
+  if (isIntersectCylinderEndFace (theBottomRad, gp_Pnt (0, 0, 0), theTrsf, aVertices)
+   || isIntersectCylinderEndFace (theTopRad, gp_Pnt (0, 0, theHeight), theTrsf, aVertices))
+  {
+    if (theInside != NULL)
+    {
+      *theInside = false;
+    }
+    return true;
+  }
+  bool isCylInsideRec = true;
+  for (int i = 0; i < 6; ++i)
+  {
+    isCylInsideRec &= IsDotInside (aPoints[i], aVertices);
+  }
+  if (theInside != NULL)
+  {
+    *theInside &= isCylInsideRec;
+  }
+  return isCylInsideRec;
+}
+
 //=======================================================================
 //function : DumpJson
 //purpose  : 
index 9b8925f12d54d84a8456dbfaeebdb24d670a6cf7..44354f1f84a83274f9abefddf14bbf33f553cad5 100644 (file)
@@ -740,6 +740,65 @@ Standard_Boolean SelectMgr_RectangularFrustum::OverlapsTriangle (const gp_Pnt& t
   return !theClipRange.IsClipped (thePickResult.Depth());
 }
 
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                 const Standard_Real theTopRad,
+                                                                 const Standard_Real theHeight,
+                                                                 const gp_Trsf& theTrsf,
+                                                                 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");
+  Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
+  const gp_Trsf aTrsfInv = theTrsf.Inverted();
+  const gp_Pnt  aLoc     = myNearPickedPnt.Transformed (aTrsfInv);
+  const gp_Dir  aRayDir  = myViewRayDir   .Transformed (aTrsfInv);
+  if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
+  {
+    return Standard_False;
+  }
+  thePickResult.SetDepth (aTimeEnter * myScale);
+  if (theClipRange.IsClipped (thePickResult.Depth()))
+  {
+    thePickResult.SetDepth (aTimeLeave * myScale);
+  }
+  const gp_Pnt aPntOnCylinder (aLoc.XYZ() + aRayDir.XYZ() * thePickResult.Depth());
+  if (Abs (aPntOnCylinder.Z()) < Precision::Confusion())
+  {
+    thePickResult.SetSurfaceNormal (-gp::DZ().Transformed (theTrsf));
+  }
+  else if (Abs (aPntOnCylinder.Z() - theHeight) < Precision::Confusion())
+  {
+    thePickResult.SetSurfaceNormal (gp::DZ().Transformed (theTrsf));
+  }
+  else
+  {
+    thePickResult.SetSurfaceNormal (gp_Vec (aPntOnCylinder.X(), aPntOnCylinder.Y(), 0.0).Transformed (theTrsf));
+  }
+  thePickResult.SetPickedPoint (aPntOnCylinder);
+  return !theClipRange.IsClipped (thePickResult.Depth());
+}
+
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_RectangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                 const Standard_Real theTopRad,
+                                                                 const Standard_Real theHeight,
+                                                                 const gp_Trsf& theTrsf,
+                                                                 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 hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf, theInside);
+}
+
 // =======================================================================
 // function : GetMousePosition
 // purpose  :
index 145f1d072a9d2a5d2422f2df932218ff483cbcb4..8788a4af51bf472cfd1afa622bfd14c18148041d 100644 (file)
@@ -144,6 +144,23 @@ public:
                                                            const Standard_Real theRadius,
                                                            Standard_Boolean* theInside) const Standard_OVERRIDE;
 
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             const SelectMgr_ViewClipRange& theClipRange,
+                                                             SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             Standard_Boolean* theInside = NULL) 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 8ecc30fa9297f55186d056a3d8cbe75d3fcbfe9c..d4eee16aecc04a133ea27a78176517b856d84ff7 100644 (file)
@@ -418,6 +418,40 @@ Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsSphere (const gp_Pnt&
   return myActiveSelectingVolume->OverlapsSphere (theCenter, theRadius, theInside);
 }
 
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                     const Standard_Real theTopRad,
+                                                                     const Standard_Real theHeight,
+                                                                     const gp_Trsf& theTrsf,
+                                                                     SelectBasics_PickResult& thePickResult) const
+{
+  if (myActiveSelectingVolume.IsNull())
+  {
+    return false;
+  }
+  return myActiveSelectingVolume->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, myViewClipRange, thePickResult);
+}
+
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_SelectingVolumeManager::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                     const Standard_Real theTopRad,
+                                                                     const Standard_Real theHeight,
+                                                                     const gp_Trsf& theTrsf,
+                                                                     Standard_Boolean* theInside) const
+{
+  if (myActiveSelectingVolume.IsNull())
+  {
+    return false;
+  }
+  return myActiveSelectingVolume->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, theInside);
+}
+
 //=======================================================================
 // function : DistToGeometryCenter
 // purpose  : Measures distance between 3d projection of user-picked
index 992a1c834f562e935da9d33d50fd9a52a2af2fae..580e206cdae0774390e699170d640cd8f1cf14ce 100644 (file)
@@ -162,6 +162,22 @@ public:
                                                            const Standard_Real theRadius,
                                                            Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
 
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             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 76177b2087eca9b40180283a1a6947f2caf4f209..5436525f6e01b23ac12c3c0bcfe92d6bacfcc6d2 100644 (file)
@@ -67,6 +67,56 @@ namespace
     NCollection_DataMap<Handle(Select3D_SensitiveEntity), Quantity_Color> myMapEntityColors;
   };
 
+  //! Help class for filling pixel with random color.
+  class GeneratedEntityTypeColorFiller : public SelectMgr_SelectionImageFiller
+  {
+  public:
+    GeneratedEntityTypeColorFiller (Image_PixMap& thePixMap,
+                                    SelectMgr_ViewerSelector* theSelector)
+    : SelectMgr_SelectionImageFiller (thePixMap, theSelector)
+    {
+      // generate per-entity colors in the order as they have been activated
+      for (SelectMgr_SelectableObjectSet::Iterator anObjIter (theSelector->SelectableObjects()); anObjIter.More(); anObjIter.Next())
+      {
+        const Handle(SelectMgr_SelectableObject)& anObj = anObjIter.Value();
+        for (SelectMgr_SequenceOfSelection::Iterator aSelIter (anObj->Selections()); aSelIter.More(); aSelIter.Next())
+        {
+          const Handle(SelectMgr_Selection)& aSel = aSelIter.Value();
+          for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (aSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
+          {
+            const Handle(SelectMgr_SensitiveEntity)& aSens = aSelEntIter.Value();
+            if (!myMapEntityColors.IsBound (aSens->BaseSensitive()->DynamicType()))
+            {
+              Quantity_Color aColor;
+              randomPastelColor (aColor);
+              myMapEntityColors.Bind (aSens->BaseSensitive()->DynamicType(), aColor);
+            }
+          }
+        }
+      }
+    }
+
+    virtual void Fill (const Standard_Integer theCol,
+                       const Standard_Integer theRow,
+                       const Standard_Integer thePicked) Standard_OVERRIDE
+    {
+      if (thePicked < 1
+       || thePicked > myMainSel->NbPicked())
+      {
+        myImage->SetPixelColor (theCol, theRow, Quantity_Color(Quantity_NOC_BLACK));
+        return;
+      }
+
+      const Handle(Select3D_SensitiveEntity)& aPickedEntity = myMainSel->PickedEntity (thePicked);
+      Quantity_Color aColor (Quantity_NOC_BLACK);
+      myMapEntityColors.Find (aPickedEntity->DynamicType(), aColor);
+      myImage->SetPixelColor (theCol, theRow, aColor);
+    }
+
+  protected:
+    NCollection_DataMap<Handle(Standard_Type), Quantity_Color> myMapEntityColors;
+  };
+
   //! Help class for filling pixel with normalized depth of ray.
   class NormalizedDepthFiller : public SelectMgr_SelectionImageFiller
   {
@@ -384,6 +434,10 @@ Handle(SelectMgr_SelectionImageFiller) SelectMgr_SelectionImageFiller::CreateFil
     {
       return new GeneratedEntityColorFiller (thePixMap, theSelector);
     }
+    case StdSelect_TypeOfSelectionImage_ColoredEntityType:
+    {
+      return new GeneratedEntityTypeColorFiller (thePixMap, theSelector);
+    }
     case StdSelect_TypeOfSelectionImage_ColoredOwner:
     {
       return new GeneratedOwnerColorFiller (thePixMap, theSelector);
index 6f458b033b84f3b536085345e7a4cca039a7d6e8..44e8dac76d445b1041830405e3def1a6ae1134bb 100644 (file)
@@ -329,6 +329,36 @@ Standard_Boolean SelectMgr_TriangularFrustum::OverlapsSphere (const gp_Pnt& theC
   return hasSphereOverlap (theCenter, theRadius);
 }
 
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                const Standard_Real theTopRad,
+                                                                const Standard_Real theHeight,
+                                                                const gp_Trsf& theTrsf,
+                                                                const SelectMgr_ViewClipRange& theClipRange,
+                                                                SelectBasics_PickResult& thePickResult) const
+{
+  (void)theClipRange;
+  (void)thePickResult;
+  return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf);
+}
+
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustum::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                const Standard_Real theTopRad,
+                                                                const Standard_Real theHeight,
+                                                                const gp_Trsf& theTrsf,
+                                                                Standard_Boolean* theInside) const
+{
+  (void) theInside;
+  return hasCylinderOverlap (theBottomRad, theTopRad, theHeight, theTrsf);
+}
+
 // =======================================================================
 // function : Clear
 // purpose  : Nullifies the handle for corresponding builder instance to prevent
index 0719132ef5f59670b0fa155f9d3308b005ee272c..a5c7d0857637e8ef2fbc3dacb801320c48feae30 100644 (file)
@@ -117,6 +117,23 @@ 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 cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             const SelectMgr_ViewClipRange& theClipRange,
+                                                             SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             Standard_Boolean* theInside = NULL) const Standard_OVERRIDE;
+
 public:
 
   //! Nullifies the handle to corresponding builder instance to prevent memory leaks
index f8ed8857f0bda28afd7a799ebf4b8ae958b316d4..31cc5e69f48335f618ec7cc6c53561376e3516d9 100644 (file)
@@ -498,6 +498,123 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsSphere (const gp_Pnt& t
   return Standard_False;
 }
 
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                   const Standard_Real theTopRad,
+                                                                   const Standard_Real theHeight,
+                                                                   const gp_Trsf& theTrsf,
+                                                                   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()->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, theClipRange, thePickResult))
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+//=======================================================================
+// function : OverlapsCylinder
+// purpose  :
+//=======================================================================
+Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsCylinder (const Standard_Real theBottomRad,
+                                                                   const Standard_Real theTopRad,
+                                                                   const Standard_Real theHeight,
+                                                                   const gp_Trsf& theTrsf,
+                                                                   Standard_Boolean* theInside) const
+{
+  const gp_Dir aCylNorm (gp::DZ().Transformed (theTrsf));
+  const gp_Pnt aBottomCenter (gp::Origin().Transformed (theTrsf));
+  const gp_Pnt aTopCenter = aBottomCenter.XYZ() + aCylNorm.XYZ() * theHeight;
+
+  const gp_Vec aVecPlane1 (myFrustums.First()->myVertices[0], myFrustums.First()->myVertices[1]);
+  const gp_Vec aVecPlane2 (myFrustums.First()->myVertices[0], myFrustums.First()->myVertices[2]);
+
+  const gp_Dir aDirNorm (aVecPlane1.Crossed (aVecPlane2));
+  const Standard_Real anAngle = aCylNorm.Angle (aDirNorm);
+  const Standard_Real aCosAngle = Cos (anAngle);
+  const gp_Pln aPln (myFrustums.First()->myVertices[0], aDirNorm);
+  Standard_Real aCoefA, aCoefB, aCoefC, aCoefD;
+  aPln.Coefficients (aCoefA, aCoefB, aCoefC, aCoefD);
+
+  const Standard_Real aTBottom = -(aBottomCenter.XYZ().Dot (aDirNorm.XYZ()) + aCoefD) / aDirNorm.Dot (aDirNorm);
+  const gp_Pnt aBottomCenterProject (aCoefA * aTBottom + aBottomCenter.X(),
+                                     aCoefB * aTBottom + aBottomCenter.Y(),
+                                     aCoefC * aTBottom + aBottomCenter.Z());
+
+  const Standard_Real aTTop = -(aTopCenter.XYZ().Dot (aDirNorm.XYZ()) + aCoefD) / aDirNorm.Dot (aDirNorm);
+  const gp_Pnt aTopCenterProject (aCoefA * aTTop + aTopCenter.X(),
+                                  aCoefB * aTTop + aTopCenter.Y(),
+                                  aCoefC * aTTop + aTopCenter.Z());
+
+  gp_XYZ aCylNormProject;
+  const gp_XYZ aTopBottomVec = aTopCenterProject.XYZ() - aBottomCenterProject.XYZ();
+  const Standard_Real aTopBottomDist = aTopBottomVec.Modulus();
+  if (aTopBottomDist > 0.0)
+  {
+    aCylNormProject = aTopBottomVec / aTopBottomDist;
+  }
+
+  gp_Pnt aPoints[6];
+  aPoints[0] = aBottomCenterProject.XYZ() - aCylNormProject * theBottomRad * Abs (aCosAngle);
+  aPoints[1] = aTopCenterProject.XYZ()    + aCylNormProject * theTopRad * Abs (aCosAngle);
+  const gp_Dir aDirEndFaces = (aCylNorm.IsParallel (aDirNorm, Precision::Angular()))
+                             ? gp::DY().Transformed (theTrsf)
+                             : aCylNorm.Crossed (aDirNorm);
+
+  aPoints[2] = aTopCenterProject.XYZ()    + aDirEndFaces.XYZ() * theTopRad;
+  aPoints[3] = aTopCenterProject.XYZ()    - aDirEndFaces.XYZ() * theTopRad;
+  aPoints[4] = aBottomCenterProject.XYZ() + aDirEndFaces.XYZ() * theBottomRad;
+  aPoints[5] = aBottomCenterProject.XYZ() - aDirEndFaces.XYZ() * theBottomRad;
+
+  gp_Pnt aVerticesBuf[3];
+  TColgp_Array1OfPnt aVertices (aVerticesBuf[0], 0, 2);
+
+  bool isCylInsideTriangSet = true;
+  for (int i = 0; i < 6; ++i)
+  {
+    bool isInside = false;
+    for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
+    {
+
+      for (int anIdx = 0; anIdx < 3; anIdx++)
+      {
+        aVertices[anIdx] = anIter.Value()->myVertices[anIdx];
+      }
+      if (anIter.Value()->IsDotInside (aPoints[i], aVertices))
+      {
+        isInside = true;
+        break;
+      }
+    }
+    isCylInsideTriangSet &= isInside;
+  }
+  if (theInside != NULL)
+  {
+    *theInside &= isCylInsideTriangSet;
+  }
+  if (isCylInsideTriangSet)
+  {
+    return true;
+  }
+  for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value()->OverlapsCylinder (theBottomRad, theTopRad, theHeight, theTrsf, theInside))
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
 // =======================================================================
 // function : GetPlanes
 // purpose  :
index 1618b44d644255204b49ec90c23a24caa6fae98c..f5c51f31a0b2fe0b3e358ef610ef3a5ace33e518 100644 (file)
@@ -118,6 +118,23 @@ public:
                                                            const SelectMgr_ViewClipRange& theClipRange,
                                                            SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
 
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             const SelectMgr_ViewClipRange& theClipRange,
+                                                             SelectBasics_PickResult& thePickResult) const Standard_OVERRIDE;
+
+  //! Returns true if selecting volume is overlapped by cylinder (or cone) with radiuses theBottomRad
+  //! and theTopRad, height theHeight and transformation to apply theTrsf.
+  Standard_EXPORT virtual Standard_Boolean OverlapsCylinder (const Standard_Real theBottomRad,
+                                                             const Standard_Real theTopRad,
+                                                             const Standard_Real theHeight,
+                                                             const gp_Trsf& theTrsf,
+                                                             Standard_Boolean* theInside = NULL) 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 8d3a79c15d7ff2b6a09e67506509f14e42da8f9e..ce3ecbf5be620cc22a8c9495e1a3472b9fe702ac 100644 (file)
@@ -27,6 +27,9 @@
 #include <GCPnts_TangentialDeflection.hxx>
 #include <GeomAbs_SurfaceType.hxx>
 #include <GeomAdaptor_Curve.hxx>
+#include <Geom_ConicalSurface.hxx>
+#include <Geom_CylindricalSurface.hxx>
+#include <Geom_Plane.hxx>
 #include <Geom_SphericalSurface.hxx>
 #include <gp_Circ.hxx>
 #include <Poly_Array1OfTriangle.hxx>
@@ -37,6 +40,7 @@
 #include <Select3D_SensitiveBox.hxx>
 #include <Select3D_SensitiveCircle.hxx>
 #include <Select3D_SensitiveCurve.hxx>
+#include <Select3D_SensitiveCylinder.hxx>
 #include <Select3D_SensitiveEntity.hxx>
 #include <Select3D_SensitiveFace.hxx>
 #include <Select3D_SensitiveGroup.hxx>
@@ -268,6 +272,142 @@ void StdSelect_BRepSelectionTool::ComputeSensitive (const TopoDS_Shape& theShape
     {
       TopTools_IndexedMapOfShape aSubfacesMap;
       TopExp::MapShapes (theShape, TopAbs_FACE, aSubfacesMap);
+      if (aSubfacesMap.Extent() == 2) // detect cone
+      {
+        const TopoDS_Face* aFaces[2] =
+        {
+          &TopoDS::Face (aSubfacesMap.FindKey (1)),
+          &TopoDS::Face (aSubfacesMap.FindKey (2))
+        };
+
+        TopLoc_Location aLocSurf;
+        const Handle(Geom_Surface)* aSurfaces[2] =
+        {
+          &BRep_Tool::Surface (*aFaces[0], aLocSurf),
+          &BRep_Tool::Surface (*aFaces[1], aLocSurf)
+        };
+
+        Standard_Integer aConIndex = 0;
+        Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast (*aSurfaces[0]);
+        Handle(Geom_Plane) aGeomPln;
+        if (!aGeomCone.IsNull())
+        {
+          aGeomPln = Handle(Geom_Plane)::DownCast (*aSurfaces[1]);
+        }
+        else
+        {
+          aConIndex = 1;
+          aGeomCone = Handle(Geom_ConicalSurface)::DownCast (*aSurfaces[1]);
+          aGeomPln  = Handle(Geom_Plane)::DownCast (*aSurfaces[0]);
+        }
+        if (!aGeomCone.IsNull()
+         && !aGeomPln.IsNull()
+         &&  aGeomPln->Position().Direction().IsEqual (aGeomCone->Position().Direction(), Precision::Angular()))
+        {
+          const gp_Cone aCone = BRepAdaptor_Surface (*aFaces[aConIndex]).Cone();
+          const Standard_Real aRad1 = aCone.RefRadius();
+          const Standard_Real aHeight = (aRad1 != 0.0)
+                                       ? aRad1 / Abs (Tan (aCone.SemiAngle()))
+                                       : aCone.Location().Distance (aGeomPln->Location());
+          const Standard_Real aRad2 = (aRad1 != 0.0) ? 0.0 : Tan (aCone.SemiAngle()) * aHeight;
+          gp_Trsf aTrsf;
+          aTrsf.SetTransformation (aCone.Position(), gp_Ax3());
+          Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad1, aRad2, aHeight, aTrsf);
+          theSelection->Add (aSensSCyl);
+          break;
+        }
+      }
+      if (aSubfacesMap.Extent() == 3) // detect cylinder or truncated cone
+      {
+        const TopoDS_Face* aFaces[3] =
+        {
+          &TopoDS::Face (aSubfacesMap.FindKey (1)),
+          &TopoDS::Face (aSubfacesMap.FindKey (2)),
+          &TopoDS::Face (aSubfacesMap.FindKey (3))
+        };
+
+        TopLoc_Location aLocSurf;
+        const Handle(Geom_Surface)* aSurfaces[3] =
+        {
+          &BRep_Tool::Surface (*aFaces[0], aLocSurf),
+          &BRep_Tool::Surface (*aFaces[1], aLocSurf),
+          &BRep_Tool::Surface (*aFaces[2], aLocSurf)
+        };
+
+        Standard_Integer aConIndex = -1, aNbPlanes = 0;
+        Handle(Geom_ConicalSurface) aGeomCone;
+        Handle(Geom_CylindricalSurface) aGeomCyl;
+        Handle(Geom_Plane) aGeomPlanes[2];
+        for (Standard_Integer aSurfIter = 0; aSurfIter < 3; ++aSurfIter)
+        {
+          const Handle(Geom_Surface)& aSurf = *aSurfaces[aSurfIter];
+          if (aConIndex == -1)
+          {
+            aGeomCone = Handle (Geom_ConicalSurface)::DownCast (aSurf);
+            if (!aGeomCone.IsNull())
+            {
+              aConIndex = aSurfIter;
+              continue;
+            }
+            aGeomCyl = Handle (Geom_CylindricalSurface)::DownCast (aSurf);
+            if (!aGeomCyl.IsNull())
+            {
+              aConIndex = aSurfIter;
+              continue;
+            }
+          }
+          if (aNbPlanes < 2)
+          {
+            aGeomPlanes[aNbPlanes] = Handle(Geom_Plane)::DownCast (aSurf);
+            if (!aGeomPlanes[aNbPlanes].IsNull())
+            {
+              ++aNbPlanes;
+            }
+          }
+        }
+
+        if (!aGeomCone.IsNull())
+        {
+          if (!aGeomPlanes[0].IsNull()
+           && !aGeomPlanes[1].IsNull()
+           &&  aGeomPlanes[0]->Position().Direction().IsEqual (aGeomCone->Position().Direction(), Precision::Angular())
+           &&  aGeomPlanes[1]->Position().Direction().IsEqual (aGeomCone->Position().Direction(), Precision::Angular()))
+          {
+            const gp_Cone aCone = BRepAdaptor_Surface (*aFaces[aConIndex]).Cone();
+            const Standard_Real aRad1 = aCone.RefRadius();
+            const Standard_Real aHeight = aGeomPlanes[0]->Location().Distance (aGeomPlanes[1]->Location());
+            gp_Trsf aTrsf;
+            aTrsf.SetTransformation (aCone.Position(), gp_Ax3());
+            const Standard_Real aTriangleHeight = (aCone.SemiAngle() > 0.0)
+                                                ?  aRad1 / Tan (aCone.SemiAngle())
+                                                :  aRad1 / Tan (Abs (aCone.SemiAngle())) - aHeight;
+            const Standard_Real aRad2 = (aCone.SemiAngle() > 0.0)
+                                       ? aRad1 * (aTriangleHeight + aHeight) / aTriangleHeight
+                                       : aRad1 * aTriangleHeight / (aTriangleHeight + aHeight);
+            Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad1, aRad2, aHeight, aTrsf);
+            theSelection->Add (aSensSCyl);
+            break;
+          }
+        }
+        else if (!aGeomCyl.IsNull())
+        {
+          if (!aGeomPlanes[0].IsNull()
+           && !aGeomPlanes[1].IsNull()
+           &&  aGeomPlanes[0]->Position().Direction().IsEqual (aGeomCyl->Position().Direction(), Precision::Angular())
+           &&  aGeomPlanes[1]->Position().Direction().IsEqual (aGeomCyl->Position().Direction(), Precision::Angular()))
+          {
+            const gp_Cylinder aCyl = BRepAdaptor_Surface (*aFaces[aConIndex]).Cylinder();
+            const Standard_Real aRad = aCyl.Radius();
+            const Standard_Real aHeight = aGeomPlanes[0]->Location().Distance (aGeomPlanes[1]->Location());
+            gp_Trsf aTrsf;
+            aTrsf.SetTransformation (aCyl.Position(), gp_Ax3());
+            Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad, aRad, aHeight, aTrsf);
+            theSelection->Add (aSensSCyl);
+            break;
+          }
+        }
+      }
+
       for (Standard_Integer aShIndex = 1; aShIndex <= aSubfacesMap.Extent(); ++aShIndex)
       {
         ComputeSensitive (aSubfacesMap (aShIndex), theOwner,
index 52c64307d987d250ec8d7080ee8d4a13f0cd7e6b..bfca297dbfae48512acc8c30e14a798bc9d99af3 100644 (file)
@@ -23,6 +23,7 @@ enum StdSelect_TypeOfSelectionImage
   StdSelect_TypeOfSelectionImage_UnnormalizedDepth,       //!< unnormalized depth (grayscale)
   StdSelect_TypeOfSelectionImage_ColoredDetectedObject,   //!< color of detected object
   StdSelect_TypeOfSelectionImage_ColoredEntity,           //!< random color for each entity
+  StdSelect_TypeOfSelectionImage_ColoredEntityType,       //!< random color for each entity type
   StdSelect_TypeOfSelectionImage_ColoredOwner,            //!< random color for each owner
   StdSelect_TypeOfSelectionImage_ColoredSelectionMode,    //!< color of selection mode
   StdSelect_TypeOfSelectionImage_SurfaceNormal            //!< normal direction values
index 67870df603a79f6b7e9404c6acedc4560b04acaf..235badc39466e5c7b7b8ef2052da2a6e52f5abc4 100644 (file)
@@ -13699,6 +13699,11 @@ static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
       {
         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
       }
+      else if (aValue == "entitytypecolor"
+            || aValue == "entitytype")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredEntityType;
+      }
       else if (aValue == "ownercolor"
             || aValue == "owner")
       {
@@ -15148,7 +15153,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
                    __FILE__, VSelectionProperties, group);
 
   theCommands.Add ("vseldump",
-                   "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|surfNormal}=depth -pickedIndex Index=1"
+                   "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|entityType|surfNormal}=depth -pickedIndex Index=1"
                    "\n\t\t:       [-xrPose base|head=base]"
                    "\n\t\t: Generate an image based on detection results:"
                    "\n\t\t:   depth       normalized depth values"
@@ -15156,7 +15161,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
                    "\n\t\t:   object      color of detected object"
                    "\n\t\t:   owner       color of detected owner"
                    "\n\t\t:   selMode     color of selection mode"
-                   "\n\t\t:   entity      color of etected entity"
+                   "\n\t\t:   entity      color of detected entity"
+                   "\n\t\t:   entityType  color of detected entity type"
                    "\n\t\t:   surfNormal  normal direction values",
                    __FILE__, VDumpSelectionImage, group);
 
diff --git a/tests/vselect/cone_cylinder/begin b/tests/vselect/cone_cylinder/begin
new file mode 100644 (file)
index 0000000..26ce000
--- /dev/null
@@ -0,0 +1,2 @@
+vinit View1 -height 400 -width 600
+set subgroup "cone_cylinder"
diff --git a/tests/vselect/cone_cylinder/check_depth b/tests/vselect/cone_cylinder/check_depth
new file mode 100644 (file)
index 0000000..f4ba540
--- /dev/null
@@ -0,0 +1,56 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests depth value returned by Select3D_SensitiveCylinder"
+puts "================================="
+
+pcylinder cyl 10 20
+vdisplay cyl -dispmode 1
+vfit
+set center_cyl [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cylinder should be detected" }
+checkpoint center_cyl_p $center_cyl {7.0710678118654755 -7.0710678118654755 16.970067811865476} 0.0001
+vtop
+vfit
+set top_cyl [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cylinder should be detected" }
+checkpoint top_cyl_p $top_cyl {0 -0.050500000000000045 20} 0.0001
+vbottom
+set bottom_cyl [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cylinder should be detected" }
+checkpoint bottom_cyl_p $bottom_cyl {0 0.050500000000000052 0} 0.0001
+vright
+vfit
+set right_cyl [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cylinder should be detected" }
+checkpoint right_cyl_p $right_cyl {10 0 9.9495000000000005} 0.0001
+vleft
+set left_cyl [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cylinder should be detected" }
+checkpoint left_cyl_p $left_cyl {-10 0 9.9495000000000005} 0.0001
+vremove cyl
+
+pcone cone 10 0 20
+vdisplay cone -dispmode 1
+vaxo
+vfit
+set center_cone [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cone should be detected" }
+checkpoint center_cone_p $center_cone {2.6384203410087546 -2.6384203410087546 12.537420341008755} 0.0001
+vtop
+vfit
+set top_cone [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cone should be detected" }
+checkpoint top_cone_p $top_cone {0 -0.050500000000000045 19.899000000000001} 0.0001
+vbottom
+set bottom_cone [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cone should be detected" }
+checkpoint bottom_cone_p $bottom_cone {0 0.050500000000000052 0} 0.0001
+vright
+vfit
+set right_cone [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cone should be detected" }
+checkpoint right_cone_p $right_cone {5.0252500000000007 0 9.9495000000000005} 0.0001
+vleft
+set left_cone [vmoveto 300 200]
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cone should be detected" }
+checkpoint left_cone_p $left_cone {-5.0252500000000007 0 9.9495000000000005} 0.0001
diff --git a/tests/vselect/cone_cylinder/detecting b/tests/vselect/cone_cylinder/detecting
new file mode 100644 (file)
index 0000000..0608ca6
--- /dev/null
@@ -0,0 +1,24 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests detecting Select3D_SensitiveCylinder"
+puts "================================="
+
+pcylinder cyl 10 20
+vdisplay cyl -dispmode 1
+vfit
+vmoveto 300 200
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cylinder should be detected" }
+vremove cyl
+
+pcone cone 10 0 20
+vdisplay cone -dispmode 1
+vfit
+vmoveto 300 200
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: cone should be detected" }
+vremove cone
+
+pcone tr_cone 10 5 10
+vdisplay tr_cone -dispmode 1
+vfit
+vmoveto 300 200
+if { ![string match "*Select3D_SensitiveCylinder*" [vstate -entities]] } { puts "Error: truncated cone should be detected" }
diff --git a/tests/vselect/cone_cylinder/generate_images b/tests/vselect/cone_cylinder/generate_images
new file mode 100644 (file)
index 0000000..5bc5d10
--- /dev/null
@@ -0,0 +1,33 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Generating images based on detection of Select3D_SensitiveCylinder"
+puts "================================="
+
+pcylinder cyl 10 20
+vdisplay cyl -dispmode 1
+vfit
+vseldump $imagedir/${casename}_cylinder_selmode_0.png  -type surfNormal
+vselmode 1 1
+vseldump $imagedir/${casename}_cylinder_selmode_1.png  -type surfNormal
+vselmode 4 1
+vseldump $imagedir/${casename}_cylinder_selmode_4.png  -type surfNormal
+vremove cyl
+
+pcone cone 10 0 20
+vdisplay cone -dispmode 1
+vfit
+vseldump $imagedir/${casename}_cone_selmode_0.png  -type surfNormal
+vselmode 1 1
+vseldump $imagedir/${casename}_cone_selmode_1.png  -type surfNormal
+vselmode 4 1
+vseldump $imagedir/${casename}_cone_selmode_4.png  -type surfNormal
+vremove cone
+
+pcone tr_cone 10 5 10
+vdisplay tr_cone -dispmode 1
+vfit
+vseldump $imagedir/${casename}_truncated_cone_selmode_0.png  -type surfNormal
+vselmode 1 1
+vseldump $imagedir/${casename}_truncated_cone_selmode_1.png  -type surfNormal
+vselmode 4 1
+vseldump $imagedir/${casename}_truncated_cone_selmode_4.png  -type surfNormal
diff --git a/tests/vselect/cone_cylinder/polygon_selection b/tests/vselect/cone_cylinder/polygon_selection
new file mode 100644 (file)
index 0000000..1f5ae6a
--- /dev/null
@@ -0,0 +1,69 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests polygon selection of Select3D_SensitiveCylinder"
+puts "================================="
+
+pcylinder c1 10 20
+pcone c2 10 0 20
+pcone c3 10 5 10
+ttranslate c1 25 25 0
+ttranslate c2 -25 25 0
+vdisplay -dispmode 1 c1 c2 c3
+vfit
+
+vselect 124 93 234 24 394 85 539 125 542 346 329 351 123 335
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 124 93 234 24 394 85 539 125 542 346 329 351 123 335 -allowoverlap
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 397 223 401 161 431 142 468 135 504 145 531 164 533 191 531 267 533 301 509 314 475 327 442 323 406 313 396 288
+if { ![string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cylinder c1 should be selected" }
+vselect 176 143 242 39 316 147 308 171 299 180 284 187 266 196 245 196 222 196 200 187 188 182 179 171 172 154
+if { [string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cone c2 should be selected" }
+vselect 179 272 217 214 242 207 271 216 279 223 282 233 311 274 311 287 303 304 283 315 247 323 221 321 196 314 184 304 177 292 172 279
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vtop
+vfit
+vselect 183 124 281 46 423 115 295 207 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]] } { puts "Error: all shapes should be unselected" }
+vselect 7 10 87 2 145 16 189 60 380 257 396 317 381 356 360 390 301 396 241 383 195 338 2 133 2 103 3 57
+if { [string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cones c2 and c3 should be selected" }
+vselect 410 142 465 149 445 205
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]] } { puts "Error: all shapes should be unselected" }
+vselect 410 142 465 149 445 205 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cylinder c1 should be selected" }
+vselect 261 306 297 275 325 320 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vright
+vfit
+vselect 0 332 65 198 201 198 269 331 260 358 15 350
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vselect 50 376 85 156 163 155 208 381 -allowoverlap 1 
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vselect 318 172 599 191 599 236 322 242 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: cylinder c1 and cone c2 should be selected" }
diff --git a/tests/vselect/cone_cylinder/rectangle_selection b/tests/vselect/cone_cylinder/rectangle_selection
new file mode 100644 (file)
index 0000000..6fa39a7
--- /dev/null
@@ -0,0 +1,96 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests rectangular selection of Select3D_SensitiveCylinder"
+puts "================================="
+
+pcylinder c1 10 20
+pcone c2 10 0 20
+pcone c3 10 5 10
+ttranslate c1 25 25 0
+ttranslate c2 -25 25 0
+vdisplay -dispmode 1 c1 c2 c3
+vfit
+vselect 15 15 585 385
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 15 15 585 385 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 314 52 565 347
+if { ![string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cylinder c1 should be selected" }
+vselect 314 52 565 347 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cylinder c1 should be selected" }
+vselect 304 52 565 347
+if { ![string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cylinder c1 should be selected" }
+vselect 304 52 565 347 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 274 77 282 92 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]] } { puts "Error: all shapes should be unselected" }
+vtop
+vfit
+vselect 90 90 510 310
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]] } { puts "Error: all shapes should be unselected" }
+vselect 90 90 510 310 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 480 60 540 120 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cylinder c1 should be selected" }
+vselect 60 60 120 120 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: only cone c2 should be selected" }
+vselect 270 270 330 330 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vselect 146 158 162 169 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be unselected" }
+vright
+vfit
+vselect 0 0 600 400
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 0 175 290 350
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vselect 310 20 600 360
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: cylinder c1 and cone c2 should be selected" }
+vselect 0 230 600 250 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: all shapes should be selected" }
+vselect 85 185 205 355 -allowoverlap 1
+if { [string match "*Selected*" [vstate c1]] ||
+     [string match "*Selected*" [vstate c2]] ||
+     ![string match "*Selected*" [vstate c3]]} { puts "Error: only cone c3 should be selected" }
+vselect 400 40 500 370 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: cylinder c1 and cone c2 should be selected" }
+vselect 425 160 500 250 -allowoverlap 1
+if { ![string match "*Selected*" [vstate c1]] ||
+     ![string match "*Selected*" [vstate c2]] ||
+     [string match "*Selected*" [vstate c3]]} { puts "Error: cylinder c1 and cone c2 should be selected" }
diff --git a/tests/vselect/cone_cylinder/single_click_selection_cone b/tests/vselect/cone_cylinder/single_click_selection_cone
new file mode 100644 (file)
index 0000000..9dc996b
--- /dev/null
@@ -0,0 +1,21 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests selection of Select3D_SensitiveCylinder"
+puts "================================="
+
+pcone cone 10 0 20
+vdisplay cone -dispmode 1
+vfit
+vselect 300 200
+if { ![string match "*Selected*" [vstate cone]] } { puts "Error: cone should be selected" }
+vselect 300 101
+if { ![string match "*Selected*" [vstate cone]] } { puts "Error: cone should be selected" }
+vselect 300 300
+if { ![string match "*Selected*" [vstate cone]] } { puts "Error: cone should be selected" }
+
+vselect 357 182
+if { [string match "*Selected*" [vstate cone]] } { puts "Error: cone should be unselected" }
+vselect 242 182
+if { [string match "*Selected*" [vstate cone]] } { puts "Error: cone should be unselected" }
+vselect 310 101
+if { [string match "*Selected*" [vstate cone]] } { puts "Error: cone should be unselected" }
diff --git a/tests/vselect/cone_cylinder/single_click_selection_cylinder b/tests/vselect/cone_cylinder/single_click_selection_cylinder
new file mode 100644 (file)
index 0000000..15148b8
--- /dev/null
@@ -0,0 +1,36 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests selection of Select3D_SensitiveCylinder"
+puts "================================="
+
+pcylinder cyl 10 20
+vdisplay cyl -dispmode 1
+vfit
+vselect 300 200
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vselect 300 100
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vselect 300 300
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+
+vselect 300 25
+if { [string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be unselected" }
+vselect 388 50
+if { [string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be unselected" }
+vselect 424 200
+if { [string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be unselected" }
+
+vselect 300 35
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vselect 420 95
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vselect 420 200
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vtop
+vfit
+vselect 300 200
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vselect 440 64
+if { ![string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be selected" }
+vselect 446 60
+if { [string match "*Selected*" [vstate cyl]] } { puts "Error: cylinder should be unselected" }
diff --git a/tests/vselect/cone_cylinder/single_click_selection_trunc_cone b/tests/vselect/cone_cylinder/single_click_selection_trunc_cone
new file mode 100644 (file)
index 0000000..315910e
--- /dev/null
@@ -0,0 +1,21 @@
+puts "================================="
+puts "0032281: Visualization - add Select3D_SensitiveCylinder"
+puts "Tests selection of Select3D_SensitiveCylinder"
+puts "================================="
+
+pcone tr_cone 10 5 10
+vdisplay tr_cone -dispmode 1
+vfit
+vselect 300 200
+if { ![string match "*Selected*" [vstate tr_cone]] } { puts "Error: truncated cone should be selected" }
+vselect 300 88
+if { ![string match "*Selected*" [vstate tr_cone]] } { puts "Error: truncated cone  should be selected" }
+vselect 421 187
+if { ![string match "*Selected*" [vstate tr_cone]] } { puts "Error: truncated cone  should be selected" }
+
+vselect 300 86
+if { [string match "*Selected*" [vstate tr_cone]] } { puts "Error: truncated cone  should be unselected" }
+vselect 378 120
+if { [string match "*Selected*" [vstate tr_cone]] } { puts "Error: truncated cone  should be unselected" }
+vselect 423 187
+if { [string match "*Selected*" [vstate tr_cone]] } { puts "Error: truncated cone  should be unselected" }
index 3442e0976fe1d8f97b31ae6e1442329fd4807224..fac69352716f6b2f4d376597824b058a60d9b0c1 100644 (file)
@@ -13,3 +13,4 @@
 013 wire_solid
 014 sphere
 015 axis
+016 cone_cylinder