Salome HOME
Fix for the problem of the nightly unit-tests performance.
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
index 517ef728dba52c69b1b0b96d3441f5ed1efd5c87..d636a3804608ac6af36832320f5e6dab92f3bbdc 100644 (file)
@@ -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_AttributeSelection.h"
@@ -30,6 +29,7 @@
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_ResultBody.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_ResultGroup.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_Tools.h>
@@ -69,6 +69,7 @@
 #include <TDF_ChildIDIterator.hxx>
 #include <Geom_Circle.hxx>
 #include <Geom_Ellipse.hxx>
+#include <Geom_TrimmedCurve.hxx>
 #include <BRep_Builder.hxx>
 
 //#define DEB_NAMING 1
@@ -104,10 +105,9 @@ const static std::string kWHOLE_FEATURE = "all-in-";
 bool Model_AttributeSelection::setValue(const ObjectPtr& theContext,
   const std::shared_ptr<GeomAPI_Shape>& theSubShape, const bool theTemporarily)
 {
-  if (theTemporarily &&
-      (!theContext.get() || theContext->groupName() != ModelAPI_Feature::group())) {
+  if (theTemporarily) {
     // just keep the stored without DF update
-    myTmpContext = std::dynamic_pointer_cast<ModelAPI_Result>(theContext);
+    myTmpContext = theContext;
     myTmpSubShape = theSubShape;
     owner()->data()->sendAttributeUpdated(this);
     return true;
@@ -182,6 +182,9 @@ 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 if (theContext->groupName() == ModelAPI_ResultGroup::group()) {
+    aSelLab.ForgetAllAttributes(true);
+    TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID);
   } 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()) {
@@ -257,7 +260,7 @@ void Model_AttributeSelection::removeTemporaryValues()
   }
 }
 
