X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=432c6f1c2e7740d37293b040c46aafd89823e727;hb=e8fce5fe73fee1a8ea2929934a7e6f71bd1e3eb5;hp=eb527e6962807d28fd529d9f07d045ee26051024;hpb=3a8eaafe73b1aba7bdbfcbade4c92a11741f0567;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index eb527e696..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" @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -39,15 +39,20 @@ #include #include #include +#include #include +#include #include #include #include +#include + #include #include #include #include +#include #include #include #include @@ -66,6 +71,7 @@ #include #include #include +#include #include //#define DEB_NAMING 1 @@ -88,15 +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"); -// reference to the external sketch face -Standard_GUID kEXT_SKETCH_FACE("ba32aa31-bde7-422f-80b4-79c757c77b49"); // 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 @@ -107,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; @@ -133,16 +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); - aSelLab.ForgetAttribute(kEXT_SKETCH_FACE); bool isDegeneratedEdge = false; // do not use the degenerated edge as a shape, a null context and shape is used in the case @@ -152,8 +148,6 @@ 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) @@ -184,20 +178,18 @@ bool Model_AttributeSelection::setValue(const ObjectPtr& theContext, std::shared_ptr aSubShape; 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(aConstruction->shape()->impl()); - } } 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) @@ -240,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); @@ -269,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) { @@ -282,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, @@ -307,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); @@ -326,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(); @@ -359,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); } } } @@ -377,11 +382,6 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp if (aConstr) { if (aConstr->isInfinite()) return aResult; // empty result - // external sketch face - Handle(TDataStd_Integer) aFaceIndex; - if (aSelLab.FindAttribute(kEXT_SKETCH_FACE, aFaceIndex)) { - return aConstr->face(aFaceIndex->Get()); - } } if (!aConstr.get()) { // for construction context, return empty result as usual even // the whole feature is selected @@ -399,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; @@ -444,35 +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()) { - 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; @@ -482,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()); @@ -503,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; } @@ -520,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()); } @@ -569,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); } @@ -602,29 +592,6 @@ 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 topological selection mechanism bool aResult = false; TopoDS_Shape anOldShape; @@ -632,25 +599,61 @@ bool Model_AttributeSelection::update() if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) anOldShape = aNS->Get(); - Selector_Selector aSelector(aSelLab); - if (aSelector.restore()) { // it is stored in old OCCT format, use TNaming_Selector - TopoDS_Shape aContextShape = aContext->shape()->impl(); - aResult = aSelector.solve(aContextShape); - } - aResult = setInvalidIfFalse(aSelLab, aResult); + 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 (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) aNewShape = aNS->Get(); - if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape)) { - // shape type shoud not not changed: if shape becomes compound of such shapes, then split + // 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(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; @@ -661,19 +664,11 @@ bool Model_AttributeSelection::update() std::shared_ptr aConstructionContext = std::dynamic_pointer_cast(aContext); if (!aConstructionContext->isInfinite()) { - // external sketch face - Handle(TDataStd_Integer) anIndex; - if (aSelLab.FindAttribute(kEXT_SKETCH_FACE, anIndex)) { - return setInvalidIfFalse(aSelLab, anIndex->Get() < aConstructionContext->facesNum()); - } - Selector_Selector aSelector(aSelLab); - aResult = aSelector.restore(); + TopoDS_Shape aContextShape = aContext->shape()->impl(); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); TopoDS_Shape anOldShape = aSelector.value(); - if (aResult) { - TopoDS_Shape aContextShape = aContext->shape()->impl(); - aResult = aSelector.solve(aContextShape); - } - aResult = setInvalidIfFalse(aSelLab, aResult); + aResult = aSelector.restore(aContextShape); + setInvalidIfFalse(aSelLab, aResult); if (aResult && !anOldShape.IsEqual(aSelector.value())) owner()->data()->sendAttributeUpdated(this); // send updated if shape is changed } else { @@ -690,7 +685,7 @@ void Model_AttributeSelection::selectBody( // perform the selection TopoDS_Shape aContext; - ResultPtr aBody = std::dynamic_pointer_cast(theContext);//myRef.value() + ResultPtr aBody = std::dynamic_pointer_cast(theContext); if (aBody) { aContext = aBody->shape()->impl(); } else { @@ -707,55 +702,22 @@ void Model_AttributeSelection::selectBody( if (!aContext.IsNull()) { TDF_Label aSelLab = selectionLabel(); TopoDS_Shape aNewSub = theSubShape->impl(); - FeaturePtr aFeatureOwner = std::dynamic_pointer_cast(owner()); - if (aFeatureOwner->document() != theContext->document()) { // reference to the sketch face - ResultConstructionPtr aConstr = - std::dynamic_pointer_cast(theContext); - int aFaceIndex = -1, aFacesNum = aConstr->facesNum(); - for(int a = 0; a < aFacesNum; a++) { - if (aConstr->face(a)->isEqual(theSubShape)) { - aFaceIndex = a; - break; - } - } - if (aFaceIndex >= 0) { - TDataStd_Integer::Set(aSelLab, kEXT_SKETCH_FACE, aFaceIndex); // store index of the face - return; - } - } + bool aSelectorOk = true; - Selector_Selector aSel(aSelLab); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); try { - aSelectorOk = aSel.select(aContext, aNewSub); + aSelectorOk = aSelector.select(aContext, aNewSub, myIsGeometricalSelection); if (aSelectorOk) { - aSel.store(); - aSelectorOk = aSel.solve(aContext); + aSelectorOk = aSelector.store(aContext); } } catch(...) { aSelectorOk = false; } - // check that selection is correct, otherwise use weak naming solution - 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(aContext)); - 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 (aSelectorOk) { + TopoDS_Shape aShape = aSelector.value(); + aSelectorOk = !aShape.IsNull() && aShape.ShapeType() == aNewSub.ShapeType(); } + setInvalidIfFalse(aSelLab, aSelectorOk); } } @@ -781,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()); @@ -803,50 +765,78 @@ 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(); if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value return contextName(aCont); } - Handle(TDataStd_Integer) aWeakId; - if (aSelLab.FindAttribute(kWEAK_NAMING, aWeakId)) { // a weak naming is used - std::ostringstream aNameStream; - aNameStream<Get(); - return aNameStream.str(); + // 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 @@ -854,33 +844,13 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa ResultConstructionPtr aConstr = std::dynamic_pointer_cast(aCont); if (aConstr->isInfinite()) { return contextName(aCont); - } else { - // external sketch face - Handle(TDataStd_Integer) aFaceIndex; - if (aSelLab.FindAttribute(kEXT_SKETCH_FACE, aFaceIndex)) { - std::shared_ptr anExtDoc = - std::dynamic_pointer_cast(aCont->document()); - Selector_Selector aSelector(anExtDoc->extConstructionsLabel()); - TopoDS_Shape aContShape = aConstr->shape()->impl(); - TopoDS_Shape aValShape = value()->impl(); - aSelector.select(aContShape, aValShape); - myRestoreDocument = anExtDoc; - std::string aName = anExtDoc->kind() + "/" + aSelector.name(this); - myRestoreDocument.reset(); - return aName; - } } } - Selector_Selector aSelector(aSelLab); - std::string aResult; - if (aSelector.restore()) + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + std::wstring aResult; + if (aCont->shape().get() && aSelector.restore(aCont->shape()->impl())) aResult = aSelector.name(this); - /* - Model_SelectionNaming aSelNaming(aSelLab); - std::string aResult = aSelNaming.namingName( - aCont, aSubSh, theDefaultName, owner()->document() != aCont->document()); - */ if (aCenterType != NOT_CENTER) { aResult += centersMap()[aCenterType]; } @@ -888,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; @@ -905,42 +875,78 @@ 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 - TopAbs_ShapeEnum aShapeType = TopAbs_ShapeEnum(GeomAPI_Shape::shapeTypeByStr(theType)); 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--) { - std::string aSubShapeName = theSubShapeName; 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) { - std::string aPartName = aSubShapeName.substr(0, aPartEnd); + 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 == aRootDoc->kind()) { + 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); + } + 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); - aDoc = std::dynamic_pointer_cast(aPart->partDoc()); - aSubShapeName = aSubShapeName.substr(aPartEnd +1); + 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); + } + } + } } } } @@ -948,7 +954,7 @@ void Model_AttributeSelection::selectSubShape( // 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()) { setValue(anObj, anEmptyShape); @@ -957,40 +963,55 @@ void Model_AttributeSelection::selectSubShape( } // the whole result selection check - if (aSubShapeName.find('/') == std::string::npos) { + if (aSubShapeName.find(L'/') == std::wstring::npos) { ObjectPtr aRes = aDoc->objectByName(ModelAPI_ResultConstruction::group(), aSubShapeName); - if (!aRes.get()) + if (!aRes.get()) { aRes = aDoc->objectByName(ModelAPI_ResultBody::group(), aSubShapeName); + if (!aRes.get()) + aRes = aDoc->objectByName(ModelAPI_ResultGroup::group(), aSubShapeName); + } if (aRes.get()) { setValue(aRes, anEmptyShape); return; } } - Selector_Selector aSelector(aDoc->generalLabel()); + Selector_Selector aSelector(selectionLabel(), baseDocumentLab()); myRestoreDocument = aDoc; - TDF_Label aContextLabel = aSelector.restoreByName(aSubShapeName, aShapeType, this); + 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(aSelector.value())); - if (aCenterType != NOT_CENTER) { + 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; std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected)); setValueCenter(aContext, aSelectedEdge, aCenterType); } - else - setValue(aContext, aShapeToBeSelected); return; } } } - aSubShapeName = theSubShapeName; } // invalid TDF_Label aSelLab = selectionLabel(); @@ -1036,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()); } @@ -1084,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) @@ -1179,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"/"; } } } @@ -1203,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); @@ -1248,7 +1236,7 @@ void Model_AttributeSelection::computeValues( std::dynamic_pointer_cast((*aNewContIter)->data()); 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()) { @@ -1258,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; @@ -1279,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()); } @@ -1298,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); + } + } + } + } } } @@ -1312,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); @@ -1349,39 +1468,145 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr 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()); + 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()) { @@ -1389,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); } } @@ -1398,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->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; @@ -1427,11 +1705,17 @@ 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->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature aFoundNewContext = true; @@ -1456,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())) @@ -1470,49 +1753,133 @@ void Model_AttributeSelection::updateInHistory() TopTools_ListOfShape aValShapes; if (searchNewContext(aDoc, aNewCShape, aContext, aValShape, aContLab, aNewContexts, aValShapes)) { - 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; + 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); } - GeomShapePtr aValueShape; - if (!aNewValues.Value().IsNull()) { - aValueShape = std::make_shared(); - aValueShape->setImpl(new TopoDS_Shape(aNewValues.Value())); - } - setValue(*aNewCont, aValueShape); - // if there are more than one result, put them by "append" into "parent" list + GeomAPI_Shape::ShapeType aListShapeType = GeomAPI_Shape::SHAPE; 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 (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; + } - // 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(); + // issue #3031: skip topology if there is more convenient shape type presents in the + // same context as a result of this + bool isWholeResult = myParent && myParent->isWholeResultAllowed() && !aSubShape.get(); + GeomAPI_Shape::ShapeType allowedType = GeomAPI_Shape::SHAPE; + if (isWholeResult) { + std::list::iterator aNewCont = aNewContexts.begin(); + TopTools_ListIteratorOfListOfShape aNewValues(aValShapes); + for(; aNewCont != aNewContexts.end(); aNewCont++, aNewValues.Next()) { + if (aNewValues.Value().IsNull()) { // only for the whole context + GeomAPI_Shape::ShapeType aShapeType = (*aNewCont)->shape()->shapeType(); + if (allowedType == GeomAPI_Shape::SHAPE) { // just set this one + allowedType = aShapeType; + } else { + GeomAPI_Shape::ShapeType anAllowed = allowedType; + if (anAllowed != aShapeType) { // select the best, nearest to the origin + GeomAPI_Shape::ShapeType anOldShapeType = aContext->shape()->shapeType(); + GeomAPI_Shape::ShapeType aDeltaAllowed = + (GeomAPI_Shape::ShapeType)(anOldShapeType - anAllowed); + if (aDeltaAllowed < 0) + aDeltaAllowed = (GeomAPI_Shape::ShapeType)(-aDeltaAllowed); + GeomAPI_Shape::ShapeType aDeltaThis = + (GeomAPI_Shape::ShapeType)(anOldShapeType - aShapeType); + if (aDeltaThis < 0) + aDeltaThis = (GeomAPI_Shape::ShapeType)(-aDeltaThis); + if (aDeltaThis == aDeltaAllowed) { // equal distance to context, select complicated + if (anOldShapeType < anAllowed) + allowedType = aShapeType; + } else if (aDeltaAllowed > aDeltaThis) { // this wins + allowedType = aShapeType; + } + } + } } + } + } + + std::list::iterator aNewCont = aNewContexts.begin(); + TopTools_ListIteratorOfListOfShape aNewValues(aValShapes); + bool aFirst = true; // first is set to this, next are appended to parent + for(; aNewCont != aNewContexts.end(); aNewCont++, aNewValues.Next()) { + if (aSkippedContext.count(*aNewCont)) + continue; - if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) { + 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; } + } - myParent->append(*aNewCont, aValueShape); + 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; } } } @@ -1523,16 +1890,17 @@ void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent myParent = theParent; } -bool Model_AttributeSelection::isWeakNaming() -{ - return selectionLabel().IsAttribute(kWEAK_NAMING); -} - -std::string Model_AttributeSelection::contextName(const TDF_Label theSelectionLab) +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 @@ -1547,7 +1915,7 @@ std::string Model_AttributeSelection::contextName(const TDF_Label theSelectionLa } if (aResult.get()) { // this is to avoid duplicated names of results problem - std::string aContextName = aResult->data()->name(); + std::wstring aContextName = aResult->data()->name(); // myLab corresponds to the current time TDF_Label aCurrentLab = selectionLabel(); while(aCurrentLab.Depth() > 3) @@ -1556,37 +1924,54 @@ std::string Model_AttributeSelection::contextName(const TDF_Label theSelectionLa int aNumInHistoryNames = aDoc->numberOfNameInHistory(aResult, aCurrentLab); while(aNumInHistoryNames > 1) { // add "_" before name the needed number of times - aContextName = "_" + aContextName; + aContextName = L"_" + aContextName; aNumInHistoryNames--; } + if (aBaseDocumnetUsed) + aContextName = Locale::Convert::toWString(aDoc->kind()) + L"/" + aContextName; return aContextName; } } - return ""; // invalid case + 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::string theName, +bool Model_AttributeSelection::restoreContext(std::wstring theName, TDF_Label& theContext, TDF_Label& theValue) { static const GeomShapePtr anEmptyShape; // to store context only - std::string aName = theName; + 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::string aSubShapeName = aName; - std::string::size_type n = aName.find('/'); - if (n != std::string::npos) { + 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()) - return false; + 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; @@ -1594,20 +1979,31 @@ bool Model_AttributeSelection::restoreContext(std::string theName, // 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::string::size_type aSlash = aSubShapeName.rfind('/'); - if (aSlash != std::string::npos) { - std::string aCompName = aSubShapeName.substr(aSlash + 1); + 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; a++) { + 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(); aRes++) { + 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; + } + } } } } @@ -1615,95 +2011,131 @@ bool Model_AttributeSelection::restoreContext(std::string theName, } } - /* to find the latest lower result that keeps given shape + if (aCont.get()) { + theContext = std::dynamic_pointer_cast(aCont->data())->label(); + } + return true; +} + +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 && aCont.get()) { + while (aFindNewContext && aResult.get()) { aFindNewContext = false; // try to find the last context to find the up to date shape - TopoDS_Shape aConShape = aCont->shape()->impl(); - Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aConShape, selectionLabel()); - if (!aNS.IsNull()) { - aNS = TNaming_Tool::CurrentNamedShape(aNS); - if (!aNS.IsNull() && isOlderThanMe(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; - aFindNewContext = true; + 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; + } } } } - } else if (aCont->groupName() == ModelAPI_ResultBody::group()) { + } + + // 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; - if (aCont->groupName() == ModelAPI_ResultBody::group()) { - ResultBodyPtr aCompBody = ModelAPI_Tools::bodyOwner(aCont, true); - if (aCompBody.get()) { - ModelAPI_Tools::allSubs(aCompBody, allRes); - allRes.push_back(aCompBody); - aCompContext = aCompBody; + 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); } - } - if (allRes.empty()) - 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); - if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext) - continue; // only lower and higher level subs are counted - 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())) + std::list >::iterator aResIter = aResults.begin(); + + // searching by sub-shape + for (; aResIter != aResults.end(); aResIter++) { + if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) 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; - } + 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(aCont); + ResultBodyPtr aComp = std::dynamic_pointer_cast(aResult); if (aComp && aComp->numberOfSubs()) { std::list allSubs; ModelAPI_Tools::allSubs(aComp, allSubs); @@ -1711,29 +2143,78 @@ bool Model_AttributeSelection::restoreContext(std::string theName, 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; + aSub->shape()->isSubShape(aSelectedShape)) { + aResult = aSub; break; } } } - */ - if (aCont.get()) { - theContext = std::dynamic_pointer_cast(aCont->data())->label(); + // 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 true; + return aResult; } -bool Model_AttributeSelection::isLater( - const TDF_Label theResult1, const TDF_Label theResult2) const +void Model_AttributeSelection::combineGeometrical() { - 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); + if (myTmpContext.get() || myTmpSubShape.get()) + return; + TDF_Label aSelLab = selectionLabel(); + if (aSelLab.IsAttribute(kINVALID_SELECTION) || !myRef.isInitialized()) + return; + + 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); + } +} + +TDF_Label Model_AttributeSelection::baseDocumentLab() +{ + if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) + return std::dynamic_pointer_cast + (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel(); + static TDF_Label anEmpty; + return anEmpty; +} + +void Model_AttributeSelection::reset() +{ + ModelAPI_AttributeSelection::reset(); + myRef.reset(); }