Salome HOME
Refactoring of the Selector package: split selection algorithms to separated classes.
authormpv <mpv@opencascade.com>
Mon, 19 Nov 2018 06:16:54 +0000 (09:16 +0300)
committermpv <mpv@opencascade.com>
Mon, 19 Nov 2018 08:45:52 +0000 (11:45 +0300)
23 files changed:
src/Model/Model_AttributeSelection.cpp
src/Model/Model_AttributeSelection.h
src/Selector/CMakeLists.txt
src/Selector/Selector_Algo.cpp [new file with mode: 0644]
src/Selector/Selector_Algo.h [new file with mode: 0644]
src/Selector/Selector_AlgoWithSubs.cpp [new file with mode: 0644]
src/Selector/Selector_AlgoWithSubs.h [new file with mode: 0644]
src/Selector/Selector_Container.cpp [new file with mode: 0644]
src/Selector/Selector_Container.h [new file with mode: 0644]
src/Selector/Selector_FilterByNeighbors.cpp [new file with mode: 0644]
src/Selector/Selector_FilterByNeighbors.h [new file with mode: 0644]
src/Selector/Selector_Intersect.cpp [new file with mode: 0644]
src/Selector/Selector_Intersect.h [new file with mode: 0644]
src/Selector/Selector_Modify.cpp [new file with mode: 0644]
src/Selector/Selector_Modify.h [new file with mode: 0644]
src/Selector/Selector_NExplode.h
src/Selector/Selector_Primitive.cpp [new file with mode: 0644]
src/Selector/Selector_Primitive.h [new file with mode: 0644]
src/Selector/Selector_Selector.cpp
src/Selector/Selector_Selector.h
src/Selector/Selector_WeakName.cpp [new file with mode: 0644]
src/Selector/Selector_WeakName.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Point.cpp

index 7ca2ca08983c15ca488215d8e1b1e67db6c04067..3d97c91c9066df87325328677f41cbbe59989750 100644 (file)
@@ -592,16 +592,10 @@ bool Model_AttributeSelection::update()
     if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
       anOldShape = aNS->Get();
 
-    Selector_Selector aSelector(aSelLab);
-    if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
-      aSelector.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
-        (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
-    }
-    if (aSelector.restore()) { // it is stored in old OCCT format, use TNaming_Selector
-      TopoDS_Shape aContextShape = aContext->shape()->impl<TopoDS_Shape>();
-      aResult = aSelector.solve(aContextShape);
-    }
-    aResult = setInvalidIfFalse(aSelLab, aResult);
+    TopoDS_Shape aContextShape = aContext->shape()->impl<TopoDS_Shape>();
+    Selector_Selector aSelector(aSelLab, baseDocumentLab());
+    aResult = aSelector.restore(aContextShape);
+    setInvalidIfFalse(aSelLab, aResult);
 
     TopoDS_Shape aNewShape;
     if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
@@ -625,19 +619,11 @@ bool Model_AttributeSelection::update()
     std::shared_ptr<Model_ResultConstruction> aConstructionContext =
       std::dynamic_pointer_cast<Model_ResultConstruction>(aContext);
     if (!aConstructionContext->isInfinite()) {
-      Selector_Selector aSelector(aSelLab);
-      if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
-        aSelector.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
-          (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
-      }
-
-      aResult = aSelector.restore();
+      TopoDS_Shape aContextShape = aContext->shape()->impl<TopoDS_Shape>();
+      Selector_Selector aSelector(aSelLab, baseDocumentLab());
       TopoDS_Shape anOldShape = aSelector.value();
-      if (aResult) {
-        TopoDS_Shape aContextShape = aContext->shape()->impl<TopoDS_Shape>();
-        aResult = aSelector.solve(aContextShape);
-      }
-      aResult = setInvalidIfFalse(aSelLab, aResult);
+      aResult = aSelector.restore(aContextShape);
+      setInvalidIfFalse(aSelLab, aResult);
       if (aResult && !anOldShape.IsEqual(aSelector.value()))
         owner()->data()->sendAttributeUpdated(this);  // send updated if shape is changed
     } else {
@@ -673,30 +659,20 @@ void Model_AttributeSelection::selectBody(
     TopoDS_Shape aNewSub = theSubShape->impl<TopoDS_Shape>();
 
     bool aSelectorOk = true;
-    Selector_Selector aSel(aSelLab);
-    if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
-      aSel.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
-        (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
-    }
+    Selector_Selector aSelector(aSelLab, baseDocumentLab());
     try {
-      aSelectorOk = aSel.select(aContext, aNewSub, myIsGeometricalSelection);
+      aSelectorOk = aSelector.select(aContext, aNewSub, myIsGeometricalSelection);
       if (aSelectorOk) {
-        aSel.store();
-        aSelectorOk = aSel.solve(aContext);
+        aSelectorOk = aSelector.store(aContext);
       }
     } catch(...) {
       aSelectorOk = false;
     }
-    Handle(TNaming_NamedShape) aSelectorShape;
-    if (aSelectorOk && aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelectorShape))
-    {
-      TopoDS_Shape aShape = aSelectorShape->Get();
-      if (aShape.IsNull() || aShape.ShapeType() != aNewSub.ShapeType())
-        aSelectorOk = false;
-    }
-    if (!aSelectorOk) {
-      setInvalidIfFalse(aSelLab, false);
+    if (aSelectorOk) {
+      TopoDS_Shape aShape = aSelector.value();
+      aSelectorOk = !aShape.IsNull() && aShape.ShapeType() == aNewSub.ShapeType();
     }
+    setInvalidIfFalse(aSelLab, aSelectorOk);
   }
 }
 
@@ -803,13 +779,9 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
     }
   }
 
-  Selector_Selector aSelector(aSelLab);
-  if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
-    aSelector.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
-      (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
-  }
+  Selector_Selector aSelector(aSelLab, baseDocumentLab());
   std::string aResult;
-  if (aSelector.restore())
+  if (aSelector.restore(aCont->shape()->impl<TopoDS_Shape>()))
     aResult = aSelector.name(this);
   if (aCenterType != NOT_CENTER) {
     aResult += centersMap()[aCenterType];
@@ -915,11 +887,7 @@ void Model_AttributeSelection::selectSubShape(
       }
     }
 
-    Selector_Selector aSelector(selectionLabel());
-    if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
-      aSelector.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
-        (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
-    }
+    Selector_Selector aSelector(selectionLabel(), baseDocumentLab());
     myRestoreDocument = aDoc;
     TDF_Label aContextLabel = aSelector.restoreByName(
       aSubShapeName, aShapeType, this, myIsGeometricalSelection);
@@ -940,8 +908,7 @@ void Model_AttributeSelection::selectSubShape(
             bool aToUnblock = false;
             aToUnblock = !owner()->data()->blockSendAttributeUpdated(true);
             myRef.setValue(aContext);
-            aSelector.store();
-            aSelector.solve(aContextShape);
+            aSelector.store(aContextShape);
             owner()->data()->sendAttributeUpdated(this);
             if (aToUnblock)
               owner()->data()->blockSendAttributeUpdated(false);
@@ -1806,13 +1773,18 @@ void Model_AttributeSelection::combineGeometrical()
   if (aFeature.get())
     return;
 
-  Selector_Selector aSelector(aSelLab);
-  if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
-    aSelector.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
-      (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
-  }
-  if (aSelector.restore()) {
-    TopoDS_Shape aContextShape = context()->shape()->impl<TopoDS_Shape>();
+  Selector_Selector aSelector(aSelLab, baseDocumentLab());
+  TopoDS_Shape aContextShape = context()->shape()->impl<TopoDS_Shape>();
+  if (aSelector.restore(aContextShape)) {
     aSelector.combineGeometrical(aContextShape);
   }
 }
+
+TDF_Label Model_AttributeSelection::baseDocumentLab()
+{
+  if (ModelAPI_Session::get()->moduleDocument() != owner()->document())
+    return std::dynamic_pointer_cast<Model_Document>
+      (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel();
+  static TDF_Label anEmpty;
+  return anEmpty;
+}
index a624e5cf08976a531e1c6f948a71fb5f372079a0..9512a3a73ebbdddb13ed03e32c51d020f735905d 100644 (file)
@@ -208,6 +208,10 @@ protected:
     return myIsGeometricalSelection;
   };
 
+  /// Returns the module document label if this selection attribute is not in this document.
+  /// Returns null label otherwise.
+  TDF_Label baseDocumentLab();
+
   friend class Model_Data;
   friend class Model_AttributeSelectionList;
 };
index 38af7997fd63307bae79ce8ab37429bb6c7c7c74..cfc38feca2d17a2fee4c6a265b3a0716d80c51c4 100644 (file)
@@ -23,12 +23,28 @@ INCLUDE(Common)
 SET(PROJECT_HEADERS
     Selector.h
     Selector_Selector.h
+    Selector_Algo.h
+    Selector_Primitive.h
+    Selector_AlgoWithSubs.h
+    Selector_Intersect.h
+    Selector_Container.h
+    Selector_Modify.h
+    Selector_FilterByNeighbors.h
+    Selector_WeakName.h
     Selector_NameGenerator.h
     Selector_NExplode.h
 )
 
 SET(PROJECT_SOURCES
     Selector_Selector.cpp
+    Selector_Algo.cpp
+    Selector_Primitive.cpp
+    Selector_AlgoWithSubs.cpp
+    Selector_Intersect.cpp
+    Selector_Container.cpp
+    Selector_Modify.cpp
+    Selector_FilterByNeighbors.cpp
+    Selector_WeakName.cpp
     Selector_NameGenerator.cpp
     Selector_NExplode.cpp
 )
