Salome HOME
Initial implementation of work of "To add all elements that share the same topology...
[modules/shaper.git] / src / Selector / Selector_Selector.cpp
index c514b8c1231ddce80f1db92af663a7125e9763c8..140294004a7058bb65c2ab028dc533b1144b6328 100644 (file)
 #include <Selector_NameGenerator.h>
 #include <Selector_NExplode.h>
 
-#include <TDF_ChildIDIterator.hxx>
 #include <TopoDS_Iterator.hxx>
 #include <TopoDS_Builder.hxx>
+#include <TopoDS.hxx>
 #include <TopExp_Explorer.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
 #include <TNaming_Tool.hxx>
 #include <TNaming_NewShapeIterator.hxx>
 #include <TNaming_OldShapeIterator.hxx>
 #include <TNaming_Iterator.hxx>
 #include <TNaming_Builder.hxx>
 #include <TopTools_MapOfShape.hxx>
+#include <BRep_Tool.hxx>
 
+#include <TDF_ChildIDIterator.hxx>
+#include <TDF_Tool.hxx>
 #include <TDataStd_Integer.hxx>
 #include <TDataStd_ReferenceArray.hxx>
 #include <TDataStd_IntegerArray.hxx>
 #include <TDataStd_Name.hxx>
+#include <TDataStd_UAttribute.hxx>
+#include <TDataStd_ExtStringList.hxx>
 
 #include <list>
 
-/// type of the selection, integerm keeps the Selector_Type value
+/// type of the selection, integer keeps the Selector_Type value
 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
 /// type of the shape, stored in case it is intersection or container
 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
 //  reference attribute that contains the reference to labels where the "from" or "base" shapes
 // of selection are located
 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
+// if the base array contains reference to the root label, this means that it refers to an
+// external document and this list contains a tag in the document
+static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a");
 // array of the neighbor levels
 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
 // weak index (integer) of the sub-shape
 static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
+// geometrical naming indicator
+static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
+
+// string identifier of the weak name in modification or intersection types of algorithm
+static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
+// string identifier of the pure weak name algorithm
+static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
+
 
 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
 {
   myWeakIndex = -1;
+  myAlwaysGeometricalNaming = false;
 }
 
 TDF_Label Selector_Selector::label()
@@ -64,37 +83,54 @@ TDF_Label Selector_Selector::label()
   return myLab;
 }
 
+void Selector_Selector::setBaseDocument(const TDF_Label theAccess)
+{
+  myBaseDocumentLab = theAccess;
+}
+
 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
-static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
-  bool aMustBeAtFinal, TDF_LabelList& theResult)
+static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal,
+  const TopoDS_Shape& theValue,
+  bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
 {
-  TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
+  bool aFoundAnyShape = false;
+  TNaming_SameShapeIterator aLabIter(theValue, theAccess);
   for(; aLabIter.More(); aLabIter.Next()) {
     Handle(TNaming_NamedShape) aNS;
-    aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
-    if (aMustBeAtFinal && aNS != theFinal)
-      continue; // looking for old at the same final label only
-    TNaming_Evolution anEvolution = aNS->Evolution();
-    if (anEvolution == TNaming_PRIMITIVE) {
-      // check that this is not in the results already
-      const TDF_Label aResult = aNS->Label();
-      TDF_LabelList::Iterator aResIter(theResult);
-      for(; aResIter.More(); aResIter.Next()) {
-        if (aResIter.Value().IsEqual(aResult))
-          break;
+    if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+      if (aMustBeAtFinal && aNS != theFinal)
+        continue; // looking for old at the same final label only
+      TNaming_Evolution anEvolution = aNS->Evolution();
+      if (anEvolution == TNaming_PRIMITIVE) {
+        // check that this is not in the results already
+        const TDF_Label aResult = aNS->Label();
+        TDF_LabelList::Iterator aResIter(theResult);
+        for(; aResIter.More(); aResIter.Next()) {
+          if (aResIter.Value().IsEqual(aResult))
+            break;
+        }
+        if (!aResIter.More()) // not found, so add this new
+          theResult.Append(aResult);
+        aFoundAnyShape = true;
       }
-      if (!aResIter.More()) // not found, so add this new
-        theResult.Append(aResult);
-    }
-    if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
-      for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
-        if (aThisIter.NewShape().IsSame(theValue)) {
-          // continue recursively, null NS means that any NS are ok
-          findBases(theFinal, aThisIter.OldShape(), false, theResult);
+      if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
+        for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
+          if (aThisIter.NewShape().IsSame(theValue)) {
+            // continue recursively, null NS means that any NS are ok
+            findBases(theAccess, theFinal, aThisIter.OldShape(),
+              false, theAdditionalDocument, theResult);
+            aFoundAnyShape = true;
+          }
         }
       }
     }
   }
+  if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document
+    static TDF_Label anEmpty;
+    if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue))
+      findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue,
+        false, anEmpty, theResult);
+  }
 }
 
 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
@@ -165,9 +201,33 @@ static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theV
   }
 }
 
