Salome HOME
Fix for the issue #1647 : problem with OB when sub-features are created.
[modules/shaper.git] / src / Model / Model_SelectionNaming.cpp
index 5c5c6132b958b1b4da468cd2d0c010115f6e1080..5bf2d58c9f71c9e010ad0bb56de1f4f5e05bd124 100644 (file)
@@ -6,8 +6,14 @@
 
 #include "Model_SelectionNaming.h"
 #include "Model_Document.h"
+#include "Model_Objects.h"
 #include <ModelAPI_Feature.h>
 #include <Events_InfoMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_ResultPart.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_ResultBody.h>
 
 #include <TopoDS_Iterator.hxx>
 #include <TopoDS.hxx>
 #include <TNaming_NamedShape.hxx>
 #include <TNaming_Localizer.hxx>
 #include <TDataStd_Name.hxx>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_CompositeFeature.h>
 #include <TColStd_MapOfTransient.hxx>
 #include <algorithm>
+#include <stdexcept>
 
 #ifdef DEB_NAMING
 #include <BRepTools.hxx>
 #endif
 
-/// added to the index in the packed map to signalize that the vertex of edge is selected
-/// (multiplied by the index of the edge)
-static const int kSTART_VERTEX_DELTA = 1000000;
-
 Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab)
 {
   myLab = theSelectionLab;
 }
 
-
 std::string Model_SelectionNaming::getShapeName(
-  std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape)
+  std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape,
+  const bool theAddContextName)
 {
   std::string aName;
   // check if the subShape is already in DF
@@ -55,15 +56,9 @@ std::string Model_SelectionNaming::getShapeName(
   if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document    
     if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
       aName = TCollection_AsciiString(anAttr->Get()).ToCString();
-      if(!aName.empty()) {         
-        const TDF_Label& aLabel = theDoc->findNamingName(aName);
-        /* MPV: the same shape with the same name may be duplicated on different labels (selection of the same construction object)
-        if(!aLabel.IsEqual(aNS->Label())) {
-        //aName.erase(); //something is wrong, to be checked!!!
-        aName += "_SomethingWrong";
-        return aName;
-        }*/
-
+      // indexes are added to sub-shapes not primitives (primitives must not be located at the same label)
+      if(!aName.empty() && aNS->Evolution() != TNaming_PRIMITIVE && theAddContextName) {
+        const TDF_Label& aLabel = aNS->Label();//theDoc->findNamingName(aName);
         static const std::string aPostFix("_");
         TNaming_Iterator anItL(aNS);
         for(int i = 1; anItL.More(); anItL.Next(), i++) {
@@ -73,14 +68,23 @@ std::string Model_SelectionNaming::getShapeName(
             break;
           }
         }
-      }        
+      }
+      if (theAddContextName && aName.find("/") == std::string::npos) { // searching for the context object
+        for(TDF_Label anObjL = aNS->Label(); anObjL.Depth() > 4; anObjL = anObjL.Father()) {
+          int aDepth = anObjL.Depth();
+          if (aDepth == 5 || aDepth == 7) {
+            ObjectPtr anObj = theDoc->objects()->object(anObjL);
+            if (anObj) {
+              aName = anObj->data()->name() + "/" + aName;
+            }
+          }
+        }
+      }
     }
   }
   return aName;
 }
 
