Salome HOME
Make SHAPER STUDY fields exported in SMESH into MED file
[modules/shaper.git] / src / Model / Model_BodyBuilder.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 893b4fc..2c5c5c3
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2019  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
 //
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include <Model_BodyBuilder.h>
@@ -120,6 +119,53 @@ Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner)
 {
 }
 
+/// Checks that shape is presented in the tree with not-selection evolution
+/// In theOriginalLabel it returns label where NS of old sub-shape is stored
+static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAccess2,
+  TopoDS_Shape theShape, TDF_Label& theOriginalLabel)
+{
+  bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape);
+  if (aResult) { //check evolution and a label of this shape
+    for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next())
+    {
+      static Handle(TNaming_NamedShape) aNS;
+      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+        if (aNS->Evolution() != TNaming_SELECTED) {
+          theOriginalLabel = aNS->Label();
+          return true;
+        }
+      }
+    }
+  }
+  if (!theAccess2.IsNull()) {
+    static const TDF_Label anEmpty;
+    return isShapeInTree(theAccess2, anEmpty, theShape, theOriginalLabel);
+  }
+  return false;
+}
+
+/// Stores entry to the external label in the entries list at this label
+static void storeExternalReference(const TDF_Label& theExternal, const TDF_Label theThis)
+{
+  // store information about the external document reference to restore old shape on open
+  if (!theExternal.IsNull() && !theExternal.Root().IsEqual(theThis.Root())) {
+    Handle(TDataStd_ExtStringList) anEntries;
+    if (!theThis.FindAttribute(kEXTERNAL_SHAPE_REF, anEntries)) {
+      anEntries = TDataStd_ExtStringList::Set(theThis, kEXTERNAL_SHAPE_REF);
+    }
+    TCollection_AsciiString anEntry;
+    TDF_Tool::Entry(theExternal, anEntry);
+    // check it already contains this entry
+    TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List());
+    for(; anIter.More(); anIter.Next())
+      if (anIter.Value() == anEntry)
+        break;
+    if (!anIter.More()) {
+      anEntries->Append(anEntry);
+    }
+  }
+}
+
 void Model_BodyBuilder::store(const GeomShapePtr& theShape,
                               const bool theIsStoreSameShapes)
 {
@@ -137,7 +183,9 @@ void Model_BodyBuilder::store(const GeomShapePtr& theShape,
       return;  // null shape inside
 
     if(!theIsStoreSameShapes) {
-      Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
+      Handle(TNaming_NamedShape) aNS;
+      if (TNaming_Tool::HasLabel(aShapeLab, aShape))
+        aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
       // the last condition is for the issue 2751 : existing shape may be found in compound-NS
       if(!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShape)) {
         // This shape is already in document, store reference instead of shape;
@@ -174,8 +222,7 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
     // clean builders
     if (theIsCleanStored)
       clean();
-    // store the new shape as primitive
-    TNaming_Builder aBuilder(aShapeLab);
+    TNaming_Builder* aBuilder = builder(0);
     if (!theFromShape || !theToShape)
       return;  // bad shape
     TopoDS_Shape aShapeBasis = theFromShape->impl<TopoDS_Shape>();
@@ -184,16 +231,35 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
     TopoDS_Shape aShapeNew = theToShape->impl<TopoDS_Shape>();
     if (aShapeNew.IsNull())
       return;  // null shape inside
-    aBuilder.Generated(aShapeBasis, aShapeNew);
+
+    // There is no sense to write history if old shape does not exist in the document.
+    TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
+      ModelAPI_Session::get()->moduleDocument())->generalLabel();
+    TDF_Label anOriginalLabel;
+    if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeBasis, anOriginalLabel)) {
+      if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway
+        aBuilder->Generated(aShapeNew);
+      }
+    } else {
+      if (aBuilder->NamedShape()->Evolution() == TNaming_PRIMITIVE) { // erase primitive before
+        myBuilders.erase(0);
+        aBuilder = builder(0);
+      }
+
+      aBuilder->Generated(aShapeBasis, aShapeNew);
+      // store information about the external document reference to restore old shape on open
+      storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
+    }
+
     // register name