+/// Returns true if the given shapes are based on the same geometry
+static bool sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) {
+  if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType())
+  {
+    if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces
+      TopLoc_Location aLoc1, aLoc2;
+      TopoDS_Face aFace1 = TopoDS::Face(theShape1);
+      Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1);
+      TopoDS_Face aFace2 = TopoDS::Face(theShape2);
+      Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2);
+      return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2);
+    } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves
+      TopLoc_Location aLoc1, aLoc2;
+      Standard_Real aFirst, aLast;
+      TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1);
+      Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast);
+      TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2);
+      Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast);
+      return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2);
+    }
+  }
+  return false;
+}
+
 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
-  const std::list<std::pair<TopoDS_Shape, int> >& theNB)
+  const std::list<std::pair<TopoDS_Shape, int> >& theNB, const bool theGeometrical)
 {
   // searching for neighbors with minimum level
   int aMinLevel = 0;
@@ -206,6 +266,7 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
     return TopoDS_Shape(); // not found any candidate
   if (aMatches.Extent() == 1)
     return aMatches.First(); // already found good candidate
+  TopoDS_Compound aResultCompound; // in case of geometrical name and many candidates
   // iterate all matches to find by other (higher level) neighbors the best candidate
   TopoDS_Shape aGoodCandidate;
   for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
@@ -222,8 +283,16 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
       if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
         if (aGoodCandidate.IsNull()) {
           aGoodCandidate = aCandidate.Value();
-        } else { // too many good candidates
-          return TopoDS_Shape();
+        } else { // another good candidate
+          if (theGeometrical && sameGeometry(aGoodCandidate, aCandidate.Value())) {
+            static TopoDS_Builder aBuilder;
+            if (aResultCompound.IsNull()) {
+              aBuilder.MakeCompound(aResultCompound);
+              aBuilder.Add(aResultCompound, aGoodCandidate);
+            }
+            aBuilder.Add(aResultCompound, aCandidate.Value());
+          } else
+            return TopoDS_Shape();
         }
       }
       if (!aLevelNBs.IsEmpty()) {
@@ -241,24 +310,60 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
         break;
     }
   }
+  if (!aResultCompound.IsNull())
+    return aResultCompound;
   return aGoodCandidate;
 }
 
 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
