Salome HOME
Issue #2155 Trim removes multi-rotation constraint, undo leads to wrong DOF
[modules/shaper.git] / src / Model / Model_Objects.cpp
index 715bc6896794871c6d61e8b00568d637303eb65a..949f99b927d30c4a2cd4e9f2b4e309d240d3c41a 100644 (file)
@@ -14,6 +14,7 @@
 #include <Model_ResultBody.h>
 #include <Model_ResultCompSolid.h>
 #include <Model_ResultGroup.h>
+#include <Model_ResultField.h>
 #include <Model_ResultParameter.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_CompositeFeature.h>
@@ -54,7 +55,7 @@ void Model_Objects::setOwner(DocumentPtr theDoc)
   myDoc = theDoc;
   // update all fields and recreate features and result objects if needed
   TDF_LabelList aNoUpdated;
-  synchronizeFeatures(aNoUpdated, true, true, true);
+  synchronizeFeatures(aNoUpdated, true, true, true, true);
   myHistory.clear();
 }
 
@@ -74,7 +75,6 @@ Model_Objects::~Model_Objects()
     ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group());
     ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
     aFeature->removeResults(0, false);
-    //aFeature->eraseResults();
     aFeature->erase();
     myFeatures.UnBind(aFeaturesIter.Key());
   }
@@ -269,6 +269,34 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
   }
 }
 
