From 77a11d3df141427a24d780c4e40d6f823c38cf69 Mon Sep 17 00:00:00 2001
From: emv <emv@opencascade.com>
Date: Thu, 29 Dec 2016 15:42:08 +0300
Subject: [PATCH] 0028189: Result of Boolean operation is non-manifold wire

1. The result of Boolean operation on the arguments of collection type, containers WIRE/SHELL/COMPSOLID, is also a collection.
The containers of type WIRE included into result should now also (as the SHELLs) have coherent orientation of its sub-shapes.
For that the new method has been implemented (BOPTools_AlgoTools::OrientEdgesOnWire(TopoDS_Shape&)) which reorients edges for correct ordering.
The duplicating containers, i.e. containers with the contents completely included in other containers, are now avoided in the result of BOP.
2. The result of Fuse operation on Compsolids is now also will be Compsolid.
3. Documentation has been updated.
4. New test cases for the issue.
5. Adjusting test cases to current behavior.

Correction of test case bugs/modalg_4/bug726_2 according to the new behavior
---
 dox/dev_guides/upgrade/upgrade.md             |   4 +
 .../boolean_operations/boolean_operations.md  |  10 +-
 src/BOPAlgo/BOPAlgo_BOP.cxx                   | 249 +++++++++++++++++-
 src/BOPTest/BOPTest_UtilityCommands.cxx       |  30 ++-
 src/BOPTools/BOPTools_AlgoTools.cxx           |  90 +++++++
 src/BOPTools/BOPTools_AlgoTools.hxx           |   8 +-
 tests/boolean/bcommon_2d/F3                   |   2 +-
 tests/boolean/bcommon_2d/F4                   |   2 +-
 tests/boolean/bcommon_2d/F5                   |   2 +-
 tests/boolean/bcommon_2d/N8                   |   2 +-
 tests/boolean/bcommon_2d/N9                   |   2 +-
 tests/boolean/bcommon_2d/O1                   |   2 +-
 tests/boolean/bcommon_2d/O7                   |   2 +-
 tests/boolean/bopcommon_2d/F3                 |   2 +-
 tests/boolean/bopcommon_2d/F4                 |   2 +-
 tests/boolean/bopcommon_2d/F5                 |   2 +-
 tests/boolean/bopcommon_2d/N8                 |   2 +-
 tests/boolean/bopcommon_2d/N9                 |   2 +-
 tests/boolean/bopcommon_2d/O1                 |   2 +-
 tests/boolean/bopcommon_2d/O7                 |   2 +-
 tests/boolean/bopcommon_complex/L3            |   2 +-
 tests/boolean/bopcommon_complex/L6            |   2 +-
 tests/boolean/bopcommon_complex/L7            |   2 +-
 tests/boolean/bopcommon_complex/L8            |   2 +-
 tests/boolean/bopcommon_complex/L9            |   2 +-
 tests/boolean/bopcommon_complex/M3            |   2 +-
 tests/boolean/bopcommon_complex/M4            |   2 +-
 tests/boolean/bopcommon_complex/M5            |   2 +-
 tests/boolean/bopcommon_complex/M6            |   2 +-
 tests/boolean/bopfuse_complex/O2              |   2 +-
 tests/boolean/bopfuse_complex/O3              |   2 +-
 tests/bugs/modalg_1/bug13538                  |   4 +-
 tests/bugs/modalg_4/bug726_2                  |   1 -
 tests/bugs/modalg_6/bug26980                  |   2 +-
 tests/bugs/modalg_6/bug28189_1                |  38 +++
 tests/bugs/modalg_6/bug28189_2                |  15 ++
 tests/bugs/modalg_6/bug28189_3                |  15 ++
 tests/bugs/modalg_6/bug28189_4                |  16 ++
 tests/bugs/modalg_6/bug28189_5                |  16 ++
 tests/bugs/modalg_6/bug28189_6                |  41 +++
 tests/bugs/modalg_6/bug28189_7                |  27 ++
 tests/bugs/modalg_6/bug28189_8                |  17 ++
 tests/bugs/modalg_6/bug28189_9                |  40 +++
 43 files changed, 626 insertions(+), 47 deletions(-)
 create mode 100644 tests/bugs/modalg_6/bug28189_1
 create mode 100644 tests/bugs/modalg_6/bug28189_2
 create mode 100644 tests/bugs/modalg_6/bug28189_3
 create mode 100644 tests/bugs/modalg_6/bug28189_4
 create mode 100644 tests/bugs/modalg_6/bug28189_5
 create mode 100644 tests/bugs/modalg_6/bug28189_6
 create mode 100644 tests/bugs/modalg_6/bug28189_7
 create mode 100644 tests/bugs/modalg_6/bug28189_8
 create mode 100644 tests/bugs/modalg_6/bug28189_9

diff --git a/dox/dev_guides/upgrade/upgrade.md b/dox/dev_guides/upgrade/upgrade.md
index e3486df8bd..cdbcff0f27 100644
--- a/dox/dev_guides/upgrade/upgrade.md
+++ b/dox/dev_guides/upgrade/upgrade.md
@@ -1177,3 +1177,7 @@ Management of highlight attributes has been revised and might require modificati
   - *myZLayer*, replaced by *myDrawer->ZLayer()*
 * The method *PrsMgr_PresentationManager::Unhighlight()* taking Display Mode as an argument has been marked deprecated.
   Implementation now performs unhighlighting of all highlighted presentation mode.
+
+@subsection upgrade_720_Result_Of_BOP_On_Containers Result of Boolean operations on containers
+
+* The result of Boolean operations on arguments of collection types (WIRE/SHELL/COMPSOLID) is now filtered from duplicating containers.
\ No newline at end of file
diff --git a/dox/user_guides/boolean_operations/boolean_operations.md b/dox/user_guides/boolean_operations/boolean_operations.md
index 92c49aa231..0b900176ef 100644
--- a/dox/user_guides/boolean_operations/boolean_operations.md
+++ b/dox/user_guides/boolean_operations/boolean_operations.md
@@ -1080,9 +1080,11 @@ The input data for this step is a *BOPAlgo_Builder* object after building result
 * The result of the operation *Cut12* for arguments *S1* and *S2* contains the parts of argument *S1* that have state **OUT** relative to the opposite argument *S2*.
 * The result of the operation *Cut21* for arguments *S1* and *S2* contains the parts of argument *S2* that have state **OUT** relative to the opposite argument *S1*.
 * For the arguments of collection type (WIRE, SHELL, COMPSOLID) the type will be passed in the result. For example, the result of Common operation between Shell and Wire will be a compound containing Wire.
