1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00

0022707: Invalid shape translating a SAT file

This commit is contained in:
SSV 2012-01-14 09:06:48 +00:00 committed by bugmaster
parent 06f3d6bca0
commit 84dc990afd
2 changed files with 355 additions and 103 deletions

View File

@ -1,9 +1,7 @@
-- File: ShapeFix_Face.cdl
-- Created: Wed Jun 3 12:33:25 1998
-- Author: data exchange team
-- <det@nnov.matra-dtv.fr>
---Copyright: Matra Datavision 1998
---File: ShapeFix_Face.cdl
---Created: Wed Jun 3 12:33:25 1998
---Author: data exchange team
---Copyright: Open CASCADE SAS 2011
class Face from ShapeFix inherits Root from ShapeFix
@ -120,6 +118,12 @@ is
---Purpose: Returns (modifiable) the auto-correct precision mode
-- by default False.
FixPeriodicDegeneratedMode (me: mutable) returns Integer;
---C++: return &
---C++: inline
---Purpose: Returns (modifiable) the activation flag for periodic
-- degenerated fix. False by default.
Face (me) returns Face from TopoDS;
---C++: inline
---Purpose: Returns a face which corresponds to the current state
@ -192,6 +196,7 @@ is
-- 100*Precision::PConfusion(). Removes these wires if they are internal.
-- Returns : True if at least one small wire removed,
-- False if does nothing.
FixLoopWire(me: mutable; aResWires : out SequenceOfShape from TopTools) returns Boolean;
---Purpose: Detects if wire has a loop and fixes this situation by splitting on the few parts.
-- if wire has a loops and it was splitted Status was set to value ShapeExtend_DONE6.
@ -220,6 +225,14 @@ is
---Purpose: Split face if there are more than one out wire
-- using inrormation after FixOrientation()
FixPeriodicDegenerated (me: mutable)
returns Boolean;
---Purpose: Fixes topology for a specific case when face is composed
-- by a single wire belting a periodic surface. In that case
-- a degenerated edge is reconstructed in the degenerated pole
-- of the surface. Initial wire gets consistent orientation.
-- Must be used in couple and before FixMissingSeam routine
Status (me; status: Status from ShapeExtend) returns Boolean;
---Purpose: Returns the status of last call to Perform()
-- ShapeExtend_OK : face was OK, nothing done
@ -249,13 +262,15 @@ fields
myFixWireMode : Integer;
myFixOrientationMode : Integer;
myFixAddNaturalBoundMode: Integer;
myFixAddNaturalBoundMode : Integer;
myFixMissingSeamMode : Integer;
myFixSmallAreaWireMode : Integer;
myFixLoopWiresMode : Integer; --gka 08.01.2004
myFixLoopWiresMode : Integer; -- gka 08.01.2004
myFixIntersectingWiresMode : Integer; -- skl 23.12.2003
myFixSplitFaceMode : Integer; -- skl 03.02.2004
myAutoCorrectPrecisionMode: Integer; --skl 26.03.2010
myAutoCorrectPrecisionMode : Integer; -- skl 26.03.2010
myFixPeriodicDegenerated : Integer; -- ssv 29.09.2011
myStatus : Integer is protected;
end Face;

View File

@ -41,7 +41,10 @@
#include <BRep_Builder.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRepTools.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <Message_Msg.hxx>
#include <ShapeBuild_ReShape.hxx>
@ -51,8 +54,10 @@
#include <ShapeFix_Edge.hxx>
#include <ShapeAnalysis_Edge.hxx>
#include <Bnd_Box2d.hxx>
#include <Geom_Circle.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_ConicalSurface.hxx>
#include <ShapeAnalysis_Wire.hxx>
#include <ShapeAnalysis_Surface.hxx>
@ -130,9 +135,10 @@ void ShapeFix_Face::ClearModes()
myFixMissingSeamMode = -1;
myFixSmallAreaWireMode = -1;
myFixIntersectingWiresMode = -1;
myFixLoopWiresMode =-1;
myFixSplitFaceMode =-1;
myFixLoopWiresMode = -1;
myFixSplitFaceMode = -1;
myAutoCorrectPrecisionMode = 1;
myFixPeriodicDegenerated = -1;
}
//=======================================================================
@ -445,6 +451,11 @@ Standard_Boolean ShapeFix_Face::Perform()
myResult = myFace;
TopoDS_Shape savShape = myFace; //gka BUG 6555
// Specific case for conic surfaces
if ( NeedFix(myFixPeriodicDegenerated) )
this->FixPeriodicDegenerated();
// fix missing seam
if ( NeedFix ( myFixMissingSeamMode ) ) {
if ( FixMissingSeam() ) {
@ -2241,3 +2252,229 @@ Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOf
return Standard_False;
}
//=======================================================================
//function : IsPeriodicConicalLoop
//purpose : Checks whether the passed wire makes up a periodic loop on
// passed conical surface
//=======================================================================
static Standard_Boolean IsPeriodicConicalLoop(const Handle(Geom_ConicalSurface)& theSurf,
const TopoDS_Wire& theWire,
const Standard_Real theTolerance,
Standard_Real& theMinU,
Standard_Real& theMaxU,
Standard_Real& theMinV,
Standard_Real& theMaxV,
Standard_Boolean& isUDecrease)
{
if ( theSurf.IsNull() )
Standard_False;
ShapeAnalysis_Edge aSAE;
TopLoc_Location aLoc;
Standard_Real aCumulDeltaU = 0.0, aCumulDeltaUAbs = 0.0;
Standard_Real aMinU = RealLast();
Standard_Real aMinV = aMinU;
Standard_Real aMaxU = -aMinU;
Standard_Real aMaxV = aMaxU;
// Iterate over the edges to check whether the wire is periodic on conical surface
BRepTools_WireExplorer aWireExp(theWire);
for ( ; aWireExp.More(); aWireExp.Next() )
{
const TopoDS_Edge& aCurrentEdge = aWireExp.Current();
Handle(Geom2d_Curve) aC2d;
Standard_Real aPFirst, aPLast;
aSAE.PCurve(aCurrentEdge, theSurf, aLoc, aC2d, aPFirst, aPLast, Standard_True);
if ( aC2d.IsNull() )
return Standard_False;
gp_Pnt2d aUVFirst = aC2d->Value(aPFirst),
aUVLast = aC2d->Value(aPLast);
Standard_Real aUFirst = aUVFirst.X(), aULast = aUVLast.X();
Standard_Real aVFirst = aUVFirst.Y(), aVLast = aUVLast.Y();
Standard_Real aCurMaxU = Max(aUFirst, aULast),
aCurMinU = Min(aUFirst, aULast);
Standard_Real aCurMaxV = Max(aVFirst, aVLast),
aCurMinV = Min(aVFirst, aVLast);
if ( aCurMinU < aMinU )
aMinU = aCurMinU;
if ( aCurMaxU > aMaxU )
aMaxU = aCurMaxU;
if ( aCurMinV < aMinV )
aMinV = aCurMinV;
if ( aCurMaxV > aMaxV )
aMaxV = aCurMaxV;
Standard_Real aDeltaU = aULast - aUFirst;
aCumulDeltaU += aDeltaU;
aCumulDeltaUAbs += Abs(aDeltaU);
}
theMinU = aMinU;
theMaxU = aMaxU;
theMinV = aMinV;
theMaxV = aMaxV;
isUDecrease = (aCumulDeltaU < 0 ? Standard_True : Standard_False);
Standard_Boolean is2PIDelta = Abs(aCumulDeltaUAbs - 2*M_PI) <= theTolerance;
Standard_Boolean isAroundApex = Abs(theMaxU - theMinU) > 2*M_PI - theTolerance;
return is2PIDelta && isAroundApex;
}
//=======================================================================
//function : FixPeriodicDegenerated
//purpose :
//=======================================================================
Standard_Boolean ShapeFix_Face::FixPeriodicDegenerated()
{
/* =====================
* Prepare fix routine
* ===================== */
if ( !Context().IsNull() )
{
TopoDS_Shape aSh = Context()->Apply(myFace);
myFace = TopoDS::Face(aSh);
}
/* ================================================
* Check if fix can be applied on the passed face
* ================================================ */
// Collect all wires owned by the face
TopTools_SequenceOfShape aWireSeq;
for ( TopoDS_Iterator aWireIt(myFace, Standard_False); aWireIt.More(); aWireIt.Next() )
{
const TopoDS_Shape& aSubSh = aWireIt.Value();
if ( aSubSh.ShapeType() != TopAbs_WIRE || ( aSubSh.Orientation() != TopAbs_FORWARD &&
aSubSh.Orientation() != TopAbs_REVERSED ) )
continue;
aWireSeq.Append( aWireIt.Value() );
}
// Get number of wires and surface
Standard_Integer aNbWires = aWireSeq.Length();
Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace);
// Only single wires on conical surfaces are checked
if ( aNbWires != 1 || aSurface.IsNull() ||
aSurface->DynamicType() != STANDARD_TYPE(Geom_ConicalSurface) )
return Standard_False;
// Get the single wire
TopoDS_Wire aSoleWire = TopoDS::Wire( aWireSeq.Value(1) );
// Check whether this wire is belting the conical surface by period
Handle(Geom_ConicalSurface) aConeSurf = Handle(Geom_ConicalSurface)::DownCast(aSurface);
Standard_Real aMinLoopU = 0.0, aMaxLoopU = 0.0, aMinLoopV = 0.0, aMaxLoopV = 0.0;
Standard_Boolean isUDecrease = Standard_False;
Standard_Boolean isConicLoop = IsPeriodicConicalLoop(aConeSurf, aSoleWire, Precision(),
aMinLoopU, aMaxLoopU,
aMinLoopV, aMaxLoopV,
isUDecrease);
if ( !isConicLoop )
return Standard_False;
/* ===============
* Retrieve apex
* =============== */
// Get base circle of the conical surface (the circle it was built from)
Handle(Geom_Curve) aConeBaseCrv = aConeSurf->VIso(0.0);
Handle(Geom_Circle) aConeBaseCirc = Handle(Geom_Circle)::DownCast(aConeBaseCrv);
// Retrieve conical props
Standard_Real aConeBaseR = aConeBaseCirc->Radius();
Standard_Real aSemiAngle = aConeSurf->SemiAngle();
if ( fabs(aSemiAngle) <= Precision::Confusion() )
return Standard_False; // Bad surface
// Find the V parameter of the apex
Standard_Real aConeBaseH = aConeBaseR / Sin(aSemiAngle);
Standard_Real anApexV = -aConeBaseH;
// Get apex vertex
TopoDS_Vertex anApex = BRepBuilderAPI_MakeVertex( aConeSurf->Apex() );
// ====================================
// Build degenerated edge in the apex
// ====================================
TopoDS_Edge anApexEdge;
BRep_Builder aBuilder;
aBuilder.MakeEdge(anApexEdge);
// Check if positional relationship between the initial wire and apex
// line in 2D is going to be consistent
if ( fabs(anApexV - aMinLoopV) <= Precision() ||
fabs(anApexV - aMaxLoopV) <= Precision() ||
( anApexV < aMaxLoopV && anApexV > aMinLoopV ) )
return Standard_False;
Handle(Geom2d_Line) anApexCurve2d;
// Apex curve below the wire
if ( anApexV < aMinLoopV )
{
anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMinLoopU, anApexV), gp_Dir2d(1, 0) );
if ( !isUDecrease )
aSoleWire.Reverse();
}
// Apex curve above the wire
if ( anApexV > aMaxLoopV )
{
anApexCurve2d = new Geom2d_Line( gp_Pnt2d(aMaxLoopU, anApexV), gp_Dir2d(-1, 0) );
if ( isUDecrease )
aSoleWire.Reverse();
}
// Create degenerated edge & wire for apex
aBuilder.UpdateEdge( anApexEdge, anApexCurve2d, myFace, Precision() );
aBuilder.Add( anApexEdge, anApex );
aBuilder.Add( anApexEdge, anApex.Reversed() );
aBuilder.Degenerated(anApexEdge, Standard_True);
aBuilder.Range( anApexEdge, 0, fabs(aMaxLoopU - aMinLoopU) );
TopoDS_Wire anApexWire = BRepBuilderAPI_MakeWire(anApexEdge);
// ===============================================================
// Finalize the fix building new face and setting up the results
// ===============================================================
// Collect the resulting set of wires
TopTools_SequenceOfShape aNewWireSeq;
aNewWireSeq.Append(aSoleWire);
aNewWireSeq.Append(anApexWire);
// Assemble new face
TopoDS_Face aNewFace = TopoDS::Face( myFace.EmptyCopied() );
aNewFace.Orientation(TopAbs_FORWARD);
BRep_Builder aFaceBuilder;
for ( Standard_Integer i = 1; i <= aNewWireSeq.Length(); i++ )
{
TopoDS_Wire aNewWire = TopoDS::Wire( aNewWireSeq.Value(i) );
aFaceBuilder.Add(aNewFace, aNewWire);
}
aNewFace.Orientation( myFace.Orientation() );
// Adjust the resulting state of the healing tool
myResult = aNewFace;
Context()->Replace(myFace, myResult);
return Standard_True;
}