Salome HOME
Issue #2593: CEA 2018-2 Geometrical Naming
[modules/shaper.git] / src / ModelHighAPI / ModelHighAPI_Dumper.cpp
index 5142efc3185f74979a58424b4479ad8196420c42..7e33d61fea254dd264a0e249f7b433ff07f18ddf 100644 (file)
@@ -25,6 +25,8 @@
 #include <GeomAPI_Pnt.h>
 #include <GeomAPI_Dir.h>
 #include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_ShapeIterator.h>
+#include <GeomAlgoAPI_NExplode.h>
 
 #include <GeomDataAPI_Dir.h>
 #include <GeomDataAPI_Point.h>
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_ResultPart.h>
+#include <ModelAPI_Session.h>
 #include <ModelAPI_Tools.h>
 
+#include <ModelGeomAlgo_Shape.h>
+
 #include <PartSetPlugin_Part.h>
 
 #include <OSD_OpenFile.hxx>
@@ -64,6 +69,7 @@ static int gCompositeStackDepth = 0;
 ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0;
 
 ModelHighAPI_Dumper::ModelHighAPI_Dumper()
+  : myGeometricalSelection(false)
 {
   clear();
 }
@@ -160,6 +166,17 @@ const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity,
       if (aNbFeatures.first == anId && aNbFeatures.second < anId) {
         // name is not user-defined
         isDefaultName = true;
+
+        // check there are postponed features of this kind,
+        // dump their names, because the sequence of features may be changed
+        for (std::list<EntityPtr>::const_iterator aPpIt = myPostponed.begin();
+            aPpIt != myPostponed.end(); ++aPpIt) {
+          FeaturePtr aCurFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aPpIt);
+          if (aCurFeature && aCurFeature->getKind() == aKind) {
+            myNames[*aPpIt].myIsDefault = false;
+            isDefaultName = false;
+          }
+        }
       }
 
       if (anId > aNbFeatures.second)
@@ -561,12 +578,28 @@ bool ModelHighAPI_Dumper::isDumped(const AttributeRefListPtr& theRefList) const
   return true;
 }
 
+static bool isSketchSub(const FeaturePtr& theFeature)
+{
+  static const std::string SKETCH("Sketch");
+  CompositeFeaturePtr anOwner = ModelAPI_Tools::compositeOwner(theFeature);
+  return anOwner && anOwner->getKind() == SKETCH;
+}
+
 bool ModelHighAPI_Dumper::isDefaultColor(const ResultPtr& theResult) const
 {
   AttributeIntArrayPtr aColor = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
   if (!aColor || !aColor->isInitialized())
     return true;
 
+  // check the result belongs to sketch entity, do not dump color in this way
+  ResultConstructionPtr aResConstr =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theResult);
+  if (aResConstr) {
+    FeaturePtr aFeature = ModelAPI_Feature::feature(theResult->data()->owner());
+    if (isSketchSub(aFeature))
+      return true;
+  }
+
   std::string aSection, aName, aDefault;
   theResult->colorConfigInfo(aSection, aName, aDefault);
 
@@ -787,16 +820,24 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ResultPtr& theResult)
 {
   // iterate in the structure of sub-results to the parent
   ResultPtr aCurRes = theResult;
+  FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
   std::list<int> anIndices; // indexes of results in the parent result, starting from topmost
   while(aCurRes.get()) {
     ResultBodyPtr aParent = ModelAPI_Tools::bodyOwner(aCurRes);
     if (aParent) {
       anIndices.push_front(ModelAPI_Tools::bodyIndex(aCurRes));
+    } else { // index of the result in the feature
+      std::list<ResultPtr>::const_iterator aRes = aFeature->results().cbegin();
+      for(int anIndex = 0; aRes != aFeature->results().cend(); aRes++, anIndex++) {
+        if (*aRes == aCurRes) {
+          anIndices.push_front(anIndex);
+          break;
+        }
+      }
     }
     aCurRes = aParent;
   }
 
-  FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
   myDumpBuffer << name(aFeature);
   for (std::list<int>::iterator anI = anIndices.begin(); anI != anIndices.end(); anI++) {
     if (anI == anIndices.begin()) {
@@ -926,6 +967,76 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
   return *this;
 }
 
+static int possibleSelectionsByPoint(const GeomPointPtr& thePoint,
+                                     const ResultPtr& theResult,
+                                     const GeomShapePtr& theShape,
+                                     const FeaturePtr& theStartFeature,
+                                     const FeaturePtr& theEndFeature)
+{
+  DocumentPtr aDoc1 = theStartFeature->document();
+  DocumentPtr aDoc2 = theEndFeature->document();
+
+  std::list<FeaturePtr> aFeatures = aDoc1->allFeatures();
+  if (aDoc1 != aDoc2) {
+    std::list<FeaturePtr> anAdditionalFeatures = aDoc2->allFeatures();
+    aFeatures.insert(aFeatures.end(), anAdditionalFeatures.begin(), anAdditionalFeatures.end());
+  }
+
+  CompositeFeaturePtr aLastCompositeFeature;
+
+  std::list<FeaturePtr>::const_iterator aFIt = aFeatures.begin();
+  while (aFIt != aFeatures.end() && *aFIt != theStartFeature) {
+    CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFIt);
+    if (aCompFeat)
+      aLastCompositeFeature = aCompFeat;
+    ++aFIt;
+  }
+
+  // collect the list of composite features, containing the last feature;
+  // these features should be excluded from searching,
+  // because the feature cannot select sub-shapes from its parent
+  std::set<FeaturePtr> aEndFeatureParents = ModelAPI_Tools::getParents(theEndFeature);
+
+  int aNbPossibleSelections = 0;
+  for (; aFIt != aFeatures.end() && *aFIt != theEndFeature; ++aFIt) {
+    bool isSkipFeature = false;
+    if (aLastCompositeFeature && aLastCompositeFeature->isSub(*aFIt))
+      isSkipFeature = true;
+    CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFIt);
+    if (aCompFeat) {
+      ResultPartPtr aPartRes =
+          std::dynamic_pointer_cast<ModelAPI_ResultPart>(aCompFeat->firstResult());
+      if (!aPartRes)
+        aLastCompositeFeature = aCompFeat;
+      if (aEndFeatureParents.find(aCompFeat) != aEndFeatureParents.end()) {
+        // do not process the parent for the last feature,
+        // because it cannot select objects from its parent
+        isSkipFeature = true;
+      }
+    }
+    if (isSkipFeature)
+      continue;
+
+    std::list<ModelGeomAlgo_Shape::SubshapeOfResult> anApproproate;
+    if (ModelGeomAlgo_Shape::findSubshapeByPoint(*aFIt, thePoint, theShape->shapeType(),
+                                                 anApproproate)) {
+      std::list<ModelGeomAlgo_Shape::SubshapeOfResult>::iterator anApIt = anApproproate.begin();
+      for (; anApIt != anApproproate.end(); ++anApIt) {
+        ++aNbPossibleSelections;
+
+        // stop if the target shape and result are found
+        GeomShapePtr aCurShape = anApIt->mySubshape;
+        if (!aCurShape)
+          aCurShape = anApIt->myResult->shape();
+
+        if (anApIt->myResult->isSame(theResult) && aCurShape->isSame(theShape))
+          break;
+      }
+    }
+  }
+  return aNbPossibleSelections;
+}
+
 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
     const std::shared_ptr<ModelAPI_AttributeSelection>& theAttrSelect)
 {
@@ -946,8 +1057,61 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
     return *this;
   }
 