-* For the arguments of collection type (WIRE, SHELL, COMPSOLID) containing overlapping parts the overlapping parts passed into result will be repeated for each container from the input shapes containing such parts.
-* The result of the operation Fuse for the arguments of collection type (WIRE, SHELL, COMPSOLID) will contain the same number of containers as the arguments. The overlapping parts (EDGES/FACES/SOLIDS) will be shared among them. For example, the result of Fuse operation between two wires will be two wires sharing coinciding edges if any.
-* The result of the operation Common for the arguments of collection type (WIRE, SHELL, COMPSOLID) will consist of the containers containing the same overlapping parts. For example, the result of Common operation between two fully/partially overlapping wires will be two wires containing the same edges.
+* For the arguments of collection type (WIRE, SHELL, COMPSOLID) containing overlapping parts the overlapping parts passed into result will be repeated for each container from the input shapes containing such parts. The containers completely included in other containers will be avoided in the result.
+* For the arguments of collection type (WIRE, SHELL, COMPSOLID) the containers included into result will have the same orientation as the original containers from arguments. In case of duplication its orientation will be defined by the orientation of the first container in arguments. Each container included into result will have coherent orientation of its sub-shapes.
+* The result of the operation Fuse for the arguments of collection type (WIRE, SHELL) will consist of the shapes of the same collection type. The overlapping parts (EDGES/FACES) will be shared among containers, but duplicating containers will be avoided in the result. For example, the result of Fuse operation between two fully coinciding wires will be one wire, but the result of Fuse operation between two partially coinciding wires will be two wires sharing coinciding edges.
+* The result of the operation Fuse for the arguments of type COMPSOLID will consist of the compound containing COMPSOLIDs created from connexity blocks of fused solids.
+* The result of the operation Common for the arguments of collection type (WIRE, SHELL, COMPSOLID) will consist of the unique containers containing the overlapping parts. For example, the result of Common operation between two fully overlapping wires will be one wire containing all splits of edges. The number of wires in the result of Common operation between two partially overlapping wires will be equal to the number of connexity blocks of overlapping edges.
 
 @subsection occt_algorithms_9_4 Examples
 
@@ -1555,7 +1557,7 @@ Let us consider two Wires that have overlapping edges, *W1* is the object and *W
 
 @figure{/user_guides/boolean_operations/images/boolean_image140.png}
  	
-* The result of *Common* operation is a compound containing two Wires both consisting of an overlapping edge. The new Wires are created from the objects:
+* The result of *Common* operation is a compound containing one Wire consisting of an overlapping edge. The new Wire is created from the objects:
 
 @figure{/user_guides/boolean_operations/images/boolean_image141.png}	
 
diff --git a/src/BOPAlgo/BOPAlgo_BOP.cxx b/src/BOPAlgo/BOPAlgo_BOP.cxx
index 932877185a..301267e9c9 100644
--- a/src/BOPAlgo/BOPAlgo_BOP.cxx
+++ b/src/BOPAlgo/BOPAlgo_BOP.cxx
@@ -36,7 +36,6 @@
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Iterator.hxx>
 #include <TopoDS_Shape.hxx>
-#include <TopTools_ListIteratorOfListOfShape.hxx>
 
 typedef NCollection_IndexedDataMap
   <BOPTools_Set,
@@ -49,6 +48,17 @@ static
 static
   void CollectContainers(const TopoDS_Shape& theS,
                          BOPCol_ListOfShape& theLSC);
+//
+static
+  void RemoveDuplicates(BOPCol_ListOfShape& theContainers);
+//
+static
+  void RemoveDuplicates(BOPCol_ListOfShape& theContainers,
+                        const TopAbs_ShapeEnum theType);
+//
+static
+  Standard_Integer NbCommonItemsInMap(const BOPCol_MapOfShape& theM1,
+                                      const BOPCol_MapOfShape& theM2);
 
 
 //=======================================================================
@@ -733,15 +743,12 @@ void BOPAlgo_BOP::BuildShape()
   //
   Standard_Integer i;
   TopAbs_ShapeEnum aType, aT1, aT2;
-  TopTools_ListOfShape aLSC, aLCB;
+  BOPCol_ListOfShape aLSC, aLCB;
   BOPCol_ListIteratorOfListOfShape aItLS, aItLSIm, aItLCB;
   TopoDS_Iterator aIt;
   BRep_Builder aBB;
   TopoDS_Shape aRC, aRCB;
   //
-  TopoDS_Compound aResult;
-  aBB.MakeCompound(aResult);
-  //
   BOPCol_MapOfShape aMSRC;
   BOPTools::MapShapes(myRC, aMSRC);
   //
@@ -757,6 +764,7 @@ void BOPAlgo_BOP::BuildShape()
     }
   }
   // make containers