-  const bool theUseNeighbors)
+  const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections)
 {
   if (theValue.IsNull() || theContext.IsNull())
     return false;
+  myGeometricalNaming = theGeometricalNaming;
   // check the value shape can be named as it is, or it is needed to construct it from the
   // higher level shapes (like a box vertex by faces that form this vertex)
-  if (!TNaming_Tool::HasLabel(myLab, theValue)) {
+  bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
+  if (aIsFound) { // additional check for selection and delete evolution only: also could not use
+    aIsFound = false;
+    for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
+    {
+      Handle(TNaming_NamedShape) aNS;
+      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
+            aNS->Evolution() == TNaming_PRIMITIVE) {
+          aIsFound = true;
+          break;
+        }
+      }
+    }
+  }
+  // searching in the base document
+  if (!aIsFound && !myBaseDocumentLab.IsNull() &&
+      TNaming_Tool::HasLabel(myBaseDocumentLab, theValue))
+  {
+    TNaming_SameShapeIterator aShapes(theValue, myBaseDocumentLab);
+    for(; aShapes.More(); aShapes.Next())
+    {
+      Handle(TNaming_NamedShape) aNS;
+      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
+          aNS->Evolution() == TNaming_PRIMITIVE) {
+          aIsFound = true;
+          break;
+        }
+      }
+    }
+  }
+  if (!aIsFound) {
     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
     myShapeType = aSelectionType;
     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
         aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
     { // iterate all sub-shapes and select them on sublabels
       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
-        if (!selectBySubSelector(theContext, aSubIter.Value())) {
+        if (!selectBySubSelector(theContext, aSubIter.Value(),
+            false, theUseNeighbors, theUseIntersections)) {//for subs no geometrical naming allowed
           return false; // if some selector is failed, everything is failed
         }
       }
@@ -268,7 +373,9 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
 
     // try to find the shape of the higher level type in the context shape
     bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
-    while(aSelectionType != TopAbs_FACE || !aFacesTried) {
+    TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
+    TopoDS_ListOfShape aLastIntersectors;
+    while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) {
       if (aSelectionType == TopAbs_FACE) {
         if (theValue.ShapeType() != TopAbs_VERTEX)
           break;
@@ -279,6 +386,9 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
       TopoDS_ListOfShape anIntList; // same as anIntersectors
       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
+        if (aSelectionType == TopAbs_EDGE &&
+            BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
+          continue;
         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
         for(; aSubExp.More(); aSubExp.Next()) {
           if (aSubExp.Current().IsSame(theValue)) {
@@ -293,24 +403,28 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
       commonShapes(anIntList, theValue.ShapeType(), aCommon);
       if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
         // name the intersectors
-        std::list<Selector_Selector> aSubSelList;
-        TopTools_MapOfShape::Iterator anInt(anIntersectors);
+        mySubSelList.clear();
+        TopoDS_ListOfShape::Iterator anInt(anIntList);
         for (; anInt.More(); anInt.Next()) {
-          if (!selectBySubSelector(theContext, anInt.Value())) {
+          if (!selectBySubSelector(theContext, anInt.Value(),
+              theGeometricalNaming, theUseNeighbors, false)) {
             break; // if some selector is failed, stop and search another solution
           }
         }
         if (!anInt.More()) { // all intersectors were correctly named
           myType = SELTYPE_INTERSECT;
           return true;
-        }
+          }
+      } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty())  {
+        aLastCommon = aCommon;
+        aLastIntersectors = anIntList;
       }
     }
 
     if (!theUseNeighbors)
       return false;
 
-    // searching by neighbours
+    // searching by neighbors
     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
     for(int aLevel = 1; true; aLevel++) {
       TopTools_MapOfShape aNewNB;
@@ -318,20 +432,26 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
       if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
         break;
       }
-      // check which can be named correctly, without by neighbors type
-      for(TopTools_MapOfShape::Iterator aNBIter(aNewNB); aNBIter.More(); ) {
-        Selector_Selector aSelector(myLab.FindChild(1));
-        if (aSelector.select(theContext, aNBIter.Value(), false)) { // add to the list of good NBs
-          aNBs.push_back(std::pair<TopoDS_Shape, int>(aNBIter.Value(), aLevel));
+      // iterate by the order in theContext to keep same naming names
+      TopExp_Explorer anOrder(theContext, theValue.ShapeType());
+      for (; anOrder.More(); anOrder.Next()) {
+        if (aNewNB.Contains(anOrder.Current())) {
+          TopoDS_Shape aNewNBShape = anOrder.Current();
+          // check which can be named correctly, without "by neighbors" type
+          Selector_Selector aSelector(myLab.FindChild(1));
+          aSelector.setBaseDocument(myBaseDocumentLab);
+          if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false, false)) {
+            // add to list of good NBs
+            aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
+          }
         }
-        aNewNB.Remove(aNBIter.Key());
-        aNBIter.Initialize(aNewNB);
       }
-      TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
+      TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming);
       if (!aResult.IsNull() && aResult.IsSame(theValue)) {
         std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
         for(; aNBIter != aNBs.end(); aNBIter++) {
-          if (!selectBySubSelector(theContext, aNBIter->first, false)) {
+          if (!selectBySubSelector(theContext, aNBIter->first,
+              theGeometricalNaming, false, false)) {
             return false; // something is wrong because before this selection was ok
           }
           myNBLevel.push_back(aNBIter->second);
@@ -341,27 +461,98 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
         return true;
       }
     }
+
+    if (aLastCommon.Extent() > 1) {
+      if (myAlwaysGeometricalNaming) {
+        TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon);
+        TopoDS_Shape aFirst = aCommonIter.Value();
+        for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+          if (!sameGeometry(aFirst, aCommonIter.Value()))
+            break;
+        }
+        if (!aCommonIter.More()) { // all geometry is same, result is a compound
+          myType = SELTYPE_INTERSECT;
+          return true;
+        }
+      }
+      // weak naming to distinguish commons coming from intersection
+      Selector_NExplode aNexp(aLastCommon);
+      myWeakIndex = aNexp.index(theValue);
+      if (myWeakIndex != -1) {
+        // name the intersectors
+        mySubSelList.clear();
+        TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
+        for (; anInt.More(); anInt.Next()) {
+          if (!selectBySubSelector(theContext, anInt.Value(),
+              theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
+            break; // if some selector is failed, stop and search another solution
+          }
+        }
+        if (!anInt.More()) { // all intersectors were correctly named
+          myType = SELTYPE_INTERSECT;
+          return true;
+        }
+      }
+    }
+
+    // pure weak naming: there is no sense to use pure weak naming for neighbors selection
+    if (theUseNeighbors) {
+      myType = SELTYPE_WEAK_NAMING;
+      Selector_NExplode aNexp(theContext, theValue.ShapeType());
+      myWeakIndex = aNexp.index(theValue);
+      if (myWeakIndex != -1) {
+        myShapeType = theValue.ShapeType();
+        // searching for context shape label to store in myFinal
+        myFinal.Nullify();
+        if (TNaming_Tool::HasLabel(myLab, theContext)) {
+          for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
+          {
+            Handle(TNaming_NamedShape) aNS;
+            if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+              TNaming_Evolution anEvolution = aNS->Evolution();
+              if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
+                  anEvolution == TNaming_MODIFY) {
+                // check this is a new shape
+                for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
+                  if (aNSIter.NewShape().IsSame(theContext)) {
+                    myFinal = aNS->Label();
+                    break;
+                  }
+                }
+              }
+            }
+          }
+        }
+        return true; // could be final empty (in case it is called recursively) or not
+      }
+    }
+
     return false;
   }
   // searching for the base shapes of the value
   Handle(TNaming_NamedShape) aPrimitiveNS;
   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
-  for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
-  {
-    Handle(TNaming_NamedShape) aNS;
-    if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
-      TNaming_Evolution anEvolution = aNS->Evolution();
-      if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
-        aPrimitiveNS = aNS;
-        break;
-      } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
-        // check this is a new shape
-        TNaming_Iterator aNSIter(aNS);
-        for(; aNSIter.More(); aNSIter.Next())
-          if (aNSIter.NewShape().IsSame(theValue))
-            break;
-        if (aNSIter.More()) // new was found
-          aModifList.Append(aNS);
+  for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
+    TDF_Label aLab = aUseExternal == 0 ? myLab : myBaseDocumentLab;
+    if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
+      continue;
+    for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
+    {
+      Handle(TNaming_NamedShape) aNS;
+      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        TNaming_Evolution anEvolution = aNS->Evolution();
+        if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
+          aPrimitiveNS = aNS;
+          break;
+        } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
+          // check this is a new shape
+          TNaming_Iterator aNSIter(aNS);
+          for(; aNSIter.More(); aNSIter.Next())
+            if (aNSIter.NewShape().IsSame(theValue))
+              break;
+          if (aNSIter.More()) // new was found
+            aModifList.Append(aNS);
+        }
       }
     }
   }
