X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=432c6f1c2e7740d37293b040c46aafd89823e727;hb=9a3d914571afc7318df989643dca720889fcc50b;hp=7b1259db39ecaa7c013a37deb329fdf113d7fa38;hpb=5b5555341ff05692c42d0381a27852707bcc73ca;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 7b1259db3..432c6f1c2 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-2021 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" @@ -23,7 +22,6 @@ #include "Model_Events.h" #include "Model_Data.h" #include "Model_Document.h" -#include "Model_SelectionNaming.h" #include #include #include @@ -31,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -40,15 +39,20 @@ #include #include #include +#include #include +#include #include #include +#include + +#include -#include #include #include #include #include +#include #include #include #include @@ -59,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +71,7 @@ #include #include #include +#include #include //#define DEB_NAMING 1 @@ -88,13 +94,9 @@ Standard_GUID kCIRCLE_CENTER("d0d0e0f1-217a-4b95-8fbb-0c4132f23718"); Standard_GUID kELLIPSE_CENTER1("f70df04c-3168-4dc9-87a4-f1f840c1275d"); // identifier of the selection of the second focus point of ellipse on edge Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32"); -// identifier of the weak naming index -Standard_GUID kWEAK_NAMING("9dcdd9be-a3a9-46eb-9b16-1c957ab20142"); -// identifier of the weak naming sub-shape type -Standard_GUID kWEAK_NAMING_SHAPETYPE("6b9cc709-e320-4a1f-9c42-df5622369ea7"); // prefix for the whole feature context identification -const static std::string kWHOLE_FEATURE = "all-in-"; +const static std::wstring kWHOLE_FEATURE = L"all-in-"; // on this label is stored: // TNaming_NamedShape - selected shape @@ -105,10 +107,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; @@ -131,15 +132,13 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext, myRef.setValue(theContext); } - // do noth use naming if selected shape is result shape itself, but not sub-shape + // do not use naming if selected shape is result shape itself, but not sub-shape TDF_Label aSelLab = selectionLabel(); aSelLab.ForgetAttribute(kSIMPLE_REF_ID); aSelLab.ForgetAttribute(kINVALID_SELECTION); aSelLab.ForgetAttribute(kCIRCLE_CENTER); aSelLab.ForgetAttribute(kELLIPSE_CENTER1); aSelLab.ForgetAttribute(kELLIPSE_CENTER2); - aSelLab.ForgetAttribute(kWEAK_NAMING); - aSelLab.ForgetAttribute(kWEAK_NAMING_SHAPETYPE); bool isDegeneratedEdge = false; // do not use the degenerated edge as a shape, a null context and shape is used in the case @@ -149,50 +148,48 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext, isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape)) == Standard_True; } if (!theContext.get() || isDegeneratedEdge) { - // to keep the reference attribute label - TDF_Label aRefLab = myRef.myRef->Label(); aSelLab.ForgetAllAttributes(true); myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father()); if (aToUnblock) owner()->data()->blockSendAttributeUpdated(false); return false; } - if (theContext->groupName() == ModelAPI_ResultBody::group()) { - ResultBodyPtr aContextBody = std::dynamic_pointer_cast(theContext); + bool isSelectBody = theContext->groupName() == ModelAPI_ResultBody::group(); + if (!isSelectBody) { + ResultConstructionPtr aContextConstruction = + std::dynamic_pointer_cast(theContext); + isSelectBody = aContextConstruction.get() && !aContextConstruction->isInfinite(); + } + if (isSelectBody) { + ResultPtr aContextResult = std::dynamic_pointer_cast(theContext); + GeomShapePtr aContextShape = aContextResult->shape(); // do not select the whole shape for body:it is already must be in the data framework // equal and null selected objects mean the same: object is equal to context, - if (aContextBody->shape().get() && - (aContextBody->shape()->isEqual(theSubShape) || !theSubShape.get())) { + if (aContextShape.get() && (aContextShape->isEqual(theSubShape) || !theSubShape.get())) { aSelLab.ForgetAllAttributes(true); TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID); } else { - selectBody(aContextBody, theSubShape); + selectBody(aContextResult, theSubShape); } } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) { - ResultConstructionPtr aContextConstruction = - std::dynamic_pointer_cast(theContext); aSelLab.ForgetAllAttributes(true); // to remove old selection data std::shared_ptr aConstruction = std::dynamic_pointer_cast(theContext); std::shared_ptr aSubShape; - if (theSubShape.get() && !aContextConstruction->shape()->isEqual(theSubShape)) + if (theSubShape.get() && !aConstruction->shape()->isEqual(theSubShape)) aSubShape = theSubShape; // the whole context - if (aConstruction->isInfinite()) { - // For correct naming selection, put the shape into the naming structure. - // It seems sub-shapes are not needed: only this shape is (and can be ) selected. - TNaming_Builder aBuilder(aSelLab); - aBuilder.Generated(aContextConstruction->shape()->impl()); - } - int anIndex = aConstruction->select(theSubShape, owner()->document()); - TDataStd_Integer::Set(aSelLab, anIndex); } else if (theContext->groupName() == ModelAPI_ResultPart::group()) { 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) @@ -235,6 +232,8 @@ void Model_AttributeSelection::setValueCenter( anUpdated = !aSelLab.IsAttribute(kELLIPSE_CENTER2); TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER2); break; + default: // [to avoid compilation warning] + break; } if (anUpdated) owner()->data()->sendAttributeUpdated(this); @@ -264,7 +263,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) { @@ -277,11 +276,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, @@ -302,7 +305,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); @@ -321,7 +324,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(); @@ -339,8 +349,8 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp if (myRef.isInitialized()) { if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape ResultPtr aContext = context(); - if (!aContext.get()) - return aResult; // empty result + if (!aContext.get() || aContext->groupName() == ModelAPI_ResultConstruction::group()) + return aResult; // empty result, for whole construction selection also return aContext->shape(); } if (aSelLab.IsAttribute(kPART_REF_ID)) { @@ -354,13 +364,13 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp } else { // face with name is already in the data model, so try to take it by name Handle(TDataStd_Name) aName; if (aSelLab.FindAttribute(TDataStd_Name::GetID(), aName)) { - std::string aSubShapeName(TCollection_AsciiString(aName->Get()).ToCString()); - std::size_t aPartEnd = aSubShapeName.find('/'); - if (aPartEnd != std::string::npos && aPartEnd != aSubShapeName.rfind('/')) { - std::string aNameInPart = aSubShapeName.substr(aPartEnd + 1); - int anIndex; + std::wstring aSubShapeName = Locale::Convert::toWString(aName->Get().ToExtString()); + std::size_t aPartEnd = aSubShapeName.find(L'/'); + if (aPartEnd != std::wstring::npos && aPartEnd != aSubShapeName.rfind(L'/')) { + std::wstring aNameInPart = aSubShapeName.substr(aPartEnd + 1); + int anInd; std::string aType; // to reuse already existing selection the type is not needed - return aPart->shapeInPart(aNameInPart, aType, anIndex); + return aPart->shapeInPart(aNameInPart, aType, anInd); } } } @@ -389,30 +399,10 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp } return GeomAlgoAPI_CompoundBuilder::compound(allShapes); } - } - - if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used - Handle(TDataStd_Integer) aWeakId; - aSelLab.FindAttribute(kWEAK_NAMING, aWeakId); - // get the context shape - GeomShapePtr aContextShape; - ResultBodyPtr aBody = std::dynamic_pointer_cast(context()); - if (aBody.get()) { - aContextShape = aBody->shape(); - } else { - ResultPtr aResult = std::dynamic_pointer_cast(myRef.value()); - if (aResult) { - aContextShape = aResult->shape(); - } + } else { + if (contextFeature().get()) { + return aResult; // for the whole sketch feature selected return null => all faces } - if (!aContextShape.get()) - return GeomShapePtr(); - Handle(TDataStd_Integer) aWeakShapeType; - aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType); - GeomAlgoAPI_NExplode aNExplode( - aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get())); - GeomShapePtr aValue = aNExplode.shape(aWeakId->Get()); - return aValue; } Handle(TNaming_NamedShape) aSelection; @@ -421,12 +411,7 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp aResult = std::shared_ptr(new GeomAPI_Shape); aResult->setImpl(new TopoDS_Shape(aSelShape)); } else if (aConstr) { // simple construction element: just shape of this construction element - Handle(TDataStd_Integer) anIndex; - if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { - if (anIndex->Get() == 0) // it is just reference to construction, nothing is in value - return aResult; - return aConstr->shape(anIndex->Get(), owner()->document()); - } + aResult = aConstr->shape(); } } return aResult; @@ -439,39 +424,37 @@ 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()) { - Handle(TDataStd_Integer) anIndex; - if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { - // for the whole shape it may return null, so, if index exists, returns true - 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; } Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel) - : myRef(theLabel) +: myRef(theLabel), + myIsGeometricalSelection(false) { myIsInitialized = myRef.isInitialized(); myParent = NULL; @@ -481,15 +464,23 @@ void Model_AttributeSelection::setID(const std::string theID) { myRef.setID(theID); ModelAPI_AttributeSelection::setID(theID); + FeaturePtr aFeature = std::dynamic_pointer_cast(owner()); + if (myParent) { + // 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()); + } } 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()); @@ -502,7 +493,7 @@ ResultPtr Model_AttributeSelection::context() if(aPart.get() && aPart->data() == aResult->data()) { ResultPtr aPartResult = std::dynamic_pointer_cast(aPart); FeaturePtr anOwnerFeature = std::dynamic_pointer_cast(owner()); - // check that this result is not this-feature result (it is forbidden t oselect itself) + // check that this result is not this-feature result (it is forbidden to select itself) if(anOwnerFeature.get() && anOwnerFeature->firstResult() != aPartResult) { return aPartResult; } @@ -519,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(myTmpContext); } return std::dynamic_pointer_cast(myRef.value()); } @@ -538,69 +529,6 @@ void Model_AttributeSelection::setObject(const std::shared_ptr& myRef.setObject(theObject); } -TDF_LabelMap& Model_AttributeSelection::scope() -{ - if (myScope.IsEmpty()) { // create a new scope if not yet done - // gets all features with named shapes that are before this feature label (before in history) - DocumentPtr aMyDoc = owner()->document(); - std::list > allFeatures = aMyDoc->allFeatures(); - std::list >::iterator aFIter = allFeatures.begin(); - bool aMePassed = false; - CompositeFeaturePtr aComposite = - std::dynamic_pointer_cast(owner()); - FeaturePtr aFeature = std::dynamic_pointer_cast(owner()); - CompositeFeaturePtr aCompositeOwner, aCompositeOwnerOwner; - if (aFeature.get()) { - aCompositeOwner = ModelAPI_Tools::compositeOwner(aFeature); - if (aCompositeOwner.get()) { - aCompositeOwnerOwner = ModelAPI_Tools::compositeOwner(aCompositeOwner); - } - } - // for group Scope is not limitet: this is always up to date objects - // this causes problem in galeries.py - //bool isGroup = aFeature.get() && aFeature->getKind() == "Group"; - for(; aFIter != allFeatures.end(); aFIter++) { - if (*aFIter == owner()) { // the left features are created later (except subs of composite) - aMePassed = true; - continue; - } - //if (isGroup) aMePassed = false; - bool isInScope = !aMePassed; - if (!isInScope && aComposite.get()) { - // try to add sub-elements of composite if this is composite - if (aComposite->isSub(*aFIter)) - isInScope = true; - } - // remove the composite-owner of this feature (sketch in extrusion-cut) - if (isInScope && (aCompositeOwner == *aFIter || aCompositeOwnerOwner == *aFIter)) - isInScope = false; - - if (isInScope && aFIter->get() && (*aFIter)->data()->isValid()) { - TDF_Label aFeatureLab = std::dynamic_pointer_cast( - (*aFIter)->data())->label().Father(); - TDF_ChildIDIterator aNSIter(aFeatureLab, TNaming_NamedShape::GetID(), true); - for(; aNSIter.More(); aNSIter.Next()) { - Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); - if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) { - myScope.Add(aNS->Label()); - } - } - } - } - // also add all naming labels created for external constructions - std::shared_ptr aDoc = std::dynamic_pointer_cast(aMyDoc); - TDF_Label anExtDocLab = aDoc->extConstructionsLabel(); - TDF_ChildIDIterator aNSIter(anExtDocLab, TNaming_NamedShape::GetID(), true); - for(; aNSIter.More(); aNSIter.Next()) { - Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); - if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) { - myScope.Add(aNS->Label()); - } - } - } - return myScope; -} - /// Sets the invalid flag if flag is false, or removes it if "true" /// Returns theFlag static bool setInvalidIfFalse(TDF_Label& theLab, const bool theFlag) { @@ -631,7 +559,7 @@ void Model_AttributeSelection::split( aSubSh->setImpl(new TopoDS_Shape(aSub.Value())); setValue(theContext, aSubSh); for(aSub.Next(); aSub.More(); aSub.Next()) { - GeomShapePtr aSubSh(new GeomAPI_Shape); + aSubSh.reset(new GeomAPI_Shape); aSubSh->setImpl(new TopoDS_Shape(aSub.Value())); myParent->append(theContext, aSubSh); } @@ -642,6 +570,7 @@ bool Model_AttributeSelection::update() { FeaturePtr aContextFeature = contextFeature(); if (aContextFeature.get()) { + owner()->data()->sendAttributeUpdated(this); // send updated if "update" called in any way return true; } TDF_Label aSelLab = selectionLabel(); @@ -663,73 +592,89 @@ bool Model_AttributeSelection::update() } if (aContext->groupName() == ModelAPI_ResultBody::group()) { - if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used - Handle(TDataStd_Integer) aWeakId; - aSelLab.FindAttribute(kWEAK_NAMING, aWeakId); - // get the context shape - GeomShapePtr aContextShape; - ResultBodyPtr aBody = std::dynamic_pointer_cast(aContext); - if (aBody.get()) { - aContextShape = aBody->shape(); - } else { - ResultPtr aResult = std::dynamic_pointer_cast(myRef.value()); - if (aResult) { - aContextShape = aResult->shape(); - } - } - if (!setInvalidIfFalse(aSelLab, aContextShape.get() != NULL)) // context shape not found - return false; - Handle(TDataStd_Integer) aWeakShapeType; - aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType); - GeomAlgoAPI_NExplode aNExplode( - aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get())); - GeomShapePtr aValue = aNExplode.shape(aWeakId->Get()); - return setInvalidIfFalse(aSelLab, aValue.get() != NULL); - } - // body: just a named shape, use selection mechanism from OCCT - TNaming_Selector aSelector(aSelLab); + // body: just a named shape, use topological selection mechanism + bool aResult = false; TopoDS_Shape anOldShape; - if (!aSelector.NamedShape().IsNull()) { - anOldShape = aSelector.NamedShape()->Get(); - } - bool aResult = aSelector.Solve(scope()) == Standard_True; - // must be before sending of updated attribute (1556) - aResult = setInvalidIfFalse(aSelLab, aResult); + Handle(TNaming_NamedShape) aNS; + if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + anOldShape = aNS->Get(); + + TopoDS_Shape aContextShape = aContext->shape()->impl(); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + aResult = aSelector.restore(aContextShape); + bool aWasInvalid = aSelLab.IsAttribute(kINVALID_SELECTION); + setInvalidIfFalse(aSelLab, aResult); + if (!aResult) + aWasInvalid = false; + TopoDS_Shape aNewShape; - if (!aSelector.NamedShape().IsNull()) { - aNewShape = aSelector.NamedShape()->Get(); + if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + aNewShape = aNS->Get(); + + // check the selected value is a part of the context + if (aResult && !aNewShape.IsNull() && !aContextShape.IsNull() && + !aContextShape.IsSame(aNewShape)) { + TopoDS_Shape aNewS = aNewShape; + // take only sub-shape of composite for checking + if (aNewS.ShapeType() == TopAbs_WIRE || aNewS.ShapeType() == TopAbs_SHELL || + aNewS.ShapeType() == TopAbs_COMPOUND || aNewS.ShapeType() == TopAbs_COMPSOLID) { + TopoDS_Iterator anIter(aNewS); + if (anIter.More()) + aNewS = anIter.Value(); + } + bool anIsInside = false; + TopExp_Explorer anExp(aContextShape, aNewS.ShapeType()); + for (; anExp.More() && !anIsInside; anExp.Next()) { + if (anExp.Current().IsSame(aNewS)) + anIsInside = true; + } + if (!anIsInside) { + aResult = false; + aNewShape.Nullify(); + setInvalidIfFalse(aSelLab, aResult); + } } - if (anOldShape.IsNull() || aNewShape.IsNull() || - !anOldShape.IsEqual(aSelector.NamedShape()->Get())) { - // shape type shoud not not changed: if shape becomes compound of such shapes, then split + + 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 (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; } if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { - Handle(TDataStd_Integer) anIndex; - if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { - std::shared_ptr aConstructionContext = - std::dynamic_pointer_cast(aContext); - bool aModified = true; - bool aValid = aConstructionContext->update(anIndex->Get(), owner()->document(), aModified); - setInvalidIfFalse(aSelLab, aValid); - if (aConstructionContext->isInfinite()) { - // Update the selected shape. - TNaming_Builder aBuilder(aSelLab); - aBuilder.Generated(aConstructionContext->shape()->impl()); - } - if (aModified) - owner()->data()->sendAttributeUpdated(this); - return aValid; + bool aResult = true; + std::shared_ptr aConstructionContext = + std::dynamic_pointer_cast(aContext); + if (!aConstructionContext->isInfinite()) { + TopoDS_Shape aContextShape = aContext->shape()->impl(); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + TopoDS_Shape anOldShape = aSelector.value(); + aResult = aSelector.restore(aContextShape); + setInvalidIfFalse(aSelLab, aResult); + if (aResult && !anOldShape.IsEqual(aSelector.value())) + owner()->data()->sendAttributeUpdated(this); // send updated if shape is changed + } else { + owner()->data()->sendAttributeUpdated(this); // send updated if "update" called in any way } + return aResult; } return setInvalidIfFalse(aSelLab, false); // unknown case } @@ -738,10 +683,9 @@ void Model_AttributeSelection::selectBody( const ResultPtr& theContext, const std::shared_ptr& theSubShape) { // perform the selection - TNaming_Selector aSel(selectionLabel()); TopoDS_Shape aContext; - ResultBodyPtr aBody = std::dynamic_pointer_cast(theContext);//myRef.value() + ResultPtr aBody = std::dynamic_pointer_cast(theContext); if (aBody) { aContext = aBody->shape()->impl(); } else { @@ -755,116 +699,25 @@ void Model_AttributeSelection::selectBody( } } - // with "recover" feature the selected context may be not up to date (issue 1710) - Handle(TNaming_NamedShape) aResult; - TDF_Label aSelLab = selectionLabel(); - TopoDS_Shape aNewContext = aContext; - bool isUpdated = true; - while(!aNewContext.IsNull() && isUpdated) { - // searching for the very last shape that was produced from this one - isUpdated = false; - if (!TNaming_Tool::HasLabel(aSelLab, aNewContext)) - // to avoid crash of TNaming_SameShapeIterator if pure shape does not exists - break; - for(TNaming_SameShapeIterator anIter(aNewContext, aSelLab); anIter.More(); anIter.Next()) { - TDF_Label aNSLab = anIter.Label(); - if (!scope().Contains(aNSLab)) - continue; - Handle(TNaming_NamedShape) aNS; - if (aNSLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) { - if (aShapesIter.Evolution() == TNaming_SELECTED) - continue; // don't use the selection evolution - if (!aShapesIter.OldShape().IsNull() && aShapesIter.OldShape().IsSame(aNewContext)) { - // found the original shape - aNewContext = aShapesIter.NewShape(); // go to the newer shape - isUpdated = true; - break; - } - } - } - } - } - if (aNewContext.IsNull()) { // a context is already deleted - setInvalidIfFalse(aSelLab, false); - Events_InfoMessage("Model_AttributeSelection", "Failed to select shape already deleted").send(); - return; - } - - TopoDS_Shape aNewSub = theSubShape ? theSubShape->impl() : aContext; - if (!aNewSub.IsEqual(aContext)) { // searching for subshape in the new context - bool isFound = false; - TopExp_Explorer anExp(aNewContext, aNewSub.ShapeType()); - for(; anExp.More(); anExp.Next()) { - if (anExp.Current().IsSame(aNewSub)) { - isFound = true; - break; - } - } - if (!isFound) { // sub-shape is not found in the up-to-date instance of the context shape - // if context is sub-result of compound/compsolid, selection of sub-shape better propagate to - // the main result (which is may be modified); the case is in 1799 - ResultBodyPtr aMain = ModelAPI_Tools::bodyOwner(theContext); - while(ModelAPI_Tools::bodyOwner(aMain).get()) - aMain = ModelAPI_Tools::bodyOwner(theContext); - if (aMain.get()) { - selectBody(aMain, theSubShape); - return; - } - setInvalidIfFalse(aSelLab, false); - Events_InfoMessage("Model_AttributeSelection", - "Failed to select sub-shape already modified").send(); - return; - } - } - - /// fix for issue 411: result modified shapes must not participate in this selection mechanism if (!aContext.IsNull()) { - FeaturePtr aFeatureOwner = std::dynamic_pointer_cast(owner()); - bool aEraseResults = false; - if (aFeatureOwner.get()) { - aEraseResults = !aFeatureOwner->results().empty(); - if (aEraseResults) // erase results without flash deleted and redisplay: do it after Select - aFeatureOwner->removeResults(0, false, false); - } + TDF_Label aSelLab = selectionLabel(); + TopoDS_Shape aNewSub = theSubShape->impl(); + bool aSelectorOk = true; + Selector_Selector aSelector(aSelLab, baseDocumentLab()); try { - aSel.Select(aNewSub, aNewContext); + aSelectorOk = aSelector.select(aContext, aNewSub, myIsGeometricalSelection); + if (aSelectorOk) { + aSelectorOk = aSelector.store(aContext); + } } catch(...) { aSelectorOk = false; } - // face may become divided after the model update, so, new labels may be added to the scope - myScope.Clear(); - - // check that selection is correct, otherwise use weak naming solution - TDF_Label aSelLab = selectionLabel(); - aSelLab.ForgetAttribute(kWEAK_NAMING); - Handle(TNaming_NamedShape) aSelectorShape; - if (aSelectorOk && aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelectorShape)) - { - TopoDS_Shape aShape = aSelectorShape->Get(); - if (aShape.IsNull() || aShape.ShapeType() != aNewSub.ShapeType()) - aSelectorOk = false; - } - if (!aSelectorOk) { // weak naming identifier instead - GeomShapePtr aContextShape(new GeomAPI_Shape); - aContextShape->setImpl(new TopoDS_Shape(aNewContext)); - GeomShapePtr aValueShape(new GeomAPI_Shape); - aValueShape->setImpl(new TopoDS_Shape(aNewSub)); - - GeomAlgoAPI_NExplode aNExplode(aContextShape, aValueShape->shapeType()); - int anId = aNExplode.index(aValueShape); - if (anId) { - TDataStd_Integer::Set(aSelLab, kWEAK_NAMING, anId); - TDataStd_Integer::Set(aSelLab, kWEAK_NAMING_SHAPETYPE, int(aValueShape->shapeType())); - } - } - - if (aEraseResults) { // flash after Select : in Groups it makes selection with shift working - static Events_Loop* aLoop = Events_Loop::loop(); - static const Events_ID kDeletedEvent = aLoop->eventByName(EVENT_OBJECT_DELETED); - aLoop->flush(kDeletedEvent); + if (aSelectorOk) { + TopoDS_Shape aShape = aSelector.value(); + aSelectorOk = !aShape.IsNull() && aShape.ShapeType() == aNewSub.ShapeType(); } + setInvalidIfFalse(aSelLab, aSelectorOk); } } @@ -890,13 +743,13 @@ bool Model_AttributeSelection::selectPart( } // store the shape (in case part is not loaded it should be useful TopoDS_Shape aShape; - std::string aName = theContext->data()->name(); + std::wstring aName = theContext->data()->name(); if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected aShape = theContext->shape()->impl(); } else { aShape = theSubShape->impl(); int anIndex; - aName += "/" + aPart->nameInPart(theSubShape, anIndex); + aName += L"/" + aPart->nameInPart(theSubShape, anIndex); TDataStd_Integer::Set(selectionLabel(), anIndex); } TNaming_Builder aBuilder(selectionLabel()); @@ -912,51 +765,92 @@ TDF_Label Model_AttributeSelection::selectionLabel() } /// prefixes of the shape names with centers defined -static std::map kCENTERS_PREFIX; +static std::map kCENTERS_PREFIX; /// returns the map that contains all possible prefixes of the center-names -static std::map& centersMap() +static std::map& centersMap() { if (kCENTERS_PREFIX.empty()) { // fill map by initial values - kCENTERS_PREFIX[ModelAPI_AttributeSelection::CIRCLE_CENTER] = "__cc"; - kCENTERS_PREFIX[ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS] = "__eff"; - kCENTERS_PREFIX[ModelAPI_AttributeSelection::ELLIPSE_SECOND_FOCUS] = "__esf"; + kCENTERS_PREFIX[ModelAPI_AttributeSelection::CIRCLE_CENTER] = L"__cc"; + kCENTERS_PREFIX[ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS] = L"__eff"; + kCENTERS_PREFIX[ModelAPI_AttributeSelection::ELLIPSE_SECOND_FOCUS] = L"__esf"; } return kCENTERS_PREFIX; } -std::string Model_AttributeSelection::namingName(const std::string& theDefaultName) +std::wstring Model_AttributeSelection::namingName(const std::wstring& theDefaultName) { - std::string aName(""); + std::wstring aName(L""); 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::wstring aNotArgName; + if (aShape.get()) { + aNotArgName = Locale::Convert::toWString(aShape->shapeTypeStr()); + if (myParent) { + std::wostringstream aStream; + aStream << "_" << selectionLabel().Father().Tag(); + aNotArgName += aStream.str(); + } + } + return aNotArgName; + } + 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::wstring aResName; + // checking part-owner + if (aContFeature->document() != owner()->document()) + aResName += Locale::Convert::toWString(aContFeature->document()->kind()) + L"/"; // 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 ""; + return L""; } + ResultPtr aCont = context(); + if (!aCont.get()) { + return L""; // invalid case + } TDF_Label aSelLab = selectionLabel(); - Handle(TDataStd_Integer) aWeakId; - if (aSelLab.FindAttribute(kWEAK_NAMING, aWeakId)) { // a weak naming is used - std::ostringstream aNameStream; - aNameStream<data()->name()<<"/weak_name_"<Get(); - return aNameStream.str(); + if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value + return contextName(aCont); } - Model_SelectionNaming aSelNaming(aSelLab); - std::string aResult = aSelNaming.namingName( - aCont, aSubSh, theDefaultName, owner()->document() != aCont->document()); + // if it is in result of another part + if (aCont->groupName() == ModelAPI_ResultPart::group()) { + ResultPartPtr aPart = std::dynamic_pointer_cast(aCont); + int anIndex; + std::wstring aResult = aSubSh.get() ? + aPart->data()->name() + L"/" + 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); + if (aConstr->isInfinite()) { + return contextName(aCont); + } + } + + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + std::wstring aResult; + if (aCont->shape().get() && aSelector.restore(aCont->shape()->impl())) + aResult = aSelector.name(this); if (aCenterType != NOT_CENTER) { aResult += centersMap()[aCenterType]; } @@ -964,13 +858,13 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa } // returns the center type and modifies the shape name if this name is center-name -static ModelAPI_AttributeSelection::CenterType centerTypeByName(std::string& theShapeName) +static ModelAPI_AttributeSelection::CenterType centerTypeByName(std::wstring& theShapeName) { - std::map::iterator aPrefixIter = + std::map::iterator aPrefixIter = centersMap().begin(); for(; aPrefixIter != centersMap().end(); aPrefixIter++) { std::size_t aFound = theShapeName.find(aPrefixIter->second); - if (aFound != std::string::npos && + if (aFound != std::wstring::npos && aFound == theShapeName.size() - aPrefixIter->second.size()) { theShapeName = theShapeName.substr(0, aFound); return aPrefixIter->first; @@ -981,180 +875,145 @@ static ModelAPI_AttributeSelection::CenterType centerTypeByName(std::string& the // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT void Model_AttributeSelection::selectSubShape( - const std::string& theType, const std::string& theSubShapeName) + const std::string& theType, const std::wstring& theSubShapeName) { if(theSubShapeName.empty() || theType.empty()) return; - std::string aSubShapeName = theSubShapeName; + std::wstring aSubShapeName = theSubShapeName; CenterType aCenterType = theType[0] == 'v' || theType[0] == 'V' ? // only for vertex-type centerTypeByName(aSubShapeName) : NOT_CENTER; std::string aType = aCenterType == NOT_CENTER ? theType : "EDGE"; // search for edge now + static const GeomShapePtr anEmptyShape; // first iteration is selection by name without center prefix, second - in case of problem, // try with initial name - for(int aUseCenter = 1; aUseCenter >= 0; aUseCenter--) { + for(int aUseCenter = 1; aUseCenter >= 0; aUseCenter--) { if (aUseCenter == 0 && aCenterType != NOT_CENTER) { aSubShapeName = theSubShapeName; aCenterType = NOT_CENTER; aType = theType; } else if (aUseCenter != 1) continue; + TopAbs_ShapeEnum aShapeType = TopAbs_ShapeEnum(GeomAPI_Shape::shapeTypeByStr(aType)); + std::shared_ptr aDoc = + std::dynamic_pointer_cast(owner()->document()); // check this is Part-name: 2 delimiters in the name - std::size_t aPartEnd = aSubShapeName.find('/'); - if (aPartEnd != std::string::npos && aPartEnd != aSubShapeName.rfind('/')) { - std::string aPartName = aSubShapeName.substr(0, aPartEnd); - ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName); - if (aFound.get()) { // found such part, so asking it for the name - ResultPartPtr aPart = std::dynamic_pointer_cast(aFound); - std::string aNameInPart = aSubShapeName.substr(aPartEnd + 1); - int anIndex; - std::shared_ptr aSelected = aPart->shapeInPart(aNameInPart, aType, anIndex); - if (aSelected.get()) { - if (aCenterType != NOT_CENTER) { - if (!aSelected->isEdge()) - continue; - std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aSelected)); - setValueCenter(aPart, aSelectedEdge, aCenterType); - } else - setValue(aPart, aSelected); - TDataStd_Integer::Set(selectionLabel(), anIndex); - return; + std::size_t aPartEnd = aSubShapeName.find(L'/'); + if (aPartEnd != std::wstring::npos) { + std::wstring aPartName = aSubShapeName.substr(0, aPartEnd); + DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); + if (aPartName == Locale::Convert::toWString(aRootDoc->kind())) { + aDoc = std::dynamic_pointer_cast(aRootDoc); + aSubShapeName = aSubShapeName.substr(aPartEnd + 1); + } + else { + ObjectPtr aFound = + owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName); + if (aFound.get()) { // found such part, so asking it for the name + ResultPartPtr aPart = std::dynamic_pointer_cast(aFound); + std::wstring aNameInPart = aSubShapeName.substr(aPartEnd + 1); + if (aNameInPart.empty()) { // whole part + setValue(aPart, anEmptyShape); + return; + } + int anIndex; + std::shared_ptr aSelected = + aPart->shapeInPart(aNameInPart, aType, anIndex); + if (aSelected.get()) { + if (aCenterType != NOT_CENTER) { + if (!aSelected->isEdge()) + continue; + std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aSelected)); + setValueCenter(aPart, aSelectedEdge, aCenterType); + } + else + setValue(aPart, aSelected); + TDataStd_Integer::Set(selectionLabel(), anIndex); + return; + } + } else { // for the ImportResult feature Objects widget this may be a result in other part + // result may be hidden (like, tranlsatiomn of part) in PartSet, so iterate Part-features + int aNum = aRootDoc->size(ModelAPI_Feature::group()); + for (int a = 0; a < aNum; a++) { + FeaturePtr aFeat = std::dynamic_pointer_cast( + aRootDoc->object(ModelAPI_Feature::group(), a)); + if (aFeat.get() && aFeat->data() && aFeat->data()->isValid() && + aFeat->getKind() == "Part" && aFeat->results().size()) { + ResultPartPtr aPart = + std::dynamic_pointer_cast(aFeat->firstResult()); + if (aPart.get() && aPart->partDoc().get() && aPart->data()->name() == aPartName) { + aDoc = std::dynamic_pointer_cast(aPart->partDoc()); + aSubShapeName = aSubShapeName.substr(aPartEnd + 1); + } + } + } } } } - std::shared_ptr aDoc = - std::dynamic_pointer_cast(owner()->document()); // check this is a whole feature context if (aSubShapeName.size() > kWHOLE_FEATURE.size() && aSubShapeName.substr(0, kWHOLE_FEATURE.size()) == kWHOLE_FEATURE) { - std::string aFeatureName = aSubShapeName.substr(kWHOLE_FEATURE.size()); + std::wstring aFeatureName = aSubShapeName.substr(kWHOLE_FEATURE.size()); ObjectPtr anObj = aDoc->objectByName(ModelAPI_Feature::group(), aFeatureName); if (anObj.get()) { - static const GeomShapePtr anEmptyShape; setValue(anObj, anEmptyShape); return; } } - Model_SelectionNaming aSelNaming(selectionLabel()); - std::shared_ptr aShapeToBeSelected; - ResultPtr aCont; - if (aSelNaming.selectSubShape(aType, aSubShapeName, aDoc, aShapeToBeSelected, aCont)) { - // try to find the last context to find the up to date shape - if (aCont->shape().get() && !aCont->shape()->isNull() && - aCont->groupName() == ModelAPI_ResultBody::group() && aDoc == owner()->document()) { - const TopoDS_Shape aConShape = aCont->shape()->impl(); - if (!aConShape.IsNull()) { - Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aConShape, selectionLabel()); - if (!aNS.IsNull()) { - aNS = TNaming_Tool::CurrentNamedShape(aNS); - if (!aNS.IsNull() && scope().Contains(aNS->Label())) { // scope check is for 2228 - TDF_Label aLab = aNS->Label(); - 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(anObj); - if (aRes) - aCont = aRes; - } - } - } - } + // the whole result selection check + if (aSubShapeName.find(L'/') == std::wstring::npos) { + ObjectPtr aRes = aDoc->objectByName(ModelAPI_ResultConstruction::group(), aSubShapeName); + if (!aRes.get()) { + aRes = aDoc->objectByName(ModelAPI_ResultBody::group(), aSubShapeName); + if (!aRes.get()) + aRes = aDoc->objectByName(ModelAPI_ResultGroup::group(), aSubShapeName); } - // if compsolid is context, try to take sub-solid as context: like in GUI and scripts - if (aCont.get() && aShapeToBeSelected.get()) { - ResultBodyPtr aComp = std::dynamic_pointer_cast(aCont); - if (aComp && aComp->numberOfSubs()) { - std::list allSubs; - ModelAPI_Tools::allSubs(aComp, allSubs); - std::list::iterator aS = allSubs.begin(); - for(; aS != allSubs.end(); aS++) { - ResultBodyPtr aSub = std::dynamic_pointer_cast(*aS); - if (aSub && aSub->numberOfSubs() == 0 && aSub->shape().get() && - aSub->shape()->isSubShape(aShapeToBeSelected)) { - aCont = aSub; - break; - } - } - } + if (aRes.get()) { + setValue(aRes, anEmptyShape); + return; } - // try to find the latest active result that must be used instead of the selected - // to set the active context (like in GUI selection), not concealed one - bool aFindNewContext = true; - while(aFindNewContext && aCont.get()) { - aFindNewContext = false; - // take references to all results: root one, any sub - ResultBodyPtr aCompContext = ModelAPI_Tools::bodyOwner(aCont, true); - std::list allRes; - if (aCompContext.get()) { - ModelAPI_Tools::allSubs(aCompContext, allRes); - allRes.push_back(aCompContext); - } else { - allRes.push_back(aCont); - } - for(std::list::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) { - ResultPtr aResCont = *aSub; - ResultBodyPtr aResBody = std::dynamic_pointer_cast(aResCont); - // only lower and higher level subs are counted - if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext) - continue; - const std::set& aRefs = aResCont->data()->refsToMe(); - std::set::const_iterator aRef = aRefs.begin(); - for(; !aFindNewContext && aRef != aRefs.end(); aRef++) { - if (!aRef->get() || !(*aRef)->owner().get()) - continue; - // concealed attribute only - FeaturePtr aRefFeat = std::dynamic_pointer_cast((*aRef)->owner()); - if (!ModelAPI_Session::get()->validators()->isConcealed( - aRefFeat->getKind(), (*aRef)->id())) + } + + Selector_Selector aSelector(selectionLabel(), baseDocumentLab()); + myRestoreDocument = aDoc; + TDF_Label aContextLabel = aSelector.restoreByName( + aSubShapeName, aShapeType, this, myIsGeometricalSelection); + myRestoreDocument.reset(); + if (!aContextLabel.IsNull()) { + ResultPtr aContext = aDoc->resultByLab(aContextLabel); // any label for document access + if (aContext.get() && aContext->shape().get()) { + TopoDS_Shape aContextShape = aContext->shape()->impl(); + if (aSelector.solve(aContextShape)) { + TopoDS_Shape aSelectorShape = aSelector.value(); + GeomShapePtr aShapeToBeSelected(new GeomAPI_Shape); + aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelectorShape)); + // make the context result the latest existing + aContext = newestContext(aContext, aShapeToBeSelected); + if (myIsGeometricalSelection || aCenterType == NOT_CENTER) { + // store the currently generated name + selectionLabel().ForgetAllAttributes(true); + bool aToUnblock = false; + aToUnblock = !owner()->data()->blockSendAttributeUpdated(true); + myRef.setValue(aContext); + aSelector.store(aContextShape); + owner()->data()->sendAttributeUpdated(this); + if (aToUnblock) + owner()->data()->blockSendAttributeUpdated(false); + return; + } else { // re-select center of circle/arc by context and value + if (!aShapeToBeSelected->isEdge()) continue; - // search the feature result that contains sub-shape selected - std::list > aResults; - - // take all sub-results or one result - std::list aRefFeatResults; - ModelAPI_Tools::allResults(aRefFeat, aRefFeatResults); - std::list::iterator aRefResIter = aRefFeatResults.begin(); - for(; aRefResIter != aRefFeatResults.end(); aRefResIter++) { - ResultBodyPtr aBody = std::dynamic_pointer_cast(*aRefResIter); - if (aBody.get() && aBody->numberOfSubs() == 0) // add only lower level subs - aResults.push_back(aBody); - } - std::list >::iterator aResIter = aResults.begin(); - for(; aResIter != aResults.end(); aResIter++) { - if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) - continue; - GeomShapePtr aShape = (*aResIter)->shape(); - GeomShapePtr aSelectedShape = - aShapeToBeSelected.get() ? aShapeToBeSelected : aCont->shape(); - if (aShape.get() && aShape->isSubShape(aSelectedShape, false)) { - aCont = *aResIter; // found new context (produced from this) with same subshape - aFindNewContext = true; // continue searching futher - break; - } - } + std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected)); + setValueCenter(aContext, aSelectedEdge, aCenterType); } + return; } } - - if (aCenterType != NOT_CENTER) { - if (!aShapeToBeSelected->isEdge()) - continue; - std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected)); - setValueCenter(aCont, aSelectedEdge, aCenterType); - } else - setValue(aCont, aShapeToBeSelected); - return; } } - + // invalid TDF_Label aSelLab = selectionLabel(); setInvalidIfFalse(aSelLab, false); reset(); @@ -1198,7 +1057,22 @@ void Model_AttributeSelection::selectSubShape(const std::string& theType, // collect features from PartSet and the current part SessionPtr aSession = ModelAPI_Session::get(); std::list aFeatures = aSession->moduleDocument()->allFeatures(); - if (aSession->moduleDocument() != owner()->document()) { + if (anOwner->getKind() == "ImportResult") { + // special case: feature "ImportResult" refers to the results from another parts, + // thus, it is necessary to go through the features of these parts too. + std::list aPartSetFeatures = aFeatures; + aFeatures.clear(); + for (std::list::iterator it = aPartSetFeatures.begin(); + it != aPartSetFeatures.end(); ++it) { + aFeatures.push_back(*it); + if ((*it)->firstResult()->groupName() == ModelAPI_ResultPart::group()) { + ResultPartPtr aPart = std::dynamic_pointer_cast((*it)->firstResult()); + std::list aPartFeatures = aPart->partDoc()->allFeatures(); + aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end()); + } + } + } + else if (aSession->moduleDocument() != owner()->document()) { std::list aPartFeatures = owner()->document()->allFeatures(); aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end()); } @@ -1246,62 +1120,20 @@ void Model_AttributeSelection::selectSubShape(const std::string& theType, } void Model_AttributeSelection::selectSubShape(const std::string& theType, - const std::string& theContextName, const int theIndex) + const std::wstring& theContextName, const int theIndex) { // selection of context by name - //std::string aNamingContextName = theContextName + "/"; - //selectSubShape(theType, aNamingContextName); - std::shared_ptr aDoc = - std::dynamic_pointer_cast(owner()->document()); - if (aDoc.get()) { - bool aUnique = true; - std::string aContextName = theContextName; - std::string anEmptySub = ""; - ResultPtr aContext = aDoc->findByName(aContextName, anEmptySub, aUnique); - //ResultPtr aContext = context(); - if (aContext.get()) { - GeomShapePtr aContShape = aContext->shape(); - if (aContShape.get()) { - GeomAlgoAPI_NExplode aNExp(aContShape, GeomAPI_Shape::shapeTypeByStr(theType)); - GeomShapePtr aValue = aNExp.shape(theIndex); - if (aValue.get()) - setValue(aContext, aValue); - } - } - } -} - -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); - } + selectSubShape(theType, theContextName); + ResultPtr aContext = context(); + if (aContext.get()) { + GeomShapePtr aContShape = aContext->shape(); + if (aContShape.get()) { + GeomAlgoAPI_NExplode aNExp(aContShape, GeomAPI_Shape::shapeTypeByStr(theType)); + GeomShapePtr aValue = aNExp.shape(theIndex); + if (aValue.get()) + setValue(aContext, aValue); } - - TopTools_IndexedMapOfShape aSubShapesMap; - TopExp::MapShapes(aMainShape, aSubShapesMap); - anID = aSubShapesMap.FindIndex(aSubShape); } - return anID; } void Model_AttributeSelection::setId(int theID) @@ -1341,17 +1173,17 @@ void Model_AttributeSelection::setId(int theID) setValue(aContextRes, aSelection); } -std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const +std::wstring Model_AttributeSelection::contextName(const ResultPtr& theContext) const { - std::string aResult; + std::wstring aResult; if (owner()->document() != theContext->document()) { if (theContext->document() == ModelAPI_Session::get()->moduleDocument()) { - aResult = theContext->document()->kind() + "/"; + aResult = Locale::Convert::toWString(theContext->document()->kind()) + L"/"; } else { ResultPtr aDocRes = ModelAPI_Tools::findPartResult( ModelAPI_Session::get()->moduleDocument(), theContext->document()); if (aDocRes.get()) { - aResult = aDocRes->data()->name() + "/"; + aResult = aDocRes->data()->name() + L"/"; } } } @@ -1365,18 +1197,12 @@ void Model_AttributeSelection::computeValues( { bool aWasWholeContext = theValShape.IsNull(); if (aWasWholeContext) { - //theShapes.Append(theValShape); - //return; theValShape = theOldContext->shape()->impl(); } - //TopoDS_Shape anOldContShape = theOldContext->shape()->impl(); + TopAbs_ShapeEnum aValType = theValShape.ShapeType(); TopoDS_Shape aNewContShape = theNewContext->shape()->impl(); - //if (anOldContShape.IsSame(theValShape)) { // full context shape substituted by new full context - //theShapes.Append(aNewContShape); - //return; - //} // 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); @@ -1408,9 +1234,9 @@ void Model_AttributeSelection::computeValues( for(; aNewContIter != aNewToIterate.end(); aNewContIter++) { std::shared_ptr aNewData = std::dynamic_pointer_cast((*aNewContIter)->data()); - TDF_Label aNewLab = aNewData->label(); + TDF_Label aNewLab = aNewData->shapeLab(); // searching for produced sub-shape fully on some label - TDF_ChildIDIterator aNSIter(aNewLab, TNaming_NamedShape::GetID(), Standard_True); + TDF_ChildIDIterator aNSIter(aNewLab, TNaming_NamedShape::GetID()); for(; aNSIter.More(); aNSIter.Next()) { Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); for(TNaming_Iterator aPairIter(aNS); aPairIter.More(); aPairIter.Next()) { @@ -1420,16 +1246,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; @@ -1441,12 +1267,37 @@ void Model_AttributeSelection::computeValues( } } if (aToFindPart == 2 && !aNewToOld.IsEmpty()) { - // map of sub-shapes -> number of occurences of these shapes in containers + // 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()); - for(; aSubExp.More(); aSubExp.Next()) { + for(aSubExp.Init(aContIter.Key(), aValType); aSubExp.More(); aSubExp.Next()) { if (!aSubs.IsBound(aSubExp.Current())) { aSubs.Bind(aSubExp.Current(), TopTools_MapOfShape()); } @@ -1460,12 +1311,118 @@ 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, + const bool theCheckWholeFeature) +{ + 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)->data()); + ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true); + if (!aRootBody.get()) + aRootBody = std::dynamic_pointer_cast(*aRootIter); + if (aRootBody.get()) { + std::list allSub; + ModelAPI_Tools::allSubs(aRootBody, allSub); + for(std::list::iterator anIt = allSub.begin(); anIt != allSub.end(); anIt++) + allRes.push_back((*anIt)->data()); + } + if (theCheckWholeFeature) + allRes.push_back(theFeature->data()); + for(std::list::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) { + const std::set& aRefs = (*aRIter)->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); + } + } + } + } } } @@ -1474,8 +1431,8 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr TDF_Label theAccessLabel, std::list& theResults, TopTools_ListOfShape& theValShapes) { - std::set aResults; // to avoid duplicates, new context, null if deleted - TopTools_ListOfShape aResContShapes; + std::list aResults; // keep order, new context, null if deleted + std::set aResultsSet; // to avoid duplicates // iterate context and shape, but also if it is sub-shape of main shape, check also it TopTools_ListOfShape aContextList; aContextList.Append(theContShape); @@ -1502,48 +1459,154 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr if (!aModifierFeat.get()) continue; FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); - if (aModifierFeat == aThisFeature || theDoc->objects()->isLater(aModifierFeat, aThisFeature)) + if (aModifierFeat == aThisFeature || !theDoc->isLaterByDep(aThisFeature, aModifierFeat)) continue; // the modifier feature is later than this, so, should not be used FeaturePtr aCurrentModifierFeat = theDoc->feature(theContext); if (aCurrentModifierFeat == aModifierFeat || - theDoc->objects()->isLater(aCurrentModifierFeat, aModifierFeat)) + !theDoc->isLaterByDep(aModifierFeat, aCurrentModifierFeat)) continue; // the current modifier is later than the found, so, useless Handle(TNaming_NamedShape) aNewNS; aModifIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNewNS); if (aNewNS->Evolution() == TNaming_MODIFY || aNewNS->Evolution() == TNaming_GENERATED) { - aResults.insert(aModifierObj); - //TNaming_Iterator aPairIter(aNewNS); - //aResContShapes.Append(aPairIter.NewShape()); - aResContShapes.Append(aModifierObj->shape()->impl()); + if (aResultsSet.find(aModifierObj) == aResultsSet.end()) { + aResultsSet.insert(aModifierObj); + aResults.push_back(aModifierObj); + } } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is empty - aResults.insert(ResultPtr()); - } else { // not-precessed modification => don't support it + aResults.push_back(ResultPtr()); + } else { // not-processed modification => don't support it continue; } } } - if (aResults.empty()) - return false; // no modifications found, must stay the same - // iterate all results to find futher modifications - std::set::iterator aResIter = aResults.begin(); - for(; aResIter != aResults.end(); aResIter++) { + // if there exist context composite and sub-result(s), leave only sub(s) + for(std::list::iterator aResIter = aResults.begin(); aResIter != aResults.end();) { + ResultPtr aParent = ModelAPI_Tools::bodyOwner(*aResIter); + for(; aParent.get(); aParent = ModelAPI_Tools::bodyOwner(aParent)) + if (aResultsSet.count(aParent)) + break; + if (aParent.get()) { + aResultsSet.erase(aParent); + for(std::list::iterator anIt = aResults.begin(); anIt != aResults.end(); anIt++) { + if (*anIt == aParent) { + aResults.erase(anIt); + aResIter = aResults.begin(); // erase from set, so, restart iteration + break; + } + } + } 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.push_back(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::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::list::iterator aResIter = aResults.begin(); + for(aResIter = aResults.begin(); aResIter != aResults.end(); aResIter++) { if (aResIter->get() != NULL) { - // compute new values by two contextes: the old and the new + 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)) { - // appeand new results instead of the current ones + // 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()) { @@ -1551,7 +1614,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); } } @@ -1560,20 +1623,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->label(); // named shape where the selected context is located + 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; @@ -1589,13 +1705,19 @@ void Model_AttributeSelection::updateInHistory() // to avoid detection of part changes by local selection only AttributeSelectionPtr aSel = std::dynamic_pointer_cast(*aRef); - if (aSel.get() && !aSel->value()->isSame(aSel->context()->shape())) + if (aSel.get() && aSel->value().get() && + !aSel->value()->isSame(aSel->context()->shape())) 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->objects()->isLater(aThisFeature, aRefFeat)) { // found better feature + if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature aFoundNewContext = true; aNewContext = aRefFeat->firstResult(); } @@ -1618,7 +1740,6 @@ void Model_AttributeSelection::updateInHistory() if (!aPairIter.More()) return; TopoDS_Shape aNewCShape = aPairIter.NewShape(); - bool anIterate = true; // trying to update also the sub-shape selected GeomShapePtr aSubShape = value(); if (aSubShape.get() && aSubShape->isEqual(aContext->shape())) @@ -1632,63 +1753,468 @@ void Model_AttributeSelection::updateInHistory() TopTools_ListOfShape aValShapes; if (searchNewContext(aDoc, aNewCShape, aContext, aValShape, aContLab, aNewContexts, aValShapes)) { - // update scope to reset to a new one - myScope.Clear(); + std::set allContexts(aNewContexts.begin(), aNewContexts.end()); + std::set aSkippedContext; + + // 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" || 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); - if (aNewCont == aNewContexts.end()) { // all results were deleted - ResultPtr anEmptyContext; - std::shared_ptr anEmptyShape; - setValue(anEmptyContext, anEmptyShape); // nullify the selection - return; + 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()) { + aValueShape = std::make_shared(); + aValueShape->setImpl(new TopoDS_Shape(aNewValues.Value())); + } + // Check that list has the same type of shape selection before adding. + GeomAPI_Shape::ShapeType aShapeShapeType = GeomAPI_Shape::SHAPE; + if (aValueShape.get()) { + aShapeShapeType = aValueShape->shapeType(); + } else { + aShapeShapeType = (*aNewCont)->shape()->shapeType(); + } + if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) { + // 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) { + 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) { + 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 { + static ResultPtr anEmptyContext; + setValue(anEmptyContext, anEmptyShape); // nullify the selection + return; + } + } + } +} - GeomShapePtr aValueShape; - if (!aNewValues.Value().IsNull()) { - aValueShape = std::make_shared(); - aValueShape->setImpl(new TopoDS_Shape(aNewValues.Value())); +void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent) +{ + myParent = theParent; +} + +std::wstring Model_AttributeSelection::contextName(const TDF_Label theSelectionLab) +{ + std::shared_ptr aDoc = myRestoreDocument.get() ? myRestoreDocument : + std::dynamic_pointer_cast(owner()->document()); + FeaturePtr aFeatureOwner = aDoc->featureByLab(theSelectionLab); + bool aBaseDocumnetUsed = false; + if (!aFeatureOwner.get()) { // use module document + aDoc = std::dynamic_pointer_cast(ModelAPI_Session::get()->moduleDocument()); + aFeatureOwner = aDoc->featureByLab(theSelectionLab); + aBaseDocumnetUsed = true; + } + if (aFeatureOwner.get()) { + // if it is sub-element of the sketch, the context name is the name of the sketch + // searching also for result - real context + ResultPtr aResult; + FeaturePtr aComposite = ModelAPI_Tools::compositeOwner(aFeatureOwner); + if (aComposite.get() && aComposite->results().size() == 1 && + aComposite->firstResult()->groupName() == ModelAPI_ResultConstruction::group()) { + aFeatureOwner = aComposite; + aResult = aFeatureOwner->firstResult(); + } else { + aResult = aDoc->resultByLab(theSelectionLab); } - setValue(*aNewCont, aValueShape); - // if there are more than one result, put them by "append" into "parent" list - if (myParent) { - for(aNewCont++, aNewValues.Next(); aNewCont != aNewContexts.end(); - aNewCont++, aNewValues.Next()) { - GeomShapePtr aValueShape; - if (!aNewValues.Value().IsNull()) { - aValueShape = std::make_shared(); - aValueShape->setImpl(new TopoDS_Shape(aNewValues.Value())); + if (aResult.get()) { + // this is to avoid duplicated names of results problem + std::wstring aContextName = aResult->data()->name(); + // myLab corresponds to the current time + TDF_Label aCurrentLab = selectionLabel(); + while(aCurrentLab.Depth() > 3) + aCurrentLab = aCurrentLab.Father(); + + int aNumInHistoryNames = + aDoc->numberOfNameInHistory(aResult, aCurrentLab); + while(aNumInHistoryNames > 1) { // add "_" before name the needed number of times + aContextName = L"_" + aContextName; + aNumInHistoryNames--; + } + if (aBaseDocumnetUsed) + aContextName = Locale::Convert::toWString(aDoc->kind()) + L"/" + aContextName; + return aContextName; + } + } + return L""; // invalid case +} + +/// This method restores by the context and value name the context label and +/// sub-label where the value is. Returns true if it is valid. +bool Model_AttributeSelection::restoreContext(std::wstring theName, + TDF_Label& theContext, TDF_Label& theValue) +{ + static const GeomShapePtr anEmptyShape; // to store context only + std::wstring aName = theName; + std::shared_ptr aDoc = myRestoreDocument.get() ? myRestoreDocument : + std::dynamic_pointer_cast(owner()->document()); + + // remove the sub-value part if exists + std::wstring aSubShapeName = aName; + std::wstring::size_type n = aName.find(L'/'); + if (n != std::wstring::npos) { + aName = aName.substr(0, n); + } + + if (aName.empty()) return false; + bool anUniqueContext = false; + ResultPtr aCont = aDoc->findByName(aName, aSubShapeName, anUniqueContext); + if (!aCont.get() || !aCont->shape().get() || aCont->shape()->isNull()) { + // name in PartSet? + aDoc = std::dynamic_pointer_cast( + ModelAPI_Session::get()->moduleDocument()); + if (theName.find(Locale::Convert::toWString(aDoc->kind())) == 0) { + // remove the document identifier from name if exists + aSubShapeName = theName.substr(aDoc->kind().size() + 1); + aName = aSubShapeName; + n = aName.find(L'/'); + if (n != std::wstring::npos) { + aName = aName.substr(0, n); + } + } + aCont = aDoc->findByName(aName, aSubShapeName, anUniqueContext); + if (!aCont.get() || !aCont->shape().get() || aCont->shape()->isNull()) + return false; + } + + // searching the sub-shape + static const ResultPtr anEmpty; + theValue = aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); + + // sketch sub-component shape and name is located in separated feature label, try the sub-name + if (theValue.IsNull() && aCont->groupName() == ModelAPI_ResultConstruction::group()) { + std::wstring::size_type aSlash = aSubShapeName.rfind(L'/'); + if (aSlash != std::wstring::npos) { + std::wstring aCompName = aSubShapeName.substr(aSlash + 1); + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(aDoc->feature(aCont)); + if (aComposite.get() && aComposite->numberOfSubs()) { + const int aSubNum = aComposite->numberOfSubs(); + for (int a = 0; a < aSubNum && theValue.IsNull(); a++) { + FeaturePtr aSub = aComposite->subFeature(a); + const std::list >& aResults = aSub->results(); + std::list >::const_iterator aRes = aResults.cbegin(); + for (; aRes != aResults.cend() && theValue.IsNull(); aRes++) { + if ((*aRes)->data()->name() == aCompName) { + theValue = std::dynamic_pointer_cast((*aRes)->data())->shapeLab(); + break; + } else { // any sub-label because the sketch line may be renamed, but not sub-vertices + TDF_Label aLab = std::dynamic_pointer_cast((*aRes)->data())->shapeLab(); + TDF_ChildIDIterator aSubNames(aLab, TDataStd_Name::GetID()); + for(; aSubNames.More(); aSubNames.Next()) { + if (Handle(TDataStd_Name)::DownCast(aSubNames.Value())->Get(). + IsEqual(aCompName.c_str())) { + theValue = aSubNames.Value()->Label(); + break; + } + } + } + } } + } + } + } + + if (aCont.get()) { + theContext = std::dynamic_pointer_cast(aCont->data())->label(); + } + return true; +} - // Check that list has the same type of shape selection before adding. - GeomAPI_Shape::ShapeType aListShapeType = GeomAPI_Shape::SHAPE; - 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; - - GeomAPI_Shape::ShapeType aShapeShapeType = GeomAPI_Shape::SHAPE; - if (aValueShape.get()) { - aShapeShapeType = aValueShape->shapeType(); - } else { - (*aNewCont)->shape()->shapeType(); +bool Model_AttributeSelection::isLater( + const TDF_Label theResult1, const TDF_Label theResult2) const +{ + std::shared_ptr aDoc = myRestoreDocument.get() ? myRestoreDocument : + std::dynamic_pointer_cast(owner()->document()); + FeaturePtr aFeat1 = aDoc->featureByLab(theResult1); + if (!aFeat1.get()) + return false; + FeaturePtr aFeat2 = aDoc->featureByLab(theResult2); + if (!aFeat2.get()) + return false; + return aDoc->isLaterByDep(aFeat1, aFeat2); +} + +ResultPtr Model_AttributeSelection::newestContext( + const ResultPtr theCurrent, const GeomShapePtr theValue) +{ + ResultPtr aResult = theCurrent; + GeomShapePtr aSelectedShape = theValue.get() ? theValue : theCurrent->shape(); + std::shared_ptr aDoc = + std::dynamic_pointer_cast(owner()->document()); + bool aFindNewContext = true; + while (aFindNewContext && aResult.get()) { + aFindNewContext = false; + // try to find the last context to find the up to date shape + TopoDS_Shape aConShape = aResult->shape()->impl(); + if (TNaming_Tool::HasLabel(selectionLabel(), aConShape)) { + Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aConShape, selectionLabel()); + if (!aNS.IsNull()) { + aNS = TNaming_Tool::CurrentNamedShape(aNS); + if (!aNS.IsNull() + && isLater(selectionLabel(), aNS->Label()) + && isLater(aNS->Label(), + std::dynamic_pointer_cast(aResult->data())->label())) + { + TDF_Label aLab = aNS->Label(); + ResultPtr aRes = aDoc->resultByLab(aLab); + if (aRes.get()) { + if (aRes->shape()->isSubShape(aSelectedShape)) { + aResult = aRes; + aFindNewContext = true; + continue; + } + } } + } + } - if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) { + // TestFillWireVertex.py - sketch constructions for wire may participate too + //if (aResult->groupName() == ModelAPI_ResultBody::group()) { + // try to search newer context by the concealment references + // take references to all results: root one, any sub + std::list allRes; + ResultPtr aCompContext; + ResultBodyPtr aCompBody = ModelAPI_Tools::bodyOwner(aResult, true); + if (aCompBody.get()) { + std::list allSub; + ModelAPI_Tools::allSubs(aCompBody, allSub); + for(std::list::iterator anIt = allSub.begin(); anIt != allSub.end(); anIt++) + allRes.push_back((*anIt)->data()); + allRes.push_back(aCompBody->data()); + aCompContext = aCompBody; + } + if (allRes.empty()) + allRes.push_back(aResult->data()); + allRes.push_back(aResult->document()->feature(aResult)->data()); + + bool aFoundReferernce = false; + for (std::list::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) { + DataPtr aResCont = *aSub; + ResultBodyPtr aResBody = std::dynamic_pointer_cast(aResCont->owner()); + if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext) + continue; // only lower and higher level subs are counted + const std::set& aRefs = aResCont->refsToMe(); + std::set::const_iterator aRef = aRefs.begin(); + for (; !aFindNewContext && aRef != aRefs.end(); aRef++) { + if (!aRef->get() || !(*aRef)->owner().get()) + continue; + // concealed attribute only + FeaturePtr aRefFeat = std::dynamic_pointer_cast((*aRef)->owner()); + if (!ModelAPI_Session::get()->validators()->isConcealed( + aRefFeat->getKind(), (*aRef)->id())) continue; + // search the feature result that contains sub-shape selected + std::list > aResults; + + // take all sub-results or one result + std::list aRefFeatResults; + ModelAPI_Tools::allResults(aRefFeat, aRefFeatResults); + std::list::iterator aRefResIter = aRefFeatResults.begin(); + for (; aRefResIter != aRefFeatResults.end(); aRefResIter++) { + ResultBodyPtr aBody = std::dynamic_pointer_cast(*aRefResIter); + if (aBody.get() && aBody->numberOfSubs() == 0) // add only lower level subs + aResults.push_back(aBody); + } + std::list >::iterator aResIter = aResults.begin(); + + // searching by sub-shape + for (; aResIter != aResults.end(); aResIter++) { + if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) + continue; + aFoundReferernce = true; + 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; + } } + } + } + if (aFoundReferernce && !aFindNewContext && + aResult->groupName() != ModelAPI_ResultConstruction::group()) { + // #19019 : result is concealed by object that contains no such sub-shape + return theCurrent; + } + } + // if compsolid is context, try to take sub-solid as context: like in GUI and scripts + ResultBodyPtr aComp = std::dynamic_pointer_cast(aResult); + if (aComp && aComp->numberOfSubs()) { + std::list allSubs; + ModelAPI_Tools::allSubs(aComp, allSubs); + std::list::iterator aS = allSubs.begin(); + for (; aS != allSubs.end(); aS++) { + ResultBodyPtr aSub = std::dynamic_pointer_cast(*aS); + if (aSub && aSub->numberOfSubs() == 0 && aSub->shape().get() && + aSub->shape()->isSubShape(aSelectedShape)) { + aResult = aSub; + break; + } + } + } + // in case sketch line was selected for wire, but wire was concealed and there is no such line + // anymore, so, actually, the sketch element was selected (which is never concealed) + if (aResult != theCurrent && theCurrent->groupName() == ModelAPI_ResultConstruction::group()) { + std::list aConcealers; + FeaturePtr aResFeature = aDoc->feature(aResult); + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + concealedFeature(aResFeature, aThisFeature, false, aConcealers, aResult, true); + if (aConcealers.size()) + aResult = theCurrent; + } + return aResult; +} + +void Model_AttributeSelection::combineGeometrical() +{ + if (myTmpContext.get() || myTmpSubShape.get()) + return; + TDF_Label aSelLab = selectionLabel(); + if (aSelLab.IsAttribute(kINVALID_SELECTION) || !myRef.isInitialized()) + return; - myParent->append(*aNewCont, aValueShape); + if (aSelLab.IsAttribute(kCIRCLE_CENTER) || aSelLab.IsAttribute(kELLIPSE_CENTER1) || + aSelLab.IsAttribute(kELLIPSE_CENTER2) || aSelLab.IsAttribute(kSIMPLE_REF_ID)) + return; + + if (aSelLab.IsAttribute(kPART_REF_ID)) { + ResultPartPtr aPart = std::dynamic_pointer_cast(context()); + if (!aPart.get() || !aPart->isActivated()) + return; // postponed naming needed + Handle(TDataStd_Integer) anIndex; + if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) { + if (anIndex->Get()) { // special selection attribute was created, use it + std::wstring aNewName; + aPart->combineGeometrical(anIndex->Get(), aNewName); + TDataStd_Name::Set(aSelLab, aNewName.c_str()); } } + return; + } + + std::shared_ptr aConstr = + std::dynamic_pointer_cast(context()); + if (aConstr.get()) + return; + FeaturePtr aFeature = contextFeature(); + if (aFeature.get()) + return; + + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + TopoDS_Shape aContextShape = context()->shape()->impl(); + if (aSelector.restore(aContextShape)) { + aSelector.combineGeometrical(aContextShape); } } -void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent) +TDF_Label Model_AttributeSelection::baseDocumentLab() { - myParent = theParent; + if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) + return std::dynamic_pointer_cast + (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel(); + static TDF_Label anEmpty; + return anEmpty; } -bool Model_AttributeSelection::isWeakNaming() +void Model_AttributeSelection::reset() { - return selectionLabel().IsAttribute(kWEAK_NAMING); + ModelAPI_AttributeSelection::reset(); + myRef.reset(); }