Salome HOME
Issue #2612 : Re-calculate model after modification of parameters
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
index b76998d854b0001c40180d39f0bfb1fafb0ca6e9..2337fb0b58d2bed9e4d3027814fb3e809048f7eb 100644 (file)
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
+#include <ModelGeomAlgo_Shape.h>
 #include <Events_InfoMessage.h>
 #include <GeomAPI_Edge.h>
+#include <GeomAPI_Pnt.h>
 #include <GeomAPI_Vertex.h>
 #include <GeomAlgoAPI_CompoundBuilder.h>
 
@@ -180,6 +182,17 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext,
     aSelLab.ForgetAllAttributes(true);
     TDataStd_UAttribute::Set(aSelLab, kPART_REF_ID);
     selectPart(std::dynamic_pointer_cast<ModelAPI_Result>(theContext), theSubShape);
+  } else { // check the feature context: parent-Part of this feature should not be used
+    FeaturePtr aFeatureContext = std::dynamic_pointer_cast<ModelAPI_Feature>(theContext);
+    if (aFeatureContext.get()) {
+      if (owner()->document() != aFeatureContext->document()) {
+        aSelLab.ForgetAllAttributes(true);
+        myRef.setValue(ObjectPtr());
+        if (aToUnblock)
+          owner()->data()->blockSendAttributeUpdated(false);
+        return false;
+      }
+    }
   }
 
   owner()->data()->sendAttributeUpdated(this);
@@ -353,20 +366,22 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::internalValue(CenterTyp
       if (aConstr->isInfinite())
         return aResult; // empty result
     }
