Skip to content

Commit

Permalink
Visualization - Selection does not work for simple shape #182
Browse files Browse the repository at this point in the history
Fixed direction calculation for Select3D_SensitiveCylinder created from Geom_CylindricalSurface
  • Loading branch information
mzernova authored and dpasukhi committed Dec 6, 2024
1 parent 875660a commit d5afabe
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 81 deletions.
158 changes: 77 additions & 81 deletions src/StdSelect/StdSelect_BRepSelectionTool.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,48 @@
#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
Expand Down Expand Up @@ -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 :
Expand Down Expand Up @@ -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;
}
}
Expand Down
21 changes: 21 additions & 0 deletions tests/v3d/bugs/bug33664_1
Original file line number Diff line number Diff line change
@@ -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
36 changes: 36 additions & 0 deletions tests/v3d/bugs/bug33664_2
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit d5afabe

Please sign in to comment.