Salome HOME
Copyright update 2022
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
index 88912aaca7d089761b674a01e9704a513f9a4c57..59c47cca2996cf49f55e8463308dcfc657820beb 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2022  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
@@ -46,6 +46,8 @@
 #include <GeomAlgoAPI_NExplode.h>
 #include <Selector_Selector.h>
 
+#include <Locale_Convert.h>
+
 #include <TNaming_NamedShape.hxx>
 #include <TNaming_Tool.hxx>
 #include <TNaming_Builder.hxx>
@@ -146,8 +148,6 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext,
       isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape)) == Standard_True;
   }
   if (!theContext.get() || isDegeneratedEdge) {
-    // to keep the reference attribute label
-    TDF_Label aRefLab = myRef.myRef->Label();
     aSelLab.ForgetAllAttributes(true);
     myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father());
     if (aToUnblock)
@@ -232,6 +232,8 @@ void Model_AttributeSelection::setValueCenter(
         anUpdated = !aSelLab.IsAttribute(kELLIPSE_CENTER2);
       TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER2);
       break;
+    default: // [to avoid compilation warning]
+      break;
     }
     if (anUpdated)
       owner()->data()->sendAttributeUpdated(this);
@@ -362,13 +364,13 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::internalValue(CenterTyp
         } else { // face with name is already in the data model, so try to take it by name
           Handle(TDataStd_Name) aName;
           if (aSelLab.FindAttribute(TDataStd_Name::GetID(), aName)) {
-            std::string aSubShapeName(TCollection_AsciiString(aName->Get()).ToCString());
-            std::size_t aPartEnd = aSubShapeName.find('/');
-            if (aPartEnd != std::string::npos && aPartEnd != aSubShapeName.rfind('/')) {
-              std::string aNameInPart = aSubShapeName.substr(aPartEnd + 1);
-              int anIndex;
+            std::wstring aSubShapeName = Locale::Convert::toWString(aName->Get().ToExtString());
+            std::size_t aPartEnd = aSubShapeName.find(L'/');
+            if (aPartEnd != std::wstring::npos && aPartEnd != aSubShapeName.rfind(L'/')) {
+              std::wstring aNameInPart = aSubShapeName.substr(aPartEnd + 1);
+              int anInd;
               std::string aType; // to reuse already existing selection the type is not needed
-              return aPart->shapeInPart(ModelAPI_Tools::toWString(aNameInPart), aType, anIndex);
+              return aPart->shapeInPart(aNameInPart, aType, anInd);
             }
           }
         }
@@ -452,10 +454,11 @@ bool Model_AttributeSelection::isInitialized()
 
 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
 : myRef(theLabel),
+  myTmpCenterType(NOT_CENTER),
+  myParent(NULL),
   myIsGeometricalSelection(false)
 {
   myIsInitialized = myRef.isInitialized();
-  myParent = NULL;
 }
 
 void Model_AttributeSelection::setID(const std::string theID)
@@ -557,7 +560,7 @@ void Model_AttributeSelection::split(
     aSubSh->setImpl(new TopoDS_Shape(aSub.Value()));
     setValue(theContext, aSubSh);
     for(aSub.Next(); aSub.More(); aSub.Next()) {
-      GeomShapePtr aSubSh(new GeomAPI_Shape);
+      aSubSh.reset(new GeomAPI_Shape);
       aSubSh->setImpl(new TopoDS_Shape(aSub.Value()));
       myParent->append(theContext, aSubSh);
     }
@@ -602,11 +605,37 @@ bool Model_AttributeSelection::update()
     aResult = aSelector.restore(aContextShape);
     bool aWasInvalid = aSelLab.IsAttribute(kINVALID_SELECTION);
     setInvalidIfFalse(aSelLab, aResult);
+    if (!aResult)
+      aWasInvalid = false;
 
     TopoDS_Shape aNewShape;
     if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
       aNewShape = aNS->Get();
 
+    // check the selected value is a part of the context
+    if (aResult && !aNewShape.IsNull() && !aContextShape.IsNull() &&
+        !aContextShape.IsSame(aNewShape)) {
+      TopoDS_Shape aNewS = aNewShape;
+      // take only sub-shape of composite for checking
+      if (aNewS.ShapeType() == TopAbs_WIRE || aNewS.ShapeType() == TopAbs_SHELL ||
+        aNewS.ShapeType() == TopAbs_COMPOUND || aNewS.ShapeType() == TopAbs_COMPSOLID) {
+        TopoDS_Iterator anIter(aNewS);
+        if (anIter.More())
+          aNewS = anIter.Value();
+      }
+      bool anIsInside = false;
+      TopExp_Explorer anExp(aContextShape, aNewS.ShapeType());
+      for (; anExp.More() && !anIsInside; anExp.Next()) {
+        if (anExp.Current().IsSame(aNewS))
+          anIsInside = true;
+      }
+      if (!anIsInside) {
+        aResult = false;
+        aNewShape.Nullify();
+        setInvalidIfFalse(aSelLab, aResult);
+      }
+    }
+
     if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape) || aWasInvalid)
     {
       // shape type should not be changed: if shape becomes compound of such shapes, then split
@@ -761,16 +790,16 @@ std::wstring Model_AttributeSelection::namingName(const std::wstring& theDefault
     GeomShapePtr aShape = value();
     if (!aShape.get() && context().get())
       aShape = context()->shape();
-    std::wstring aName;
+    std::wstring aNotArgName;
     if (aShape.get()) {
-      aName = ModelAPI_Tools::toWString(aShape->shapeTypeStr());
+      aNotArgName = Locale::Convert::toWString(aShape->shapeTypeStr());
       if (myParent) {
         std::wostringstream aStream;
         aStream << "_" << selectionLabel().Father().Tag();
-        aName += aStream.str();
+        aNotArgName += aStream.str();
       }
     }
-    return aName;
+    return aNotArgName;
   }
 
   CenterType aCenterType = NOT_CENTER;
@@ -781,7 +810,7 @@ std::wstring Model_AttributeSelection::namingName(const std::wstring& theDefault
     std::wstring aResName;
     // checking part-owner
     if (aContFeature->document() != owner()->document())
-        aResName += ModelAPI_Tools::toWString(aContFeature->document()->kind()) + L"/";
+        aResName += Locale::Convert::toWString(aContFeature->document()->kind()) + L"/";
     // selection of a full feature
     if (aContFeature.get()) {
       return aResName + kWHOLE_FEATURE + aContFeature->name();
@@ -836,7 +865,7 @@ static ModelAPI_AttributeSelection::CenterType centerTypeByName(std::wstring& th
     centersMap().begin();
   for(; aPrefixIter != centersMap().end(); aPrefixIter++) {
     std::size_t aFound = theShapeName.find(aPrefixIter->second);
-    if (aFound != std::string::npos &&
+    if (aFound != std::wstring::npos &&
         aFound == theShapeName.size() - aPrefixIter->second.size()) {
       theShapeName = theShapeName.substr(0, aFound);
       return aPrefixIter->first;
@@ -870,11 +899,11 @@ void Model_AttributeSelection::selectSubShape(
     std::shared_ptr<Model_Document> aDoc =
       std::dynamic_pointer_cast<Model_Document>(owner()->document());
     // check this is Part-name: 2 delimiters in the name
-    std::size_t aPartEnd = aSubShapeName.find('/');
-    if (aPartEnd != std::string::npos) {
+    std::size_t aPartEnd = aSubShapeName.find(L'/');
+    if (aPartEnd != std::wstring::npos) {
       std::wstring aPartName = aSubShapeName.substr(0, aPartEnd);
       DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
-      if (aPartName == ModelAPI_Tools::toWString(aRootDoc->kind())) {
+      if (aPartName == Locale::Convert::toWString(aRootDoc->kind())) {
         aDoc = std::dynamic_pointer_cast<Model_Document>(aRootDoc);
         aSubShapeName = aSubShapeName.substr(aPartEnd + 1);
       }
@@ -935,7 +964,7 @@ void Model_AttributeSelection::selectSubShape(
     }
 
     // the whole result selection check
-    if (aSubShapeName.find('/') == std::string::npos) {
+    if (aSubShapeName.find(L'/') == std::wstring::npos) {
       ObjectPtr aRes = aDoc->objectByName(ModelAPI_ResultConstruction::group(), aSubShapeName);
       if (!aRes.get()) {
         aRes = aDoc->objectByName(ModelAPI_ResultBody::group(), aSubShapeName);
@@ -1029,7 +1058,22 @@ void Model_AttributeSelection::selectSubShape(const std::string& theType,
   // collect features from PartSet and the current part
   SessionPtr aSession = ModelAPI_Session::get();
   std::list<FeaturePtr> aFeatures = aSession->moduleDocument()->allFeatures();
-  if (aSession->moduleDocument() != owner()->document()) {
+  if (anOwner->getKind() == "ImportResult") {
+    // special case: feature "ImportResult" refers to the results from another parts,
+    // thus, it is necessary to go through the features of these parts too.
+    std::list<FeaturePtr> aPartSetFeatures = aFeatures;
+    aFeatures.clear();
+    for (std::list<FeaturePtr>::iterator it = aPartSetFeatures.begin();
+         it != aPartSetFeatures.end(); ++it) {
+      aFeatures.push_back(*it);
+      if ((*it)->firstResult()->groupName() == ModelAPI_ResultPart::group()) {
+        ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>((*it)->firstResult());
+        std::list<FeaturePtr> aPartFeatures = aPart->partDoc()->allFeatures();
+        aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end());
+      }
+    }
+  }
+  else if (aSession->moduleDocument() != owner()->document()) {
     std::list<FeaturePtr> aPartFeatures = owner()->document()->allFeatures();
     aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end());
   }
@@ -1135,7 +1179,7 @@ std::wstring Model_AttributeSelection::contextName(const ResultPtr& theContext)
   std::wstring aResult;
   if (owner()->document() != theContext->document()) {
     if (theContext->document() == ModelAPI_Session::get()->moduleDocument()) {
-      aResult = ModelAPI_Tools::toWString(theContext->document()->kind()) + L"/";
+      aResult = Locale::Convert::toWString(theContext->document()->kind()) + L"/";
     } else {
       ResultPtr aDocRes = ModelAPI_Tools::findPartResult(
         ModelAPI_Session::get()->moduleDocument(), theContext->document());
@@ -1254,8 +1298,7 @@ void Model_AttributeSelection::computeValues(
     NCollection_DataMap<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> aSubs;
     TopTools_DataMapOfShapeShape::Iterator aContIter(aNewToOld);
     for(; aContIter.More(); aContIter.Next()) {
-      TopExp_Explorer aSubExp(aContIter.Key(), aValType);
-      for(; aSubExp.More(); aSubExp.Next()) {
+      for(aSubExp.Init(aContIter.Key(), aValType); aSubExp.More(); aSubExp.Next()) {
         if (!aSubs.IsBound(aSubExp.Current())) {
           aSubs.Bind(aSubExp.Current(), TopTools_MapOfShape());
         }
@@ -1320,7 +1363,8 @@ void Model_AttributeSelection::computeValues(
 
 void Model_AttributeSelection::concealedFeature(
   const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
-  std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature)
+  std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature,
+  const bool theCheckWholeFeature)
 {
   std::set<FeaturePtr> alreadyProcessed;
   alreadyProcessed.insert(theFeature);
@@ -1336,16 +1380,21 @@ void Model_AttributeSelection::concealedFeature(
   }
   std::list<ResultPtr>::const_iterator aRootIter = aRootRes.cbegin();
   for(; aRootIter != aRootRes.cend(); aRootIter++) {
-    std::list<ResultPtr> allRes;
-    allRes.push_back(*aRootIter);
+    std::list<DataPtr> allRes;
+    allRes.push_back((*aRootIter)->data());
     ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true);
     if (!aRootBody.get())
       aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRootIter);
     if (aRootBody.get()) {
-      ModelAPI_Tools::allSubs(aRootBody, allRes);
-    }
-    for(std::list<ResultPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
-      const std::set<AttributePtr>& aRefs = (*aRIter)->data()->refsToMe();
+      std::list<ResultPtr> allSub;
+      ModelAPI_Tools::allSubs(aRootBody, allSub);
+      for(std::list<ResultPtr>::iterator anIt = allSub.begin(); anIt != allSub.end(); anIt++)
+        allRes.push_back((*anIt)->data());
+    }
+    if (theCheckWholeFeature)
+      allRes.push_back(theFeature->data());
+    for(std::list<DataPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
+      const std::set<AttributePtr>& aRefs = (*aRIter)->refsToMe();
       std::set<AttributePtr>::const_iterator aRef = aRefs.cbegin();
       for (; aRef != aRefs.cend(); aRef++) {
         if (!aRef->get() || !(*aRef)->owner().get())
@@ -1692,7 +1741,6 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
   if (!aPairIter.More())
     return;
   TopoDS_Shape aNewCShape = aPairIter.NewShape();
-  bool anIterate = true;
   // trying to update also the sub-shape selected
   GeomShapePtr aSubShape = value();
   if (aSubShape.get() && aSubShape->isEqual(aContext->shape()))
@@ -1706,10 +1754,8 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
   TopTools_ListOfShape aValShapes;
   if (searchNewContext(aDoc, aNewCShape, aContext, aValShape, aContLab, aNewContexts, aValShapes))
   {
-    std::set<ResultPtr> allContexts, aSkippedContext;
-    std::list<ResultPtr>::iterator aNewContext = aNewContexts.begin();
-    for(; aNewContext != aNewContexts.end(); aNewContext++)
-      allContexts.insert(*aNewContext);
+    std::set<ResultPtr> allContexts(aNewContexts.begin(), aNewContexts.end());
+    std::set<ResultPtr> aSkippedContext;
 
     // if there exist context composite and sub-result(s), leave only sub(s)
     std::set<ResultPtr>::iterator aResIter = allContexts.begin();
@@ -1883,7 +1929,7 @@ std::wstring Model_AttributeSelection::contextName(const TDF_Label theSelectionL
         aNumInHistoryNames--;
       }
       if (aBaseDocumnetUsed)
-        aContextName = ModelAPI_Tools::toWString(aDoc->kind()) + L"/" + aContextName;
+        aContextName = Locale::Convert::toWString(aDoc->kind()) + L"/" + aContextName;
       return aContextName;
     }
   }
@@ -1902,8 +1948,8 @@ bool Model_AttributeSelection::restoreContext(std::wstring theName,
 
   // remove the sub-value part if exists
   std::wstring aSubShapeName = aName;
-  std::string::size_type n = aName.find('/');
-  if (n != std::string::npos) {
+  std::wstring::size_type n = aName.find(L'/');
+  if (n != std::wstring::npos) {
     aName = aName.substr(0, n);
   }
 
@@ -1914,11 +1960,12 @@ bool Model_AttributeSelection::restoreContext(std::wstring theName,
     // name in PartSet?
     aDoc = std::dynamic_pointer_cast<Model_Document>(
       ModelAPI_Session::get()->moduleDocument());
-    if (theName.find(ModelAPI_Tools::toWString(aDoc->kind())) == 0) { // remove the document identifier from name if exists
+    if (theName.find(Locale::Convert::toWString(aDoc->kind())) == 0) {
+      // remove the document identifier from name if exists
       aSubShapeName = theName.substr(aDoc->kind().size() + 1);
       aName = aSubShapeName;
-      std::string::size_type n = aName.find('/');
-      if (n != std::string::npos) {
+      n = aName.find(L'/');
+      if (n != std::wstring::npos) {
         aName = aName.substr(0, n);
       }
     }
@@ -1933,8 +1980,8 @@ bool Model_AttributeSelection::restoreContext(std::wstring theName,
 
   // sketch sub-component shape and name is located in separated feature label, try the sub-name
   if (theValue.IsNull() && aCont->groupName() == ModelAPI_ResultConstruction::group()) {
-    std::string::size_type aSlash = aSubShapeName.rfind('/');
-    if (aSlash != std::string::npos) {
+    std::wstring::size_type aSlash = aSubShapeName.rfind(L'/');
+    if (aSlash != std::wstring::npos) {
       std::wstring aCompName = aSubShapeName.substr(aSlash + 1);
       CompositeFeaturePtr aComposite =
         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aDoc->feature(aCont));
@@ -1965,6 +2012,23 @@ bool Model_AttributeSelection::restoreContext(std::wstring theName,
     }
   }
 
+  // Fix for opened study (aDoc->myNamingNames is empty)
+  if (theValue.IsNull() && aCont->groupName() != ModelAPI_ResultConstruction::group()) {
+    std::wstring::size_type aSlash = aSubShapeName.rfind(L'/');
+    if (aSlash != std::wstring::npos) {
+      std::wstring aCompName = aSubShapeName.substr(aSlash + 1);
+      TDF_Label aLab = std::dynamic_pointer_cast<Model_Data>(aCont->data())->shapeLab();
+      TDF_ChildIDIterator aSubNames (aLab, TDataStd_Name::GetID());
+      for (; aSubNames.More(); aSubNames.Next()) {
+        if (Handle(TDataStd_Name)::DownCast(aSubNames.Value())->Get().IsEqual(aCompName.c_str())) {
+          theValue = aSubNames.Value()->Label();
+          aDoc->addNamingName(theValue, aSubShapeName);
+          break;
+        }
+      }
+    }
+  }
+
   if (aCont.get()) {
     theContext = std::dynamic_pointer_cast<Model_Data>(aCont->data())->label();
   }
@@ -2023,23 +2087,28 @@ ResultPtr Model_AttributeSelection::newestContext(
     //if (aResult->groupName() == ModelAPI_ResultBody::group()) {
       // try to search newer context by the concealment references
       // take references to all results: root one, any sub
-    std::list<ResultPtr> allRes;
+    std::list<DataPtr> allRes;
     ResultPtr aCompContext;
     ResultBodyPtr aCompBody = ModelAPI_Tools::bodyOwner(aResult, true);
     if (aCompBody.get()) {
-      ModelAPI_Tools::allSubs(aCompBody, allRes);
-      allRes.push_back(aCompBody);
+      std::list<ResultPtr> allSub;
+      ModelAPI_Tools::allSubs(aCompBody, allSub);
+      for(std::list<ResultPtr>::iterator anIt = allSub.begin(); anIt != allSub.end(); anIt++)
+        allRes.push_back((*anIt)->data());
+      allRes.push_back(aCompBody->data());
       aCompContext = aCompBody;
     }
     if (allRes.empty())
-      allRes.push_back(aResult);
+      allRes.push_back(aResult->data());
+    allRes.push_back(aResult->document()->feature(aResult)->data());
 
-    for (std::list<ResultPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
-      ResultPtr aResCont = *aSub;
-      ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResCont);
+    bool aFoundReferernce = false;
+    for (std::list<DataPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
+      DataPtr aResCont = *aSub;
+      ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResCont->owner());
       if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext)
         continue; // only lower and higher level subs are counted
-      const std::set<AttributePtr>& aRefs = aResCont->data()->refsToMe();
+      const std::set<AttributePtr>& aRefs = aResCont->refsToMe();
       std::set<AttributePtr>::const_iterator aRef = aRefs.begin();
       for (; !aFindNewContext && aRef != aRefs.end(); aRef++) {
         if (!aRef->get() || !(*aRef)->owner().get())
@@ -2067,6 +2136,7 @@ ResultPtr Model_AttributeSelection::newestContext(
         for (; aResIter != aResults.end(); aResIter++) {
           if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled())
             continue;
+          aFoundReferernce = true;
           GeomShapePtr aShape = (*aResIter)->shape();
           if (aShape.get() && aShape->isSubShape(aSelectedShape, false)) {
             aResult = *aResIter; // found new context (produced from this) with same subshape
@@ -2076,6 +2146,11 @@ ResultPtr Model_AttributeSelection::newestContext(
         }
       }
     }
+    if (aFoundReferernce && !aFindNewContext &&
+        aResult->groupName() != ModelAPI_ResultConstruction::group()) {
+      // #19019 : result is concealed by object that contains no such sub-shape
+      return theCurrent;
+    }
   }
   // if compsolid is context, try to take sub-solid as context: like in GUI and scripts
   ResultBodyPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResult);
@@ -2092,10 +2167,16 @@ ResultPtr Model_AttributeSelection::newestContext(
       }
     }
   }
-  // in case sketch line was selected for wire, but wire was concealed and not such line anymore,
-  // so, actually, the sketch element was selected (which is never concealed)
-  if (aResult != theCurrent && aResult->isConcealed())
-    aResult = theCurrent;
+  // in case sketch line was selected for wire, but wire was concealed and there is no such line
+  // anymore, so, actually, the sketch element was selected (which is never concealed)
+  if (aResult != theCurrent && theCurrent->groupName() == ModelAPI_ResultConstruction::group()) {
+    std::list<FeaturePtr> aConcealers;
+    FeaturePtr aResFeature = aDoc->feature(aResult);
+    FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+    concealedFeature(aResFeature, aThisFeature, false, aConcealers, aResult, true);
+    if (aConcealers.size())
+      aResult = theCurrent;
+  }
   return aResult;
 }