]> OCCT Git - occt.git/commitdiff
Visualization - Selection does not work for simple shape #182
authormzernova <mzernova@opencascade.com>
Thu, 18 Jul 2024 23:16:11 +0000 (00:16 +0100)
committerdpasukhi <dpasukhi@opencascade.com>
Fri, 6 Dec 2024 14:40:35 +0000 (14:40 +0000)
Fixed direction calculation for Select3D_SensitiveCylinder created from Geom_CylindricalSurface

src/StdSelect/StdSelect_BRepSelectionTool.cxx
tests/v3d/bugs/bug33664_1 [new file with mode: 0644]
tests/v3d/bugs/bug33664_2 [new file with mode: 0644]

index 07b5a96543ffe528a78104206805823dd05f2094..11239478816488f0cec5981e78e6eec04a21013f 100644 (file)
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Wire.hxx>
 
+#include <array>
+
 #define BVH_PRIMITIVE_LIMIT 800000
 
+namespace
+{
+  //=======================================================================
+  //function : getCylinderCircles
+  //purpose  : Extracts up to two circular edges from a hollow cylinder face
+  //=======================================================================
+  std::array<gp_Circ, 2> getCylinderCircles(const TopoDS_Face& theHollowCylinder, Standard_Size& theNumCircles)
+  {
+    std::array<gp_Circ, 2> aCircles; // Array to store up to two circles
+    theNumCircles             = 0;   // Initialize the number of circles found
+    Standard_Integer aLinesNb = 0;   // Counter for the number of edges processed
+
+    for (TopExp_Explorer anEdgeExp(theHollowCylinder, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next())
+    {
+      const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExp.Current());
+      BRepAdaptor_Curve  anAdaptor(anEdge);
+      aLinesNb++;
+
+      if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge))
+      {
+        theNumCircles++;
+        aCircles[theNumCircles - 1] = anAdaptor.Circle();
+      }
+      else if (anAdaptor.GetType() != GeomAbs_Line || aLinesNb > 4)
+      {
+        theNumCircles = 0;
+        return std::array<gp_Circ, 2>();
+      }
+      if (theNumCircles == 2)
+      {
+        break;
+      }
+    }
+
+    return aCircles;
+  }
+}
+
 //==================================================
 // function: PreBuildBVH
 // purpose : Pre-builds BVH tree for heavyweight
@@ -561,57 +601,6 @@ void StdSelect_BRepSelectionTool::GetEdgeSensitive (const TopoDS_Shape& theShape
   }
 }
 
-//=======================================================================
-//function : getCylinderHeight
-//purpose  :
-//=======================================================================
-static Standard_Real getCylinderHeight (const Handle(Poly_Triangulation)& theTriangulation,
-                                        const TopLoc_Location& theLoc)
-{
-  Bnd_Box aBox;
-  gp_Trsf aScaleTrsf;
-  aScaleTrsf.SetScaleFactor (theLoc.Transformation().ScaleFactor());
-  theTriangulation->MinMax (aBox, aScaleTrsf);
-  return aBox.CornerMax().Z() - aBox.CornerMin().Z();
-}
-
-//=======================================================================
-//function : isCylinderOrCone
-//purpose  :
-//=======================================================================
-static Standard_Boolean isCylinderOrCone (const TopoDS_Face& theHollowCylinder, const gp_Pnt& theLocation, gp_Dir& theDirection)
-{
-  Standard_Integer aCirclesNb = 0;
-  Standard_Boolean isCylinder = Standard_False;
-  gp_Pnt aPos;
-
-  TopExp_Explorer anEdgeExp;
-  for (anEdgeExp.Init (theHollowCylinder, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next())
-  {
-    const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeExp.Current());
-    BRepAdaptor_Curve anAdaptor (anEdge);
-
-    if (anAdaptor.GetType() == GeomAbs_Circle
-     && BRep_Tool::IsClosed (anEdge))
-    {
-      aCirclesNb++;
-      isCylinder = Standard_True;
-      if (aCirclesNb == 2)
-      {
-        // Reverse the direction of the cylinder, relevant if the cylinder was created as a prism
-        if (aPos.IsEqual (theLocation, Precision::Confusion()))
-        {
-          theDirection.Reverse();
-        }
-        return Standard_True;
-      }
-      aPos = anAdaptor.Circle().Location().XYZ();
-    }
-  }
-
-  return isCylinder;
-}
-
 //=======================================================================
 //function : GetSensitiveEntityForFace
 //purpose  :
@@ -656,55 +645,62 @@ Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace (const TopoDS_
         return Standard_True;
       }
     }
