]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/Model/Model_AttributeSelection.cpp
Salome HOME
Fix for the issue #3116 : Create Edge, Wire all-in is missed for feature in Partset
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
index 5ec767a0a525920872abc1a4b893ebb5f2bfd432..9d1e6cb65311873de13c46cde27684fe2a2bdcc5 100644 (file)
@@ -185,10 +185,11 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext,
   } else if (theContext->groupName() == ModelAPI_ResultGroup::group()) {
     aSelLab.ForgetAllAttributes(true);
     TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID);
-  } else { // check the feature context: parent-Part of this feature should not be used
+  } else { // check the feature context: only construction features of PartSet could be selected
     FeaturePtr aFeatureContext = std::dynamic_pointer_cast<ModelAPI_Feature>(theContext);
-    if (aFeatureContext.get()) {
-      if (owner()->document() != aFeatureContext->document()) {
+    if (aFeatureContext.get() && owner()->document() != aFeatureContext->document()) {
+      if (aFeatureContext->results().empty() ||
+          aFeatureContext->firstResult()->groupName() != ModelAPI_ResultConstruction::group()) {
         aSelLab.ForgetAllAttributes(true);
         myRef.setValue(ObjectPtr());
         if (aToUnblock)
@@ -599,19 +600,32 @@ bool Model_AttributeSelection::update()
     TopoDS_Shape aContextShape = aContext->shape()->impl<TopoDS_Shape>();
     Selector_Selector aSelector(aSelLab, baseDocumentLab());
     aResult = aSelector.restore(aContextShape);
+    bool aWasInvalid = aSelLab.IsAttribute(kINVALID_SELECTION);
     setInvalidIfFalse(aSelLab, aResult);
 
     TopoDS_Shape aNewShape;
     if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
       aNewShape = aNS->Get();
 
-    if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape)) {
+    if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape) || aWasInvalid)
+    {
       // shape type should not be changed: if shape becomes compound of such shapes, then split
       if (myParent && !anOldShape.IsNull() && !aNewShape.IsNull() &&
           anOldShape.ShapeType() != aNewShape.ShapeType() &&
           aNewShape.ShapeType() == TopAbs_COMPOUND) {
         split(aContext, aNewShape, anOldShape.ShapeType());
       }
+      // for issue #3076 check that the new value belongs to the new context
+      if (!aNewShape.IsNull() && !aContextShape.IsNull() &&
+          (aNewShape.ShapeType() == TopAbs_VERTEX || aNewShape.ShapeType() == TopAbs_EDGE ||
+           aNewShape.ShapeType() == TopAbs_FACE)) {
+        TopExp_Explorer anExp(aContextShape, aNewShape.ShapeType());
+        for(; anExp.More(); anExp.Next()) {
+          if (anExp.Current().IsSame(aNewShape))
+            break;
+        }
+        aResult = setInvalidIfFalse(aSelLab, anExp.More());
+      }
       owner()->data()->sendAttributeUpdated(this);  // send updated if shape is changed
     }
     return aResult;
@@ -760,19 +774,22 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
 
   CenterType aCenterType = NOT_CENTER;
   std::shared_ptr<GeomAPI_Shape> aSubSh = internalValue(aCenterType);
-  ResultPtr aCont = context();
 
-  if (!aCont.get() ||
-      (aCont->groupName() == ModelAPI_ResultConstruction::group() && contextFeature().get())) {
+  FeaturePtr aContFeature = contextFeature();
+  if (aContFeature.get()) {
+    std::string aResName;
+    // checking part-owner
+    if (aContFeature->document() != owner()->document())
+        aResName += aContFeature->document()->kind() + "/";
     // selection of a full feature
-    FeaturePtr aFeatureCont = contextFeature();
-    if (aFeatureCont.get()) {
-      return kWHOLE_FEATURE + aFeatureCont->name();
+    if (aContFeature.get()) {
+      return aResName + kWHOLE_FEATURE + aContFeature->name();
     }
     // in case of selection of removed result
     return "";
   }
 
+  ResultPtr aCont = context();
   TDF_Label aSelLab = selectionLabel();
   if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value
     return contextName(aCont);
@@ -1279,8 +1296,8 @@ void Model_AttributeSelection::computeValues(
 
 
 void Model_AttributeSelection::concealedFeature(
-  const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers,
-  const ResultPtr theResultOfFeature)
+  const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
+  std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature)
 {
   std::set<FeaturePtr> alreadyProcessed;
   alreadyProcessed.insert(theFeature);
@@ -1315,7 +1332,9 @@ void Model_AttributeSelection::concealedFeature(
         if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
           continue;
         alreadyProcessed.insert(aRefFeat);
-        if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+        if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id())
+          || (theCheckCopy &&
+              std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aRefFeat).get()))
         {
           // for extrusion cut in python script the nested sketch reference may be concealed before
           // it is nested, so, check this composite feature is valid
@@ -1397,12 +1416,13 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
     } else aResIter++;
   }
 
+  bool aStaySame = false;
   if (aResults.empty()) {
     // check the context become concealed by operation which is earlier than this selection
     FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
     FeaturePtr aContextOwner = theDoc->feature(theContext);
     std::list<FeaturePtr> aConcealers;
-    concealedFeature(aContextOwner, aThisFeature, aConcealers, theContext);
+    concealedFeature(aContextOwner, aThisFeature, false, aConcealers, theContext);
     std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
     for(; aConcealer != aConcealers.end(); aConcealer++) {
       std::list<ResultPtr> aRefResults;
@@ -1423,26 +1443,87 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
       if (aResults.empty())
         return true; // feature conceals result, return true, so the context will be removed
     }
-    if (aResults.empty())
-      return false; // no modifications found, must stay the same
+    aStaySame = aResults.empty();
+  }
+  if (myParent && myParent->isMakeCopy()) {
+    // check there are copies before the new results, so, make a copy
+    std::set<ResultPtr>::iterator aResIter = aResults.begin();
+    std::list<ObjectPtr> aCopyContext;
+    std::list<GeomShapePtr> aCopyVals;
+    // features between the new and the old: check the "Move" interface to get a copy
+    FeaturePtr aRootOwner = theDoc->feature(theContext);
+    FeaturePtr anOwner = ModelAPI_Tools::compositeOwner(aRootOwner);
+    for(; anOwner.get(); anOwner = ModelAPI_Tools::compositeOwner(anOwner))
+      aRootOwner = anOwner;
+    FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+    // iterate all results to find a "Copy" features between the new and one and to add the
+    // copy-results also to results if this attribute refers to the copied shape
+    int anIndex = kUNDEFINED_FEATURE_INDEX;
+    for(FeaturePtr aFeat = theDoc->objects()->nextFeature(aRootOwner, anIndex); aFeat.get() &&
+        aFeat != aThisFeature; aFeat = theDoc->objects()->nextFeature(aFeat, anIndex)) {
+      std::shared_ptr<ModelAPI_FeatureCopyInterface> aCopier =
+        std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aFeat);
+      if (aCopier.get()) {
+        GeomShapePtr aValShape(new GeomAPI_Shape);
+        aValShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(
+          theValShape.IsNull() ? theContShape : theValShape));
+        aCopier->getCopies(theContext, aValShape, aCopyContext, aCopyVals);
+      }
+    }
+    // check for the further modifications of the copy contexts and values
+    std::list<ObjectPtr>::iterator aCopyContIter = aCopyContext.begin();
+    std::list<GeomShapePtr>::iterator aCopyValIter = aCopyVals.begin();
+    for(; aCopyContIter != aCopyContext.end(); aCopyContIter++, aCopyValIter++) {
+      ResultPtr aNewCont = std::dynamic_pointer_cast<ModelAPI_Result>(*aCopyContIter);
+      TopoDS_Shape aNewContShape = aNewCont->shape()->impl<TopoDS_Shape>();
+      GeomShapePtr aNewVal = *aCopyValIter;
+      TopoDS_Shape aNewValShape;
+      if (aNewVal.get() && !aNewVal->isNull())
+        aNewValShape = aNewVal->impl<TopoDS_Shape>();
+      std::list<ResultPtr> aNewRes;
+      TopTools_ListOfShape aNewUpdatedVal;
+      if (searchNewContext(theDoc, aNewContShape, aNewCont, aNewValShape,
+          theAccessLabel, aNewRes, aNewUpdatedVal)) {
+        // append new results instead of the current ones
+        std::list<ResultPtr>::iterator aNewIter = aNewRes.begin();
+        TopTools_ListIteratorOfListOfShape aNewUpdVal(aNewUpdatedVal);
+        for(; aNewIter != aNewRes.end(); aNewIter++, aNewUpdVal.Next()) {
+          theResults.push_back(*aNewIter);
+          theValShapes.Append(aNewUpdVal.Value());
+        }
+      } else { // the current result is good
+        theResults.push_back(aNewCont);
+        theValShapes.Append(aNewValShape);
+      }
+    }
+    if (aStaySame && !theResults.empty()) { // no changes except copy, so, keep the origin as first
+      theResults.push_front(theContext);
+      theValShapes.Prepend(theValShape);
+      return true;
+    }
   }
