0027271: Unifysamedomain invalid result
[occt.git] / src / ShapeUpgrade / ShapeUpgrade_UnifySameDomain.cxx
index 2dc4fef..b36a1f7 100644 (file)
 #include <TopTools_SequenceOfShape.hxx>
 #include <gp_Circ.hxx>
 #include <BRepAdaptor_Curve.hxx>
+#include <BRepClass_FaceClassifier.hxx>
+#include <BRepAdaptor_Curve2d.hxx>
+#include <gp_Vec2d.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(ShapeUpgrade_UnifySameDomain,MMgt_TShared)
 
 struct SubSequenceOfEdges
 {
@@ -92,6 +97,42 @@ struct SubSequenceOfEdges
   TopoDS_Edge UnionEdges;
 };
 
+static Standard_Boolean IsLikeSeam(const TopoDS_Edge& anEdge,
+                                   const TopoDS_Face& aFace,
+                                   const Handle(Geom_Surface)& aBaseSurface)
+{
+  if (!aBaseSurface->IsUPeriodic() && !aBaseSurface->IsVPeriodic())
+    return Standard_False;
+
+  BRepAdaptor_Curve2d BAcurve2d(anEdge, aFace);
+  gp_Pnt2d FirstPoint, LastPoint;
+  gp_Vec2d FirstDir, LastDir;
+  BAcurve2d.D1(BAcurve2d.FirstParameter(), FirstPoint, FirstDir);
+  BAcurve2d.D1(BAcurve2d.LastParameter(),  LastPoint,  LastDir);
+  Standard_Real Length = FirstDir.Magnitude();
+  if (Length <= gp::Resolution())
+    return Standard_False;
+  else
+    FirstDir /= Length;
+  Length = LastDir.Magnitude();
+  if (Length <= gp::Resolution())
+    return Standard_False;
+  else
+    LastDir /= Length;
+  
+  Standard_Real Tol = 1.e-7;
+  if (aBaseSurface->IsUPeriodic() &&
+    (Abs(FirstDir.X()) < Tol) &&
+    (Abs(LastDir.X()) < Tol))
+    return Standard_True;
+
+  if (aBaseSurface->IsVPeriodic() &&
+    (Abs(FirstDir.Y()) < Tol) &&
+    (Abs(LastDir.Y()) < Tol))
+    return Standard_True;
+
+  return Standard_False;
+}
 
 //=======================================================================
 //function : AddOrdinaryEdges
@@ -525,6 +566,11 @@ static TopoDS_Edge GlueEdgesWithPCurves(const TopTools_SequenceOfShape& aChain,
   return ResEdge;
 }
 