@@ -395,38 +586,57 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
 
   if (!aModifList.IsEmpty()) {
     // searching for all the base shapes of this modification
-    findBases(aModifList.First(), theValue, true, myBases);
+    findBases(myLab, aModifList.First(), theValue, true, myBaseDocumentLab, myBases);
     if (!myBases.IsEmpty()) {
       myFinal = aModifList.First()->Label();
       TopoDS_ListOfShape aCommon;
       findModificationResult(aCommon);
-      // trying to search by neighbours
+      // trying to search by neighbors
       if (aCommon.Extent() > 1) { // more complicated selection
+        if (myAlwaysGeometricalNaming) {
+          TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
+          TopoDS_Shape aFirst = aCommonIter.Value();
+          for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+            if (!sameGeometry(aFirst, aCommonIter.Value()))
+              break;
+          }
+          if (!aCommonIter.More()) { // all geometry is same, result is a compound
+            myType = SELTYPE_MODIFICATION;
+            return true;
+          }
+        }
         if (!theUseNeighbors)
           return false;
 
-        // searching by neighbours
-        std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
+        // searching by neighbors
+        std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
         for(int aLevel = 1; true; aLevel++) {
           TopTools_MapOfShape aNewNB;
           findNeighbors(theContext, theValue, aLevel, aNewNB);
           if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
             break;
           }
-          // check which can be named correctly, without by neighbors type
-          for(TopTools_MapOfShape::Iterator aNBIter(aNewNB); aNBIter.More(); ) {
-            Selector_Selector aSelector(myLab.FindChild(1));
-            if (aSelector.select(theContext, aNBIter.Value(), false)) { // add to the list of good NBs
-              aNBs.push_back(std::pair<TopoDS_Shape, int>(aNBIter.Value(), aLevel));
+          // iterate by the order in theContext to keep same naming names
+          TopExp_Explorer anOrder(theContext, theValue.ShapeType());
+          for (; anOrder.More(); anOrder.Next()) {
+            if (aNewNB.Contains(anOrder.Current())) {
+              TopoDS_Shape aNewNBShape = anOrder.Current();
+              // check which can be named correctly, without "by neighbors" type
+              Selector_Selector aSelector(myLab.FindChild(1));
+              if (!myBaseDocumentLab.IsNull())
+                aSelector.setBaseDocument(myBaseDocumentLab);
+              if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false)) {
+                // add to list of good NBs
+                aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
+              }
             }
-            aNewNB.Remove(aNBIter.Key());
-            aNBIter.Initialize(aNewNB);
           }
-          TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
+          TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming);
           if (!aResult.IsNull() && aResult.IsSame(theValue)) {
             std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
             for(; aNBIter != aNBs.end(); aNBIter++) {
-              if (!selectBySubSelector(theContext, aNBIter->first)) {
+              if (!selectBySubSelector(theContext, aNBIter->first,
+                  theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
                 return false; // something is wrong because before this selection was ok
               }
               myNBLevel.push_back(aNBIter->second);
@@ -436,8 +646,21 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
             return true;
           }
         }
-        // filter by neighbours did not help
-        if (aCommon.Extent() > 1) { // weak naming between the common results
+        // filter by neighbors did not help
+        if (aCommon.Extent() > 1) {
+          if (myAlwaysGeometricalNaming) {
+            TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
+            TopoDS_Shape aFirst = aCommonIter.Value();
+            for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+              if (!sameGeometry(aFirst, aCommonIter.Value()))
+                break;
+            }
+            if (!aCommonIter.More()) { // all geometry is same, result is a compound
+              myType = SELTYPE_FILTER_BY_NEIGHBOR;
+              return true;
+            }
+          }
+          // weak naming between the common results
           Selector_NExplode aNexp(aCommon);
           myWeakIndex = aNexp.index(theValue);
           if (myWeakIndex == -1)
@@ -446,17 +669,64 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape
       }
     }
     myType = SELTYPE_MODIFICATION;
-    return !myBases.IsEmpty();
+    if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
+      TopoDS_ListOfShape aCommon;
+      myFinal = aModifList.First()->Label();
+      Handle(TNaming_NamedShape) aNS;
+      if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
+          const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
+          if (!aNewShape.IsNull())
+            aCommon.Append(aNewShape);
+        }
+      }
+      Selector_NExplode aNexp(aCommon);
+      myWeakIndex = aNexp.index(theValue);
+      if (myWeakIndex == -1)
+        return false;
+    }
+    return true;
   }
 
   // not found a good result
   return false;
 }
 