diff --git a/src/Selector/Selector_Algo.cpp b/src/Selector/Selector_Algo.cpp
new file mode 100644 (file)
index 0000000..c64e012
--- /dev/null
@@ -0,0 +1,420 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_Algo.h>
+
+#include <Selector_Primitive.h>
+#include <Selector_Intersect.h>
+#include <Selector_Modify.h>
+#include <Selector_Container.h>
+#include <Selector_FilterByNeighbors.h>
+#include <Selector_WeakName.h>
+
+#include <TDF_Tool.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS.hxx>
+#include <Geom_Surface.hxx>
+#include <BRep_Tool.hxx>
+#include <TNaming_Builder.hxx>
+#include <TNaming_Tool.hxx>
+#include <TNaming_SameShapeIterator.hxx>
+#include <TNaming_Iterator.hxx>
+#include <TDataStd_ReferenceArray.hxx>
+#include <TDataStd_ExtStringList.hxx>
+#include <TDataStd_Integer.hxx>
+
+/// type of the selection, integer keeps the Selector_Type value
+static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
+// geometrical naming indicator
+static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
+
+
+//  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");
+
+Selector_Algo::Selector_Algo()
+{
+  myGeometricalNaming = false; // default values
+  myAlwaysGeometricalNaming = false;
+}
+
+#define SET_ALGO_FLAGS(algo) \
+  algo->myLab = theAccess; \
+  algo->myBaseDocumentLab = theBaseDocument; \
+  algo->myGeometricalNaming = theGeometricalNaming; \
+  algo->myUseNeighbors = theUseNeighbors; \
+  algo->myUseIntersections = theUseIntersections; \
+  algo->myAlwaysGeometricalNaming = theAlwaysGeometricalNaming;
+
+Selector_Algo* Selector_Algo::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
+  const TDF_Label theAccess, const TDF_Label theBaseDocument,
+  const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections,
+  const bool theAlwaysGeometricalNaming)
+{
+  Selector_Algo* aResult = NULL;
+  if (theValue.IsNull() || theContext.IsNull())
+    return aResult;
+
+  // 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)
+  bool aIsFound = TNaming_Tool::HasLabel(theAccess, theValue);
+  if (aIsFound) { // additional check for selection and delete evolution only: also could not use
+    aIsFound = false;
+    for(TNaming_SameShapeIterator aShapes(theValue, theAccess); 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 && !theBaseDocument.IsNull() && TNaming_Tool::HasLabel(theBaseDocument, theValue))
+  {
+    TNaming_SameShapeIterator aShapes(theValue, theBaseDocument);
+    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();
+    if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
+      aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
+    {
+      Selector_Container* aContainer = new Selector_Container;
+      SET_ALGO_FLAGS(aContainer);
+      if (aContainer->select(theContext, theValue))
+        return aContainer;
+      delete aContainer;
+      return false;
+    }
+    Selector_Intersect* anIntersect = new Selector_Intersect;
+    SET_ALGO_FLAGS(anIntersect);
+    bool aGoodIntersector = anIntersect->select(theContext, theValue);
+    // weak intersector is bad for not use neighbors and has lower priority than neighbors
+    if (aGoodIntersector && anIntersect->myWeakIndex == -1) {
+      return anIntersect;
+    }
+    if (!theUseNeighbors) {
+      delete anIntersect;
+      return false;
+    }
+    // searching by neighbors
+    Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
+    SET_ALGO_FLAGS(aNBs);
+    if (aNBs->select(theContext, theValue)) {
+      delete anIntersect;
+      return aNBs;
+    }
+    delete aNBs;
+    if (aGoodIntersector) { // if neighbors are bad, use intersector with weak index
+      return anIntersect;
+    }
+    delete anIntersect;
+
+    // pure weak naming: there is no sense to use pure weak naming for neighbors selection
+    if (theUseNeighbors) {
+      Selector_WeakName* aWeak = new Selector_WeakName;
+      SET_ALGO_FLAGS(aWeak);
+      if (aWeak->select(theContext, theValue)) {
+        return aWeak;
+      }
+      delete aWeak;
+    }
+    return NULL; // not found value in the tree, not found context shape in the tree also
+  }
+  // searching for the base shapes of the value
+  Handle(TNaming_NamedShape) aPrimitiveNS;
+  NCollection_List<Handle(TNaming_NamedShape)> aModifList;
+  for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
+    TDF_Label aLab = aUseExternal == 0 ? theAccess : theBaseDocument;
+    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);
+        }
+      }
+    }
+  }
+
+  if (!aPrimitiveNS.IsNull()) {
+    Selector_Primitive* aPrimitive = new Selector_Primitive;
+    SET_ALGO_FLAGS(aPrimitive);
+    aPrimitive->select(aPrimitiveNS->Label());
+    return aPrimitive;
+  } else {
+    Selector_Modify* aModify = new Selector_Modify;
+    SET_ALGO_FLAGS(aModify);
+    bool aGoodModify = aModify->select(aModifList, theContext, theValue);
+    // weak intersector is bad for not use neighbors and has lower priority than neighbors
+    if (aGoodModify && aModify->myWeakIndex == -1) {
+      return aModify;
+    }
+    if (!theUseNeighbors) {
+      delete aModify;
+      return false;
+    }
+    // searching by neighbors
+    Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
+    SET_ALGO_FLAGS(aNBs);
+    if (aNBs->select(theContext, theValue)) {
+      delete aModify;
+      return aNBs;
+    }
+    delete aNBs;
+
+    if (aGoodModify) { // if neighbors are bad, use modify algo with weak index
+      return aModify;
+    }
+    delete aModify;
+  }
+
+  return NULL; // invalid case
+}
+
+Selector_Algo* Selector_Algo::relesectWithAllGeometry(
+  Selector_Algo* theOldAlgo, const TopoDS_Shape theContext)
+{
+  return select(theContext, theOldAlgo->value(),
+    theOldAlgo->myLab, theOldAlgo->myBaseDocumentLab, true, true, true, true);
+}
+
+void Selector_Algo::storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast)
+{
+  Handle(TDataStd_ReferenceArray) anArray =
+    TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, theRef.Extent());
+  Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
+  const TDF_Label aThisDocRoot = myLab.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(myLab, 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;
+  }
+}
+
+bool Selector_Algo::restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast)
+{
+  const TDF_Label aThisDocRoot = myLab.Root();
+  Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
+  TDataStd_ListOfExtendedString::Iterator anIter;
+  Handle(TDataStd_ReferenceArray) anArray;
+  if (myLab.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 (myBaseDocumentLab.IsNull())
+          return false;
+        if (anEntries.IsNull()) {
+          if (!myLab.FindAttribute(kBASE_LIST, anEntries))
+            return false;
+          anIter.Initialize(anEntries->List());
+        }
+        if (!anIter.More())
+          return false;
+        TDF_Tool::Label(myBaseDocumentLab.Data(), anIter.Value(), aLab);
+        anIter.Next();
+      }
+      if (anIndex == anUpper) {
+        theLast = aLab;
+      } else {
+        theRef.Append(aLab);
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+void Selector_Algo::store(const TopoDS_Shape theShape)
+{
+  TNaming_Builder aBuilder(myLab);
+  aBuilder.Select(theShape, theShape);
+}
+
+bool Selector_Algo::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;
+}
+
+TopoDS_Shape Selector_Algo::value()
+{
+  Handle(TNaming_NamedShape) aNS;
+  if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
+    return aNS->Get();
+  return TopoDS_Shape(); // empty, error shape
+}
+
+Selector_Algo* Selector_Algo::restoreByLab(TDF_Label theLab)
+{
+  Handle(TDataStd_Integer) aTypeAttr;
+  if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
+    return NULL;
+  Selector_Type aType = Selector_Type(aTypeAttr->Get());
+  Selector_Algo* aResult = NULL;
+  switch (aType) {
+  case SELTYPE_CONTAINER: {
+    aResult = new Selector_Container;
+    break;
+  }
+  case SELTYPE_INTERSECT: {
+    aResult = new Selector_Intersect;
+    break;
+  }
+  case SELTYPE_MODIFICATION: {
+    aResult = new Selector_Modify;
+    break;
+  }
+  case SELTYPE_PRIMITIVE: {
+    aResult = new Selector_Primitive;
+    break;
+  }
+  case SELTYPE_FILTER_BY_NEIGHBOR: {
+    aResult = new Selector_FilterByNeighbors;
+    break;
+  }
+  case SELTYPE_WEAK_NAMING: {
+    aResult = new Selector_WeakName;
+    break;
+  }
+  default: { // unknown case
+  }
+  }
+  if (aResult) {
+    bool aGeomNaming = myLab.IsAttribute(kGEOMETRICAL_NAMING);
+    aResult->myLab = theLab;
+    aResult->myBaseDocumentLab = myBaseDocumentLab;
+    aResult->myGeometricalNaming = aGeomNaming;
+    aResult->myUseNeighbors = myUseNeighbors;
+    aResult->myUseIntersections = myUseIntersections;
+    if (!aResult->restore()) {
+      delete aResult;
+      aResult = NULL;
+    }
+  }
+  return aResult;
+}
+
+Selector_Algo* Selector_Algo::restoreByName(TDF_Label theLab, TDF_Label theBaseDocLab,
+  std::string theName, const TopAbs_ShapeEnum theShapeType,
+  Selector_NameGenerator* theNameGenerator, TDF_Label& theContextLab)
+{
+  Selector_Algo* aResult = NULL;
+  if (theName[0] == '[') { // intersection or container
+    switch(theShapeType) {
+    case TopAbs_COMPOUND:
+    case TopAbs_COMPSOLID:
+    case TopAbs_SHELL:
+    case TopAbs_WIRE:
+      aResult = new Selector_Container;
+      break;
+    case TopAbs_VERTEX:
+    case TopAbs_EDGE:
+    case TopAbs_FACE:
+      aResult = new Selector_Intersect;
+      break;
+    default:;
+    }
+  } else if (theName[0] == '(') { // filter by neighbors
+    aResult = new Selector_FilterByNeighbors;
+  } if (theName.find(pureWeakNameID()) == 0) { // weak naming identifier
+  } else if (theName.find('&') != std::string::npos) { // modification
+    aResult = new Selector_Modify;
+  } else { // primitive
+    aResult = new Selector_Primitive;
+  }
+  if (aResult) {
+    aResult->myLab = theLab;
+    aResult->myBaseDocumentLab = theBaseDocLab;
+    theContextLab = aResult->restoreByName(theName, theShapeType, theNameGenerator);
+    if (theContextLab.IsNull()) {
+      delete aResult;
+      aResult = NULL;
+    }
+  }
+  return aResult;
+}
+
+void Selector_Algo::storeType(const Selector_Type theType)
+{
+  TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)(theType));
+}
diff --git a/src/Selector/Selector_Algo.h b/src/Selector/Selector_Algo.h
new file mode 100644 (file)
index 0000000..b58e99d
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_Algo_H_
+#define Selector_Algo_H_
+
+#include "Selector.h"
+
+#include <Standard_GUID.hxx>
+#include <TDF_Label.hxx>
+#include <TDF_LabelList.hxx>
+#include <TopoDS_Shape.hxx>
+
+class Selector_NameGenerator;
+
+/**\class Selector_Selector
+ * \ingroup DataModel
+ * \brief Base class for all kinds of selection algorithms.
+ */
+class Selector_Algo
+{
+  TopAbs_ShapeEnum myShapeType; ///< type of this shape
+
+  TDF_Label myLab; ///< label where this also may be located
+  TDF_Label myBaseDocumentLab; ///< an access-label of the document that may contain initial shapes
+  bool myGeometricalNaming; ///< flag that indicates that geometrical naming selection is enabled
+  bool myAlwaysGeometricalNaming; ///< to enable geometrical naming from beginning, at select
+  bool myUseNeighbors; ///< to use neighbors algorithms
+  bool myUseIntersections; ///< to use intersections algorithms
+
+public:
+  /// Type of a selector algorithm: on this type depends what is stored in this label and how to
+  /// restore it on update.
+  enum Selector_Type {
+    SELTYPE_CONTAINER, ///< just a container of sub-elements, keeps the shape type of container
+    SELTYPE_INTERSECT, ///< sub-shape is intersection of higher level objects
+    SELTYPE_PRIMITIVE, ///< sub-shape found as a primitive on some label
+    SELTYPE_MODIFICATION, ///< modification of base shapes to the final label
+    SELTYPE_FILTER_BY_NEIGHBOR,  ///< identification by neighbor shapes in context
+    SELTYPE_WEAK_NAMING, ///< pure weak naming by weak index in context
+  };
+
+  /// Initializes the algorithm
+  SELECTOR_EXPORT Selector_Algo();
+
+  /// Initializes the selector structure on the label.
+  /// Stores the name data to restore after modification.
+  /// \param theContext whole shape that contains the selected sub-shape
+  /// \param theValue selected subshape
+  /// \param theGeometricalNaming treats selection with equal surfaces as one
+  /// \param theUseNeighbors enables searching algorithm by neighbors
+  /// \param theUseIntersections enables searching algorithm by intersection of higher level shapes
+  SELECTOR_EXPORT static Selector_Algo* select(
+    const TopoDS_Shape theContext, const TopoDS_Shape theValue,
+    const TDF_Label theAccess, const TDF_Label theBaseDocument,
+    const bool theGeometricalNaming = false,
+    const bool theUseNeighbors = true, const bool theUseIntersections = true,
+    const bool theAlwaysGeometricalNaming = false);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() = 0;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() = 0;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) = 0;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) = 0;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) = 0;
+  /// Returns the current sub-shape value (null if can not resolve)
+  SELECTOR_EXPORT TopoDS_Shape value();
+  /// Restores sub-algorithm of a given type by the storage-label
+  SELECTOR_EXPORT Selector_Algo* restoreByLab(TDF_Label theLab);
+  /// Restores the selected sub-algorithm by the naming name.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT static Selector_Algo* restoreByName(
+    TDF_Label theLab, TDF_Label theBaseDocLab, std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator,
+    TDF_Label& theContextLab);
+
+  /// Returns true if the given shapes are based on the same geometry
+  static bool sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2);
+
+  /// Creates a new selection algorithm for selection of all topology based on the same geometry
+  SELECTOR_EXPORT static Selector_Algo* relesectWithAllGeometry(
+    Selector_Algo* theOldAlgo, const TopoDS_Shape theContext);
+
+protected:
+  /// Returns label where this algorithm is attached to, or just an access label to the document
+  const TDF_Label& label() const
+  {return myLab;}
+  /// Stores the array of references to theLab: references to elements of ref-list, then the last
+  void storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast);
+  /// Restores references to the labels: references to elements of ref-list, then the last
+  bool restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast);
+  /// Stores result of selection at the given label
+  void store(const TopoDS_Shape theShape);
+  /// Returns an access-label of the document that may contain initial shapes
+  const TDF_Label& baseDocument() const
+  {return myBaseDocumentLab;}
+  /// Returns the geometrical naming flag
+  bool geometricalNaming() const
+  {return myGeometricalNaming;}
+  /// Returns always geometrical naming flag
+  bool alwaysGeometricalNaming() const
+  {return myAlwaysGeometricalNaming;}
+  /// Returns use neighbors flag
+  bool useNeighbors() const
+  {return myUseNeighbors;}
+  /// Returns use intersections flag
+  bool useIntersections() const
+  {return myUseIntersections;}
+  /// Returns GUID for the weak index (integer attribute) of the sub-shape
+  static const Standard_GUID& weakID()
+  {
+    static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
+    return kWEAK_INDEX;
+  }
+  /// Returns GUID for the type of the shape, stored in case it is intersection or container
+  static const Standard_GUID& shapeTypeID()
+  {
+    static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
+    return kSHAPE_TYPE;
+  }
+  /// string identifier of the weak name in modification or intersection types of algorithm
+  static const std::string& weakNameID()
+  {
+    static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
+    return kWEAK_NAME_IDENTIFIER;
+  }
+  /// string identifier of the pure weak name
+  static const std::string& pureWeakNameID()
+  {
+    static const std::string kPURE_WEAK_NAME_IDENTIFIER = "_weak_name_";
+    return kPURE_WEAK_NAME_IDENTIFIER;
+  }
+  /// Stores the type of an algorithm in the data tree (in myLab)
+  void storeType(const Selector_Type theType);
+};
+
+#endif
diff --git a/src/Selector/Selector_AlgoWithSubs.cpp b/src/Selector/Selector_AlgoWithSubs.cpp
new file mode 100644 (file)
index 0000000..32229e5
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_AlgoWithSubs.h>
+
+Selector_AlgoWithSubs::Selector_AlgoWithSubs() : Selector_Algo()
+{}
+
+void Selector_AlgoWithSubs::clearSubAlgos()
+{
+  std::list<Selector_Algo*>::iterator anAlgo = mySubSelList.begin();
+  for(; anAlgo != mySubSelList.end(); anAlgo++) {
+    delete *anAlgo;
+  }
+  mySubSelList.clear();
+}
+
+Selector_AlgoWithSubs::~Selector_AlgoWithSubs()
+{
+  clearSubAlgos();
+}
+
+TDF_Label Selector_AlgoWithSubs::newSubLabel()
+{
+  return label().FindChild(int(mySubSelList.size() + 1));
+}
+
+bool Selector_AlgoWithSubs::append(Selector_Algo* theAlgo, const bool theEraseIfNull)
+{
+  if (theAlgo) {
+    mySubSelList.push_back(theAlgo);
+    return true;
+  }
+  if (theEraseIfNull)
+    clearSubAlgos();
+  return false;
+}
+
+const std::list<Selector_Algo*>& Selector_AlgoWithSubs::list() const
+{
+  return mySubSelList;
+}
diff --git a/src/Selector/Selector_AlgoWithSubs.h b/src/Selector/Selector_AlgoWithSubs.h
new file mode 100644 (file)
index 0000000..58734a3
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_AlgoWithSubs_H_
+#define Selector_AlgoWithSubs_H_
+
+#include "Selector_Algo.h"
+
+#include <list>
+
+/**\class Selector_AlgoWithSubs
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: generic algorithm that contains sub-algorithms inside.
+ * It is base for Container, Intersection and FilterByNeighbours algorithms.
+ */
+class Selector_AlgoWithSubs: public Selector_Algo
+{
+  std::list<Selector_Algo*> mySubSelList; ///< list of sub-algorithms
+public:
+  /// Initializes selector
+  Selector_AlgoWithSubs();
+  /// Destructor
+  virtual ~Selector_AlgoWithSubs();
+  /// Erases the sub-algorithms stored
+  void clearSubAlgos();
+  /// Returns the next label for a new sub-selector created
+  TDF_Label newSubLabel();
+  /// Appends a new algorithm to the list, erases list if it is null (failed)
+  bool append(Selector_Algo* theAlgo, const bool theEraseIfNull = true);
+  /// Returns the stored list of sub-algorithms.
+  const std::list<Selector_Algo*>& list() const;
+};
+
+#endif
diff --git a/src/Selector/Selector_Container.cpp b/src/Selector/Selector_Container.cpp
new file mode 100644 (file)
index 0000000..32d7134
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_Container.h>
+
+#include <Selector_NameGenerator.h>
+#include <Selector_NExplode.h>
+
+#include <TNaming_NamedShape.hxx>
+#include <TDataStd_Name.hxx>
+#include <TDataStd_Integer.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopExp_Explorer.hxx>
+#include <BRep_Tool.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+
+Selector_Container::Selector_Container() : Selector_AlgoWithSubs()
+{}
+
+bool Selector_Container::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+{
+  myShapeType = theValue.ShapeType();
+
+  // iterate all sub-shapes and select them on sublabels
+  for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
+    Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, aSubIter.Value(),
+      newSubLabel(), baseDocument(),
+      false, useNeighbors(), useIntersections()); //for subs no geometrical naming allowed
+    if (!append(aSubAlgo))
+      return false;
+  }
+  return true;
+}
+
+void Selector_Container::store()
+{
+  storeType(Selector_Algo::SELTYPE_CONTAINER);
+  // store all sub-selectors
+  TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++) {
+    (*aSubSel)->store();
+  }
+  TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
+}
+
+bool Selector_Container::restore()
+{
+  Handle(TDataStd_Integer) aShapeTypeAttr;
+  if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
+    return false;
+  myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+  // restore sub-selectors
+  bool aSubResult = true;
+  for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) {
+    Selector_Algo* aSubSel = restoreByLab(aSub.Value());
+    if (!append(aSubSel, false)) {
+      break; // some empty label left in the end
+    }
+  }
+  return true;
+}
+
+TDF_Label Selector_Container::restoreByName(std::string theName,
+  const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
+{
+  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);
+      TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
+      switch (myShapeType) {
+      case TopAbs_COMPSOLID: aSubShapeType = TopAbs_SOLID; break;
+      case TopAbs_WIRE: aSubShapeType = TopAbs_EDGE; break;
+      default:;
+      }
+      TDF_Label aSubContext;
+      Selector_Algo* aSubSel =
+        Selector_Algo::restoreByName(
+          label(), baseDocument(), aSubStr, aSubShapeType, theNameGenerator, aSubContext);
+      if (!append(aSubSel))
+        return TDF_Label();
+
+      if (aSubContext.IsNull()) {
+        delete aSubSel;
+        clearSubAlgos();
+        return TDF_Label();
+      }
+      if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
+        if (!theNameGenerator->isLater(aContext, aSubContext))
+          aContext = aSubContext;
+      } else {
+        aContext = aSubContext;
+      }
+    } else
+      return TDF_Label(); // invalid parentheses
+  }
+  return aContext;
+}
+
+bool Selector_Container::solve(const TopoDS_Shape& theContext)
+{
+  TopoDS_Shape aResult;
+
+  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;
+  }
+  }
+  TopoDS_ListOfShape aSubSelectorShapes;
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++) {
+    if (!(*aSubSel)->solve(theContext)) {
+      return false;
+    }
+    aBuilder.Add(aResult, (*aSubSel)->value());
+  }
+  if (!aResult.IsNull()) {
+    Selector_Algo::store(aResult);
+    return true;
+  }
+  return false;
+}
+
+std::string Selector_Container::name(Selector_NameGenerator* theNameGenerator)
+{
+  std::string aResult;
+  // add names of sub-components one by one in "[]"
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++) {
+    aResult += '[';
+    aResult += (*aSubSel)->name(theNameGenerator);
+    aResult += ']';
+  }
+  return aResult;
+}
diff --git a/src/Selector/Selector_Container.h b/src/Selector/Selector_Container.h
new file mode 100644 (file)
index 0000000..668b651
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_Container_H_
+#define Selector_Container_H_
+
+#include "Selector_AlgoWithSubs.h"
+
+#include <list>
+
+/**\class Selector_Container
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: selected shape is a container of sub-shapes that must
+ * be named one by one.
+ */
+class Selector_Container: public Selector_AlgoWithSubs
+{
+  TopAbs_ShapeEnum myShapeType; ///< type of this container
+public:
+  /// Initializes the selection of this kind
+  SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() override;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() override;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override;
+private:
+  /// Initializes selector
+  Selector_Container();
+
+  friend class Selector_Algo;
+};
+
+#endif
diff --git a/src/Selector/Selector_FilterByNeighbors.cpp b/src/Selector/Selector_FilterByNeighbors.cpp
new file mode 100644 (file)
index 0000000..43221ba
--- /dev/null
@@ -0,0 +1,354 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_FilterByNeighbors.h>
+
+#include <Selector_NameGenerator.h>
+
+#include <TopoDS.hxx>
+#include <TopoDS_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TDataStd_Integer.hxx>
+#include <TDataStd_IntegerArray.hxx>
+#include <TDF_ChildIterator.hxx>
+
+// array of the neighbor levels
+static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
+
+Selector_FilterByNeighbors::Selector_FilterByNeighbors() : Selector_AlgoWithSubs()
+{}
+
+/// 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, const bool theGeometrical)
+{
+  // 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
+  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;
+  TopTools_MapOfShape aGoodCandidates; // already added good candidates to the map
+  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 { // another good candidate
+          if (theGeometrical && Selector_Algo::sameGeometry(aGoodCandidate, aCandidate.Value())) {
+            if (!aGoodCandidates.Add(aCandidate.Value()))
+              break;
+            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()) {
+        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 (!aValidCadidate) // candidate is not valid, break the checking
+        break;
+    }
+  }
+  if (!aResultCompound.IsNull())
+    return aResultCompound;
+  return aGoodCandidate;
+}
+
+bool Selector_FilterByNeighbors::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+{
+  myShapeType = theValue.ShapeType();
+  // 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;
+    }
+    // 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_Algo* aSubAlgo = Selector_Algo::select(theContext, aNewNBShape,
+          newSubLabel(), baseDocument(), geometricalNaming(), false, false);
+        if (aSubAlgo) {
+          // add to list of good NBs
+          aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
+        }
+        delete aSubAlgo; // don't keep this sub-algo until all subs and whole validity are checked
+      }
+    }
+    TopoDS_Shape aResult = findNeighbor(theContext, aNBs, geometricalNaming());
+    if (!aResult.IsNull() && aResult.IsSame(theValue)) {
+      std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
+      for(; aNBIter != aNBs.end(); aNBIter++) {
+        Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, aNBIter->first,
+          newSubLabel(), baseDocument(), geometricalNaming(), false, false);
+        if (append(aSubAlgo)) {
+          myNBLevel.push_back(aNBIter->second);
+        } else {
+          delete aSubAlgo;
+        }
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+void Selector_FilterByNeighbors::store()
+{
+  storeType(Selector_Algo::SELTYPE_FILTER_BY_NEIGHBOR);
+  TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
+  // store numbers of levels corresponded to the neighbors in sub-selectors
+  Handle(TDataStd_IntegerArray) anArray =
+    TDataStd_IntegerArray::Set(label(), 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_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++) {
+    (*aSubSel)->store();
+  }
+}
+
+bool Selector_FilterByNeighbors::restore()
+{
+  Handle(TDataStd_Integer) aShapeTypeAttr;
+  if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
+    return false;
+  myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+  // restore levels indices
+  Handle(TDataStd_IntegerArray) anArray;
+  if (!label().FindAttribute(kLEVELS_ARRAY, anArray))
+    return false;
+  for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
+    myNBLevel.push_back(anArray->Value(anIndex));
+  }
+  // restore sub-selectors
+  bool aSubResult = true;
+  for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) {
+    Selector_Algo* aSubSel = restoreByLab(aSub.Value());
+    if (!append(aSubSel, false)) {
+      break; // some empty label left in the end
+    }
+  }
+  return true;
+}
+
+TDF_Label Selector_FilterByNeighbors::restoreByName(std::string theName,
+  const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
+{
+  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);
+      TDF_Label aSubContext;
+      Selector_Algo* aSubSel =
+        Selector_Algo::restoreByName(
+          label(), baseDocument(), aSubStr, myShapeType, theNameGenerator, aSubContext);
+      if (!append(aSubSel))
+        return TDF_Label();
+
+      if (aSubContext.IsNull()) {
+        delete aSubSel;
+        clearSubAlgos();
+        return TDF_Label();
+      }
+      if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
+        if (!theNameGenerator->isLater(aContext, aSubContext))
+          aContext = aSubContext;
+      } 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 &&
+        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;
+}
+
+bool Selector_FilterByNeighbors::solve(const TopoDS_Shape& theContext)
+{
+  TopoDS_Shape aResult;
+
+  std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
+  std::list<int>::iterator aLevel = myNBLevel.begin();
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++, aLevel++) {
+    if (!(*aSubSel)->solve(theContext)) {
+      return false;
+    }
+    aNBs.push_back(std::pair<TopoDS_Shape, int>((*aSubSel)->value(), *aLevel));
+  }
+  aResult = findNeighbor(theContext, aNBs, geometricalNaming());
+  if (!aResult.IsNull()) {
+    Selector_Algo::store(aResult);
+    return true;
+  }
+  return false;
+}
+
+std::string Selector_FilterByNeighbors::name(Selector_NameGenerator* theNameGenerator)
+{
+  // (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_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++, aLevel++) {
+    aResult += "(" + (*aSubSel)->name(theNameGenerator) + ")";
+    if (*aLevel > 1) {
+      std::ostringstream aLevelStr;
+      aLevelStr<<*aLevel;
+      aResult += aLevelStr.str();
+    }
+  }
+  return aResult;
+}
diff --git a/src/Selector/Selector_FilterByNeighbors.h b/src/Selector/Selector_FilterByNeighbors.h
new file mode 100644 (file)
index 0000000..721e4a9
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_FilterByNeighbors_H_
+#define Selector_FilterByNeighbors_H_
+
+#include "Selector_AlgoWithSubs.h"
+
+#include <list>
+
+/**\class Selector_FilterByNeighbors
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: selected shape is identified by neighbor faces of
+ * the same type. Or neighbors of neighbors are considered, etc.
+ * be named one by one.
+ */
+class Selector_FilterByNeighbors: public Selector_AlgoWithSubs
+{
+  TopAbs_ShapeEnum myShapeType; ///< type of this shape
+  std::list<int> myNBLevel; ///< list of integers corresponding to subs neighborhood level
+public:
+  /// Initializes the selection of this kind
+  SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() override;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() override;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override;
+private:
+  /// Initializes selector
+  Selector_FilterByNeighbors();
+
+  friend class Selector_Algo;
+};
+
+#endif
diff --git a/src/Selector/Selector_Intersect.cpp b/src/Selector/Selector_Intersect.cpp
new file mode 100644 (file)
index 0000000..8d1a3de
--- /dev/null
@@ -0,0 +1,316 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_Intersect.h>
+
+#include <Selector_NameGenerator.h>
+#include <Selector_NExplode.h>
+
+#include <TNaming_NamedShape.hxx>
+#include <TDataStd_Name.hxx>
+#include <TDataStd_Integer.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopExp_Explorer.hxx>
+#include <BRep_Tool.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+
+Selector_Intersect::Selector_Intersect() : Selector_AlgoWithSubs()
+{
+  myWeakIndex = -1; // no index by default
+}
+
+// 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);
+      }
+    }
+  }
+}
+
+bool Selector_Intersect::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+{
+  myShapeType = theValue.ShapeType();
+  TopAbs_ShapeEnum aSelectionType = myShapeType;
+  // 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
+  TopoDS_ListOfShape aLastCommon; // store not good commons, but which may be used for weak naming
+  TopoDS_ListOfShape 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()) {
+      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)) {
+          if (anIntersectors.Add(aSelExp.Current()))
+            anIntList.Append(aSelExp.Current());
+          break;
+        }
+      }
+    }
+    // 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
+      TopoDS_ListOfShape::Iterator anInt(anIntList);
+      for (; anInt.More(); anInt.Next()) {
+        Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(),
+          newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), false);
+        if (!append(aSubAlgo))
+          break; // if some selector is failed, stop and search another solution
+      }
+      if (!anInt.More()) { // all intersectors were correctly named
+        return true;
+      }
+    } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty())  {
+      aLastCommon = aCommon;
+      aLastIntersectors = anIntList;
+    }
+  }
+  if (aLastCommon.Extent() > 1) {
+    if (alwaysGeometricalNaming()) {
+      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
+        return true;
+      }
+    }
+    // weak naming to distinguish commons coming from intersection
+    Selector_NExplode aNexp(aLastCommon);
+    myWeakIndex = aNexp.index(theValue);
+    if (myWeakIndex != -1) {
+      // name the intersectors
+      TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
+      for (; anInt.More(); anInt.Next()) {
+        Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(),
+          newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), useIntersections());
+        if (!append(aSubAlgo))
+          break; // if some selector is failed, stop and search another solution
+      }
+      if (!anInt.More()) { // all intersectors were correctly named
+        return true;
+      }
+    }
+  }
+  return false; // solution does not found
+}
+
+void Selector_Intersect::store()
+{
+  storeType(Selector_Algo::SELTYPE_INTERSECT);
+  // store all sub-selectors
+  TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); aSubSel++) {
+    (*aSubSel)->store();
+  }
+  TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
+  if (myWeakIndex != -1) {
+    TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
+  }
+}
+
+bool Selector_Intersect::restore()
+{
+  Handle(TDataStd_Integer) aShapeTypeAttr;
+  if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
+    return false;
+  myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+  // restore sub-selectors
+  bool aSubResult = true;
+  for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) {
+    Selector_Algo* aSubSel = restoreByLab(aSub.Value());
+    if (!append(aSubSel, false)) {
+      break; // some empty label left in the end
+    }
+  }
+  Handle(TDataStd_Integer) aWeakInt;
+  if (label().FindAttribute(weakID(), aWeakInt)) {
+    myWeakIndex = aWeakInt->Get();
+  }
+  return true;
+}
+
+TDF_Label Selector_Intersect::restoreByName(std::string theName,
+  const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
+{
+  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(weakNameID()) == 0) { // weak name identifier
+        std::string aWeakIndex = aSubStr.substr(weakNameID().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:;
+          }
+        }
+      }
+      TDF_Label aSubContext;
+      Selector_Algo* aSubSel =
+        Selector_Algo::restoreByName(
+          label(), baseDocument(), aSubStr, aSubShapeType, theNameGenerator, aSubContext);
+      if (!append(aSubSel))
+        return TDF_Label();
+
+      if (aSubContext.IsNull()) {
+        delete aSubSel;
+        clearSubAlgos();
+        return TDF_Label();
+      }
+      if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
+        if (!theNameGenerator->isLater(aContext, aSubContext))
+          aContext = aSubContext;
+      } else {
+        aContext = aSubContext;
+      }
+    } else
+      return TDF_Label(); // invalid parentheses
+  }
+  return aContext;
+}
+
+bool Selector_Intersect::solve(const TopoDS_Shape& theContext)
+{
+  TopoDS_Shape aResult;
+  TopoDS_ListOfShape aSubSelectorShapes;
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); 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 if (geometricalNaming() && 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();
+  }
+  if (!aResult.IsNull()) {
+    Selector_Algo::store(aResult);
+    return true;
+  }
+  return false;
+}
+
+std::string Selector_Intersect::name(Selector_NameGenerator* theNameGenerator)
+{
+  std::string aResult;
+  // add names of sub-components one by one in "[]" +optionally [weak_name_1]
+  std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
+  for(; aSubSel != list().cend(); 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<<"["<<weakNameID()<<myWeakIndex<<"]";
+    aResult += aWeakStr.str();
+  }
+  return aResult;
+}
diff --git a/src/Selector/Selector_Intersect.h b/src/Selector/Selector_Intersect.h
new file mode 100644 (file)
index 0000000..e3e27ac
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_Intersect_H_
+#define Selector_Intersect_H_
+
+#include "Selector_AlgoWithSubs.h"
+
+#include <list>
+
+/**\class Selector_Intersect
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: sub-shape is intersection of higher level objects.
+ */
+class Selector_Intersect: public Selector_AlgoWithSubs
+{
+  TopAbs_ShapeEnum myShapeType; ///< type of this shape
+  int myWeakIndex; ///< weak index in case intersection produces several shapes
+public:
+  /// Initializes the selection of this kind
+  SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() override;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() override;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override;
+private:
+  /// Initializes selector
+  Selector_Intersect();
+
+  friend class Selector_Algo;
+};
+
+#endif
diff --git a/src/Selector/Selector_Modify.cpp b/src/Selector/Selector_Modify.cpp
new file mode 100644 (file)
index 0000000..f764e1d
--- /dev/null
@@ -0,0 +1,329 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_Modify.h>
+
+#include <Selector_NameGenerator.h>
+#include <Selector_NExplode.h>
+
+#include <TNaming_NamedShape.hxx>
+#include <TNaming_Iterator.hxx>
+#include <TNaming_SameShapeIterator.hxx>
+#include <TNaming_NewShapeIterator.hxx>
+#include <TNaming_Tool.hxx>
+#include <TDataStd_Name.hxx>
+#include <TDataStd_Integer.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopExp_Explorer.hxx>
+#include <BRep_Tool.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+
+Selector_Modify::Selector_Modify() : Selector_Algo()
+{
+  myWeakIndex = -1; // no index by default
+}
+
+// adds to theResult all labels that contain initial shapes for theValue located in theFinal
+static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal,
+  const TopoDS_Shape& theValue,
+  bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
+{
+  bool aFoundAnyShape = false;
+  TNaming_SameShapeIterator aLabIter(theValue, theAccess);
+  for(; aLabIter.More(); aLabIter.Next()) {
+    Handle(TNaming_NamedShape) aNS;
+    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 (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 in theResults all shapes with history started in theBase and ended in theFinal
+static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
+  const TDF_Label& theFinal,
+  const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& 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_Modify::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() != label().Root()) {
+      anAdditionalDoc = label();
+    }
+    TopTools_MapOfShape 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()) {
+          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_Modify::select(NCollection_List<Handle(TNaming_NamedShape)>& theModifList,
+  const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+{
+  if (theModifList.Extent() > 1) { // searching for the best modification result: by context
+    Handle(TNaming_NamedShape) aCandidate;
+    NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(theModifList);
+    for (; !theModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
+      aCandidate = aModIter.Value();
+      TDF_Label aFatherLab = aCandidate->Label().Father();
+      Handle(TNaming_NamedShape) aFatherNS;
+      if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
+        for (TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
+          if (theContext.IsSame(anIter.NewShape())) { // found the best modification
+            theModifList.Clear();
+            break;
+          }
+        }
+      }
+    }
+    // take the best candidate, or the last in the iteration
+    theModifList.Clear();
+    theModifList.Append(aCandidate);
+  }
+
+  if (!theModifList.IsEmpty()) {
+    // searching for all the base shapes of this modification
+    findBases(label(), theModifList.First(), theValue, true, baseDocument(), myBases);
+    if (!myBases.IsEmpty()) {
+      myFinal = theModifList.First()->Label();
+      TopoDS_ListOfShape aCommon;
+      findModificationResult(aCommon);
+      // trying to search by neighbors
+      if (aCommon.Extent() > 1) { // more complicated selection
+        if (alwaysGeometricalNaming()) {
+          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
+            return true;
+          }
+        }
+      }
+    }
+    // weak naming case
+    TopoDS_ListOfShape aCommon;
+    myFinal = theModifList.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);
+    return myWeakIndex != -1;
+  }
+  return false;
+}
+
+void Selector_Modify::store()
+{
+  storeType(Selector_Algo::SELTYPE_MODIFICATION);
+  storeBaseArray(myBases, myFinal);
+  if (myWeakIndex != -1) {
+    TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
+  }
+}
+
+bool Selector_Modify::restore()
+{
+  if (restoreBaseArray(myBases, myFinal)) {
+    Handle(TDataStd_Integer) aWeakInt;
+    if (label().FindAttribute(weakID(), aWeakInt)) {
+      myWeakIndex = aWeakInt->Get();
+    }
+    return true;
+  }
+  return false;
+}
+
+TDF_Label Selector_Modify::restoreByName(std::string theName,
+  const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
+{
+  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(weakNameID()) == 0) { // weak name identifier
+      std::string aWeakIndex = aSubStr.substr(weakNameID().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;
+}
+
+bool Selector_Modify::solve(const TopoDS_Shape& theContext)
+{
+  TopoDS_Shape aResult;
+  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 && geometricalNaming()) {// 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;
+      }
+
+    }
+  }
+
+  if (!aResult.IsNull()) {
+    Selector_Algo::store(aResult);
+    return true;
+  }
+  return false;
+}
+
+std::string Selector_Modify::name(Selector_NameGenerator* theNameGenerator)
+{
+  // 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<<"&"<<weakNameID()<<myWeakIndex;
+    aResult += aWeakStr.str();
+  }
+  return aResult;
+}
diff --git a/src/Selector/Selector_Modify.h b/src/Selector/Selector_Modify.h
new file mode 100644 (file)
index 0000000..30bf737
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_Modify_H_
+#define Selector_Modify_H_
+
+#include "Selector_Algo.h"
+
+#include <TNaming_NamedShape.hxx>
+
+#include <list>
+
+/**\class Selector_Modify
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: sub-shape is modification of primitive at some
+ * final stage.
+ */
+class Selector_Modify: public Selector_Algo
+{
+  TDF_Label myFinal; ///< final label of the primitive or generation, where the value is
+  TDF_LabelList myBases; ///< initial labels that contain shapes that produce the modification
+  int myWeakIndex; ///< weak index in case modification produces several shapes
+public:
+  /// Initializes the selection of this kind by list of named shapes where the modification results
+  /// are presented and the selected value.
+  SELECTOR_EXPORT bool select(NCollection_List<Handle(TNaming_NamedShape)>& theModifList,
+    const TopoDS_Shape theContext, const TopoDS_Shape theValue);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() override;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() override;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override;
+
+private:
+  /// Initializes selector
+  Selector_Modify();
+  /// Searches the final shapes presented in all results from bases basing on modification fields
+  void findModificationResult(TopoDS_ListOfShape& theCommon);
+
+  friend class Selector_Algo;
+};
+
+#endif
index dc4d0064bd6d0f3b514f7ef01b284ffd54518ea4..cb23b4d24c3ec19ff6fd8185889ef6158b0b4add 100644 (file)
@@ -45,7 +45,7 @@ class Selector_NExplode
    SELECTOR_EXPORT TopoDS_Shape shape(const int theIndex);
 
 protected:
-  TopoDS_ListOfShape mySorted; ///< keepthe the ordered list of shapes
+  TopoDS_ListOfShape mySorted; ///< keep the ordered list of shapes
 };
 
 #endif
diff --git a/src/Selector/Selector_Primitive.cpp b/src/Selector/Selector_Primitive.cpp
new file mode 100644 (file)
index 0000000..15c617d
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_Primitive.h>
+
+#include <Selector_NameGenerator.h>
+
+#include <TNaming_NamedShape.hxx>
+#include <TDataStd_Name.hxx>
+
+
+Selector_Primitive::Selector_Primitive() : Selector_Algo()
+{
+}
+
+void Selector_Primitive::select(const TDF_Label theFinalLabel)
+{
+  myFinal = theFinalLabel;
+}
+
+void Selector_Primitive::store()
+{
+  storeType(Selector_Algo::SELTYPE_PRIMITIVE);
+  static const TDF_LabelList anEmptyRefList;
+  storeBaseArray(anEmptyRefList, myFinal);
+}
+
+bool Selector_Primitive::restore()
+{
+  static TDF_LabelList anEmptyRefList;
+  return restoreBaseArray(anEmptyRefList, myFinal);
+}
+
+TDF_Label Selector_Primitive::restoreByName(std::string theName,
+  const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
+{
+  TDF_Label aContext;
+  if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
+    if (myFinal.IsNull())
+      aContext.Nullify();
+  }
+  return aContext;
+}
+
+bool Selector_Primitive::solve(const TopoDS_Shape& theContext)
+{
+  Handle(TNaming_NamedShape) aNS;
+  if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+    Selector_Algo::store(aNS->Get());
+    return true;
+  }
+  return false;
+}
+
+std::string Selector_Primitive::name(Selector_NameGenerator* theNameGenerator)
+{
+  Handle(TDataStd_Name) aName;
+  if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
+    return "";
+  std::string aResult = theNameGenerator->contextName(myFinal);
+  if (!aResult.empty())
+    aResult += "/" + std::string(TCollection_AsciiString(aName->Get()).ToCString());
+  return aResult;
+}
diff --git a/src/Selector/Selector_Primitive.h b/src/Selector/Selector_Primitive.h
new file mode 100644 (file)
index 0000000..ea8b23a
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_Primitive_H_
+#define Selector_Primitive_H_
+
+#include "Selector_Algo.h"
+
+/**\class Selector_Primitive
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: exact referencing to alone shape in the data structure.
+ */
+class Selector_Primitive: public Selector_Algo
+{
+  TDF_Label myFinal; ///< final label of the where the value is
+public:
+  /// Initializes the selection of this kind
+  /// \param theLabel the final label with the primitive shape
+  SELECTOR_EXPORT void select(const TDF_Label theFinalLabel);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() override;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() override;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override;
+private:
+  /// Initializes selector
+  Selector_Primitive();
+
+  friend class Selector_Algo;
+};
+
+#endif
index 0a5c87ac3b7cfb38d3a4f9cfe960e33b647c1211..62d1ad0cba9f24cd2f818bc5bd1016adb3affb7d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+  // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 #include <Selector_Selector.h>
 
 #include <Selector_NameGenerator.h>
