Salome HOME
Fixes for the issue #2375 model with dump/import script
[modules/shaper.git] / src / Selector / Selector_Selector.cpp
index 45880cab08e24decdc3397901b311dcc94450ea5..d4b1f2319dda33d32486ca82442853d911c44858 100644 (file)
 
 #include <Selector_Selector.h>
 
+#include <Selector_NameGenerator.h>
+#include <Selector_NExplode.h>
+
+#include <TDF_ChildIDIterator.hxx>
 #include <TopoDS_Iterator.hxx>
+#include <TopoDS_Builder.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TNaming_Tool.hxx>
 #include <TNaming_NewShapeIterator.hxx>
+#include <TNaming_OldShapeIterator.hxx>
+#include <TNaming_SameShapeIterator.hxx>
 #include <TNaming_Iterator.hxx>
+#include <TNaming_Builder.hxx>
 #include <TopTools_MapOfShape.hxx>
 
 #include <TDataStd_Integer.hxx>
 #include <TDataStd_ReferenceArray.hxx>
+#include <TDataStd_IntegerArray.hxx>
+#include <TDataStd_Name.hxx>
 
 #include <list>
 
 /// type of the selection, integerm 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_LIST("7c515b1a-9549-493d-9946-a4933a22f45f");
+static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
+// 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");
 
 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
 {
+  myWeakIndex = -1;
 }
 
 TDF_Label Selector_Selector::label()
@@ -49,87 +66,374 @@ TDF_Label Selector_Selector::label()
 
 // 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,
-  TDF_LabelList& theResult)
+  bool aMustBeAtFinal, TDF_LabelList& theResult)
+{
+  TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
+  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 (!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);
+        }
+      }
+    }
+  }
+}
+
+// returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
+static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
+  TopoDS_ListOfShape& theResults)
+{
+  TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
+  for(; aSubSel != theShapes.end(); aSubSel++) {
+    TopTools_MapOfShape aCurrentMap;
+    for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
+      if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
+        theResults.Append(anExp.Current());
+    }
+    if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
+      for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
+        if (aCurrentMap.Contains(aComIter.Value()))
+          aComIter.Next();
+        else
+          theResults.Remove(aComIter);
+      }
+    }
+  }
+}
+
+/// Searches neighbor of theLevel of neighborhood to theValue in theContex
+static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
+  const int theLevel, TopTools_MapOfShape& theResult)
+{
+  TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
+  if (theValue.ShapeType() == TopAbs_FACE)
+    aConnectorType = TopAbs_EDGE;
+  TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
+  for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
+    aNBConnectors.Add(aValExp.Current());
+  }
+
+  TopTools_MapOfShape alreadyProcessed;
+  alreadyProcessed.Add(theValue);
+
+  for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
+    TopoDS_ListOfShape aGoodCandidates;
+    TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
+    for(; aCandidate.More(); aCandidate.Next()) {
+      if (alreadyProcessed.Contains(aCandidate.Current()))
+        continue;
+      TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
+      for(; aCandConnector.More(); aCandConnector.Next()) {
+        if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
+          break;
+      }
+      if (aCandConnector.More()) {
+        if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
+          theResult.Add(aCandidate.Current());
+        } else { // add to the NB of the current level
+          aGoodCandidates.Append(aCandidate.Current());
+        }
+      }
+    }
+    if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
+      for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
+        TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
+        for(; aGoodConnector.More(); aGoodConnector.Next()) {
+          aNBConnectors.Add(aGoodConnector.Current());
+        }
+        alreadyProcessed.Add(aGood.Value());
+      }
+    }
+  }
+}
+
+/// 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)
 {
-  for(TNaming_Iterator aThisIter(theFinal); aThisIter.More(); aThisIter.Next()) {
-    if (aThisIter.NewShape().IsSame(theValue)) {
-      const TopoDS_Shape& anOldShape = aThisIter.OldShape();
-      // searching for all old shapes in this sequence of modification
-      TNaming_NewShapeIterator aNSIter(anOldShape, theFinal->Label());
-      for(; aNSIter.More(); aNSIter.Next()) {
-        TNaming_Evolution anEvolution = aNSIter.NamedShape()->Evolution();
-        if (anEvolution == TNaming_PRIMITIVE) { // found a good candidate, a base shape
-          // check that this is not in the results already
-          const TDF_Label aResult = aNSIter.NamedShape()->Label();
-          TDF_LabelList::Iterator aResIter(theResult);
-          for(; aResIter.More(); aResIter.Next()) {
-            if (aResIter.Value().IsEqual(aResult))
-              break;
+  // searching for neighbors with minimum level
+  int aMinLevel = 0;
+  std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
+  for(; aNBIter != theNB.cend(); aNBIter++) {
+    if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
+      aMinLevel = aNBIter->second;
+    }
+  }
+  // collect all neighbors which are neighbors of sub-shapes with minimum level
+  bool aFirst = true;
+  TopoDS_ListOfShape aMatches;
+  for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
+    if (aNBIter->second == aMinLevel) {
+      TopTools_MapOfShape aThisNBs;
+      findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
+      // aMatches must contain common part of all NBs lists
+      for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
+        if (aFirst) {
+          aMatches.Append(aThisNB.Value());
+        } else {
+          // remove all in aMatches which are not in this NBs
+          for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
+            if (aThisNBs.Contains(aMatch.Value())) {
+              aMatch.Next();
+            } else {
+              aMatches.Remove(aMatch);
+            }
+          }
+        }
+      }
+      aFirst = false;
+    }
+  }
+  if (aMatches.IsEmpty())
+    return TopoDS_Shape(); // not found any candidate
+  if (aMatches.Extent() == 1)
+    return aMatches.First(); // already found good candidate
+  // 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()) {
+    bool aValidCadidate = true;
+    for(int aLevel = aMinLevel + 1; true; aLevel++) {
+      bool aFooundHigherLevel = false;
+      TopoDS_ListOfShape aLevelNBs;
+      for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
+        if (aNBIter->second == aLevel)
+          aLevelNBs.Append(aNBIter->first);
+        else if (aNBIter->second >= aLevel)
+          aFooundHigherLevel = true;
+      }
+      if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
+        if (aGoodCandidate.IsNull()) {
+          aGoodCandidate = aCandidate.Value();
+        } else { // too many good candidates
+          return TopoDS_Shape();
+        }
+      }
+      if (!aLevelNBs.IsEmpty()) {
+        TopTools_MapOfShape aNBsOfCandidate;
+        findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
+        // check all stored neighbors are in the map of real neighbors
+        for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
+          if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
+            aValidCadidate = false;
+            break;
           }
-          if (!aResIter.More()) // not found, so add this new
-            theResult.Append(aResult);
-        } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
-          // continue recursively
-          findBases(aNSIter.NamedShape(), anOldShape, theResult);
         }
       }