+/// Stores the array of references to the label: references to elements of ref-list, then the last
+static void storeBaseArray(const TDF_Label& theLab,
+  const TDF_LabelList& theRef, const TDF_Label& theLast)
+{
+  Handle(TDataStd_ReferenceArray) anArray =
+    TDataStd_ReferenceArray::Set(theLab, kBASE_ARRAY, 0, theRef.Extent());
+  Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
+  const TDF_Label aThisDocRoot = theLab.Root();
+  TDF_LabelList::Iterator aBIter(theRef);
+  for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
+    const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
+    // check this is a label of this document
+    if (aLab.Root().IsEqual(aThisDocRoot)) {
+      anArray->SetValue(anIndex, aLab);
+    } else { // store reference to external document as an entry-string
+      if (anEntries.IsNull()) {
+        anEntries = TDataStd_ExtStringList::Set(theLab, kBASE_LIST);
+      }
+      TCollection_AsciiString anEntry;
+      TDF_Tool::Entry(aLab, anEntry);
+      anEntries->Append(anEntry);
+      anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
+    }
+    if (!aBIter.More())
+      break;
+  }
+}
+
 void Selector_Selector::store()
 {
+  static const TDF_LabelList anEmptyRefList;
   myLab.ForgetAllAttributes(true); // remove old naming data
   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
+  if (myGeometricalNaming)
+    TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING);
   switch(myType) {
   case SELTYPE_CONTAINER:
   case SELTYPE_INTERSECT: {
@@ -466,22 +736,17 @@ void Selector_Selector::store()
     for(; aSubSel != mySubSelList.end(); aSubSel++) {
       aSubSel->store();
     }
+    if (myWeakIndex != -1) {
+      TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
+    }
     break;
   }
   case SELTYPE_PRIMITIVE: {
-    Handle(TDataStd_ReferenceArray) anArray =
-      TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
-    anArray->SetValue(0, myFinal);
+    storeBaseArray(myLab, anEmptyRefList, myFinal);
     break;
   }
   case SELTYPE_MODIFICATION: {
-    Handle(TDataStd_ReferenceArray) anArray =
-      TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
-    TDF_LabelList::Iterator aBIter(myBases);
-    for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
-      anArray->SetValue(anIndex, aBIter.Value());
-    }
-    anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
+    storeBaseArray(myLab, myBases, myFinal);
     if (myWeakIndex != -1) {
       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
     }
@@ -501,6 +766,15 @@ void Selector_Selector::store()
     for(; aSubSel != mySubSelList.end(); aSubSel++) {
       aSubSel->store();
     }
+    break;
+  }
+  case SELTYPE_WEAK_NAMING: {
+    TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
+    TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
+    if (!myFinal.IsNull()) {
+      storeBaseArray(myLab, anEmptyRefList, myFinal);
+    }
+    break;
   }
   default: { // unknown case
     break;
@@ -508,11 +782,49 @@ void Selector_Selector::store()
   }
 }
 
+/// Restores references to the labels: references to elements of ref-list, then the last
+static bool restoreBaseArray(const TDF_Label& theLab, const TDF_Label& theBaseDocumetnLab,
+  TDF_LabelList& theRef, TDF_Label& theLast)
+{
+  const TDF_Label aThisDocRoot = theLab.Root();
+  Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
+  TDataStd_ListOfExtendedString::Iterator anIter;
+  Handle(TDataStd_ReferenceArray) anArray;
+  if (theLab.FindAttribute(kBASE_ARRAY, anArray)) {
+    int anUpper = anArray->Upper();
+    for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
+      TDF_Label aLab = anArray->Value(anIndex);
+      if (aLab.IsEqual(aThisDocRoot)) { // external document reference
+        if (theBaseDocumetnLab.IsNull())
+          return false;
+        if (anEntries.IsNull()) {
+          if (!theLab.FindAttribute(kBASE_LIST, anEntries))
+            return false;
+          anIter.Initialize(anEntries->List());
+        }
+        if (!anIter.More())
+          return false;
+        TDF_Tool::Label(theBaseDocumetnLab.Data(), anIter.Value(), aLab);
+        anIter.Next();
+      }
+      if (anIndex == anUpper) {
+        theLast = aLab;
+      } else {
+        theRef.Append(aLab);
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+
 bool Selector_Selector::restore()
 {
   Handle(TDataStd_Integer) aTypeAttr;
   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
     return false;
+  myGeometricalNaming = myLab.IsAttribute(kGEOMETRICAL_NAMING);
   myType = Selector_Type(aTypeAttr->Get());
   switch(myType) {
   case SELTYPE_CONTAINER:
@@ -526,27 +838,21 @@ bool Selector_Selector::restore()
     mySubSelList.clear();
     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
+      mySubSelList.back().setBaseDocument(myBaseDocumentLab);
       if (!mySubSelList.back().restore())
         aSubResult = false;
     }
+    Handle(TDataStd_Integer) aWeakInt;
+    if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
+      myWeakIndex = aWeakInt->Get();
+    }
     return aSubResult;
   }
   case SELTYPE_PRIMITIVE: {
-    Handle(TDataStd_ReferenceArray) anArray;
-    if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
-      myFinal = anArray->Value(0);
-      return true;
-    }
-    return false;
+    return restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal);
   }
   case SELTYPE_MODIFICATION: {
-    Handle(TDataStd_ReferenceArray) anArray;
-    if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
-      int anUpper = anArray->Upper();
-      for(int anIndex = 0; anIndex < anUpper; anIndex++) {
-        myBases.Append(anArray->Value(anIndex));
-      }
-      myFinal = anArray->Value(anUpper);
+    if (restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) {
       Handle(TDataStd_Integer) aWeakInt;
       if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
         myWeakIndex = aWeakInt->Get();
@@ -565,6 +871,7 @@ bool Selector_Selector::restore()
     mySubSelList.clear();
     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
+      mySubSelList.back().setBaseDocument(myBaseDocumentLab);
       if (!mySubSelList.back().restore())
         aSubResult = false;
     }
@@ -577,6 +884,19 @@ bool Selector_Selector::restore()
     }
     return true;
   }