-    else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast (aSurf))
+    else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast(aSurf))
     {
-      gp_Dir aDummyDir;
-      if (isCylinderOrCone (theFace, gp_Pnt(), aDummyDir))
-      {
-        const gp_Cone aCone = BRepAdaptor_Surface (theFace).Cone();
-        const Standard_Real aRad1 = aCone.RefRadius();
-        const Standard_Real aHeight = getCylinderHeight (aTriangulation, aLoc);
+      Standard_Size                aNumCircles;
+      const std::array<gp_Circ, 2> aCircles = getCylinderCircles(theFace, aNumCircles);
 
-        gp_Trsf aTrsf;
-        aTrsf.SetTransformation (aCone.Position(), gp::XOY());
+      if (aNumCircles > 0 && aNumCircles < 3)
+      {
+        const gp_Cone aCone = BRepAdaptor_Surface(theFace).Cone();
 
-        Standard_Real aRad2;
-        if (aRad1 == 0.0)
+        gp_Trsf       aTrsf;
+        Standard_Real aRad1, aRad2, aHeight;
+        if (aNumCircles == 1)
         {
-          aRad2 = Tan (aCone.SemiAngle()) * aHeight;
+          aRad1   = 0.0;
+          aRad2   = aCircles[0].Radius();
+          aHeight = aRad2 * Tan(aCone.SemiAngle());
+          aTrsf.SetTransformation(aCone.Position(), gp::XOY());
         }
         else
         {
-          const Standard_Real aTriangleHeight = (aCone.SemiAngle() > 0.0)
-            ? aRad1 / Tan (aCone.SemiAngle())
-            : aRad1 / Tan (Abs (aCone.SemiAngle())) - aHeight;
-          aRad2 = (aCone.SemiAngle() > 0.0)
-            ? aRad1 * (aTriangleHeight + aHeight) / aTriangleHeight
-            : aRad1 * aTriangleHeight / (aTriangleHeight + aHeight);
+          aRad1             = aCircles[0].Radius();
+          aRad2             = aCircles[1].Radius();
+          aHeight           = aCircles[0].Location().Distance(aCircles[1].Location());
+
+          const gp_Pnt aPos = aCircles[0].Location();
+          const gp_Dir aDirection(aCircles[1].Location().XYZ() - aPos.XYZ());
+
+          aTrsf.SetTransformation(gp_Ax3(aPos, aDirection), gp::XOY());
         }
 
-        Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad1, aRad2, aHeight, aTrsf, true);
-        theSensitiveList.Append (aSensSCyl);
+        Handle(Select3D_SensitiveCylinder) aSensSCyl =
+          new Select3D_SensitiveCylinder(theOwner, aRad1, aRad2, aHeight, aTrsf, true);
+        theSensitiveList.Append(aSensSCyl);
         return Standard_True;
       }
     }
-    else if (Handle(Geom_CylindricalSurface) aGeomCyl = Handle(Geom_CylindricalSurface)::DownCast (aSurf))
+    else if (Handle(Geom_CylindricalSurface) aGeomCyl = Handle(Geom_CylindricalSurface)::DownCast(aSurf))
     {
-      const gp_Cylinder aCyl = BRepAdaptor_Surface (theFace).Cylinder();
-      gp_Ax3 aPos = aCyl.Position();
-      gp_Dir aDirection = aPos.Direction();
+      Standard_Size                aNumCircles;
+      const std::array<gp_Circ, 2> aCircles = getCylinderCircles(theFace, aNumCircles);
 
-      if (isCylinderOrCone (theFace, aPos.Location(), aDirection))
+      if (aNumCircles == 2)
       {
+        const gp_Cylinder aCyl   = BRepAdaptor_Surface(theFace).Cylinder();
+
         const Standard_Real aRad = aCyl.Radius();
-        const Standard_Real aHeight = getCylinderHeight (aTriangulation, aLoc);
+        const gp_Pnt        aPos = aCircles[0].Location();
+        const gp_Dir        aDirection(aCircles[1].Location().XYZ() - aPos.XYZ());
+        const Standard_Real aHeight = aPos.Distance(aCircles[1].Location());
 
         gp_Trsf aTrsf;
-        aPos.SetDirection (aDirection);
-        aTrsf.SetTransformation (aPos, gp::XOY());
+        aTrsf.SetTransformation(gp_Ax3(aPos, aDirection), gp::XOY());
 
-        Handle(Select3D_SensitiveCylinder) aSensSCyl = new Select3D_SensitiveCylinder (theOwner, aRad, aRad, aHeight, aTrsf, true);
-        theSensitiveList.Append (aSensSCyl);
+        Handle(Select3D_SensitiveCylinder) aSensSCyl =
+          new Select3D_SensitiveCylinder(theOwner, aRad, aRad, aHeight, aTrsf, true);
+        theSensitiveList.Append(aSensSCyl);
         return Standard_True;
       }
     }
diff --git a/tests/v3d/bugs/bug33664_1 b/tests/v3d/bugs/bug33664_1
new file mode 100644 (file)
index 0000000..445cc69
--- /dev/null
@@ -0,0 +1,21 @@
+puts "============"
+puts "0033664: Visualization - Selection does not work for simple shape"
+puts "============"
+puts ""
+
+pload MODELING VISUALIZATION
+vclear
+vinit View1
+
+restore [locate_data_file cylinder_surface.brep] b
+vdisplay -dispMode 1 b
+vfit
+vsensdis
+
+vselect 200 200
+if {[vnbselected] != "1"} {
+  puts "ERROR: wrong sensitive area"
+}
+
+vselect 0 0
+vdump $::imagedir/${::casename}_cylinder.png
diff --git a/tests/v3d/bugs/bug33664_2 b/tests/v3d/bugs/bug33664_2
new file mode 100644 (file)
index 0000000..ed1cbf6
--- /dev/null
@@ -0,0 +1,36 @@
+puts "============"
+puts "0033664: Visualization - Selection does not work for simple shape"
+puts "============"
+puts ""
+
+pload MODELING VISUALIZATION
+vclear
+vinit View1
+
+pcone c1 50 100 100
+ttranslate c1 100 0 100
+explode c1
+explode c1_1
+
+pcone c2 100 50 100
+ttranslate c2 -100 0 100
+explode c2
+explode c2_1
+
+pcone c3 0 100 100
+ttranslate c3 100 0 -100
+explode c3
+explode c3_1
+
+pcone c4 100 0 100
+ttranslate c4 -100 0 -100
+explode c4
+explode c4_1
+
+vdisplay c1_1_1 c2_1_1 c3_1_1 c4_1_1 -dispmode 1
+vsensdis
+
+vfront
+vfit
+
+vdump $::imagedir/${::casename}_cone.png