From d5afabec90fcc1e25d217ea6386ccc3d8e15488c Mon Sep 17 00:00:00 2001 From: mzernova Date: Fri, 19 Jul 2024 00:16:11 +0100 Subject: [PATCH] Visualization - Selection does not work for simple shape #182 Fixed direction calculation for Select3D_SensitiveCylinder created from Geom_CylindricalSurface --- src/StdSelect/StdSelect_BRepSelectionTool.cxx | 158 +++++++++--------- tests/v3d/bugs/bug33664_1 | 21 +++ tests/v3d/bugs/bug33664_2 | 36 ++++ 3 files changed, 134 insertions(+), 81 deletions(-) create mode 100644 tests/v3d/bugs/bug33664_1 create mode 100644 tests/v3d/bugs/bug33664_2 diff --git a/src/StdSelect/StdSelect_BRepSelectionTool.cxx b/src/StdSelect/StdSelect_BRepSelectionTool.cxx index 07b5a96543..1123947881 100644 --- a/src/StdSelect/StdSelect_BRepSelectionTool.cxx +++ b/src/StdSelect/StdSelect_BRepSelectionTool.cxx @@ -62,8 +62,48 @@ #include #include +#include + #define BVH_PRIMITIVE_LIMIT 800000 +namespace +{ + //======================================================================= + //function : getCylinderCircles + //purpose : Extracts up to two circular edges from a hollow cylinder face + //======================================================================= + std::array getCylinderCircles(const TopoDS_Face& theHollowCylinder, Standard_Size& theNumCircles) + { + std::array 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(); + } + 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 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 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 index 0000000000..445cc692f7 --- /dev/null +++ b/tests/v3d/bugs/bug33664_1 @@ -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 index 0000000000..ed1cbf622a --- /dev/null +++ b/tests/v3d/bugs/bug33664_2 @@ -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