X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=9d1e6cb65311873de13c46cde27684fe2a2bdcc5;hb=302437da7f4443349276e835e87452c29dd7c07a;hp=1db965d233bc30a35d1ed1269207245c9ce2be69;hpb=833f9ff0035309f13fe854e9dbc2413c1951b07a;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 1db965d23..9d1e6cb65 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -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 @@ -12,10 +12,9 @@ // // 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 +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "Model_AttributeSelection.h" @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +69,7 @@ #include #include #include +#include #include //#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& 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(theContext); + myTmpContext = theContext; myTmpSubShape = theSubShape; owner()->data()->sendAttributeUpdated(this); return true; @@ -182,10 +182,14 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext, aSelLab.ForgetAllAttributes(true); TDataStd_UAttribute::Set(aSelLab, kPART_REF_ID); selectPart(std::dynamic_pointer_cast(theContext), theSubShape); - } else { // check the feature context: parent-Part of this feature should not be used + } else if (theContext->groupName() == ModelAPI_ResultGroup::group()) { + aSelLab.ForgetAllAttributes(true); + TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID); + } else { // check the feature context: only construction features of PartSet could be selected FeaturePtr aFeatureContext = std::dynamic_pointer_cast(theContext); - if (aFeatureContext.get()) { - if (owner()->document() != aFeatureContext->document()) { + if (aFeatureContext.get() && owner()->document() != aFeatureContext->document()) { + if (aFeatureContext->results().empty() || + aFeatureContext->firstResult()->groupName() != ModelAPI_ResultConstruction::group()) { aSelLab.ForgetAllAttributes(true); myRef.setValue(ObjectPtr()); if (aToUnblock) @@ -257,7 +261,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 +274,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, @@ -295,7 +303,7 @@ GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::Cen std::shared_ptr Model_AttributeSelection::value() { - if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) + if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) return std::shared_ptr(); CenterType aType = NOT_CENTER; std::shared_ptr aResult = internalValue(aType); @@ -314,7 +322,14 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp // it is just reference to construction. return myTmpSubShape; } - return myTmpSubShape.get() ? myTmpSubShape : myTmpContext->shape(); + FeaturePtr aFeature = + std::dynamic_pointer_cast(myTmpContext); + if (aFeature.get()) { + // it is just reference to construction. + return myTmpSubShape; + } + return myTmpSubShape.get() ? myTmpSubShape : + std::dynamic_pointer_cast(myTmpContext)->shape(); } TDF_Label aSelLab = selectionLabel(); @@ -407,28 +422,29 @@ bool Model_AttributeSelection::isInvalid() bool Model_AttributeSelection::isInitialized() { - if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized - std::shared_ptr aResult; - if (myRef.isInitialized()) { - TDF_Label aSelLab = selectionLabel(); - if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape - ResultPtr aContext = context(); - return aContext.get() != NULL; - } - Handle(TNaming_NamedShape) aSelection; - if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { - return !aSelection->Get().IsNull(); - } else { // for simple construction element: just shape of this construction element - std::shared_ptr aConstr = - std::dynamic_pointer_cast(context()); - if (aConstr.get()) { - return true; - } - // for the whole feature, a feature object - FeaturePtr aFeat = contextFeature(); - if (aFeat.get()) - return true; - } + if (myRef.isInitialized()) { + TDF_Label aSelLab = selectionLabel(); + // 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; + } + Handle(TNaming_NamedShape) aSelection; + if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { + return !aSelection->Get().IsNull(); + } else { // for simple construction element: just shape of this construction element + if (myRef.value().get()) + return true; + // check that this is on open of document, so, results are not initialized yet + TDF_Label aRefLab = myRef.myRef->Get(); + if (aRefLab.IsNull() || !owner().get()) + return false; + std::shared_ptr aMyDoc = + std::dynamic_pointer_cast(owner()->document()); + if (!aMyDoc.get()) + return false; + // check at least the feature exists + return aMyDoc->featureByLab(aRefLab).get() != NULL; } } return false; @@ -448,7 +464,8 @@ void Model_AttributeSelection::setID(const std::string theID) ModelAPI_AttributeSelection::setID(theID); FeaturePtr aFeature = std::dynamic_pointer_cast(owner()); if (myParent) { - myIsGeometricalSelection = true;//myParent->isGeometricalSelection(); + // to be able to select as geometrical selection and then - split + myIsGeometricalSelection = true; // myParent->isGeometricalSelection(); } else { myIsGeometricalSelection = ModelAPI_Session::get()->validators()->isGeometricalSelection(aFeature->getKind(), id()); @@ -457,11 +474,11 @@ void Model_AttributeSelection::setID(const std::string theID) ResultPtr Model_AttributeSelection::context() { - if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) + if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) return ResultPtr(); if (myTmpContext.get() || myTmpSubShape.get()) { - return myTmpContext; + return std::dynamic_pointer_cast(myTmpContext); } ResultPtr aResult = std::dynamic_pointer_cast(myRef.value()); @@ -491,8 +508,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(myTmpContext); } return std::dynamic_pointer_cast(myRef.value()); } @@ -583,20 +600,32 @@ bool Model_AttributeSelection::update() TopoDS_Shape aContextShape = aContext->shape()->impl(); Selector_Selector aSelector(aSelLab, baseDocumentLab()); aResult = aSelector.restore(aContextShape); + bool aWasInvalid = aSelLab.IsAttribute(kINVALID_SELECTION); setInvalidIfFalse(aSelLab, aResult); TopoDS_Shape aNewShape; if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) aNewShape = aNS->Get(); - if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape)) { + if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape) || aWasInvalid) + { // shape type should not be changed: if shape becomes compound of such shapes, then split - if (!myIsGeometricalSelection && myParent && !anOldShape.IsNull() && !aNewShape.IsNull() && + if (myParent && !anOldShape.IsNull() && !aNewShape.IsNull() && anOldShape.ShapeType() != aNewShape.ShapeType() && - (aNewShape.ShapeType() == TopAbs_COMPOUND || aNewShape.ShapeType() == TopAbs_COMPSOLID)) - { + aNewShape.ShapeType() == TopAbs_COMPOUND) { split(aContext, aNewShape, anOldShape.ShapeType()); } + // for issue #3076 check that the new value belongs to the new context + if (!aNewShape.IsNull() && !aContextShape.IsNull() && + (aNewShape.ShapeType() == TopAbs_VERTEX || aNewShape.ShapeType() == TopAbs_EDGE || + aNewShape.ShapeType() == TopAbs_FACE)) { + TopExp_Explorer anExp(aContextShape, aNewShape.ShapeType()); + for(; anExp.More(); anExp.Next()) { + if (anExp.Current().IsSame(aNewShape)) + break; + } + aResult = setInvalidIfFalse(aSelLab, anExp.More()); + } owner()->data()->sendAttributeUpdated(this); // send updated if shape is changed } return aResult; @@ -727,21 +756,40 @@ 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 aSubSh = internalValue(aCenterType); - ResultPtr aCont = context(); - if (!aCont.get() || - (aCont->groupName() == ModelAPI_ResultConstruction::group() && contextFeature().get())) { + FeaturePtr aContFeature = contextFeature(); + if (aContFeature.get()) { + std::string aResName; + // checking part-owner + if (aContFeature->document() != owner()->document()) + aResName += aContFeature->document()->kind() + "/"; // selection of a full feature - FeaturePtr aFeatureCont = contextFeature(); - if (aFeatureCont.get()) { - return kWHOLE_FEATURE + aFeatureCont->name(); + if (aContFeature.get()) { + return aResName + kWHOLE_FEATURE + aContFeature->name(); } // in case of selection of removed result return ""; } + ResultPtr aCont = context(); TDF_Label aSelLab = selectionLabel(); if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value return contextName(aCont); @@ -751,14 +799,13 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa if (aCont->groupName() == ModelAPI_ResultPart::group()) { ResultPartPtr aPart = std::dynamic_pointer_cast(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(aCont); @@ -867,8 +914,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; @@ -1020,39 +1070,6 @@ void Model_AttributeSelection::selectSubShape(const std::string& theType, } } -int Model_AttributeSelection::Id() -{ - int anID = 0; - std::shared_ptr aSelection = value(); - ResultPtr aContextRes = context(); - // support for compsolids: - while(ModelAPI_Tools::bodyOwner(aContextRes).get()) { - aContextRes = ModelAPI_Tools::bodyOwner(aContextRes); - } - std::shared_ptr aContext = aContextRes->shape(); - - - TopoDS_Shape aMainShape = aContext->impl(); - const TopoDS_Shape& aSubShape = aSelection->impl(); - // searching for the latest main shape - if (aSelection && !aSelection->isNull() && aContext && !aContext->isNull()) - { - std::shared_ptr aDoc = - std::dynamic_pointer_cast(context()->document()); - if (aDoc.get()) { - Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel()); - if (!aNS.IsNull()) { - aMainShape = TNaming_Tool::CurrentShape(aNS); - } - } - - TopTools_IndexedMapOfShape aSubShapesMap; - TopExp::MapShapes(aMainShape, aSubShapesMap); - anID = aSubShapesMap.FindIndex(aSubShape); - } - return anID; -} - void Model_AttributeSelection::setId(int theID) { std::shared_ptr aSelection; @@ -1116,9 +1133,10 @@ void Model_AttributeSelection::computeValues( if (aWasWholeContext) { theValShape = theOldContext->shape()->impl(); } + TopAbs_ShapeEnum aValType = theValShape.ShapeType(); TopoDS_Shape aNewContShape = theNewContext->shape()->impl(); // 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); @@ -1162,16 +1180,16 @@ void Model_AttributeSelection::computeValues( theShapes.Clear(); return; } - theShapes.Append(aPairIter.NewShape()); + // don't add edges generated from faces + 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; @@ -1183,11 +1201,37 @@ void Model_AttributeSelection::computeValues( } } if (aToFindPart == 2 && !aNewToOld.IsEmpty()) { + // also iterate the whole old shape to find not-modified shapes that contain this old + TopoDS_Shape anOldContShape = theOldContext->shape()->impl(); + NCollection_Map aNewTypes; // types of shapes to iterate + TopTools_DataMapOfShapeShape::Iterator aNewTypeIter(aNewToOld); + for(; aNewTypeIter.More(); aNewTypeIter.Next()) { + if (aNewTypeIter.Key().ShapeType() != aValType) + aNewTypes.Add(aNewTypeIter.Key().ShapeType()); + } + NCollection_Map::Iterator aTypeIter(aNewTypes); + for(; aTypeIter.More(); aTypeIter.Next()) { + for(TopExp_Explorer anExp(anOldContShape, aTypeIter.Value()); anExp.More(); anExp.Next()) { + TopoDS_Shape anOld = anExp.Current(); + if (aNewToOld.IsBound(anOld) || anOlds.Contains(anOld)) // this was modified + continue; + TopExp_Explorer aValExp(anOld, aValType); + for(; aValExp.More(); aValExp.Next()) { + const TopoDS_Shape& anUnchanged = aValExp.Current(); + if (anUnchanged.IsSame(theValShape)) { + aNewToOld.Bind(anOld, anOld); + anOlds.Add(anOld); + break; + } + } + } + } + // map of sub-shapes -> number of occurrences of these shapes in containers NCollection_DataMap 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()); @@ -1202,12 +1246,112 @@ void Model_AttributeSelection::computeValues( aSubsIter(aSubs); for(; aSubsIter.More(); aSubsIter.Next()) { if (aSubsIter.Value().Size() == aCountInOld) { - theShapes.Append(aSubsIter.Key()); + TopoDS_Shape anOld = aSubsIter.Key(); + // check this exists in the new shape + TopExp_Explorer aNew(aNewContShape, anOld.ShapeType()); + for (; aNew.More(); aNew.Next()) { + if (aNew.Current().IsSame(anOld)) + break; + } + if (aNew.More()) + theShapes.Append(anOld); } } } if (theShapes.IsEmpty()) { // nothing was changed - theShapes.Append(aWasWholeContext ? TopoDS_Shape() : theValShape); + if (aWasWholeContext) + theShapes.Append(TopoDS_Shape()); + else { // if theValShape exists in new context, add it without changes, otherwise - nothing + 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(); + 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, const bool theCheckCopy, + std::list& theConcealers, const ResultPtr theResultOfFeature) +{ + std::set alreadyProcessed; + alreadyProcessed.insert(theFeature); + if (theStop.get()) + alreadyProcessed.insert(theStop); + /// iterate all results to find the concealment-attribute + std::list 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::const_iterator aRootIter = aRootRes.cbegin(); + for(; aRootIter != aRootRes.cend(); aRootIter++) { + std::list allRes; + allRes.push_back(*aRootIter); + ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true); + if (!aRootBody.get()) + aRootBody = std::dynamic_pointer_cast(*aRootIter); + if (aRootBody.get()) { + ModelAPI_Tools::allSubs(aRootBody, allRes); + } + for(std::list::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) { + const std::set& aRefs = (*aRIter)->data()->refsToMe(); + std::set::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((*aRef)->owner()); + if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization + continue; + alreadyProcessed.insert(aRefFeat); + if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()) + || (theCheckCopy && + std::dynamic_pointer_cast(aRefFeat).get())) + { + // 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 aDoc = + std::dynamic_pointer_cast(theStop->document()); + if (!aDoc->isLaterByDep(theStop, aRefFeat)) // skip feature later than stop + continue; + } + theConcealers.push_back(aRefFeat); + } + } + } + } } } @@ -1217,7 +1361,6 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr std::list& theResults, TopTools_ListOfShape& theValShapes) { std::set aResults; // to avoid duplicates, new context, null if deleted - TopTools_ListOfShape aResContShapes; // iterate context and shape, but also if it is sub-shape of main shape, check also it TopTools_ListOfShape aContextList; aContextList.Append(theContShape); @@ -1254,7 +1397,6 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr aModifIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNewNS); if (aNewNS->Evolution() == TNaming_MODIFY || aNewNS->Evolution() == TNaming_GENERATED) { aResults.insert(aModifierObj); - aResContShapes.Append(aModifierObj->shape()->impl()); } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is empty aResults.insert(ResultPtr()); } else { // not-processed modification => don't support it @@ -1262,25 +1404,126 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr } } } - if (aResults.empty()) - return false; // no modifications found, must stay the same + // if there exist context composite and sub-result(s), leave only sub(s) + for(std::set::iterator aResIter = aResults.begin(); aResIter != aResults.end();) { + ResultPtr aParent = ModelAPI_Tools::bodyOwner(*aResIter); + for(; aParent.get(); aParent = ModelAPI_Tools::bodyOwner(aParent)) + if (aResults.count(aParent)) + break; + if (aParent.get()) { // erase from set, so, restart iteration + aResults.erase(aParent); + aResIter = aResults.begin(); + } else aResIter++; + } + + bool aStaySame = false; + if (aResults.empty()) { + // check the context become concealed by operation which is earlier than this selection + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + FeaturePtr aContextOwner = theDoc->feature(theContext); + std::list aConcealers; + concealedFeature(aContextOwner, aThisFeature, false, aConcealers, theContext); + std::list::iterator aConcealer = aConcealers.begin(); + for(; aConcealer != aConcealers.end(); aConcealer++) { + std::list aRefResults; + ModelAPI_Tools::allResults(*aConcealer, aRefResults); + std::list::iterator aRefIter = aRefResults.begin(); + for(; aRefIter != aRefResults.end(); aRefIter++) { + ResultBodyPtr aRefBody = std::dynamic_pointer_cast(*aRefIter); + if (!aRefBody.get() || aRefBody->numberOfSubs() != 0) // iterate only leafs + continue; + GeomShapePtr aRefShape = aRefBody->shape(); + if (!aRefShape.get() || aRefShape->isNull()) + continue; + if (aRefShape->impl().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 + } + aStaySame = aResults.empty(); + } + if (myParent && myParent->isMakeCopy()) { + // check there are copies before the new results, so, make a copy + std::set::iterator aResIter = aResults.begin(); + std::list aCopyContext; + std::list aCopyVals; + // features between the new and the old: check the "Move" interface to get a copy + FeaturePtr aRootOwner = theDoc->feature(theContext); + FeaturePtr anOwner = ModelAPI_Tools::compositeOwner(aRootOwner); + for(; anOwner.get(); anOwner = ModelAPI_Tools::compositeOwner(anOwner)) + aRootOwner = anOwner; + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + // iterate all results to find a "Copy" features between the new and one and to add the + // copy-results also to results if this attribute refers to the copied shape + int anIndex = kUNDEFINED_FEATURE_INDEX; + for(FeaturePtr aFeat = theDoc->objects()->nextFeature(aRootOwner, anIndex); aFeat.get() && + aFeat != aThisFeature; aFeat = theDoc->objects()->nextFeature(aFeat, anIndex)) { + std::shared_ptr aCopier = + std::dynamic_pointer_cast(aFeat); + if (aCopier.get()) { + GeomShapePtr aValShape(new GeomAPI_Shape); + aValShape->setImpl(new TopoDS_Shape( + theValShape.IsNull() ? theContShape : theValShape)); + aCopier->getCopies(theContext, aValShape, aCopyContext, aCopyVals); + } + } + // check for the further modifications of the copy contexts and values + std::list::iterator aCopyContIter = aCopyContext.begin(); + std::list::iterator aCopyValIter = aCopyVals.begin(); + for(; aCopyContIter != aCopyContext.end(); aCopyContIter++, aCopyValIter++) { + ResultPtr aNewCont = std::dynamic_pointer_cast(*aCopyContIter); + TopoDS_Shape aNewContShape = aNewCont->shape()->impl(); + GeomShapePtr aNewVal = *aCopyValIter; + TopoDS_Shape aNewValShape; + if (aNewVal.get() && !aNewVal->isNull()) + aNewValShape = aNewVal->impl(); + std::list aNewRes; + TopTools_ListOfShape aNewUpdatedVal; + if (searchNewContext(theDoc, aNewContShape, aNewCont, aNewValShape, + theAccessLabel, aNewRes, aNewUpdatedVal)) { + // append new results instead of the current ones + std::list::iterator aNewIter = aNewRes.begin(); + TopTools_ListIteratorOfListOfShape aNewUpdVal(aNewUpdatedVal); + for(; aNewIter != aNewRes.end(); aNewIter++, aNewUpdVal.Next()) { + theResults.push_back(*aNewIter); + theValShapes.Append(aNewUpdVal.Value()); + } + } else { // the current result is good + theResults.push_back(aNewCont); + theValShapes.Append(aNewValShape); + } + } + if (aStaySame && !theResults.empty()) { // no changes except copy, so, keep the origin as first + theResults.push_front(theContext); + theValShapes.Prepend(theValShape); + return true; + } + } + if (aStaySame) + return false; + // iterate all results to find further modifications std::set::iterator aResIter = aResults.begin(); - for(; aResIter != aResults.end(); aResIter++) { + for(aResIter = aResults.begin(); aResIter != aResults.end(); aResIter++) { if (aResIter->get() != NULL) { + ResultPtr aNewResObj = *aResIter; // compute new values by two contexts: the old and the new TopTools_ListOfShape aValShapes; - computeValues(theContext, *aResIter, theValShape, aValShapes); + computeValues(theContext, aNewResObj, theValShape, aValShapes); TopTools_ListIteratorOfListOfShape aNewVal(aValShapes); for(; aNewVal.More(); aNewVal.Next()) { std::list aNewRes; TopTools_ListOfShape aNewUpdatedVal; TopoDS_Shape aNewValSh = aNewVal.Value(); - TopoDS_Shape aNewContShape = (*aResIter)->shape()->impl(); + TopoDS_Shape aNewContShape = aNewResObj->shape()->impl(); + if (theValShape.IsNull() && aNewContShape.IsSame(aNewValSh)) aNewValSh.Nullify(); - if (searchNewContext(theDoc, aNewContShape, *aResIter, aNewValSh, + if (searchNewContext(theDoc, aNewContShape, aNewResObj, aNewValSh, theAccessLabel, aNewRes, aNewUpdatedVal)) { // append new results instead of the current ones @@ -1291,7 +1534,7 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr theValShapes.Append(aNewUpdVal.Value()); } } else { // the current result is good - theResults.push_back(*aResIter); + theResults.push_back(aNewResObj); theValShapes.Append(aNewValSh); } } @@ -1300,20 +1543,73 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr return true; // theResults must be empty: everything is deleted } -void Model_AttributeSelection::updateInHistory() +void Model_AttributeSelection::updateInHistory(bool& theRemove) { + static std::shared_ptr anEmptyShape; + ResultPtr aContext = std::dynamic_pointer_cast(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(myRef.value()); + if (aFeature.get()) { + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + std::list aConcealers; + bool aCopyPossible = myParent && myParent->isMakeCopy(); + concealedFeature(aFeature, aThisFeature, aCopyPossible, aConcealers, ResultPtr()); + if (aConcealers.empty()) + return; + // if there are copies, but no direct modification, keep the original + bool aKeepOrigin = false; + if (aCopyPossible) { + std::list::iterator aConcealer = aConcealers.begin(); + for(aKeepOrigin = true; aConcealer != aConcealers.end(); aConcealer++) + if (!std::dynamic_pointer_cast(*aConcealer).get()) { + aKeepOrigin = false; + break; + } + if (aKeepOrigin) { + aConcealers.push_front(aFeature); + } + } + bool aChanged = false; + std::list::iterator aConcealer = aConcealers.begin(); + for(; aConcealer != aConcealers.end(); aConcealer++) + if (aChanged) { + if (aKeepOrigin || !myParent->isInList(*aConcealer, anEmptyShape)) + myParent->append(*aConcealer, anEmptyShape); + } else { + if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates + setValue(*aConcealer, anEmptyShape); + aChanged = true; + } else if (aCopyPossible && *aConcealer == aFeature) {// keep origin in case of copy + aChanged = true; + } + } + if (!aChanged) // remove this + theRemove = true; + else if (!aKeepOrigin) // searching further modifications only if current changed + updateInHistory(theRemove); + } + } + return;// only bodies and parts may be modified later in the history, skip otherwise + } + std::shared_ptr aDoc = std::dynamic_pointer_cast(aContext->document()); std::shared_ptr aContData = std::dynamic_pointer_cast(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; @@ -1334,7 +1630,12 @@ void Model_AttributeSelection::updateInHistory() continue; FeaturePtr aRefFeat = std::dynamic_pointer_cast((*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(owner()); if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature aFoundNewContext = true; @@ -1373,17 +1674,77 @@ void Model_AttributeSelection::updateInHistory() TopTools_ListOfShape aValShapes; if (searchNewContext(aDoc, aNewCShape, aContext, aValShape, aContLab, aNewContexts, aValShapes)) { + std::set allContexts, aSkippedContext; + std::list::iterator aNewContext = aNewContexts.begin(); + for(; aNewContext != aNewContexts.end(); aNewContext++) + allContexts.insert(*aNewContext); + + // if there exist context composite and sub-result(s), leave only sub(s) + std::set::iterator aResIter = allContexts.begin(); + for(; aResIter != allContexts.end(); aResIter++) { + ResultPtr aParent = ModelAPI_Tools::bodyOwner(*aResIter); + for(; aParent.get(); aParent = ModelAPI_Tools::bodyOwner(aParent)) + if (allContexts.count(aParent)) + aSkippedContext.insert(aParent); + } + 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::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::iterator aNewCont = aNewContexts.begin(); TopTools_ListIteratorOfListOfShape aNewValues(aValShapes); bool aFirst = true; // first is set to this, next are appended to parent for(; aNewCont != aNewContexts.end(); aNewCont++, aNewValues.Next()) { + 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()) { @@ -1398,20 +1759,51 @@ void Model_AttributeSelection::updateInHistory() 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(aNewContext); + if (aBodyContext.get() && aBodyContext->numberOfSubs() != 0) { + std::list aLower; + ModelAPI_Tools::allSubs(aBodyContext, aLower, true); + for(std::list::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 (aNewContext == aContext && myParent && myParent->isMakeCopy()) { + // this may be exactly the old one, not modified in case of copy + aFirst = false; + } } else if (myParent) { - 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 - ResultPtr anEmptyContext; - std::shared_ptr anEmptyShape; - setValue(anEmptyContext, anEmptyShape); // nullify the selection - return; + if (myParent) { + theRemove = true; + } else { + static ResultPtr anEmptyContext; + setValue(anEmptyContext, anEmptyShape); // nullify the selection + return; + } } } } @@ -1547,18 +1939,6 @@ bool Model_AttributeSelection::restoreContext(std::string theName, return true; } -TDF_Label Model_AttributeSelection::newestContext(const TDF_Label theCurrentContext) { - std::shared_ptr aDoc = myRestoreDocument.get() ? myRestoreDocument : - std::dynamic_pointer_cast(owner()->document()); - ResultPtr aContext = aDoc->resultByLab(theCurrentContext); - if (aContext.get()) { - aContext = newestContext(aContext, GeomShapePtr(), true); - if (aContext.get()) - return std::dynamic_pointer_cast(aContext->data())->label(); - } - return theCurrentContext; // nothing is changed -} - bool Model_AttributeSelection::isLater( const TDF_Label theResult1, const TDF_Label theResult2) const { @@ -1574,7 +1954,7 @@ bool Model_AttributeSelection::isLater( } ResultPtr Model_AttributeSelection::newestContext( - const ResultPtr theCurrent, const GeomShapePtr theValue, const bool theAnyValue) + const ResultPtr theCurrent, const GeomShapePtr theValue) { ResultPtr aResult = theCurrent; GeomShapePtr aSelectedShape = theValue.get() ? theValue : theCurrent->shape(); @@ -1597,7 +1977,7 @@ ResultPtr Model_AttributeSelection::newestContext( TDF_Label aLab = aNS->Label(); ResultPtr aRes = aDoc->resultByLab(aLab); if (aRes.get()) { - if (theAnyValue || aRes->shape()->isSubShape(aSelectedShape)) { + if (aRes->shape()->isSubShape(aSelectedShape)) { aResult = aRes; aFindNewContext = true; continue; @@ -1606,47 +1986,6 @@ ResultPtr Model_AttributeSelection::newestContext( } } } - if (theAnyValue) { // only for neighbors for now - // try to find modification of sub-shapes: the best number of matches - std::map aMatches; // result -> number of matches of shapes to find the best - TDF_Label aResLab = std::dynamic_pointer_cast(aResult->data())->shapeLab(); - TDF_ChildIDIterator aModifIter(aResLab, TNaming_NamedShape::GetID()); - for(; aModifIter.More(); aModifIter.Next()) { - Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aModifIter.Value()); - if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED) { - for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) { - TNaming_NewShapeIterator aNewIter(aNSIter.NewShape(), aNS->Label()); - for(; aNewIter.More(); aNewIter.Next()) { - TDF_Label aLab = aNewIter.Label(); - if (isLater(aLab, aNS->Label()) && isLater(selectionLabel(), aLab)) { - ResultPtr aRes = aDoc->resultByLab(aLab); - if (aRes.get()) { - if (aMatches.find(aRes) == aMatches.end()) - aMatches[aRes] = 0; - aMatches[aRes]++; // found result, add matches - } - } - } - } - } - } - // searching for the best result-candidate - int aBest = 0; - ResultPtr aBestResult; - std::map::iterator aMatchIter = aMatches.begin(); - for(; aMatchIter != aMatches.end(); aMatchIter++) { - if (aMatchIter->second > aBest) { - aBest = aMatchIter->second; - aBestResult = aMatchIter->first; - } - } - if (aBestResult.get()) { - aResult = aBestResult; - aFindNewContext = true; - continue; - } - } - // TestFillWireVertex.py - sketch constructions for wire may participate too //if (aResult->groupName() == ModelAPI_ResultBody::group()) { @@ -1692,43 +2031,15 @@ ResultPtr Model_AttributeSelection::newestContext( } std::list >::iterator aResIter = aResults.begin(); - if (theAnyValue) { // searching the best sub-result by maximum number of references to orig - int aReferencesCount = 0; - ResultPtr aBestResult; - for (; aResIter != aResults.end(); aResIter++) { - if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) - continue; - TDF_Label aCandidateLab = - std::dynamic_pointer_cast((*aResIter)->data())->shapeLab(); - Handle(TDF_Reference) aRef; - if (aCandidateLab.FindAttribute(TDF_Reference::GetID(), aRef)) { - TDF_Label aRefLab = aRef->Get(); - ResultPtr aRefRes = aDoc->resultByLab(aRefLab); - if (aRefRes.get() && aRefRes->shape().get() && - aRefRes->shape()->isEqual(aResult->shape())) {// it directly references to result - aResult = *aResIter; // found new context (produced from this) with same subshape - aFindNewContext = true; // continue searching further - break; - } - } else { - if (!aBestResult.get()) - aBestResult = *aResIter; - } - } - if (aBestResult.get() && !aFindNewContext) { // the first good result for now - aResult = aBestResult; // found new context - aFindNewContext = true; - } - } else { // searching by sub-shape - for (; aResIter != aResults.end(); aResIter++) { - if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) - continue; - GeomShapePtr aShape = (*aResIter)->shape(); - if (aShape.get() && (theAnyValue || aShape->isSubShape(aSelectedShape, false))) { - aResult = *aResIter; // found new context (produced from this) with same subshape - aFindNewContext = true; // continue searching further - break; - } + // searching by sub-shape + for (; aResIter != aResults.end(); aResIter++) { + if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) + continue; + GeomShapePtr aShape = (*aResIter)->shape(); + if (aShape.get() && aShape->isSubShape(aSelectedShape, false)) { + aResult = *aResIter; // found new context (produced from this) with same subshape + aFindNewContext = true; // continue searching further + break; } } } @@ -1743,7 +2054,7 @@ ResultPtr Model_AttributeSelection::newestContext( for (; aS != allSubs.end(); aS++) { ResultBodyPtr aSub = std::dynamic_pointer_cast(*aS); if (aSub && aSub->numberOfSubs() == 0 && aSub->shape().get() && - (theAnyValue || aSub->shape()->isSubShape(aSelectedShape))) { + aSub->shape()->isSubShape(aSelectedShape)) { aResult = aSub; break; } @@ -1806,3 +2117,9 @@ TDF_Label Model_AttributeSelection::baseDocumentLab() static TDF_Label anEmpty; return anEmpty; } + +void Model_AttributeSelection::reset() +{ + ModelAPI_AttributeSelection::reset(); + myRef.reset(); +}