+      if (!aValidCadidate) // candidate is not valid, break the checking
+        break;
     }
   }
+  return aGoodCandidate;
 }
 
-bool Selector_Selector::Select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
+  const bool theUseNeighbors)
 {
   if (theValue.IsNull() || theContext.IsNull())
     return false;
   // 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;
+        }
+      }
+    }
+  }
+  if (!aIsFound) {
     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
+    myShapeType = aSelectionType;
     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
-        aSelectionType == TopAbs_SOLID) { // iterate all sub-shapes and select them on sublabels
-      std::list<Selector_Selector> aSubSelList;
+        aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
+    { // iterate all sub-shapes and select them on sublabels
       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
-        aSubSelList.push_back(Selector_Selector(myLab.FindChild(aSubSelList.size() + 1)));
-        if (!aSubSelList.back().Select(theContext, aSubIter.Value())) {
+        if (!selectBySubSelector(theContext, aSubIter.Value())) {
           return false; // if some selector is failed, everything is failed
         }
       }
       myType = SELTYPE_CONTAINER;
-      myShapeType = aSelectionType;
       return true;
     }
 
     // try to find the shape of the higher level type in the context shape
-    while(aSelectionType != TopAbs_FACE) {
-      if (aSelectionType == TopAbs_VERTEX) aSelectionType = TopAbs_EDGE;
-      else if (aSelectionType == TopAbs_EDGE) aSelectionType = TopAbs_FACE;
+    bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
+    TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
+    TopTools_MapOfShape aLastIntersectors;
+    while(aSelectionType != TopAbs_FACE || !aFacesTried) {
+      if (aSelectionType == TopAbs_FACE) {
+        if (theValue.ShapeType() != TopAbs_VERTEX)
+          break;
+        aFacesTried = true;
+        aSelectionType = TopAbs_EDGE;
+      } else
+        aSelectionType = TopAbs_FACE;
       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()) {
         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
         for(; aSubExp.More(); aSubExp.Next()) {
           if (aSubExp.Current().IsSame(theValue)) {
-            anIntersectors.Add(aSelExp.Current());
+            if (anIntersectors.Add(aSelExp.Current()))
+              anIntList.Append(aSelExp.Current());
             break;
           }
         }
       }
-      //TODO: check if intersectors produce several subs, try to remove one of the intersector
+      // check that solution is only one
+      TopoDS_ListOfShape aCommon;
+      commonShapes(anIntList, theValue.ShapeType(), aCommon);
+      if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
+        // name the intersectors
+        mySubSelList.clear();
+        TopTools_MapOfShape::Iterator anInt(anIntersectors);
+        for (; anInt.More(); anInt.Next()) {
+          if (!selectBySubSelector(theContext, anInt.Value())) {
+            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 = anIntersectors;
+      }
+    }
 
-      // name the intersectors
+    if (!theUseNeighbors)
+      return false;
 
+    // searching by neighbours
+    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));
+        }
+        aNewNB.Remove(aNBIter.Key());
+        aNBIter.Initialize(aNewNB);
+      }
+      TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
+      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)) {
+            return false; // something is wrong because before this selection was ok
+          }
+          myNBLevel.push_back(aNBIter->second);
+
+        }
+        myType = SELTYPE_FILTER_BY_NEIGHBOR;
+        return true;
+      }
     }