+  BOPCol_ListOfShape aLCRes;
   aItLS.Initialize(aLSC);
   for (; aItLS.More(); aItLS.Next()) {
     const TopoDS_Shape& aSC = aItLS.Value();
@@ -767,7 +775,7 @@ void BOPAlgo_BOP::BuildShape()
     for (; aIt.More(); aIt.Next()) {
       const TopoDS_Shape& aS = aIt.Value();
       if (myImages.IsBound(aS)) {
-        const TopTools_ListOfShape& aLSIm = myImages.Find(aS);
+        const BOPCol_ListOfShape& aLSIm = myImages.Find(aS);
         //
         aItLSIm.Initialize(aLSIm);
         for (; aItLSIm.More(); aItLSIm.Next()) {
@@ -817,14 +825,31 @@ void BOPAlgo_BOP::BuildShape()
         aBB.Add(aRCB, aCBS);
       }
       //
-      if (aType == TopAbs_SHELL) {
+      if (aType == TopAbs_WIRE) {
+        // reorient wire
+        BOPTools_AlgoTools::OrientEdgesOnWire(aRCB);
+      }
+      else if (aType == TopAbs_SHELL) {
         BOPTools_AlgoTools::OrientFacesOnShell(aRCB);
       }
       //
-      aBB.Add(aResult, aRCB);
+      aRCB.Orientation(aSC.Orientation());
+      //
+      aLCRes.Append(aRCB);
     }
   }
   //
+  RemoveDuplicates(aLCRes);
+  //
+  // add containers to result
+  TopoDS_Compound aResult;
+  aBB.MakeCompound(aResult);
+  //
+  aItLS.Initialize(aLCRes);
+  for (; aItLS.More(); aItLS.Next()) {
+    aBB.Add(aResult, aItLS.Value());
+  }
+  //
   // add the rest of the shapes into result
   BOPCol_MapOfShape aMSResult;
   BOPTools::MapShapes(aResult, aMSResult);
@@ -832,7 +857,7 @@ void BOPAlgo_BOP::BuildShape()
   aIt.Initialize(myRC);
   for (; aIt.More(); aIt.Next()) {
     const TopoDS_Shape& aS = aIt.Value();
-    if (!aMSResult.Contains(aS)) {
+    if (aMSResult.Add(aS)) {
       aBB.Add(aResult, aS);
     }
   }
@@ -859,6 +884,7 @@ void BOPAlgo_BOP::BuildSolid()
   BOPAlgo_BuilderSolid aSB; 
   BOPCol_MapOfShape aMSA, aMZ;
   BOPTools_IndexedDataMapOfSetShape aDMSTS;
+  BOPCol_ListOfShape aLSC;
   //
   myErrorStatus=0;
   //
@@ -868,6 +894,9 @@ void BOPAlgo_BOP::BuildSolid()
     aItLS.Initialize(aLSA);
     for (; aItLS.More(); aItLS.Next()) {
       const TopoDS_Shape& aSA=aItLS.Value();
+      //
+      CollectContainers(aSA, aLSC);
+      //
       aExp.Init(aSA, TopAbs_SOLID);
       for (; aExp.More(); aExp.Next()) {
         const TopoDS_Shape& aZA=aExp.Current();
@@ -1018,7 +1047,87 @@ void BOPAlgo_BOP::BuildSolid()
     aBB.Add(aRC, aSx);
   }
   //
-  myShape=aRC;
+  if (aLSC.IsEmpty()) {
+    // no Compsolids in arguments
+    myShape=aRC;
+    return;
+  }
+  //
+  // build new Compsolids from new solids containing splits
+  // of faces from arguments of type Compsolid
+  //
+  TopoDS_Shape aResult;
+  BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aResult);
+  //
+  // optimization for one solid in the result
+  if (aLSR.Extent() == 1 && !aNbSx) {
+    TopoDS_Shape aCS;
+    BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
+    aBB.Add(aCS, aLSR.First());
+    //
+    aBB.Add(aResult, aCS);
+    myShape = aResult;
+    return;
+  }
+  //
+  // get splits of faces of the Compsolid arguments
+  BOPCol_MapOfShape aMFCs;
+  aItLS.Initialize(aLSC);
+  for (; aItLS.More(); aItLS.Next()) {
+    const TopoDS_Shape& aCs = aItLS.Value();
+    aExp.Init(aCs, TopAbs_FACE);
+    for (; aExp.More(); aExp.Next()) {
+      const TopoDS_Shape& aF = aExp.Current();
+      const BOPCol_ListOfShape* pLFIm = myImages.Seek(aF);
+      if (!pLFIm) {
+        aMFCs.Add(aF);
+      }
+      else {
+        BOPCol_ListIteratorOfListOfShape aItLFIm(*pLFIm);
+        for (; aItLFIm.More(); aItLFIm.Next()) {
+          aMFCs.Add(aItLFIm.Value());
+        }
+      }
+    }
+  }
+  //
+  // build connexity blocks from new solids
+  BOPCol_ListOfShape aLCBS;
+  BOPTools_AlgoTools::MakeConnexityBlocks(aRC, TopAbs_FACE, TopAbs_SOLID, aLCBS);
+  //
+  aItLS.Initialize(aLCBS);
+  for (; aItLS.More(); aItLS.Next()) {
+    const TopoDS_Shape& aCB = aItLS.Value();
+    //
+    // check if the Compsolid should be created
+    aExp.Init(aCB, TopAbs_FACE);
+    for (; aExp.More(); aExp.Next()) {
+      if (aMFCs.Contains(aExp.Current())) {
+        break;
+      }
+    }
+    //
+    if (!aExp.More()) {
+      // add solids directly into result as their origins are not Compsolids
+      for (aIt.Initialize(aCB); aIt.More(); aIt.Next()) {
+        aBB.Add(aResult, aIt.Value());
+      }
+      continue;
+    }
+    //
+    // make Compsolid
+    TopoDS_Shape aCS;
+    BOPTools_AlgoTools::MakeContainer(TopAbs_COMPSOLID, aCS);
+    //
+    aIt.Initialize(aCB);
+    for (; aIt.More(); aIt.Next()) {
+      aBB.Add(aCS, aIt.Value());
+    }
+    //
+    aBB.Add(aResult, aCS);
+  }
+  //
+  myShape = aResult;
 }
 //=======================================================================
 //function : IsBoundSplits
@@ -1121,3 +1230,123 @@ void CollectContainers(const TopoDS_Shape& theS,
   }
 }
 
+//=======================================================================
+//function : RemoveDuplicates
+//purpose  : Filters the containers with identical contents
+//=======================================================================
+void RemoveDuplicates(BOPCol_ListOfShape& theContainers)
+{
+  RemoveDuplicates(theContainers, TopAbs_WIRE);
+  RemoveDuplicates(theContainers, TopAbs_SHELL);
+  RemoveDuplicates(theContainers, TopAbs_COMPSOLID);
+}
+
+//=======================================================================
+//function : RemoveDuplicates
+//purpose  : Filters the containers of given type with identical contents
+//=======================================================================
+void RemoveDuplicates(BOPCol_ListOfShape& theContainers,
+                      const TopAbs_ShapeEnum theType)
+{
+  // get containers of given type
+  BOPCol_ListOfShape aLC;
+  BOPCol_ListIteratorOfListOfShape aItLC(theContainers);
+  for (; aItLC.More(); aItLC.Next()) {
+    const TopoDS_Shape& aC = aItLC.Value();
+    if (aC.ShapeType() == theType) {
+      aLC.Append(aC);
+    }
+  }
+  //
+  if (aLC.IsEmpty()) {
+    return;
+  }
+  //
+  // map containers to compare its contents
+  NCollection_IndexedDataMap<TopoDS_Shape, BOPCol_MapOfShape> aContents;
+  //
+  aItLC.Initialize(aLC);
+  for (; aItLC.More(); aItLC.Next()) {
+    const TopoDS_Shape& aC = aItLC.Value();
+    //
+    BOPCol_MapOfShape& aMC = aContents(aContents.Add(aC, BOPCol_MapOfShape()));
+    //
+    TopoDS_Iterator aIt(aC);
+    for (; aIt.More(); aIt.Next()) {
+      aMC.Add(aIt.Value());
+    }
+  }
+  //
+  // compare the contents of the containers and find duplicates
+  BOPCol_MapOfShape aDuplicates;
+  //
+  Standard_Integer i, j, aNb = aContents.Extent();
+  for (i = 1; i <= aNb; ++i) {
+    const TopoDS_Shape& aCi = aContents.FindKey(i);
+    if (aDuplicates.Contains(aCi)) {
+      continue;
+    }
+    const BOPCol_MapOfShape& aMi = aContents(i);
+    Standard_Integer aNbi = aMi.Extent();
+    //
+    for (j = i + 1; j <= aNb; ++j) {
+      const TopoDS_Shape& aCj = aContents.FindKey(j);
+      if (aDuplicates.Contains(aCj)) {
+        continue;
+      }
+      const BOPCol_MapOfShape& aMj = aContents(j);
+      Standard_Integer aNbj = aMj.Extent();
+      //
+      Standard_Integer aNbCommon = NbCommonItemsInMap(aMi, aMj);
+      //
+      if (aNbj == aNbCommon) {
+        aDuplicates.Add(aCj);
+        continue;
+      }
+      //
+      if (aNbi == aNbCommon) {
+        aDuplicates.Add(aCi);
+        break;
+      }
+    }
+  }
+  //
+  if (aDuplicates.IsEmpty()) {
+    return;
+  }
+  //
+  // remove duplicating containers
+  aItLC.Initialize(theContainers);
+  for (; aItLC.More(); ) {
+    const TopoDS_Shape& aC = aItLC.Value();
+    if (aDuplicates.Contains(aC)) {
+      theContainers.Remove(aItLC);
+      continue;
+    }
+    aItLC.Next();
+  }
+}
+
+//=======================================================================
+//function : NbCommonItemsInMap
+//purpose  : Counts the items contained in both maps
+//=======================================================================
+Standard_Integer NbCommonItemsInMap(const BOPCol_MapOfShape& theM1,
+                                    const BOPCol_MapOfShape& theM2)
+{
+  const BOPCol_MapOfShape* aMap1 = &theM1;
+  const BOPCol_MapOfShape* aMap2 = &theM2;
+  //
+  if (theM2.Extent() < theM1.Extent()) {
+    aMap1 = &theM2;
+    aMap2 = &theM1;
+  }
+  //
+  Standard_Integer iCommon = 0;
+  for (BOPCol_MapIteratorOfMapOfShape aIt(*aMap1); aIt.More(); aIt.Next()) {
+    if (aMap2->Contains(aIt.Value())) {
+      ++iCommon;
+    }
+  }
+  return iCommon;
+}
diff --git a/src/BOPTest/BOPTest_UtilityCommands.cxx b/src/BOPTest/BOPTest_UtilityCommands.cxx
index 970fb105e6..0d51aa1bf5 100644
--- a/src/BOPTest/BOPTest_UtilityCommands.cxx
+++ b/src/BOPTest/BOPTest_UtilityCommands.cxx
@@ -15,6 +15,7 @@
 
 #include <BOPTest.hxx>
 
+#include <BOPTools_AlgoTools.hxx>
 #include <BOPTools_AlgoTools2D.hxx>
 #include <DBRep.hxx>
 #include <IntTools_Context.hxx>
@@ -23,8 +24,8 @@
 #include <TopoDS_Face.hxx>
 #include <TopoDS_Shape.hxx>
 
-static Standard_Integer attachpcurve   (Draw_Interpretor&, Standard_Integer, const char**);
-
+static Standard_Integer attachpcurve (Draw_Interpretor&, Standard_Integer, const char**);
+static Standard_Integer edgestowire  (Draw_Interpretor&, Standard_Integer, const char**);
 
 
 //=======================================================================
@@ -41,6 +42,7 @@ static Standard_Integer attachpcurve   (Draw_Interpretor&, Standard_Integer, con
   // Commands
   
   theCommands.Add("attachpcurve", "attachpcurve eold enew face", __FILE__, attachpcurve, group);
+  theCommands.Add("edgestowire" , "edgestowire wire edges"     , __FILE__, edgestowire , group);
 }
 
 //=======================================================================
@@ -102,3 +104,27 @@ static Standard_Integer attachpcurve(Draw_Interpretor& theDI,
 
   return 0;
 }
+
+//=======================================================================
+//function : edgestowire
+//purpose  : Orients the edges to make wire
+//=======================================================================
+static Standard_Integer edgestowire(Draw_Interpretor& theDI,
+                                    Standard_Integer  theNArg,
+                                    const char ** theArgVal)
+{
+  if (theNArg != 3) {
+    theDI << "Use: edgestowire wire edges\n";
+    return 1;
+  }
+  //
+  TopoDS_Shape anEdges = DBRep::Get(theArgVal[2]);
+  if (anEdges.IsNull()) {
+    theDI << "no edges\n";
+    return 1;
+  }
+  //
+  BOPTools_AlgoTools::OrientEdgesOnWire(anEdges);
+  DBRep::Set(theArgVal[1], anEdges);
+  return 0;
+}
diff --git a/src/BOPTools/BOPTools_AlgoTools.cxx b/src/BOPTools/BOPTools_AlgoTools.cxx
index d695831fe7..85be6dac95 100644
--- a/src/BOPTools/BOPTools_AlgoTools.cxx
+++ b/src/BOPTools/BOPTools_AlgoTools.cxx
@@ -18,6 +18,7 @@
 
 #include <BOPCol_IndexedMapOfShape.hxx>
 #include <BOPCol_MapOfShape.hxx>
+#include <BOPCol_MapOfOrientedShape.hxx>
 #include <BOPTools.hxx>
 #include <BOPTools_AlgoTools.hxx>
 #include <BOPTools_AlgoTools2D.hxx>
@@ -54,6 +55,7 @@
 #include <TopAbs_Orientation.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
 #include <TopoDS_Compound.hxx>
 #include <TopoDS_CompSolid.hxx>
 #include <TopoDS_Edge.hxx>
@@ -197,6 +199,94 @@ void BOPTools_AlgoTools::MakeConnexityBlocks
   }// for (; aIt.More(); aIt.Next()) 
 }
 //=======================================================================