+  case SELTYPE_WEAK_NAMING: {
+    Handle(TDataStd_Integer) aWeakInt;
+    if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
+      return false;
+    myWeakIndex = aWeakInt->Get();
+    Handle(TDataStd_Integer) aShapeTypeAttr;
+    if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
+      return false;
+    myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+    if (!restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal))
+      return false;
+    return true;
+  }
   default: { // unknown case
   }
   }
@@ -584,26 +904,39 @@ bool Selector_Selector::restore()
 }
 
 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
-static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
-  TopTools_MapOfShape& theResults)
+static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
+  const TDF_Label& theFinal,
+  const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults)
 {
-  for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
-    TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
-    if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
-      if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
-        theResults.Add(aBaseIter.Shape());
-      } else {
-        findFinals(aBaseIter.Shape(), theFinal, theResults);
+  if (TNaming_Tool::HasLabel(anAccess, theBase)) {
+    for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
+    {
+      TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
+      if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
+        if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
+          theResults.Add(aBaseIter.Shape());
+        } else {
+          findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults);
+        }
       }
     }
   }
+  if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
+    static TDF_Label anEmpty;
+    findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults);
+  }
 }
 
 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
+    TDF_Label anAdditionalDoc; // this document if base is started in extra document
+    if (aBase.Value().Root() != myLab.Root()) {
+      anAdditionalDoc = myLab;
+    }
     TopTools_MapOfShape aFinals;
-    for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
-      findFinals(aBaseShape.NewShape(), myFinal, aFinals);
+    for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
+      findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals);
+    }
     if (!aFinals.IsEmpty()) {
       if (theCommon.IsEmpty()) { // just copy all to common
         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
@@ -674,9 +1007,33 @@ bool Selector_Selector::solve(const TopoDS_Shape& theContext)
     }
     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
     commonShapes(aSubSelectorShapes, myShapeType, aCommon);
-    if (aCommon.Extent() != 1)
-      return false;
-    aResult = aCommon.First();
+    if (aCommon.Extent() != 1) {
+      if (myWeakIndex != -1) {
+        Selector_NExplode aNexp(aCommon);
+        aResult = aNexp.shape(myWeakIndex);
+      } else if (myGeometricalNaming && aCommon.Extent() > 1) {
+        // check results are on the same geometry, create compound
+        TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
+        TopoDS_Shape aFirst = aCommonIter.Value();
+        for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+          if (!sameGeometry(aFirst, aCommonIter.Value()))
+            break;
+        }
+        if (!aCommonIter.More()) { // all geometry is same, create a result compound
+          TopoDS_Builder aBuilder;
+          TopoDS_Compound aCompound;
+          aBuilder.MakeCompound(aCompound);
+          for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) {
+            aBuilder.Add(aCompound, aCommonIter.Value());
+          }
+          aResult = aCompound;
+        }
+      } else {
+        return false;
+      }
+    } else {
+      aResult = aCommon.First();
+    }
     break;
   }
   case SELTYPE_PRIMITIVE: {
@@ -684,16 +1041,47 @@ bool Selector_Selector::solve(const TopoDS_Shape& theContext)
     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
       aResult = aNS->Get();
     }
+    break;
   }
   case SELTYPE_MODIFICATION: {
-    TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
-    findModificationResult(aFinalsCommon);
-    if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
-      aResult = aFinalsCommon.First();
-    else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
-      Selector_NExplode aNExp(aFinalsCommon);
-      aResult = aNExp.shape(myWeakIndex);
+    if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index
+      TopoDS_ListOfShape aCommon;
+      Handle(TNaming_NamedShape) aNS;
+      if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
+          const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
+          if (!aNewShape.IsNull())
+            aCommon.Append(aNewShape);
+        }
+      }
+      Selector_NExplode aNexp(aCommon);
+      aResult = aNexp.shape(myWeakIndex);
+    } else { // standard case
+      TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
+      findModificationResult(aFinalsCommon);
+      if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape
+        aResult = aFinalsCommon.First();
+      } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) {
+        Selector_NExplode aNExp(aFinalsCommon);
+        aResult = aNExp.shape(myWeakIndex);
+      } else if (aFinalsCommon.Extent() > 1 && myGeometricalNaming) {// if same geometry - compound
+        TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon);
+        TopoDS_Shape aFirst = aCommonIter.Value();
+        for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+          if (!sameGeometry(aFirst, aCommonIter.Value()))
+            break;
+        }
+        if (!aCommonIter.More()) { // all geometry is same, create a result compound
+          TopoDS_Builder aBuilder;
+          TopoDS_Compound aCompound;
+          aBuilder.MakeCompound(aCompound);
+          for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) {
+            aBuilder.Add(aCompound, aCommonIter.Value());
+          }
+          aResult = aCompound;
+        }
 