+
+    // weak naming to distinguish commons coming from intersection
+    if (aLastCommon.Extent() > 1) {
+      Selector_NExplode aNexp(aLastCommon);
+      myWeakIndex = aNexp.index(theValue);
+      if (myWeakIndex != -1) {
+        // name the intersectors
+        mySubSelList.clear();
+        TopTools_MapOfShape::Iterator anInt(aLastIntersectors);
+        for (; anInt.More(); anInt.Next()) {
+          if (!selectBySubSelector(theContext, anInt.Value())) {
+            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
+    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_NewShapeIterator aNewShapes(theValue, myLab); aNewShapes.More(); aNewShapes.Next())
+  for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
   {
-    TNaming_Evolution anEvolution = aNewShapes.NamedShape()->Evolution();
-    if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as primitive => PRIMITIVE
-      aPrimitiveNS = aNewShapes.NamedShape();
-      break;
-    } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
-      aModifList.Append(aNewShapes.NamedShape());
+    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);
+      }
     }
   }
 
@@ -162,40 +466,141 @@ 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, myBases);
-    myFinal = aModifList.First()->Label();
+    findBases(aModifList.First(), theValue, true, myBases);
+    if (!myBases.IsEmpty()) {
+      myFinal = aModifList.First()->Label();
+      TopoDS_ListOfShape aCommon;
+      findModificationResult(aCommon);
+      // trying to search by neighbours
+      if (aCommon.Extent() > 1) { // more complicated selection
+        if (!theUseNeighbors)
+          return false;
+
+        // searching by neighbours
+        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 list of good NBs
+              aNBs.push_back(std::pair<TopoDS_Shape, int>(aNBIter.Value(), aLevel));
+            }
+            aNewNB.Remove(aNBIter.Key());
+            aNBIter.Initialize(aNewNB);
+          }
+          TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
+          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)) {
+                return false; // something is wrong because before this selection was ok
+              }
+              myNBLevel.push_back(aNBIter->second);
+
+            }
+            myType = SELTYPE_FILTER_BY_NEIGHBOR;
+            return true;
+          }
+        }
+        // filter by neighbours did not help
+        if (aCommon.Extent() > 1) { // weak naming between the common results
+          Selector_NExplode aNexp(aCommon);
+          myWeakIndex = aNexp.index(theValue);
+          if (myWeakIndex == -1)
+            return false;
+        }
+      }
+    }
     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;
+      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;
 }
 
