]> SALOME platform Git repositories - modules/shaper.git/blobdiff - src/Model/Model_BodyBuilder.cpp
Salome HOME
Updated copyright comment
[modules/shaper.git] / src / Model / Model_BodyBuilder.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 04c4059..d397d0a
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2024  CEA, EDF
 //
 // 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>
 
+#include <Locale_Convert.h>
+
 #include <Model_Data.h>
 #include <Model_Document.h>
 #include <ModelAPI_Session.h>
@@ -80,6 +81,7 @@ static int getGenerationTag(const TopoDS_Shape& theShape) {
     case TopAbs_VERTEX: return GENERATED_VERTICES_TAG;
     case TopAbs_EDGE:   return GENERATED_EDGES_TAG;
     case TopAbs_FACE:   return GENERATED_FACES_TAG;
+    default: break; // [to avoid compilation warning]
   }
 
   return INVALID_TAG;
@@ -91,6 +93,7 @@ static int getModificationTag(const TopoDS_Shape& theShape) {
     case TopAbs_VERTEX: return MODIFIED_VERTICES_TAG;
     case TopAbs_EDGE:   return MODIFIED_EDGES_TAG;
     case TopAbs_FACE:   return MODIFIED_FACES_TAG;
+    default: break; // [to avoid compilation warning]
   }
 
   return INVALID_TAG;
@@ -129,7 +132,7 @@ static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAcces
   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;
+      Handle(TNaming_NamedShape) aNS;
       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
         if (aNS->Evolution() != TNaming_SELECTED) {
           theOriginalLabel = aNS->Label();
@@ -184,7 +187,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;
@@ -201,7 +206,7 @@ void Model_BodyBuilder::store(const GeomShapePtr& theShape,
     if(!aBuilder.NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
       if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
-        std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
+        std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString());
         if(!aName.empty()) {
           std::shared_ptr<Model_Document> aDoc =
             std::dynamic_pointer_cast<Model_Document>(document());
@@ -217,7 +222,6 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
 {
   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
   if (aData) {
-    TDF_Label aShapeLab = aData->shapeLab();
     // clean builders
     if (theIsCleanStored)
       clean();
@@ -254,7 +258,7 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
     if(!aBuilder->NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
       if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
-        std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
+        std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString());
         if(!aName.empty()) {
           std::shared_ptr<Model_Document> aDoc =
             std::dynamic_pointer_cast<Model_Document>(document());
@@ -294,13 +298,17 @@ void Model_BodyBuilder::storeGenerated(const std::list<GeomShapePtr>& theFromSha
   }
 }
 
+static TDF_Label builderLabel(DataPtr theData, const int theTag )
+{
+  std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theData);
+  return theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag);
+}
+
 TNaming_Builder* Model_BodyBuilder::builder(const int theTag)
 {
   std::map<int, TNaming_Builder*>::iterator aFind = myBuilders.find(theTag);
   if (aFind == myBuilders.end()) {
-    std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
-    myBuilders[theTag] = new TNaming_Builder(
-      theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag));
+    myBuilders[theTag] = new TNaming_Builder(builderLabel(data(), theTag));
     aFind = myBuilders.find(theTag);
   }
   return aFind->second;
@@ -328,7 +336,23 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
     TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
       ModelAPI_Session::get()->moduleDocument())->generalLabel();
     TDF_Label anOriginalLabel;
+    TopTools_ListOfShape anOldList;
     if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeOld, anOriginalLabel)) {
+      // check this could be a compund by the whole feature selection
+      if (aShapeOld.ShapeType() == TopAbs_COMPOUND)  {
+        for(TopoDS_Iterator aCompIter(aShapeOld); aCompIter.More(); aCompIter.Next()) {
+          if (isShapeInTree(aData->shapeLab(), anAccess2, aCompIter.Value(), anOriginalLabel)) {
+            anOldList.Append(aCompIter.Value());
+          } else {
+            anOldList.Clear();
+            break;
+          }
+        }
+      }
+    } else {
+      anOldList.Append(aShapeOld);
+    }
+    if (anOldList.IsEmpty()) {
       if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway
         aBuilder->Generated(aShapeNew);
       }
@@ -337,8 +361,10 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
         myBuilders.erase(0);
         aBuilder = builder(0);
       }
-
-      aBuilder->Modify(aShapeOld, aShapeNew);
+      TopTools_ListIteratorOfListOfShape anOldIter(anOldList);
+      for(; anOldIter.More(); anOldIter.Next()) {
+        aBuilder->Modify(anOldIter.Value(), aShapeNew);
+      }
       // store information about the external document reference to restore old shape on open
       storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
     }