+// function: OrientEdgesOnWire
+// purpose: Reorient edges on wire for correct ordering
+//=======================================================================
+void BOPTools_AlgoTools::OrientEdgesOnWire(TopoDS_Shape& theWire)
+{
+  // make vertex-edges connexity map
+  BOPCol_IndexedDataMapOfShapeListOfShape aVEMap;
+  BOPTools::MapShapesAndAncestors(theWire, TopAbs_VERTEX, TopAbs_EDGE, aVEMap);
+  //
+  if (aVEMap.IsEmpty()) {
+    return;
+  }
+  //
+  BRep_Builder aBB;
+  // new wire
+  TopoDS_Wire aWire;
+  aBB.MakeWire(aWire);
+  // fence map
+  BOPCol_MapOfOrientedShape aMFence;
+  //
+  TopoDS_Iterator aIt(theWire);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Edge& aEC = TopoDS::Edge(aIt.Value());
+    if (!aMFence.Add(aEC)) {
+      continue;
+    }
+    //
+    // add edge to a wire as it is
+    aBB.Add(aWire, aEC);
+    //
+    TopoDS_Vertex aV1, aV2;
+    TopExp::Vertices(aEC, aV1, aV2, Standard_True);
+    //
+    if (aV1.IsSame(aV2)) {
+      // closed edge, go to the next edge
+      continue;
+    }
+    //
+    // orient the adjacent edges
+    for (Standard_Integer i = 0; i < 2; ++i) {
+      TopoDS_Shape aVC = !i ? aV1 : aV2;
+      //
+      for (;;) {
+        const BOPCol_ListOfShape& aLE = aVEMap.FindFromKey(aVC);
+        if (aLE.Extent() != 2) {
+          // free vertex or multi-connexity, go to the next edge
+          break;
+        }
+        //
+        Standard_Boolean bStop = Standard_True;
+        //
+        BOPCol_ListIteratorOfListOfShape aItLE(aLE);
+        for (; aItLE.More(); aItLE.Next()) {
+          const TopoDS_Edge& aEN = TopoDS::Edge(aItLE.Value());
+          if (aMFence.Contains(aEN)) {
+            continue;
+          }
+          //
+          TopoDS_Vertex aVN1, aVN2;
+          TopExp::Vertices(aEN, aVN1, aVN2, Standard_True);
+          if (aVN1.IsSame(aVN2)) {
+            // closed edge, go to the next edge
+            break;
+          }
+          //
+          // change orientation if necessary and go to the next edges
+          if ((!i && aVC.IsSame(aVN2)) || (i && aVC.IsSame(aVN1))) {
+            aBB.Add(aWire, aEN);
+          }
+          else {
+            aBB.Add(aWire, aEN.Reversed());
+          }
+          aMFence.Add(aEN);
+          aVC = aVC.IsSame(aVN1) ? aVN2 : aVN1;
+          bStop = Standard_False;
+          break;
+        }
+        //
+        if (bStop) {
+          break;
+        }
+      }
+    }
+  }
+  //
+  theWire = aWire;
+}
+//=======================================================================
 // function: OrientFacesOnShell
 // purpose: 
 //=======================================================================