-    // whole feature
-    FeaturePtr aFeature = contextFeature();
-    if (aFeature.get()) {
-      std::list<GeomShapePtr> allShapes;
-      std::list<ResultPtr>::const_iterator aRes = aFeature->results().cbegin();
-      for (; aRes != aFeature->results().cend(); aRes++) {
-        if (aRes->get() && !(*aRes)->isDisabled()) {
-          GeomShapePtr aShape = (*aRes)->shape();
-          if (aShape.get() && !aShape->isNull()) {
-            allShapes.push_back(aShape);
+    if (!aConstr.get()) { // for construction context, return empty result as usual even
+      // the whole feature is selected
+      FeaturePtr aFeature = contextFeature();
+      if (aFeature.get()) {
+        std::list<GeomShapePtr> allShapes;
+        std::list<ResultPtr>::const_iterator aRes = aFeature->results().cbegin();
+        for (; aRes != aFeature->results().cend(); aRes++) {
+          if (aRes->get() && !(*aRes)->isDisabled()) {
+            GeomShapePtr aShape = (*aRes)->shape();
+            if (aShape.get() && !aShape->isNull()) {
+              allShapes.push_back(aShape);
+            }
           }
         }
+        return GeomAlgoAPI_CompoundBuilder::compound(allShapes);
       }
-      return GeomAlgoAPI_CompoundBuilder::compound(allShapes);
     }
 
     Handle(TNaming_NamedShape) aSelection;
@@ -438,6 +453,7 @@ void Model_AttributeSelection::setID(const std::string theID)
 }
 
 ResultPtr Model_AttributeSelection::context()
+{
   if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
     return ResultPtr();
 
@@ -447,19 +463,26 @@ ResultPtr Model_AttributeSelection::context()
 
   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
   // for parts there could be same-data result, so take the last enabled
-  if (aResult.get() && aResult->groupName() == ModelAPI_ResultPart::group()) {
-    int aSize = aResult->document()->size(ModelAPI_ResultPart::group());
-    for(int a = aSize - 1; a >= 0; a--) {
-      ObjectPtr aPart = aResult->document()->object(ModelAPI_ResultPart::group(), a);
-      if (aPart.get() && aPart->data() == aResult->data()) {
-        ResultPtr aPartResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPart);
-        FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-        // check that this result is not this-feature result (it is forbidden t oselect itself)
-        if (anOwnerFeature.get() && anOwnerFeature->firstResult() != aPartResult) {
-          return aPartResult;
+  if (aResult.get()) {
+    if(aResult->groupName() == ModelAPI_ResultPart::group()) {
+      int aSize = aResult->document()->size(ModelAPI_ResultPart::group());
+      for(int a = aSize - 1; a >= 0; a--) {
+        ObjectPtr aPart = aResult->document()->object(ModelAPI_ResultPart::group(), a);
+        if(aPart.get() && aPart->data() == aResult->data()) {
+          ResultPtr aPartResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPart);
+          FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+          // check that this result is not this-feature result (it is forbidden t oselect itself)
+          if(anOwnerFeature.get() && anOwnerFeature->firstResult() != aPartResult) {
+            return aPartResult;
+          }
         }
       }
     }
+  } else { // if feature - construction is selected, it has only one result, return this result
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myRef.value());
+    if (aFeature.get() && aFeature->results().size() == 1 &&
+        aFeature->firstResult()->groupName() == ModelAPI_ResultConstruction::group())
+      return aFeature->firstResult();
   }
   return aResult;
 }
@@ -469,9 +492,13 @@ FeaturePtr Model_AttributeSelection::contextFeature() {
     return FeaturePtr(); // feature can not be selected temporarily
   }
   return std::dynamic_pointer_cast<ModelAPI_Feature>(myRef.value());
-
 }
-
+ObjectPtr Model_AttributeSelection::contextObject() {
+  FeaturePtr aRes = contextFeature();
+  if (aRes.get())
+    return aRes;
+  return context();
+}
 
 
 void Model_AttributeSelection::setObject(const std::shared_ptr<ModelAPI_Object>& theObject)
@@ -582,6 +609,10 @@ void Model_AttributeSelection::split(
 
 bool Model_AttributeSelection::update()
 {
+  FeaturePtr aContextFeature = contextFeature();
+  if (aContextFeature.get()) {
+    return true;
+  }
   TDF_Label aSelLab = selectionLabel();
   ResultPtr aContext = context();
   if (!aContext.get())
@@ -819,7 +850,8 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
   std::shared_ptr<GeomAPI_Shape> aSubSh = internalValue(aCenterType);
   ResultPtr aCont = context();
 
-  if (!aCont.get()) {
+  if (!aCont.get() ||
+      (aCont->groupName() == ModelAPI_ResultConstruction::group() && contextFeature().get())) {
     // selection of a full feature
     FeaturePtr aFeatureCont = contextFeature();
     if (aFeatureCont.get()) {
@@ -926,9 +958,14 @@ void Model_AttributeSelection::selectSubShape(
             aNS = TNaming_Tool::CurrentNamedShape(aNS);
             if (!aNS.IsNull() && scope().Contains(aNS->Label())) { // scope check is for 2228
               TDF_Label aLab = aNS->Label();
-              while(aLab.Depth() != 7 && aLab.Depth() > 5)
+              if (aLab.Depth() % 2 == 0)
                 aLab = aLab.Father();
               ObjectPtr anObj = aDoc->objects()->object(aLab);
+              while(!anObj.get() && aLab.Depth() > 5) {
+                aLab = aLab.Father().Father();
+                anObj = aDoc->objects()->object(aLab);
+              }
+
               if (anObj.get()) {
                 ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
                 if (aRes)
@@ -944,10 +981,11 @@ void Model_AttributeSelection::selectSubShape(
         if (aComp && aComp->numberOfSubs()) {
           std::list<ResultPtr> allSubs;
           ModelAPI_Tools::allSubs(aComp, allSubs);
-          std::list<ResultPtr>::reverse_iterator aS = allSubs.rbegin(); // iterate from lower level
-          for(; aS != allSubs.rend(); aS++) {
-            ResultPtr aSub = *aS;
-            if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aShapeToBeSelected)) {
+          std::list<ResultPtr>::iterator aS = allSubs.begin();
+          for(; aS != allSubs.end(); aS++) {
+            ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aS);
+            if (aSub && aSub->numberOfSubs() == 0 && aSub->shape().get() &&
+                aSub->shape()->isSubShape(aShapeToBeSelected)) {
               aCont = aSub;
               break;
             }
@@ -960,13 +998,20 @@ void Model_AttributeSelection::selectSubShape(
       while(aFindNewContext && aCont.get()) {
         aFindNewContext = false;
         // take references to all results: root one, any sub
-        ResultBodyPtr aCompContext = ModelAPI_Tools::bodyOwner(aCont);
+        ResultBodyPtr aCompContext = ModelAPI_Tools::bodyOwner(aCont, true);
         std::list<ResultPtr> allRes;
-        if (aCompContext.get())
+        if (aCompContext.get()) {
           ModelAPI_Tools::allSubs(aCompContext, allRes);
-        allRes.push_back(aCont);
+          allRes.push_back(aCompContext);
+        } else {
+          allRes.push_back(aCont);
+        }
         for(std::list<ResultPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
           ResultPtr aResCont = *aSub;
+          ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResCont);
+          // only lower and higher level subs are counted
+          if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext)
+            continue;
           const std::set<AttributePtr>& aRefs = aResCont->data()->refsToMe();
           std::set<AttributePtr>::const_iterator aRef = aRefs.begin();
           for(; !aFindNewContext && aRef != aRefs.end(); aRef++) {
@@ -1022,6 +1067,91 @@ void Model_AttributeSelection::selectSubShape(
   reset();
 }
 
+void Model_AttributeSelection::selectSubShape(const std::string& theType,
+                                              const GeomPointPtr& thePoint)
+{
+  if (theType.empty() || !thePoint)
+    return;
+
+  // list of parent features
+  FeaturePtr anOwner = ModelAPI_Feature::feature(owner());
+  std::set<FeaturePtr> aParents = ModelAPI_Tools::getParents(anOwner);
+
+  int aSelectionIndex = 0;
+  GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(theType);
+  if (aType == GeomAPI_Shape::SHAPE) {
+    // possibly, the string consists of the type and the index,
+    // thus, try to separate them
+    size_t aUndersporePos = theType.find_first_of('_');
+    if (aUndersporePos != std::string::npos)
+      aType = GeomAPI_Shape::shapeTypeByStr(theType.substr(0, aUndersporePos));
+
+    if (aType != GeomAPI_Shape::SHAPE) {
+      for (std::string::const_iterator aChar = theType.begin() + aUndersporePos + 1;
+           aChar != theType.end(); ++aChar) {
+        if (std::isdigit(*aChar))
+          aSelectionIndex = aSelectionIndex * 10 + (*aChar - '0');
+        else {
+          aSelectionIndex = 1;
+          break;
+        }
+      }
+      aSelectionIndex -= 1;
+    }
+  }
+
+  std::list<ModelGeomAlgo_Shape::SubshapeOfResult> anAppropriate;
+
+  // collect features from PartSet and the current part
+  SessionPtr aSession = ModelAPI_Session::get();
+  std::list<FeaturePtr> aFeatures = aSession->moduleDocument()->allFeatures();
+  if (aSession->moduleDocument() != owner()->document()) {
+    std::list<FeaturePtr> aPartFeatures = owner()->document()->allFeatures();
+    aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end());
+  }
+  // Process results of all features from the last to the first
+  // to find appropriate sub-shape
+  for (std::list<FeaturePtr>::const_reverse_iterator anIt = aFeatures.rbegin();
+       anIt != aFeatures.rend(); ++anIt) {
+    // selection cannot be linked to the parent features
+    if (aParents.find(*anIt) != aParents.end())
+      continue;
+    // check the feature is a part of composite feature (like sketch elements),
+    // then do not process it, it will be processed in scope of composite feature
+    bool isSubOfComposite = false;
+    const std::set<AttributePtr>& aRefs = (*anIt)->data()->refsToMe();
+    for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+         aRefIt != aRefs.end() && !isSubOfComposite; ++aRefIt) {
+      FeaturePtr aFeature = ModelAPI_Feature::feature((*aRefIt)->owner());
+      CompositeFeaturePtr aCompFeature =
+          std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
+      isSubOfComposite = aCompFeature && aCompFeature->isSub(*anIt);
+    }
+    if (isSubOfComposite)
+      continue;
+
+    // process results of the current feature to find appropriate sub-shape
+    if (ModelGeomAlgo_Shape::findSubshapeByPoint(*anIt, thePoint, aType, anAppropriate)) {
+      std::list<ModelGeomAlgo_Shape::SubshapeOfResult>::iterator anApIt = anAppropriate.begin();
+      for (; aSelectionIndex > 0 && anApIt != anAppropriate.end(); --aSelectionIndex)
+        ++anApIt; // skip this shape, because one of the previous is selected
+
+      if (anApIt != anAppropriate.end()) {
+        if (anApIt->myCenterType == (int)ModelAPI_AttributeSelection::NOT_CENTER)
+          setValue(anApIt->myResult, anApIt->mySubshape);
+        else
+          setValueCenter(anApIt->myResult, anApIt->mySubshape->edge(),
+                         (ModelAPI_AttributeSelection::CenterType)anApIt->myCenterType);
+        return;
+      }
+    }
+  }
+
+  TDF_Label aSelLab = selectionLabel();
+  setInvalidIfFalse(aSelLab, false);
+  reset();
+}
+
 int Model_AttributeSelection::Id()
 {
   int anID = 0;