Salome HOME
Useful commits from master and V8_5_0
[modules/shaper.git] / src / Model / Model_BodyBuilder.cpp
index 4209b2401ccbf509f25e120e8ecc6a8fc593d574..1a8ea5507f9518ca3810ac4bb6ba615e21bbfe6d 100755 (executable)
@@ -49,6 +49,7 @@
 #include <BRep_Tool.hxx>
 #include <GeomAPI_Shape.h>
 #include <GeomAlgoAPI_MakeShape.h>
+#include <GeomAlgoAPI_SortListOfShapes.h>
 #include <Config_PropManager.h>
 // DEB
 //#include <TCollection_AsciiString.hxx>
@@ -94,7 +95,12 @@ static void evolutionToSelectionRec(TDF_Label theLab, const bool theFlag) {
     std::list<std::pair<TopoDS_Shape, TopoDS_Shape> >::iterator aPairsIter = aShapePairs.begin();
     for(; aPairsIter != aShapePairs.end(); aPairsIter++) {
       if (theFlag) { // disabled => make selection
-        aBuilder.Select(aPairsIter->second, aPairsIter->first);
+        if (anEvolution == TNaming_DELETE) // issue 2274 : don't put too many same null shapes
+          aBuilder.Select(aPairsIter->first, aPairsIter->first);
+        else if (anEvolution == TNaming_PRIMITIVE)
+          aBuilder.Select(aPairsIter->second, aPairsIter->second);
+        else
+          aBuilder.Select(aPairsIter->second, aPairsIter->first);
       } else if (anEvol == TNaming_GENERATED) {
         aBuilder.Generated(aPairsIter->first, aPairsIter->second);
       } else if (anEvol == TNaming_MODIFY) {
@@ -209,7 +215,8 @@ void Model_BodyBuilder::storeModified(const std::shared_ptr<GeomAPI_Shape>& theO
   if (aData) {
     TDF_Label& aShapeLab = aData->shapeLab();
     // clean builders
-    clean();
+    if (theDecomposeSolidsTag != -2)
+      clean();
     // store the new shape as primitive
     TNaming_Builder aBuilder(aShapeLab);
     if (!theOldShape || !theNewShape)
@@ -265,6 +272,8 @@ void Model_BodyBuilder::clean()
     }
   }
   myBuilders.clear();
+  // remove the old reference (if any)
+  aLab.ForgetAttribute(TDF_Reference::GetID());
 }
 
 Model_BodyBuilder::~Model_BodyBuilder()
@@ -277,7 +286,8 @@ 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(aData->shapeLab().FindChild(theTag));
+    myBuilders[theTag] = new TNaming_Builder(
+      theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag));
     aFind = myBuilders.find(theTag);
   }
   return aFind->second;
@@ -350,17 +360,63 @@ void Model_BodyBuilder::loadDeletedShapes (GeomAlgoAPI_MakeShape* theMS,
   TopoDS_Shape aShapeIn = theShapeIn->impl<TopoDS_Shape>();
   TopTools_MapOfShape aView;
   TopExp_Explorer ShapeExplorer (aShapeIn, (TopAbs_ShapeEnum)theKindOfShape);
+  GeomShapePtr aResultShape = shape();
   for (; ShapeExplorer.More(); ShapeExplorer.Next ()) {
     const TopoDS_Shape& aRoot = ShapeExplorer.Current ();
     if (!aView.Add(aRoot)) continue;
     std::shared_ptr<GeomAPI_Shape> aRShape(new GeomAPI_Shape());
     aRShape->setImpl((new TopoDS_Shape(aRoot)));
     if (theMS->isDeleted (aRShape)) {
-      builder(theTag)->Delete(aRoot);
+      if (!aResultShape->isSubShape(aRShape, false)) {
+          ListOfShape aHist;
+          theMS->modified(aRShape, aHist);
+          if (aHist.size() == 0 || (aHist.size() == 1 && aHist.front()->isSame(aRShape)))
+            builder(theTag)->Delete(aRoot);
+      }
+    }
+  }
+}
+
+// Keep only the shapes with minimal shape type
+static void keepTopLevelShapes(ListOfShape& theShapes, const TopoDS_Shape& theRoot,
+  const GeomShapePtr& theResultShape = GeomShapePtr())
+{
+  GeomAPI_Shape::ShapeType aKeepShapeType = GeomAPI_Shape::SHAPE;
+  ListOfShape::iterator anIt = theShapes.begin();
+  while (anIt != theShapes.end()) {
+    TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
+    bool aSkip = aNewShape.IsNull() ||
+      (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape)));
+    if (aSkip || theRoot.IsSame(aNewShape) || (theResultShape &&
+        (!theResultShape->isSubShape(*anIt, false) || theResultShape->isSame(*anIt)))) {
+      ListOfShape::iterator aRemoveIt = anIt++;
+      theShapes.erase(aRemoveIt);
+    } else {
+      GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType();
+      if (aType < aKeepShapeType) {
+        // found a shape with lesser shape type => remove all previous shapes
+        aKeepShapeType = aType;
+        theShapes.erase(theShapes.begin(), anIt);
+        ++anIt;
+      } else if (aType > aKeepShapeType) {
+        // shapes with greater shape type should be removed from the list
+        ListOfShape::iterator aRemoveIt = anIt++;
+        theShapes.erase(aRemoveIt);
+      } else
+        ++anIt;
     }
   }
 }
 