-#include <Selector_NExplode.h>
+#include <Selector_Algo.h>
 
-#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_SameShapeIterator.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, 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()
-{
-  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(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal,
-  const TopoDS_Shape& theValue,
-  bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
-{
-  bool aFoundAnyShape = false;
-  TNaming_SameShapeIterator aLabIter(theValue, theAccess);
-  for(; aLabIter.More(); aLabIter.Next()) {
-    Handle(TNaming_NamedShape) aNS;
-    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 (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)
-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());
-      }
-    }
-  }
-}
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TNaming_NamedShape.hxx>
 
-/// 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;
-}
+Selector_Selector::Selector_Selector(TDF_Label theLab, TDF_Label theBaseDocLab) :
+  myLab(theLab), myBaseDocumentLab(theBaseDocLab), myAlgo(NULL)
+{}
 
-/// 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 bool theGeometrical)
+Selector_Selector::~Selector_Selector()
 {
-  // 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
-  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;
-  TopTools_MapOfShape aGoodCandidates; // already added good candidates to the map
-  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 { // another good candidate
-          if (theGeometrical && sameGeometry(aGoodCandidate, aCandidate.Value())) {
-            if (!aGoodCandidates.Add(aCandidate.Value()))
-              break;
-            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()) {
-        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 (!aValidCadidate) // candidate is not valid, break the checking
-        break;
-    }
-  }
-  if (!aResultCompound.IsNull())
-    return aResultCompound;
-  return aGoodCandidate;
+  if (myAlgo)
+    delete myAlgo;
 }
 
 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