-    if(!aBuilder.NamedShape()->IsEmpty()) {
+    if(!aBuilder->NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
-      if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
+      if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
         std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
         if(!aName.empty()) {
           std::shared_ptr<Model_Document> aDoc =
             std::dynamic_pointer_cast<Model_Document>(document());
-          aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
+          aDoc->addNamingName(aBuilder->NamedShape()->Label(), aName);
         }
       }
     }
@@ -205,15 +271,19 @@ void Model_BodyBuilder::storeGenerated(const std::list<GeomShapePtr>& theFromSha
 {
   bool aStored = false;
   std::list<GeomShapePtr>::const_iterator anOldIter = theFromShapes.cbegin();
-  for(; anOldIter != theFromShapes.cend(); anOldIter++) {
-    ListOfShape aNews; // check this old really generates theToShape
-    theMakeShape->generated(*anOldIter, aNews);
-    ListOfShape::iterator aNewIter = aNews.begin();
-    for(; aNewIter != aNews.end(); aNewIter++) {
-      if (theToShape->isSame(*aNewIter))
-        break;
+  for (; anOldIter != theFromShapes.cend(); anOldIter++) {
+    bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire();
+    if (!aStore) {
+      ListOfShape aNews; // check this old really generates theToShape
+      theMakeShape->generated(*anOldIter, aNews);
+      ListOfShape::iterator aNewIter = aNews.begin();
+      for (; aNewIter != aNews.end(); aNewIter++) {
+        if (theToShape->isSame(*aNewIter))
+          break;
+      }
+      aStore = aNewIter != aNews.end();
     }
-    if (aNewIter != aNews.end()) {
+    if (aStore) {
       storeGenerated(*anOldIter, theToShape, !aStored);
       TNaming_Builder* aBuilder = builder(0);
       aStored = !aBuilder->NamedShape()->IsEmpty();
@@ -245,7 +315,6 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
   if (aData) {
     // clean builders
     if (theIsCleanStored) clean();
-    // store the new shape as primitive
     TNaming_Builder* aBuilder = builder(0);
     if (!theOldShape || !theNewShape)
       return;  // bad shape
@@ -255,7 +324,26 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
     TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
     if (aShapeNew.IsNull())
       return;  // null shape inside
-    aBuilder->Modify(aShapeOld, aShapeNew);
+
+    // There is no sense to write history if old shape does not exist in the document.
+    TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
+      ModelAPI_Session::get()->moduleDocument())->generalLabel();
+    TDF_Label anOriginalLabel;
+    if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeOld, anOriginalLabel)) {
+      if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway
+        aBuilder->Generated(aShapeNew);
+      }
+    } else {
+      if (aBuilder->NamedShape()->Evolution() == TNaming_PRIMITIVE) { // erase primitive before
+        myBuilders.erase(0);
+        aBuilder = builder(0);
+      }
+
+      aBuilder->Modify(aShapeOld, aShapeNew);
+      // store information about the external document reference to restore old shape on open
+      storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
+    }
+
     if(!aBuilder->NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
       if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
@@ -276,21 +364,44 @@ void Model_BodyBuilder::storeModified(const std::list<GeomShapePtr>& theOldShape
   bool aStored = false;
   std::list<GeomShapePtr>::const_iterator anOldIter = theOldShapes.cbegin();
   for(; anOldIter != theOldShapes.cend(); anOldIter++) {
-    ListOfShape aNews; // check this old really modifies theNewShape
-    theMakeShape->modified(*anOldIter, aNews);
-    ListOfShape::iterator aNewIter = aNews.begin();
-    for(; aNewIter != aNews.end(); aNewIter++) {
-      if (theNewShape->isSame(*aNewIter))
-        break;
+    // compounds may cause crash if call "modified"
+    bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire();
+    if (!aStore) {
+      ListOfShape aNews; // check this old really modifies theNewShape
+      theMakeShape->modified(*anOldIter, aNews);
+      ListOfShape::iterator aNewIter = aNews.begin();
+      for(; aNewIter != aNews.end(); aNewIter++) {
+        if (theNewShape->isSame(*aNewIter))
+          break;
+      }
+      aStore = aNewIter != aNews.end();
     }
-    if (aNewIter != aNews.end()) {
+    if (aStore) {
       storeModified(*anOldIter, theNewShape, !aStored);
       TNaming_Builder* aBuilder = builder(0);
       aStored = !aBuilder->NamedShape()->IsEmpty();
     }
   }
-  if (!aStored) { // store as PRIMITIVE, but clean in any way
-    store(theNewShape);
+  if (!aStored) {
+    // check the new shape is already in the tree, so, no need to store primitive, just reference
+    std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
+    if (aData.get()) {
+      TDF_Label aShapeLab = aData->shapeLab();
+      TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
+      Handle(TNaming_NamedShape) aNS;
+      if (TNaming_Tool::HasLabel(aShapeLab, aShapeNew))
+        aNS = TNaming_Tool::NamedShape(aShapeNew, aShapeLab);
+      // the last condition is for the issue 2751 : existing shape may be found in compound-NS
+      if (!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShapeNew)) {
+        // This shape is already in document, store reference instead of shape;
+        const TDF_Label aFoundLabel = aNS->Label();
+        TDF_Reference::Set(aShapeLab, aFoundLabel);
+        myBuilders.erase(0);
+        aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID());
+        return;
+      }
+    }
+    store(theNewShape); // store as PRIMITIVE, but clean in any way
     return;
   }
 }
@@ -482,53 +593,6 @@ static void keepTopLevelShapes(ListOfShape& theShapes,
   }
 }
 
-/// Checks that shape is presented in the tree with not-selection evolution
-/// In theOriginalLabel it returns label where NS of old sub-shape is stored
-static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAccess2,
-  TopoDS_Shape theShape, TDF_Label& theOriginalLabel)
-{
-  bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape);
-  if (aResult) { //check evolution and a label of this shape
-    for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next())
-    {
-      static Handle(TNaming_NamedShape) aNS;
-      if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
-        if (aNS->Evolution() != TNaming_SELECTED) {
-          theOriginalLabel = aNS->Label();
-          return true;
-        }
-      }
-    }
-  }
-  if (!theAccess2.IsNull()) {
-    static const TDF_Label anEmpty;
-    return isShapeInTree(theAccess2, anEmpty, theShape, theOriginalLabel);
-  }
-  return false;
-}
-
-/// Stores entry to the external label in the entries list at this label
-static void storeExternalReference(const TDF_Label& theExternal, const TDF_Label theThis)
-{
-  // store information about the external document reference to restore old shape on open
-  if (!theExternal.IsNull() && !theExternal.Root().IsEqual(theThis.Root())) {
-    Handle(TDataStd_ExtStringList) anEntries;
-    if (!theThis.FindAttribute(kEXTERNAL_SHAPE_REF, anEntries)) {
-      anEntries = TDataStd_ExtStringList::Set(theThis, kEXTERNAL_SHAPE_REF);
-    }
-    TCollection_AsciiString anEntry;
-    TDF_Tool::Entry(theExternal, anEntry);
-    // check it already contains this entry
-    TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List());
-    for(; anIter.More(); anIter.Next())
-      if (anIter.Value() == anEntry)
-        break;
-    if (!anIter.More()) {
-      anEntries->Append(anEntry);
-    }
-  }
-}
-
 void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
                                            const GeomShapePtr& theOldShape,
                                            const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
@@ -602,7 +666,8 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
 void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
                                             const GeomShapePtr& theOldShape,
                                             const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
-                                            const std::string& theName)
+                                            const std::string& theName,
+                                            const bool theSaveOldIfNotInTree)
 {
   GeomShapePtr aResultShape = shape();
   TopTools_MapOfShape anAlreadyProcessedShapes;
@@ -623,7 +688,11 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
     bool anOldSubShapeNotInTree =
       !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
     if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
-      continue;
+      if (theSaveOldIfNotInTree) {
+        std::string aSelectionName = theName + "Selected";
+        generated(anOldSubShape, aSelectionName, false);
+      } else
+        continue;
     }
 
     // Get new shapes.
@@ -645,6 +714,9 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
         continue;
       }
 
+      if (aResultShape->isSame(aNewShape))
+        continue; // it is stored on the root level
+
       TopAbs_ShapeEnum aNewShapeType = aNewShape_.ShapeType();
       if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
         // TODO: This is a workaround. New shape should be only edge or face.