-void Selector_Selector::Store()
+void Selector_Selector::store()
 {
+  myLab.ForgetAllAttributes(true); // remove old naming data
   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
   switch(myType) {
-  case SELTYPE_CONTAINER: {
-    /// TODO
-    break;
-  }
+  case SELTYPE_CONTAINER:
   case SELTYPE_INTERSECT: {
-    /// TODO
+    TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
+    // store also all sub-selectors
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    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, 0, 0);
-    anArray->SetValue(0, myBases.First());
+    Handle(TDataStd_ReferenceArray) anArray =
+      TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
+    anArray->SetValue(0, myFinal);
     break;
   }
   case SELTYPE_MODIFICATION: {
     Handle(TDataStd_ReferenceArray) anArray =
-      TDataStd_ReferenceArray::Set(myLab, 0, myBases.Extent() - 1);
+      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
+    if (myWeakIndex != -1) {
+      TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
+    }
+    break;
+  }
+  case SELTYPE_FILTER_BY_NEIGHBOR: {
+    TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
+    // store numbers of levels corresponded to the neighbors in sub-selectors
+    Handle(TDataStd_IntegerArray) anArray =
+      TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
+    std::list<int>::iterator aLevel = myNBLevel.begin();
+    for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
+      anArray->SetValue(anIndex, *aLevel);
+    }
+    // store all sub-selectors
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    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);
+    // store myFinal in the base array
+    if (!myFinal.IsNull()) {
+      Handle(TDataStd_ReferenceArray) anArray =
+        TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
+      anArray->SetValue(0, myFinal);
+    }
     break;
   }
   default: { // unknown case
@@ -203,3 +608,506 @@ void Selector_Selector::Store()
   }
   }
 }
