]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Implementation of mechanism of publication into the SHAPERSTUDY that propagates modif...
authormpv <mikhail.ponikarov@opencascade.com>
Tue, 7 Apr 2020 11:17:01 +0000 (14:17 +0300)
committermpv <mikhail.ponikarov@opencascade.com>
Tue, 7 Apr 2020 11:17:01 +0000 (14:17 +0300)
src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py
src/Model/Model_ResultBody.cpp
src/Model/Model_ResultBody.h
src/ModelAPI/ModelAPI_ResultBody.h
src/ModelAPI/ModelAPI_Tools.cpp
src/ModelAPI/ModelAPI_Tools.h

index 07aa2200555e2b17ed9137873cc9deac9722bfe6..aca23d5643df2bc33518eb279b2e615e0e861328 100644 (file)
@@ -58,6 +58,24 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
     def initAttributes(self):
         pass
 
+    ## Computes unique entry for result: partId:featureId[number of result in feature]
+    def computeEntry(self, theRes):
+        aDoc = theRes.document()
+        aFeat = aDoc.feature(theRes)
+        aFeatId = str(aFeat.data().featureId())
+        aRootDoc = ModelAPI.ModelAPI_Session.get().moduleDocument()
+        aPartFeat = ModelAPI.findPartFeature(aRootDoc, aDoc)
+        aPartFeatureId = str(aPartFeat.data().featureId())
+        aResIndex = 0
+        for aRes in aFeat.results():
+          if aRes.data().isEqual(theRes.data()):
+            break
+          aResIndex += 1
+        if aResIndex != 0:
+          aFeatId += ":" + str(aResIndex)
+        anEntry = aPartFeatureId + ":" + aFeatId
+        return anEntry
+
     ## Exports all shapes and groups into the GEOM module.
     def execute(self):
         aSession = ModelAPI.ModelAPI_Session.get()
@@ -77,7 +95,7 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
         # collect all processed internal entries to break the link of unprocessed later
         allProcessed = []
 
-        # iterate all parts and all results to publish them in SHAPER_STUDY
+        # iterate all parts and all results to find all alive items
         for aPartId in range(aPartSet.size(model.ModelAPI_ResultPart_group())):
           aPartObject = aPartSet.object(model.ModelAPI_ResultPart_group(), aPartId)
           aPartRes = ModelAPI.modelAPI_ResultPart(ModelAPI.modelAPI_Result(aPartObject))
@@ -87,18 +105,62 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
             break
           aPartFeatureId = aPartSet.feature(aPartRes).data().featureId()
           # Collects all features of exported results to find results of the same features and extend id.
-          # Map from feature index to index of result. If index is zero (initial), no surrfix to entry is added.
-          aFeaturesIndices = {}
           for aResId in range(aPartDoc.size(model.ModelAPI_ResultBody_group())):
             aResObject = aPartDoc.object(model.ModelAPI_ResultBody_group(), aResId)
             aRes = model.objectToResult(aResObject)