+      }
     }
     break;
   }
@@ -707,7 +1095,23 @@ bool Selector_Selector::solve(const TopoDS_Shape& theContext)
       }
       aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
     }
-    aResult = findNeighbor(theContext, aNBs);
+    aResult = findNeighbor(theContext, aNBs, myGeometricalNaming);
+    break;
+  }
+  case SELTYPE_WEAK_NAMING: {
+    TopoDS_Shape aContext;
+    if (myFinal.IsNull()) {
+      aContext = theContext;
+    } else {
+      Handle(TNaming_NamedShape) aNS;
+      if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        aContext = aNS->Get();
+      }
+    }
+    if (!aContext.IsNull()) {
+      Selector_NExplode aNexp(aContext, myShapeType);
+      aResult = aNexp.shape(myWeakIndex);
+    }
   }
   default: { // unknown case
   }
@@ -729,19 +1133,39 @@ TopoDS_Shape Selector_Selector::value()
   return TopoDS_Shape(); // empty, error shape
 }
 
-static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
-
 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
   switch(myType) {
   case SELTYPE_CONTAINER:
   case SELTYPE_INTERSECT: {
     std::string aResult;
-    // add names of sub-components one by one in "[]"
+    // add names of sub-components one by one in "[]" +optionally [weak_name_1]
     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
     for(; aSubSel != mySubSelList.end(); aSubSel++) {
       aResult += '[';
       aResult += aSubSel->name(theNameGenerator);
       aResult += ']';
+      TopoDS_Shape aSubVal = aSubSel->value();
+      if (!aSubVal.IsNull()) {
+        TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
+        if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
+          switch(aSubType) {
+          case TopAbs_COMPOUND: aResult += "c"; break;
+          case TopAbs_COMPSOLID: aResult += "o"; break;
+          case TopAbs_SOLID: aResult += "s"; break;
+          case TopAbs_SHELL: aResult += "h"; break;
+          case TopAbs_WIRE: aResult += "w"; break;
+          case TopAbs_EDGE: aResult += "e"; break;
+          case TopAbs_VERTEX: aResult += "v"; break;
+          default:
+            ;
+          }
+        }
+      }
+    }
+    if (myWeakIndex != -1) {
+      std::ostringstream aWeakStr;
+      aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
+      aResult += aWeakStr.str();
     }
     return aResult;
   }
@@ -759,19 +1183,18 @@ std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
       return "";
     aResult += theNameGenerator->contextName(myFinal) + "/" +
-      std::string(TCollection_AsciiString(aName->Get()).ToCString()) + "&";
+      std::string(TCollection_AsciiString(aName->Get()).ToCString());
     for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
-      if (aBase != myBases.begin())
-        aResult += "&";
       if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
         return "";
+      aResult += "&";
       aResult += theNameGenerator->contextName(*aBase) + "/" +
         std::string(TCollection_AsciiString(aName->Get()).ToCString());
-      if (myWeakIndex != -1) {
-        std::ostringstream aWeakStr;
-        aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
-        aResult += aWeakStr.str();
-      }
+    }
+    if (myWeakIndex != -1) {
+      std::ostringstream aWeakStr;
+      aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
+      aResult += aWeakStr.str();
     }
     return aResult;
   }
@@ -782,11 +1205,23 @@ std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
       aResult += "(" + aSubSel->name(theNameGenerator) + ")";
-      if (*aLevel > 1)
-        aResult += *aLevel;
+      if (*aLevel > 1) {
+        std::ostringstream aLevelStr;
+        aLevelStr<<*aLevel;
+        aResult += aLevelStr.str();
+      }
     }
     return aResult;
   }
+  case SELTYPE_WEAK_NAMING: {
+    // _weak_naming_1_Context
+    std::ostringstream aWeakStr;
+    aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
+    std::string aResult = aWeakStr.str();
+    if (!myFinal.IsNull())
+      aResult += "_" + theNameGenerator->contextName(myFinal);
+    return aResult;
+  }
   default: { // unknown case
   }
   };