diff --git a/src/BOPTools/BOPTools_AlgoTools.hxx b/src/BOPTools/BOPTools_AlgoTools.hxx
index feaf2509f8..dddfb07ae2 100644
--- a/src/BOPTools/BOPTools_AlgoTools.hxx
+++ b/src/BOPTools/BOPTools_AlgoTools.hxx
@@ -193,8 +193,12 @@ public:
   //! theLCB (as list of compounds)
   //! in terms of connexity by the shapes of theType
   Standard_EXPORT static void MakeConnexityBlocks (const TopoDS_Shape& theS, const TopAbs_ShapeEnum theType1, const TopAbs_ShapeEnum theType2, BOPCol_ListOfShape& theLCB);
-  
-  Standard_EXPORT static void OrientFacesOnShell (TopoDS_Shape& theS);
+
+  //! Correctly orients edges on the wire
+  Standard_EXPORT static void OrientEdgesOnWire (TopoDS_Shape& theWire);
+
+  //! Correctly orients faces on the shell
+  Standard_EXPORT static void OrientFacesOnShell (TopoDS_Shape& theShell);
   
 
   //! Provides valid values of tolerances for the shape <theS>
diff --git a/tests/boolean/bcommon_2d/F3 b/tests/boolean/bcommon_2d/F3
index 69a6cecfbd..c4d4be1685 100644
--- a/tests/boolean/bcommon_2d/F3
+++ b/tests/boolean/bcommon_2d/F3
@@ -3,7 +3,7 @@ restore [locate_data_file offset_wire_034.brep] b
 
 bcommon result b a
 
-checkprops result -l 691.95
+checkprops result -l 345.975
 checksection result
 checknbshapes result -vertex 8 -edge 7 -t
 