-            aResFeatureId = str(aPartDoc.feature(aRes).data().featureId())
-            if aResFeatureId in aFeaturesIndices:
-              aFeaturesIndices[aResFeatureId] += 1
-              aResFeatureId += ":" + str(aFeaturesIndices[aResFeatureId])
-            else:
-              aFeaturesIndices[aResFeatureId] = 0
-            aSSEntry = str(aPartFeatureId) + ":" + aResFeatureId
+            aSSEntry = self.computeEntry(aRes)
+            allProcessed.append(aSSEntry)
+
+        # process all SHAPER-STUDY shapes to find dead of evolved
+        allNewReferences = [] # entries of new objects that are now referenced by evolved
+        aSOIter = SHAPERSTUDY_utils.getStudy().NewChildIterator(aComponent)
+        while aSOIter.More():
+          aSO = aSOIter.Value()
+          aSOIter.Next() # here because there is continue inside the loop
+          anIOR = aSO.GetIOR()
+          if len(anIOR):
+            anObj = salome.orb.string_to_object(anIOR)
+            if isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
+              anEntry = anObj.GetEntry()
+              if len(anEntry) == 0:
+                continue;
+              elif anEntry not in allProcessed: # found a removed shape: make it dead for the moment
+                # but before check this result was updated to the new result
+                anEvolutionRes = ModelAPI.singleEvolution(anEntry)
+                if anEvolutionRes:
+                  # try to find the last evolution
+                  aNewEntry = self.computeEntry(anEvolutionRes)
+                  aNewRes = ModelAPI.singleEvolution(aNewEntry)
+                  while aNewRes:
+                    aNewEntry = self.computeEntry(aNewRes)
+                    aNewRes = ModelAPI.singleEvolution(aNewEntry)
+                  allNewReferences.append(aNewEntry)
+                  anObj.SetEntry(aNewEntry) # set a new entry and a shape
+                  anObj.SetShapeByStream(anEvolutionRes.shape().getShapeStream(False))
+                  aSO.SetAttrString("AttributeName", anEvolutionRes.data().name()) # also rename
+                else: # remove the reference - red node
+                  aRes, aSO2 = aSO.FindSubObject(1)
+                  if aRes:
+                    aRes, aRef = aSO2.ReferencedObject()
+                    if aRes:
+                      aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
+                      aBuilder.RemoveReference(aSO2)
+
+         # iterate all parts and all results to publish them in SHAPER_STUDY
+        for aPartId in range(aPartSet.size(model.ModelAPI_ResultPart_group())):
+          aPartObject = aPartSet.object(model.ModelAPI_ResultPart_group(), aPartId)
+          aPartRes = ModelAPI.modelAPI_ResultPart(ModelAPI.modelAPI_Result(aPartObject))
+          aPartDoc = aPartRes.partDoc()
+          if aPartDoc is None and aPartObject is not None:
+            break
+          aPartFeatureId = aPartSet.feature(aPartRes).data().featureId()
+          # Collects all features of exported results to find results of the same features and extend id.
+          for aResId in range(aPartDoc.size(model.ModelAPI_ResultBody_group())):
+            aResObject = aPartDoc.object(model.ModelAPI_ResultBody_group(), aResId)
+            aRes = model.objectToResult(aResObject)
+            aSSEntry = self.computeEntry(aRes)
+            if aSSEntry in allNewReferences:
+              continue
             aSShape = anEngine.FindOrCreateShape(aSSEntry)
             aSShape.SetShapeByStream(aRes.shape().getShapeStream(False))
             if not aSShape.GetSO(): # publish in case it is a new shape
@@ -116,27 +178,6 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
             # Fields
             self.processGroups(aRes, anEngine, aPartFeatureId, aSShape, True)
 
-        # process all SHAPER-STUDY shapes to find dead
-        aSOIter = SHAPERSTUDY_utils.getStudy().NewChildIterator(aComponent)
-        while aSOIter.More():
-          aSO = aSOIter.Value()
-          aSOIter.Next() ### here because there is continue inside the loop!
-          anIOR = aSO.GetIOR()
-          if len(anIOR):
-            anObj = salome.orb.string_to_object(anIOR)
-            if isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
-              anEntry = anObj.GetEntry()
-              if len(anEntry) == 0:
-                continue;
-              elif anEntry not in allProcessed: # found a removed shape: make it dead for the moment
-                # remove the reference - red node
-                aRes, aSO2 = aSO.FindSubObject(1)
-                if aRes:
-                  aRes, aRef = aSO2.ReferencedObject()
-                  if aRes:
-                    aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
-                    aBuilder.RemoveReference(aSO2)
-
     # Part of the "execute" method: processes the Groups of theRes result publication.
     # If theFields is true, the same is performed for Fields.
     def processGroups(self, theRes, theEngine, thePartFeatureId, theStudyShape, theFields):
index 62b47c7cbddcf468710296cbe5fbe00c5594bf87..b7bf782297290b4c9553baa2328fef2ce5b18e1c 100644 (file)
 #include <GeomAPI_ShapeIterator.h>
 #include <GeomAPI_ShapeExplorer.h>
 
+#include <TNaming_NamedShape.hxx>
+#include <TNaming_Iterator.hxx>
+#include <TNaming_SameShapeIterator.hxx>
+#include <TNaming_Tool.hxx>
 #include <TopoDS_Shape.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopTools_MapOfShape.hxx>
 #include <TDataStd_UAttribute.hxx>
+#include <TDF_Reference.hxx>
 
 // if this attribute exists, the shape is connected topology
 Standard_GUID kIsConnectedTopology("e51392e0-3a4d-405d-8e36-bbfe19858ef5");
@@ -449,3 +454,36 @@ void Model_ResultBody::computeOldForSub(const GeomShapePtr& theSub,
     }
   }
 }