+  if (aStaySame)
+    return false;
+
   // iterate all results to find further modifications
   std::set<ResultPtr>::iterator aResIter = aResults.begin();
-  for(; aResIter != aResults.end(); aResIter++) {
+  for(aResIter = aResults.begin(); aResIter != aResults.end(); aResIter++) {
     if (aResIter->get() != NULL) {
+      ResultPtr aNewResObj = *aResIter;
       // compute new values by two contexts: the old and the new
       TopTools_ListOfShape aValShapes;
-      computeValues(theContext, *aResIter, theValShape, aValShapes);
+      computeValues(theContext, aNewResObj, theValShape, aValShapes);
 
       TopTools_ListIteratorOfListOfShape aNewVal(aValShapes);
       for(; aNewVal.More(); aNewVal.Next()) {
         std::list<ResultPtr> aNewRes;
         TopTools_ListOfShape aNewUpdatedVal;
         TopoDS_Shape aNewValSh = aNewVal.Value();
-        TopoDS_Shape aNewContShape = (*aResIter)->shape()->impl<TopoDS_Shape>();
+        TopoDS_Shape aNewContShape = aNewResObj->shape()->impl<TopoDS_Shape>();
+
         if (theValShape.IsNull() && aNewContShape.IsSame(aNewValSh))
           aNewValSh.Nullify();
-        if (searchNewContext(theDoc, aNewContShape, *aResIter, aNewValSh,
+        if (searchNewContext(theDoc, aNewContShape, aNewResObj, aNewValSh,
                              theAccessLabel, aNewRes, aNewUpdatedVal))
         {
           // append new results instead of the current ones
@@ -1453,7 +1534,7 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
             theValShapes.Append(aNewUpdVal.Value());
           }
         } else { // the current result is good
-          theResults.push_back(*aResIter);
+          theResults.push_back(aNewResObj);
           theValShapes.Append(aNewValSh);
         }
       }
@@ -1475,25 +1556,40 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
       if (aFeature.get()) {
         FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
         std::list<FeaturePtr> aConcealers;
-        concealedFeature(aFeature, aThisFeature, aConcealers, ResultPtr());
+        bool aCopyPossible = myParent && myParent->isMakeCopy();
+        concealedFeature(aFeature, aThisFeature, aCopyPossible, aConcealers, ResultPtr());
         if (aConcealers.empty())
           return;
+        // if there are copies, but no direct modification, keep the original
+        bool aKeepOrigin = false;
+        if (aCopyPossible) {
+          std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+          for(aKeepOrigin = true; aConcealer != aConcealers.end(); aConcealer++)
+            if (!std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(*aConcealer).get()) {
+              aKeepOrigin = false;
+              break;
+            }
+          if (aKeepOrigin) {
+            aConcealers.push_front(aFeature);
+          }
+        }
         bool aChanged = false;
         std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
         for(; aConcealer != aConcealers.end(); aConcealer++)
-          if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
-            setValue(*aConcealer, anEmptyShape);
-            aChanged = true;
-          }
-        if (aConcealer == aConcealers.end()) {
-          if (!aChanged) // remove this
-            theRemove = true;
-        } else { // append new
-          for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
-            if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+          if (aChanged) {
+            if (aKeepOrigin || !myParent->isInList(*aConcealer, anEmptyShape))
               myParent->append(*aConcealer, anEmptyShape);
-        }
-        if (aChanged) // searching for the further modifications
+          } else {
+            if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+              setValue(*aConcealer, anEmptyShape);
+              aChanged = true;
+            } else if (aCopyPossible && *aConcealer == aFeature) {// keep origin in case of copy
+              aChanged = true;
+            }
+          }
+        if (!aChanged) // remove this
+          theRemove = true;
+        else if (!aKeepOrigin) // searching further modifications only if current changed
           updateInHistory(theRemove);
       }
     }
@@ -1691,6 +1787,9 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
         if (!myParent || !myParent->isInList(aNewContext, aValueShape)) { // avoid duplicates
           setValue(aNewContext, aValueShape);
           aFirst = false;
+        } else if (aNewContext == aContext && myParent && myParent->isMakeCopy()) {
+          // this may be exactly the old one, not modified in case of copy
+          aFirst = false;
         }
       } else if (myParent) {
         if (!myParent->isInList(aNewContext, aValueShape)) // avoid addition of duplicates