-  const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections)
+  const bool theGeometricalNaming)
 {
   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)
-  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(),
-            false, theUseNeighbors, theUseIntersections)) {//for subs no geometrical naming allowed
-          return false; // if some selector is failed, everything is failed
-        }
-      }
-      myType = SELTYPE_CONTAINER;
-      return true;
-    }
-
-    // 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
-    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;
-        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()) {
-        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)) {
-            if (anIntersectors.Add(aSelExp.Current()))
-              anIntList.Append(aSelExp.Current());
-            break;
-          }
-        }
-      }
-      // 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();
-        TopoDS_ListOfShape::Iterator anInt(anIntList);
-        for (; anInt.More(); anInt.Next()) {
-          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 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;
-      }
-      // 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));
-          }
-        }
-      }
-      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,
-              theGeometricalNaming, false, false)) {
-            return false; // something is wrong because before this selection was ok
-          }
-          myNBLevel.push_back(aNBIter->second);
-
-        }
-        myType = SELTYPE_FILTER_BY_NEIGHBOR;
-        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(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);
-        }
-      }
-    }
-  }
 
-  if (!aPrimitiveNS.IsNull()) {
-    myType = SELTYPE_PRIMITIVE;
-    myFinal = aPrimitiveNS->Label();
-    return true;
-  }
-
-  if (aModifList.Extent() > 1) { // searching for the best modification result: by context
-    Handle(TNaming_NamedShape) aCandidate;
-    NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
-    for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
-       aCandidate = aModIter.Value();
-      TDF_Label aFatherLab = aCandidate->Label().Father();
-      Handle(TNaming_NamedShape) aFatherNS;
-      if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
-        for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
-          if (theContext.IsSame(anIter.NewShape())) { // found the best modification
-            aModifList.Clear();
-            break;
-          }
-        }
-      }
-    }
-    // take the best candidate, or the last in the iteration
-    aModifList.Clear();
-    aModifList.Append(aCandidate);
-  }
-
-  if (!aModifList.IsEmpty()) {
-    // searching for all the base shapes of this modification
-    findBases(myLab, aModifList.First(), theValue, true, myBaseDocumentLab, myBases);
-    if (!myBases.IsEmpty()) {
-      myFinal = aModifList.First()->Label();
-      TopoDS_ListOfShape aCommon;
-      findModificationResult(aCommon);
-      // 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 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;
-          }
-          // 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));
-              }
-            }
-          }
-          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,
-                  theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
-                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 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)
-            return false;
-        }
-      }
-    }
-    myType = SELTYPE_MODIFICATION;
-    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;
-  }
+  myAlgo = Selector_Algo::select(theContext, theValue, myLab, myBaseDocumentLab,
+    theGeometricalNaming, true, 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: {
-    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: {
-    storeBaseArray(myLab, anEmptyRefList, myFinal);
-    break;
-  }
-  case SELTYPE_MODIFICATION: {
-    storeBaseArray(myLab, myBases, myFinal);
-    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);
-    if (!myFinal.IsNull()) {
-      storeBaseArray(myLab, anEmptyRefList, myFinal);
-    }
-    break;
-  }
-  default: { // unknown case
-    break;
-  }
-  }
+  return myAlgo != NULL;
 }
 