+// returns an ancestor shape-type thaty used for naming-definition of the sub-type
+TopAbs_ShapeEnum typeOfAncestor(const TopAbs_ShapeEnum theSubType) {
+  if (theSubType == TopAbs_VERTEX)
+    return TopAbs_EDGE;
+  if (theSubType == TopAbs_EDGE)
+    return TopAbs_FACE;
+  return TopAbs_VERTEX; // bad case
+}
+
 void Model_BodyBuilder::loadAndOrientModifiedShapes (
   GeomAlgoAPI_MakeShape* theMS,
   std::shared_ptr<GeomAPI_Shape>  theShapeIn,
@@ -379,16 +435,29 @@ void Model_BodyBuilder::loadAndOrientModifiedShapes (
   GeomShapePtr aResultShape = shape();
   TopoDS_Shape aShapeIn = theShapeIn->impl<TopoDS_Shape>();
   TopTools_MapOfShape aView;
+  std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
   TopExp_Explorer aShapeExplorer (aShapeIn, (TopAbs_ShapeEnum)theKindOfShape);
   for (; aShapeExplorer.More(); aShapeExplorer.Next ()) {
     const TopoDS_Shape& aRoot = aShapeExplorer.Current ();
     if (!aView.Add(aRoot)) continue;
-    if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull())
-      continue; // there is no sence to write history is old shape does not persented in document
+
+    bool aNotInTree =
+      TNaming_Tool::NamedShape(aRoot, aData->shapeLab()).IsNull();
+    if (aNotInTree && !theIsStoreSeparate) {
+      // there is no sense to write history if old shape does not exist in the document
+      continue; // but if it is stored separately, it will be builded as a primitive
+    }
     ListOfShape aList;
     std::shared_ptr<GeomAPI_Shape> aRShape(new GeomAPI_Shape());
     aRShape->setImpl((new TopoDS_Shape(aRoot)));
     theMS->modified(aRShape, aList);
+    if (!theIsStoreSeparate)
+      keepTopLevelShapes(aList, aRoot, aResultShape);
+    // sort the list of images before naming
+    GeomAlgoAPI_SortListOfShapes::sort(aList);
+
+    // to trace situation where several objects are produced by one parent (#2317)
+    int aSameParentShapes = -1;
     std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator
       anIt = aList.begin(), aLast = aList.end();
     for (; anIt != aLast; anIt++) {
@@ -399,26 +468,97 @@ void Model_BodyBuilder::loadAndOrientModifiedShapes (
       }
       GeomShapePtr aGeomNewShape(new GeomAPI_Shape());
       aGeomNewShape->setImpl(new TopoDS_Shape(aNewShape));
-      if(!aRoot.IsSame(aNewShape) && aResultShape->isSubShape(aGeomNewShape)) {
+      if(!aRoot.IsSame(aNewShape) && aResultShape->isSubShape(aGeomNewShape, false) &&
+         !aResultShape->isSame(*anIt)) { // to avoid put of same shape on main label and sub
+        int aBuilderTag = aTag;
+        if (!theIsStoreSeparate) {
+          aSameParentShapes++;
+        } else if (aNotInTree) { // check this new shape can not be represented as
+          // a sub-shape of higher level sub-shapes
+          TopAbs_ShapeEnum aNewType = aNewShape.ShapeType();
+          TopAbs_ShapeEnum anAncestorType = typeOfAncestor(aNewType);
+          if (anAncestorType != TopAbs_VERTEX) {
+            bool aFound = false;
+            TopoDS_Shape aResultTShape = aResultShape->impl<TopoDS_Shape>();
+            TopExp_Explorer anAncestorExp(aResultTShape, anAncestorType);
+            for(; anAncestorExp.More() && !aFound; anAncestorExp.Next()) {
+              if (aResultTShape.IsSame(anAncestorExp.Current()))
+                continue;
+              TopExp_Explorer aSubExp(anAncestorExp.Current(), aNewType);
+              for(; aSubExp.More(); aSubExp.Next()) {
+                if (aNewShape.IsSame(aSubExp.Current())) {
+                  aFound = true;
+                  break;
+                }
+              }
+            }
+            if (aFound) {
+              continue; // not need to store this shape in the BRep structure
+            }
+          }
+        }
+
+        static const int THE_ANCHOR_TAG = 100000;
+        int aCurShapeType = (int)((*anIt)->shapeType());
+        bool needSuffix = false; // suffix for the name based on the shape type
+        if (aSameParentShapes > 0) { // store in other label
+          aBuilderTag = THE_ANCHOR_TAG - aSameParentShapes * 10 - aCurShapeType;
+          needSuffix = true;
+        } else if (aCurShapeType != theKindOfShape) {
+          // modified shape has different type => set another tag
+          // to avoid shapes of different types on the same label
+          aBuilderTag = THE_ANCHOR_TAG - aCurShapeType;
+          needSuffix = true;
+        }
+        std::string aSuffix;
+        if (needSuffix) {
+          switch (aCurShapeType) {
+          case GeomAPI_Shape::VERTEX: aSuffix = "_v"; break;
+          case GeomAPI_Shape::EDGE:   aSuffix = "_e"; break;
+          case GeomAPI_Shape::FACE:   aSuffix = "_f"; break;
+          default: break;
+          }
+        }
+
         if(theIsStoreAsGenerated) {
           // Here we store shapes as generated, to avoid problem when one parent shape produce
           // several child shapes. In this case naming could not determine which shape to select.
-          builder(aTag)->Generated(aRoot,aNewShape);
+          builder(aBuilderTag)->Generated(aRoot, aNewShape);
+        } else if (aNotInTree) {
+          // not in tree -> store as primitive (stored as separated)
+          builder(aBuilderTag)->Generated(aNewShape);
+        } else if (aNewShape.ShapeType() > aRoot.ShapeType()) {
+           // if lower-level type is produced, make it as generated
+          builder(aBuilderTag)->Generated(aRoot, aNewShape);
         } else {
-          builder(aTag)->Modify(aRoot,aNewShape);
+          builder(aBuilderTag)->Modify(aRoot, aNewShape);
         }
         if(isBuilt) {
-          if(theIsStoreSeparate) {
+          aStream.str(std::string());
+          aStream.clear();
+          aStream << theName;
+          if(theIsStoreSeparate)
+             aStream << "_" << anIndex++;
+
+          if (aSameParentShapes > 0) {
             aStream.str(std::string());
             aStream.clear();
-            aStream << theName << "_" << anIndex++;
-            aName = aStream.str();
+            aStream << aName << "_" << aSameParentShapes << "divided";
           }
-          buildName(aTag, aName);
+
+          aStream << aSuffix;
+          buildName(aBuilderTag, aStream.str());
         }
         if(theIsStoreSeparate) {
           aTag++;
         }
+      } else if (aResultShape->isSame(*anIt)) {
+        // keep the modification evolution on the root level (2241 - history propagation issue)
+        if(theIsStoreAsGenerated) {
+          builder(0)->Generated(aRoot, aNewShape);
+        } else {
+          builder(0)->Modify(aRoot, aNewShape);
+        }
       }
     }
   }
@@ -439,12 +579,13 @@ void Model_BodyBuilder::loadAndOrientGeneratedShapes (
   for (; aShapeExplorer.More(); aShapeExplorer.Next ()) {
     const TopoDS_Shape& aRoot = aShapeExplorer.Current ();
     if (!aView.Add(aRoot)) continue;
-    if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull())
-      continue; // there is no sence to write history is old shape does not persented in document
+    //if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull())
+    //  continue; // there is no sense to write history if old shape does not exist in the document
     ListOfShape aList;
     std::shared_ptr<GeomAPI_Shape> aRShape(new GeomAPI_Shape());
     aRShape->setImpl((new TopoDS_Shape(aRoot)));
     theMS->generated(aRShape, aList);
+    keepTopLevelShapes(aList, aRoot);
     std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator
       anIt = aList.begin(), aLast = aList.end();
     for (; anIt != aLast; anIt++) {