1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

0028414: Data Exchange, STEP - Face on a closed surface with single inner wire and without natural bound not correctly read

Problem: From the point of view of the STEP format (and others), it is allowed
to describe a face on a surface with natural boundaries (torus, sphere) without
specifying these boundaries. Thus, a face on a closed surface and containing
an inner wire (or several) is correctly defined and describes a face with a
cutout defined by this wire. At the same time, there is a function
(ShapeFix_Face::FixOrientation) in the ShapeHealing procedure that corrects the
orientation of the wires, and it starts before the function of adding natural
boundaries (ShapeFix_Face::FixAddNaturalBound). There are many shapes that have
incorrectly oriented wires and this procedure successfully heals them, but on a
correctly specified face with single inner wire on closed surface, we do not get
the entire surface with a cutout, but a part of the surface defined by the wire.
This fix is intended to resolve this ambiguity.

Change:
1. Added function isNeedAddNaturalBound that returns TRUE if face needs to add
 natural bounds.
2. Corrected condition in FixOrientation to ignoring faces that needs to add
 natural bounds.
3. For tests in which one wire was incorrectly oriented on a closed surface,
flag AddNaturalBound was disabled.
5. Test with cutout from torus was created: bugs step bug28414.

Result: By default, it is correct to add natural boundaries, because this case
 is correct from the point of view of the STEP format and others.
This commit is contained in:
atereshi
2022-09-20 11:48:14 +03:00
committed by smoskvin
parent 492b09dcae
commit a453f9d128
21 changed files with 656 additions and 102 deletions

View File

@@ -647,11 +647,10 @@ Standard_Boolean ShapeFix_Face::Perform()
// fix natural bounds
Standard_Boolean NeedSplit = Standard_True;
if ( NeedFix ( myFixAddNaturalBoundMode ) ) {
if ( FixAddNaturalBound() ) {
NeedSplit = Standard_False;
myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
}
if (FixAddNaturalBound())
{
NeedSplit = Standard_False;
myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE5 );
}
// split face
@@ -840,9 +839,11 @@ Standard_Boolean ShapeFix_Face::FixAddNaturalBound()
return Standard_True;
}
// check if surface is double-closed and fix is needed
if ( !IsSurfaceUVPeriodic (mySurf->Adaptor3d()) || ShapeAnalysis::IsOuterBound (myFace) )
// check if surface doesn't need natural bounds
if (!isNeedAddNaturalBound(ws))
{
return Standard_False;
}
// Collect information on free intervals in U and V
TColgp_SequenceOfPnt2d intU, intV, centers;
@@ -1002,6 +1003,50 @@ Standard_Boolean ShapeFix_Face::FixOrientation()
return FixOrientation(MapWires);
}
//=======================================================================
// function : isNeedAddNaturalBound
// purpose :
//=======================================================================
Standard_Boolean ShapeFix_Face::isNeedAddNaturalBound(const TopTools_SequenceOfShape& theOrientedWires)
{
// if fix is not needed
if (!NeedFix (myFixAddNaturalBoundMode))
{
return Standard_False;
}
// if surface is not double-closed
if (!IsSurfaceUVPeriodic (mySurf->Adaptor3d()))
{
return Standard_False;
}
// if face has an OUTER bound
if (ShapeAnalysis::IsOuterBound (myFace))
{
return Standard_False;
}
// check that not any wire has a seam edge and not any edge is degenerated.
// because the presence of a seam or degenerated edge indicates that this wire should be an external one,
// and in case of its incorrect orientation, this will be corrected.
Standard_Integer aNbOriented = theOrientedWires.Length();
for (Standard_Integer i = 1; i <= aNbOriented; i++)
{
TopoDS_Wire aWire = TopoDS::Wire(theOrientedWires.Value(i));
for (TopoDS_Iterator anEdgeIt(aWire); anEdgeIt.More(); anEdgeIt.Next())
{
TopoDS_Edge anEdge = TopoDS::Edge(anEdgeIt.Value());
if (BRep_Tool::Degenerated(anEdge))
{
return Standard_False;
}
if (BRep_Tool::IsClosed(anEdge, myFace))
{
return Standard_False;
}
}
}
return Standard_True;
}
//=======================================================================
//function : FixOrientation
@@ -1071,9 +1116,8 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap
// if no wires, just do nothing
if ( nb <= 0) return Standard_False;
Standard_Integer nbInternal=0;
Standard_Boolean isAddNaturalBounds = (NeedFix (myFixAddNaturalBoundMode) && IsSurfaceUVPeriodic(mySurf->Adaptor3d()));
Standard_Boolean isAddNaturalBounds = isNeedAddNaturalBound(ws);
TColStd_SequenceOfInteger aSeqReversed;
// if wire is only one, check its orientation
if ( nb == 1 ) {
@@ -1084,9 +1128,7 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap
af.Orientation ( TopAbs_FORWARD );
B.Add (af,ws.Value(1));
if ((myFixAddNaturalBoundMode != 1 ||
!IsSurfaceUVPeriodic(mySurf->Adaptor3d())) &&
!ShapeAnalysis::IsOuterBound(af))
if (!isAddNaturalBounds && !ShapeAnalysis::IsOuterBound(af))
{
Handle(ShapeExtend_WireData) sbdw =
new ShapeExtend_WireData(TopoDS::Wire(ws.Value(1)));
@@ -1244,7 +1286,7 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap
if(!(stb==ste)) {
sta = TopAbs_UNKNOWN;
SI.Bind(aw,0);
j=nb;
j=nbAll;
break;
}
}
@@ -1363,11 +1405,9 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap
}
//done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
if(isAddNaturalBounds && nb == aSeqReversed.Length())
done = Standard_False;
else
done = (done && (nb ==1 || (isAddNaturalBounds || (!isAddNaturalBounds && nbInternal <nb))));
// Faut-il reconstruire ? si myRebil est mis
if ( done ) {
TopoDS_Shape S = myFace.EmptyCopied();