-/// 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)
+bool Selector_Selector::store(const TopoDS_Shape theContext)
 {
-  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;
+  myAlgo->store();
+  return myAlgo->solve(theContext); // to update the selection shape on the label
 }
 
-
-bool Selector_Selector::restore()
+bool Selector_Selector::restore(const TopoDS_Shape theContext)
 {
-  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:
-  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()));
-      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: {
-    return restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal);
-  }
-  case SELTYPE_MODIFICATION: {
-    if (restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) {
-      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()));
-      mySubSelList.back().setBaseDocument(myBaseDocumentLab);
-      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());
-    if (!restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal))
-      return false;
+  if (myAlgo->restoreByLab(myLab)) {
+    myAlgo->solve(theContext); // to update the selection shape on the label
     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 TDF_Label& anAccess, const TopoDS_Shape& theBase,
-  const TDF_Label& theFinal,
-  const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& 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(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()) {
-          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 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: {
-    Handle(TNaming_NamedShape) aNS;
-    if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
-      aResult = aNS->Get();
-    }
-    break;
-  }
-  case SELTYPE_MODIFICATION: {
-    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;
-  }
-  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, 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
-  }
-  }
-
-  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;
@@ -1137,305 +75,63 @@ TopoDS_Shape Selector_Selector::value()
 }
 
 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 += ']';