@@ -346,7 +372,7 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
     if(!aBuilder->NamedShape()->IsEmpty()) {
       Handle(TDataStd_Name) anAttr;
       if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
-        std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
+        std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString());
         if(!aName.empty()) {
           std::shared_ptr<Model_Document> aDoc =
             std::dynamic_pointer_cast<Model_Document>(document());
@@ -364,7 +390,8 @@ void Model_BodyBuilder::storeModified(const std::list<GeomShapePtr>& theOldShape
   std::list<GeomShapePtr>::const_iterator anOldIter = theOldShapes.cbegin();
   for(; anOldIter != theOldShapes.cend(); anOldIter++) {
     // compounds may cause crash if call "modified"
-    bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire();
+    bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire() ||
+               (*anOldIter)->isCompSolid();
     if (!aStore) {
       ListOfShape aNews; // check this old really modifies theNewShape
       theMakeShape->modified(*anOldIter, aNews);
@@ -381,8 +408,26 @@ void Model_BodyBuilder::storeModified(const std::list<GeomShapePtr>& theOldShape
       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;
   }
 }
@@ -434,7 +479,7 @@ void Model_BodyBuilder::buildName(const int theTag, const std::string& theName)
   }
   aName.insert(0, aPrefix);
 
-  TDataStd_Name::Set(builder(theTag)->NamedShape()->Label(), aName.c_str());
+  TDataStd_Name::Set(builderLabel(data(), theTag), aName.c_str());
 }
 bool Model_BodyBuilder::generated(const GeomShapePtr& theNewShape,
                                   const std::string& theName,
@@ -484,7 +529,7 @@ void Model_BodyBuilder::generated(const GeomShapePtr& theOldShape,
   if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
     // TODO: This is a workaround. New shape should be only vertex, edge or face.
     TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE;
-    aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
+    aTag = aNewShapeType == TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
     for (TopExp_Explorer anExp(aNewShape, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
       builder(aTag)->Generated(anOldShape, anExp.Current());
     }
@@ -589,6 +634,11 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
     if (aCompound.get()) aShapeToExplore = aCompound;
   }
 
+  // Store all types of subshapes in the map to use them for checking
+  // if the new shapes are sub-shapes of this result
+  TopTools_MapOfShape aResultShapeSubMap;
+  TopExp::MapShapes(aResultShape->impl<TopoDS_Shape>(), aResultShapeSubMap);
+
   TopTools_MapOfShape anAlreadyProcessedShapes;
   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
   for (GeomAPI_ShapeExplorer anOldShapeExp(aShapeToExplore, theShapeTypeToExplore);
@@ -600,36 +650,40 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
 
     // There is no sense to write history if shape already processed
     // or old shape does not exist in the document.
-    bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
-    TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
-      ModelAPI_Session::get()->moduleDocument())->generalLabel();
+    if (!anAlreadyProcessedShapes.Add(anOldSubShape_))
+    {
+      continue;
+    }
+
+    TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(ModelAPI_Session::get()->moduleDocument())->generalLabel();
     TDF_Label anOriginalLabel;
-    bool anOldSubShapeNotInTree =
-      !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
-    if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
+    if (!isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel))
+    {
       continue;
     }
 
     // Get new shapes.
     ListOfShape aNewShapes;
     theAlgo->modified(anOldSubShape, aNewShapes);
-
     for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
          aNewShapesIt != aNewShapes.cend();
          ++aNewShapesIt)
     {
       GeomShapePtr aNewShape = *aNewShapesIt;
       const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
-      bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
 
-      bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
-      bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
-      if (aNewShapeIsSameAsOldShape || aNewShapeIsNotInResultShape)
+      if (anOldSubShape->isSame(aNewShape))
         continue;
 
       if (aResultShape->isSame(aNewShape))
         continue; // it is stored on the root level (2241 - history propagation issue)
 
+      // Look in the map instead of aResultShape->isSubShape(aNewShape, false)
+      // to avoid many iterations of sub-shapes hierarchy that leads to performance issues
+      if (!aResultShapeSubMap.Contains(aNewShape_))
+        continue;
+
+      const bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
       int aTag = isGenerated ? getGenerationTag(aNewShape_) : getModificationTag(aNewShape_);
       TNaming_Builder*aBuilder = builder(aTag);
       if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_))
@@ -647,7 +701,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;
@@ -668,7 +723,13 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
     bool anOldSubShapeNotInTree =
       !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
     if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
-      continue;
+      // The second condition is added due to #20170 because sub-shape must be added to real parent
+      // shape, not the reference. The naming name of pure reference is not registered in document.
+      if (theSaveOldIfNotInTree && !aData->shapeLab().IsAttribute(TDF_Reference::GetID())) {
+        std::string aSelectionName = theName + "Selected";
+        generated(anOldSubShape, aSelectionName, false);
+      } else
+        continue;
     }
 
     // Get new shapes.
@@ -690,16 +751,19 @@ 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.
         TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE
                                                                             : TopAbs_FACE;
-        int aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
+        int aTag = aNewShapeType == TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
         for (TopExp_Explorer anExp(aNewShape_, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
           builder(aTag)->Generated(anOldSubShape_, anExp.Current());
           // store information about the external document reference to restore old shape on open
-          storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label());
+          storeExternalReference(anOriginalLabel, builderLabel(data(), aTag));
         }
         buildName(aTag, theName);
       } else {
@@ -708,7 +772,7 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
         builder(aTag)->Generated(anOldSubShape_, aNewShape_);
         buildName(aTag, theName);
         // store information about the external document reference to restore old shape on open
-        storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label());
+        storeExternalReference(anOriginalLabel, builderLabel(data(), aTag));
       }
     }
   }
@@ -908,8 +972,12 @@ int findAmbiguities(const TopoDS_Shape&           theShapeIn,
 //=======================================================================
 void Model_BodyBuilder::loadFirstLevel(GeomShapePtr theShape, const std::string& theName)
 {
-  if(theShape->isNull()) return;
-  TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
+  GeomShapePtr aShapePtr = shape();
+  if (theShape->isNull() || !aShapePtr.get())
+    return;
+  TopoDS_Shape aShape = shape()->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return;
   std::string aName;
   if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) {
     TopoDS_Iterator itr(aShape);