+
+void Model_AttributeSelection::setId(int theID)
+{
+ std::shared_ptr<GeomAPI_Shape> aSelection;
+
+ ResultPtr aContextRes = context();
+ // support for compsolids:
+ while(ModelAPI_Tools::bodyOwner(aContextRes).get()) {
+ aContextRes = ModelAPI_Tools::bodyOwner(aContextRes);
+ }
+ std::shared_ptr<GeomAPI_Shape> aContext = aContextRes->shape();
+
+ TopoDS_Shape aMainShape = aContext->impl<TopoDS_Shape>();
+ // searching for the latest main shape
+ if (theID > 0 && aContext && !aContext->isNull())
+ {
+ std::shared_ptr<Model_Document> aDoc =
+ std::dynamic_pointer_cast<Model_Document>(aContextRes->document());
+ if (aDoc.get()) {
+ Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
+ if (!aNS.IsNull()) {
+ aMainShape = TNaming_Tool::CurrentShape(aNS);
+ }
+ }
+
+ TopTools_IndexedMapOfShape aSubShapesMap;
+ TopExp::MapShapes(aMainShape, aSubShapesMap);
+ const TopoDS_Shape& aSelShape = aSubShapesMap.FindKey(theID);
+
+ std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
+ aResult->setImpl(new TopoDS_Shape(aSelShape));
+
+ aSelection = aResult;
+ }
+
+ setValue(aContextRes, aSelection);
+}
+
+std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const
+{
+ std::string aResult;
+ if (owner()->document() != theContext->document()) {
+ if (theContext->document() == ModelAPI_Session::get()->moduleDocument()) {
+ aResult = theContext->document()->kind() + "/";
+ } else {
+ ResultPtr aDocRes = ModelAPI_Tools::findPartResult(
+ ModelAPI_Session::get()->moduleDocument(), theContext->document());
+ if (aDocRes.get()) {
+ aResult = aDocRes->data()->name() + "/";
+ }
+ }
+ }
+ aResult += theContext->data()->name();
+ 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>();
+ }
+ //TopoDS_Shape anOldContShape = theOldContext->shape()->impl<TopoDS_Shape>();
+ TopoDS_Shape aNewContShape = theNewContext->shape()->impl<TopoDS_Shape>();
+ //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<ResultPtr> aNewToIterate;
+ aNewToIterate.push_back(theNewContext);
+ ResultBodyPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theNewContext);
+ if (aComp.get()) {
+ std::list<ResultPtr> allNewContextSubs;
+ ModelAPI_Tools::allSubs(aComp, allNewContextSubs);
+ std::list<ResultPtr>::iterator aSub = allNewContextSubs.begin();
+ for(; aSub != allNewContextSubs.end(); aSub++) {
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*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<ResultPtr>::iterator aNewContIter = aNewToIterate.begin();
+ for(; aNewContIter != aNewToIterate.end(); aNewContIter++) {
+ std::shared_ptr<Model_Data> aNewData =
+ std::dynamic_pointer_cast<Model_Data>((*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<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher> 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<TopoDS_Shape, TopTools_MapOfShape, TopTools_ShapeMapHasher>::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<Model_Document> theDoc,
+ const TopoDS_Shape theContShape, ResultPtr theContext, TopoDS_Shape theValShape,
+ TDF_Label theAccessLabel,
+ std::list<ResultPtr>& theResults, TopTools_ListOfShape& theValShapes)
+{
+ std::set<ResultPtr> 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<TopoDS_Shape>());
+ }
+ 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<ModelAPI_Result>
+ (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<ModelAPI_Result>
+ (theDoc->objects()->object(anObjLab.Father()));
+ if (!aModifierObj.get())
+ continue;
+ }
+ FeaturePtr aModifierFeat = theDoc->feature(aModifierObj);
+ if (!aModifierFeat.get())
+ continue;
+ FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(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<TopoDS_Shape>());
+ } 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<ResultPtr>::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<ResultPtr> aNewRes;
+ TopTools_ListOfShape aNewUpdatedVal;
+ TopoDS_Shape aNewValSh = aNewVal.Value();
+ TopoDS_Shape aNewContShape = (*aResIter)->shape()->impl<TopoDS_Shape>();
+ 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<ResultPtr>::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<ModelAPI_Result>(myRef.value());
+ // only bodies and parts may be modified later in the history, don't do anything otherwise
+ if (!aContext.get() || (aContext->groupName() != ModelAPI_ResultBody::group() &&
+ aContext->groupName() != ModelAPI_ResultPart::group()))
+ return;
+ std::shared_ptr<Model_Document> aDoc =
+ std::dynamic_pointer_cast<Model_Document>(aContext->document());
+ std::shared_ptr<Model_Data> aContData = std::dynamic_pointer_cast<Model_Data>(aContext->data());
+ if (!aContData.get() || !aContData->isValid())
+ return;
+ TDF_Label aContLab = aContData->shapeLab(); // named shape where the selected context is located
+ Handle(TNaming_NamedShape) 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<ModelAPI_ResultPart>(aNewContext);
+ if (aPartContext.get()) { // searching for the up to date references to the referenced cont
+ const std::set<AttributePtr>& aRefs = aPartContext->data()->refsToMe();
+ std::set<AttributePtr>::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<ModelAPI_AttributeSelection>(*aRef);
+ if (aSel.get() && !aSel->value()->isSame(aSel->context()->shape()))
+ continue;
+
+ FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
+ if (aRefFeat.get() && aRefFeat != owner()) {
+ FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+ if (!aDoc->isLaterByDep(aRefFeat, aThisFeature)) { // found better feature
+ aFoundNewContext = true;
+ aNewContext = aRefFeat->firstResult();
+ }
+ }
+ }
+ }
+ }
+ }
+ if (aNewContext != aContext) {
+ setValue(aNewContext, value());
+ }
+ return;
+ }
+ FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+ FeaturePtr aCurrentModifierFeat = aDoc->feature(aContext);
+ // iterate the context shape modifications in order to find a feature that is upper in history
+ // that this one and is really modifies the referenced result to refer to it
+ ResultPtr aModifierResFound;
+ TNaming_Iterator aPairIter(aContNS);
+ if (!aPairIter.More())
+ return;
+ TopoDS_Shape aNewCShape = aPairIter.NewShape();
+ bool anIterate = true;
+ // trying to update also the sub-shape selected
+ GeomShapePtr aSubShape = value();
+ if (aSubShape.get() && aSubShape->isEqual(aContext->shape()))
+ aSubShape.reset();
+ TopoDS_Shape aValShape;
+ if (aSubShape.get()) {
+ aValShape = aSubShape->impl<TopoDS_Shape>();
+ }
+
+ std::list<ResultPtr> aNewContexts;
+ TopTools_ListOfShape aValShapes;
+ if (searchNewContext(aDoc, aNewCShape, aContext, aValShape, aContLab, aNewContexts, aValShapes))
+ {
+ std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
+ TopTools_ListIteratorOfListOfShape aNewValues(aValShapes);
+ if (aNewCont == aNewContexts.end()) { // all results were deleted
+ ResultPtr anEmptyContext;
+ std::shared_ptr<GeomAPI_Shape> anEmptyShape;
+ setValue(anEmptyContext, anEmptyShape); // nullify the selection
+ return;
+ }
+
+ GeomShapePtr aValueShape;
+ if (!aNewValues.Value().IsNull()) {
+ aValueShape = std::make_shared<GeomAPI_Shape>();
+ aValueShape->setImpl<TopoDS_Shape>(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<GeomAPI_Shape>();
+ aValueShape->setImpl<TopoDS_Shape>(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);
+ }
+ }
+ }
+}
+
+void Model_AttributeSelection::setParent(Model_AttributeSelectionList* theParent)
+{
+ myParent = theParent;
+}
+
+std::string Model_AttributeSelection::contextName(const TDF_Label theSelectionLab)
+{
+ std::shared_ptr<Model_Document> aDoc = myRestoreDocument.get() ? myRestoreDocument :
+ std::dynamic_pointer_cast<Model_Document>(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<Model_Document> aDoc = myRestoreDocument.get() ? myRestoreDocument :
+ std::dynamic_pointer_cast<Model_Document>(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<ModelAPI_CompositeFeature>(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<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
+ std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
+ for (; aRes != aResults.cend() && theValue.IsNull(); aRes++) {
+ if ((*aRes)->data()->name() == aCompName) {
+ theValue = std::dynamic_pointer_cast<Model_Data>((*aRes)->data())->shapeLab();
+ break;
+ } else if (aCompName.find((*aRes)->data()->name()) != std::string::npos) {// sub-vertex
+ TDF_Label aLab = std::dynamic_pointer_cast<Model_Data>((*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<TopoDS_Shape>();
+ 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<ModelAPI_Result>(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<ResultPtr> 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<ResultPtr>::iterator aSub = allRes.begin(); aSub != allRes.end(); aSub++) {
+ ResultPtr aResCont = *aSub;
+ ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResCont);
+ if (aResBody.get() && aResBody->numberOfSubs() > 0 && aResBody != aCompContext)
+ continue; // only lower and higher level subs are counted
+ const std::set<AttributePtr>& aRefs = aResCont->data()->refsToMe();
+ std::set<AttributePtr>::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<ModelAPI_Feature>((*aRef)->owner());
+ if (!ModelAPI_Session::get()->validators()->isConcealed(
+ aRefFeat->getKind(), (*aRef)->id()))
+ continue;
+ // search the feature result that contains sub-shape selected
+ std::list<std::shared_ptr<ModelAPI_Result> > aResults;
+
+ // take all sub-results or one result
+ std::list<ResultPtr> aRefFeatResults;
+ ModelAPI_Tools::allResults(aRefFeat, aRefFeatResults);
+ std::list<ResultPtr>::iterator aRefResIter = aRefFeatResults.begin();
+ for(; aRefResIter != aRefFeatResults.end(); aRefResIter++) {
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRefResIter);
+ if (aBody.get() && aBody->numberOfSubs() == 0) // add only lower level subs
+ aResults.push_back(aBody);
+ }
+ std::list<std::shared_ptr<ModelAPI_Result> >::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<ModelAPI_ResultBody>(aCont);
+ if (aComp && aComp->numberOfSubs()) {
+ std::list<ResultPtr> allSubs;
+ ModelAPI_Tools::allSubs(aComp, allSubs);
+ std::list<ResultPtr>::iterator aS = allSubs.begin();
+ for (; aS != allSubs.end(); aS++) {
+ ResultBodyPtr aSub = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aS);
+ if (aSub && aSub->numberOfSubs() == 0 && aSub->shape().get() &&
+ aSub->shape()->isSubShape(aShapeToBeSelected)) {
+ aCont = aSub;
+ break;
+ }
+ }
+ }
+ */
+ if (aCont.get()) {
+ theContext = std::dynamic_pointer_cast<Model_Data>(aCont->data())->label();
+ }
+ return true;
+}
+
+bool Model_AttributeSelection::isLater(
+ const TDF_Label theResult1, const TDF_Label theResult2) const
+{
+ std::shared_ptr<Model_Document> aDoc = myRestoreDocument.get() ? myRestoreDocument :
+ std::dynamic_pointer_cast<Model_Document>(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);
+}