+//=======================================================================
+//function : MergeSubSeq
+//purpose  : Merges a sequence of edges into one edge if possible
+//=======================================================================
+
 static Standard_Boolean MergeSubSeq(const TopTools_SequenceOfShape& aChain, TopoDS_Edge& OutEdge, double Tol, Standard_Boolean ConcatBSplines) 
 {
   ShapeAnalysis_Edge sae;
@@ -614,24 +660,48 @@ static Standard_Boolean MergeSubSeq(const TopTools_SequenceOfShape& aChain, Topo
     Handle(Geom_Circle) Cir = Handle(Geom_Circle)::DownCast(c3d);
 
     TopoDS_Vertex V1 = sae.FirstVertex(FE);
-    gp_Pnt PV1 = BRep_Tool::Pnt(V1);
     TopoDS_Vertex V2 = sae.LastVertex(TopoDS::Edge(aChain.Last()));
-    gp_Pnt PV2 = BRep_Tool::Pnt(V2);
-    TopoDS_Vertex VM = sae.LastVertex(FE);
-    gp_Pnt PVM = BRep_Tool::Pnt(VM);
-    GC_MakeCircle MC (PV1,PVM,PV2);
     TopoDS_Edge E;
-    if (!MC.IsDone() || MC.Value().IsNull()) {
-      // jfa for Mantis issue 0020228
-      if (PV1.Distance(PV2) > Precision::Confusion())
-        return Standard_False;
+    if (V1.IsSame(V2)) {
       // closed chain
-      B.MakeEdge (E,Cir,Precision::Confusion());
-      B.Add(E,V1);
-      B.Add(E,V2);
-      E.Orientation(FE.Orientation());
+      BRepAdaptor_Curve adef(FE);
+      Handle(Geom_Circle) Cir1;
+      double FP, LP;
+      if ( FE.Orientation() == TopAbs_FORWARD)
+      {
+        FP = adef.FirstParameter();
+        LP = adef.LastParameter();
+      }
+      else
+      {
+        FP = adef.LastParameter();
+        LP = adef.FirstParameter();
+      }
+      if (Abs(FP) < Precision::PConfusion())
+      {
+        B.MakeEdge (E,Cir, Precision::Confusion());
+        B.Add(E,V1);
+        B.Add(E,V2);
+        E.Orientation(FE.Orientation());
+      }
+      else
+      {
+        GC_MakeCircle MC1 (adef.Value(FP), adef.Value((FP + LP) * 0.5), adef.Value(LP));
+        if (MC1.IsDone())
+          Cir1 = MC1.Value();
+        else
+          return Standard_False;
+        B.MakeEdge (E, Cir1, Precision::Confusion());
+        B.Add(E,V1);
+        B.Add(E,V2);
+      }
     }
     else {
+      gp_Pnt PV1 = BRep_Tool::Pnt(V1);
+      gp_Pnt PV2 = BRep_Tool::Pnt(V2);
+      TopoDS_Vertex VM = sae.LastVertex(FE);
+      gp_Pnt PVM = BRep_Tool::Pnt(VM);
+      GC_MakeCircle MC (PV1,PVM,PV2);
       Handle(Geom_Circle) C = MC.Value();
       gp_Pnt P0 = C->Location();
       gp_Dir D1(gp_Vec(P0,PV1));
@@ -704,6 +774,11 @@ static Standard_Boolean MergeSubSeq(const TopTools_SequenceOfShape& aChain, Topo
   return Standard_False;
 }
 
+//=======================================================================
+//function : IsMergingPossible
+//purpose  : Checks if merging of two edges is possible
+//=======================================================================
+
 static Standard_Boolean IsMergingPossible(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2, 
                                           double Tol, const TopTools_MapOfShape& DegEdgeVrt)
 {
@@ -751,6 +826,12 @@ static Standard_Boolean IsMergingPossible(const TopoDS_Edge& edge1, const TopoDS
   return Standard_True;
 }
 
+//=======================================================================
+//function : GenerateSubSeq
+//purpose  : Generates sub-sequences of edges from sequence of edges
+//Edges from each subsequences can be merged into the one edge  
+//=======================================================================
+
 static void GenerateSubSeq (const TopTools_SequenceOfShape& anInpEdgeSeq,
                             NCollection_Sequence<SubSequenceOfEdges>& SeqOfSubSeqOfEdges,
                             Standard_Boolean IsClosed, double Tol, const TopTools_MapOfShape& DegEdgeVrt )
@@ -769,9 +850,9 @@ static void GenerateSubSeq (const TopTools_SequenceOfShape& anInpEdgeSeq,
     isOk = IsMergingPossible(edge1, edge2, Tol, DegEdgeVrt);
     if (!isOk)
     {
-      SubSequenceOfEdges SubSeq;
-      SubSeq.SeqsEdges.Append(edge2);
-      SeqOfSubSeqOfEdges.Append(SubSeq);
+      SubSequenceOfEdges aSubSeq;
+      aSubSeq.SeqsEdges.Append(edge2);
+      SeqOfSubSeqOfEdges.Append(aSubSeq);
     }
     else
       SeqOfSubSeqOfEdges.ChangeLast().SeqsEdges.Append(edge2);
@@ -794,26 +875,16 @@ static void GenerateSubSeq (const TopTools_SequenceOfShape& anInpEdgeSeq,
 //function : MergeEdges
 //purpose  : auxilary
 //=======================================================================
-static Standard_Boolean MergeEdges(const TopTools_SequenceOfShape& SeqEdges,
+static Standard_Boolean MergeEdges(TopTools_SequenceOfShape& SeqEdges,
                                    const Standard_Real Tol,
                                    const Standard_Boolean ConcatBSplines,
                                    NCollection_Sequence<SubSequenceOfEdges>& SeqOfSubSeqOfEdges,
                                    const TopTools_MapOfShape& NonMergVrt )
 {
-  // make chain for union
-  //BRep_Builder B;
-  ShapeAnalysis_Edge sae;
-  TopoDS_Edge FirstE = TopoDS::Edge(SeqEdges.Value(1));
-  TopoDS_Edge LastE = FirstE;
-  TopoDS_Vertex VF = sae.FirstVertex(FirstE);
-  TopoDS_Vertex VL = sae.LastVertex(LastE);
-  TopTools_SequenceOfShape aChain;
-  aChain.Append(FirstE);
-  TColStd_MapOfInteger IndUsedEdges;
-  IndUsedEdges.Add(1);
+  // skip degenerated edges, and forbid merging through them
+  TopTools_IndexedDataMapOfShapeListOfShape aMapVE;
   Standard_Integer j;
   TopTools_MapOfShape VerticesToAvoid;
-  TopTools_SequenceOfShape SeqEdges1;
   for (j = 1; j <= SeqEdges.Length(); j++)
   {
     TopoDS_Edge anEdge = TopoDS::Edge(SeqEdges(j));
@@ -823,38 +894,90 @@ static Standard_Boolean MergeEdges(const TopTools_SequenceOfShape& SeqEdges,
       TopExp::Vertices(anEdge, V1, V2);
       VerticesToAvoid.Add(V1);
       VerticesToAvoid.Add(V2);
-      continue;
+      SeqEdges.Remove(j--);
     }
-    SeqEdges1.Append(anEdge);
+    else
+    {
+      // fill in the map V-E
+      for (TopoDS_Iterator it(anEdge.Oriented(TopAbs_FORWARD)); it.More(); it.Next())
+      {
+        TopoDS_Shape aV = it.Value();
+        if (aV.Orientation() == TopAbs_FORWARD || aV.Orientation() == TopAbs_REVERSED)
+        {
+          if (!aMapVE.Contains(aV))
+            aMapVE.Add(aV, TopTools_ListOfShape());
+          aMapVE.ChangeFromKey(aV).Append(anEdge);
   }
+      }
+    }
+  }
+  VerticesToAvoid.Unite(NonMergVrt);
 
-  for(j=2; j<=SeqEdges1.Length(); j++) {
-    for(Standard_Integer k=2; k<=SeqEdges1.Length(); k++) {
-      if(IndUsedEdges.Contains(k)) continue;
-      TopoDS_Edge edge = TopoDS::Edge(SeqEdges1.Value(k));
-      TopoDS_Vertex VF2 = sae.FirstVertex(edge);
-      TopoDS_Vertex VL2 = sae.LastVertex(edge);
-      if(VF2.IsSame(VL)) {
+  // do loop while there are unused edges
+  TopTools_MapOfShape aUsedEdges;
+  for (;;)
+  {
+    TopoDS_Edge edge;
+    for(j=1; j <= SeqEdges.Length(); j++)
+    {
+      edge = TopoDS::Edge(SeqEdges.Value(j));
+      if (!aUsedEdges.Contains(edge))
+        break;
+    }
+    if (j > SeqEdges.Length())
+      break; // all edges have been used
+
+    // make chain for unite
+    TopTools_SequenceOfShape aChain;
         aChain.Append(edge);
-        LastE = edge;
-        VL = sae.LastVertex(LastE);
-        IndUsedEdges.Add(k);
-      }
-      else if(VL2.IsSame(VF)) {
+    aUsedEdges.Add(edge);
+    TopoDS_Vertex V[2];
+    TopExp::Vertices(edge, V[0], V[1], Standard_True);
+
+    // connect more edges to the chain in both directions
+    for (j = 0; j < 2; j++)
+    {
+      Standard_Boolean isAdded = Standard_True;
+      while (isAdded)
+      {
+        isAdded = Standard_False;
+        if (V[j].IsNull())
+          break;
+        const TopTools_ListOfShape& aLE = aMapVE.FindFromKey(V[j]);
+        for (TopTools_ListIteratorOfListOfShape itL(aLE); itL.More(); itL.Next())
+        {
+          edge = TopoDS::Edge(itL.Value());
+          if (!aUsedEdges.Contains(edge))
+          {
+            if (j == 0)
         aChain.Prepend(edge);
-        FirstE = edge;
-        VF = sae.FirstVertex(FirstE);
-        IndUsedEdges.Add(k);
+            else
+              aChain.Append(edge);
+            aUsedEdges.Add(edge);
+            TopoDS_Vertex VF2, VL2;
+            TopExp::Vertices(edge, VF2, VL2, Standard_True);
+            V[j] = (VF2.IsSame(V[j]) ? VL2 : VF2);
+            isAdded = Standard_True;
+            break;
       }
     }
   }
+    }
+
+    if (aChain.Length() < 2)
+      continue;
 
   Standard_Boolean IsClosed = Standard_False;
-  if (VF.IsSame ( VL ))
+    if (V[0].IsSame ( V[1] ))
     IsClosed = Standard_True;
 
-  VerticesToAvoid.Unite(NonMergVrt);
-  GenerateSubSeq(aChain, SeqOfSubSeqOfEdges, IsClosed, Tol, VerticesToAvoid);
+    // split chain by vertices at which merging is not possible
+    NCollection_Sequence<SubSequenceOfEdges> aOneSeq;
+    GenerateSubSeq(aChain, aOneSeq, IsClosed, Tol, VerticesToAvoid);
+
+    // put sub-chains in the result
+    SeqOfSubSeqOfEdges.Append(aOneSeq);
+  }
 
   for (int i = 1; i <= SeqOfSubSeqOfEdges.Length(); i++)
   {
@@ -867,7 +990,13 @@ static Standard_Boolean MergeEdges(const TopTools_SequenceOfShape& SeqEdges,
   return Standard_True;
 }
 
-static Standard_Boolean MergeSeq (const TopTools_SequenceOfShape& SeqEdges,
+//=======================================================================
+//function : MergeSeq
+//purpose  : Tries to unify the sequence of edges with the set of another edges 
+//which lies on the same geometry
+//=======================================================================
+
+static Standard_Boolean MergeSeq (TopTools_SequenceOfShape& SeqEdges,
                                   const Standard_Real Tol,
                                   const Standard_Boolean ConcatBSplines,
                                   Handle(ShapeBuild_ReShape)& theContext,
@@ -898,6 +1027,11 @@ static Standard_Boolean MergeSeq (const TopTools_SequenceOfShape& SeqEdges,
     return Standard_False;
 }
 
+//=======================================================================
+//function : CheckSharedVertices
+//purpose  : Checks the sequence of edges on the presence of shared vertex 
+//=======================================================================
+
 static void CheckSharedVertices(const TopTools_SequenceOfShape& theSeqEdges, 
                                 const TopTools_IndexedDataMapOfShapeListOfShape& theMapEdgesVertex,
                                 TopTools_MapOfShape& theShareVertMap)
@@ -934,11 +1068,11 @@ static void CheckSharedVertices(const TopTools_SequenceOfShape& theSeqEdges,
 //=======================================================================
 
 ShapeUpgrade_UnifySameDomain::ShapeUpgrade_UnifySameDomain()
+  : myUnifyFaces (Standard_True),
+    myUnifyEdges (Standard_True),
+    myConcatBSplines (Standard_False),
+    myAllowInternal (Standard_False)
 {
-  myUnifyEdges = Standard_True;
-  myUnifyFaces = Standard_True;
-  myConcatBSplines = Standard_False;
-
   myContext = new ShapeBuild_ReShape;
 }
 
@@ -951,13 +1085,13 @@ ShapeUpgrade_UnifySameDomain::ShapeUpgrade_UnifySameDomain(const TopoDS_Shape& a
                                                            const Standard_Boolean UnifyEdges,
                                                            const Standard_Boolean UnifyFaces,
                                                            const Standard_Boolean ConcatBSplines)
+  : myInitShape (aShape),
+    myUnifyFaces (UnifyFaces),
+    myUnifyEdges (UnifyEdges),
+    myConcatBSplines (ConcatBSplines),
+    myAllowInternal (Standard_False),
+    myShape (aShape)
 {
-  myInitShape = aShape;
-  myShape = aShape;
-  myUnifyEdges = UnifyEdges;
-  myUnifyFaces = UnifyFaces;
-  myConcatBSplines = ConcatBSplines;
-
   myContext = new ShapeBuild_ReShape;
 }
 
@@ -979,7 +1113,47 @@ void ShapeUpgrade_UnifySameDomain::Initialize(const TopoDS_Shape& aShape,
 
   myContext->Clear();
   myOldShapes.Clear();
-  //myGenerated.Clear();
+}
+
+//=======================================================================
+//function : AllowInternalEdges
+//purpose  : 
+//=======================================================================
+
+void ShapeUpgrade_UnifySameDomain::AllowInternalEdges (const Standard_Boolean theValue)
+{
+  myAllowInternal = theValue;
+}
+
+//=======================================================================
+//function : putIntWires
+//purpose  : Add internal wires that are classified inside the face as a subshape,
+//           and remove them from the sequence
+//=======================================================================
+static void putIntWires(TopoDS_Shape& theFace, TopTools_SequenceOfShape& theWires)
+{
+  TopoDS_Face& aFace = TopoDS::Face(theFace);
+  for (Standard_Integer i=1; i <= theWires.Length(); i++)
+  {
+    TopoDS_Shape aWire = theWires(i);
+    gp_Pnt2d aP2d;
+    Standard_Boolean isP2d = Standard_False;
+    for (TopoDS_Iterator it(aWire); it.More() && !isP2d; it.Next())
+    {
+      const TopoDS_Edge& anEdge = TopoDS::Edge(it.Value());
+      Standard_Real aFirst, aLast;
+      Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(anEdge, aFace, aFirst, aLast);
+      aC2d->D0((aFirst + aLast) * 0.5, aP2d);
+      isP2d = Standard_True;
+    }
+    BRepClass_FaceClassifier aClass(aFace, aP2d, Precision::PConfusion());
+    if (aClass.State() == TopAbs_IN)
+    {
+      BRep_Builder().Add(aFace, aWire);
+      theWires.Remove(i);
+      i--;
+    }
+  }
 }
 
 //=======================================================================
@@ -989,23 +1163,22 @@ void ShapeUpgrade_UnifySameDomain::Initialize(const TopoDS_Shape& aShape,
 
 void ShapeUpgrade_UnifySameDomain::UnifyFaces()
 {
-  //Handle(ShapeBuild_ReShape) myContext = new ShapeBuild_ReShape;
-  TopoDS_Shape aResShape = myContext->Apply(myShape);
+  // creating map of edge faces for the whole shape
+  TopTools_IndexedDataMapOfShapeListOfShape aGMapEdgeFaces;
+  TopExp::MapShapesAndAncestors(myShape, TopAbs_EDGE, TopAbs_FACE, aGMapEdgeFaces);
 
   // processing each shell
   TopExp_Explorer exps;
   for (exps.Init(myShape, TopAbs_SHELL); exps.More(); exps.Next()) {
     TopoDS_Shell aShell = TopoDS::Shell(exps.Current());
 
-    // creating map of edge faces
+    // creating map of edge faces for the shell
     TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces;
     TopExp::MapShapesAndAncestors(aShell, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces);
 
     // map of processed shapes
     TopTools_MapOfShape aProcessed;
 
-    //Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape;
-
     Standard_Integer NbModif = 0;
     Standard_Boolean hasFailed = Standard_False;
     Standard_Real tol = Precision::Confusion();
@@ -1046,6 +1219,13 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
         if (BRep_Tool::Degenerated(edge))
           continue;
 
+        // get connectivity of the edge in the global shape
+        const TopTools_ListOfShape& aGList = aGMapEdgeFaces.FindFromKey(edge);
+        if (!myAllowInternal && aGList.Extent() != 2) {
+          // non mainfold case is not processed unless myAllowInternal
+          continue;
+        }
+        // process faces connected through the edge in the current shell
         const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge);
         TopTools_ListIteratorOfListOfShape anIter(aList);
         for (; anIter.More(); anIter.Next()) {
@@ -1058,10 +1238,9 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
 
           if (IsSameDomain(aFace,anCheckedFace)) {
 
-            if (aList.Extent() != 2) {
-              // non mainfold case is not processed
+            // hotfix for 27271: prevent merging along periodic direction.
+            if (IsLikeSeam(edge, aFace, aBaseSurface))
               continue;
-            }
 
             // replacing pcurves
             TopoDS_Face aMockUpFace;
@@ -1081,6 +1260,72 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
         }
       }
 
+      if (faces.Length() > 1) {
+        // fill in the connectivity map for selected faces
+        TopTools_IndexedDataMapOfShapeListOfShape aMapEF;
+        for (i = 1; i <= faces.Length(); i++) {
+          TopExp::MapShapesAndAncestors(faces(i), TopAbs_EDGE, TopAbs_FACE, aMapEF);
+        }
+
+        // Collect multiconnected edges, i.e. edges that are internal to
+        // the set of selected faces and have connections to other faces.
+        TopTools_ListOfShape aMultEdges;
+        for (i = 1; i <= aMapEF.Extent(); i++) {
+          const TopTools_ListOfShape& aLF = aMapEF(i);
+          if (aLF.Extent() == 2) {
+            const TopoDS_Shape& aE = aMapEF.FindKey(i);
+            const TopTools_ListOfShape& aGLF = aGMapEdgeFaces.FindFromKey(aE);
+            if (aGLF.Extent() > 2) {
+              aMultEdges.Append(aE);
+            }
+          }
+        }
+        if (!aMultEdges.IsEmpty()) {
+          if (!myAllowInternal) {
+            // Remove from the selection the faces containing multiconnected edges
+            TopTools_MapOfShape anAvoidFaces;
+            TopTools_ListIteratorOfListOfShape it(aMultEdges);
+            for (; it.More(); it.Next()) {
+              const TopoDS_Shape& aE = it.Value();
+              const TopTools_ListOfShape& aLF = aMapEF.FindFromKey(aE);
+              anAvoidFaces.Add(aLF.First());
+              anAvoidFaces.Add(aLF.Last());
+            }
+            for (i = 1; i <= faces.Length(); ) {
+              if (anAvoidFaces.Contains(faces(i))) {
+                // update the boundaries of merged area, for that
+                // remove from 'edges' the edges of this face and add to 'edges' 
+                // the edges of this face that were not present in 'edges' before
+                TopExp_Explorer ex(faces(i), TopAbs_EDGE);
+                for (; ex.More(); ex.Next()) {
+                  TopoDS_Shape aE = ex.Current();
+                  Standard_Integer j;
+                  for (j = 1; j <= edges.Length(); j++) {
+                    if (edges(j).IsSame(aE))
+                      break;
+                  }
+                  if (j <= edges.Length())
+                    edges.Remove(j);
+                  else
+                    edges.Append(aE);
+                }
+                faces.Remove(i);
+              }
+              else
+                i++;
+            }
+          }
+          else {
+            // add multiconnected edges as internal in new face
+            TopTools_ListIteratorOfListOfShape it(aMultEdges);
+            for (; it.More(); it.Next()) {
+              const TopoDS_Shape& aE = it.Value();
+              edges.Append(aE.Oriented(TopAbs_INTERNAL));
+            }
+          }
+        }
+      }
+
       // all faces collected in the sequence. Perform union of faces
       if (faces.Length() > 1) {
         NbModif++;
@@ -1089,6 +1334,7 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
         B.MakeFace(aResult,aBaseSurface,aBaseLocation,0);
         Standard_Integer nbWires = 0;
 
+        TopoDS_Face tmpF = TopoDS::Face(myContext->Apply(faces(1).Oriented(TopAbs_FORWARD)));
         // connecting wires
         while (edges.Length()>0) {
 
@@ -1100,6 +1346,8 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
 
           TopoDS_Edge anEdge = TopoDS::Edge(edges(1));
           edges.Remove(1);
+          // collect internal edges in separate wires
+          Standard_Boolean isInternal = (anEdge.Orientation() == TopAbs_INTERNAL);
 
           isEdge3d |= !BRep_Tool::Degenerated(anEdge);
           B.Add(aWire,anEdge);
@@ -1113,6 +1361,10 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
             isNewFound = Standard_False;
             for(Standard_Integer j = 1; j <= edges.Length(); j++) {
               anEdge = TopoDS::Edge(edges(j));
+              // check if the current edge orientation corresponds to the first one
+              Standard_Boolean isCurrInternal = (anEdge.Orientation() == TopAbs_INTERNAL);
+              if (isCurrInternal != isInternal)
+                continue;
               TopExp::Vertices(anEdge,V1,V2);
               if(aVertices.Contains(V1) || aVertices.Contains(V2)) {
                 isEdge3d |= !BRep_Tool::Degenerated(anEdge);
@@ -1130,7 +1382,6 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
           aWire.Closed (BRep_Tool::IsClosed (aWire));
           aWire = TopoDS::Wire(myContext->Apply(aWire));
 
-          TopoDS_Face tmpF = TopoDS::Face(myContext->Apply(faces(1).Oriented(TopAbs_FORWARD)));
           Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire(aWire,tmpF,Precision::Confusion());
           sfw->FixReorder();
           Standard_Boolean isDegRemoved = Standard_False;
@@ -1259,14 +1510,27 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
           //CompShell.SetContext( aContext );
           CompShell.SetContext( myContext );
 
-          TopTools_SequenceOfShape parts;
+          TopTools_SequenceOfShape parts, anIntWires;
           ShapeFix_SequenceOfWireSegment wires;
           for(TopExp_Explorer W_Exp(aCurrent,TopAbs_WIRE);W_Exp.More();W_Exp.Next()) {
+            const TopoDS_Wire& aWire = TopoDS::Wire(W_Exp.Current());
+            // check if the wire is ordinary (contains non-internal edges)
+            Standard_Boolean isInternal = Standard_True;
+            for (TopoDS_Iterator it(aWire); it.More() && isInternal; it.Next())
+              isInternal = (it.Value().Orientation() == TopAbs_INTERNAL);
+            if (isInternal)
+            {
+              // place internal wire separately
+              anIntWires.Append(aWire);
+            }
+            else
+            {
             Handle(ShapeExtend_WireData) sbwd =
-              new ShapeExtend_WireData ( TopoDS::Wire(W_Exp.Current() ));
+                new ShapeExtend_WireData (aWire);
             ShapeFix_WireSegment seg ( sbwd, TopAbs_REVERSED );
             wires.Append(seg);
           }
+          }
 
           CompShell.DispatchWires ( parts,wires );
           for (Standard_Integer j=1; j <= parts.Length(); j++ ) {
@@ -1274,10 +1538,12 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
             //aFixOrient.SetContext(aContext);
             aFixOrient.SetContext(myContext);
             aFixOrient.FixOrientation();
+            // put internal wires to faces
+            putIntWires(parts(j), anIntWires);
           }
 
           TopoDS_Shape CompRes;
-          if ( faces.Length() !=1 ) {
+          if ( parts.Length() !=1 ) {
             TopoDS_Shell S;
             B.MakeShell ( S );
             for ( i=1; i <= parts.Length(); i++ )
@@ -1317,6 +1583,7 @@ void ShapeUpgrade_UnifySameDomain::UnifyFaces()
       TopoDS_Shape aResult = myContext->Apply(aShell);
 
       ShapeFix_Edge sfe;
+      if (!myContext.IsNull()) sfe.SetContext(myContext);
       for (exp.Init(aResult,TopAbs_EDGE); exp.More(); exp.Next()) {
         TopoDS_Edge E = TopoDS::Edge(exp.Current());
         sfe.FixVertexTolerance (E);
@@ -1414,6 +1681,15 @@ void ShapeUpgrade_UnifySameDomain::UnifyEdges()
     MergeSeq(SeqEdges, Tol, myConcatBSplines, myContext, myOldShapes, SharedVert, NewEdges2OldEdges);
   }
 
+  TopTools_DataMapOfShapeShape oldFaces2NewFaces;
+  for (exp.Init(myShape, TopAbs_FACE); exp.More(); exp.Next()) 
+  {
+    const TopoDS_Face& f = TopoDS::Face(exp.Current());
+    TopoDS_Face NewF = TopoDS::Face(myContext->Apply(f));
+    if (!NewF.IsNull())
+      oldFaces2NewFaces.Bind(f, NewF);
+  }
+
   // processing each face
   for (exp.Init(aRes, TopAbs_FACE); exp.More(); exp.Next()) {
     //TopoDS_Face aFace = TopoDS::Face(aContext->Apply(exp.Current().Oriented(TopAbs_FORWARD)));
@@ -1428,7 +1704,7 @@ void ShapeUpgrade_UnifySameDomain::UnifyEdges()
       Standard_Integer NbFacesPerEdge = aList.Extent();
       for ( ; anIter.More(); anIter.Next()) {
         TopoDS_Face face = TopoDS::Face(anIter.Value());
-        TopoDS_Face face1 = TopoDS::Face(myContext->Apply(anIter.Value()));
+        TopoDS_Face face1 = TopoDS::Face(oldFaces2NewFaces(anIter.Value()));
         if (face1.IsSame(aFace) && NbFacesPerEdge != 1)
           continue;
         if (NbFacesPerEdge == 1)