mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-19 13:40:49 +03:00
0025923: Remove small wires on face read from STEP
The analysis of small area in the method ShapeAnalysis_Wire::CheckSmallArea is performed the following way: - On the fisrt step algorithm produces a rough estimation of part of surface area. - In a case if obtained estimation is less than tolerance then evaluate real area and comapre this value with tolerance. - New flag has been added to XSTEPResource/IGES. In a case if flag is true the faces with small 3d area is removed from ShapeFix context. Test-case for issue #25923 and update test-cases in de group according to the new behavior.
This commit is contained in:
@@ -490,9 +490,9 @@ is
|
||||
Tolerance: Real = 0.0) returns Boolean;
|
||||
---Purpose: Detects a notch
|
||||
|
||||
CheckSmallArea (me: mutable; prec2d : Real = 0)
|
||||
CheckSmallArea (me: mutable; theWire : Wire from TopoDS; theIsOuterWire : Boolean)
|
||||
returns Boolean;
|
||||
---Purpose: Checks if wire has parametric area less than prec2d.
|
||||
---Purpose: Checks if wire has parametric area less than precision.
|
||||
|
||||
CheckShapeConnect (me : mutable; shape : Shape from TopoDS; prec: Real = 0.0)
|
||||
returns Boolean;
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <GeomAdaptor_HSurface.hxx>
|
||||
#include <Geom2dAdaptor_Curve.hxx>
|
||||
#include <Geom2dInt_GInter.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <IntRes2d_Domain.hxx>
|
||||
#include <IntRes2d_Transition.hxx>
|
||||
#include <IntRes2d_IntersectionPoint.hxx>
|
||||
@@ -48,9 +49,11 @@
|
||||
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
|
||||
#include <ShapeExtend.hxx>
|
||||
#include <ShapeAnalysis.hxx>
|
||||
@@ -1705,46 +1708,103 @@ Standard_Boolean ShapeAnalysis_Wire::CheckNotchedEdges(const Standard_Integer nu
|
||||
//function : CheckSmallArea
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
Standard_Boolean ShapeAnalysis_Wire::CheckSmallArea(const Standard_Real prec2d)
|
||||
Standard_Boolean ShapeAnalysis_Wire::CheckSmallArea(const TopoDS_Wire& theWire,
|
||||
const Standard_Boolean theIsOuterWire)
|
||||
{
|
||||
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL1);
|
||||
Standard_Integer NbEdges = myWire->NbEdges();
|
||||
if ( !IsReady() || NbEdges <1 ) return Standard_False;
|
||||
const Standard_Integer aNbControl = 23;
|
||||
const Standard_Integer NbEdges = myWire->NbEdges();
|
||||
if ( !IsReady() || NbEdges < 1 )
|
||||
return Standard_False;
|
||||
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_OK);
|
||||
|
||||
Standard_Integer NbControl=23;
|
||||
Standard_Real area=0;
|
||||
gp_XY prev, cont;
|
||||
for (Standard_Integer nbe = 1; nbe <= NbEdges; nbe++) {
|
||||
Standard_Real First, Last;
|
||||
Handle(Geom2d_Curve) c2d;
|
||||
ShapeAnalysis_Edge sae;
|
||||
if (!sae.PCurve(myWire->Edge(nbe),myFace,c2d,First,Last)) {
|
||||
|
||||
Standard_Real aF, aL, aLength(0.0);
|
||||
const Standard_Real anInv = 1.0 / static_cast<Standard_Real>(aNbControl - 1);
|
||||
gp_XY aCenter2d(0., 0.);
|
||||
|
||||
// try to find mid point for closed contour
|
||||
Handle(Geom2d_Curve) aCurve2d;
|
||||
for (Standard_Integer j = 1; j <= NbEdges; ++j)
|
||||
{
|
||||
const ShapeAnalysis_Edge anAnalyzer;
|
||||
if (!anAnalyzer.PCurve(myWire->Edge(j),myFace,aCurve2d,aF,aL))
|
||||
{
|
||||
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_Integer ibeg = 0;
|
||||
if( nbe == 1 ) {
|
||||
gp_Pnt2d pntIni = c2d->Value(First);
|
||||
prev = pntIni.XY();
|
||||
cont = prev;
|
||||
ibeg = 1;
|
||||
}
|
||||
for ( Standard_Integer i = ibeg; i < NbControl; i++) {
|
||||
Standard_Real prm = ((NbControl-1-i)*First + i*Last)/(NbControl-1);
|
||||
gp_Pnt2d pntCurr = c2d->Value(prm);
|
||||
gp_XY curr = pntCurr.XY();
|
||||
area += curr ^ prev;
|
||||
prev = curr;
|
||||
|
||||
for (Standard_Integer i = 1; i < aNbControl; ++i)
|
||||
{
|
||||
const Standard_Real aV = anInv * ((aNbControl - 1 - i) * aF+ i * aL);
|
||||
aCenter2d += aCurve2d->Value(aV).XY();
|
||||
}
|
||||
}
|
||||
area += cont ^ prev;
|
||||
if ( Abs(area) < 2*prec2d*prec2d ) {
|
||||
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
|
||||
return Standard_True;
|
||||
aCenter2d *= 1.0 / static_cast<Standard_Real>(NbEdges * (aNbControl - 1));
|
||||
|
||||
// check approximated area in 3D
|
||||
gp_Pnt aPnt3d;
|
||||
gp_XYZ aPrev3d, aCross(0., 0., 0.);
|
||||
gp_XYZ aCenter(mySurf->Value(aCenter2d.X(), aCenter2d.Y()).XYZ());
|
||||
|
||||
Handle(Geom_Curve) aCurve3d;
|
||||
for (Standard_Integer j = 1; j <= NbEdges; ++j)
|
||||
{
|
||||
const ShapeAnalysis_Edge anAnalizer;
|
||||
if (!anAnalizer.Curve3d(myWire->Edge(j), aCurve3d, aF, aL))
|
||||
{
|
||||
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_FAIL2);
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
Standard_Integer aBegin = 0;
|
||||
if (j == 1)
|
||||
{
|
||||
aBegin = 1;
|
||||
aPnt3d = aCurve3d->Value(aF);
|
||||
aPrev3d = aPnt3d.XYZ() - aCenter;
|
||||
}
|
||||
for (Standard_Integer i = aBegin; i < aNbControl; ++i)
|
||||
{
|
||||
const Standard_Real anU =
|
||||
anInv * ( (aNbControl - 1 - i) * aF + i * aL );
|
||||
const gp_Pnt aPnt = aCurve3d->Value(anU);
|
||||
const gp_XYZ& aCurrent = aPnt.XYZ();
|
||||
const gp_XYZ aVec = aCurrent - aCenter;
|
||||
|
||||
aCross += aPrev3d ^ aVec;
|
||||
aLength += aPnt3d.Distance(aPnt);
|
||||
|
||||
aPnt3d = aPnt;
|
||||
aPrev3d = aVec;
|
||||
}
|
||||
}
|
||||
|
||||
Standard_Real aTolerance = aLength * myPrecision;
|
||||
if ( aCross.Modulus() < aTolerance )
|
||||
{
|
||||
// check real area in 3D
|
||||
GProp_GProps aProps;
|
||||
GProp_GProps aLProps;
|
||||
if (theIsOuterWire)
|
||||
{
|
||||
BRepGProp::SurfaceProperties(myFace, aProps);
|
||||
BRepGProp::LinearProperties(myFace, aLProps);
|
||||
}
|
||||
else
|
||||
{
|
||||
BRepBuilderAPI_MakeFace aFace(mySurf->Surface(), theWire);
|
||||
BRepGProp::SurfaceProperties(aFace.Face(), aProps);
|
||||
BRepGProp::LinearProperties(aFace.Face(), aLProps);
|
||||
}
|
||||
|
||||
Standard_Real aNewTolerance = aLProps.Mass() * myPrecision;
|
||||
if ( aProps.Mass() < 0.5 * aNewTolerance )
|
||||
{
|
||||
myStatus = ShapeExtend::EncodeStatus (ShapeExtend_DONE1);
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
|
@@ -105,6 +105,13 @@ is
|
||||
---C++: inline
|
||||
---Purpose: Returns (modifiable) the fix small area wire mode, by default
|
||||
-- False. If True, drops small wires.
|
||||
|
||||
RemoveSmallAreaFaceMode (me: mutable) returns Integer;
|
||||
---C++: return &
|
||||
---C++: inline
|
||||
---Purpose: Returns (modifiable) the remove face with small area, by default
|
||||
-- False. If True, drops faces with small outer wires.
|
||||
|
||||
FixIntersectingWiresMode (me: mutable) returns Integer;
|
||||
---C++: return &
|
||||
---C++: inline
|
||||
@@ -202,7 +209,7 @@ is
|
||||
-- missing seam edge
|
||||
-- Returns True if missing seam was added
|
||||
|
||||
FixSmallAreaWire (me: mutable) returns Boolean;
|
||||
FixSmallAreaWire (me: mutable; theIsRemoveSmallFace: Boolean = Standard_False) returns Boolean;
|
||||
---Purpose: Detects wires with small area (that is less than
|
||||
-- 100*Precision::PConfusion(). Removes these wires if they are internal.
|
||||
-- Returns : True if at least one small wire removed,
|
||||
@@ -276,6 +283,7 @@ fields
|
||||
myFixAddNaturalBoundMode : Integer;
|
||||
myFixMissingSeamMode : Integer;
|
||||
myFixSmallAreaWireMode : Integer;
|
||||
myRemoveSmallAreaFaceMode : Integer;
|
||||
myFixLoopWiresMode : Integer; -- gka 08.01.2004
|
||||
myFixIntersectingWiresMode : Integer; -- skl 23.12.2003
|
||||
myFixSplitFaceMode : Integer; -- skl 03.02.2004
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <GeomAdaptor_HSurface.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
@@ -51,6 +52,7 @@
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopTools_SequenceOfShape.hxx>
|
||||
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepTopAdaptor_FClass2d.hxx>
|
||||
@@ -685,13 +687,14 @@ Standard_Boolean ShapeFix_Face::Perform()
|
||||
myFace = TopoDS::Face ( exp.Current() );
|
||||
|
||||
// fix small-area wires
|
||||
if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) ) {
|
||||
if ( FixSmallAreaWire() )
|
||||
myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
|
||||
if ( NeedFix ( myFixSmallAreaWireMode, Standard_False ) )
|
||||
{
|
||||
const Standard_Boolean isRemoveFace = NeedFix( myRemoveSmallAreaFaceMode, Standard_False );
|
||||
if ( FixSmallAreaWire( isRemoveFace ) )
|
||||
myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( ! Context().IsNull() ) {
|
||||
if(Status ( ShapeExtend_DONE ) && !isReplaced && !aInitFace.IsSame(savShape))
|
||||
{
|
||||
@@ -1840,51 +1843,69 @@ Standard_Boolean ShapeFix_Face::FixMissingSeam()
|
||||
//function : FixSmallAreaWire
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
//%14 pdn 24.02.99 PRO10109, USA60293 fix wire on face with small area.
|
||||
Standard_Boolean ShapeFix_Face::FixSmallAreaWire()
|
||||
Standard_Boolean ShapeFix_Face::FixSmallAreaWire(const Standard_Boolean theIsRemoveSmallFace)
|
||||
{
|
||||
if ( ! Context().IsNull() ) {
|
||||
TopoDS_Shape S = Context()->Apply ( myFace );
|
||||
myFace = TopoDS::Face ( S );
|
||||
if ( !Context().IsNull() )
|
||||
{
|
||||
TopoDS_Shape aShape = Context()->Apply(myFace);
|
||||
myFace = TopoDS::Face(aShape);
|
||||
}
|
||||
|
||||
//smh#8
|
||||
TopoDS_Shape emptyCopied = myFace.EmptyCopied();
|
||||
TopoDS_Face face = TopoDS::Face (emptyCopied);
|
||||
|
||||
BRep_Builder aBuilder;
|
||||
Standard_Integer nbRemoved = 0, nbWires = 0;
|
||||
BRep_Builder B;
|
||||
Standard_Real prec = ::Precision::PConfusion()*100;
|
||||
for (TopoDS_Iterator wi (myFace, Standard_False); wi.More(); wi.Next()) {
|
||||
if(wi.Value().ShapeType() != TopAbs_WIRE &&
|
||||
(wi.Value().Orientation() != TopAbs_FORWARD && wi.Value().Orientation() != TopAbs_REVERSED))
|
||||
continue;
|
||||
TopoDS_Wire wire = TopoDS::Wire ( wi.Value() );
|
||||
Handle(ShapeAnalysis_Wire) saw = new ShapeAnalysis_Wire(wire,myFace,prec);
|
||||
if ( saw->CheckSmallArea(prec) )
|
||||
|
||||
TopoDS_Shape anEmptyCopy = myFace.EmptyCopied();
|
||||
TopoDS_Face aFace = TopoDS::Face(anEmptyCopy);
|
||||
|
||||
const TopoDS_Wire anOuterWire = BRepTools::OuterWire(myFace);
|
||||
const Standard_Real aTolerance3d = ShapeFix_Root::Precision();
|
||||
for (TopoDS_Iterator aWIt(myFace, Standard_False); aWIt.More(); aWIt.Next())
|
||||
{
|
||||
const TopoDS_Shape& aShape = aWIt.Value();
|
||||
if ( aShape.ShapeType() != TopAbs_WIRE &&
|
||||
aShape.Orientation() != TopAbs_FORWARD &&
|
||||
aShape.Orientation() != TopAbs_REVERSED )
|
||||
{
|
||||
SendWarning ( wire, Message_Msg ("FixAdvFace.FixSmallAreaWire.MSG0") );// Null area wire detected, wire skipped
|
||||
nbRemoved++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const TopoDS_Wire& aWire = TopoDS::Wire(aShape);
|
||||
const Standard_Boolean isOuterWire = anOuterWire.IsEqual(aWire);
|
||||
Handle(ShapeAnalysis_Wire) anAnalyzer = new ShapeAnalysis_Wire(aWire, myFace, aTolerance3d);
|
||||
if ( anAnalyzer->CheckSmallArea(aWire, isOuterWire) )
|
||||
{
|
||||
// Null area wire detected, wire skipped
|
||||
SendWarning(aWire, Message_Msg("FixAdvFace.FixSmallAreaWire.MSG0"));
|
||||
++nbRemoved;
|
||||
}
|
||||
else
|
||||
{
|
||||
B.Add(face,wire);
|
||||
nbWires++;
|
||||
aBuilder.Add(aFace, aWire);
|
||||
++nbWires;
|
||||
}
|
||||
}
|
||||
if ( nbRemoved <=0 ) return Standard_False;
|
||||
|
||||
if ( nbWires <=0 ) {
|
||||
|
||||
if ( nbRemoved <= 0 )
|
||||
return Standard_False;
|
||||
|
||||
if ( nbWires <= 0 )
|
||||
{
|
||||
#ifdef OCCT_DEBUG
|
||||
cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" << endl;
|
||||
#endif
|
||||
if ( theIsRemoveSmallFace && !Context().IsNull() )
|
||||
Context()->Remove(myFace);
|
||||
|
||||
return Standard_False;
|
||||
}
|
||||
#ifdef OCCT_DEBUG
|
||||
cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" << endl;
|
||||
#endif
|
||||
if ( ! Context().IsNull() ) Context()->Replace ( myFace, face );
|
||||
myFace = face;
|
||||
if ( !Context().IsNull() )
|
||||
Context()->Replace(myFace, aFace);
|
||||
|
||||
myFace = aFace;
|
||||
return Standard_True;
|
||||
}
|
||||
//=======================================================================
|
||||
|
@@ -63,6 +63,16 @@ inline Standard_Integer& ShapeFix_Face::FixSmallAreaWireMode()
|
||||
return myFixSmallAreaWireMode;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : RemoveSmallAreaFaceMode
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
inline Standard_Integer& ShapeFix_Face::RemoveSmallAreaFaceMode()
|
||||
{
|
||||
return myRemoveSmallAreaFaceMode;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : FixIntersectingWiresMode
|
||||
//purpose :
|
||||
|
@@ -725,6 +725,7 @@ static Standard_Boolean fixshape (const Handle(ShapeProcess_Context)& context)
|
||||
sff->FixAddNaturalBoundMode() = ctx->IntegerVal ( "FixAddNaturalBoundMode", -1 );
|
||||
sff->FixMissingSeamMode() = ctx->IntegerVal ( "FixMissingSeamMode", -1 );
|
||||
sff->FixSmallAreaWireMode() = ctx->IntegerVal ( "FixSmallAreaWireMode", -1 );
|
||||
sff->RemoveSmallAreaFaceMode() = ctx->IntegerVal ( "RemoveSmallAreaFaceMode", -1 );
|
||||
sff->FixIntersectingWiresMode() = ctx->IntegerVal ( "FixIntersectingWiresMode", -1 );
|
||||
sff->FixLoopWiresMode() = ctx->IntegerVal ( "FixLoopWiresMode", -1 );
|
||||
sff->FixSplitFaceMode() = ctx->IntegerVal ( "FixSplitFaceMode", -1 );
|
||||
|
@@ -26,6 +26,7 @@ FromIGES.FixShape.FixOrientationMode : -1
|
||||
FromIGES.FixShape.FixAddNaturalBoundMode : -1
|
||||
FromIGES.FixShape.FixMissingSeamMode : -1
|
||||
FromIGES.FixShape.FixSmallAreaWireMode : -1
|
||||
FromIGES.FixShape.RemoveSmallAreaFaceMode : -1
|
||||
FromIGES.FixShape.FixIntersectingWiresMode : -1
|
||||
FromIGES.FixShape.FixLoopWiresMode : -1
|
||||
FromIGES.FixShape.FixSplitFaceMode : -1
|
||||
|
Reference in New Issue
Block a user