+void Model_Objects::eraseAllFeatures()
+{
+  static Events_ID kDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  static const ModelAPI_EventCreator* kCreator = ModelAPI_EventCreator::get();
+  // make all features invalid (like deleted)
+  NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFIter(myFeatures);
+  for(; aFIter.More(); aFIter.Next()) {
+    FeaturePtr aFeature = aFIter.Value();
+    std::list<ResultPtr> aResList;
+    ModelAPI_Tools::allResults(aFeature, aResList);
+    std::list<ResultPtr>::iterator aRIter = aResList.begin();
+    for(; aRIter != aResList.end(); aRIter++) {
+      ResultPtr aRes = *aRIter;
+      if (aRes && aRes->data()->isValid()) {
+        kCreator->sendDeleted(myDoc, aRes->groupName());
+        kCreator->sendUpdated(aRes, kDispEvent);
+        aRes->setData(aRes->data()->invalidPtr());
+
+      }
+    }
+    kCreator->sendUpdated(aFeature, kDispEvent);
+    aFeature->setData(aFeature->data()->invalidPtr());
+  }
+  kCreator->sendDeleted(myDoc, ModelAPI_Feature::group());
+  myFeatures.Clear(); // just remove features without modification of DS
+  updateHistory(ModelAPI_Feature::group());
+}
+
 void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
 {
   TDF_Label aFeaturesLab = featuresLabel();
@@ -611,7 +639,7 @@ std::shared_ptr<ModelAPI_Feature> Model_Objects::featureById(const int theId)
 
 void Model_Objects::synchronizeFeatures(
   const TDF_LabelList& theUpdated, const bool theUpdateReferences,
-  const bool theOpen, const bool theFlush)
+  const bool theExecuteFeatures, const bool theOpen, const bool theFlush)
 {
   Model_Document* anOwner = std::dynamic_pointer_cast<Model_Document>(myDoc).get();
   if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize
@@ -667,7 +695,7 @@ void Model_Objects::synchronizeFeatures(
       aFeature = myFeatures.Find(aFeatureLabel);
       aKeptFeatures.insert(aFeature);
       if (anUpdatedMap.Contains(aFeatureLabel)) {
-        if (!theOpen) { // on abort/undo/redo reinitialize attributes is something is changed
+        if (!theOpen) { // on abort/undo/redo reinitialize attributes if something is changed
           std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs =
             aFeature->data()->attributes("");
           std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
@@ -722,23 +750,15 @@ void Model_Objects::synchronizeFeatures(
   // they may be connected, like sketch and sub elements)
   // After synchronisation of back references because sketch
   // must be set in sub-elements before "execute" by updateResults
-  std::list<FeaturePtr> aComposites; // composites must be updated after their subs (issue 360)
+  std::set<FeaturePtr> aProcessed; // composites must be updated after their subs (issue 360)
   TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID());
   for (; aLabIter2.More(); aLabIter2.Next()) {
     TDF_Label aFeatureLabel = aLabIter2.Value()->Label();
     if (myFeatures.IsBound(aFeatureLabel)) {  // a new feature is inserted
       FeaturePtr aFeature = myFeatures.Find(aFeatureLabel);
-      if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature).get())
-        aComposites.push_back(aFeature);
-      else
-        updateResults(aFeature);
+      updateResults(aFeature, aProcessed);
     }
   }
-  std::list<FeaturePtr>::iterator aComposite = aComposites.begin();
-  for(; aComposite != aComposites.end(); aComposite++) {
-    updateResults(*aComposite);
-  }
-
   // the synchronize should be done after updateResults
   // in order to correct back references of updated results
   if (theUpdateReferences) {
@@ -749,7 +769,7 @@ void Model_Objects::synchronizeFeatures(
     myHistory.clear();
   }
 
-  if (theOpen)
+  if (theExecuteFeatures)
     anOwner->executeFeatures() = false;
   aLoop->activateFlushes(isActive);
 
@@ -763,7 +783,7 @@ void Model_Objects::synchronizeFeatures(
     aLoop->flush(aRedispEvent);
     aLoop->flush(aToHideEvent);
   }
-  if (theOpen)
+  if (theExecuteFeatures)
     anOwner->executeFeatures() = true;
 }
 
@@ -1008,6 +1028,23 @@ std::shared_ptr<ModelAPI_ResultGroup> Model_Objects::createGroup(
   return aResult;
 }
 
+std::shared_ptr<ModelAPI_ResultField> Model_Objects::createField(
+    const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
+{
+  TDF_Label aLab = resultLabel(theFeatureData, theIndex);
+  TDataStd_Comment::Set(aLab, ModelAPI_ResultField::group().c_str());
+  ObjectPtr anOldObject = object(aLab);
+  std::shared_ptr<ModelAPI_ResultField> aResult;
+  if (anOldObject.get()) {
+    aResult = std::dynamic_pointer_cast<ModelAPI_ResultField>(anOldObject);
+  }
+  if (!aResult.get()) {
+    aResult = std::shared_ptr<ModelAPI_ResultField>(new Model_ResultField(theFeatureData));
+    storeResult(theFeatureData, aResult, theIndex);
+  }
+  return aResult;
+}
+
 std::shared_ptr<ModelAPI_ResultParameter> Model_Objects::createParameter(
       const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
@@ -1057,8 +1094,22 @@ std::string Model_Objects::featureResultGroup(FeaturePtr theFeature)
   return anEmpty; // not found
 }
 
-void Model_Objects::updateResults(FeaturePtr theFeature)
+void Model_Objects::updateResults(FeaturePtr theFeature, std::set<FeaturePtr>& theProcessed)
 {
+  if (theProcessed.find(theFeature) != theProcessed.end())
+    return;
+  theProcessed.insert(theFeature);
+  // for composites update subs recursively (sketch elements results are needed for the sketch)
+  CompositeFeaturePtr aComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+  if (aComp.get() && aComp->getKind() != "Part") { // don't go inside of parts sub-features
+    // update subs of composites first
+    int aSubNum = aComp->numberOfSubs();
+    for(int a = 0; a < aSubNum; a++) {
+      FeaturePtr aSub = aComp->subFeature(a);
+      updateResults(aComp->subFeature(a), theProcessed);
+    }
+  }
+
   // for not persistent is will be done by parametric updater automatically
   //if (!theFeature->isPersistentResult()) return;
   // check the existing results and remove them if there is nothing on the label
@@ -1100,15 +1151,14 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
           if (!aNewP->partDoc().get())
             // create the part result: it is better to restore the previous result if it is possible
             theFeature->execute();
-          break;
         } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) {
           theFeature->execute(); // construction shapes are needed for sketch solver
-          break;
         } else if (aGroup->Get() == ModelAPI_ResultGroup::group().c_str()) {
           aNewBody = createGroup(theFeature->data(), aResIndex);
+        } else if (aGroup->Get() == ModelAPI_ResultField::group().c_str()) {
+          aNewBody = createField(theFeature->data(), aResIndex);
         } else if (aGroup->Get() == ModelAPI_ResultParameter::group().c_str()) {
           theFeature->attributeChanged("expression"); // just produce a value
-          break;
         } else {
           Events_InfoMessage("Model_Objects", "Unknown type of result is found in the document:")
             .arg(TCollection_AsciiString(aGroup->Get()).ToCString()).send();