X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=ffa3015b4c700e765ac91bb146cc835a6a249176;hb=2da91de2a9adef6b5bc5c94f840831f33334e0cb;hp=7348703eeb17c95499f749f23305f4cee53a7d7b;hpb=5a67842979db286af5bb5015fe413d8b06c6587e;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 7348703ee..ffa3015b4 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -23,21 +23,28 @@ #include "Model_Events.h" #include "Model_Data.h" #include "Model_Document.h" -#include "Model_SelectionNaming.h" #include #include #include #include #include -#include +#include #include #include #include #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include -#include #include #include #include @@ -47,13 +54,20 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include #include +#include +#include +#include +#include //#define DEB_NAMING 1 #ifdef DEB_NAMING @@ -69,39 +83,67 @@ Standard_GUID kPART_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb27"); // selection is invalid after recomputation Standard_GUID kINVALID_SELECTION("bce47fd7-80fa-4462-9d63-2f58acddd49d"); +// identifier of the selection of the center of circle on edge +Standard_GUID kCIRCLE_CENTER("d0d0e0f1-217a-4b95-8fbb-0c4132f23718"); +// identifier of the selection of the first focus point of ellipse on edge +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"); +// reference to the external sketch face +Standard_GUID kEXT_SKETCH_FACE("ba32aa31-bde7-422f-80b4-79c757c77b49"); +// reference to the external sketch edge +Standard_GUID kEXT_SKETCH_EDGE("ba32aa31-bde7-422f-80b4-79c757c77b48"); +// reference to the external sketch vertex +Standard_GUID kEXT_SKETCH_VERT("ba32aa31-bde7-422f-80b4-79c757c77b47"); + +// prefix for the whole feature context identification +const static std::string kWHOLE_FEATURE = "all-in-"; + // on this label is stored: // TNaming_NamedShape - selected shape // TNaming_Naming - topological selection information (for the body) // TDataStd_IntPackedMap - indexes of edges in composite element (for construction) // TDataStd_Integer - type of the selected shape (for construction) // TDF_Reference - from ReferenceAttribute, the context -void Model_AttributeSelection::setValue(const ResultPtr& theContext, +bool Model_AttributeSelection::setValue(const ObjectPtr& theContext, const std::shared_ptr& theSubShape, const bool theTemporarily) { - if (theTemporarily) { // just keep the stored without DF update - myTmpContext = theContext; + if (theTemporarily && + (!theContext.get() || theContext->groupName() != ModelAPI_Feature::group())) { + // just keep the stored without DF update + myTmpContext = std::dynamic_pointer_cast(theContext); myTmpSubShape = theSubShape; owner()->data()->sendAttributeUpdated(this); - return; + return true; } else { myTmpContext.reset(); myTmpSubShape.reset(); + myTmpCenterType = NOT_CENTER; } - const std::shared_ptr& anOldShape = value(); + CenterType aType; + const std::shared_ptr& anOldShape = internalValue(aType); bool isOldContext = theContext == myRef.value(); bool isOldShape = isOldContext && (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape))); - if (isOldShape) return; // shape is the same, so context is also unchanged + if (isOldShape) return false; // shape is the same, so context is also unchanged + bool aToUnblock = false; // update the referenced object if needed if (!isOldContext) { - myRef.setValue(theContext); + aToUnblock = !owner()->data()->blockSendAttributeUpdated(true); + myRef.setValue(theContext); } // do noth 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(kEXT_SKETCH_FACE); + aSelLab.ForgetAttribute(kEXT_SKETCH_EDGE); + aSelLab.ForgetAttribute(kEXT_SKETCH_VERT); bool isDegeneratedEdge = false; // do not use the degenerated edge as a shape, a null context and shape is used in the case @@ -115,34 +157,109 @@ void Model_AttributeSelection::setValue(const ResultPtr& theContext, TDF_Label aRefLab = myRef.myRef->Label(); aSelLab.ForgetAllAttributes(true); myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father()); - return; + if (aToUnblock) + owner()->data()->blockSendAttributeUpdated(false); + return false; } - if (theContext->groupName() == ModelAPI_ResultBody::group()) { + 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 (theContext->shape().get() && - (theContext->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(theContext, theSubShape); + selectBody(aContextResult, theSubShape); } } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) { aSelLab.ForgetAllAttributes(true); // to remove old selection data std::shared_ptr aConstruction = std::dynamic_pointer_cast(theContext); std::shared_ptr aSubShape; - if (theSubShape.get() && !theContext->shape()->isEqual(theSubShape)) + if (theSubShape.get() && !aConstruction->shape()->isEqual(theSubShape)) aSubShape = theSubShape; // the whole context - int anIndex = aConstruction->select(theSubShape, owner()->document()); - TDataStd_Integer::Set(aSelLab, anIndex); + 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(theContext, theSubShape); + selectPart(std::dynamic_pointer_cast(theContext), theSubShape); + } else { // check the feature context: parent-Part of this feature should not be used + FeaturePtr aFeatureContext = std::dynamic_pointer_cast(theContext); + if (aFeatureContext.get()) { + if (owner()->document() != aFeatureContext->document()) { + aSelLab.ForgetAllAttributes(true); + myRef.setValue(ObjectPtr()); + if (aToUnblock) + owner()->data()->blockSendAttributeUpdated(false); + return false; + } + } } owner()->data()->sendAttributeUpdated(this); + + if (aToUnblock) + owner()->data()->blockSendAttributeUpdated(false); + + return true; +} + +void Model_AttributeSelection::setValueCenter( + const ObjectPtr& theContext, const std::shared_ptr& theEdge, + const CenterType theCenterType, const bool theTemporarily) +{ + bool anUpdated = setValue(theContext, theEdge, theTemporarily); + if (theTemporarily) { + myTmpCenterType = theCenterType; + } else { // store in the data structure + TDF_Label aSelLab = selectionLabel(); + switch(theCenterType) { + case CIRCLE_CENTER: + if (!anUpdated) + anUpdated = !aSelLab.IsAttribute(kCIRCLE_CENTER); + TDataStd_UAttribute::Set(aSelLab, kCIRCLE_CENTER); + break; + case ELLIPSE_FIRST_FOCUS: + if (!anUpdated) + anUpdated = !aSelLab.IsAttribute(kELLIPSE_CENTER1); + TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER1); + break; + case ELLIPSE_SECOND_FOCUS: + if (!anUpdated) + anUpdated = !aSelLab.IsAttribute(kELLIPSE_CENTER2); + TDataStd_UAttribute::Set(aSelLab, kELLIPSE_CENTER2); + break; + } + if (anUpdated) + owner()->data()->sendAttributeUpdated(this); + } +} + +void Model_AttributeSelection::selectValue( + const std::shared_ptr& theSource) +{ + CenterType aType; + std::shared_ptr aValue = + std::dynamic_pointer_cast(theSource)->internalValue(aType); + if (!aValue.get() || aType == NOT_CENTER) { + setValue(theSource->context(), aValue); + } else { + std::shared_ptr anEdge(new GeomAPI_Edge); + anEdge->setImpl(new TopoDS_Shape(aValue->impl())); + setValueCenter(theSource->context(), anEdge, aType); + } } void Model_AttributeSelection::removeTemporaryValues() @@ -153,10 +270,57 @@ void Model_AttributeSelection::removeTemporaryValues() } } +// returns the center of the edge: circular or elliptical +GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::CenterType theType) +{ + if (theType != ModelAPI_AttributeSelection::NOT_CENTER && theEdge.get() != NULL) { + TopoDS_Shape aShape = theEdge->impl(); + if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge anEdge = TopoDS::Edge(aShape); + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (!aCurve.IsNull()) { + TopoDS_Vertex aVertex; + BRep_Builder aBuilder; + if (theType == ModelAPI_AttributeSelection::CIRCLE_CENTER) { + Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve); + if (!aCirc.IsNull()) { + aBuilder.MakeVertex(aVertex, aCirc->Location(), Precision::Confusion()); + } + } else { // ellipse + Handle(Geom_Ellipse) anEll = Handle(Geom_Ellipse)::DownCast(aCurve); + if (!anEll.IsNull()) { + aBuilder.MakeVertex(aVertex, + theType == ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS ? + anEll->Focus1() : anEll->Focus2(), Precision::Confusion()); + } + } + if (!aVertex.IsNull()) { + std::shared_ptr aResult(new GeomAPI_Vertex); + aResult->setImpl(new TopoDS_Vertex(aVertex)); + return aResult; + } + } + } + } + return theEdge; // no vertex, so, return the initial edge +} + std::shared_ptr Model_AttributeSelection::value() { + if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) + return std::shared_ptr(); + CenterType aType = NOT_CENTER; + std::shared_ptr aResult = internalValue(aType); + return centerByEdge(aResult, aType); +} + +std::shared_ptr Model_AttributeSelection::internalValue(CenterType& theType) +{ + theType = NOT_CENTER; GeomShapePtr aResult; if (myTmpContext.get() || myTmpSubShape.get()) { + theType = myTmpCenterType; ResultConstructionPtr aResulConstruction = std::dynamic_pointer_cast(myTmpContext); if(aResulConstruction.get()) { @@ -170,11 +334,19 @@ std::shared_ptr Model_AttributeSelection::value() if (aSelLab.IsAttribute(kINVALID_SELECTION)) return aResult; + if (aSelLab.IsAttribute(kCIRCLE_CENTER)) + theType = CIRCLE_CENTER; + else if (aSelLab.IsAttribute(kELLIPSE_CENTER1)) + theType = ELLIPSE_FIRST_FOCUS; + else if (aSelLab.IsAttribute(kELLIPSE_CENTER2)) + theType = ELLIPSE_SECOND_FOCUS; + + 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)) { @@ -201,22 +373,75 @@ std::shared_ptr Model_AttributeSelection::value() } } + std::shared_ptr aConstr = + std::dynamic_pointer_cast(context()); + if (aConstr) { + if (aConstr->isInfinite()) + return aResult; // empty result + // external sketch face + Handle(TDataStd_Integer) anIndex; + if (aSelLab.FindAttribute(kEXT_SKETCH_FACE, anIndex)) { + return aConstr->face(anIndex->Get()); + } + if (aSelLab.FindAttribute(kEXT_SKETCH_EDGE, anIndex) || + aSelLab.FindAttribute(kEXT_SKETCH_VERT, anIndex)) { + bool isVert = anIndex->ID() == kEXT_SKETCH_VERT; // vertex is selected + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast( + aConstr->document()->feature(aConstr)); + if (aComposite.get()) { + int aSubNum = anIndex->Get() % 1000000; + int aVertShape = (anIndex->Get() - aSubNum) / 1000000; + FeaturePtr aSubFeat = aComposite->subFeature(aSubNum); + if (aSubFeat.get()) { + const std::list >& aResults = aSubFeat->results(); + std::list >::const_iterator aRes = aResults.cbegin(); + for (; aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + if (aConstr->shape()) { + if (!isVert && aConstr->shape()->isEdge()) + return aConstr->shape(); + else if (isVert && aVertShape == 0 && aConstr->shape()->isVertex()) + return aConstr->shape(); + else if (isVert && aVertShape > 1 && aConstr->shape()->isEdge()) { + GeomAPI_ShapeExplorer anExp(aConstr->shape(), GeomAPI_Shape::VERTEX); + for(; anExp.more(); anExp.next()) { + if (aVertShape == 1) + return anExp.current(); + aVertShape--; + } + } + } + } + } + } + } + } + if (!aConstr.get()) { // for construction context, return empty result as usual even + // the whole feature is selected + FeaturePtr aFeature = contextFeature(); + if (aFeature.get()) { + std::list allShapes; + std::list::const_iterator aRes = aFeature->results().cbegin(); + for (; aRes != aFeature->results().cend(); aRes++) { + if (aRes->get() && !(*aRes)->isDisabled()) { + GeomShapePtr aShape = (*aRes)->shape(); + if (aShape.get() && !aShape->isNull()) { + allShapes.push_back(aShape); + } + } + } + return GeomAlgoAPI_CompoundBuilder::compound(allShapes); + } + } + Handle(TNaming_NamedShape) aSelection; if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { TopoDS_Shape aSelShape = aSelection->Get(); aResult = std::shared_ptr(new GeomAPI_Shape); aResult->setImpl(new TopoDS_Shape(aSelShape)); - } else { // for simple construction element: just shape of this construction element - std::shared_ptr aConstr = - std::dynamic_pointer_cast(context()); - if (aConstr) { - 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()); - } - } + } else if (aConstr) { // simple construction element: just shape of this construction element + aResult = aConstr->shape(); } } return aResult; @@ -244,12 +469,12 @@ bool Model_AttributeSelection::isInitialized() 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; } } } @@ -269,30 +494,54 @@ void Model_AttributeSelection::setID(const std::string theID) ModelAPI_AttributeSelection::setID(theID); } -ResultPtr Model_AttributeSelection::context() { +ResultPtr Model_AttributeSelection::context() +{ + if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) + return ResultPtr(); + if (myTmpContext.get() || myTmpSubShape.get()) { return myTmpContext; } ResultPtr aResult = std::dynamic_pointer_cast(myRef.value()); // for parts there could be same-data result, so take the last enabled - if (aResult.get() && aResult->groupName() == ModelAPI_ResultPart::group()) { - int aSize = aResult->document()->size(ModelAPI_ResultPart::group()); - for(int a = aSize - 1; a >= 0; a--) { - ObjectPtr aPart = aResult->document()->object(ModelAPI_ResultPart::group(), a); - if (aPart.get() && aPart->data() == aResult->data()) { - ResultPtr aPartResult = std::dynamic_pointer_cast(aPart); - FeaturePtr anOwnerFeature = std::dynamic_pointer_cast(owner()); - // check that this result is not this-feature result (it is forbidden t oselect itself) - if (anOwnerFeature.get() && anOwnerFeature->firstResult() != aPartResult) { - return aPartResult; + if (aResult.get()) { + if(aResult->groupName() == ModelAPI_ResultPart::group()) { + int aSize = aResult->document()->size(ModelAPI_ResultPart::group()); + for(int a = aSize - 1; a >= 0; a--) { + ObjectPtr aPart = aResult->document()->object(ModelAPI_ResultPart::group(), a); + if(aPart.get() && aPart->data() == aResult->data()) { + ResultPtr aPartResult = std::dynamic_pointer_cast(aPart); + FeaturePtr anOwnerFeature = std::dynamic_pointer_cast(owner()); + // check that this result is not this-feature result (it is forbidden t oselect itself) + if(anOwnerFeature.get() && anOwnerFeature->firstResult() != aPartResult) { + return aPartResult; + } } } } + } else { // if feature - construction is selected, it has only one result, return this result + FeaturePtr aFeature = std::dynamic_pointer_cast(myRef.value()); + if (aFeature.get() && aFeature->results().size() == 1 && + aFeature->firstResult()->groupName() == ModelAPI_ResultConstruction::group()) + return aFeature->firstResult(); } return aResult; } +FeaturePtr Model_AttributeSelection::contextFeature() { + if (myTmpContext.get() || myTmpSubShape.get()) { + return FeaturePtr(); // feature can not be selected temporarily + } + return std::dynamic_pointer_cast(myRef.value()); +} +ObjectPtr Model_AttributeSelection::contextObject() { + FeaturePtr aRes = contextFeature(); + if (aRes.get()) + return aRes; + return context(); +} + void Model_AttributeSelection::setObject(const std::shared_ptr& theObject) { @@ -300,68 +549,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 - 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) { @@ -401,6 +588,11 @@ void Model_AttributeSelection::split( 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(); ResultPtr aContext = context(); if (!aContext.get()) @@ -420,21 +612,25 @@ bool Model_AttributeSelection::update() } if (aContext->groupName() == ModelAPI_ResultBody::group()) { - // 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(); + Handle(TNaming_NamedShape) aNS; + 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); } - bool aResult = aSelector.Solve(scope()) == Standard_True; - // must be before sending of updated attribute (1556) aResult = setInvalidIfFalse(aSelLab, aResult); + TopoDS_Shape aNewShape; - if (!aSelector.NamedShape().IsNull()) { - aNewShape = aSelector.NamedShape()->Get(); - } - if (anOldShape.IsNull() || aNewShape.IsNull() || - !anOldShape.IsEqual(aSelector.NamedShape()->Get())) { + 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 if (myParent && !anOldShape.IsNull() && !aNewShape.IsNull() && anOldShape.ShapeType() != aNewShape.ShapeType() && @@ -448,17 +644,39 @@ bool Model_AttributeSelection::update() } 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 (aModified) - owner()->data()->sendAttributeUpdated(this); - return aValid; + bool aResult = true; + 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()); + } + if (aSelLab.FindAttribute(kEXT_SKETCH_EDGE, anIndex) || + aSelLab.FindAttribute(kEXT_SKETCH_VERT, anIndex)) { + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast( + aConstructionContext->document()->feature(aConstructionContext)); + if (aComposite.get()) { + FeaturePtr aSubFeat = aComposite->subFeature(anIndex->Get() % 1000000); + return setInvalidIfFalse(aSelLab, aSubFeat.get() != NULL); + } + return setInvalidIfFalse(aSelLab, false); // composite sub-feature is not found + } + Selector_Selector aSelector(aSelLab); + aResult = aSelector.restore(); + TopoDS_Shape anOldShape = aSelector.value(); + if (aResult) { + TopoDS_Shape aContextShape = aContext->shape()->impl(); + aResult = aSelector.solve(aContextShape); + } + aResult = 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 } @@ -467,10 +685,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);//myRef.value() if (aBody) { aContext = aBody->shape()->impl(); } else { @@ -484,82 +701,94 @@ 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; + 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 + if (theSubShape->shapeType() == TopAbs_FACE) { // 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; + } + } else if (theSubShape->shapeType() == TopAbs_EDGE || // sketch result edge (full one) + theSubShape->shapeType() == TopAbs_VERTEX) { // or start/end vertex + bool isVertex = theSubShape->shapeType() == TopAbs_VERTEX; + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast( + theContext->document()->feature(theContext)); + if (aComposite.get()) { // iterate edges of composite to find index of matched with value + int aSub, anEdgeIndex = -1, aSubNum = aComposite->numberOfSubs(); + int aVertIndex = -1, aVertShape = -1; // shape: 0 full, 1 start, 2 end + for(aSub = 0; aSub < aSubNum && anEdgeIndex == -1; aSub++) { + FeaturePtr aSubFeat = aComposite->subFeature(aSub); + const std::list >& aResults = aSubFeat->results(); + std::list >::const_iterator aRes = aResults.cbegin(); + for (; aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + if (aConstr->shape() && aConstr->shape()->isEdge()) { + if (isVertex) { + GeomAPI_ShapeExplorer aVertExp(aConstr->shape(), GeomAPI_Shape::VERTEX); + for(int aNum = 1; aVertExp.more(); aVertExp.next(), aNum++) { + if (aVertExp.current()->isSame(theSubShape) && aVertShape != 0) { + aVertIndex = aSub; + aVertShape = aNum; + } + } + } else { + if (aConstr->shape()->isSame(theSubShape)) { + anEdgeIndex = aSub; + break; + } + } + } else if (isVertex && aConstr->shape() && aConstr->shape()->isVertex()) { + if (aConstr->shape()->isSame(theSubShape)) { + aVertIndex = aSub; + aVertShape = 0; + } + } + } + } + if (anEdgeIndex >= 0) { + TDataStd_Integer::Set(aSelLab, kEXT_SKETCH_EDGE, anEdgeIndex); // store index of edge + return; + } else if (aVertIndex >= 0) { + aVertIndex += aVertShape * 1000000; // to store both integers: index and shape + TDataStd_Integer::Set(aSelLab, kEXT_SKETCH_VERT, aVertIndex); // store index of edge + return; + } + } } } - } - 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().IsEqual(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), case is in 1799 - ResultCompSolidPtr aMain = ModelAPI_Tools::compSolidOwner(theContext); - if (aMain.get()) { - selectBody(aMain, theSubShape); - return; + bool aSelectorOk = true; + Selector_Selector aSel(aSelLab); + try { + aSelectorOk = aSel.select(aContext, aNewSub); + if (aSelectorOk) { + aSel.store(); + aSelectorOk = aSel.solve(aContext); } - setInvalidIfFalse(aSelLab, false); - Events_InfoMessage("Model_AttributeSelection", - "Failed to select sub-shape already modified").send(); - return; + } catch(...) { + aSelectorOk = false; } - } - - /// 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); + 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; } - aSel.Select(aNewSub, aNewContext); - - 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) { + setInvalidIfFalse(aSelLab, false); } } } @@ -607,21 +836,100 @@ TDF_Label Model_AttributeSelection::selectionLabel() return myRef.myRef->Label().FindChild(1); } +/// prefixes of the shape names with centers defined +static std::map kCENTERS_PREFIX; + +/// returns the map that contains all possible prefixes of the center-names +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"; + } + return kCENTERS_PREFIX; +} + std::string Model_AttributeSelection::namingName(const std::string& theDefaultName) { std::string aName(""); if(!this->isInitialized()) return !theDefaultName.empty() ? theDefaultName : aName; - std::shared_ptr aSubSh = value(); + CenterType aCenterType = NOT_CENTER; + std::shared_ptr aSubSh = internalValue(aCenterType); ResultPtr aCont = context(); - if (!aCont.get()) // in case of selection of removed result + if (!aCont.get() || + (aCont->groupName() == ModelAPI_ResultConstruction::group() && contextFeature().get())) { + // selection of a full feature + FeaturePtr aFeatureCont = contextFeature(); + if (aFeatureCont.get()) { + return kWHOLE_FEATURE + aFeatureCont->name(); + } + // in case of selection of removed result return ""; + } + + TDF_Label aSelLab = selectionLabel(); + if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value + return contextName(aCont); + } - Model_SelectionNaming aSelNaming(selectionLabel()); - return aSelNaming.namingName( + // whole infinitive construction + if (aCont->groupName() == ModelAPI_ResultConstruction::group()) { + ResultConstructionPtr aConstr = std::dynamic_pointer_cast(aCont); + if (aConstr->isInfinite()) { + return contextName(aCont); + } else { + // external sketch face + Handle(TDataStd_Integer) anIndex; + if (aSelLab.FindAttribute(kEXT_SKETCH_FACE, anIndex) || + aSelLab.FindAttribute(kEXT_SKETCH_EDGE, anIndex) || + aSelLab.FindAttribute(kEXT_SKETCH_VERT, anIndex)) { + 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()) + 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]; + } + return aResult; +} + +// returns the center type and modifies the shape name if this name is center-name +static ModelAPI_AttributeSelection::CenterType centerTypeByName(std::string& theShapeName) +{ + std::map::iterator aPrefixIter = + centersMap().begin(); + for(; aPrefixIter != centersMap().end(); aPrefixIter++) { + std::size_t aFound = theShapeName.find(aPrefixIter->second); + if (aFound != std::string::npos && + aFound == theShapeName.size() - aPrefixIter->second.size()) { + theShapeName = theShapeName.substr(0, aFound); + return aPrefixIter->first; + } + } + return ModelAPI_AttributeSelection::NOT_CENTER; } // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT @@ -630,54 +938,173 @@ void Model_AttributeSelection::selectSubShape( { if(theSubShapeName.empty() || theType.empty()) return; - // check this is Part-name: 2 delimiters in the name - std::size_t aPartEnd = theSubShapeName.find('/'); - if (aPartEnd != std::string::npos && aPartEnd != theSubShapeName.rfind('/')) { - std::string aPartName = theSubShapeName.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 = theSubShapeName.substr(aPartEnd + 1); - int anIndex; - std::shared_ptr aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex); - if (aSelected.get()) { - setValue(aPart, aSelected); - TDataStd_Integer::Set(selectionLabel(), anIndex); + std::string 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) { + aCenterType = NOT_CENTER; + aType = theType; + } else if (aUseCenter != 1) continue; + + 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); + DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); + if (aPartName == 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); + aDoc = std::dynamic_pointer_cast(aPart->partDoc()); + aSubShapeName = aSubShapeName.substr(aPartEnd +1); + } + } + } + + // 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()); + ObjectPtr anObj = aDoc->objectByName(ModelAPI_Feature::group(), aFeatureName); + if (anObj.get()) { + setValue(anObj, anEmptyShape); return; } } - } - Model_SelectionNaming aSelNaming(selectionLabel()); - std::shared_ptr aDoc = - std::dynamic_pointer_cast(owner()->document()); - std::shared_ptr aShapeToBeSelected; - ResultPtr aCont; - if (aSelNaming.selectSubShape(theType, theSubShapeName, 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()) { - TDF_Label aLab = aNS->Label(); - while(aLab.Depth() != 7 && aLab.Depth() > 5) - aLab = aLab.Father(); - ObjectPtr 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('/') == std::string::npos) { + ObjectPtr aRes = aDoc->objectByName(ModelAPI_ResultConstruction::group(), aSubShapeName); + if (!aRes.get()) + aRes = aDoc->objectByName(ModelAPI_ResultBody::group(), aSubShapeName); + if (aRes.get()) { + setValue(aRes, anEmptyShape); + return; + } + } + + Selector_Selector aSelector(aDoc->generalLabel()); + myRestoreDocument = aDoc; + TDF_Label aContextLabel = aSelector.restoreByName(aSubShapeName, aShapeType, this); + 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)) { + GeomShapePtr aShapeToBeSelected(new GeomAPI_Shape); + aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelector.value())); + if (aCenterType != NOT_CENTER) { + if (!aShapeToBeSelected->isEdge()) + continue; + std::shared_ptr aSelectedEdge(new GeomAPI_Edge(aShapeToBeSelected)); + setValueCenter(aContext, aSelectedEdge, aCenterType); } + else + setValue(aContext, aShapeToBeSelected); + return; } } } - setValue(aCont, aShapeToBeSelected); + aSubShapeName = theSubShapeName; + } + // invalid + TDF_Label aSelLab = selectionLabel(); + setInvalidIfFalse(aSelLab, false); + reset(); +} + +void Model_AttributeSelection::selectSubShape(const std::string& theType, + const GeomPointPtr& thePoint) +{ + if (theType.empty() || !thePoint) return; + + // list of parent features + FeaturePtr anOwner = ModelAPI_Feature::feature(owner()); + std::set aParents = ModelAPI_Tools::getParents(anOwner); + + int aSelectionIndex = 0; + GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(theType); + if (aType == GeomAPI_Shape::SHAPE) { + // possibly, the string consists of the type and the index, + // thus, try to separate them + size_t aUndersporePos = theType.find_first_of('_'); + if (aUndersporePos != std::string::npos) + aType = GeomAPI_Shape::shapeTypeByStr(theType.substr(0, aUndersporePos)); + + if (aType != GeomAPI_Shape::SHAPE) { + for (std::string::const_iterator aChar = theType.begin() + aUndersporePos + 1; + aChar != theType.end(); ++aChar) { + if (std::isdigit(*aChar)) + aSelectionIndex = aSelectionIndex * 10 + (*aChar - '0'); + else { + aSelectionIndex = 1; + break; + } + } + aSelectionIndex -= 1; + } + } + + std::list anAppropriate; + + // collect features from PartSet and the current part + SessionPtr aSession = ModelAPI_Session::get(); + std::list aFeatures = aSession->moduleDocument()->allFeatures(); + if (aSession->moduleDocument() != owner()->document()) { + std::list aPartFeatures = owner()->document()->allFeatures(); + aFeatures.insert(aFeatures.end(), aPartFeatures.begin(), aPartFeatures.end()); + } + // Process results of all features from the last to the first + // to find appropriate sub-shape + for (std::list::const_reverse_iterator anIt = aFeatures.rbegin(); + anIt != aFeatures.rend(); ++anIt) { + // selection cannot be linked to the parent features + if (aParents.find(*anIt) != aParents.end()) + continue; + // check the feature is a part of composite feature (like sketch elements), + // then do not process it, it will be processed in scope of composite feature + bool isSubOfComposite = false; + const std::set& aRefs = (*anIt)->data()->refsToMe(); + for (std::set::const_iterator aRefIt = aRefs.begin(); + aRefIt != aRefs.end() && !isSubOfComposite; ++aRefIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature((*aRefIt)->owner()); + CompositeFeaturePtr aCompFeature = + std::dynamic_pointer_cast(aFeature); + isSubOfComposite = aCompFeature && aCompFeature->isSub(*anIt); + } + if (isSubOfComposite) + continue; + + // process results of the current feature to find appropriate sub-shape + if (ModelGeomAlgo_Shape::findSubshapeByPoint(*anIt, thePoint, aType, anAppropriate)) { + std::list::iterator anApIt = anAppropriate.begin(); + for (; aSelectionIndex > 0 && anApIt != anAppropriate.end(); --aSelectionIndex) + ++anApIt; // skip this shape, because one of the previous is selected + + if (anApIt != anAppropriate.end()) { + if (anApIt->myCenterType == (int)ModelAPI_AttributeSelection::NOT_CENTER) + setValue(anApIt->myResult, anApIt->mySubshape); + else + setValueCenter(anApIt->myResult, anApIt->mySubshape->edge(), + (ModelAPI_AttributeSelection::CenterType)anApIt->myCenterType); + return; + } + } } TDF_Label aSelLab = selectionLabel(); @@ -685,21 +1112,48 @@ void Model_AttributeSelection::selectSubShape( reset(); } +void Model_AttributeSelection::selectSubShape(const std::string& theType, + const std::string& 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(); - std::shared_ptr aContext = context()->shape(); + ResultPtr aContextRes = context(); // support for compsolids: - if (context().get() && ModelAPI_Tools::compSolidOwner(context()).get()) - aContext = ModelAPI_Tools::compSolidOwner(context())->shape(); + 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()) + if (aSelection && !aSelection->isNull() && aContext && !aContext->isNull()) { std::shared_ptr aDoc = std::dynamic_pointer_cast(context()->document()); @@ -719,21 +1173,21 @@ int Model_AttributeSelection::Id() void Model_AttributeSelection::setId(int theID) { - const ResultPtr& aContext = context(); std::shared_ptr aSelection; - std::shared_ptr aContextShape = aContext->shape(); + ResultPtr aContextRes = context(); // support for compsolids: - if (aContext.get() && ModelAPI_Tools::compSolidOwner(aContext).get()) - aContextShape = ModelAPI_Tools::compSolidOwner(aContext)->shape(); + while(ModelAPI_Tools::bodyOwner(aContextRes).get()) { + aContextRes = ModelAPI_Tools::bodyOwner(aContextRes); + } + std::shared_ptr aContext = aContextRes->shape(); - TopoDS_Shape aMainShape = aContextShape->impl(); + TopoDS_Shape aMainShape = aContext->impl(); // searching for the latest main shape - if (theID > 0 && - aContextShape && !aContextShape->isNull()) + if (theID > 0 && aContext && !aContext->isNull()) { std::shared_ptr aDoc = - std::dynamic_pointer_cast(aContext->document()); + std::dynamic_pointer_cast(aContextRes->document()); if (aDoc.get()) { Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel()); if (!aNS.IsNull()) { @@ -751,7 +1205,7 @@ void Model_AttributeSelection::setId(int theID) aSelection = aResult; } - setValue(aContext, aSelection); + setValue(aContextRes, aSelection); } std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const @@ -772,21 +1226,256 @@ std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) c return aResult; } +void Model_AttributeSelection::computeValues( + ResultPtr theOldContext, ResultPtr theNewContext, TopoDS_Shape theValShape, + TopTools_ListOfShape& theShapes) +{ + bool aWasWholeContext = theValShape.IsNull(); + if (aWasWholeContext) { + //theShapes.Append(theValShape); + //return; + theValShape = theOldContext->shape()->impl(); + } + //TopoDS_Shape anOldContShape = theOldContext->shape()->impl(); + 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()); + for(; aSubExp.More(); aSubExp.Next()) { + if (aSubExp.Current().IsSame(theValShape)) { + theShapes.Append(theValShape); + return; + } + } + // if new context becomes compsolid, the resulting sub may be in sub-solids + std::list aNewToIterate; + aNewToIterate.push_back(theNewContext); + ResultBodyPtr aComp = std::dynamic_pointer_cast(theNewContext); + if (aComp.get()) { + std::list allNewContextSubs; + ModelAPI_Tools::allSubs(aComp, allNewContextSubs); + std::list::iterator aSub = allNewContextSubs.begin(); + for(; aSub != allNewContextSubs.end(); aSub++) { + ResultBodyPtr aBody = std::dynamic_pointer_cast(*aSub); + if (aBody.get() && aBody->numberOfSubs() == 0) // add only lower level subs + aNewToIterate.push_back(aBody); + } + } + + // first iteration: searching for the whole shape appearance (like face of the box) + // second iteration: searching for sub-shapes that contain the sub (like vertex on faces) + int aToFindPart = 0; + TopTools_DataMapOfShapeShape aNewToOld; // map from new containers to old containers (with val) + TopTools_MapOfShape anOlds; // to know how many olds produced new containers + for(; aToFindPart != 2 && theShapes.IsEmpty(); aToFindPart++) { + std::list::iterator aNewContIter = aNewToIterate.begin(); + for(; aNewContIter != aNewToIterate.end(); aNewContIter++) { + std::shared_ptr aNewData = + 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); + for(; aNSIter.More(); aNSIter.Next()) { + Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value()); + for(TNaming_Iterator aPairIter(aNS); aPairIter.More(); aPairIter.Next()) { + if (aToFindPart == 0) { // search shape is fully inside + if (aPairIter.OldShape().IsSame(theValShape)) { + if (aPairIter.NewShape().IsNull()) {// value was removed + theShapes.Clear(); + return; + } + theShapes.Append(aPairIter.NewShape()); + } + } else if (!aPairIter.OldShape().IsNull()) { // search shape that contains this sub + TopExp_Explorer anExp(aPairIter.OldShape(), theValShape.ShapeType()); + for(; anExp.More(); anExp.Next()) { + if (anExp.Current().IsSame(theValShape)) { // found a new container + if (aPairIter.NewShape().IsNull()) {// value was removed + theShapes.Clear(); + return; + } + aNewToOld.Bind(aPairIter.NewShape(), aPairIter.OldShape()); + anOlds.Add(aPairIter.OldShape()); + break; + } + } + } + } + } + } + } + if (aToFindPart == 2 && !aNewToOld.IsEmpty()) { + // map of sub-shapes -> number of occurences 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()) { + if (!aSubs.IsBound(aSubExp.Current())) { + aSubs.Bind(aSubExp.Current(), TopTools_MapOfShape()); + } + // store old to know how many olds produced this shape + aSubs.ChangeFind(aSubExp.Current()).Add(aContIter.Value()); + } + } + // if sub is appeared same times in containers as the number of old shapes that contain it + int aCountInOld = anOlds.Size(); + NCollection_DataMap::Iterator + aSubsIter(aSubs); + for(; aSubsIter.More(); aSubsIter.Next()) { + if (aSubsIter.Value().Size() == aCountInOld) { + theShapes.Append(aSubsIter.Key()); + } + } + } + if (theShapes.IsEmpty()) { // nothing was changed + theShapes.Append(aWasWholeContext ? TopoDS_Shape() : theValShape); + } +} + +bool Model_AttributeSelection::searchNewContext(std::shared_ptr theDoc, + const TopoDS_Shape theContShape, ResultPtr theContext, TopoDS_Shape theValShape, + TDF_Label theAccessLabel, + std::list& theResults, TopTools_ListOfShape& theValShapes) +{ + std::set aResults; // to avoid duplicates, new context, null if deleted + TopTools_ListOfShape aResContShapes; + // iterate context and shape, but also if it is sub-shape of main shape, check also it + TopTools_ListOfShape aContextList; + aContextList.Append(theContShape); + if (theContext.get()) { + ResultPtr aComposite = ModelAPI_Tools::bodyOwner(theContext); + if (aComposite.get() && aComposite->shape().get() && !aComposite->shape()->isNull()) + aContextList.Append(aComposite->shape()->impl()); + } + for(TopTools_ListOfShape::Iterator aContIter(aContextList); aContIter.More(); aContIter.Next()) { + TNaming_SameShapeIterator aModifIter(aContIter.ChangeValue(), theAccessLabel); + for(; aModifIter.More(); aModifIter.Next()) { + TDF_Label anObjLab = aModifIter.Label().Father(); + ResultPtr aModifierObj = std::dynamic_pointer_cast + (theDoc->objects()->object(anObjLab)); + if (!aModifierObj.get()) { + // #2241: shape may be sub-element of new object, not main (shell created from faces) + if (!anObjLab.IsRoot()) + aModifierObj = std::dynamic_pointer_cast + (theDoc->objects()->object(anObjLab.Father())); + if (!aModifierObj.get()) + continue; + } + FeaturePtr aModifierFeat = theDoc->feature(aModifierObj); + if (!aModifierFeat.get()) + continue; + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + 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->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()); + } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is empty + aResults.insert(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 (aResIter->get() != NULL) { + // compute new values by two contextes: the old and the new + TopTools_ListOfShape aValShapes; + computeValues(theContext, *aResIter, 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(); + if (theValShape.IsNull() && aNewContShape.IsSame(aNewValSh)) + aNewValSh.Nullify(); + if (searchNewContext(theDoc, aNewContShape, *aResIter, aNewValSh, + theAccessLabel, aNewRes, aNewUpdatedVal)) + { + // appeand 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(*aResIter); + theValShapes.Append(aNewValSh); + } + } + } + } + return true; // theResults must be empty: everything is deleted +} + void Model_AttributeSelection::updateInHistory() { ResultPtr aContext = std::dynamic_pointer_cast(myRef.value()); - // only bodies may be modified later in the history, don't do anything otherwise - if (!aContext.get() || aContext->groupName() != ModelAPI_ResultBody::group()) + // 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; + 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 Handle(TNaming_NamedShape) aContNS; - if (!aContLab.FindAttribute(TNaming_NamedShape::GetID(), aContNS)) + if (!aContLab.FindAttribute(TNaming_NamedShape::GetID(), aContNS)) { + bool aFoundNewContext = true; + ResultPtr aNewContext = aContext; + while(aFoundNewContext) { + aFoundNewContext = false; + // parts have no shape in result, so, trace references using the Part info + if (aNewContext->groupName() == ModelAPI_ResultPart::group()) { + ResultPartPtr aPartContext = std::dynamic_pointer_cast(aNewContext); + if (aPartContext.get()) { // searching for the up to date references to the referenced cont + const std::set& aRefs = aPartContext->data()->refsToMe(); + std::set::const_iterator aRef = aRefs.begin(); + for(; aRef != aRefs.end(); aRef++) { + // 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())) + continue; + + FeaturePtr aRefFeat = std::dynamic_pointer_cast((*aRef)->owner()); + if (aRefFeat.get() && aRefFeat != owner()) { + FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); + if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature + aFoundNewContext = true; + aNewContext = aRefFeat->firstResult(); + } + } + } + } + } + } + if (aNewContext != aContext) { + setValue(aNewContext, value()); + } return; - std::shared_ptr aDoc = - std::dynamic_pointer_cast(aContext->document()); + } FeaturePtr aThisFeature = std::dynamic_pointer_cast(owner()); FeaturePtr aCurrentModifierFeat = aDoc->feature(aContext); // iterate the context shape modifications in order to find a feature that is upper in history @@ -795,66 +1484,66 @@ void Model_AttributeSelection::updateInHistory() TNaming_Iterator aPairIter(aContNS); if (!aPairIter.More()) return; - TopoDS_Shape aNewShape = aPairIter.NewShape(); + 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())) aSubShape.reset(); + TopoDS_Shape aValShape; + if (aSubShape.get()) { + aValShape = aSubShape->impl(); + } - while(anIterate) { - anIterate = false; - TNaming_SameShapeIterator aModifIter(aNewShape, aContLab); - for(; aModifIter.More(); aModifIter.Next()) { - ResultPtr aModifierObj = std::dynamic_pointer_cast - (aDoc->objects()->object(aModifIter.Label().Father())); - if (!aModifierObj.get()) - break; - FeaturePtr aModifierFeat = aDoc->feature(aModifierObj); - if (!aModifierFeat.get()) - break; - if (aModifierFeat == aThisFeature || aDoc->objects()->isLater(aModifierFeat, aThisFeature)) - continue; // the modifier feature is later than this, so, should not be used - if (aCurrentModifierFeat == aModifierFeat || - aDoc->objects()->isLater(aCurrentModifierFeat, aModifierFeat)) - 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) { - aModifierResFound = aModifierObj; - aCurrentModifierFeat = aModifierFeat; - TNaming_Iterator aPairIter(aNewNS); - aNewShape = aPairIter.NewShape(); - anIterate = true; - break; - } else if (aNewNS->Evolution() == TNaming_DELETE) { // a shape was deleted => result is null - ResultPtr anEmptyContext; - std::shared_ptr anEmptyShape; - setValue(anEmptyContext, anEmptyShape); // nullify the selection - return; - } else { // not-precessed modification => don't support it - continue; - } + std::list aNewContexts; + 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; } - } - if (aModifierResFound.get()) { - // update scope to reset to a new one - myScope.Clear(); - myRef.setValue(aModifierResFound); - // if context shape type is changed to more complicated and this context is selected, split - if (myParent &&!aSubShape.get() && aModifierResFound->shape().get() && aContext->shape().get()) - { - TopoDS_Shape anOldShape = aContext->shape()->impl(); - TopoDS_Shape aNewShape = aModifierResFound->shape()->impl(); - if (!anOldShape.IsNull() && !aNewShape.IsNull() && - anOldShape.ShapeType() != aNewShape.ShapeType() && - (aNewShape.ShapeType() == TopAbs_COMPOUND || aNewShape.ShapeType() == TopAbs_COMPSOLID)) { - // prepare for split in "update" - TDF_Label aSelLab = selectionLabel(); - split(aContext, aNewShape, anOldShape.ShapeType()); + + 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 + 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())); + } + + // 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(); + } + + if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) { + continue; + } + + myParent->append(*aNewCont, aValueShape); } } - update(); // it must recompute a new sub-shape automatically } } @@ -862,3 +1551,224 @@ void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent { myParent = theParent; } + +std::string 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); + 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); + } + if (aResult.get()) { + // this is to avoid duplicated names of results problem + std::string 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 = "_" + aContextName; + aNumInHistoryNames--; + } + return aContextName; + } + } + return ""; // 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, + TDF_Label& theContext, TDF_Label& theValue) +{ + static const GeomShapePtr anEmptyShape; // to store context only + std::string 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) { + 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; + + // 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::string::size_type aSlash = aSubShapeName.rfind('/'); + if (aSlash != std::string::npos) { + std::string 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 if (aCompName.find((*aRes)->data()->name()) != std::string::npos) {// sub-vertex + 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; + } + } + } + } + } + } + } + } + + /* to find the latest lower result that keeps given shape + bool aFindNewContext = true; + while(aFindNewContext && aCont.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; + } + } + } + } else if (aCont->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; + } + } + 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())) + 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; + } + } + } + } + } + } + // if compsolid is context, try to take sub-solid as context: like in GUI and scripts + 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 (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); +}