]> OCCT Git - occt.git/commitdiff
Visualization - Improve detection of full cylinder/cone parameters #830
authorKirill Gavrilov <kirill@sview.ru>
Mon, 24 Nov 2025 23:02:34 +0000 (23:02 +0000)
committerdpasukhi <dpasukhi@opencascade.com>
Mon, 24 Nov 2025 23:02:34 +0000 (23:02 +0000)
Parametric space of TopoDS_Face and ElSLib::ConeVIso() are now used for calculating parameters.
Scale factor is pre-applied.

src/Visualization/TKV3d/StdSelect/StdSelect_BRepSelectionTool.cxx

index 43096395cc12ef52b5bd4febc89389d84a929e18..9d819b401334ff23ae14643cf1df3f03ae2658f2 100644 (file)
@@ -22,6 +22,7 @@
 #include <BRepMesh_IncrementalMesh.hxx>
 #include <BRepTools.hxx>
 #include <BRepTools_WireExplorer.hxx>
+#include <ElSLib.hxx>
 #include <GCPnts_TangentialDeflection.hxx>
 #include <GeomAbs_SurfaceType.hxx>
 #include <Geom_ConicalSurface.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
+#include <TopoDS_Iterator.hxx>
 #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)
+// Check if face represents a full cylinder or cone surface
+// (single wire with 4 edges: 2 seam edges and 2 circular edges)
+static Standard_Boolean isCylinderOrCone(const TopoDS_Face& theFace)
 {
-  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
+  if (theFace.NbChildren() != 1)
+    return false;
+
+  const TopoDS_Iterator aWireIt(theFace);
+  const TopoDS_Shape&   aWire = aWireIt.Value();
+  if (aWire.ShapeType() != TopAbs_WIRE || aWire.NbChildren() != 4)
+    return false;
 
-  for (TopExp_Explorer anEdgeExp(theHollowCylinder, TopAbs_EDGE); anEdgeExp.More();
-       anEdgeExp.Next())
+  int aNbSeams = 0, aNbCirles = 0;
+  for (TopoDS_Iterator anEdgeIt(aWire); anEdgeIt.More(); anEdgeIt.Next())
   {
-    const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExp.Current());
-    BRepAdaptor_Curve  anAdaptor(anEdge);
-    aLinesNb++;
+    const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIt.Value());
+    if (BRep_Tool::IsClosed(anEdge, theFace))
+      ++aNbSeams;
 
-    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;
-    }
+    BRepAdaptor_Curve anAdaptor(anEdge);
+    if (anAdaptor.GetType() == GeomAbs_Circle)
+      ++aNbCirles;
   }
-
-  return aCircles;
+  return aNbSeams == 2 && aNbCirles == 2;
 }
 } // namespace
 
@@ -653,119 +643,127 @@ Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace(
   const Standard_Real    theMaxParam,
   const Standard_Boolean theInteriorFlag)
 {
-  TopLoc_Location aLoc;
-  if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(theFace, aLoc))
+  TopLoc_Location             aLocSurf;
+  const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFace, aLocSurf);
+  if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf))
   {
-    TopLoc_Location             aLocSurf;
-    const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFace, aLocSurf);
-    if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf))
+    bool isFullSphere = theFace.NbChildren() == 0;
+    if (theFace.NbChildren() == 1)
     {
-      bool isFullSphere = theFace.NbChildren() == 0;
-      if (theFace.NbChildren() == 1)
+      const TopoDS_Iterator aWireIter(theFace);
+      const TopoDS_Wire&    aWire = TopoDS::Wire(aWireIter.Value());
+      if (aWire.NbChildren() == 4)
       {
-        const TopoDS_Iterator aWireIter(theFace);
-        const TopoDS_Wire&    aWire = TopoDS::Wire(aWireIter.Value());
-        if (aWire.NbChildren() == 4)
+        Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0;
+        for (TopoDS_Iterator anEdgeIter(aWire); anEdgeIter.More(); anEdgeIter.Next())
         {
-          Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0;
-          for (TopoDS_Iterator anEdgeIter(aWire); anEdgeIter.More(); anEdgeIter.Next())
-          {
-            const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIter.Value());
-            aNbSeamEdges += BRep_Tool::IsClosed(anEdge, theFace);
-            aNbDegenEdges += BRep_Tool::Degenerated(anEdge);
-          }
-          isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2;
+          const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIter.Value());
+          aNbSeamEdges += BRep_Tool::IsClosed(anEdge, theFace);
+          aNbDegenEdges += BRep_Tool::Degenerated(anEdge);
         }
