0031307: Modeling Algorithms - Offset algorithm produces incorrect result in mode...
[occt.git] / src / BRepOffset / BRepOffset_MakeOffset_1.cxx
index f78f8cc..6462ea6 100644 (file)
@@ -70,6 +70,8 @@
 
 typedef NCollection_DataMap
   <TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> BRepOffset_DataMapOfShapeMapOfShape;
+typedef NCollection_DataMap
+  <TopoDS_Shape, TopTools_IndexedMapOfShape, TopTools_ShapeMapHasher> BRepOffset_DataMapOfShapeIndexedMapOfShape;
 
 static
   void IntersectTrimmedEdges(const TopTools_ListOfShape& theLF,
@@ -161,24 +163,25 @@ static
                         const TopTools_DataMapOfShapeListOfShape& theOEOrigins,
                         TopTools_IndexedMapOfShape& theInvEdges,
                         TopTools_IndexedMapOfShape& theValidEdges,
-                        TopTools_DataMapOfShapeListOfShape& theDMFLVE,
-                        TopTools_DataMapOfShapeListOfShape& theDMFLNE,
-                        TopTools_DataMapOfShapeListOfShape& theDMFLIE,
-                        TopTools_DataMapOfShapeListOfShape& theDMFLVIE,
+                        BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
+                        BRepOffset_DataMapOfShapeMapOfShape& theDMFMNE,
+                        BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
+                        BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE,
                         TopTools_DataMapOfShapeListOfShape& theDMEOrLEIm,
                         TopTools_MapOfShape& theMEInverted,
-                        TopTools_MapOfShape& theEdgesInvalidByVertex);
+                        TopTools_MapOfShape& theEdgesInvalidByVertex,
+                        TopTools_MapOfShape& theEdgesValidByVertex);
 
 static
   void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
                         const TopTools_IndexedMapOfShape& theInvEdges,
                         const TopTools_IndexedMapOfShape& theValidEdges,
-                        const TopTools_DataMapOfShapeListOfShape& theDMFLVE,
-                        const TopTools_DataMapOfShapeListOfShape& theDMFLIE,
-                        const TopTools_ListOfShape& theLENeutral,
-                        const TopTools_ListOfShape& theLEValInverted,
+                        const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
+                        const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
+                        const TopTools_MapOfShape& theLENeutral,
                         const TopTools_MapOfShape& theMEInverted,
                         const TopTools_MapOfShape& theEdgesInvalidByVertex,
+                        const TopTools_MapOfShape& theEdgesValidByVertex,
                         const TopTools_MapOfShape& theMFHoles,
                         TopTools_IndexedMapOfShape& theMFInvInHole,
                         TopTools_ListOfShape& theInvFaces,
@@ -234,6 +237,7 @@ static
   void RemoveInvalidSplitsFromValid(const TopTools_IndexedDataMapOfShapeListOfShape& theInvFaces,
                                     const TopTools_DataMapOfShapeShape& theArtInvFaces,
                                     const TopTools_MapOfShape& theMEInverted,
+                                    const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE,
                                     TopTools_IndexedDataMapOfShapeListOfShape& theFImages);
 
 static
@@ -286,8 +290,9 @@ static
                          TopTools_DataMapOfShapeListOfShape& theOEOrigins);
 
 static
-  void FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
+  void FilterInvalidFaces(TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
                           const TopTools_IndexedDataMapOfShapeListOfShape& theDMEF,
+                          const TopTools_IndexedMapOfShape& theInvEdges,
                           const TopTools_IndexedMapOfShape& theMERemoved,
                           TopTools_IndexedDataMapOfShapeListOfShape& theInvFaces,
                           TopTools_DataMapOfShapeShape& theArtInvFaces);
@@ -295,7 +300,7 @@ static
 static
   void FilterInvalidEdges(const TopTools_IndexedDataMapOfShapeListOfShape& theInvFaces,
                           const TopTools_DataMapOfShapeShape& theArtInvFaces,
-                          const TopTools_DataMapOfShapeListOfShape& theDMFLIE,
+                          const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
                           const TopTools_IndexedMapOfShape& theMERemoved,
                           TopTools_IndexedMapOfShape& theInvEdges);
 
@@ -836,18 +841,20 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
   //
   // processed faces
   TopTools_ListOfShape aLFDone;
-  // extended face - list of neutral edges, i.e. in one splits - valid and in others - invalid
-  TopTools_DataMapOfShapeListOfShape aDMFLNE;
-  // list of valid edges for each face
-  TopTools_DataMapOfShapeListOfShape aDMFLVE;
-  // list of invalid edges for each face
-  TopTools_DataMapOfShapeListOfShape aDMFLIE;
+  // extended face - map of neutral edges, i.e. in one split - valid and in other - invalid
+  BRepOffset_DataMapOfShapeMapOfShape aDMFMNE;
+  // map of valid edges for each face
+  BRepOffset_DataMapOfShapeMapOfShape aDMFMVE;
+  // map of invalid edges for each face
+  BRepOffset_DataMapOfShapeIndexedMapOfShape aDMFMIE;
   // map of valid inverted edges for the face
