X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_AttributeSelection.cpp;h=96c947bf4eaa31ca1b950b81ed169db31dfbe935;hb=9ba3503e67afb18e8f5f318a17d48990ed8dc5e9;hp=418186066fb26bca5498a1b3cdcba2db87d0e602;hpb=51cfbd8e37603efaae48a4102d4376899bc6fcae;p=modules%2Fshaper.git diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 418186066..96c947bf4 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -29,16 +29,20 @@ #include #include #include -#include +#include #include #include #include #include #include #include +#include #include #include +#include #include +#include +#include #include #include @@ -84,6 +88,13 @@ Standard_GUID kCIRCLE_CENTER("d0d0e0f1-217a-4b95-8fbb-0c4132f23718"); Standard_GUID kELLIPSE_CENTER1("f70df04c-3168-4dc9-87a4-f1f840c1275d"); // identifier of the selection of the second focus point of ellipse on edge Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32"); +// identifier of the weak naming index +Standard_GUID kWEAK_NAMING("9dcdd9be-a3a9-46eb-9b16-1c957ab20142"); +// identifier of the weak naming sub-shape type +Standard_GUID kWEAK_NAMING_SHAPETYPE("6b9cc709-e320-4a1f-9c42-df5622369ea7"); + +// prefix for the whole feature context identification +const static std::string kWHOLE_FEATURE = "all-in-"; // on this label is stored: // TNaming_NamedShape - selected shape @@ -91,11 +102,13 @@ Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32"); // 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 -bool 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 true; @@ -111,9 +124,11 @@ bool Model_AttributeSelection::setValue(const ResultPtr& theContext, bool isOldShape = isOldContext && (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape))); 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 @@ -123,6 +138,8 @@ bool Model_AttributeSelection::setValue(const ResultPtr& theContext, aSelLab.ForgetAttribute(kCIRCLE_CENTER); aSelLab.ForgetAttribute(kELLIPSE_CENTER1); aSelLab.ForgetAttribute(kELLIPSE_CENTER2); + aSelLab.ForgetAttribute(kWEAK_NAMING); + aSelLab.ForgetAttribute(kWEAK_NAMING_SHAPETYPE); bool isDegeneratedEdge = false; // do not use the degenerated edge as a shape, a null context and shape is used in the case @@ -136,45 +153,65 @@ bool Model_AttributeSelection::setValue(const ResultPtr& theContext, TDF_Label aRefLab = myRef.myRef->Label(); aSelLab.ForgetAllAttributes(true); myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father()); + if (aToUnblock) + owner()->data()->blockSendAttributeUpdated(false); return false; } if (theContext->groupName() == ModelAPI_ResultBody::group()) { + ResultBodyPtr aContextBody = std::dynamic_pointer_cast(theContext); // 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 (aContextBody->shape().get() && + (aContextBody->shape()->isEqual(theSubShape) || !theSubShape.get())) { aSelLab.ForgetAllAttributes(true); TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID); } else { - selectBody(theContext, theSubShape); + selectBody(aContextBody, theSubShape); } } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) { + ResultConstructionPtr aContextConstruction = + std::dynamic_pointer_cast(theContext); aSelLab.ForgetAllAttributes(true); // to remove old selection data std::shared_ptr aConstruction = std::dynamic_pointer_cast(theContext); std::shared_ptr aSubShape; - if (theSubShape.get() && !theContext->shape()->isEqual(theSubShape)) + if (theSubShape.get() && !aContextConstruction->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(theContext->shape()->impl()); + aBuilder.Generated(aContextConstruction->shape()->impl()); } int anIndex = aConstruction->select(theSubShape, owner()->document()); TDataStd_Integer::Set(aSelLab, anIndex); } else if (theContext->groupName() == ModelAPI_ResultPart::group()) { aSelLab.ForgetAllAttributes(true); TDataStd_UAttribute::Set(aSelLab, kPART_REF_ID); - selectPart(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 ResultPtr& theContext, const std::shared_ptr& theEdge, + const ObjectPtr& theContext, const std::shared_ptr& theEdge, const CenterType theCenterType, const bool theTemporarily) { bool anUpdated = setValue(theContext, theEdge, theTemporarily); @@ -265,6 +302,8 @@ GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::Cen 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); @@ -334,6 +373,47 @@ std::shared_ptr Model_AttributeSelection::internalValue(CenterTyp if (aConstr->isInfinite()) return aResult; // empty result } + 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); + } + } + + 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(); + } + } + 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; if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { TopoDS_Shape aSelShape = aSelection->Get(); @@ -379,6 +459,10 @@ bool Model_AttributeSelection::isInitialized() return true; } } + // for the whole feature, a feature object + FeaturePtr aFeat = contextFeature(); + if (aFeat.get()) + return true; } } } @@ -398,30 +482,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) { @@ -448,13 +556,14 @@ TDF_LabelMap& Model_AttributeSelection::scope() } } // for group Scope is not limitet: this is always up to date objects - bool isGroup = aFeature.get() && aFeature->getKind() == "Group"; + // this causes problem in galeries.py + //bool isGroup = aFeature.get() && aFeature->getKind() == "Group"; for(; aFIter != allFeatures.end(); aFIter++) { if (*aFIter == owner()) { // the left features are created later (except subs of composite) aMePassed = true; continue; } - if (isGroup) aMePassed = false; + //if (isGroup) aMePassed = false; bool isInScope = !aMePassed; if (!isInScope && aComposite.get()) { // try to add sub-elements of composite if this is composite @@ -530,6 +639,10 @@ void Model_AttributeSelection::split( bool Model_AttributeSelection::update() { + FeaturePtr aContextFeature = contextFeature(); + if (aContextFeature.get()) { + return true; + } TDF_Label aSelLab = selectionLabel(); ResultPtr aContext = context(); if (!aContext.get()) @@ -549,6 +662,28 @@ bool Model_AttributeSelection::update() } if (aContext->groupName() == ModelAPI_ResultBody::group()) { + if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used + Handle(TDataStd_Integer) aWeakId; + aSelLab.FindAttribute(kWEAK_NAMING, aWeakId); + // get the context shape + GeomShapePtr aContextShape; + ResultBodyPtr aBody = std::dynamic_pointer_cast(aContext); + if (aBody.get()) { + aContextShape = aBody->shape(); + } else { + ResultPtr aResult = std::dynamic_pointer_cast(myRef.value()); + if (aResult) { + aContextShape = aResult->shape(); + } + } + if (!setInvalidIfFalse(aSelLab, aContextShape.get() != NULL)) // context shape not found + return false; + Handle(TDataStd_Integer) aWeakShapeType; + aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType); + GeomAlgoAPI_NExplode aNExplode(aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get())); + GeomShapePtr aValue = aNExplode.shape(aWeakId->Get()); + return setInvalidIfFalse(aSelLab, aValue.get() != NULL); + } // body: just a named shape, use selection mechanism from OCCT TNaming_Selector aSelector(aSelLab); TopoDS_Shape anOldShape; @@ -666,8 +801,10 @@ void Model_AttributeSelection::selectBody( } 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); + // the main result (which is may be modified); the case is in 1799 + ResultBodyPtr aMain = ModelAPI_Tools::bodyOwner(theContext); + while(ModelAPI_Tools::bodyOwner(aMain).get()) + aMain = ModelAPI_Tools::bodyOwner(theContext); if (aMain.get()) { selectBody(aMain, theSubShape); return; @@ -688,7 +825,38 @@ void Model_AttributeSelection::selectBody( if (aEraseResults) // erase results without flash deleted and redisplay: do it after Select aFeatureOwner->removeResults(0, false, false); } - aSel.Select(aNewSub, aNewContext); + bool aSelectorOk = true; + try { + aSel.Select(aNewSub, aNewContext); + } catch(...) { + aSelectorOk = false; + } + // face may become divided after the model update, so, new labels may be added to the scope + myScope.Clear(); + + // check that selection is correct, otherwise use weak naming solution + TDF_Label aSelLab = selectionLabel(); + aSelLab.ForgetAttribute(kWEAK_NAMING); + Handle(TNaming_NamedShape) aSelectorShape; + if (aSelectorOk && aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelectorShape)) + { + TopoDS_Shape aShape = aSelectorShape->Get(); + if (aShape.IsNull() || aShape.ShapeType() != aNewSub.ShapeType()) + aSelectorOk = false; + } + if (!aSelectorOk) { // weak naming identifier instead + GeomShapePtr aContextShape(new GeomAPI_Shape); + aContextShape->setImpl(new TopoDS_Shape(aNewContext)); + GeomShapePtr aValueShape(new GeomAPI_Shape); + aValueShape->setImpl(new TopoDS_Shape(aNewSub)); + + GeomAlgoAPI_NExplode aNExplode(aContextShape, aValueShape->shapeType()); + int anId = aNExplode.index(aValueShape); + if (anId) { + TDataStd_Integer::Set(aSelLab, kWEAK_NAMING, anId); + TDataStd_Integer::Set(aSelLab, kWEAK_NAMING_SHAPETYPE, int(aValueShape->shapeType())); + } + } if (aEraseResults) { // flash after Select : in Groups it makes selection with shift working static Events_Loop* aLoop = Events_Loop::loop(); @@ -765,10 +933,26 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa 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(); + Handle(TDataStd_Integer) aWeakId; + if (aSelLab.FindAttribute(kWEAK_NAMING, aWeakId)) { // a weak naming is used + std::ostringstream aNameStream; + aNameStream<data()->name()<<"/weak_name_"<Get(); + return aNameStream.str(); + } - Model_SelectionNaming aSelNaming(selectionLabel()); + Model_SelectionNaming aSelNaming(aSelLab); std::string aResult = aSelNaming.namingName( aCont, aSubSh, theDefaultName, owner()->document() != aCont->document()); if (aCenterType != NOT_CENTER) { @@ -837,9 +1021,21 @@ void Model_AttributeSelection::selectSubShape( } } - Model_SelectionNaming aSelNaming(selectionLabel()); std::shared_ptr aDoc = std::dynamic_pointer_cast(owner()->document()); + // check this is a whole feature context + if (aSubShapeName.size() > kWHOLE_FEATURE.size() && + aSubShapeName.substr(0, kWHOLE_FEATURE.size()) == kWHOLE_FEATURE) { + std::string aFeatureName = aSubShapeName.substr(kWHOLE_FEATURE.size()); + ObjectPtr anObj = aDoc->objectByName(ModelAPI_Feature::group(), aFeatureName); + if (anObj.get()) { + static const GeomShapePtr anEmptyShape; + setValue(anObj, anEmptyShape); + return; + } + } + + Model_SelectionNaming aSelNaming(selectionLabel()); std::shared_ptr aShapeToBeSelected; ResultPtr aCont; if (aSelNaming.selectSubShape(aType, aSubShapeName, aDoc, aShapeToBeSelected, aCont)) { @@ -853,9 +1049,14 @@ void Model_AttributeSelection::selectSubShape( aNS = TNaming_Tool::CurrentNamedShape(aNS); if (!aNS.IsNull() && scope().Contains(aNS->Label())) { // scope check is for 2228 TDF_Label aLab = aNS->Label(); - while(aLab.Depth() != 7 && aLab.Depth() > 5) + 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) @@ -867,11 +1068,15 @@ void Model_AttributeSelection::selectSubShape( } // if compsolid is context, try to take sub-solid as context: like in GUI and scripts if (aCont.get() && aShapeToBeSelected.get()) { - ResultCompSolidPtr aComp = std::dynamic_pointer_cast(aCont); + ResultBodyPtr aComp = std::dynamic_pointer_cast(aCont); if (aComp && aComp->numberOfSubs()) { - for(int aSubNum = 0; aSubNum < aComp->numberOfSubs(); aSubNum++) { - ResultPtr aSub = aComp->subResult(aSubNum); - if (aSub && aSub->shape().get() && aSub->shape()->isSubShape(aShapeToBeSelected)) { + 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; } @@ -881,47 +1086,57 @@ void Model_AttributeSelection::selectSubShape( // try to find the latest active result that must be used instead of the selected // to set the active context (like in GUI selection), not concealed one bool aFindNewContext = true; - while(aFindNewContext && aCont.get() && aShapeToBeSelected.get()) { + while(aFindNewContext && aCont.get()) { aFindNewContext = false; - const std::set& aRefs = aCont->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())) + // take references to all results: root one, any sub + ResultBodyPtr aCompContext = ModelAPI_Tools::bodyOwner(aCont, true); + std::list allRes; + if (aCompContext.get()) { + ModelAPI_Tools::allSubs(aCompContext, allRes); + allRes.push_back(aCompContext); + } else { + allRes.push_back(aCont); + } + for(std::list::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) { + ResultPtr aResCont = *aSub; + ResultBodyPtr aResBody = std::dynamic_pointer_cast(aResCont); + // only lower and higher level subs are counted + if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext) continue; - // search the feature result that contains sub-shape selected - std::list > aResults; - - // take all sub-results or one result - const std::list >& aFResults = aRefFeat->results(); - std::list >::const_iterator aRIter = aFResults.begin(); - for (; aRIter != aFResults.cend(); aRIter++) { - // iterate sub-bodies of compsolid - ResultCompSolidPtr aComp = std::dynamic_pointer_cast(*aRIter); - if (aComp.get() && aComp->numberOfSubs() > 0) { - int aNumSub = aComp->numberOfSubs(); - for(int a = 0; a < aNumSub; a++) { - aResults.push_back(aComp->subResult(a)); - } - } else { - aResults.push_back(*aRIter); - } - } - std::list >::iterator aResIter = aResults.begin(); - for(; aResIter != aResults.end(); aResIter++) { - if (!aResIter->get() || !(*aResIter)->data()->isValid() || (*aResIter)->isDisabled()) + 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; - GeomShapePtr aShape = (*aResIter)->shape(); - if (aShape.get() && aShape->isSubShape(aShapeToBeSelected, false)) { - aCont = *aResIter; // found new context (produced from this) with same subshape - //if (!aShape->isSubShape(aShapeToBeSelected, true)) // take context orientation - // aShapeToBeSelected->setOrientation(); - aFindNewContext = true; // continue searching futher - break; + // 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; + } } } } @@ -943,21 +1158,133 @@ void Model_AttributeSelection::selectSubShape( 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(); + setInvalidIfFalse(aSelLab, false); + 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()); @@ -977,21 +1304,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()) { @@ -1009,7 +1336,7 @@ void Model_AttributeSelection::setId(int theID) aSelection = aResult; } - setValue(aContext, aSelection); + setValue(aContextRes, aSelection); } std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const @@ -1057,10 +1384,16 @@ void Model_AttributeSelection::computeValues( // if new context becomes compsolid, the resulting sub may be in sub-solids std::list aNewToIterate; aNewToIterate.push_back(theNewContext); - ResultCompSolidPtr aComp = std::dynamic_pointer_cast(theNewContext); + ResultBodyPtr aComp = std::dynamic_pointer_cast(theNewContext); if (aComp.get()) { - for(int a = 0; a < aComp->numberOfSubs(); a++) - aNewToIterate.push_back(aComp->subResult(a, false)); + 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) @@ -1145,7 +1478,7 @@ bool Model_AttributeSelection::searchNewContext(std::shared_ptr TopTools_ListOfShape aContextList; aContextList.Append(theContShape); if (theContext.get()) { - ResultPtr aComposite = ModelAPI_Tools::compSolidOwner(theContext); + ResultPtr aComposite = ModelAPI_Tools::bodyOwner(theContext); if (aComposite.get() && aComposite->shape().get() && !aComposite->shape()->isNull()) aContextList.Append(aComposite->shape()->impl()); } @@ -1324,6 +1657,24 @@ void Model_AttributeSelection::updateInHistory() 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); } } @@ -1334,3 +1685,8 @@ void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent { myParent = theParent; } + +bool Model_AttributeSelection::isWeakNaming() +{ + return selectionLabel().IsAttribute(kWEAK_NAMING); +}