Salome HOME
Merge remote-tracking branch 'remotes/origin/EDF_2020_Lot2'
[modules/shaper.git] / src / Selector / Selector_FilterByNeighbors.cpp
index 2d5488e159d392b6c77b9d617b777eee7a46119a..49992956baf17b69272e20cdb32a5b6e949e68c5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2020  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
 //
 // 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
+// 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>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include <Selector_FilterByNeighbors.h>
@@ -42,19 +41,32 @@ static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theV
   const int theLevel, TopTools_MapOfShape& theResult)
 {
   TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
-  if (theValue.ShapeType() == TopAbs_FACE)
+  TopAbs_ShapeEnum aValueType = theValue.ShapeType();
+  if (aValueType == TopAbs_FACE)
     aConnectorType = TopAbs_EDGE;
+  else if (aValueType == TopAbs_COMPOUND) { // for geometrical naming: compound of faces
+    TopExp_Explorer anExp(theValue, TopAbs_FACE);
+    if (anExp.More()) {
+      aConnectorType = TopAbs_EDGE;
+      aValueType = TopAbs_FACE;
+    } else {
+      aValueType = TopAbs_EDGE;
+    }
+  }
   TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
-  for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
+  for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next())
     aNBConnectors.Add(aValExp.Current());
-  }
 
   TopTools_MapOfShape alreadyProcessed;
-  alreadyProcessed.Add(theValue);
+  if (aValueType == theValue.ShapeType())
+    alreadyProcessed.Add(theValue);
+  else
+    for(TopExp_Explorer aValExp(theValue, aValueType); aValExp.More(); aValExp.Next())
+      alreadyProcessed.Add(aValExp.Current());
 
   for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
     TopoDS_ListOfShape aGoodCandidates;
-    TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
+    TopExp_Explorer aCandidate(theContext, aValueType);
     for(; aCandidate.More(); aCandidate.Next()) {
       if (alreadyProcessed.Contains(aCandidate.Current()))
         continue;
@@ -102,18 +114,16 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
     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) {
+      if (aFirst) { // aMatches must contain common part of all NBs lists
+        for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
           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);
-            }
+        }
+      } 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);
           }
         }
       }
@@ -155,6 +165,7 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
           } else
             return TopoDS_Shape();
         }
+        break; // no more NBs with higher levels
       }
       if (!aLevelNBs.IsEmpty()) {
         TopTools_MapOfShape aNBsOfCandidate;
@@ -176,12 +187,16 @@ static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
   return aGoodCandidate;
 }
 
-bool Selector_FilterByNeighbors::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
+bool Selector_FilterByNeighbors::select(
+  const TDF_Label theContextLab, const TopoDS_Shape theContext, const TopoDS_Shape theValue)
 {
   myShapeType = theValue.ShapeType();
+  myContext = theContextLab;
   // searching by neighbors
   std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
-  for(int aLevel = 1; true; aLevel++) {
+  // # 19071 : moving through all levels may be too long, in practice there are no more than 2 or 3
+  // levels real cases, so, make it "5" as maximum possible
+  for(int aLevel = 1; aLevel < 5; aLevel++) {
     TopTools_MapOfShape aNewNB;
     findNeighbors(theContext, theValue, aLevel, aNewNB);
     if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
@@ -237,6 +252,11 @@ void Selector_FilterByNeighbors::store()
   for(; aSubSel != list().cend(); aSubSel++) {
     (*aSubSel)->store();
   }
+  // store context reference if exists
+  if (!myContext.IsNull()) {
+    static const TDF_LabelList anEmptyRefList;
+    storeBaseArray(anEmptyRefList, myContext);
+  }
 }
 
 bool Selector_FilterByNeighbors::restore()
@@ -253,7 +273,6 @@ bool Selector_FilterByNeighbors::restore()
     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(), baseDocument());
     if (!append(aSubSel, false)) {
@@ -262,30 +281,35 @@ bool Selector_FilterByNeighbors::restore()
       // some selector fails, try to use rest selectors, myNBLevel becomes negative: unused
       if (myNBLevel.size() > list().size()) {
         std::list<int>::iterator aListIter = myNBLevel.begin();
-        for(int a = 0; a < list().size(); a++)
+        for(size_t a = 0; a < list().size(); a++)
           aListIter++;
         *aListIter = -*aListIter;
         list().push_back(NULL);
       }
     }
   }