-  TopTools_DataMapOfShapeListOfShape aDMFLVIE;
+  BRepOffset_DataMapOfShapeMapOfShape aDMFMVIE;
   // map of splits to check for internals
   TopTools_IndexedMapOfShape aMFToCheckInt;
   // map of edges created from vertex and marked as invalid
   TopTools_MapOfShape aMEdgeInvalidByVertex;
+  // map of edges created from vertex and marked as valid
+  TopTools_MapOfShape aMEdgeValidByVertex;
   // connection map from old edges to new ones
   TopTools_DataMapOfShapeListOfShape aDMEOrLEIm;
   //
@@ -937,7 +944,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
       }
       //
       if (bArtificialCase) {
-        TopTools_ListOfShape aLEInv;
+        TopTools_IndexedMapOfShape aMEInv;
         // make the face invalid
         theArtInvFaces.Bind(aF, aCE);
         //
@@ -950,7 +957,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
             const TopoDS_Shape& aE = aExpE.Current();
             if (aMapEInv.Contains(aE)) {
               theInvEdges.Add(aE);
-              AppendToList(aLEInv, aE);
+              aMEInv.Add (aE);
             }
             else {
               theValidEdges.Add(aE);
@@ -958,7 +965,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
           }
         }
         //
-        aDMFLIE.Bind(aF, aLEInv);
+        aDMFMIE.Bind(aF, aMEInv);
         aLFDone.Append(aF);
         //
         continue;
@@ -967,8 +974,8 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
     //
     // find invalid edges
     FindInvalidEdges(aF, aLFImages, theEdgesOrigins, theFacesOrigins, theAnalyse, theOEImages,
-                     theOEOrigins, theInvEdges, theValidEdges, aDMFLVE, aDMFLNE, aDMFLIE,
-                     aDMFLVIE, aDMEOrLEIm, theInvertedEdges, aMEdgeInvalidByVertex);
+                     theOEOrigins, theInvEdges, theValidEdges, aDMFMVE, aDMFMNE, aDMFMIE,
+                     aDMFMVIE, aDMEOrLEIm, theInvertedEdges, aMEdgeInvalidByVertex, aMEdgeValidByVertex);
     //
     // save the new splits
     if (!pLFIm) {
@@ -982,7 +989,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
     aLFDone.Append(aF);
   }
   //
-  if (theInvEdges.IsEmpty() && theArtInvFaces.IsEmpty()) {
+  if (theInvEdges.IsEmpty() && theArtInvFaces.IsEmpty() && aDMFMIE.IsEmpty()) {
     return;
   }
   //
@@ -1035,7 +1042,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
     }
   }
 
-  TopTools_ListOfShape anEmptyList;
+  TopTools_MapOfShape anEmptyMap;
   // invalid faces inside the holes
   TopTools_IndexedMapOfShape aMFInvInHole;
   // all hole faces
@@ -1055,18 +1062,13 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
     if (bArtificialCase) {
       aLFInv = aLFImages;
     }