+
+void Model_ResultBody::modifiedSources(std::list<ResultPtr>& theSources)
+{
+  TDF_Label aLab = std::dynamic_pointer_cast<Model_Data>(data())->shapeLab();
+  TDF_LabelMap aResMap;
+  if (aLab.IsAttribute(TNaming_NamedShape::GetID())) {
+    for(TNaming_Iterator anIter(aLab); anIter.More(); anIter.Next()) {
+      TopoDS_Shape anOld = anIter.OldShape();
+      if (!anOld.IsNull() && TNaming_Tool::HasLabel(aLab, anOld)) {
+        // searching where this old shape is a new shape
+        for(TNaming_SameShapeIterator aNewIter(anOld, aLab); aNewIter.More(); aNewIter.Next()) {
+          for(TNaming_Iterator aNSIter(aNewIter.Label()); aNSIter.More(); aNSIter.Next()) {
+            if (!aNSIter.NewShape().IsNull() && aNSIter.NewShape().IsSame(anOld)) {
+              aResMap.Add(aNewIter.Label());
+              break;
+            }
+          }
+        }
+      }
+    }
+  } else if (aLab.IsAttribute(TDF_Reference::GetID())) { // check also simple reference to the origin
+    Handle(TDF_Reference) aRef;
+    aLab.FindAttribute(TDF_Reference::GetID(), aRef);
+    aResMap.Add(aRef->Get());
+  }
+
+  std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(document());
+  for(TDF_MapIteratorOfLabelMap aLabIter(aResMap); aLabIter.More(); aLabIter.Next()) {
+    ResultPtr aRes = aDoc->resultByLab(aLabIter.Value());
+    if (aRes.get())
+      theSources.push_back(aRes);
+  }
+}
index d0a1f908e68c946dbf38b6859de94cb8326ef33a..d87918a98442220cd1bf8c0ec0e22b0b0cdda14f 100644 (file)
@@ -113,6 +113,9 @@ public:
   /// Cleans cash related to the already stored elements
   MODEL_EXPORT virtual void cleanCash() override;
 
+  /// Returns in the set results that are stored as modified or generated in this result
+  MODEL_EXPORT virtual void modifiedSources(std::list<ResultPtr>& theSources) override;
+
 protected:
   /// Makes a body on the given feature
   Model_ResultBody();
index 7b9b3177871ffff939626c90df9b938758e107bf..6026388dfce769c0a5fef0b38d05d671d0065d7a 100644 (file)
@@ -183,6 +183,9 @@ public:
   /// Cleans cash related to the already stored elements
   MODELAPI_EXPORT virtual void cleanCash() = 0;
 
+  /// Returns in the set results that are stored as modified or generated in this result
+  MODELAPI_EXPORT virtual void modifiedSources(std::list<ResultPtr>& theSources) = 0;
+
 protected:
   /// Default constructor accessible only from Model_Objects
   MODELAPI_EXPORT ModelAPI_ResultBody();
index 8a19702d6251e081c972b5bfa117532237c17887..de4c97ccdd2320c75b47dfc75d117abd9c49455b 100644 (file)
@@ -1102,6 +1102,121 @@ std::list<FeaturePtr> referencedFeatures(
   return aResList;
 }
 