-// returns the center of the edge: circular or elliptical
+// returns the center of the edge: circular or elliptic
 GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::CenterType theType)
 {
   if (theType != ModelAPI_AttributeSelection::NOT_CENTER && theEdge.get() != NULL) {
@@ -270,11 +273,15 @@ GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::Cen
         TopoDS_Vertex aVertex;
         BRep_Builder aBuilder;
         if (theType == ModelAPI_AttributeSelection::CIRCLE_CENTER) {
+          while(!aCurve.IsNull() && aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
+            aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
           Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve);
           if (!aCirc.IsNull()) {
             aBuilder.MakeVertex(aVertex, aCirc->Location(), Precision::Confusion());
           }
         } else { // ellipse
+          while(!aCurve.IsNull() && aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
+            aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
           Handle(Geom_Ellipse) anEll = Handle(Geom_Ellipse)::DownCast(aCurve);
           if (!anEll.IsNull()) {
             aBuilder.MakeVertex(aVertex,
@@ -314,7 +321,14 @@ std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::internalValue(CenterTyp
       // it is just reference to construction.
       return myTmpSubShape;
     }
-    return myTmpSubShape.get() ? myTmpSubShape : myTmpContext->shape();
+    FeaturePtr aFeature =
+      std::dynamic_pointer_cast<ModelAPI_Feature>(myTmpContext);
+    if (aFeature.get()) {
+      // it is just reference to construction.
+      return myTmpSubShape;
+    }
+    return myTmpSubShape.get() ? myTmpSubShape :
+      std::dynamic_pointer_cast<ModelAPI_Result>(myTmpContext)->shape();
   }
 
   TDF_Label aSelLab = selectionLabel();
@@ -411,7 +425,8 @@ bool Model_AttributeSelection::isInitialized()
     std::shared_ptr<GeomAPI_Shape> aResult;
     if (myRef.isInitialized()) {
       TDF_Label aSelLab = selectionLabel();
-      if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
+      // it is just reference to shape, not sub-shape
+      if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
         ResultPtr aContext = context();
         return aContext.get() != NULL;
       }
@@ -465,7 +480,7 @@ ResultPtr Model_AttributeSelection::context()
     return ResultPtr();
 
   if (myTmpContext.get() || myTmpSubShape.get()) {
-    return myTmpContext;
+    return std::dynamic_pointer_cast<ModelAPI_Result>(myTmpContext);
   }
 
   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
@@ -495,8 +510,8 @@ ResultPtr Model_AttributeSelection::context()
 }
 
 FeaturePtr Model_AttributeSelection::contextFeature() {
-  if (myTmpContext.get() || myTmpSubShape.get()) {
-    return FeaturePtr(); // feature can not be selected temporarily
+  if (myTmpContext.get()) {
+    return std::dynamic_pointer_cast<ModelAPI_Feature>(myTmpContext);
   }
   return std::dynamic_pointer_cast<ModelAPI_Feature>(myRef.value());
 }
@@ -730,6 +745,22 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
   if(!this->isInitialized())
     return !theDefaultName.empty() ? theDefaultName : aName;
 
+  // not argument has not parametric name (filters)
+  if (!this->isArgument() || (myParent && !myParent->isArgument())) {
+    GeomShapePtr aShape = value();
+    if (!aShape.get() && context().get())
+      aShape = context()->shape();
+    std::string aName;
+    if (aShape.get()) {
+      aName = aShape->shapeTypeStr();
+      if (myParent) {
+        aName += std::string("_") +
+          TCollection_AsciiString(selectionLabel().Father().Tag()).ToCString();
+      }
+    }
+    return aName;
+  }
+
   CenterType aCenterType = NOT_CENTER;
   std::shared_ptr<GeomAPI_Shape> aSubSh = internalValue(aCenterType);
   ResultPtr aCont = context();
@@ -754,14 +785,13 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa
   if (aCont->groupName() == ModelAPI_ResultPart::group()) {
     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aCont);
     int anIndex;
-    GeomShapePtr aValue = value();
-    if (aValue.get())
-      return aPart->data()->name() + "/" + aPart->nameInPart(aValue, anIndex);
-    else
-      return aPart->data()->name();
+    std::string aResult = aSubSh.get() ?
+      aPart->data()->name() + "/" + aPart->nameInPart(aSubSh, anIndex) : aPart->data()->name();
+    if (aCenterType != NOT_CENTER)
+      aResult += centersMap()[aCenterType];
+    return aResult;
   }
 
-
   // whole infinitive construction
   if (aCont->groupName() == ModelAPI_ResultConstruction::group()) {
     ResultConstructionPtr aConstr = std::dynamic_pointer_cast<Model_ResultConstruction>(aCont);
@@ -870,8 +900,11 @@ void Model_AttributeSelection::selectSubShape(
     // the whole result selection check
     if (aSubShapeName.find('/') == std::string::npos) {
       ObjectPtr aRes = aDoc->objectByName(ModelAPI_ResultConstruction::group(), aSubShapeName);
-      if (!aRes.get())
+      if (!aRes.get()) {
         aRes = aDoc->objectByName(ModelAPI_ResultBody::group(), aSubShapeName);
+        if (!aRes.get())
+          aRes = aDoc->objectByName(ModelAPI_ResultGroup::group(), aSubShapeName);
+      }
       if (aRes.get()) {
         setValue(aRes, anEmptyShape);
         return;
@@ -1086,9 +1119,10 @@ void Model_AttributeSelection::computeValues(
   if (aWasWholeContext) {
     theValShape = theOldContext->shape()->impl<TopoDS_Shape>();
   }
+  TopAbs_ShapeEnum aValType = theValShape.ShapeType();
   TopoDS_Shape aNewContShape = theNewContext->shape()->impl<TopoDS_Shape>();
   // if a new value is unchanged in the new context, do nothing: value is correct
-  TopExp_Explorer aSubExp(aNewContShape, theValShape.ShapeType());
+  TopExp_Explorer aSubExp(aNewContShape, aValType);
   for(; aSubExp.More(); aSubExp.Next()) {
     if (aSubExp.Current().IsSame(theValShape)) {
       theShapes.Append(theValShape);
@@ -1133,17 +1167,15 @@ void Model_AttributeSelection::computeValues(
                 return;
               }
               // don't add edges generated from faces
-              if (aPairIter.NewShape().ShapeType() <= theValShape.ShapeType())
+              if (aPairIter.NewShape().ShapeType() <= aValType)
                 theShapes.Append(aPairIter.NewShape());
             }
           } else if (!aPairIter.OldShape().IsNull()) { // search shape that contains this sub
-            TopExp_Explorer anExp(aPairIter.OldShape(), theValShape.ShapeType());
+            TopExp_Explorer anExp(aPairIter.OldShape(), aValType);
             for(; anExp.More(); anExp.Next()) {
               if (anExp.Current().IsSame(theValShape)) { // found a new container
-                if (aPairIter.NewShape().IsNull()) {// value was removed
-                  theShapes.Clear();
-                  return;
-                }
+                if (aPairIter.NewShape().IsNull()) // skip removed high-level shape
+                  continue;
                 aNewToOld.Bind(aPairIter.NewShape(), aPairIter.OldShape());
                 anOlds.Add(aPairIter.OldShape());
                 break;
@@ -1160,7 +1192,7 @@ void Model_AttributeSelection::computeValues(
     NCollection_Map<TopAbs_ShapeEnum> aNewTypes; // types of shapes to iterate
     TopTools_DataMapOfShapeShape::Iterator aNewTypeIter(aNewToOld);
     for(; aNewTypeIter.More(); aNewTypeIter.Next()) {
-      if (aNewTypeIter.Key().ShapeType() != theValShape.ShapeType())
+      if (aNewTypeIter.Key().ShapeType() != aValType)
         aNewTypes.Add(aNewTypeIter.Key().ShapeType());
     }
     NCollection_Map<TopAbs_ShapeEnum>::Iterator aTypeIter(aNewTypes);
@@ -1169,7 +1201,7 @@ void Model_AttributeSelection::computeValues(
         TopoDS_Shape anOld = anExp.Current();
         if (aNewToOld.IsBound(anOld) || anOlds.Contains(anOld)) // this was modified
           continue;
-        TopExp_Explorer aValExp(anOld, theValShape.ShapeType());
+        TopExp_Explorer aValExp(anOld, aValType);
         for(; aValExp.More(); aValExp.Next()) {
           const TopoDS_Shape& anUnchanged = aValExp.Current();
           if (anUnchanged.IsSame(theValShape)) {
@@ -1185,7 +1217,7 @@ void Model_AttributeSelection::computeValues(
     NCollection_DataMap<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> aSubs;
     TopTools_DataMapOfShapeShape::Iterator aContIter(aNewToOld);
     for(; aContIter.More(); aContIter.Next()) {
-      TopExp_Explorer aSubExp(aContIter.Key(), theValShape.ShapeType());
+      TopExp_Explorer aSubExp(aContIter.Key(), aValType);
       for(; aSubExp.More(); aSubExp.Next()) {
         if (!aSubs.IsBound(aSubExp.Current())) {
           aSubs.Bind(aSubExp.Current(), TopTools_MapOfShape());
@@ -1216,13 +1248,94 @@ void Model_AttributeSelection::computeValues(
     if (aWasWholeContext)
       theShapes.Append(TopoDS_Shape());
     else { // if theValShape exists in new context, add it without changes, otherwise - nothing
-      for (TopExp_Explorer aNew(aNewContShape, theValShape.ShapeType()); aNew.More(); aNew.Next()){
+      for (TopExp_Explorer aNew(aNewContShape, aValType); aNew.More(); aNew.Next()){
         if (aNew.Current().IsSame(theValShape)) {
           theShapes.Append(theValShape);
           break;
         }
       }
     }
+  } else if (theShapes.Size() > 1) {
+    // check it is possible to remove extra sub-shapes:
+    // keep only shapes with the same number of containers if possible
+    TopAbs_ShapeEnum anAncType = TopAbs_FACE;
+    if (aValType == TopAbs_VERTEX)
+      anAncType = TopAbs_EDGE;
+    TopoDS_Shape anOldContext = theOldContext->shape()->impl<TopoDS_Shape>();
+    TopTools_IndexedDataMapOfShapeListOfShape anOldMap;
+    TopExp::MapShapesAndUniqueAncestors(anOldContext, aValType,  anAncType, anOldMap);
+    if (anOldMap.Contains(theValShape)) {
+      int aNumInOld = anOldMap.FindFromKey(theValShape).Extent();
+      TopTools_IndexedDataMapOfShapeListOfShape aNewMap;
+      TopExp::MapShapesAndUniqueAncestors(aNewContShape, aValType,  anAncType, aNewMap);
+      TopTools_ListOfShape aNewResults;
+      for(TopTools_ListOfShape::Iterator aNewSubs(theShapes); aNewSubs.More(); aNewSubs.Next()) {
+        TopoDS_Shape aCand = aNewSubs.Value();
+        if (aNewMap.Contains(aCand) && aNewMap.FindFromKey(aCand).Extent() == aNumInOld)
+          aNewResults.Append(aCand);
+      }
+      if (!aNewResults.IsEmpty() && aNewResults.Size() < theShapes.Size())
+        theShapes = aNewResults;
+    }
+  }
+}
+
+
+void Model_AttributeSelection::concealedFeature(
+  const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers,
+  const ResultPtr theResultOfFeature)
+{
+  std::set<FeaturePtr> alreadyProcessed;
+  alreadyProcessed.insert(theFeature);
+  if (theStop.get())
+    alreadyProcessed.insert(theStop);
+  /// iterate all results to find the concealment-attribute
+  std::list<ResultPtr> aRootRes;
+  if (theResultOfFeature.get()) {
+    ResultPtr aRoot = ModelAPI_Tools::bodyOwner(theResultOfFeature, true);
+    aRootRes.push_back(aRoot ? aRoot : theResultOfFeature);
+  } else { // all results of a feature
+   aRootRes = theFeature->results();
+  }
+  std::list<ResultPtr>::const_iterator aRootIter = aRootRes.cbegin();
+  for(; aRootIter != aRootRes.cend(); aRootIter++) {
+    std::list<ResultPtr> allRes;
+    allRes.push_back(*aRootIter);
+    ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true);
+    if (!aRootBody.get())
+      aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRootIter);
+    if (aRootBody.get()) {
+      ModelAPI_Tools::allSubs(aRootBody, allRes);
+    }
+    for(std::list<ResultPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
+      const std::set<AttributePtr>& aRefs = (*aRIter)->data()->refsToMe();
+      std::set<AttributePtr>::const_iterator aRef = aRefs.cbegin();
+      for (; aRef != aRefs.cend(); aRef++) {
+        if (!aRef->get() || !(*aRef)->owner().get())
+          continue;
+        // concealed attribute only
+        FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
+        if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
+          continue;
+        alreadyProcessed.insert(aRefFeat);
+        if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+        {
+          // for extrusion cut in python script the nested sketch reference may be concealed before
+          // it is nested, so, check this composite feature is valid
+          static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+          // need to be validated to update the "Apply" state if not previewed
+          if (aFactory->validate(aRefFeat)) {
+            if (theStop.get()) {
+              std::shared_ptr<Model_Document> aDoc =
+                std::dynamic_pointer_cast<Model_Document>(theStop->document());
+              if (!aDoc->isLaterByDep(theStop, aRefFeat)) // skip feature later than stop
+                continue;
+            }
+            theConcealers.push_back(aRefFeat);
+          }
+        }
+      }
+    }
   }
 }
 
@@ -1289,38 +1402,32 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
 
   if (aResults.empty()) {
     // check the context become concealed by operation which is earlier than this selection
-    std::list<ResultPtr> allRes;
-    ResultPtr aRoot = ModelAPI_Tools::bodyOwner(theContext, true);
-    if (!aRoot.get())
-      aRoot = theContext;
-    ResultBodyPtr aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aRoot);
-    if (aRootBody.get()) {
-      ModelAPI_Tools::allSubs(aRootBody, allRes);
-      allRes.push_back(aRootBody);
-    } else
-      allRes.push_back(aRoot);
-
     FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
-    for (std::list<ResultPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
-      ResultPtr aResCont = *aSub;
-      const std::set<AttributePtr>& aRefs = aResCont->data()->refsToMe();
-      std::set<AttributePtr>::const_iterator aRef = aRefs.begin();
-      for (; aRef != aRefs.end(); aRef++) {
-        if (!aRef->get() || !(*aRef)->owner().get())
+    FeaturePtr aContextOwner = theDoc->feature(theContext);
+    std::list<FeaturePtr> aConcealers;
+    concealedFeature(aContextOwner, aThisFeature, aConcealers, theContext);
+    std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+    for(; aConcealer != aConcealers.end(); aConcealer++) {
+      std::list<ResultPtr> aRefResults;
+      ModelAPI_Tools::allResults(*aConcealer, aRefResults);
+      std::list<ResultPtr>::iterator aRefIter = aRefResults.begin();
+      for(; aRefIter != aRefResults.end(); aRefIter++) {
+        ResultBodyPtr aRefBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRefIter);
+        if (!aRefBody.get() || aRefBody->numberOfSubs() != 0) // iterate only leafs
           continue;
-        // concealed attribute only
-        FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
-        if (aRefFeat == aThisFeature)
+        GeomShapePtr aRefShape = aRefBody->shape();
+        if (!aRefShape.get() || aRefShape->isNull())
           continue;
-        if (!ModelAPI_Session::get()->validators()->isConcealed(
-          aRefFeat->getKind(), (*aRef)->id()))
-          continue;
-        if (!theDoc->isLaterByDep(aRefFeat, aThisFeature)) {
-          return true; // feature conceals result, return true, so the context will be removed
+        if (aRefShape->impl<TopoDS_Shape>().IsSame(theContShape)) {
+          // add the new context result with the same shape
+          aResults.insert(aRefBody);
         }
       }
+      if (aResults.empty())
+        return true; // feature conceals result, return true, so the context will be removed
     }
-    return false; // no modifications found, must stay the same
+    if (aResults.empty())
+      return false; // no modifications found, must stay the same
   }
   // iterate all results to find further modifications
   std::set<ResultPtr>::iterator aResIter = aResults.begin();
@@ -1360,18 +1467,56 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr<Model_Document>
 
 void Model_AttributeSelection::updateInHistory(bool& theRemove)
 {
+  static std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+
   ResultPtr aContext = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
-  // only bodies and parts may be modified later in the history, don't do anything otherwise
   if (!aContext.get() || (aContext->groupName() != ModelAPI_ResultBody::group() &&
-      aContext->groupName() != ModelAPI_ResultPart::group()))
-    return;
+      aContext->groupName() != ModelAPI_ResultPart::group())) {
+    // but check the case the whole results are allowed: whole features may be selected
+    if (myParent && myParent->isWholeResultAllowed()) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myRef.value());
+      if (aFeature.get()) {
+        FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+        std::list<FeaturePtr> aConcealers;
+        concealedFeature(aFeature, aThisFeature, aConcealers, ResultPtr());
+        if (aConcealers.empty())
+          return;
+        bool aChanged = false;
+        std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+        for(; aConcealer != aConcealers.end(); aConcealer++)
+          if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+            setValue(*aConcealer, anEmptyShape);
+            aChanged = true;
+          }
+        if (aConcealer == aConcealers.end()) {
+          if (!aChanged) // remove this
+            theRemove = true;
+        } else { // append new
+          for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
+            if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+              myParent->append(*aConcealer, anEmptyShape);
+        }
+        if (aChanged) // searching for the further modifications
+          updateInHistory(theRemove);
+      }
+    }
+    return;// only bodies and parts may be modified later in the history, skip otherwise
+  }
+
   std::shared_ptr<Model_Document> aDoc =
     std::dynamic_pointer_cast<Model_Document>(aContext->document());
   std::shared_ptr<Model_Data> aContData = std::dynamic_pointer_cast<Model_Data>(aContext->data());
   if (!aContData.get() || !aContData->isValid())
     return;
   TDF_Label aContLab = aContData->shapeLab(); // named shape where the selected context is located
+
+  // checking this may be just a reference to another context (same shape), so use that label
   Handle(TNaming_NamedShape) aContNS;
+  Handle(TDF_Reference) aRefAttr;
+  while(!aContLab.FindAttribute(TNaming_NamedShape::GetID(), aContNS) &&
+        aContLab.FindAttribute(TDF_Reference::GetID(), aRefAttr))
+    aContLab = aRefAttr->Get();
+
   if (!aContLab.FindAttribute(TNaming_NamedShape::GetID(), aContNS)) {
     bool aFoundNewContext = true;
     ResultPtr aNewContext = aContext;
@@ -1392,7 +1537,12 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
               continue;
 
             FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
-            if (aRefFeat.get() && aRefFeat != owner()) {
+
+            if (aRefFeat.get() && aRefFeat != owner() && aRefFeat->firstResult().get()) {
+              // check the reference is concealed: #2900
+              ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
+              if (!aValidators->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+                continue;
               FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
               if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature
                 aFoundNewContext = true;
@@ -1447,9 +1597,48 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
 
     GeomAPI_Shape::ShapeType aListShapeType = GeomAPI_Shape::SHAPE;
     if (myParent) {
-      if (myParent->selectionType() == "VERTEX") aListShapeType = GeomAPI_Shape::VERTEX;
-      else if (myParent->selectionType() == "EDGE") aListShapeType = GeomAPI_Shape::EDGE;
-      else if (myParent->selectionType() == "FACE") aListShapeType = GeomAPI_Shape::FACE;
+      if (myParent->selectionType() == "VERTEX" || myParent->selectionType() == "Vertices")
+        aListShapeType = GeomAPI_Shape::VERTEX;
+      else if (myParent->selectionType() == "EDGE" || myParent->selectionType() == "Edges")
+        aListShapeType = GeomAPI_Shape::EDGE;
+      else if (myParent->selectionType() == "FACE" || myParent->selectionType() == "Faces")
+        aListShapeType = GeomAPI_Shape::FACE;
+    }
+
+    // issue #3031: skip topology if there is more convenient shape type presents in the
+    // same context as a result of this
+    bool isWholeResult = myParent && myParent->isWholeResultAllowed() && !aSubShape.get();
+    GeomAPI_Shape::ShapeType allowedType = GeomAPI_Shape::SHAPE;
+    if (isWholeResult) {
+      std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
+      TopTools_ListIteratorOfListOfShape aNewValues(aValShapes);
+      for(; aNewCont != aNewContexts.end(); aNewCont++, aNewValues.Next()) {
+        if (aNewValues.Value().IsNull()) { // only for the whole context
+          GeomAPI_Shape::ShapeType aShapeType = (*aNewCont)->shape()->shapeType();
+          if (allowedType == GeomAPI_Shape::SHAPE) { // just set this one
+            allowedType = aShapeType;
+          } else {
+            GeomAPI_Shape::ShapeType anAllowed = allowedType;
+            if (anAllowed != aShapeType) { // select the best, nearest to the origin
+              GeomAPI_Shape::ShapeType anOldShapeType = aContext->shape()->shapeType();
+              GeomAPI_Shape::ShapeType aDeltaAllowed =
+                (GeomAPI_Shape::ShapeType)(anOldShapeType - anAllowed);
+              if (aDeltaAllowed < 0)
+                aDeltaAllowed = (GeomAPI_Shape::ShapeType)(-aDeltaAllowed);
+              GeomAPI_Shape::ShapeType aDeltaThis =
+                (GeomAPI_Shape::ShapeType)(anOldShapeType - aShapeType);
+              if (aDeltaThis < 0)
+                aDeltaThis = (GeomAPI_Shape::ShapeType)(-aDeltaThis);
+              if (aDeltaThis == aDeltaAllowed) { // equal distance to context, select complicated
+                if (anOldShapeType < anAllowed)
+                  allowedType = aShapeType;
+              } else if (aDeltaAllowed > aDeltaThis) { // this wins
+                allowedType = aShapeType;
+              }
+            }
+          }
+        }
+      }
     }
 
     std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
@@ -1459,6 +1648,11 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
       if (aSkippedContext.count(*aNewCont))
         continue;
 
+      if (isWholeResult && aNewValues.Value().IsNull())
+        if (allowedType != GeomAPI_Shape::SHAPE &&
+            (*aNewCont)->shape()->shapeType() != allowedType)
+          continue; // there is better result exists with the better shape type (issue #3031)
+
       GeomShapePtr aValueShape;
       if (!aNewValues.Value().IsNull()) {
         aValueShape = std::make_shared<GeomAPI_Shape>();
@@ -1472,23 +1666,45 @@ void Model_AttributeSelection::updateInHistory(bool& theRemove)
         aShapeShapeType = (*aNewCont)->shape()->shapeType();
       }
       if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) {
-        continue;
+        // exception is for whole results selected
+        if (!isWholeResult) {
+          continue;
+        }
+      }
+
+      ResultPtr aNewContext = *aNewCont;
+      if (aValueShape.get()) { // #2892 if context is higher level result, search this sub in lower
+        ResultBodyPtr aBodyContext = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aNewContext);
+        if (aBodyContext.get() && aBodyContext->numberOfSubs() != 0) {
+          std::list<ResultPtr> aLower;
+          ModelAPI_Tools::allSubs(aBodyContext, aLower, true);
+          for(std::list<ResultPtr>::iterator aL = aLower.begin(); aL != aLower.end(); aL++) {
+            GeomShapePtr aLShape = (*aL)->shape();
+            if (aLShape.get() && !aLShape->isNull()) {
+              if (aLShape->isSubShape(aValueShape, false)) {
+                aNewContext = *aL;
+                break;
+              }
+            }
+          }
+        }
       }
 
       if (aFirst) {
-        setValue(*aNewCont, aValueShape);
-        aFirst = false;
+        if (!myParent || !myParent->isInList(aNewContext, aValueShape)) { // avoid duplicates
+          setValue(aNewContext, aValueShape);
+          aFirst = false;
+        }
       } else if (myParent) {
-        if (!myParent->isInList(*aNewCont, aValueShape)) // avoid addition of duplicates
-          myParent->append(*aNewCont, aValueShape);
+        if (!myParent->isInList(aNewContext, aValueShape)) // avoid addition of duplicates
+          myParent->append(aNewContext, aValueShape);
       }
     }
     if (aFirst) { // nothing was added, all results were deleted
       if (myParent) {
         theRemove = true;
       } else {
-        ResultPtr anEmptyContext;
-        std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+        static ResultPtr anEmptyContext;
         setValue(anEmptyContext, anEmptyShape); // nullify the selection
         return;
       }