-      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;
-  }
-  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 "";
+  return myAlgo->name(theNameGenerator);
 }
 
 TDF_Label Selector_Selector::restoreByName(
   std::string theName, const TopAbs_ShapeEnum theShapeType,
   Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming)
 {
-  myGeometricalNaming = theGeometricalNaming;
-  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;
-        }
-        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)));
-        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)) {
-          if (!theNameGenerator->isLater(aContext, aSubContext))
-            aContext = aSubContext;
-        } else {
-          aContext = aSubContext;
-        }
-      } else
-        return TDF_Label(); // invalid parentheses
-    }
-    return aContext;
-  } else if (theName[0] == '(') { // filter by neighbors
-    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)));
-        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)) {
-          if (!theNameGenerator->isLater(aContext, aSubContext))
-            aContext = aSubContext;
-        } 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 &&
-                        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) { // without '&' 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;
+  TDF_Label aResult;
+  myAlgo = Selector_Algo::restoreByName(
+    myLab, myBaseDocumentLab, theName, theShapeType, theNameGenerator, aResult);
+  if (myAlgo) {
+    return aResult;
   }
   return TDF_Label();
 }
 
-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 (!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());
+
+  Selector_Algo* aNewAlgo = Selector_Algo::relesectWithAllGeometry(myAlgo, theContext);
+  if (aNewAlgo) {
+    aNewAlgo->store();
+    aNewAlgo->solve(theContext);
+    delete myAlgo;
+    myAlgo = aNewAlgo;
+  } else {
+    // 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 (myAlgo->sameGeometry(aValue, anExp.Current()))
+          aList.Append(anExp.Current());
+      }
     }
-    if (select(theContext, aCompound, true)) {
-      store();
-      solve(theContext);
+    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());
+      }
+      Selector_Algo* aNewAlgo = Selector_Algo::relesectWithAllGeometry(myAlgo, theContext);
+      if (aNewAlgo) {
+        aNewAlgo->store();
+        aNewAlgo->solve(theContext);
+        delete myAlgo;
+        myAlgo = aNewAlgo;
+      }
     }
   }
 }
+
+bool Selector_Selector::solve(const TopoDS_Shape theContext)
+{
+  return myAlgo->solve(theContext);
+}
index 46f2db6e53a0effdda3fbbc4cbd86063b70cd035..d3e5b8a3b51f5a3ca6e7eb551da343bd7bb1348e 100644 (file)
 #include "Selector.h"
 
 #include <TDF_Label.hxx>
-#include <TDF_LabelList.hxx>
 #include <TopoDS_Shape.hxx>
-#include <list>
 
 class Selector_NameGenerator;