+
+bool Selector_Selector::restore()
+{
+  Handle(TDataStd_Integer) aTypeAttr;
+  if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
+    return false;
+  myType = Selector_Type(aTypeAttr->Get());
+  switch(myType) {
+  case SELTYPE_CONTAINER:
+  case SELTYPE_INTERSECT: {
+    Handle(TDataStd_Integer) aShapeTypeAttr;
+    if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
+      return false;
+    myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+    // restore sub-selectors
+    bool aSubResult = true;
+    mySubSelList.clear();
+    for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
+      mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
+      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;
+  }
+  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);
+      Handle(TDataStd_Integer) aWeakInt;
+      if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
+        myWeakIndex = aWeakInt->Get();
+      }
+      return true;
+    }
+    return false;
+  }
+  case SELTYPE_FILTER_BY_NEIGHBOR: {
+    Handle(TDataStd_Integer) aShapeTypeAttr;
+    if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
+      return false;
+    myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+    // restore sub-selectors
+    bool aSubResult = true;
+    mySubSelList.clear();
+    for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
+      mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
+      if (!mySubSelList.back().restore())
+        aSubResult = false;
+    }
+    // restore levels indices
+    Handle(TDataStd_IntegerArray) anArray;
+    if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
+      return false;
+    for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
+      myNBLevel.push_back(anArray->Value(anIndex));
+    }
+    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());
+    Handle(TDataStd_ReferenceArray) anArray;
+    if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
+      myFinal = anArray->Value(0);
+    }
+    return true;
+  }
+  default: { // unknown case
+  }
+  }
+  return false;
+}
+
+/// 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)
+{
+  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);
+      }
+    }
+  }
+}
+
+void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
+  for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
+    TopTools_MapOfShape aFinals;
+    for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
+      findFinals(aBaseShape.NewShape(), myFinal, aFinals);
+    if (!aFinals.IsEmpty()) {
+      if (theCommon.IsEmpty()) { // just copy all to common
+        for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
+          theCommon.Append(aFinal.Key());
+        }
+      } else { // keep only shapes presented in both lists
+        for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
+          if (aFinals.Contains(aCommon.Value())) {
+            aCommon.Next();
+          } else { // common is not found, remove it
+            theCommon.Remove(aCommon);
+          }
+        }
+      }
+    }
+  }
+}
+
+bool Selector_Selector::solve(const TopoDS_Shape& theContext)
+{
+  TopoDS_Shape aResult; // null if invalid
+  switch(myType) {
+  case SELTYPE_CONTAINER: {
+    TopoDS_Builder aBuilder;
+    switch(myShapeType) {
+    case TopAbs_COMPOUND: {
+      TopoDS_Compound aComp;
+      aBuilder.MakeCompound(aComp);
+      aResult = aComp;
+      break;
+      }
+    case TopAbs_COMPSOLID: {
+      TopoDS_CompSolid aComp;
+      aBuilder.MakeCompSolid(aComp);
+      aResult = aComp;
+      break;
+    }
+    case TopAbs_SHELL: {
+      TopoDS_Shell aShell;
+      aBuilder.MakeShell(aShell);
+      aResult = aShell;
+      break;
+    }
+    case TopAbs_WIRE: {
+      TopoDS_Wire aWire;
+      aBuilder.MakeWire(aWire);
+      aResult = aWire;
+      break;
+    }
+    }
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    for(; aSubSel != mySubSelList.end(); aSubSel++) {
+      if (!aSubSel->solve(theContext)) {
+        return false;
+      }
+      aBuilder.Add(aResult, aSubSel->value());
+    }
+    break;
+  }
+  case SELTYPE_INTERSECT: {
+    TopoDS_ListOfShape aSubSelectorShapes;
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    for(; aSubSel != mySubSelList.end(); aSubSel++) {
+      if (!aSubSel->solve(theContext)) {
+        return false;
+      }
+      aSubSelectorShapes.Append(aSubSel->value());
+    }
+    TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
+    commonShapes(aSubSelectorShapes, myShapeType, aCommon);
+    if (aCommon.Extent() != 1) {
+      if (myWeakIndex != -1) {
+        Selector_NExplode aNexp(aCommon);
+        aResult = aNexp.shape(myWeakIndex);
+      } else {
+        return false;
+      }
+    } else {
+      aResult = aCommon.First();
+    }
+    break;
+  }
+  case SELTYPE_PRIMITIVE: {
+    Handle(TNaming_NamedShape) aNS;
+    if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+      aResult = aNS->Get();
+    }
+    break;
+  }
+  case SELTYPE_MODIFICATION: {
+    if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index
+      TopoDS_ListOfShape aCommon;
+      Handle(TNaming_NamedShape) aNS;
+      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) // 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);
+      }
+    }
+    break;
+  }
+  case SELTYPE_FILTER_BY_NEIGHBOR: {
+    std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
+    std::list<int>::iterator aLevel = myNBLevel.begin();
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
+      if (!aSubSel->solve(theContext)) {
+        return false;
+      }
+      aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
+    }
+    aResult = findNeighbor(theContext, aNBs);
+    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
+  }
+  }
+
+  TNaming_Builder aBuilder(myLab);
+  if (!aResult.IsNull()) {
+    aBuilder.Select(aResult, aResult);
+    return true;
+  }
+  return false; // builder just erases the named shape in case of error
+}
+
+TopoDS_Shape Selector_Selector::value()
+{
+  Handle(TNaming_NamedShape) aNS;
+  if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
+    return aNS->Get();
+  return TopoDS_Shape(); // empty, error shape
+}
+
+static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
+static const std::string kPUREWEAK_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 "[]" +optionally [weak_name_1]
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    for(; aSubSel != mySubSelList.end(); aSubSel++) {
+      aResult += '[';
+      aResult += aSubSel->name(theNameGenerator);
+      aResult += ']';
+    }
+    if (myWeakIndex != -1) {
+      std::ostringstream aWeakStr;
+      aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
+      aResult += aWeakStr.str();
+    }
+    return aResult;
+  }
+  case SELTYPE_PRIMITIVE: {
+    Handle(TDataStd_Name) aName;
+    if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
+      return "";
+    return theNameGenerator->contextName(myFinal) + "/" +
+      std::string(TCollection_AsciiString(aName->Get()).ToCString());
+  }
+  case SELTYPE_MODIFICATION: {
+    // final&base1&base2 +optionally: [weak_name_1]
+    std::string aResult;
+    Handle(TDataStd_Name) aName;
+    if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
+      return "";
+    aResult += theNameGenerator->contextName(myFinal) + "/" +
+      std::string(TCollection_AsciiString(aName->Get()).ToCString());
+    for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
+      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();
+    }
+    return aResult;
+  }
+  case SELTYPE_FILTER_BY_NEIGHBOR: {
+    // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
+    std::string aResult;
+    std::list<int>::iterator aLevel = myNBLevel.begin();
+    std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
+    for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
+      aResult += "(" + aSubSel->name(theNameGenerator) + ")";
+      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
+  }
+  };
+  return "";
+}
+
+TDF_Label Selector_Selector::restoreByName(
+  std::string theName, const TopAbs_ShapeEnum theShapeType,
+  Selector_NameGenerator* theNameGenerator)
+{
+  if (theName[0] == '[') { // intersection or container
+    switch(theShapeType) {
+    case TopAbs_COMPOUND:
+    case TopAbs_COMPSOLID:
+    case TopAbs_SHELL:
+    case TopAbs_WIRE:
+      myType = SELTYPE_CONTAINER;
+      break;
+    case TopAbs_VERTEX:
+    case TopAbs_EDGE:
+    case TopAbs_FACE:
+      myType = SELTYPE_INTERSECT;
+      break;
+    default:
+      return TDF_Label(); // unknown case
+    }
+    myShapeType = theShapeType;
+    TDF_Label aContext;
+    for(size_t aStart = 0; aStart != std::string::npos;
+        aStart = theName.find('[', aStart + 1)) {
+      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;
+        }
+        mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
+        TDF_Label aSubContext =
+          mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
+        if (aSubContext.IsNull())
+          return aSubContext; // invalid sub-selection parsing
+        if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
+          if (!theNameGenerator->isLater(aContext, aSubContext))
+            aContext = aSubContext;
+        } else {
+          aContext = aSubContext;
+        }
+      } else
+        return TDF_Label(); // invalid parentheses
+    }
+    return aContext;
+  } else if (theName[0] == '(') { // filter by neighbours
+    myType = SELTYPE_FILTER_BY_NEIGHBOR;
+    TDF_Label aContext;
+    for(size_t aStart = 0; aStart != std::string::npos;
+      aStart = theName.find('(', aStart + 1)) {
+      size_t anEndPos = theName.find(')', aStart + 1);
+      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);
+        if (aSubContext.IsNull())
+          return aSubContext; // invalid sub-selection parsing
+        if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
+          if (!theNameGenerator->isLater(aContext, aSubContext))
+            aContext = aSubContext;
+        } else {
+          aContext = aSubContext;
+        }
+        // searching for the level index
+        std::string aLevel;
+        for(anEndPos++; anEndPos != std::string::npos &&
+                        theName[anEndPos] != '(' && theName[anEndPos] != 0;
+            anEndPos++) {
+          aLevel += theName[anEndPos];
+        }
+        if (aLevel.empty())
+          myNBLevel.push_back(1); // by default it is 1
+        else {
+          int aNum = atoi(aLevel.c_str());
+          if (aNum > 0)
+            myNBLevel.push_back(aNum);
+          else
+            return TDF_Label(); // invalid number
+        }
+      } else
+        return TDF_Label(); // invalid parentheses
+    }
+    return aContext;
+  } 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) { // wihtout '&' it can be only primitive
+    myType = SELTYPE_PRIMITIVE;
+    TDF_Label aContext;
+    if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
+      if (!myFinal.IsNull())
+        return aContext;
+    }
+  } else { // modification
+    myType = SELTYPE_MODIFICATION;
+    TDF_Label aContext;
+    for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
+      if (aStart != 0)
+        aStart++;
+      anEnd = theName.find('&', aStart);
+      std::string aSubStr =
+        theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
+      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;
+      }
+      TDF_Label aSubContext, aValue;
+      if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
+        return TDF_Label(); // can not restore
+      if(aSubContext.IsNull() || aValue.IsNull())
+        return TDF_Label(); // can not restore
+      if (myFinal.IsNull()) {
+        myFinal = aValue;
+        aContext = aSubContext;
+      } else
+        myBases.Append(aValue);
+    }
+    return aContext;
+  }
+  return TDF_Label();
+}
+
+bool Selector_Selector::selectBySubSelector(
+  const TopoDS_Shape theContext, const TopoDS_Shape theValue, const bool theUseNeighbors)
+{
+  mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
+  if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors)) {
+    mySubSelList.clear(); // if one of the selector is failed, all become invalid
+    return false;
+  }
+  return true;
+}