-      }
-      if (isFullSphere)
-      {
-        gp_Sphere                        aSphere = BRepAdaptor_Surface(theFace).Sphere();
-        Handle(Select3D_SensitiveSphere) aSensSphere =
-          new Select3D_SensitiveSphere(theOwner,
-                                       aSphere.Position().Axis().Location(),
-                                       aSphere.Radius());
-        theSensitiveList.Append(aSensSphere);
-        return Standard_True;
+        isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2;
       }
     }
-    else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast(aSurf))
+    if (isFullSphere)
     {
-      Standard_Size                aNumCircles;
-      const std::array<gp_Circ, 2> aCircles = getCylinderCircles(theFace, aNumCircles);
-
-      if (aNumCircles > 0 && aNumCircles < 3)
-      {
-        const gp_Cone aCone = BRepAdaptor_Surface(theFace).Cone();
-
-        gp_Trsf       aTrsf;
-        Standard_Real aRad1, aRad2, aHeight;
-        if (aNumCircles == 1)
-        {
-          aRad1   = 0.0;
-          aRad2   = aCircles[0].Radius();
-          aHeight = aRad2 * std::tan(aCone.SemiAngle());
-          aTrsf.SetTransformation(aCone.Position(), gp::XOY());
-        }
-        else
-        {
-          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());
-        }
+      gp_Sphere                        aSphere = BRepAdaptor_Surface(theFace).Sphere();
+      Handle(Select3D_SensitiveSphere) aSensSphere =
+        new Select3D_SensitiveSphere(theOwner,
+                                     aSphere.Position().Axis().Location(),
+                                     aSphere.Radius());
+      theSensitiveList.Append(aSensSphere);
+      return Standard_True;
+    }
+  }
+  else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast(aSurf))
+  {
+    if (isCylinderOrCone(theFace))
+    {
+      double aURange[2] = {}, aVRange[2] = {};
+      BRepTools::UVBounds(theFace, aURange[0], aURange[1], aVRange[0], aVRange[1]);
+
+      const gp_Circ aCirc1  = ElSLib::ConeVIso(aGeomCone->Position(),
+                                              aGeomCone->RefRadius(),
+                                              aGeomCone->SemiAngle(),
+                                              aVRange[0]);
+      const gp_Circ aCirc2  = ElSLib::ConeVIso(aGeomCone->Position(),
+                                              aGeomCone->RefRadius(),
+                                              aGeomCone->SemiAngle(),
+                                              aVRange[1]);
+      const double  aHeight = aCirc1.Location().Distance(aCirc2.Location());
+
+      gp_Ax3 aPos = aGeomCone->Position();
+      aPos.SetLocation(aCirc1.Location());
+      gp_Trsf aLocTrsf;
+      aLocTrsf.SetTransformation(aPos, gp::XOY());
+
+      gp_Trsf      aTrsf  = aLocSurf * aLocTrsf;
+      const double aScale = aTrsf.ScaleFactor();
+      aTrsf.SetScaleFactor(1.0);
 
-        Handle(Select3D_SensitiveCylinder) aSensSCyl =
-          new Select3D_SensitiveCylinder(theOwner, aRad1, aRad2, aHeight, aTrsf, true);
-        theSensitiveList.Append(aSensSCyl);
-        return Standard_True;
-      }
+      Handle(Select3D_SensitiveCylinder) aSensSCyl =
+        new Select3D_SensitiveCylinder(theOwner,
+                                       aCirc1.Radius() * aScale,
+                                       aCirc2.Radius() * aScale,
+                                       aHeight * aScale,
+                                       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))
+  {
+    if (isCylinderOrCone(theFace))
     {
-      Standard_Size                aNumCircles;
-      const std::array<gp_Circ, 2> aCircles = getCylinderCircles(theFace, aNumCircles);
+      double aURange[2] = {}, aVRange[2] = {};
+      BRepTools::UVBounds(theFace, aURange[0], aURange[1], aVRange[0], aVRange[1]);
 
-      if (aNumCircles == 2)
-      {
-        const gp_Cylinder aCyl = BRepAdaptor_Surface(theFace).Cylinder();
+      const double aRad    = aGeomCyl->Radius();
+      const double aHeight = aVRange[1] - aVRange[0];
 
-        const Standard_Real aRad = aCyl.Radius();
-        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_Ax3 aPos = aGeomCyl->Position();
+      aPos.SetLocation(aGeomCyl->Location().XYZ() + aPos.Direction().XYZ() * aVRange[0]);
+      gp_Trsf aLocTrsf;
+      aLocTrsf.SetTransformation(aPos, gp::XOY());
 
-        gp_Trsf aTrsf;
-        aTrsf.SetTransformation(gp_Ax3(aPos, aDirection), gp::XOY());
+      gp_Trsf      aTrsf  = aLocSurf * aLocTrsf;
+      const double aScale = aTrsf.ScaleFactor();
+      aTrsf.SetScaleFactor(1.0);
 
-        Handle(Select3D_SensitiveCylinder) aSensSCyl =
-          new Select3D_SensitiveCylinder(theOwner, aRad, aRad, aHeight, aTrsf, true);
-        theSensitiveList.Append(aSensSCyl);
-        return Standard_True;
-      }
+      Handle(Select3D_SensitiveCylinder) aSensSCyl =
+        new Select3D_SensitiveCylinder(theOwner,
+                                       aRad * aScale,
+                                       aRad * aScale,
+                                       aHeight * aScale,
+                                       aTrsf,
+                                       true);
+      theSensitiveList.Append(aSensSCyl);
+      return Standard_True;
     }
-    else if (Handle(Geom_Plane) aGeomPlane = Handle(Geom_Plane)::DownCast(aSurf))
+  }
+  else if (Handle(Geom_Plane) aGeomPlane = Handle(Geom_Plane)::DownCast(aSurf))
+  {
+    TopTools_IndexedMapOfShape aSubfacesMap;
+    TopExp::MapShapes(theFace, TopAbs_EDGE, aSubfacesMap);
+    if (aSubfacesMap.Extent() == 1)
     {
-      TopTools_IndexedMapOfShape aSubfacesMap;
-      TopExp::MapShapes(theFace, TopAbs_EDGE, aSubfacesMap);
-      if (aSubfacesMap.Extent() == 1)
+      const TopoDS_Edge& anEdge = TopoDS::Edge(aSubfacesMap.FindKey(1));
+      BRepAdaptor_Curve  anAdaptor(anEdge);
+      if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge))
       {
-        const TopoDS_Edge& anEdge = TopoDS::Edge(aSubfacesMap.FindKey(1));
-        BRepAdaptor_Curve  anAdaptor(anEdge);
-        if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge))
-        {
-          Handle(Select3D_SensitiveCircle) aSensSCyl =
-            new Select3D_SensitiveCircle(theOwner, anAdaptor.Circle(), theInteriorFlag);
-          theSensitiveList.Append(aSensSCyl);
-          return Standard_True;
-        }
+        Handle(Select3D_SensitiveCircle) aSensSCyl =
+          new Select3D_SensitiveCircle(theOwner, anAdaptor.Circle(), theInteriorFlag);
+        theSensitiveList.Append(aSensSCyl);
+        return Standard_True;
       }
     }
+  }
 
+  TopLoc_Location aLoc;
+  if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(theFace, aLoc))
+  {
     Handle(Select3D_SensitiveTriangulation) STG =
       new Select3D_SensitiveTriangulation(theOwner, aTriangulation, aLoc, theInteriorFlag);
     theSensitiveList.Append(STG);