-    else {
+    else
+    {
       // neutral edges
-      TopTools_ListOfShape* pLNE = aDMFLNE.ChangeSeek(aF);
-      if (!pLNE) {
-        pLNE = &anEmptyList;
-      }
-      // valid inverted edges
-      TopTools_ListOfShape* pLIVE = aDMFLVIE.ChangeSeek(aF);
-      if (!pLIVE) {
-        pLIVE = &anEmptyList;
+      const TopTools_MapOfShape* pMNE = aDMFMNE.ChangeSeek(aF);
+      if (!pMNE) {
+        pMNE = &anEmptyMap;
       }
-      //
       // find faces inside holes wires
       TopTools_MapOfShape aMFHoles;
       const TopoDS_Face& aFOr = TopoDS::Face(theFacesOrigins.Find(aF));
@@ -1079,8 +1081,8 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
       }
       //
       // find invalid faces
-      FindInvalidFaces(aLFImages, theInvEdges, theValidEdges, aDMFLVE, aDMFLIE,
-                       *pLNE, *pLIVE, theInvertedEdges, aMEdgeInvalidByVertex,
+      FindInvalidFaces(aLFImages, theInvEdges, theValidEdges, aDMFMVE, aDMFMIE,
+                       *pMNE, theInvertedEdges, aMEdgeInvalidByVertex, aMEdgeValidByVertex,
                        aMFHoles, aMFInvInHole, aLFInv, anInvertedFaces);
     }
     //
@@ -1128,7 +1130,8 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
   }
   //
   // remove invalid splits from valid splits
-  RemoveInvalidSplitsFromValid(theInvFaces, theArtInvFaces, theInvertedEdges, theFImages);
+  RemoveInvalidSplitsFromValid (theInvFaces, theArtInvFaces, theInvertedEdges,
+                                aDMFMVIE, theFImages);
   //
   // remove inside faces
   TopTools_IndexedMapOfShape aMEInside;
@@ -1157,7 +1160,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
   FilterEdgesImages(aCFIm, theOEImages, theOEOrigins);
   //
   // filter invalid faces
-  FilterInvalidFaces(theFImages, aDMEF, aMEInside, theInvFaces, theArtInvFaces);
+  FilterInvalidFaces(theFImages, aDMEF, theInvEdges, aMEInside, theInvFaces, theArtInvFaces);
   aNb = theInvFaces.Extent();
   if (!aNb) {
     theInvEdges.Clear();
@@ -1180,7 +1183,7 @@ void BuildSplitsOfFaces(const TopTools_ListOfShape& theLF,
 #endif
   //
   // filter invalid edges
-  FilterInvalidEdges(theInvFaces, theArtInvFaces, aDMFLIE, aMERemoved, theInvEdges);
+  FilterInvalidEdges(theInvFaces, theArtInvFaces, aDMFMIE, aMERemoved, theInvEdges);
   //
 #ifdef OFFSET_DEBUG
   // show invalid edges
@@ -1562,13 +1565,14 @@ void FindInvalidEdges(const TopoDS_Face& theF,
                       const TopTools_DataMapOfShapeListOfShape& theOEOrigins,
                       TopTools_IndexedMapOfShape& theInvEdges,
                       TopTools_IndexedMapOfShape& theValidEdges,
-                      TopTools_DataMapOfShapeListOfShape& theDMFLVE,
-                      TopTools_DataMapOfShapeListOfShape& theDMFLNE,
-                      TopTools_DataMapOfShapeListOfShape& theDMFLIE,
-                      TopTools_DataMapOfShapeListOfShape& theDMFLVIE,
+                      BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
+                      BRepOffset_DataMapOfShapeMapOfShape& theDMFMNE,
+                      BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
+                      BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE,
                       TopTools_DataMapOfShapeListOfShape& theDMEOrLEIm,
                       TopTools_MapOfShape& theMEInverted,
-                      TopTools_MapOfShape& theEdgesInvalidByVertex)
+                      TopTools_MapOfShape& theEdgesInvalidByVertex,
+                      TopTools_MapOfShape& theEdgesValidByVertex)
 {
   // Edge is considered as invalid in the following cases:
   // 1. Its orientation on the face has changed comparing to the originals edge and face;
@@ -1590,6 +1594,8 @@ void FindInvalidEdges(const TopoDS_Face& theF,
   // maps for checking the inverted edges
   TopTools_IndexedDataMapOfShapeListOfShape aDMVE, aDMEF;
   TopTools_IndexedMapOfShape aMEdges;
+  // back map from the original shapes to their offset images
+  TopTools_DataMapOfShapeListOfShape anImages;
   //
   TopTools_ListIteratorOfListOfShape aItLF(theLFImages);
   for (; aItLF.More(); aItLF.Next()) {
@@ -1619,6 +1625,22 @@ void FindInvalidEdges(const TopoDS_Face& theF,
         }
         AppendToList(*pLE, aE);
       }
+
+      // back map from original edges to their offset images
+      const TopTools_ListOfShape* pLOr = theEdgesOrigins.Seek (aE);
+      if (!pLOr)
+        continue;
+      for (TopTools_ListOfShape::Iterator itOr (*pLOr); itOr.More(); itOr.Next())
+      {
+        const TopoDS_Shape& aSOr = itOr.Value();
+        TopoDS_Shape aSInF;
+        if (!FindShape (aSOr, aFOr, theAnalyse, aSInF))
+          continue;
+        TopTools_ListOfShape* pImages = anImages.ChangeSeek (aSInF);
+        if (!pImages)
+          pImages = anImages.Bound (aSInF, TopTools_ListOfShape());
+        AppendToList (*pImages, aE);
+      }
     }
   }
   //
@@ -1631,9 +1653,9 @@ void FindInvalidEdges(const TopoDS_Face& theF,
     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
     //
     // valid edges for this split
-    TopTools_ListOfShape aLVE;
+    TopTools_MapOfShape aMVE;
     // invalid edges for this split
-    TopTools_ListOfShape aLIE;
+    TopTools_IndexedMapOfShape aMIE;
     //
     TopExp_Explorer aExp(aFIm, TopAbs_EDGE);
     for (; aExp.More(); aExp.Next()) {
@@ -1660,6 +1682,8 @@ void FindInvalidEdges(const TopoDS_Face& theF,
           ++aNbVOr;
         }
       }
+      if (aNbVOr > 1 && (aLEOr.Extent() - aNbVOr) > 1)
+        continue;
       //
       TopTools_MapOfShape aME, aMV, aMF;
       Standard_Boolean bInvalid = Standard_False, bChecked = Standard_False;
@@ -1690,12 +1714,22 @@ void FindInvalidEdges(const TopoDS_Face& theF,
           if (pLEFOr) {
             TopoDS_Compound aCEOr;
             BRep_Builder().MakeCompound(aCEOr);
+            // Avoid classification of edges originated from vertices
+            // located between tangent edges
+            Standard_Boolean bAllTgt = Standard_True;
             TopTools_ListIteratorOfListOfShape aItLEFOr(*pLEFOr);
-            for (; aItLEFOr.More(); aItLEFOr.Next()) {
+            gp_Vec aVRef = GetAverageTangent (aItLEFOr.Value(), aNbP);
+            for (; aItLEFOr.More(); aItLEFOr.Next())
+            {
               const TopoDS_Shape& aEOr = aItLEFOr.Value();
               BRep_Builder().Add(aCEOr, aEOr);
+
+              gp_Vec aVCur = GetAverageTangent (aEOr, aNbP);
+              if (!aVRef.IsParallel (aVCur, Precision::Angular()))
+                bAllTgt = Standard_False;
             }
-            aEOrF = aCEOr;
+            if (!bAllTgt)
+              aEOrF = aCEOr;
           }
         }
         else {
@@ -1712,22 +1746,56 @@ void FindInvalidEdges(const TopoDS_Face& theF,
           // the edge has not been found
           continue;
         }
-        //
-        // Check orientations of the image edge and original edge.
-        // In case the 3d curves are having the same direction the orientations 
-        // must be the same. Otherwise the orientations should also be different.
-        //
-        // get average tangent vector for each curve taking into account
-        // the orientations of the edges, i.e. the edge is reversed
-        // the vector is reversed as well
-        gp_Vec aVSum1 = GetAverageTangent(aEIm, aNbP);
-        gp_Vec aVSum2 = GetAverageTangent(aEOrF, aNbP);
-        //
-        aVSum1.Normalize();
-        aVSum2.Normalize();
-        //
-        Standard_Real aCos = aVSum1.Dot(aVSum2);
-        if (!bVertex) {
+
+        if (bVertex)
+        {
+          TopTools_MapOfShape aMVTotal;
+          Standard_Integer aNbChecked = 0;
+          // Just check if the original edges sharing the vertex do not share it any more.
+          for (TopoDS_Iterator it (aEOrF); it.More(); it.Next())
+          {
+            const TopoDS_Shape& aEOr = it.Value();
+            const TopTools_ListOfShape* aLIm = anImages.Seek (aEOr);
+            if (!aLIm)
+              continue;
+            ++aNbChecked;
+            TopTools_IndexedDataMapOfShapeListOfShape aMVLoc;
+            for (TopTools_ListOfShape::Iterator itLIM (*aLIm); itLIM.More(); itLIM.Next())
+              TopExp::MapShapesAndAncestors (itLIM.Value(), TopAbs_VERTEX, TopAbs_EDGE, aMVLoc);
+            for (Standard_Integer i = 1; i <= aMVLoc.Extent(); ++i)
+            {
+              if (aMVLoc(i).Extent() > 1 && !aMVTotal.Add (aMVLoc.FindKey (i)))
+              {
+                bInvalid = Standard_True;
+                theEdgesInvalidByVertex.Add(aEIm);
+                break;
+              }
+            }
+            if (bInvalid)
+              break;
+          }
+          if (!bInvalid && aNbChecked < 2)
+            continue;
+          else
+            theEdgesValidByVertex.Add (aEIm);
+        }
+        else
+        {
+          //
+          // Check orientations of the image edge and original edge.
+          // In case the 3d curves are having the same direction the orientations 
+          // must be the same. Otherwise the orientations should also be different.
+          //
+          // get average tangent vector for each curve taking into account
+          // the orientations of the edges, i.e. the edge is reversed
+          // the vector is reversed as well
+          gp_Vec aVSum1 = GetAverageTangent(aEIm, aNbP);
+          gp_Vec aVSum2 = GetAverageTangent(aEOrF, aNbP);
+          //
+          aVSum1.Normalize();
+          aVSum2.Normalize();
+          //
+          Standard_Real aCos = aVSum1.Dot(aVSum2);
           if (Abs(aCos) < 0.9999) {
             continue;
           }
@@ -1744,13 +1812,10 @@ void FindInvalidEdges(const TopoDS_Face& theF,
                  itFA.More(); itFA.Next())
               aMF.Add (itFA.Value());
           }
-        }
-        //
-        if (aCos < Precision::Confusion()) {
-          bInvalid = Standard_True;
-          aNbInv++;
-          if (bVertex) {
-            theEdgesInvalidByVertex.Add(aEIm);
+          //
+          if (aCos < Precision::Confusion()) {
+            bInvalid = Standard_True;
+            aNbInv++;
           }
         }
         bChecked = Standard_True;
@@ -1760,7 +1825,7 @@ void FindInvalidEdges(const TopoDS_Face& theF,
         continue;
       }
       //
-      Standard_Boolean bLocalOnly = Standard_False;
+      Standard_Boolean bLocalOnly = (aNbVOr > 1 && (aLEOr.Extent() - aNbVOr) > 1);
       Standard_Integer aNbE = aME.Extent(), aNbV = aMV.Extent();
       if (aNbE > 1 && aNbV == 2*aNbE)
       {
@@ -1796,7 +1861,7 @@ void FindInvalidEdges(const TopoDS_Face& theF,
       if (bInvalid) {
         if (!bLocalOnly)
           theInvEdges.Add(aEIm);
-        aLIE.Append(aEIm);
+        aMIE.Add (aEIm);
         aMEInv.Add(aEIm);
         continue;
       }
@@ -1809,27 +1874,29 @@ void FindInvalidEdges(const TopoDS_Face& theF,
       if (!bInverted || !aNbVOr) {
         if (!bLocalOnly)
           theValidEdges.Add(aEIm);
-        aLVE.Append(aEIm);
+        aMVE.Add (aEIm);
         aMEVal.Add(aEIm);
       }
     }
     //
     // valid edges
-    if (aLVE.Extent()) {
-      theDMFLVE.Bind(aFIm, aLVE);
+    if (aMVE.Extent())
+    {
+      theDMFMVE.Bind (aFIm, aMVE);
     }
     //
     // invalid edges
-    if (aLIE.Extent()) {
-      theDMFLIE.Bind(aFIm, aLIE);
+    if (aMIE.Extent())
+    {
+      theDMFMIE.Bind (aFIm, aMIE);
     }
   }
   //
   // process invalid edges:
   // check for the inverted edges
-  TopTools_ListOfShape aLVIE;
+  TopTools_MapOfShape aMVIE;
   // fill neutral edges
-  TopTools_ListOfShape aLNE;
+  TopTools_MapOfShape aMNE;
   //
   Standard_Integer i, aNbEInv = aMEInv.Extent();
   for (i = 1; i <= aNbEInv; ++i) {
@@ -1837,8 +1904,9 @@ void FindInvalidEdges(const TopoDS_Face& theF,
     //
     // neutral edges - on the splits of the same offset face
     // it is valid for one split and invalid for other
-    if (aMEVal.Contains(aEIm)) {
-      aLNE.Append(aEIm);
+    if (aMEVal.Contains(aEIm))
+    {
+      aMNE.Add (aEIm);
       continue;
     }
     //
@@ -1864,18 +1932,20 @@ void FindInvalidEdges(const TopoDS_Face& theF,
             !aMEInv.Contains(aEIm1) && !aMEInt.Contains(aEIm1) &&
             theMEInverted.Contains(aEIm1)) {
           theInvEdges.Add(aEIm1);
-          aLVIE.Append(aEIm1);
+          aMVIE.Add (aEIm1);
         }
       }
     }
   }
   //
-  if (aLNE.Extent()) {
-    theDMFLNE.Bind(theF, aLNE);
+  if (aMNE.Extent())
+  {
+    theDMFMNE.Bind (theF, aMNE);
   }
   //
-  if (aLVIE.Extent()) {
-    theDMFLVIE.Bind(theF, aLVIE);
+  if (aMVIE.Extent())
+  {
+    theDMFMVIE.Bind (theF, aMVIE);
   }
 }
 
@@ -1886,12 +1956,12 @@ void FindInvalidEdges(const TopoDS_Face& theF,
 void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
                       const TopTools_IndexedMapOfShape& theInvEdges,
                       const TopTools_IndexedMapOfShape& theValidEdges,
-                      const TopTools_DataMapOfShapeListOfShape& theDMFLVE,
-                      const TopTools_DataMapOfShapeListOfShape& theDMFLIE,
-                      const TopTools_ListOfShape& theLENeutral,
-                      const TopTools_ListOfShape& theLEValInverted,
+                      const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVE,
+                      const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
+                      const TopTools_MapOfShape& theMENeutral,
                       const TopTools_MapOfShape& theMEInverted,
                       const TopTools_MapOfShape& theEdgesInvalidByVertex,
+                      const TopTools_MapOfShape& theEdgesValidByVertex,
                       const TopTools_MapOfShape& theMFHoles,
                       TopTools_IndexedMapOfShape& theMFInvInHole,
                       TopTools_ListOfShape& theInvFaces,
@@ -1910,21 +1980,7 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
   Standard_Boolean bHasValid, bAllValid, bAllInvalid, bHasReallyInvalid, bAllInvNeutral;
   Standard_Boolean bValid, bValidLoc, bInvalid, bInvalidLoc, bNeutral, bInverted;
   Standard_Boolean bIsInvalidByInverted;
-  Standard_Integer i, aNbChecked;
-  //
-  // neutral edges
-  TopTools_MapOfShape aMEN;
-  for (TopTools_ListIteratorOfListOfShape aItLE(theLENeutral); aItLE.More(); aItLE.Next())
-  {
-    aMEN.Add(aItLE.Value());
-  }
-  //
-  // valid inverted edges
-  TopTools_MapOfShape aMEValInverted;
-  for (TopTools_ListIteratorOfListOfShape aItLE(theLEValInverted); aItLE.More(); aItLE.Next())
-  {
-    aMEValInverted.Add(aItLE.Value());
-  }
+  Standard_Integer aNbChecked;
   //
   Standard_Boolean bTreatInvertedAsInvalid = (theLFImages.Extent() == 1);
   //
@@ -1934,26 +1990,22 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
   // faces for post treat
   TopTools_ListOfShape aLFPT;
   //
+  TopTools_IndexedDataMapOfShapeListOfShape aDMEF;
   TopTools_ListIteratorOfListOfShape aItLF(theLFImages);
+  for (; aItLF.More(); aItLF.Next())
+  {
+    const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
+    TopExp::MapShapesAndAncestors (aFIm, TopAbs_EDGE, TopAbs_FACE, aDMEF);
+  }
+
+  aItLF.Initialize (theLFImages);
   for (; aItLF.More(); ) {
     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
     //
     // valid edges for this split
-    TopTools_MapOfShape aMVE;
+    const TopTools_MapOfShape* pMVE = theDMFMVE.Seek (aFIm);
     // invalid edges for this split
-    TopTools_MapOfShape aMIE;
-    //
-    for (i = 0; i < 2; ++i) {
-      TopTools_MapOfShape& aME = !i ? aMVE : aMIE;
-      const TopTools_ListOfShape* pLE = !i ? theDMFLVE.Seek(aFIm) : theDMFLIE.Seek(aFIm);
-      if (pLE) {
-        TopTools_ListIteratorOfListOfShape aItLE(*pLE);
-        for (; aItLE.More(); aItLE.Next()) {
-          const TopoDS_Shape& aE = aItLE.Value();
-          aME.Add(aE);
-        }
-      }
-    }
+    const TopTools_IndexedMapOfShape* pMIE = theDMFMIE.Seek (aFIm);
     //
     bHasValid = Standard_False;
     bAllValid = Standard_True;
@@ -1970,29 +2022,34 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
       //
       bValid = theValidEdges.Contains(aEIm);
       bInvalid = theInvEdges.Contains(aEIm);
-      bNeutral = aMEN.Contains(aEIm);
+      bNeutral = theMENeutral.Contains(aEIm);
       //
       if (!bValid && !bInvalid && !bNeutral) {
         // edge has not been checked for some reason
         continue;
       }
-      //
+
+      // skip not-boundary edges originated from vertex
+      if ((theEdgesInvalidByVertex.Contains (aEIm) ||
+           theEdgesValidByVertex.Contains (aEIm)) &&
+           aDMEF.FindFromKey (aEIm).Extent() != 1)
+        continue;
+
       ++aNbChecked;
       //
-      bInvalidLoc = aMIE.Contains(aEIm);
+      bInvalidLoc = pMIE && pMIE->Contains (aEIm);
       bHasReallyInvalid = bInvalid && bInvalidLoc && !bValid && !theEdgesInvalidByVertex.Contains(aEIm);
       if (bHasReallyInvalid) {
         break;
       }
       //
-      bValidLoc = aMVE.Contains(aEIm);
-      //
+      bValidLoc = pMVE && pMVE->Contains(aEIm);
       bInverted = theMEInverted.Contains(aEIm);
       if (!bInvalid && !bInvalidLoc && bTreatInvertedAsInvalid) {
         bInvalid = bInverted;
       }
       //
-      if (bValidLoc && (bNeutral || aMEValInverted.Contains(aEIm))) {
+      if (bValidLoc && bNeutral) {
         bHasValid = Standard_True;
       }
       //
@@ -2053,27 +2110,14 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
   if (aLFPT.IsEmpty() || aMENRem.IsEmpty()) {
     return;
   }
-  //
-  Standard_Integer aNb = aMENRem.Extent();
-  for (i = 1; i <= aNb; ++i) {
-    aMEN.Remove(aMENRem(i));
-  }
-  //
+
   // check the splits once more
   aItLF.Initialize(aLFPT);
   for (; aItLF.More(); aItLF.Next()) {
     const TopoDS_Face& aFIm = *(TopoDS_Face*)&aItLF.Value();
     //
     // valid edges for this split
-    TopTools_MapOfShape aMVE;
-    const TopTools_ListOfShape* pLVE = theDMFLVE.Seek(aFIm);
-    if (pLVE) {
-      TopTools_ListIteratorOfListOfShape aItLE(*pLVE);
-      for (; aItLE.More(); aItLE.Next()) {
-        const TopoDS_Shape& aE = aItLE.Value();
-        aMVE.Add(aE);
-      }
-    }
+    const TopTools_MapOfShape* pMVE = theDMFMVE.Seek(aFIm);
     //
     bHasValid = Standard_False;
     bAllValid = Standard_True;
@@ -2086,14 +2130,14 @@ void FindInvalidFaces(TopTools_ListOfShape& theLFImages,
       //
       bValid = theValidEdges.Contains(aEIm);
       bInvalid = theInvEdges.Contains(aEIm);
-      bNeutral = aMEN.Contains(aEIm);
-      bValidLoc = aMVE.Contains(aEIm);
+      bNeutral = theMENeutral.Contains(aEIm) && !aMENRem.Contains (aEIm);
+      bValidLoc = pMVE && pMVE->Contains(aEIm);
       //
       if (!bInvalid && bTreatInvertedAsInvalid) {
         bInvalid = theMEInverted.Contains(aEIm);
       }
       //
-      if (bValidLoc && (bNeutral || aMEValInverted.Contains(aEIm))) {
+      if (bValidLoc && bNeutral) {
         bHasValid = Standard_True;
       }
       //
@@ -2836,6 +2880,7 @@ void RemoveInvalidSplitsByInvertedEdges(const TopTools_MapOfShape& theMEInverted
 void RemoveInvalidSplitsFromValid(const TopTools_IndexedDataMapOfShapeListOfShape& theInvFaces,
                                   const TopTools_DataMapOfShapeShape& theArtInvFaces,
                                   const TopTools_MapOfShape& theMEInverted,
+                                  const BRepOffset_DataMapOfShapeMapOfShape& theDMFMVIE,
                                   TopTools_IndexedDataMapOfShapeListOfShape& theFImages)
 {
   // Decide whether to remove the found invalid faces or not.
@@ -2911,22 +2956,49 @@ void RemoveInvalidSplitsFromValid(const TopTools_IndexedDataMapOfShapeListOfShap
     TopTools_IndexedDataMapOfShapeListOfShape aDMEF;
     TopExp::MapShapesAndAncestors(aCB, TopAbs_EDGE, TopAbs_FACE, aDMEF);
     //
+    TopTools_DataMapOfShapeListOfShape aDMFF;
     aExp.Init(aCB, TopAbs_FACE);
     for (; aExp.More(); aExp.Next()) {
       const TopoDS_Shape& aFCB = aExp.Current();
-      //
-      TopExp_Explorer aExpE(aFCB, TopAbs_EDGE);
-      for (; aExpE.More(); aExpE.Next()) {
-        const TopoDS_Shape& aECB = aExpE.Current();
-        if (aDMEF.FindFromKey(aECB).Extent() > 1) {
-          if (!theMEInverted.Contains(aECB)) {
+      const TopoDS_Shape& aF = aDMIFOF.Find (aFCB);
+      TopTools_ListOfShape* pList = aDMFF.ChangeSeek (aF);
+      if (!pList)
+        pList = aDMFF.Bound (aF, TopTools_ListOfShape());
+      pList->Append (aFCB);
+    }
+
+    for (TopTools_DataMapOfShapeListOfShape::Iterator itM (aDMFF); itM.More(); itM.Next())
+    {
+      const TopoDS_Shape& aF = itM.Key();
+      const TopTools_MapOfShape* pValidInverted = theDMFMVIE.Seek (aF);
+
+      // either remove all of these faces or none.
+      const TopTools_ListOfShape& aLFCB = itM.Value();
+      TopTools_ListOfShape::Iterator itL (aLFCB);
+      for (; itL.More(); itL.Next())
+      {
+        const TopoDS_Shape& aFCB = itL.Value();
+        TopExp_Explorer aExpE(aFCB, TopAbs_EDGE);
+        for (; aExpE.More(); aExpE.Next()) {
+          const TopoDS_Shape& aECB = aExpE.Current();
+          if (pValidInverted && pValidInverted->Contains (aECB))
             break;
+          if (aDMEF.FindFromKey(aECB).Extent() > 1)
+          {
+            if (!theMEInverted.Contains(aECB))
+              break;
           }
         }
+        if (!aExpE.More())
+          // if one removed - remove all
+          break;
       }
-      //
-      if (!aExpE.More()) {
-        aMFToRem.Add(aFCB);
+      if (itL.More())
+      {
+        for (itL.Initialize (aLFCB); itL.More(); itL.Next())
+        {
+          aMFToRem.Add (itL.Value());
+        }
       }
     }
   }
@@ -3752,8 +3824,9 @@ void FilterEdgesImages(const TopoDS_Shape& theS,
 //function : FilterInvalidFaces
 //purpose  : Filtering of the invalid faces
 //=======================================================================
-void FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
+void FilterInvalidFaces(TopTools_IndexedDataMapOfShapeListOfShape& theFImages,
                         const TopTools_IndexedDataMapOfShapeListOfShape& theDMEF,
+                        const TopTools_IndexedMapOfShape& theInvEdges,
                         const TopTools_IndexedMapOfShape& theMERemoved,
                         TopTools_IndexedDataMapOfShapeListOfShape& theInvFaces,
                         TopTools_DataMapOfShapeShape& theArtInvFaces)
@@ -3764,10 +3837,12 @@ void FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFIma
   // do not remove invalid faces if it creates free edges
   //
   TopTools_IndexedDataMapOfShapeListOfShape aReallyInvFaces;
+  // Edge-Face connexity map of all splits, both invalid and valid
+  TopTools_IndexedDataMapOfShapeListOfShape aDMEFAll;
   TopTools_ListIteratorOfListOfShape aItLF;
   //
-  Standard_Integer i, aNb = theInvFaces.Extent();
-  for (i = 1; i <= aNb; ++i) {
+  const Standard_Integer aNb = theInvFaces.Extent();
+  for (Standard_Integer i = 1; i <= aNb; ++i) {
     const TopoDS_Shape& aF = theInvFaces.FindKey(i);
     const TopTools_ListOfShape& aLFInv = theInvFaces(i);
     //
@@ -3785,7 +3860,7 @@ void FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFIma
       continue;
     }
     //
-    const TopTools_ListOfShape& aLFIm = theFImages.FindFromKey(aF);
+    TopTools_ListOfShape& aLFIm = theFImages.ChangeFromKey(aF);
     Standard_Boolean bInvalid = aLFIm.IsEmpty();
     //
     if (!bInvalid) {
@@ -3837,6 +3912,55 @@ void FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFIma
         bInvalid = aItLF.More();
       }
     }
+    if (bInvalid)
+    {
+      if (aDMEFAll.IsEmpty())
+      {
+        aDMEFAll = theDMEF;
+        for (Standard_Integer iF = 1; iF <= aNb; ++iF)
+          for (TopTools_ListOfShape::Iterator itLFInv (theInvFaces(iF)); itLFInv.More(); itLFInv.Next())
+            TopExp::MapShapesAndAncestors (itLFInv.Value(), TopAbs_EDGE, TopAbs_FACE, aDMEFAll);
+      }
+
+      TopTools_MapOfShape aLocalSplits;
+      for (Standard_Integer j = 0; j < 2; ++j)
+        for (aItLF.Initialize((!j ? aLFIm : aLFInv)); aItLF.More(); aItLF.Next())
+          aLocalSplits.Add (aItLF.Value());
+
+      // Check if all invalid edges are located inside the split and do not touch
+      // any other faces both invalid and valid
+      aItLF.Initialize(aLFInv);
+      for (; aItLF.More(); aItLF.Next())
+      {
+        const TopoDS_Shape& aFIm = aItLF.Value();
+        TopExp_Explorer aExp(aFIm, TopAbs_EDGE);
+        for (; aExp.More(); aExp.Next())
+        {
+          const TopoDS_Shape& aE = aExp.Current();
+          if (theInvEdges.Contains (aE) && !theMERemoved.Contains (aE))
+          {
+            const TopTools_ListOfShape& aLF = aDMEFAll.FindFromKey (aE);
+            TopTools_ListOfShape::Iterator itLF (aLF);
+            for (; itLF.More(); itLF.Next())
+            {
+              if (!aLocalSplits.Contains (itLF.Value()))
+                break;
+            }
+            if (itLF.More())
+              break;
+          }
+        }
+        if (aExp.More())
+          break;
+      }
+      bInvalid = aItLF.More();
+      if (!bInvalid)
+      {
+        aItLF.Initialize(aLFInv);
+        for (; aItLF.More(); aItLF.Next())
+          AppendToList (aLFIm, aItLF.Value());
+      }
+    }
     //
     if (bInvalid) {
       aReallyInvFaces.Add(aF, aLFInv);
@@ -3852,7 +3976,7 @@ void FilterInvalidFaces(const TopTools_IndexedDataMapOfShapeListOfShape& theFIma
 //=======================================================================
 void FilterInvalidEdges(const TopTools_IndexedDataMapOfShapeListOfShape& theInvFaces,
                         const TopTools_DataMapOfShapeShape& theArtInvFaces,
-                        const TopTools_DataMapOfShapeListOfShape& theDMFLIE,
+                        const BRepOffset_DataMapOfShapeIndexedMapOfShape& theDMFMIE,
                         const TopTools_IndexedMapOfShape& theMERemoved,
                         TopTools_IndexedMapOfShape& theInvEdges)
 {
@@ -3907,10 +4031,11 @@ void FilterInvalidEdges(const TopTools_IndexedDataMapOfShapeListOfShape& theInvF
   for (i = 1; i <= aNb; ++i) {
     const TopoDS_Shape& aF = theInvFaces.FindKey(i);
     if (theArtInvFaces.IsBound(aF)) {
-      const TopTools_ListOfShape& aLEInv = theDMFLIE.Find(aF);
-      aItLF.Initialize(aLEInv);
-      for (; aItLF.More(); aItLF.Next()) {
-        const TopoDS_Shape& aE = aItLF.Value();
+      const TopTools_IndexedMapOfShape& aMIE = theDMFMIE.Find(aF);
+      const Standard_Integer aNbIE = aMIE.Extent();
+      for (Standard_Integer iE = 1; iE <= aNbIE; ++iE)
+      {
+        const TopoDS_Shape& aE = aMIE (iE);
         if (aMEInv.Contains(aE) && !aMEInvToAvoid.Contains(aE)) {
           aReallyInvEdges.Add(aE);
         }