diff --git a/tests/boolean/bcommon_2d/F4 b/tests/boolean/bcommon_2d/F4
index dba135c2eb..d914dd080e 100644
--- a/tests/boolean/bcommon_2d/F4
+++ b/tests/boolean/bcommon_2d/F4
@@ -3,7 +3,7 @@ restore [locate_data_file case_3_wire2.brep] b
 
 bcommon result b a
 
-checkprops result -l 691.95
+checkprops result -l 345.975
 checksection result
 checknbshapes result -vertex 14 -edge 13 -t
 
diff --git a/tests/boolean/bcommon_2d/F5 b/tests/boolean/bcommon_2d/F5
index 3b29e74907..f50b1d41d6 100644
--- a/tests/boolean/bcommon_2d/F5
+++ b/tests/boolean/bcommon_2d/F5
@@ -3,7 +3,7 @@ restore [locate_data_file case_3_wire5.brep] b
 
 bcommon result b a
 
-checkprops result -l 132.732
+checkprops result -l 66.3661
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bcommon_2d/N8 b/tests/boolean/bcommon_2d/N8
index 5db9303c50..d50c21f90c 100644
--- a/tests/boolean/bcommon_2d/N8
+++ b/tests/boolean/bcommon_2d/N8
@@ -3,7 +3,7 @@ restore [locate_data_file case_9_wire1.brep] b
 
 bcommon result b a
 
-checkprops result -l 287.575
+checkprops result -l 143.787
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bcommon_2d/N9 b/tests/boolean/bcommon_2d/N9
index 2e28b209c0..58d2f06811 100644
--- a/tests/boolean/bcommon_2d/N9
+++ b/tests/boolean/bcommon_2d/N9
@@ -3,7 +3,7 @@ restore [locate_data_file case_9_wire2.brep] b
 
 bcommon result b a
 
-checkprops result -l 287.575
+checkprops result -l 143.787
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bcommon_2d/O1 b/tests/boolean/bcommon_2d/O1
index 7726d9837e..59ebd0268a 100644
--- a/tests/boolean/bcommon_2d/O1
+++ b/tests/boolean/bcommon_2d/O1
@@ -3,7 +3,7 @@ restore [locate_data_file case_9_wire3.brep] b
 
 bcommon result b a
 
-checkprops result -l 159.8
+checkprops result -l 79.9002
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bcommon_2d/O7 b/tests/boolean/bcommon_2d/O7
index 8d35aa0f2c..f8e1535045 100644
--- a/tests/boolean/bcommon_2d/O7
+++ b/tests/boolean/bcommon_2d/O7
@@ -3,7 +3,7 @@ restore [locate_data_file case_9_wire1.brep] b
 
 bcommon result b a
 
