]> OCCT Git - occt.git/commitdiff
Modeling - Fix null surface crash in fixshape (#623)
authorSander Adamson <sander.adamson@cloudnc.com>
Fri, 1 Aug 2025 17:10:21 +0000 (18:10 +0100)
committerGitHub <noreply@github.com>
Fri, 1 Aug 2025 17:10:21 +0000 (18:10 +0100)
- 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

src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Surface.cxx
src/ModelingAlgorithms/TKShHealing/ShapeAnalysis/ShapeAnalysis_Wire.cxx
src/ModelingAlgorithms/TKShHealing/ShapeFix/ShapeFix_Face.cxx
tests/bugs/modalg_8/bug33895 [new file with mode: 0644]

index 557cc67e3d1c4947b948e8c2b610a9d097b533f0..72b993395938ca1cead7116180f32d9705f07705 100644 (file)
@@ -48,6 +48,7 @@
 #include <GeomAdaptor_Surface.hxx>
 #include <gp_Pnt.hxx>
 #include <gp_Pnt2d.hxx>
+#include <Message.hxx>
 #include <Precision.hxx>
 #include <ShapeAnalysis.hxx>
 #include <ShapeAnalysis_Curve.hxx>
@@ -56,6 +57,8 @@
 #include <Standard_Failure.hxx>
 #include <Standard_Type.hxx>
 
+#include <cassert>
+
 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.;
index 3dfe97505cc721f74ece6a8a13dd88798771aa3f..f2b1732753b769351a78e10f38bd2106f40ca975 100644 (file)
@@ -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)
index 129e0b6cabcb4c87d0130e1ee6cde60859944ef5..7376d2dea779c594d280ec420e4faab9539ddde7 100644 (file)
 
 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=size;
-      }
-    }
-    newpreci=sqrt(newpreci)/2.*1.00001;
-    if( aSavPreci > 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 "<<aSeqReversed.Value(k)<<" of "<<nb<<" reversed"<<std::endl; // mise au point !
-// clang-format on
-#endif
-    }
   }
   return done;
 }
@@ -1632,6 +1546,11 @@ static Standard_Boolean CheckWire(const TopoDS_Wire&  wire,
 
 Standard_Boolean ShapeFix_Face::FixMissingSeam()
 {
+  if (mySurf.IsNull())
+  {
+    return Standard_False;
+  }
+
   Standard_Boolean uclosed = mySurf->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 (file)
index 0000000..6f65d9c
--- /dev/null
@@ -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