+class Selector_Algo;
 
 /**\class Selector_Selector
  * \ingroup DataModel
@@ -37,41 +36,16 @@ class Selector_NameGenerator;
  */
 class Selector_Selector
 {
-  /// Type of a selector: on this type depends what is stored in this label and how to
-  /// restore it on update.
-  enum Selector_Type {
-    SELTYPE_CONTAINER, ///< just a container of sub-elements, keeps the shape type of container
-    SELTYPE_INTERSECT, ///< sub-shape is intersection of higher level objects
-    SELTYPE_PRIMITIVE, ///< sub-shape found as a primitive on some label
-    SELTYPE_MODIFICATION, ///< modification of base shapes to the final label
-    SELTYPE_FILTER_BY_NEIGHBOR,  ///< identification by neighbor shapes in context
-    SELTYPE_WEAK_NAMING, ///< pure weak naming by weak index in context
-  };
-
-  Selector_Type myType; ///< Type of this selector.
-  TopAbs_ShapeEnum myShapeType; ///< type of this shape: in container, intersection or neighbors
-  std::list<Selector_Selector> mySubSelList; ///< list of sub-selectors if needed
-  TDF_Label myFinal; ///< final label of the primitive or generation, where the value is
-  TDF_LabelList myBases; ///< initial labels that contain shapes that produce the modification
-  int myWeakIndex; ///< index of the shape among commons for the modification type (-1 - not set)
-
-  std::list<int> myNBLevel; ///< list of integers corresponding to mySubSelList neighborhood level
-
   TDF_Label myLab; ///< main label where selector is performed
-
   TDF_Label myBaseDocumentLab; ///< an access-label to the document that may contain initial shapes
-
-  bool myGeometricalNaming; ///< flag that indicates that geometrical naming selection is enabled
-  bool myAlwaysGeometricalNaming; /// to enable geometrical naming from beginning, at select
+  Selector_Algo* myAlgo; ///< root algorithm of the selector
 
 public:
   /// Initializes selector on the label
-  SELECTOR_EXPORT Selector_Selector(TDF_Label theLab);
-  /// Returns label of this selector
-  SELECTOR_EXPORT TDF_Label label();
+  SELECTOR_EXPORT Selector_Selector(TDF_Label theLab, TDF_Label theBaseDocLab = TDF_Label());
 
-  /// Sets the base document access label.
-  SELECTOR_EXPORT void setBaseDocument(const TDF_Label theAccess);
+  /// Destructor
+  SELECTOR_EXPORT ~Selector_Selector();
 
   /// Initializes the selector structure on the label.
   /// Stores the name data to restore after modification.
@@ -81,15 +55,14 @@ public:
   /// \param theUseNeighbors enables searching algorithm by neighbors
   /// \param theUseIntersections enables searching algorithm by intersection of higher level shapes
   SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
-    const bool theGeometricalNaming = false,
-    const bool theUseNeighbors = true, const bool theUseIntersections = true);
+    const bool theGeometricalNaming = false);
 
   /// Stores the name to the label and sub-labels tree
-  SELECTOR_EXPORT void store();
+  SELECTOR_EXPORT bool store(const TopoDS_Shape theContext);
 
   /// Restores the selected shape by the topological naming kept in the data structure
   /// Returns true if it can restore structure correctly
-  SELECTOR_EXPORT bool restore();
+  SELECTOR_EXPORT bool restore(const TopoDS_Shape theContext);
 
   /// Restores the selected shape by the topological name string.
   /// Returns not empty label of the context.
@@ -97,9 +70,6 @@ public:
     std::string theName, const TopAbs_ShapeEnum theShapeType,
     Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming = false);
 
-  /// Updates the current shape by the stored topological name
-  SELECTOR_EXPORT bool solve(const TopoDS_Shape& theContext);
-
   /// Returns the current sub-shape value (null if can not resolve)
   SELECTOR_EXPORT TopoDS_Shape value();
 
@@ -109,15 +79,8 @@ public:
   /// Makes the current local selection becomes all sub-shapes with same base geometry.
   SELECTOR_EXPORT void combineGeometrical(const TopoDS_Shape theContext);
 
-private:
-
-  /// Create and keep in the list the sub-selector that select the given value.
-  /// Returns true if selection is correct.
-  bool selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
-    const bool theGeometricalNaming = false, const bool theUseNeighbors = true,
-    const bool theUseIntersections = true);
-  /// Searches the final shapes presented in all results from bases basing on modification fields
-  void findModificationResult(TopoDS_ListOfShape& theCommon);
+  /// Stores the selected shape in he tree and returns true if shape found correctly
+  SELECTOR_EXPORT bool solve(const TopoDS_Shape theContext);
 };
 
 #endif
diff --git a/src/Selector/Selector_WeakName.cpp b/src/Selector/Selector_WeakName.cpp
new file mode 100644 (file)
index 0000000..6ede1c3
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <Selector_WeakName.h>
+
+#include <Selector_NameGenerator.h>
+#include <Selector_NExplode.h>
+
+#include <TNaming_Tool.hxx>
+#include <TNaming_SameShapeIterator.hxx>
+#include <TNaming_Iterator.hxx>
+#include <TDataStd_Integer.hxx>
+
+Selector_WeakName::Selector_WeakName() : Selector_Algo()
+{
+}
+
+bool Selector_WeakName::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+{
+  myShapeType = theValue.ShapeType();
+  Selector_NExplode aNexp(theContext, myShapeType);
+  myWeakIndex = aNexp.index(theValue);
+  if (myWeakIndex != -1) {
+    // searching for context shape label to store in myFinal
+    if (TNaming_Tool::HasLabel(label(), theContext)) {
+      for(TNaming_SameShapeIterator aShapes(theContext, label()); 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)) {
+                myContext = aNS->Label();
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+void Selector_WeakName::store()
+{
+  static const TDF_LabelList anEmptyRefList;
+  storeType(Selector_Algo::SELTYPE_WEAK_NAMING);
+  storeBaseArray(anEmptyRefList, myContext);
+  TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
+  TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType);
+}
+
+bool Selector_WeakName::restore()
+{
+  Handle(TDataStd_Integer) aWeakInt;
+  if (!label().FindAttribute(weakID(), aWeakInt))
+    return false;
+  myWeakIndex = aWeakInt->Get();
+  Handle(TDataStd_Integer) aShapeTypeAttr;
+  if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr))
+    return false;
+  myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
+  static TDF_LabelList anEmptyRefList;
+  return restoreBaseArray(anEmptyRefList, myContext);
+}
+
+TDF_Label Selector_WeakName::restoreByName(std::string theName,
+  const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
+{
+  std::string aWeakIndex = theName.substr(pureWeakNameID().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);
+    if (theNameGenerator->restoreContext(aContextName, aContext, myContext)) {
+      if (myContext.IsNull())
+        aContext.Nullify();
+    }
+  }
+  return aContext;
+}
+
+bool Selector_WeakName::solve(const TopoDS_Shape& theContext)
+{
+
+  TopoDS_Shape aContext;
+  if (myContext.IsNull()) {
+    aContext = theContext;
+  } else {
+    Handle(TNaming_NamedShape) aNS;
+    if (myContext.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+      aContext = aNS->Get();
+    }
+  }
+  if (!aContext.IsNull()) {
+    Selector_NExplode aNexp(aContext, myShapeType);
+    TopoDS_Shape aResult = aNexp.shape(myWeakIndex);
+    if (!aResult.IsNull()) {
+      Selector_Algo::store(aResult);
+      return true;
+    }
+  }
+  return false;
+}
+
+std::string Selector_WeakName::name(Selector_NameGenerator* theNameGenerator)
+{
+  // _weak_naming_1_Context
+  std::ostringstream aWeakStr;
+  aWeakStr<<pureWeakNameID()<<myWeakIndex;
+  std::string aResult = aWeakStr.str();
+  if (!myContext.IsNull())
+    aResult += "_" + theNameGenerator->contextName(myContext);
+  return aResult;
+}
diff --git a/src/Selector/Selector_WeakName.h b/src/Selector/Selector_WeakName.h
new file mode 100644 (file)
index 0000000..7f1016a
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef Selector_WeakName_H_
+#define Selector_WeakName_H_
+
+#include "Selector_Algo.h"
+
+/**\class Selector_WeakName
+ * \ingroup DataModel
+ * \brief Kind of selection algorithm: if other algorithms fail, this stores the geometrical
+ * index of the selected shape. Pure weak naming approach.
+ */
+class Selector_WeakName: public Selector_Algo
+{
+  TopAbs_ShapeEnum myShapeType; ///< type of this shape
+  int myWeakIndex; ///< weak index in case modification produces several shapes
+  TDF_Label myContext; ///< context shape label
+public:
+  /// Initializes the selection of this kind
+  SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue);
+
+  /// Stores the name to the label and sub-labels tree
+  SELECTOR_EXPORT virtual void store() override;
+
+  /// Restores the selected shape by the topological naming kept in the data structure
+  /// Returns true if it can restore structure correctly
+  SELECTOR_EXPORT virtual bool restore() override;
+
+  /// Restores the selected shape by the topological name string.
+  /// Returns not empty label of the context.
+  SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName,
+    const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override;
+
+  /// Updates the current shape by the stored topological name
+  SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override;
+
+  /// Returns the naming name of the selection
+  SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override;
+private:
+  /// Initializes selector
+  Selector_WeakName();
+
+  friend class Selector_Algo;
+};
+
+#endif
index 252ecf18118b57f82eda9f600e73a45ba5b1639c..d2f727f7163af635bfa357999f9fcf135413e668 100644 (file)
@@ -67,7 +67,7 @@ bool SketchPlugin_Point::isFixed() {
 }
 
 void SketchPlugin_Point::attributeChanged(const std::string& theID) {
-  // the second condition for unability to move external point anywhere
+  // the second condition for inability to move external point anywhere
   if (theID == EXTERNAL_ID() || isFixed()) {
     std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
     if (!aSelection) {