-
-
 bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap)
 {
   // a trivial case: F1 & F2,  aNumber = 1, i.e. intersection gives 1 edge.
@@ -123,9 +127,17 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
 #endif
   std::shared_ptr<Model_Document> aDoc = 
     std::dynamic_pointer_cast<Model_Document>(theContext->document());
+  if (theContext->groupName() == ModelAPI_ResultPart::group()) {
+    ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(theContext);
+    int anIndex;
+    return aPart->data()->name() + "/" + aPart->nameInPart(theSubSh, anIndex);
+  }
+
+  // add the result name to the name of the shape (it was in BodyBuilder, but did not work on Result rename)
+  bool isNeedContextName = theContext->shape().get() && !theContext->shape()->isEqual(theSubSh);
 
   // check if the subShape is already in DF
-  aName = getShapeName(aDoc, aSubShape);
+  aName = getShapeName(aDoc, aSubShape, isNeedContextName);
   if(aName.empty() ) { // not in the document!
     TopAbs_ShapeEnum aType = aSubShape.ShapeType();
     switch (aType) {
@@ -172,7 +184,7 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
         // build name of the sub-shape Edge
         for(int i=1; i <= aSMap.Extent(); i++) {
           const TopoDS_Shape& aFace = aSMap.FindKey(i);
-          std::string aFaceName = getShapeName(aDoc, aFace);
+          std::string aFaceName = getShapeName(aDoc, aFace, isNeedContextName);
           if(i == 1)
             aName = aFaceName;
           else 
@@ -180,7 +192,7 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
         }
         TopTools_ListIteratorOfListOfShape itl(aListOfNbs);
         for (;itl.More();itl.Next()) {
-          std::string aFaceName = getShapeName(aDoc, itl.Value());
+          std::string aFaceName = getShapeName(aDoc, itl.Value(), isNeedContextName);
           aName += "&" + aFaceName;
         }                
       }
@@ -229,7 +241,7 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
             TopTools_ListIteratorOfListOfShape itl(aListE);
             for (int i = 1;itl.More();itl.Next(),i++) {
               const TopoDS_Shape& anEdge = itl.Value();
-              std::string anEdgeName = getShapeName(aDoc, anEdge);
+              std::string anEdgeName = getShapeName(aDoc, anEdge, isNeedContextName);
               if (anEdgeName.empty()) { // edge is not in DS, trying by faces anyway
                 isByFaces = true;
                 aName.clear();
@@ -249,7 +261,7 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
           TopTools_ListIteratorOfListOfShape itl(aList);
           for (int i = 1;itl.More();itl.Next(),i++) {
             const TopoDS_Shape& aFace = itl.Value();
-            std::string aFaceName = getShapeName(aDoc, aFace);
+            std::string aFaceName = getShapeName(aDoc, aFace, isNeedContextName);
             if(i == 1)
               aName = aFaceName;
             else 
@@ -259,10 +271,8 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
       }
       break;
     }
-    // register name                   
-    // aDoc->addNamingName(selectionLabel(), aName);
-    // the selected sub-shape will not be shared and as result it will not require registration
   }
+
   return aName;
 }
 
@@ -319,9 +329,13 @@ const TopoDS_Shape getShapeFromNS(
   if (n == std::string::npos) n = 0;
   std::string aSubString = theSubShapeName.substr(n + 1);
   n = aSubString.rfind('_');
-  if (n == std::string::npos) return aSelection;
-  aSubString = aSubString.substr(n+1);
-  int indx = atoi(aSubString.c_str());
+  int indx;
+  if (n == std::string::npos) {// for primitives this is a first 
+    indx = 1;
+  } else {
+    aSubString = aSubString.substr(n+1);
+    indx = atoi(aSubString.c_str());
+  }
 
   TNaming_Iterator anItL(theNS);
   for(int i = 1; anItL.More(); anItL.Next(), i++) {
@@ -336,18 +350,19 @@ const TopoDS_Shape findFaceByName(
   const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc)
 {
   TopoDS_Shape aFace;
-  std::string::size_type n, nb = theSubShapeName.rfind('/');                   
-  if (nb == std::string::npos) nb = 0;
-  std::string aSubString = theSubShapeName.substr(nb + 1);
-  n = aSubString.rfind('_');
-  if (n != std::string::npos) {
-    std::string aSubStr2 = aSubString.substr(0, n);
-    aSubString  = theSubShapeName.substr(0, nb + 1);
-    aSubString = aSubString + aSubStr2;        
-  } else
-    aSubString = theSubShapeName;
-
-  const TDF_Label& aLabel = theDoc->findNamingName(aSubString);
+  //std::string::size_type n, nb = theSubShapeName.rfind('/');                 
+  //if (nb == std::string::npos) nb = 0;
+  //std::string aSubString = theSubShapeName.substr(nb + 1);
+  std::string aSubString = theSubShapeName;
+
+  TDF_Label aLabel = theDoc->findNamingName(aSubString);
+  if (aLabel.IsNull()) { // try to remove additional artificial suffix
+    std::string::size_type n = aSubString.rfind('_');
+    if (n != std::string::npos) {
+      aSubString = aSubString.substr(0, n);
+       aLabel = theDoc->findNamingName(aSubString);
+    }
+  }
   if(aLabel.IsNull()) return aFace;
   Handle(TNaming_NamedShape) aNS;
   if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
@@ -499,17 +514,18 @@ bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names
     } else {
       int anOrientation = 1; // default
       if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r'
-        const char aSymbol = anID.back();
-        if (aSymbol == 'r') anOrientation = -1;
-        anID.pop_back();
+        std::string::iterator aSymbol = anID.end() - 1;
+        if (*aSymbol == 'r') anOrientation = -1;
+        anID.erase(aSymbol); // remove last symbol
       }
       // check start/end symbols
-      if (anID.back() == 's') {
+      std::string::iterator aBack = anID.end() - 1;
+      if (*aBack == 's') {
         anOrientation *= 2;
-        anID.pop_back();
-      } else if (anID.back() == 'e') {
+        anID.erase(aBack); // remove last symbol
+      } else if (*aBack == 'e') {
         anOrientation *= 3;
-        anID.pop_back();
+        anID.erase(aBack); // remove last symbol
       }
 
       if (aNames.find(anID) != aNames.end()) {
@@ -524,9 +540,8 @@ bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names
 /// produces theEdge orientation relatively to theContext face
 int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge)
 {
-  if (theContext.ShapeType() != TopAbs_FACE)
+  if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE)
     return 0;
-  TopoDS_Face aContext = TopoDS::Face(theContext);
   if (theEdge.Orientation() == TopAbs_FORWARD) 
     return 1;
   if (theEdge.Orientation() == TopAbs_REVERSED) 
@@ -593,9 +608,12 @@ std::string Model_SelectionNaming::shortName(
   aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
   // remove the last 's', 'e', 'f' and 'r' symbols: they are used as markers of start/end/forward/rewersed indicators
   static const std::string aSyms("sefr");
-  while(aSyms.find(aName.back()) != std::string::npos) {
-    aName.pop_back();
+  std::string::iterator aSuffix = aName.end() - 1;
+  while(aSyms.find(*aSuffix) != std::string::npos) {
+    --aSuffix;
   }
+  aName.erase(aSuffix + 1, aName.end());
+
   if (theEdgeVertexPos == 1) {
     aName += "s"; // start
   } else if (theEdgeVertexPos == 2) {
@@ -611,25 +629,53 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
 {
   if(theSubShapeName.empty() || theType.empty()) return false;
   TopAbs_ShapeEnum aType = translateType(theType);
-  std::string aContName = getContextName(theSubShapeName);
+
+  // check that it was selected in another document
+  size_t aSlash = theSubShapeName.find("/");
+  std::string aSubShapeName = theSubShapeName;
+  std::shared_ptr<Model_Document> aDoc = theDoc;
+  if (aSlash != std::string::npos) {
+    std::string aDocName = theSubShapeName.substr(0, aSlash);
+    DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
+    if (aDocName == aRootDoc->kind()) {
+      aDoc = std::dynamic_pointer_cast<Model_Document>(aRootDoc);
+    } else {
+      for (int a = aRootDoc->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) {
+        ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(
+            aRootDoc->object(ModelAPI_ResultPart::group(), a));
+        if (aPart.get() && aPart->isActivated() && aPart->data()->name() == aDocName) {
+          aDoc = std::dynamic_pointer_cast<Model_Document>(aPart->partDoc());
+        }
+      }
+    }
+    if (aDoc != theDoc) { // so, the first word is the document name => reduce the string for the next manips
+      aSubShapeName = theSubShapeName.substr(aSlash + 1);
+    }
+  }
+
+  std::string aContName = getContextName(aSubShapeName);
   if(aContName.empty()) return false;
-  ResultPtr aCont = theDoc->findByName(aContName);
+  ResultPtr aCont = aDoc->findByName(aContName);
    // possible this is body where postfix is added to distinguish several shapes on the same label
   int aSubShapeId = -1; // -1 means sub shape not found
-  if (!aCont.get() && aContName == theSubShapeName) {
+  // for result body the name wihtout "_" has higher priority than with it: it is always added
+  if ((!aCont.get()/* || (aCont->groupName() == ModelAPI_ResultBody::group())*/) && 
+       aContName == aSubShapeName) {
     size_t aPostIndex = aContName.rfind('_');
     if (aPostIndex != std::string::npos) {
       std::string aSubContName = aContName.substr(0, aPostIndex);
-      aCont = theDoc->findByName(aSubContName);
-      if (aCont.get()) {
+      ResultPtr aSubCont = aDoc->findByName(aSubContName);
+      if (aSubCont.get()) {
         try {
           std::string aNum = aContName.substr(aPostIndex + 1);
           aSubShapeId = std::stoi(aNum);
         } catch (std::invalid_argument&) {
           aSubShapeId = -1;
         }
-        if (aSubShapeId > 0)
+        if (aSubShapeId > 0) {
           aContName = aSubContName;
+          aCont = aSubCont;
+        }
       }
     }
   }
@@ -639,28 +685,29 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
   switch (aType) 
   {
   case TopAbs_FACE:
+  case TopAbs_WIRE:
     {
-      aSelection = findFaceByName(theSubShapeName, theDoc);
+      aSelection = findFaceByName(aSubShapeName, aDoc);
     }
     break;
   case TopAbs_EDGE:
     {  
-      const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
+      const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName);
       if(!aLabel.IsNull()) {
         Handle(TNaming_NamedShape) aNS;
         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
-          aSelection = getShapeFromNS(theSubShapeName, aNS);
+          aSelection = getShapeFromNS(aSubShapeName, aNS);
         }
       }
     }
     break;
   case TopAbs_VERTEX:
     {
-      const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
+      const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName);
       if(!aLabel.IsNull()) {
         Handle(TNaming_NamedShape) aNS;
         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
-          aSelection = getShapeFromNS(theSubShapeName, aNS);
+          aSelection = getShapeFromNS(aSubShapeName, aNS);
         }
       }
     }
@@ -669,7 +716,6 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
   case TopAbs_COMPSOLID:
   case TopAbs_SOLID:
   case TopAbs_SHELL:
-  case TopAbs_WIRE:
   default: {//TopAbs_SHAPE
     /// case when the whole sketch is selected, so, selection type is compound, but there is no value
     if (aCont.get() && aCont->shape().get()) {
@@ -678,7 +724,7 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
         return true;
       } else if (aSubShapeId > 0) { // try to find sub-shape by the index
         TopExp_Explorer anExp(aCont->shape()->impl<TopoDS_Shape>(), aType);
-        for(; aSubShapeId > 0 && anExp.More(); aSubShapeId--) {
+        for(; aSubShapeId > 1 && anExp.More(); aSubShapeId--) {
           anExp.Next();
         }
         if (anExp.More()) {
@@ -695,13 +741,13 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
   }
   // another try to find edge or vertex by faces
   std::list<std::string> aListofNames;
-  size_t aN = aSelection.IsNull() ? ParseName(theSubShapeName, aListofNames) : 0;
+  size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0;
   if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) {
     if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE
       TopTools_ListOfShape aList;
       std::list<std::string>::iterator it = aListofNames.begin();
       for(; it != aListofNames.end(); it++){
-        const TopoDS_Shape aFace = findFaceByName(*it, theDoc);
+        const TopoDS_Shape aFace = findFaceByName(*it, aDoc);
         if(!aFace.IsNull())
           aList.Append(aFace);         
       }
@@ -718,25 +764,25 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
   // in case of construction, there is no registered names for all sub-elements,
   // even for the main element; so, trying to find them by name (without "&" intersections)
   if (aN == 0) {
-    size_t aConstrNamePos = theSubShapeName.find("/");
+    size_t aConstrNamePos = aSubShapeName.find("/");
     bool isFullName = aConstrNamePos == std::string::npos;
     std::string aContrName = aContName;
-    //  isFullName ? theSubShapeName : theSubShapeName.substr(0, aConstrNamePos);
-    ResultPtr aConstr = theDoc->findByName(aContrName);
+    ResultPtr aConstr = aDoc->findByName(aContrName);
     if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) {
       theCont = aConstr;
       if (isFullName) {
-        theShapeToBeSelected = aConstr->shape();
+        // For the full construction selection shape must be empty.
+        //theShapeToBeSelected = aConstr->shape();
         return true;
       }
       // for sketch sub-elements selected
       CompositeFeaturePtr aComposite = 
-        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theDoc->feature(aConstr));
+        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aDoc->feature(aConstr));
       if (aComposite.get()) {
         if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
           // collect all IDs in the name
           std::map<int, int> anIDs;
-          if (!parseSubIndices(aComposite, theSubShapeName, 
+          if (!parseSubIndices(aComposite, aSubShapeName, 
               aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs))
             return false;
 
@@ -775,9 +821,52 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType,
               }
             }
           }
-        } else if (aType == TopAbs_FACE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
+          // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
+        } else if (aType == TopAbs_FACE || aType == TopAbs_WIRE) {
+          std::map<int, int> anIDs;
+          if (!parseSubIndices(aComposite, aSubShapeName, 
+              aType == TopAbs_FACE ? "Face" : "Wire", anIDs, true))
+            return false;
+
+          NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
+          const int aSubNum = aComposite->numberOfSubs();
+          for(int a = 0; a < aSubNum; a++) {
+            int aSubID = aComposite->subFeatureId(a);
+            if (anIDs.find(aSubID) != anIDs.end()) {
+              FeaturePtr aSub = aComposite->subFeature(a);
+              const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
+              std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
+              for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
+                ResultConstructionPtr aConstr = 
+                  std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
+                if (aConstr->shape() && aConstr->shape()->isEdge()) {
+                  const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
+                  TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
+                  if (!anEdge.IsNull()) {
+                    Standard_Real aFirst, aLast;
+                    Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+                    allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
+                  }
+                }
+              }
+            }
+          }
+          std::shared_ptr<GeomAPI_Shape> aFoundFace = findAppropriateFace(aConstr, allCurves);
+          if (aFoundFace.get()) {
+            if (aType == TopAbs_WIRE) { // just get a wire from face to have wire
+              TopExp_Explorer aWireExp(aFoundFace->impl<TopoDS_Shape>(), TopAbs_WIRE);
+              if (aWireExp.More()) {
+                theShapeToBeSelected.reset(new GeomAPI_Shape);
+                theShapeToBeSelected->setImpl<TopoDS_Shape>(new TopoDS_Shape(aWireExp.Current()));
+              } else return false;
+            } else {
+              theShapeToBeSelected = aFoundFace;
+            }
+            return true;
+          }
+        } else if (aType == TopAbs_WIRE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
           std::map<int, int> anIDs;
-          if (!parseSubIndices(aComposite, theSubShapeName, "Face", anIDs, true))
+          if (!parseSubIndices(aComposite, aSubShapeName, "Wire", anIDs))
             return false;
 
           NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges