From 599869329ccb53dd1943d0172b11f2c54082a7b5 Mon Sep 17 00:00:00 2001 From: Sander Adamson Date: Fri, 1 Aug 2025 18:10:21 +0100 Subject: [PATCH] Modeling - Fix null surface crash in fixshape (#623) - Added null surface validation in ShapeAnalysis_Surface constructor and Init method - Added null surface checks throughout ShapeFix_Face methods to prevent crashes - Enhanced robustness by validating surface availability before performing surface-dependent operations --- .../ShapeAnalysis/ShapeAnalysis_Surface.cxx | 23 +- .../ShapeAnalysis/ShapeAnalysis_Wire.cxx | 62 +++--- .../TKShHealing/ShapeFix/ShapeFix_Face.cxx | 208 ++++-------------- tests/bugs/modalg_8/bug33895 | 21 ++ 4 files changed, 111 insertions(+), 203 deletions(-) create mode 100644 tests/bugs/modalg_8/bug33895 diff --git a/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Surface.cxx b/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Surface.cxx index 557cc67e3d..72b9933959 100644 --- a/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Surface.cxx +++ b/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Surface.cxx @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,8 @@ #include #include +#include + IMPLEMENT_STANDARD_RTTIEXT(ShapeAnalysis_Surface, Standard_Transient) namespace @@ -105,18 +108,32 @@ ShapeAnalysis_Surface::ShapeAnalysis_Surface(const Handle(Geom_Surface)& S) myUCloseVal(-1), myVCloseVal(-1) { + // Bug 33895: Prevent crash when surface is null + if (mySurf.IsNull()) + { + Message::SendWarning("ShapeAnalysis_Surface: Cannot create with null surface"); + assert(!mySurf.IsNull()); + return; + } mySurf->Bounds(myUF, myUL, myVF, myVL); myAdSur = new GeomAdaptor_Surface(mySurf); } //================================================================================================= -void ShapeAnalysis_Surface::Init(const Handle(Geom_Surface)& S) +void ShapeAnalysis_Surface::Init(const Handle(Geom_Surface)& theSurface) { - if (mySurf == S) + if (mySurf == theSurface) + return; + // Bug 33895: Prevent crash when surface is null + if (theSurface.IsNull()) + { + Message::SendWarning("ShapeAnalysis_Surface: Cannot initialize with null surface"); + assert(!theSurface.IsNull()); return; + } myExtOK = Standard_False; //: 30 - mySurf = S; + mySurf = theSurface; myNbDeg = -1; myUCloseVal = myVCloseVal = -1; myGap = 0.; diff --git a/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Wire.cxx b/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Wire.cxx index 3dfe97505c..f2b1732753 100644 --- a/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Wire.cxx +++ b/src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Wire.cxx @@ -150,8 +150,16 @@ void ShapeAnalysis_Wire::Load(const Handle(ShapeExtend_WireData)& sbwd) void ShapeAnalysis_Wire::SetFace(const TopoDS_Face& face) { myFace = face; - if (!face.IsNull()) - mySurf = new ShapeAnalysis_Surface(BRep_Tool::Surface(myFace)); + if (myFace.IsNull()) + { + return; + } + + const Handle(Geom_Surface) aSurface = BRep_Tool::Surface(myFace); + if (!face.IsNull() && !aSurface.IsNull()) + { + mySurf = new ShapeAnalysis_Surface(aSurface); + } } //================================================================================================= @@ -677,7 +685,6 @@ Standard_Boolean ShapeAnalysis_Wire::CheckSmall(const Standard_Integer num, if (!IsLoaded() || NbEdges() <= 1) return Standard_False; - // Standard_Integer n = ( num ? num : NbEdges() ); //szv#4:S4163:12Mar99 not needed TopoDS_Edge E = myWire->Edge(num ? num : NbEdges()); ShapeAnalysis_Edge sae; @@ -701,35 +708,35 @@ Standard_Boolean ShapeAnalysis_Wire::CheckSmall(const Standard_Integer num, gp_Pnt p2 = BRep_Tool::Pnt(V2); Standard_Real dist = p1.Distance(p2); Standard_Real prec = precsmall; // Min ( myPrecision, precsmall ); - // Standard_Real prec = Min(BRep_Tool::Tolerance(V1),BRep_Tool::Tolerance(V2)); //skl if (dist > prec) - return Standard_False; // pas nulle + return Standard_False; // not small enough - // La courbe 3D a present : est-elle FERMEE ou DE LONGUEUR NULLE ... ??? - // Pour cela on prend le point milieu (y a-t-il mieux) - // Si pas de C3D, on essaie la C2D ... + // The 3D curve now: is it CLOSED or ZERO LENGTH...??? + // To do this, we take the midpoint (is there anything better?) + // If there's no 3D curve, we try 2D... - gp_Pnt Pm; + gp_Pnt aMidpoint; Standard_Real cf, cl; Handle(Geom_Curve) c3d; if (sae.Curve3d(E, c3d, cf, cl, Standard_False)) - Pm = c3d->Value((cf + cl) / 2.); + { + aMidpoint = c3d->Value((cf + cl) / 2.); + } else { Handle(Geom2d_Curve) c2d; - if (!myFace.IsNull() && sae.PCurve(E, myFace, c2d, cf, cl, Standard_False)) + if (!myFace.IsNull() && !mySurf.IsNull() && sae.PCurve(E, myFace, c2d, cf, cl, Standard_False)) { gp_Pnt2d p2m = c2d->Value((cf + cl) / 2.); - Pm = mySurf->Value(p2m); + aMidpoint = mySurf->Value(p2m); } else { - myStatus = ShapeExtend::EncodeStatus(ShapeExtend_FAIL1); - Pm = p1; - //: n2 return Standard_False; + myStatus = ShapeExtend::EncodeStatus(ShapeExtend_FAIL1); + aMidpoint = p1; } } - if (Pm.Distance(p1) > prec || Pm.Distance(p2) > prec) + if (aMidpoint.Distance(p1) > prec || aMidpoint.Distance(p2) > prec) return Standard_False; myStatus |= ShapeExtend::EncodeStatus(V1.IsSame(V2) ? ShapeExtend_DONE1 : ShapeExtend_DONE2); @@ -836,8 +843,6 @@ Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated(const Standard_Integer num myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_FAIL2); return Standard_False; } - //: i8 if ( BRep_Tool::Degenerated ( E1 ) || - //: i8 BRep_Tool::Degenerated ( E2 ) ) return Standard_False; // deja OK TopoDS_Vertex Vp = sae.FirstVertex(E1); //: i9 TopoDS_Vertex V0 = sae.LastVertex(E1); @@ -922,7 +927,7 @@ Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated(const Standard_Integer num // rln S4135 if ( prec > myPrecision ) mySurf->ComputeSingularities ( myPrecision ); //:51 } - // voila, on a soit dgnr soit lack + // there you go, we either have degenerate or lack if (!lack && !dgnr) { //: abv 29.08.01: if singularity not detected but edge is marked @@ -948,8 +953,6 @@ Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated(const Standard_Integer num if (sae.PCurve(E1, myFace, c2d, a, b, Standard_True)) { p2d1 = c2d->Value(b); - // #84 rln gp_Pnt2d p2d = c2d->Value ( b ); - // #84 rln par1 = ( p2d.XY() - aP2d.XY() ) * theDir2d.XY(); } else myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_FAIL1); @@ -957,19 +960,10 @@ Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated(const Standard_Integer num if (sae.PCurve((dgnr ? E3 : E2), myFace, c2d, a, b, Standard_True)) { p2d2 = c2d->Value(a); - // #84 rln gp_Pnt2d p2d = c2d->Value ( a ); - // #84 rln par2 = ( p2d.XY() - aP2d.XY() ) * theDir2d.XY(); } else myStatus |= ShapeExtend::EncodeStatus(ShapeExtend_FAIL1); } - /* - if ( par2 < par1 ) { - par1 = -par1; - par2 = -par2; - theDir2d.Reverse(); - } - */ // #84 rln 18.03.99 if pcurve is not degenerate anymore, the fix is postponned // to ShapeFix_Wire::FixLacking @@ -990,8 +984,6 @@ Standard_Boolean ShapeAnalysis_Wire::CheckDegenerated(const Standard_Integer num if (p2d1.Distance(p2d2) /*Abs (par1 - par2)*/ <= max + gp::Resolution()) return Standard_False; - // #84 rln p2d1 = aP2d.XY() + par1 * theDir2d.XY(); - // #84 rln p2d2 = aP2d.XY() + par2 * theDir2d.XY(); myStatus = ShapeExtend::EncodeStatus(dgnr ? ShapeExtend_DONE2 : ShapeExtend_DONE1); return Standard_True; } @@ -1036,6 +1028,12 @@ Standard_Boolean ShapeAnalysis_Wire::CheckGap3d(const Standard_Integer num) Standard_Boolean ShapeAnalysis_Wire::CheckGap2d(const Standard_Integer num) { + if (myFace.IsNull() || mySurf.IsNull()) + { + myStatus = ShapeExtend::EncodeStatus(ShapeExtend_FAIL1); + return Standard_False; + } + myStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK); // szv#4:S4163:12Mar99 optimized if (!IsReady() || NbEdges() < 1) diff --git a/src/ModelingAlgorithms/TKShHealing/ShapeFix/ShapeFix_Face.cxx b/src/ModelingAlgorithms/TKShHealing/ShapeFix/ShapeFix_Face.cxx index 129e0b6cab..7376d2dea7 100644 --- a/src/ModelingAlgorithms/TKShHealing/ShapeFix/ShapeFix_Face.cxx +++ b/src/ModelingAlgorithms/TKShHealing/ShapeFix/ShapeFix_Face.cxx @@ -89,10 +89,6 @@ IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Face, ShapeFix_Root) -#ifdef OCCT_DEBUG - #define DEBUG -#endif - static Standard_Boolean IsSurfaceUVInfinite(const Handle(Geom_Surface)& theSurf) { Standard_Real UMin, UMax, VMin, VMax; @@ -208,16 +204,18 @@ void ShapeFix_Face::Init(const Handle(ShapeAnalysis_Surface)& surf, //================================================================================================= -void ShapeFix_Face::Init(const TopoDS_Face& face) +void ShapeFix_Face::Init(const TopoDS_Face& theFace) { myStatus = 0; - mySurf = new ShapeAnalysis_Surface(BRep_Tool::Surface(face)); - myFwd = (face.Orientation() != TopAbs_REVERSED); - myFace = face; - myShape = myFace; - // myFace = TopoDS::Face(face.EmptyCopied()); - // for (TopoDS_Iterator ws (face,Standard_False); ws.More(); ws.Next()) - // Add (TopoDS::Wire (ws.Value()) ); + // Check if surface is null. It doesn't make sense to create ShapeAnalysis_Surface in that case. + const Handle(Geom_Surface) aSurface = BRep_Tool::Surface(theFace); + if (!aSurface.IsNull()) + { + mySurf = new ShapeAnalysis_Surface(aSurface); + } + myFwd = (theFace.Orientation() != TopAbs_REVERSED); + myFace = theFace; + myShape = myFace; } //================================================================================================= @@ -314,13 +312,6 @@ static Standard_Boolean SplitWire(const TopoDS_Face& face, break; } - if (aResWires.Length() > 1) - { -#ifdef OCCT_DEBUG - std::cout << "Wire was split on " << aResWires.Length() << " wires" << std::endl; -#endif - } - return Standard_True; } @@ -363,34 +354,6 @@ Standard_Boolean ShapeFix_Face::Perform() TopoDS_Face tmpFace = TopoDS::Face(emptyCopied); tmpFace.Orientation(TopAbs_FORWARD); - /* - // skl 14.05.2002 OCC55 + corrected 03.03.2004 - Standard_Real dPreci = aSavPreci*aSavPreci; - dPreci*=4; - Standard_Real newpreci=dPreci; - for(TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next()) { - TopoDS_Edge edge = TopoDS::Edge ( exp.Current() ); - Standard_Real first,last; - Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge, first, last); - if(!c3d.IsNull()) { - Bnd_Box bb; - bb.Add(c3d->Value(first)); - bb.Add(c3d->Value(last)); - bb.Add(c3d->Value((last+first)/2.)); - Standard_Real x1,x2,y1,y2,z1,z2,size; - bb.Get(x1,y1,z1,x2,y2,z2); - size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1); - if(size newpreci && newpreci > Precision::Confusion()) { - SetPrecision(newpreci); - theAdvFixWire->SetPrecision(newpreci); - } - // end skl 14.05.2002 - */ - // skl 29.03.2010 (OCC21623) if (myAutoCorrectPrecisionMode) { @@ -453,22 +416,17 @@ Standard_Boolean ShapeFix_Face::Perform() wire = w; } B.Add(tmpFace, wire); - // if ( theAdvFixWire->Status ( ShapeExtend_FAIL ) ) - // myStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 ); } - theAdvFixWire->FixLackingMode() = usFixLackingMode; - // theAdvFixWire->FixNotchedEdgesMode() = usFixNotchedEdgesMode; // CR0024983 + theAdvFixWire->FixLackingMode() = usFixLackingMode; theAdvFixWire->FixSelfIntersectionMode() = usFixSelfIntersectionMode; if (!myFwd) tmpFace.Orientation(TopAbs_REVERSED); if (fixed) { - // if ( ! myFwd ) tmpFace.Orientation ( TopAbs_REVERSED ); if (!Context().IsNull()) Context()->Replace(S, tmpFace); - // myFace = tmpFace; isReplaced = Standard_True; } if (fixed || isfixReorder) @@ -738,7 +696,7 @@ Standard_Boolean ShapeFix_Face::Perform() static void Shift2dWire(const TopoDS_Wire& w, const TopoDS_Face& f, const gp_Vec2d vec, - const Handle(ShapeAnalysis_Surface)& mySurf, + const Handle(ShapeAnalysis_Surface)& theSurface, Standard_Boolean recompute3d = Standard_False) { gp_Trsf2d tr2d; @@ -759,7 +717,7 @@ static void Shift2dWire(const TopoDS_Wire& w, // recompute 3d curve and vertex sbe.RemoveCurve3d(edge); sbe.BuildCurve3d(edge); - B.UpdateVertex(sae.FirstVertex(edge), mySurf->Value(C2d->Value(cf)), 0.); + B.UpdateVertex(sae.FirstVertex(edge), theSurface->Value(C2d->Value(cf)), 0.); } } } @@ -827,6 +785,11 @@ static Standard_Real FindBestInterval(TColgp_SequenceOfPnt2d& intervals) Standard_Boolean ShapeFix_Face::FixAddNaturalBound() { + if (mySurf.IsNull()) + { + return Standard_False; + } + if (!Context().IsNull()) { TopoDS_Shape S = Context()->Apply(myFace); @@ -898,10 +861,7 @@ Standard_Boolean ShapeFix_Face::FixAddNaturalBound() { Standard_Real Umin, Vmin, Umax, Vmax; // Bnd_Box2d B; - TopoDS_Wire aw = TopoDS::Wire(ws.Value(i)); - // PTV 01.11.2002 ACIS907, OCC921 begin - // BRepTools::AddUVBounds(myFace,aw,B); - // B.Get(Umin, Vmin, Umax, Vmax); + TopoDS_Wire aw = TopoDS::Wire(ws.Value(i)); TopoDS_Face aWireFace = TopoDS::Face(myFace.EmptyCopied()); BRep_Builder aB; aB.Add(aWireFace, aw); @@ -936,33 +896,6 @@ Standard_Boolean ShapeFix_Face::FixAddNaturalBound() } // Create naturally bounded surface and add that wire to sequence - /* variant 1 - // Create fictive grid and call ComposeShell - Handle(Geom_RectangularTrimmedSurface) RTS = - new Geom_RectangularTrimmedSurface ( mySurf->Surface(), SUF+shift.X(), SUL+shift.X(), - SVF+shift.Y(), SVL+shift.Y() ); - Handle(TColGeom_HArray2OfSurface) grid = new TColGeom_HArray2OfSurface ( 1, 1, 1, 1 ); - grid->SetValue ( 1, 1, RTS ); - Handle(ShapeExtend_CompositeSurface) G = new ShapeExtend_CompositeSurface ( grid ); - TopLoc_Location L; - - ShapeFix_ComposeShell CompShell; - CompShell.Init ( G, L, myFace, ::Precision::Confusion() ); - CompShell.ClosedMode() = Standard_True; - CompShell.NaturalBoundMode() = Standard_True; - CompShell.SetContext( Context() ); - CompShell.SetMaxTolerance(MaxTolerance()); - CompShell.Perform(); - TopoDS_Shape res = CompShell.Result(); - - Context()->Replace ( myFace, res ); - for (TopExp_Explorer exp ( res, TopAbs_FACE ); exp.More(); exp.Next() ) { - myFace = TopoDS::Face ( exp.Current() ); - BRepTools::Update(myFace); //:p4 - } - myResult = Context()->Apply ( myResult ); - */ - /* variant 2 */ TopLoc_Location L; Handle(Geom_Surface) surf = BRep_Tool::Surface(myFace, L); BRepBuilderAPI_MakeFace mf(surf, Precision::Confusion()); @@ -1039,10 +972,6 @@ Standard_Boolean ShapeFix_Face::FixAddNaturalBound() myFace = TopoDS::Face(S); BRepTools::Update(myFace); -/**/ -#ifdef OCCT_DEBUG - std::cout << "Natural bound on sphere or torus with holes added" << std::endl; // mise au point ! -#endif // clang-format off SendWarning ( myFace, Message_Msg ( "FixAdvFace.FixOrientation.MSG0" ) );// Face created with natural bounds // clang-format on @@ -1069,7 +998,7 @@ Standard_Boolean ShapeFix_Face::isNeedAddNaturalBound( return Standard_False; } // if surface is not double-closed - if (!IsSurfaceUVPeriodic(mySurf->Adaptor3d())) + if (mySurf && !IsSurfaceUVPeriodic(mySurf->Adaptor3d())) { return Standard_False; } @@ -1204,23 +1133,18 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap } } // in case of several wires, perform complex analysis - // ATTENTION ESSAI - // Plusieurs wires : orientations relatives - // Chaque wire doit "contenir" tous les autres - // Evidemment, en cas de peau de leopard, il peut y avoir probleme - else - { - // On prend chaque wire (NB: pcurves presentes !) - // En principe on devrait rejeter les wires non fermes (cf couture manque ?) - // On le classe par rapport aux autres, qui doivent tous etre, soit IN soit - // OUT. Sinon il y a imbrication -> SDB. Si IN, OK, si OUT on inverse - // (nb : ici pas myClos donc pas de pb de couture) - // Si au moins une inversion, il faut refaire la face (cf myRebil) - - //: 94 abv 30 Jan 98: calculate parametric precision - - // GeomAdaptor_Surface& Ads = mySurf->Adaptor3d()->ChangeSurface(); - // Standard_Real toluv = Min ( Ads.UResolution(Precision()), Ads.VResolution(Precision()) ); + // TEST CAUTION + // Multiple wires: relative orientations + // Each wire must "contain" all the others + // Obviously, in the case of leopard skin, there may be a problem + else if (!mySurf.IsNull()) + { + // Take each wire (NB: curves present!) + // In principle, we should reject unclosed wires (see missing seam?) + // We classify it relative to the others, which must all be either IN or + // OUT. Otherwise, there is nesting -> SDB. If IN, OK, if OUT, we reverse + // (NB: not myClos here, so no stitching problem) + // If there is at least one inversion, the face must be redone (see myRebil) Standard_Boolean uclosed = mySurf->IsUClosed(); Standard_Boolean vclosed = mySurf->IsVClosed(); Standard_Real SUF, SUL, SVF, SVL; @@ -1295,7 +1219,6 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap Bnd_Box2d aBox1 = aWireBoxes.Value(i); TopoDS_Shape dummy = myFace.EmptyCopied(); TopoDS_Face af = TopoDS::Face(dummy); - // B.MakeFace (af,mySurf->Surface(),::Precision::Confusion()); af.Orientation(TopAbs_FORWARD); B.Add(af, aw); // PTV OCC945 06.11.2002 files ie_exhaust-A.stp (entities 3782, 3787) @@ -1519,7 +1442,7 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap if (isAddNaturalBounds && nb == aSeqReversed.Length()) done = Standard_False; - // Faut-il reconstruire ? si myRebil est mis + // Should I rebuild? if myRebil is set if (done) { TopoDS_Shape S = myFace.EmptyCopied(); @@ -1545,15 +1468,6 @@ Standard_Boolean ShapeFix_Face::FixOrientation(TopTools_DataMapOfShapeListOfShap Context()->Replace(myFace, S); myFace = TopoDS::Face(S); BRepTools::Update(myFace); - Standard_Integer k = 1; - for (; k <= aSeqReversed.Length(); k++) - { -#ifdef OCCT_DEBUG - // clang-format off - std::cout<<"Wire no "<IsUClosed(); Standard_Boolean vclosed = mySurf->IsVClosed(); @@ -1745,25 +1664,12 @@ Standard_Boolean ShapeFix_Face::FixMissingSeam() else { w2.Reverse(); -#ifdef OCCT_DEBUG - if (!isdeg2) - std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): wire reversed" << std::endl; -#endif } } -#ifdef OCCT_DEBUG - else - std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): incompatible open wires" - << std::endl; -#endif } // else return Standard_False; // abort else { -#ifdef OCCT_DEBUG - std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): more than two open wires detected!" - << std::endl; -#endif //: abv 30.08.09: if more than one open wires and more than two of them are // completely degenerated, remove any of them if (isdeg || isdeg1 || isdeg2) @@ -1772,10 +1678,6 @@ Standard_Boolean ShapeFix_Face::FixMissingSeam() w1.Nullify(); w2.Nullify(); i = 0; -#ifdef OCCT_DEBUG - std::cout << "Warning: ShapeFix_Face::FixMissingSeam(): open degenerated wire removed" - << std::endl; -#endif continue; } } @@ -2093,8 +1995,6 @@ Standard_Boolean ShapeFix_Face::FixMissingSeam() B.Add(tmpF, aSeqNonManif.Value(j)); ShapeFix_ComposeShell CompShell; - // TopoDS_Face tmpF = myFace; - // tmpF.Orientation(TopAbs_FORWARD); CompShell.Init(G, L, tmpF, ::Precision::Confusion()); // myPrecision if (Context().IsNull()) SetContext(new ShapeBuild_ReShape); @@ -2210,19 +2110,11 @@ Standard_Boolean ShapeFix_Face::FixSmallAreaWire(const Standard_Boolean theIsRem if (nbWires <= 0) { -#ifdef OCCT_DEBUG - std::cout << "Warning: ShapeFix_Face: All wires on a face have small area; left untouched" - << std::endl; -#endif if (theIsRemoveSmallFace && !Context().IsNull()) Context()->Remove(myFace); return Standard_False; } -#ifdef OCCT_DEBUG - std::cout << "Warning: ShapeFix_Face: " << nbRemoved << " small area wire(s) removed" - << std::endl; -#endif aFace.Orientation(myFace.Orientation()); if (!Context().IsNull()) Context()->Replace(myFace, aFace); @@ -2439,7 +2331,7 @@ Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires) Standard_Boolean isClosed = Standard_True; // checking that obtained wires is closed in 2D space - if (mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) + if (mySurf && mySurf->Adaptor3d()->GetType() != GeomAbs_Plane) { TopoDS_Shape emptyCopied = myFace.EmptyCopied(); @@ -2453,15 +2345,7 @@ Standard_Boolean ShapeFix_Face::FixLoopWire(TopTools_SequenceOfShape& aResWires) } } - Standard_Boolean isDone = (aResWires.Length() && isClosed); - if (isDone && aResWires.Length() > 1) - { -#ifdef OCCT_DEBUG - std::cout << "Wire was split on " << aResWires.Length() << " wires" << std::endl; -#endif - } - - return isDone; + return !aResWires.IsEmpty() && isClosed; } //================================================================================================= @@ -2490,15 +2374,6 @@ Standard_Boolean ShapeFix_Face::SplitEdge(const Handle(ShapeExtend_WireData)& se BRepTools::Update(E); } - // for ( Standard_Integer i=1; i <= sewd->NbEdges(); i++ ) { - // TopoDS_Edge E = sewd->Edge(i); - // TopoDS_Shape S = Context()->Apply ( E ); - // if ( S == E ) continue; - // for ( TopExp_Explorer exp(S,TopAbs_EDGE); exp.More(); exp.Next() ) - // sewd->Add ( exp.Current(), i++ ); - // sewd->Remove ( i-- ); - // } - // change sewd and boxes sewd->Set(newE1, num); if (num == sewd->NbEdges()) @@ -2740,9 +2615,6 @@ Standard_Boolean ShapeFix_Face::FixSplitFace(const TopTools_DataMapOfShapeListOf V2 = sae.LastVertex(E2); if (!V1.IsSame(V2)) { -#ifdef OCCT_DEBUG - std::cout << "wire not closed --> stop split" << std::endl; -#endif return Standard_False; } // create face diff --git a/tests/bugs/modalg_8/bug33895 b/tests/bugs/modalg_8/bug33895 new file mode 100644 index 0000000000..6f65d9c040 --- /dev/null +++ b/tests/bugs/modalg_8/bug33895 @@ -0,0 +1,21 @@ +puts "========================================================================" +puts "Bug 33895: fixshape crashes on tessellated geometry without surfaces" +puts "No crash expected" +puts "========================================================================" + +pload XDE MODELING + +stepread [locate_data_file gh623_tessellated_tetrahedron_ap242.step] anInputShape * + +# Check what kind of shape we get +checknbshapes anInputShape_1 -t + +# Validate shape - will show BRepCheck_NoSurface errors +puts "REQUIRED All: Faulty shapes in variables faulty_1 to faulty_6" +checkshape anInputShape_1 + +# Fix shapes. No crash expected. +fixshape aFixed anInputShape_1 + +# Check result. +checknbshapes aFixed -face 4 -shell 4 -compound 1 -shape 9 -t -- 2.39.5