@@ -795,8 +1230,9 @@ std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
 
 TDF_Label Selector_Selector::restoreByName(
   std::string theName, const TopAbs_ShapeEnum theShapeType,
-  Selector_NameGenerator* theNameGenerator)
+  Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming)
 {
+  myGeometricalNaming = theGeometricalNaming;
   if (theName[0] == '[') { // intersection or container
     switch(theShapeType) {
     case TopAbs_COMPOUND:
@@ -820,9 +1256,31 @@ TDF_Label Selector_Selector::restoreByName(
       size_t anEndPos = theName.find(']', aStart + 1);
       if (anEndPos != std::string::npos) {
         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
+        if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
+          std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
+          myWeakIndex = atoi(aWeakIndex.c_str());
+          continue;
+        }
+        TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
+        if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
+          char aShapeChar = theName[anEndPos + 1];
+          if (theName[anEndPos + 1] != '[') {
+            switch(aShapeChar) {
+            case 'c': aSubShapeType = TopAbs_COMPOUND; break;
+            case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
+            case 's': aSubShapeType = TopAbs_SOLID; break;
+            case 'h': aSubShapeType = TopAbs_SHELL; break;
+            case 'w': aSubShapeType = TopAbs_WIRE; break;
+            case 'e': aSubShapeType = TopAbs_EDGE; break;
+            case 'v': aSubShapeType = TopAbs_VERTEX; break;
+            default:;
+            }
+          }
+        }
         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
-        TDF_Label aSubContext =
-          mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
+        mySubSelList.back().setBaseDocument(myBaseDocumentLab);
+        TDF_Label aSubContext = mySubSelList.back().restoreByName(
+          aSubStr, aSubShapeType, theNameGenerator, theGeometricalNaming);
         if (aSubContext.IsNull())
           return aSubContext; // invalid sub-selection parsing
         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
@@ -835,7 +1293,7 @@ TDF_Label Selector_Selector::restoreByName(
         return TDF_Label(); // invalid parentheses
     }
     return aContext;
-  } else if (theName[0] == '(') { // filter by neighbours
+  } else if (theName[0] == '(') { // filter by neighbors
     myType = SELTYPE_FILTER_BY_NEIGHBOR;
     TDF_Label aContext;
     for(size_t aStart = 0; aStart != std::string::npos;
@@ -844,8 +1302,9 @@ TDF_Label Selector_Selector::restoreByName(
       if (anEndPos != std::string::npos) {
         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
-        TDF_Label aSubContext =
-          mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
+        mySubSelList.back().setBaseDocument(myBaseDocumentLab);
+        TDF_Label aSubContext = mySubSelList.back().restoreByName(
+          aSubStr, theShapeType, theNameGenerator, theGeometricalNaming);
         if (aSubContext.IsNull())
           return aSubContext; // invalid sub-selection parsing
         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
@@ -854,6 +1313,9 @@ TDF_Label Selector_Selector::restoreByName(
         } else {
           aContext = aSubContext;
         }
+        if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
+          aContext = theNameGenerator->newestContext(aContext);
+
         // searching for the level index
         std::string aLevel;
         for(anEndPos++; anEndPos != std::string::npos &&
@@ -874,7 +1336,19 @@ TDF_Label Selector_Selector::restoreByName(
         return TDF_Label(); // invalid parentheses
     }
     return aContext;
-  } else if (theName.find('&') == std::string::npos) { // wihtout '&' it can be only primitive
+  } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
+    myType = SELTYPE_WEAK_NAMING;
+    std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
+    std::size_t aContextPosition = aWeakIndex.find("_");
+    myWeakIndex = atoi(aWeakIndex.c_str());
+    myShapeType = theShapeType;
+    TDF_Label aContext;
+    if (aContextPosition != std::string::npos) { // context is also defined
+      std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
+      theNameGenerator->restoreContext(aContextName, aContext, myFinal);
+    }
+    return aContext;
+  } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive
     myType = SELTYPE_PRIMITIVE;
     TDF_Label aContext;
     if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
@@ -911,13 +1385,54 @@ TDF_Label Selector_Selector::restoreByName(
   return TDF_Label();
 }
 
-bool Selector_Selector::selectBySubSelector(
-  const TopoDS_Shape theContext, const TopoDS_Shape theValue, const bool theUseNeighbors)
+bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext,
+  const TopoDS_Shape theValue, const bool theGeometricalNaming,
+  const bool theUseNeighbors, const bool theUseIntersections)
 {
   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
-  if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors)) {
+  if (!myBaseDocumentLab.IsNull())
+    mySubSelList.back().setBaseDocument(myBaseDocumentLab);
+  if (!mySubSelList.back().select(theContext, theValue,
+      theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
     mySubSelList.clear(); // if one of the selector is failed, all become invalid
     return false;
   }
   return true;
 }
+
+void Selector_Selector::combineGeometrical(const TopoDS_Shape theContext)
+{
+  TopoDS_Shape aValue = value();
+  if (aValue.IsNull() || aValue.ShapeType() == TopAbs_COMPOUND)
+    return;
+  myAlwaysGeometricalNaming = true;
+  mySubSelList.clear();
+  myBases.Clear();
+  myWeakIndex = -1;
+  if (select(theContext, aValue, true)) {
+    store();
+    solve(theContext);
+    return;
+  }
+  // if can not select, select the compound in a custom way
+  TopTools_MapOfShape aMap;
+  TopoDS_ListOfShape aList;
+  for(TopExp_Explorer anExp(theContext, aValue.ShapeType()); anExp.More(); anExp.Next()) {
+    if (aMap.Add(anExp.Current())) {
+      if (sameGeometry(aValue, anExp.Current()))
+        aList.Append(anExp.Current());
+    }
+  }
+  if (aList.Size() > 1) {
+    TopoDS_Builder aBuilder;
+    TopoDS_Compound aCompound;
+    aBuilder.MakeCompound(aCompound);
+    for(TopoDS_ListIteratorOfListOfShape aListIter(aList); aListIter.More(); aListIter.Next()) {
+      aBuilder.Add(aCompound, aListIter.Value());
+    }
+    if (select(theContext, aCompound, true)) {
+      store();
+      solve(theContext);
+    }
+  }
+}