-  myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" <<
-    theAttrSelect->namingName() << "\")";
+  // how to dump selection: construction features are dumped by name always
+  bool isDumpByGeom = myGeometricalSelection;
+  FeaturePtr aSelectedFeature;
+  if (isDumpByGeom) {
+    ResultPtr aRes = theAttrSelect->context();
+    FeaturePtr aFeature = theAttrSelect->contextFeature();
+    if (aRes && !aFeature)
+      aSelectedFeature = ModelAPI_Feature::feature(aRes->data()->owner());
+    isDumpByGeom = aSelectedFeature && aSelectedFeature->isInHistory();
+  }
+
+  if (theAttrSelect->isGeometricalSelection() && aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
+    GeomAPI_ShapeIterator anIt(aShape);
+    aShape = anIt.current();
+  }
+
+  myDumpBuffer << "\"" << aShape->shapeTypeStr();
+  bool aStandardDump = true;
+  if (isDumpByGeom) {
+    // check the selected item is a ResultPart;
+    // in this case it is necessary to get shape with full transformation
+    // for correct calculation of the middle point
+    ResultPartPtr aResPart =
+        std::dynamic_pointer_cast<ModelAPI_ResultPart>(theAttrSelect->context());
+    if (aResPart && aShape->shapeType() == GeomAPI_Shape::COMPOUND)
+      aShape = aResPart->shape();
+    GeomPointPtr aMiddlePoint = aShape->middlePoint();
+    // calculate number of features, which could be selected by the same point
+    FeaturePtr anOwner = ModelAPI_Feature::feature(theAttrSelect->owner());
+    int aNbPossibleSelections = possibleSelectionsByPoint(aMiddlePoint,
+        theAttrSelect->context(), aShape, aSelectedFeature, anOwner);
+
+    // produce the index if the number of applicable features is greater than 1
+    std::string anIndex;
+    if (aNbPossibleSelections > 1) {
+      std::ostringstream anOutput;
+      anOutput << "_" << aNbPossibleSelections;
+      anIndex = anOutput.str();
+    }
+
+    myDumpBuffer << anIndex << "\", ";
+    *this << aMiddlePoint;
+    aStandardDump = false;
+  } if (myWeakNamingSelection && aShape.get() && theAttrSelect->context().get() &&
+       aShape != theAttrSelect->context()->shape()) { // weak naming for local selection only
+    GeomAlgoAPI_NExplode aNExplode(theAttrSelect->context()->shape(), aShape->shapeType());
+    int anIndex = aNExplode.index(aShape);
+    if (anIndex != 0) { // found a week-naming index, so, export it
+      myDumpBuffer<<"\", \""<<theAttrSelect->context()->data()->name()<<"\", "<<anIndex;
+      aStandardDump = false;
+    }
+  }
+  if (aStandardDump)
+    myDumpBuffer << "\", \"" << theAttrSelect->namingName() << "\"";
+  myDumpBuffer << ")";
   return *this;
 }
 
@@ -985,8 +1149,7 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
       } else {
         isAdded = true;
       }
-      myDumpBuffer << "model.selection(\"" <<
-        aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
+      *this << anAttribute;
     }
 
     myDumpBuffer << "]";