+std::shared_ptr<ModelAPI_Result> singleEvolution(const std::string theEntry)
+{
+  ResultPtr aRes;
+  std::size_t aFirstColon = theEntry.find(":");
+  if (aFirstColon == std::string::npos)
+    return aRes;
+  // searching a part
+  std::string aPartIdStr = theEntry.substr(0, aFirstColon);
+  int aPartId = std::stoi(aPartIdStr);
+  SessionPtr aSession = ModelAPI_Session::get();
+  DocumentPtr aRoot = aSession->moduleDocument();
+  int aRootFeatures = aRoot->size(ModelAPI_Feature::group());
+  FeaturePtr aPartFeat;
+  for(int aRootId = 0; aRootId < aRootFeatures; aRootId++) {
+    ObjectPtr aRootObj = aRoot->object(ModelAPI_Feature::group(), aRootId);
+    FeaturePtr aRootFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(aRootObj);
+    if (aRootFeat.get()) {
+      DataPtr aData = aRootFeat->data();
+      if (aData.get() && aData->isValid() && aData->featureId() == aPartId) {
+        aPartFeat = aRootFeat;
+        break;
+      }
+    }
+  }
+  if (!aPartFeat.get() || aPartFeat->results().empty())
+    return aRes;
+   DocumentPtr aPartDoc = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeat->firstResult())->partDoc();
+   if (!aPartDoc.get())
+     return aRes;
+  // searching a feature
+  std::string aFeatIdStr = theEntry.substr(aFirstColon + 1);
+  std::string aResIdStr;
+  std::size_t aSecondColon = aFeatIdStr.find(":");
+  if (aSecondColon != std::string::npos) {
+    aResIdStr = aFeatIdStr.substr(aSecondColon + 1);
+    aFeatIdStr = aFeatIdStr.substr(0, aSecondColon);
+  }
+  int aFeatId = std::stoi(aFeatIdStr);
+  int aFeaturesNum = aPartDoc->size(ModelAPI_Feature::group());
+  FeaturePtr aFeat;
+  for(int anId = 0; anId < aFeaturesNum; anId++) {
+    ObjectPtr anObj = aPartDoc->object(ModelAPI_Feature::group(), anId);
+    aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(anObj);
+    if (aFeat.get()) {
+      DataPtr aData = aFeat->data();
+      if (aData.get() && aData->isValid() && aData->featureId() == aFeatId)
+        break;
+      aFeat.reset();
+    }
+  }
+  if (!aFeat.get() || aFeat->results().empty())
+    return aRes;
+  // searching for a result
+  int aResId = 0;
+  if (!aResIdStr.empty()) {
+    aResId = std::stoi(aResIdStr);
+  }
+  ResultPtr anOldRes;
+  std::list<ResultPtr>::const_iterator aResIt = aFeat->results().cbegin();
+  for(; aResIt != aFeat->results().cend(); aResIt++) {
+    if (aResId == 0) {
+      anOldRes = *aResIt;
+      break;
+    }
+    aResId--;
+  }
+  if (!anOldRes.get() || !anOldRes->shape().get())
+    return aRes;
+  // searching for a new result
+  std::list<ResultPtr> allRes;
+  allResults(aFeat, allRes);
+  std::list<ObjectPtr> allObjs;
+  allObjs.push_back(aFeat);
+  for(std::list<ResultPtr>::iterator anIter = allRes.begin(); anIter != allRes.end(); anIter++)
+    allObjs.push_back(*anIter);
+  ModelAPI_ValidatorsFactory* aValidators = aSession->validators();
+  FeaturePtr aConcealer;
+  for(std::list<ObjectPtr>::iterator anOld = allObjs.begin(); anOld != allObjs.end(); anOld++) {
+    const std::set<AttributePtr>& aRefs = (*anOld)->data()->refsToMe();
+    std::set<AttributePtr>::const_iterator aRefIt = aRefs.cbegin();
+    for(; aRefIt != aRefs.end(); aRefIt++) {
+      FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
+      if (!aRefFeat.get())
+        continue;
+      if (!aValidators->isConcealed(aRefFeat->getKind(), (*aRefIt)->id()))
+        continue; // use only concealed attributes
+      if (aConcealer.get() && aConcealer != aRefFeat)
+        return aRes; // multiple concealers
+      aConcealer = aRefFeat;
+    }
+  }
+  if (!aConcealer.get() || aConcealer->results().size() != 1)
+    return aRes; // no new features at all or concealer contains may result
+  if (!aConcealer->firstResult()->shape().get() || aConcealer->firstResult()->shape()->shapeType() != anOldRes->shape()->shapeType())
+    return aRes; // shapes in old and new results are not of the same type
+  aRes = aConcealer->firstResult();
+
+  ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aRes);
+  if (aBody.get()) {
+    std::list<ResultPtr> aSources;
+    aBody->modifiedSources(aSources);
+    if (aSources.empty())
+      return ResultPtr(); // no sources of modification stored in the data tree
+    std::list<ResultPtr>::iterator aSourceIter = aSources.begin();
+    for(; aSourceIter != aSources.end(); aSourceIter++) {
+      FeaturePtr aSourceFeat = aPartDoc->feature(*aSourceIter);
+      if (!aSourceFeat.get())
+        return ResultPtr(); // invalid feature or feature from other document
+      if (aSourceFeat != aFeat)
+        return ResultPtr(); // modied by other feature
+    }
+  }
+  return aRes;
+}
+
 // LCOV_EXCL_STOP
 
 } // namespace ModelAPI_Tools
index a90cd60fa461c124dad9516f301a20cc3ec71156..c1208e63f84886868c5395a0673ee99d36100931 100644 (file)
@@ -300,6 +300,11 @@ MODELAPI_EXPORT std::list<std::shared_ptr<ModelAPI_Feature> > referencedFeatures
   std::shared_ptr<ModelAPI_Result> theTarget, const std::string& theFeatureKind,
   const bool theSortResults);
 
+/*! Returns the result that was created from theEntry result: only this result is created, same shape type,
+ * only from this result the result is created.
+* \param theEntry string that identifies a result (part feature id):(feature is)[:(result number in the feature)]
+*/
+MODELAPI_EXPORT std::shared_ptr<ModelAPI_Result> singleEvolution(const std::string theEntry);
 }
 
 #endif