-checkprops result -l 287.575
+checkprops result -l 143.787
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bopcommon_2d/F3 b/tests/boolean/bopcommon_2d/F3
index 4c5fb8f07d..d5d8b00904 100644
--- a/tests/boolean/bopcommon_2d/F3
+++ b/tests/boolean/bopcommon_2d/F3
@@ -4,7 +4,7 @@ restore [locate_data_file offset_wire_034.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 691.95
+checkprops result -l 345.975
 checksection result
 checknbshapes result -vertex 8 -edge 7 -t
 
diff --git a/tests/boolean/bopcommon_2d/F4 b/tests/boolean/bopcommon_2d/F4
index e2feb823ae..370a6e1477 100644
--- a/tests/boolean/bopcommon_2d/F4
+++ b/tests/boolean/bopcommon_2d/F4
@@ -4,7 +4,7 @@ restore [locate_data_file case_3_wire2.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 691.95
+checkprops result -l 345.975
 checksection result
 checknbshapes result -vertex 14 -edge 13 -t
 
diff --git a/tests/boolean/bopcommon_2d/F5 b/tests/boolean/bopcommon_2d/F5
index 9232a1f79d..440600962f 100644
--- a/tests/boolean/bopcommon_2d/F5
+++ b/tests/boolean/bopcommon_2d/F5
@@ -4,7 +4,7 @@ restore [locate_data_file case_3_wire5.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 132.732
+checkprops result -l 66.3661
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bopcommon_2d/N8 b/tests/boolean/bopcommon_2d/N8
index ac0211ee91..bd71120c22 100644
--- a/tests/boolean/bopcommon_2d/N8
+++ b/tests/boolean/bopcommon_2d/N8
@@ -4,7 +4,7 @@ restore [locate_data_file case_9_wire1.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 287.575
+checkprops result -l 143.787
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bopcommon_2d/N9 b/tests/boolean/bopcommon_2d/N9
index deb6774153..90f6b6fb17 100644
--- a/tests/boolean/bopcommon_2d/N9
+++ b/tests/boolean/bopcommon_2d/N9
@@ -4,7 +4,7 @@ restore [locate_data_file case_9_wire2.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 287.575
+checkprops result -l 143.787
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bopcommon_2d/O1 b/tests/boolean/bopcommon_2d/O1
index 29f1692135..fdb80c32f9 100644
--- a/tests/boolean/bopcommon_2d/O1
+++ b/tests/boolean/bopcommon_2d/O1
@@ -4,7 +4,7 @@ restore [locate_data_file case_9_wire3.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 159.8
+checkprops result -l 79.9002
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bopcommon_2d/O7 b/tests/boolean/bopcommon_2d/O7
index d2a930d92a..7827f872d6 100644
--- a/tests/boolean/bopcommon_2d/O7
+++ b/tests/boolean/bopcommon_2d/O7
@@ -4,7 +4,7 @@ restore [locate_data_file case_9_wire1.brep] b
 bop a b
 bopcommon result
 
-checkprops result -l 287.575
+checkprops result -l 143.787
 checksection result
 checknbshapes result -vertex 2 -edge 1 -t
 
diff --git a/tests/boolean/bopcommon_complex/L3 b/tests/boolean/bopcommon_complex/L3
index 4ccbc3fc23..ecfee32859 100644
--- a/tests/boolean/bopcommon_complex/L3
+++ b/tests/boolean/bopcommon_complex/L3
@@ -4,5 +4,5 @@ restore [locate_data_file sh2a] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 700
+checkprops result -s 350
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/L6 b/tests/boolean/bopcommon_complex/L6
index fe929868c4..a943daa42b 100644
--- a/tests/boolean/bopcommon_complex/L6
+++ b/tests/boolean/bopcommon_complex/L6
@@ -4,5 +4,5 @@ restore [locate_data_file sh7] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 200
+checkprops result -s 100
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/L7 b/tests/boolean/bopcommon_complex/L7
index 59a063bda1..56b4b6e70e 100644
--- a/tests/boolean/bopcommon_complex/L7
+++ b/tests/boolean/bopcommon_complex/L7
@@ -4,5 +4,5 @@ restore [locate_data_file sh8] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 191.421
+checkprops result -s 95.7107
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/L8 b/tests/boolean/bopcommon_complex/L8
index 7f639db3cd..74f3ab96fd 100644
--- a/tests/boolean/bopcommon_complex/L8
+++ b/tests/boolean/bopcommon_complex/L8
@@ -4,5 +4,5 @@ restore [locate_data_file sh9] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 800
+checkprops result -s 400
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/L9 b/tests/boolean/bopcommon_complex/L9
index 020028f985..30ed85ff5d 100644
--- a/tests/boolean/bopcommon_complex/L9
+++ b/tests/boolean/bopcommon_complex/L9
@@ -4,5 +4,5 @@ restore [locate_data_file shx] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 662.742
+checkprops result -s 331.371
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/M3 b/tests/boolean/bopcommon_complex/M3
index 49abd94a24..e1517435ce 100644
--- a/tests/boolean/bopcommon_complex/M3
+++ b/tests/boolean/bopcommon_complex/M3
@@ -4,5 +4,5 @@ restore [locate_data_file sg2] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 4188.79
+checkprops result -s 2094.4
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/M4 b/tests/boolean/bopcommon_complex/M4
index 6caa88490e..03d1db6dff 100644
--- a/tests/boolean/bopcommon_complex/M4
+++ b/tests/boolean/bopcommon_complex/M4
@@ -4,5 +4,5 @@ restore [locate_data_file sf5] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 3221.73
+checkprops result -s 1610.86
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/M5 b/tests/boolean/bopcommon_complex/M5
index 19e809e8f2..7821f20549 100644
--- a/tests/boolean/bopcommon_complex/M5
+++ b/tests/boolean/bopcommon_complex/M5
@@ -4,5 +4,5 @@ restore [locate_data_file sf3] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 3221.73
+checkprops result -s 1610.86
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopcommon_complex/M6 b/tests/boolean/bopcommon_complex/M6
index 37e7a1a24e..5b565cbaac 100644
--- a/tests/boolean/bopcommon_complex/M6
+++ b/tests/boolean/bopcommon_complex/M6
@@ -4,5 +4,5 @@ restore [locate_data_file sf55] b2
 bop b1 b2
 bopcommon result
 
-checkprops result -s 75398.2
+checkprops result -s 37699.1
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopfuse_complex/O2 b/tests/boolean/bopfuse_complex/O2
index db2ebd79ef..8a852cb0d6 100644
--- a/tests/boolean/bopfuse_complex/O2
+++ b/tests/boolean/bopfuse_complex/O2
@@ -4,5 +4,5 @@ restore [locate_data_file sf5] b2
 bop b1 b2
 bopfuse result
 
-checkprops result -s 64442.7
+checkprops result -s 62831.9
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/boolean/bopfuse_complex/O3 b/tests/boolean/bopfuse_complex/O3
index 32bf6aad6f..65ad2281bc 100644
--- a/tests/boolean/bopfuse_complex/O3
+++ b/tests/boolean/bopfuse_complex/O3
@@ -4,5 +4,5 @@ restore [locate_data_file sf3] b2
 bop b1 b2
 bopfuse result
 
-checkprops result -s 64442.7
+checkprops result -s 62831.9
 checkview -display result -2d -otherwise { b1 b2 } -s -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_1/bug13538 b/tests/bugs/modalg_1/bug13538
index e224ecaad3..28148d0305 100755
--- a/tests/bugs/modalg_1/bug13538
+++ b/tests/bugs/modalg_1/bug13538
@@ -15,8 +15,8 @@ explode b Sh
 bop a_1 b_1
 bopcommon result
 
-checkprops result -s 20000
+checkprops result -s 10000
 checkshape result
-checknbshapes result -vertex 4 -edge 4 -wire 1 -face 1 -shell 2 -solid 0 -compsolid 0 -compound 1 -shape 13
+checknbshapes result -vertex 4 -edge 4 -wire 1 -face 1 -shell 1 -solid 0 -compsolid 0 -compound 1 -shape 12
 set 2viewer 0
 
diff --git a/tests/bugs/modalg_4/bug726_2 b/tests/bugs/modalg_4/bug726_2
index c1636c26c2..461c2e37f8 100755
--- a/tests/bugs/modalg_4/bug726_2
+++ b/tests/bugs/modalg_4/bug726_2
@@ -1,4 +1,3 @@
-puts "TODO OCC12345 ALL: Faulty shapes in variables faulty_1 to faulty_"
 puts "TODO OCC12345 ALL: Error : The area of result shape is"
 
 puts "========"
diff --git a/tests/bugs/modalg_6/bug26980 b/tests/bugs/modalg_6/bug26980
index 9816fcb810..5066a6e3f2 100644
--- a/tests/bugs/modalg_6/bug26980
+++ b/tests/bugs/modalg_6/bug26980
@@ -6,7 +6,7 @@ puts ""
 # Intersection part of Boolean algorithm spends much system time and system memory
 #################################
 
-set max_time 120
+set max_time 130
 set mem_max_wsetpeak 500000000
 
 
diff --git a/tests/bugs/modalg_6/bug28189_1 b/tests/bugs/modalg_6/bug28189_1
new file mode 100644
index 0000000000..4f51c38f8b
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_1
@@ -0,0 +1,38 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+restore [locate_data_file bug28189_contour.brep] s
+restore [locate_data_file bug28189_solid.brep] c
+
+bcommon result s c
+
+checknbshapes result -vertex 3 -edge 2 -wire 1
+checkprops result -l 173.267
+
+# check orientation of edges in the resulting wire
+
+explode result e
+explode result_1 v
+explode result_2 v
+
+set cmp1 [compare result_1_1 result_2_1]
+set cmp2 [compare result_1_1 result_2_2]
+
+if {[regexp "same shapes" $cmp1]} {
+  if {[regexp "equal shapes" $cmp1]} {
+    puts "Error: Incorrect orientation of edges in wire"
+  }
+} elseif {[regexp "same shapes" $cmp2]} {
+  if {[regexp "equal shapes" $cmp2]} {
+    puts "Error: Incorrect orientation of edges in wire"
+  }
+} else {
+  puts "Error: No shared vertex"
+}
+
+checkview -display result -2d -path ${imagedir}/${test_image}.png
\ No newline at end of file
diff --git a/tests/bugs/modalg_6/bug28189_2 b/tests/bugs/modalg_6/bug28189_2
new file mode 100644
index 0000000000..6d878c4d3a
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_2
@@ -0,0 +1,15 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+box b1 10 10 10
+box b2 10 10 10
+eval compound [explode b1 w] b1
+eval compound [explode b1 w] b2
+bcommon result b1 b2
+
+checknbshapes result -wire 6
diff --git a/tests/bugs/modalg_6/bug28189_3 b/tests/bugs/modalg_6/bug28189_3
new file mode 100644
index 0000000000..b2c2fd3cc6
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_3
@@ -0,0 +1,15 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+box b1 10 10 10
+box b2 10 10 10
+eval compound [explode b1 w] b1
+eval compound [explode b1 w] b2
+bfuse result b1 b2
+
+checknbshapes result -wire 6
diff --git a/tests/bugs/modalg_6/bug28189_4 b/tests/bugs/modalg_6/bug28189_4
new file mode 100644
index 0000000000..76f51bfc3e
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_4
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+box b1 10 10 10
+box b2 10 10 10
+eval compound [explode b1 w] b1
+eval compound [explode b1 w] b2
+ttranslate b2 5 0 0
+bcommon result b1 b2
+
+checknbshapes result -wire 4
diff --git a/tests/bugs/modalg_6/bug28189_5 b/tests/bugs/modalg_6/bug28189_5
new file mode 100644
index 0000000000..ba17389cd8
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_5
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+box b1 10 10 10
+box b2 10 10 10
+eval compound [explode b1 w] b1
+eval compound [explode b1 w] b2
+ttranslate b2 5 0 0
+bfuse result b1 b2
+
+checknbshapes result -wire 12
diff --git a/tests/bugs/modalg_6/bug28189_6 b/tests/bugs/modalg_6/bug28189_6
new file mode 100644
index 0000000000..ec2593abb2
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_6
@@ -0,0 +1,41 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+vertex v1 0 0 0
+vertex v2 1 0 0
+vertex v3 1 1 0
+vertex v4 0 1 0
+edge e1 v1 v2
+edge e2 v3 v2
+edge e3 v3 v4
+edge e4 v1 v4
+
+compound e1 e2 e3 e4 edges
+edgestowire result edges
+
+if {![regexp "WIRE" [whatis result]]} {
+  puts "Error: Wire is not created"
+}
+
+explode result
+
+if {![regexp "FORWARD" [whatis result_1]]} {
+  puts "Error: Incorrect orientation of edges in wire"
+}
+
+if {![regexp "REVERSED" [whatis result_2]]} {
+  puts "Error: Incorrect orientation of edges in wire"
+}
+
+if {![regexp "FORWARD" [whatis result_3]]} {
+  puts "Error: Incorrect orientation of edges in wire"
+}
+
+if {![regexp "REVERSED" [whatis result_4]]} {
+  puts "Error: Incorrect orientation of edges in wire"
+}
diff --git a/tests/bugs/modalg_6/bug28189_7 b/tests/bugs/modalg_6/bug28189_7
new file mode 100644
index 0000000000..5fad480f58
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_7
@@ -0,0 +1,27 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+polyline p1 0 0 0 1 0 0
+polyline p2 0 0 0 1 0 0
+
+orientation p1 R
+orientation p2 F
+
+bfuse result1 p1 p2
+explode result1
+
+if {![regexp "REVERSED" [whatis result1_1]]} {
+  puts "Error: Incorrect orientation of wire"
+}
+
+bcommon result2 p2 p1
+explode result2
+
+if {![regexp "FORWARD" [whatis result2_1]]} {
+  puts "Error: Incorrect orientation of wire"
+}
diff --git a/tests/bugs/modalg_6/bug28189_8 b/tests/bugs/modalg_6/bug28189_8
new file mode 100644
index 0000000000..08e860cdd9
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_8
@@ -0,0 +1,17 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+box b1 10 10 10
+box b2 5 5 5 10 10 10
+shape c1 Cs
+shape c2 Cs
+add b1 c1
+add b2 c2
+
+bfuse result c1 c2
+checknbshapes result -compsolid 1 -solid 1
diff --git a/tests/bugs/modalg_6/bug28189_9 b/tests/bugs/modalg_6/bug28189_9
new file mode 100644
index 0000000000..9a1de7b24b
--- /dev/null
+++ b/tests/bugs/modalg_6/bug28189_9
@@ -0,0 +1,40 @@
+puts "========"
+puts "OCC28189"
+puts "========"
+puts ""
+#################################################
+# Result of Boolean operation is non-manifold wire
+#################################################
+
+box b1 10 10 10
+box b2 5 5 5 10 10 10
+box b3 20 0 0 10 10 10
+box b4 25 5 5 10 10 10
+shape c1 Cs
+shape c2 Cs
+add b1 c1
+add b2 c2
+
+bclearobjects
+bcleartools
+baddobjects c1 b3
+baddtools c2 b4
+bfillds
+bbop result 1
+
+checknbshapes result -solid 2 -compsolid 1
+
+explode result
+
+if {[regexp "COMPSOLID" [whatis result_1]]} {
+  if {![regexp "SOLID" [whatis result_2]]} {
+    puts "Error: Incorrect shape types in the result"
+  }
+} elseif {[regexp "SOLID" [whatis result_1]]} {
+  if {![regexp "COMPSOLID" [whatis result_2]]} {
+    puts "Error: Incorrect shape types in the result"
+  }
+} else {
+  puts "Error: Incorrect shape types in the result"
+}
+