Visualization - Improve detection of full cylinder/cone parameters #830

Parametric space of TopoDS_Face and ElSLib::ConeVIso() are now used for calculating parameters.
Scale factor is pre-applied.
This commit is contained in:
Kirill Gavrilov
2025-11-24 23:02:34 +00:00
committed by dpasukhi
parent 6730c842bd
commit c64a167a96

View File

@@ -22,6 +22,7 @@
#include <BRepMesh_IncrementalMesh.hxx> #include <BRepMesh_IncrementalMesh.hxx>
#include <BRepTools.hxx> #include <BRepTools.hxx>
#include <BRepTools_WireExplorer.hxx> #include <BRepTools_WireExplorer.hxx>
#include <ElSLib.hxx>
#include <GCPnts_TangentialDeflection.hxx> #include <GCPnts_TangentialDeflection.hxx>
#include <GeomAbs_SurfaceType.hxx> #include <GeomAbs_SurfaceType.hxx>
#include <Geom_ConicalSurface.hxx> #include <Geom_ConicalSurface.hxx>
@@ -58,51 +59,40 @@
#include <TopExp.hxx> #include <TopExp.hxx>
#include <TopExp_Explorer.hxx> #include <TopExp_Explorer.hxx>
#include <TopoDS.hxx> #include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx> #include <TopoDS_Face.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx> #include <TopoDS_Shape.hxx>
#include <TopoDS_Wire.hxx> #include <TopoDS_Wire.hxx>
#include <array>
#define BVH_PRIMITIVE_LIMIT 800000 #define BVH_PRIMITIVE_LIMIT 800000
namespace namespace
{ {
//======================================================================= // Check if face represents a full cylinder or cone surface
// function : getCylinderCircles // (single wire with 4 edges: 2 seam edges and 2 circular edges)
// purpose : Extracts up to two circular edges from a hollow cylinder face static Standard_Boolean isCylinderOrCone(const TopoDS_Face& theFace)
//=======================================================================
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 if (theFace.NbChildren() != 1)
theNumCircles = 0; // Initialize the number of circles found return false;
Standard_Integer aLinesNb = 0; // Counter for the number of edges processed
for (TopExp_Explorer anEdgeExp(theHollowCylinder, TopAbs_EDGE); anEdgeExp.More(); const TopoDS_Iterator aWireIt(theFace);
anEdgeExp.Next()) const TopoDS_Shape& aWire = aWireIt.Value();
if (aWire.ShapeType() != TopAbs_WIRE || aWire.NbChildren() != 4)
return false;
int aNbSeams = 0, aNbCirles = 0;
for (TopoDS_Iterator anEdgeIt(aWire); anEdgeIt.More(); anEdgeIt.Next())
{ {
const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExp.Current()); const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIt.Value());
BRepAdaptor_Curve anAdaptor(anEdge); if (BRep_Tool::IsClosed(anEdge, theFace))
aLinesNb++; ++aNbSeams;
if (anAdaptor.GetType() == GeomAbs_Circle && BRep_Tool::IsClosed(anEdge)) BRepAdaptor_Curve anAdaptor(anEdge);
{ if (anAdaptor.GetType() == GeomAbs_Circle)
theNumCircles++; ++aNbCirles;
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 aNbSeams == 2 && aNbCirles == 2;
return aCircles;
} }
} // namespace } // namespace
@@ -653,119 +643,127 @@ Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace(
const Standard_Real theMaxParam, const Standard_Real theMaxParam,
const Standard_Boolean theInteriorFlag) const Standard_Boolean theInteriorFlag)
{ {
TopLoc_Location aLocSurf;
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFace, aLocSurf);
if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf))
{
bool isFullSphere = theFace.NbChildren() == 0;
if (theFace.NbChildren() == 1)
{
const TopoDS_Iterator aWireIter(theFace);
const TopoDS_Wire& aWire = TopoDS::Wire(aWireIter.Value());
if (aWire.NbChildren() == 4)
{
Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0;
for (TopoDS_Iterator anEdgeIter(aWire); anEdgeIter.More(); anEdgeIter.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIter.Value());
aNbSeamEdges += BRep_Tool::IsClosed(anEdge, theFace);
aNbDegenEdges += BRep_Tool::Degenerated(anEdge);
}
isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2;
}
}
if (isFullSphere)
{
gp_Sphere aSphere = BRepAdaptor_Surface(theFace).Sphere();
Handle(Select3D_SensitiveSphere) aSensSphere =
new Select3D_SensitiveSphere(theOwner,
aSphere.Position().Axis().Location(),
aSphere.Radius());
theSensitiveList.Append(aSensSphere);
return Standard_True;
}
}
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,
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))
{
if (isCylinderOrCone(theFace))
{
double aURange[2] = {}, aVRange[2] = {};
BRepTools::UVBounds(theFace, aURange[0], aURange[1], aVRange[0], aVRange[1]);
const double aRad = aGeomCyl->Radius();
const double aHeight = aVRange[1] - aVRange[0];
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 = aLocSurf * aLocTrsf;
const double aScale = aTrsf.ScaleFactor();
aTrsf.SetScaleFactor(1.0);
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))
{
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))
{
Handle(Select3D_SensitiveCircle) aSensSCyl =
new Select3D_SensitiveCircle(theOwner, anAdaptor.Circle(), theInteriorFlag);
theSensitiveList.Append(aSensSCyl);
return Standard_True;
}
}
}
TopLoc_Location aLoc; TopLoc_Location aLoc;
if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(theFace, aLoc)) if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(theFace, aLoc))
{ {
TopLoc_Location aLocSurf;
const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(theFace, aLocSurf);
if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast(aSurf))
{
bool isFullSphere = theFace.NbChildren() == 0;
if (theFace.NbChildren() == 1)
{
const TopoDS_Iterator aWireIter(theFace);
const TopoDS_Wire& aWire = TopoDS::Wire(aWireIter.Value());
if (aWire.NbChildren() == 4)
{
Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0;
for (TopoDS_Iterator anEdgeIter(aWire); anEdgeIter.More(); anEdgeIter.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeIter.Value());
aNbSeamEdges += BRep_Tool::IsClosed(anEdge, theFace);
aNbDegenEdges += BRep_Tool::Degenerated(anEdge);
}
isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2;
}
}
if (isFullSphere)
{
gp_Sphere aSphere = BRepAdaptor_Surface(theFace).Sphere();
Handle(Select3D_SensitiveSphere) aSensSphere =
new Select3D_SensitiveSphere(theOwner,
aSphere.Position().Axis().Location(),
aSphere.Radius());
theSensitiveList.Append(aSensSphere);
return Standard_True;
}
}
else if (Handle(Geom_ConicalSurface) aGeomCone = Handle(Geom_ConicalSurface)::DownCast(aSurf))
{
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());
}
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))
{
Standard_Size aNumCircles;
const std::array<gp_Circ, 2> aCircles = getCylinderCircles(theFace, aNumCircles);
if (aNumCircles == 2)
{
const gp_Cylinder aCyl = BRepAdaptor_Surface(theFace).Cylinder();
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_Trsf aTrsf;
aTrsf.SetTransformation(gp_Ax3(aPos, aDirection), gp::XOY());
Handle(Select3D_SensitiveCylinder) aSensSCyl =
new Select3D_SensitiveCylinder(theOwner, aRad, aRad, aHeight, aTrsf, true);
theSensitiveList.Append(aSensSCyl);
return Standard_True;
}
}
else if (Handle(Geom_Plane) aGeomPlane = Handle(Geom_Plane)::DownCast(aSurf))
{
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))
{
Handle(Select3D_SensitiveCircle) aSensSCyl =
new Select3D_SensitiveCircle(theOwner, anAdaptor.Circle(), theInteriorFlag);
theSensitiveList.Append(aSensSCyl);
return Standard_True;
}
}
}
Handle(Select3D_SensitiveTriangulation) STG = Handle(Select3D_SensitiveTriangulation) STG =
new Select3D_SensitiveTriangulation(theOwner, aTriangulation, aLoc, theInteriorFlag); new Select3D_SensitiveTriangulation(theOwner, aTriangulation, aLoc, theInteriorFlag);
theSensitiveList.Append(STG); theSensitiveList.Append(STG);