+  // restore context reference if exists
+  static TDF_LabelList anEmptyRefList;
+  restoreBaseArray(anEmptyRefList, myContext);
+
   return myNBLevel.size() == list().size() && !myNBLevel.empty();
 }
 
-TDF_Label Selector_FilterByNeighbors::restoreByName(std::string theName,
+TDF_Label Selector_FilterByNeighbors::restoreByName(std::wstring 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);
+  std::wstring aLastLevel; // last level string (after '(' )  to check the context name in the end
+  for (size_t aStart = 0; aStart != std::wstring::npos;
+       aStart = theName.find(L'(', aStart + 1)) {
+    size_t anEndPos = theName.find(L')', aStart + 1);
+    if (anEndPos != std::wstring::npos) {
+      std::wstring aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
       TDF_Label aSubContext;
       Selector_Algo* aSubSel =
-        Selector_Algo::restoreByName(
-          newSubLabel(), baseDocument(), aSubStr, myShapeType, theNameGenerator, aSubContext);
+        Selector_Algo::restoreByName(newSubLabel(), baseDocument(), aSubStr, myShapeType,
+          geometricalNaming(), theNameGenerator, aSubContext);
       if (!append(aSubSel))
         return TDF_Label();
 
@@ -300,20 +324,21 @@ TDF_Label Selector_FilterByNeighbors::restoreByName(std::string theName,
       } else {
         aContext = aSubContext;
       }
-      if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
-        aContext = theNameGenerator->newestContext(aContext);
+      //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;
+      std::wstring aLevel;
+      for (anEndPos++; anEndPos != std::wstring::npos &&
+        theName[anEndPos] != L'(' && theName[anEndPos] != 0;
         anEndPos++) {
         aLevel += theName[anEndPos];
       }
-      if (aLevel.empty())
+      aLastLevel = aLevel;
+      if (aLevel.empty() || aLevel[0] == L'_')
         myNBLevel.push_back(1); // by default it is 1
       else {
-        int aNum = atoi(aLevel.c_str());
+        int aNum = std::stoi(aLevel.c_str());
         if (aNum > 0)
           myNBLevel.push_back(aNum);
         else
@@ -322,6 +347,20 @@ TDF_Label Selector_FilterByNeighbors::restoreByName(std::string theName,
     } else
       return TDF_Label(); // invalid parentheses
   }
+  if (!aLastLevel.empty()) { // get the context
+    size_t aLinePos = aLastLevel.find(L"_");
+    if (aLinePos != std::wstring::npos) {
+      std::wstring aContextName = aLastLevel.substr(aLinePos + 1);
+      if (!aContextName.empty()) {
+        TDF_Label aThisContext, aValue;
+        if (theNameGenerator->restoreContext(aContextName, aThisContext, aValue)) {
+          if (!aThisContext.IsNull())
+            aContext = aThisContext;
+        }
+      }
+    }
+  }
+  myContext = aContext;
   return aContext;
 }
 
@@ -349,21 +388,33 @@ bool Selector_FilterByNeighbors::solve(const TopoDS_Shape& theContext)
   return false;
 }
 
-std::string Selector_FilterByNeighbors::name(Selector_NameGenerator* theNameGenerator)
+std::wstring 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;
+  bool aThisContextNameNeeded = !myContext.IsNull();
+  std::wstring aContextName;
+  if (aThisContextNameNeeded)
+    aContextName = theNameGenerator->contextName(myContext);
+  std::wstring aResult;
   std::list<int>::iterator aLevel = myNBLevel.begin();
   std::list<Selector_Algo*>::const_iterator aSubSel = list().cbegin();
   for(; aSubSel != list().cend(); aSubSel++, aLevel++) {
     if (!*aSubSel)
       continue;
-    aResult += "(" + (*aSubSel)->name(theNameGenerator) + ")";
+    std::wstring aSubName = (*aSubSel)->name(theNameGenerator);
+    aResult += L"(" + aSubName + L")";
     if (*aLevel > 1) {
-      std::ostringstream aLevelStr;
+      std::wostringstream aLevelStr;
       aLevelStr<<*aLevel;
       aResult += aLevelStr.str();
     }
+    // sub-name already contains the needed context name, so, here it is not needed
+    if (aThisContextNameNeeded && (
+         aSubName.find(aContextName) == 0 || aSubName.substr(1).find(aContextName) == 0))
+      aThisContextNameNeeded = false;
+  }
+  if (aThisContextNameNeeded) {
+    aResult = aResult + L"_" + aContextName;
   }
   return aResult;
 }