]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_AttributeSelection.cpp
Salome HOME
Fix compilation errors on CentOS
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_AttributeSelection.cpp
4 // Created:     2 Oct 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include "Model_AttributeSelection.h"
8 #include "Model_Application.h"
9 #include "Model_Events.h"
10 #include "Model_Data.h"
11 #include "Model_Document.h"
12 #include "Model_SelectionNaming.h"
13 #include <ModelAPI_Feature.h>
14 #include <ModelAPI_ResultBody.h>
15 #include <ModelAPI_ResultConstruction.h>
16 #include <ModelAPI_ResultPart.h>
17 #include <ModelAPI_CompositeFeature.h>
18 #include <ModelAPI_Tools.h>
19 #include <GeomAPI_Shape.h>
20 #include <GeomAPI_PlanarEdges.h>
21 #include <Events_InfoMessage.h>
22
23 #include <TNaming_Selector.hxx>
24 #include <TNaming_NamedShape.hxx>
25 #include <TNaming_Tool.hxx>
26 #include <TNaming_Builder.hxx>
27 #include <TNaming_Localizer.hxx>
28 #include <TopoDS_Shape.hxx>
29 #include <TopoDS_Compound.hxx>
30 #include <TDataStd_IntPackedMap.hxx>
31 #include <TDataStd_Integer.hxx>
32 #include <TDataStd_UAttribute.hxx>
33 #include <TDataStd_Name.hxx>
34 #include <TopTools_MapOfShape.hxx>
35 #include <TopTools_IndexedMapOfShape.hxx>
36 #include <TopTools_MapIteratorOfMapOfShape.hxx>
37 #include <TopTools_ListOfShape.hxx>
38 #include <NCollection_DataMap.hxx>
39 #include <TopExp_Explorer.hxx>
40 #include <TDF_LabelMap.hxx>
41 #include <BRep_Tool.hxx>
42 #include <BRep_Builder.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS.hxx>
45 #include <TopExp.hxx>
46 #include <TColStd_MapOfTransient.hxx>
47 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
48 #include <TopTools_ListIteratorOfListOfShape.hxx>
49 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
50 #include <gp_Pnt.hxx>
51 #include <Precision.hxx>
52 #include <TDF_ChildIterator.hxx>
53 #include <TDF_ChildIDIterator.hxx>
54 #include <TDataStd_Name.hxx>
55 #include <TopAbs_ShapeEnum.hxx>
56 #include <TopoDS_Iterator.hxx>
57 #include <TNaming_Iterator.hxx>
58 #include <BRep_Builder.hxx>
59 #include <ModelAPI_Session.h>
60
61 using namespace std;
62 //#define DEB_NAMING 1
63 #ifdef DEB_NAMING
64 #include <BRepTools.hxx>
65 #endif
66 /// added to the index in the packed map to signalize that the vertex of edge is selected
67 /// (multiplied by the index of the edge)
68 static const int kSTART_VERTEX_DELTA = 1000000;
69 // identifier that there is simple reference: selection equals to context
70 Standard_GUID kSIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb29");
71 // simple reference in the construction
72 Standard_GUID kCONSTUCTION_SIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb28");
73 // reference to Part sub-object
74 Standard_GUID kPART_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb27");
75 // selection is invalid after recomputation
76 Standard_GUID kINVALID_SELECTION("bce47fd7-80fa-4462-9d63-2f58acddd49d");
77
78 // on this label is stored:
79 // TNaming_NamedShape - selected shape
80 // TNaming_Naming - topological selection information (for the body)
81 // TDataStd_IntPackedMap - indexes of edges in composite element (for construction)
82 // TDataStd_Integer - type of the selected shape (for construction)
83 // TDF_Reference - from ReferenceAttribute, the context
84 void Model_AttributeSelection::setValue(const ResultPtr& theContext,
85   const std::shared_ptr<GeomAPI_Shape>& theSubShape, const bool theTemporarily)
86 {
87   if (theTemporarily) { // just keep the stored without DF update
88     myTmpContext = theContext;
89     myTmpSubShape = theSubShape;
90     owner()->data()->sendAttributeUpdated(this);
91     return;
92   } else {
93     myTmpContext.reset();
94     myTmpSubShape.reset();
95   }
96
97   const std::shared_ptr<GeomAPI_Shape>& anOldShape = value();
98   bool isOldContext = theContext == myRef.value();
99   bool isOldShape = isOldContext &&
100     (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
101   if (isOldShape) return; // shape is the same, so context is also unchanged
102   // update the referenced object if needed
103   if (!isOldContext) {
104       myRef.setValue(theContext);
105   }
106
107   // do noth use naming if selected shape is result shape itself, but not sub-shape
108   TDF_Label aSelLab = selectionLabel();
109   aSelLab.ForgetAttribute(kSIMPLE_REF_ID);
110   aSelLab.ForgetAttribute(kCONSTUCTION_SIMPLE_REF_ID);
111   aSelLab.ForgetAttribute(kINVALID_SELECTION);
112
113   bool isDegeneratedEdge = false;
114   // do not use the degenerated edge as a shape, a null context and shape is used in the case
115   if (theSubShape.get() && !theSubShape->isNull() && theSubShape->isEdge()) {
116     const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
117     if (aSubShape.ShapeType() == TopAbs_EDGE)
118       isDegeneratedEdge = BRep_Tool::Degenerated(TopoDS::Edge(aSubShape)) == Standard_True;
119   }
120   if (!theContext.get() || isDegeneratedEdge) {
121     // to keep the reference attribute label
122     TDF_Label aRefLab = myRef.myRef->Label();
123     aSelLab.ForgetAllAttributes(true);
124     myRef.myRef = TDF_Reference::Set(aSelLab.Father(), aSelLab.Father());
125     return;
126   }
127   if (theContext->groupName() == ModelAPI_ResultBody::group()) {
128     // do not select the whole shape for body:it is already must be in the data framework
129     // equal and null selected objects mean the same: object is equal to context,
130     if (theContext->shape().get() && 
131         (theContext->shape()->isEqual(theSubShape) || !theSubShape.get())) {
132       aSelLab.ForgetAllAttributes(true);
133       TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID);
134     } else {
135       selectBody(theContext, theSubShape);
136     }
137   } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) {
138     if (!theSubShape.get()) {
139       // to sub, so the whole result is selected
140       aSelLab.ForgetAllAttributes(true);
141       TDataStd_UAttribute::Set(aSelLab, kCONSTUCTION_SIMPLE_REF_ID);
142       ResultConstructionPtr aConstruction = 
143         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theContext);
144       if (aConstruction->isInfinite()) {
145         // For correct naming selection, put the shape into the naming structure.
146         // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
147         TNaming_Builder aBuilder(aSelLab);
148         aBuilder.Generated(theContext->shape()->impl<TopoDS_Shape>());
149         std::shared_ptr<Model_Document> aMyDoc = 
150           std::dynamic_pointer_cast<Model_Document>(owner()->document());
151         std::string aName = contextName(theContext);
152         // for selection in different document, add the document name
153         aMyDoc->addNamingName(aSelLab, aName);
154         TDataStd_Name::Set(aSelLab, aName.c_str());
155       } else {  // for sketch the naming is needed in DS
156         BRep_Builder aCompoundBuilder;
157         TopoDS_Compound aComp;
158         aCompoundBuilder.MakeCompound(aComp);
159         for(int a = 0; a < aConstruction->facesNum(); a++) {
160           TopoDS_Shape aFace = aConstruction->face(a)->impl<TopoDS_Shape>();
161           aCompoundBuilder.Add(aComp, aFace);
162         }
163         std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
164         aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aComp));
165         selectConstruction(theContext, aShape);
166       }
167     } else {
168       selectConstruction(theContext, theSubShape);
169     }
170   } else if (theContext->groupName() == ModelAPI_ResultPart::group()) {
171     aSelLab.ForgetAllAttributes(true);
172     TDataStd_UAttribute::Set(aSelLab, kPART_REF_ID);
173     selectPart(theContext, theSubShape);
174   }
175   //the attribute initialized state should be changed by sendAttributeUpdated only
176   //myIsInitialized = true;
177
178   owner()->data()->sendAttributeUpdated(this);
179
180   std::string aSelName = namingName();
181   if(!aSelName.empty())
182     TDataStd_Name::Set(selectionLabel(), aSelName.c_str()); //set name
183 }
184
185 std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
186 {
187   GeomShapePtr aResult;
188   if (myTmpContext.get() || myTmpSubShape.get()) {
189     ResultConstructionPtr aResulConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myTmpContext);
190     if(aResulConstruction.get()) {
191       // it is just reference to construction.
192       return myTmpSubShape;
193     }
194     return myTmpSubShape.get() ? myTmpSubShape : myTmpContext->shape();
195   }
196
197   TDF_Label aSelLab = selectionLabel();
198   if (aSelLab.IsAttribute(kINVALID_SELECTION))
199     return aResult;
200
201   if (myRef.isInitialized()) {
202     if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
203       ResultPtr aContext = context();
204       if (!aContext.get()) 
205         return aResult; // empty result
206       return aContext->shape();
207     }
208     if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { // it is just reference to construction, nothing is in value
209         return aResult; // empty result
210     }
211     if (aSelLab.IsAttribute(kPART_REF_ID)) {
212       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(context());
213       if (!aPart.get() || !aPart->isActivated())
214         return std::shared_ptr<GeomAPI_Shape>(); // postponed naming needed
215       Handle(TDataStd_Integer) anIndex;
216       if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) {
217         if (anIndex->Get()) { // special selection attribute was created, use it
218           return aPart->selectionValue(anIndex->Get());
219         } else { // face with name is already in the data model, so try to take it by name
220           Handle(TDataStd_Name) aName;
221           if (selectionLabel().FindAttribute(TDataStd_Name::GetID(), aName)) {
222             std::string aSubShapeName(TCollection_AsciiString(aName->Get()).ToCString());
223             std::size_t aPartEnd = aSubShapeName.find('/');
224             if (aPartEnd != string::npos && aPartEnd != aSubShapeName.rfind('/')) {
225               string aNameInPart = aSubShapeName.substr(aPartEnd + 1);
226               int anIndex;
227               std::string aType; // to reuse already existing selection the type is not needed
228               return aPart->shapeInPart(aNameInPart, aType, anIndex);
229             }
230           }
231         }
232       }
233     }
234
235     Handle(TNaming_NamedShape) aSelection;
236     if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
237       TopoDS_Shape aSelShape = aSelection->Get();
238       aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
239       aResult->setImpl(new TopoDS_Shape(aSelShape));
240     } else { // for simple construction element: just shape of this construction element
241       ResultConstructionPtr aConstr = 
242         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(context());
243       if (aConstr) {
244         return aConstr->shape();
245       }
246     }
247   }
248   return aResult;
249 }
250
251 bool Model_AttributeSelection::isInvalid()
252 {
253   return selectionLabel().IsAttribute(kINVALID_SELECTION) == Standard_True;
254 }
255
256 bool Model_AttributeSelection::isInitialized()
257 {
258   if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized
259     std::shared_ptr<GeomAPI_Shape> aResult;
260     if (myRef.isInitialized()) {
261       TDF_Label aSelLab = selectionLabel();
262       if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
263         ResultPtr aContext = context();
264         return aContext.get() != NULL;
265       }
266       if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { // it is just reference to construction, nothing is in value
267           return true;
268       }
269
270       Handle(TNaming_NamedShape) aSelection;
271       if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
272         return !aSelection->Get().IsNull();
273       } else { // for simple construction element: just shape of this construction element
274         ResultConstructionPtr aConstr = 
275           std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(context());
276         if (aConstr.get()) {
277           return aConstr->shape().get() != NULL;
278         }
279       }
280     }
281   }
282   return false;
283 }
284
285 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
286   : myRef(theLabel)
287 {
288   myIsInitialized = myRef.isInitialized();
289 }
290
291 void Model_AttributeSelection::setID(const std::string theID)
292 {
293   myRef.setID(theID);
294   ModelAPI_AttributeSelection::setID(theID);
295 }
296
297 ResultPtr Model_AttributeSelection::context() {
298   if (myTmpContext.get() || myTmpSubShape.get()) {
299     return myTmpContext;
300   }
301
302   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
303   // for parts there could be same-data result, so take the last enabled
304   if (aResult.get() && aResult->groupName() == ModelAPI_ResultPart::group()) {
305     int aSize = aResult->document()->size(ModelAPI_ResultPart::group());
306     for(int a = aSize - 1; a >= 0; a--) {
307       ObjectPtr aPart = aResult->document()->object(ModelAPI_ResultPart::group(), a);
308       if (aPart.get() && aPart->data() == aResult->data()) {
309         ResultPtr aPartResult = std::dynamic_pointer_cast<ModelAPI_Result>(aPart);
310         FeaturePtr anOwnerFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
311         // check that this result is not this-feature result (it is forbidden t oselect itself)
312         if (anOwnerFeature.get() && anOwnerFeature->firstResult() != aPartResult) {
313           return aPartResult;
314         }
315       }
316     }
317   }
318   return aResult;
319 }
320
321
322 void Model_AttributeSelection::setObject(const std::shared_ptr<ModelAPI_Object>& theObject)
323 {
324   ModelAPI_AttributeSelection::setObject(theObject);
325   myRef.setObject(theObject);
326 }
327
328 TDF_LabelMap& Model_AttributeSelection::scope()
329 {
330   if (myScope.IsEmpty()) { // create a new scope if not yet done
331     // gets all features with named shapes that are before this feature label (before in history)
332     DocumentPtr aMyDoc = owner()->document();
333     std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures = aMyDoc->allFeatures();
334     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator aFIter = allFeatures.begin();
335     bool aMePassed = false;
336     CompositeFeaturePtr aComposite = 
337       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(owner());
338     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
339     CompositeFeaturePtr aCompositeOwner, aCompositeOwnerOwner;
340     if (aFeature.get()) {
341       aCompositeOwner = ModelAPI_Tools::compositeOwner(aFeature);
342       if (aCompositeOwner.get()) {
343          aCompositeOwnerOwner = ModelAPI_Tools::compositeOwner(aCompositeOwner);
344       }
345     }
346     // for group Scope is not limitet: this is always up to date objects
347     bool isGroup = aFeature.get() && aFeature->getKind() == "Group";
348     for(; aFIter != allFeatures.end(); aFIter++) {
349       if (*aFIter == owner()) {  // the left features are created later (except subs of composite)
350         aMePassed = true;
351         continue;
352       }
353       if (isGroup) aMePassed = false;
354       bool isInScope = !aMePassed;
355       if (!isInScope && aComposite.get()) { // try to add sub-elements of composite if this is composite
356         if (aComposite->isSub(*aFIter))
357           isInScope = true;
358       }
359       // remove the composite-owner of this feature (sketch in extrusion-cut)
360       if (isInScope && (aCompositeOwner == *aFIter || aCompositeOwnerOwner == *aFIter))
361         isInScope = false;
362
363       if (isInScope && aFIter->get() && (*aFIter)->data()->isValid()) {
364         TDF_Label aFeatureLab = std::dynamic_pointer_cast<Model_Data>(
365           (*aFIter)->data())->label().Father();
366         TDF_ChildIDIterator aNSIter(aFeatureLab, TNaming_NamedShape::GetID(), 1);
367         for(; aNSIter.More(); aNSIter.Next()) {
368           Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value());
369           if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) {
370             myScope.Add(aNS->Label());
371           }
372         }
373       }
374     }
375   }
376   return myScope;
377 }
378
379 /// Sets the invalid flag if flag is false, or removes it if "true"
380 /// Returns theFlag
381 static bool setInvalidIfFalse(TDF_Label& theLab, const bool theFlag) {
382   if (theFlag) {
383     theLab.ForgetAttribute(kINVALID_SELECTION);
384   } else {
385     TDataStd_UAttribute::Set(theLab, kINVALID_SELECTION);
386   }
387   return theFlag;
388 }
389
390 bool Model_AttributeSelection::update()
391 {
392   TDF_Label aSelLab = selectionLabel();
393   ResultPtr aContext = context();
394   if (!aContext.get()) 
395     return setInvalidIfFalse(aSelLab, false);
396   if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
397     return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull());
398   }
399   if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { // it is just reference to construction, not sub-shape
400     // if there is a sketch, the sketch-naming must be updated
401     ResultConstructionPtr aConstruction = 
402       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
403     if (!aConstruction->isInfinite()) {
404       BRep_Builder aCompoundBuilder;
405       TopoDS_Compound aComp;
406       aCompoundBuilder.MakeCompound(aComp);
407       for(int a = 0; a < aConstruction->facesNum(); a++) {
408         TopoDS_Shape aFace = aConstruction->face(a)->impl<TopoDS_Shape>();
409         aCompoundBuilder.Add(aComp, aFace);
410       }
411       std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
412       aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aComp));
413       selectConstruction(aContext, aShape);
414     } else {
415       // For correct naming selection, put the shape into the naming structure.
416       // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
417       TNaming_Builder aBuilder(aSelLab);
418       aBuilder.Generated(aContext->shape()->impl<TopoDS_Shape>());
419       std::shared_ptr<Model_Document> aMyDoc = 
420         std::dynamic_pointer_cast<Model_Document>(owner()->document());
421       std::string aName = contextName(aContext);
422       aMyDoc->addNamingName(aSelLab, aName);
423       TDataStd_Name::Set(aSelLab, aName.c_str());
424     }
425     return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull());
426   }
427
428   if (aSelLab.IsAttribute(kPART_REF_ID)) { // it is reference to the part object
429     std::shared_ptr<GeomAPI_Shape> aNoSelection;
430     bool aResult = selectPart(aContext, aNoSelection, true);
431     aResult = setInvalidIfFalse(aSelLab, aResult);
432     if (aResult) {
433       owner()->data()->sendAttributeUpdated(this);
434     }
435     return aResult;
436   }
437
438   if (aContext->groupName() == ModelAPI_ResultBody::group()) {
439     // body: just a named shape, use selection mechanism from OCCT
440     TNaming_Selector aSelector(aSelLab);
441     bool aResult = aSelector.Solve(scope()) == Standard_True;
442     aResult = setInvalidIfFalse(aSelLab, aResult); // must be before sending of updated attribute (1556)
443     owner()->data()->sendAttributeUpdated(this);
444     return aResult;
445   } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
446     // construction: identification by the results indexes, recompute faces and
447     // take the face that more close by the indexes
448     ResultConstructionPtr aConstructionContext = 
449       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
450     FeaturePtr aContextFeature = aContext->document()->feature(aContext);
451     // sketch sub-element
452     if (aConstructionContext && 
453         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature).get())
454     {
455       TDF_Label aLab = myRef.myRef->Label();
456       // getting a type of selected shape
457       Handle(TDataStd_Integer) aTypeAttr;
458       if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
459         return setInvalidIfFalse(aSelLab, false);
460       }
461       TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
462       // selected indexes will be needed in each "if"
463       Handle(TDataStd_IntPackedMap) aSubIds;
464       std::shared_ptr<GeomAPI_Shape> aNewSelected;
465       bool aNoIndexes = 
466         !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
467       // for now working only with composite features
468       CompositeFeaturePtr aComposite = 
469         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
470       if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
471         return setInvalidIfFalse(aSelLab, false);
472       }
473
474       if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) { // compound is for the whole sketch selection
475         // If this is a wire with plane defined then it is a sketch-like object
476         if (!aConstructionContext->facesNum()) // no faces, update can not work correctly
477           return setInvalidIfFalse(aSelLab, false);
478         // if there is no edges indexes, any face can be used: take the first
479         std::shared_ptr<GeomAPI_Shape> aNewSelected;
480         if (aNoIndexes) {
481           aNewSelected = aConstructionContext->face(0);
482         } else { // searching for most looks-like initial face by the indexes
483           // prepare edges of the current result for the fast searching
484           NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
485           const int aSubNum = aComposite->numberOfSubs();
486           for(int a = 0; a < aSubNum; a++) {
487             int aSubID = aComposite->subFeatureId(a);
488             if (aSubIds->Contains(aSubID)) {
489               FeaturePtr aSub = aComposite->subFeature(a);
490               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
491               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
492               for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
493                 ResultConstructionPtr aConstr = 
494                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
495                 if (aConstr->shape() && aConstr->shape()->isEdge()) {
496                   const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
497                   TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
498                   if (!anEdge.IsNull()) {
499                     Standard_Real aFirst, aLast;
500                     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
501                     // searching for orientation information
502                     int anOrient = 0;
503                     Handle(TDataStd_Integer) anInt;
504                     if (aSelLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)){
505                       anOrient = anInt->Get();
506                     }
507                     allCurves.Bind(aCurve, anOrient);
508                   }
509                 }
510               }
511             }
512           }
513           aNewSelected = Model_SelectionNaming::findAppropriateFace(aContext, allCurves);
514         }
515         if (aNewSelected) { // store this new selection
516           if (aShapeType == TopAbs_WIRE) { // just get a wire from face to have wire
517             TopExp_Explorer aWireExp(aNewSelected->impl<TopoDS_Shape>(), TopAbs_WIRE);
518             if (aWireExp.More()) {
519               aNewSelected.reset(new GeomAPI_Shape);
520               aNewSelected->setImpl<TopoDS_Shape>(new TopoDS_Shape(aWireExp.Current()));
521             }
522           }
523           selectConstruction(aContext, aNewSelected);
524           setInvalidIfFalse(aSelLab, true);
525           owner()->data()->sendAttributeUpdated(this);
526           return true;
527         } else { // if the selection is not found, put the empty shape: it's better to have disappeared shape, than the old, the lost one
528           TNaming_Builder anEmptyBuilder(selectionLabel());
529           return setInvalidIfFalse(aSelLab, false);
530         }
531       } else if (aShapeType == TopAbs_EDGE) {
532         // just reselect the edge by the id
533         const int aSubNum = aComposite->numberOfSubs();
534         for(int a = 0; a < aSubNum; a++) {
535           // if aSubIds take any, the first appropriate
536           if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
537             // found the appropriate feature
538             FeaturePtr aFeature = aComposite->subFeature(a);
539             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
540               aFeature->results().cbegin();
541             for(;aResIter != aFeature->results().cend(); aResIter++) {
542               ResultConstructionPtr aRes = 
543                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
544               if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
545                 selectConstruction(aContext, aRes->shape());
546                 setInvalidIfFalse(aSelLab, true);
547                 owner()->data()->sendAttributeUpdated(this);
548                 return true;
549               }
550             }
551           }
552         }
553       } else if (aShapeType == TopAbs_VERTEX) {
554         // just reselect the vertex by the id of edge
555         const int aSubNum = aComposite->numberOfSubs();
556         for(int a = 0; a < aSubNum; a++) {
557           // if aSubIds take any, the first appropriate
558           int aFeatureID = aComposite->subFeatureId(a);
559           if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
560             aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
561             aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
562               // searching for deltas
563               int aVertexNum = 0;
564               if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
565               else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
566               // found the feature with appropriate edge
567               FeaturePtr aFeature = aComposite->subFeature(a);
568               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
569                 aFeature->results().cbegin();
570               for(;aResIter != aFeature->results().cend(); aResIter++) {
571                 ResultConstructionPtr aRes = 
572                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
573                 if (aRes && aRes->shape()) {
574                   if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
575                     selectConstruction(aContext, aRes->shape());
576                     setInvalidIfFalse(aSelLab, true);
577                     owner()->data()->sendAttributeUpdated(this);
578                     return true;
579                   } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
580                     const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
581                     int aVIndex = 1;
582                     for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
583                       if (aVIndex == aVertexNum) { // found!
584                         std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
585                         aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
586                         selectConstruction(aContext, aVertex);
587                         setInvalidIfFalse(aSelLab, true);
588                         owner()->data()->sendAttributeUpdated(this);
589                         return true;
590                       }
591                       aVIndex++;
592                     }
593                   }
594                 }
595               }
596           }
597         }
598       }
599     } else { // simple construction element: the selected is that needed
600       selectConstruction(aContext, aContext->shape());
601       setInvalidIfFalse(aSelLab, true);
602       owner()->data()->sendAttributeUpdated(this);
603       return true;
604     }
605   }
606   return setInvalidIfFalse(aSelLab, false); // unknown case
607 }
608
609
610 void Model_AttributeSelection::selectBody(
611   const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape)
612 {
613   // perform the selection
614   TNaming_Selector aSel(selectionLabel());
615   TopoDS_Shape aContext;
616
617   ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
618   if (aBody) {
619     aContext = aBody->shape()->impl<TopoDS_Shape>();
620   } else {
621     ResultPtr aResult = 
622       std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
623     if (aResult) {
624       aContext = aResult->shape()->impl<TopoDS_Shape>();
625     } else {
626       Events_InfoMessage("Model_AttributeSelection", "A result with shape is expected").send();
627       return;
628     }
629   }
630   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : aContext;
631   /// fix for issue 411: result modified shapes must not participate in this selection mechanism
632   FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
633   if (aFeatureOwner.get())
634     aFeatureOwner->eraseResults();
635   if (!aContext.IsNull()) {
636     aSel.Select(aNewShape, aContext); 
637   }
638 }
639
640 /// registers the name of the shape in the label (theID == 0) of sub label (theID is a tag)
641 /// if theID is zero, 
642 /// theOrientation is additional information about the positioning of edge relatively to face
643 ///    it is stored in the integer attribute of the edge sub-label: 
644 ///    -1 is out, 1 is in, 0 is not needed
645 static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape,
646   const int theID, const FeaturePtr& theContextFeature, std::shared_ptr<Model_Document> theDoc,
647   std::string theAdditionalName, std::map<int, int>& theOrientations,
648   std::map<int, std::string>& theSubNames, // name of sub-elements by ID to be exported instead of indexes
649   Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)(),
650   const int theOrientation = 0)
651 {
652   TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
653   if (theOrientation != 0) { // store the orientation of edge relatively to face if needed
654     TDataStd_Integer::Set(aLab, theOrientation);
655   }
656   TNaming_Builder aBuilder(aLab);
657   aBuilder.Generated(theShape);
658   std::stringstream aName;
659   // add the part name if the selected object is located in other part
660   if (theDoc != theContextFeature->document()) {
661     if (theContextFeature->document() == ModelAPI_Session::get()->moduleDocument()) {
662       aName<<theContextFeature->document()->kind()<<"/";
663     } else {
664       ResultPtr aDocRes = ModelAPI_Tools::findPartResult(
665         ModelAPI_Session::get()->moduleDocument(), theContextFeature->document());
666       if (aDocRes.get()) {
667         aName<<aDocRes->data()->name()<<"/";
668       }
669     }
670   }
671   aName<<theContextFeature->name();
672   if (theShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction
673     aName<<"/";
674     if (!theAdditionalName.empty())
675       aName<<theAdditionalName<<"/";
676     if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face";
677     else if (theShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
678     else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
679     else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
680
681     if (theRefs.IsNull()) {
682       aName<<theID;
683       if (theOrientation == 1)
684         aName<<"f";
685       else if (theOrientation == -1)
686         aName<<"r";
687     } else { // make a composite name from all sub-elements indexes: "1_2_3_4"
688       TColStd_MapIteratorOfPackedMapOfInteger aRef(theRefs->GetMap());
689       for(; aRef.More(); aRef.Next()) {
690         aName<<"-"<<theSubNames[aRef.Key()];
691         if (theOrientations.find(aRef.Key()) != theOrientations.end()) {
692           if (theOrientations[aRef.Key()] == 1)
693             aName<<"f";
694           else if (theOrientations[aRef.Key()] == -1)
695             aName<<"r";
696         }
697       }
698     }
699   }
700
701   theDoc->addNamingName(aLab, aName.str());
702   TDataStd_Name::Set(aLab, aName.str().c_str());
703 }
704
705 void Model_AttributeSelection::selectConstruction(
706   const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape)
707 {
708   std::shared_ptr<Model_Document> aMyDoc = 
709     std::dynamic_pointer_cast<Model_Document>(owner()->document());
710   FeaturePtr aContextFeature = theContext->document()->feature(theContext);
711   CompositeFeaturePtr aComposite = 
712     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
713   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
714   if (!aComposite || aComposite->numberOfSubs() == 0) {
715     // saving of context is enough: result construction contains exactly the needed shape
716     TNaming_Builder aBuilder(selectionLabel());
717     aBuilder.Generated(aSubShape);
718     std::string aName = contextName(theContext);
719     aMyDoc->addNamingName(selectionLabel(), aName);
720     TDataStd_Name::Set(selectionLabel(), aName.c_str());
721     return;
722   }
723   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(owner()->data());
724   TDF_Label aLab = myRef.myRef->Label();
725   // identify the results of sub-object of the composite by edges
726   // save type of the selected shape in integer attribute
727   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
728   TDataStd_Integer::Set(aLab, (int)aShapeType);
729   gp_Pnt aVertexPos;
730   TColStd_MapOfTransient allCurves;
731   if (aShapeType == TopAbs_VERTEX) { // compare positions
732     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
733   } else { 
734     for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
735       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
736       Standard_Real aFirst, aLast;
737       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
738       allCurves.Add(aCurve);
739     }
740   }
741   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
742   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
743   std::map<int, int> anOrientations; //map from edges IDs to orientations of these edges in face
744   std::map<int, std::string> aSubNames; //map from edges IDs to names of edges
745   aRefs->Clear();
746   const int aSubNum = aComposite->numberOfSubs();
747   for(int a = 0; a < aSubNum; a++) {
748     FeaturePtr aSub = aComposite->subFeature(a);
749     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
750     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
751     // there may be many shapes (circle and center): register if at least one is in selection
752     for(; aRes != aResults.cend(); aRes++) {
753       ResultConstructionPtr aConstr = 
754         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
755       if (!aConstr->shape()) {
756         continue;
757       }
758       if (aShapeType == TopAbs_VERTEX) {
759         if (aConstr->shape()->isVertex()) { // compare vertices positions
760           const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
761           gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
762           if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
763             aRefs->Add(aComposite->subFeatureId(a));
764             aSubNames[aComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr);
765           }
766         } else { // get first or last vertex of the edge: last is stored with additional delta
767           const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
768           int aDelta = kSTART_VERTEX_DELTA;
769           for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
770             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
771             if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
772               aRefs->Add(aDelta + aComposite->subFeatureId(a));
773               aSubNames[aDelta + aComposite->subFeatureId(a)] =
774                 Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
775               break;
776             }
777             aDelta += kSTART_VERTEX_DELTA;
778           }
779         }
780       } else {
781         if (aConstr->shape()->isEdge()) {
782           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
783           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
784           if (!anEdge.IsNull()) {
785             Standard_Real aFirst, aLast;
786             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
787             if (allCurves.Contains(aCurve)) {
788               int anID = aComposite->subFeatureId(a);
789               aRefs->Add(anID);
790               aSubNames[anID] = Model_SelectionNaming::shortName(aConstr);
791               if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
792                 // add edges to sub-label to support naming for edges selection
793                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
794                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
795                   TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
796                   Standard_Real aFirst, aLast;
797                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
798                   if (aFaceCurve == aCurve) {
799                     int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
800                     anOrientations[anID] = anOrient;
801                     registerSubShape(
802                       selectionLabel(), anEdge, anID, aContextFeature, aMyDoc, "", anOrientations,
803                       aSubNames, Handle(TDataStd_IntPackedMap)(), anOrient);
804                   }
805                 }
806               } else { // put vertices of the selected edge to sub-labels
807                 // add edges to sub-label to support naming for edges selection
808                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
809                 int aTagIndex = anID + kSTART_VERTEX_DELTA;
810                 for(; anEdgeExp.More(); anEdgeExp.Next(), aTagIndex += kSTART_VERTEX_DELTA) {
811                   TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
812
813                   std::stringstream anAdditionalName; 
814                   registerSubShape(
815                     selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc, "", anOrientations,
816                     aSubNames);
817                 }
818               }
819             }
820           }
821         }
822       }
823     }
824   }
825   // store the selected as primitive
826   TNaming_Builder aBuilder(selectionLabel());
827   aBuilder.Generated(aSubShape);
828     registerSubShape(
829       selectionLabel(), aSubShape, 0, aContextFeature, aMyDoc, "", anOrientations, aSubNames, aRefs); 
830 }
831
832 bool Model_AttributeSelection::selectPart(
833   const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
834   const bool theUpdate)
835 {
836   ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(theContext);
837   if (!aPart.get() || !aPart->isActivated())
838     return true; // postponed naming
839   if (theUpdate) {
840     Handle(TDataStd_Integer) anIndex;
841     if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) { // by internal selection
842       if (anIndex->Get() > 0) {
843         // update the selection by index
844         return aPart->updateInPart(anIndex->Get());
845       } else {
846         return true; // nothing to do, referencing just by name
847       }
848     }
849     return true; // nothing to do, referencing just by name
850   }
851   // store the shape (in case part is not loaded it should be useful
852   TopoDS_Shape aShape;
853   std::string aName = theContext->data()->name();
854   if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected
855     aShape = theContext->shape()->impl<TopoDS_Shape>();
856   } else {
857     aShape = theSubShape->impl<TopoDS_Shape>();
858     int anIndex;
859     aName += "/" + aPart->nameInPart(theSubShape, anIndex);
860     TDataStd_Integer::Set(selectionLabel(), anIndex);
861   }
862   TNaming_Builder aBuilder(selectionLabel());
863   aBuilder.Select(aShape, aShape);
864   // identify by name in the part
865   TDataStd_Name::Set(selectionLabel(), aName.c_str());
866   return !aName.empty();
867 }
868
869 TDF_Label Model_AttributeSelection::selectionLabel()
870 {
871   return myRef.myRef->Label().FindChild(1);
872 }
873
874 std::string Model_AttributeSelection::namingName(const std::string& theDefaultName)
875 {
876   std::string aName("");
877   if(!this->isInitialized())
878     return !theDefaultName.empty() ? theDefaultName : aName;
879   Handle(TDataStd_Name) anAtt;
880   if(selectionLabel().FindAttribute(TDataStd_Name::GetID(), anAtt)) {
881     aName = TCollection_AsciiString(anAtt->Get()).ToCString();
882     return aName;
883   }
884
885   std::shared_ptr<GeomAPI_Shape> aSubSh = value();
886   ResultPtr aCont = context();
887
888   Model_SelectionNaming aSelNaming(selectionLabel());
889   return aSelNaming.namingName(aCont, aSubSh, theDefaultName);
890 }
891
892 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
893 void Model_AttributeSelection::selectSubShape(
894   const std::string& theType, const std::string& theSubShapeName)
895 {
896   if(theSubShapeName.empty() || theType.empty()) return;
897
898   // check this is Part-name: 2 delimiters in the name
899   std::size_t aPartEnd = theSubShapeName.find('/');
900   if (aPartEnd != string::npos && aPartEnd != theSubShapeName.rfind('/')) {
901     std::string aPartName = theSubShapeName.substr(0, aPartEnd);
902     ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
903     if (aFound.get()) { // found such part, so asking it for the name
904       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFound);
905       string aNameInPart = theSubShapeName.substr(aPartEnd + 1);
906       int anIndex;
907       std::shared_ptr<GeomAPI_Shape> aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex);
908       if (aSelected.get()) {
909         setValue(aPart, aSelected);
910         TDataStd_Integer::Set(selectionLabel(), anIndex);
911         return;
912       }
913     }
914   }
915
916   Model_SelectionNaming aSelNaming(selectionLabel());
917   std::shared_ptr<Model_Document> aDoc = 
918     std::dynamic_pointer_cast<Model_Document>(owner()->document());
919   std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected;
920   ResultPtr aCont;
921   if (aSelNaming.selectSubShape(theType, theSubShapeName, aDoc, aShapeToBeSelected, aCont)) {
922     setValue(aCont, aShapeToBeSelected);
923   }
924 }
925
926 int Model_AttributeSelection::Id()
927 {
928   int anID = 0;
929   std::shared_ptr<GeomAPI_Shape> aSelection = value();
930   std::shared_ptr<GeomAPI_Shape> aContext = context()->shape();
931   // support for compsolids:
932   if (context().get() && ModelAPI_Tools::compSolidOwner(context()).get())
933     aContext = ModelAPI_Tools::compSolidOwner(context())->shape();
934
935
936   TopoDS_Shape aMainShape = aContext->impl<TopoDS_Shape>();
937   const TopoDS_Shape& aSubShape = aSelection->impl<TopoDS_Shape>();
938   // searching for the latest main shape
939   if (aSelection && !aSelection->isNull() &&
940     aContext   && !aContext->isNull())
941   {
942     std::shared_ptr<Model_Document> aDoc =
943       std::dynamic_pointer_cast<Model_Document>(context()->document());
944     if (aDoc.get()) {
945       Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
946       if (!aNS.IsNull()) {
947         aMainShape = TNaming_Tool::CurrentShape(aNS);
948       }
949     }
950
951     TopTools_IndexedMapOfShape aSubShapesMap;
952     TopExp::MapShapes(aMainShape, aSubShapesMap);
953     anID = aSubShapesMap.FindIndex(aSubShape);
954   }
955   return anID;
956 }
957
958 void Model_AttributeSelection::setId(int theID)
959 {
960   const ResultPtr& aContext = context();
961   std::shared_ptr<GeomAPI_Shape> aSelection;
962
963   std::shared_ptr<GeomAPI_Shape> aContextShape = aContext->shape();
964   // support for compsolids:
965   if (aContext.get() && ModelAPI_Tools::compSolidOwner(aContext).get())
966     aContextShape = ModelAPI_Tools::compSolidOwner(aContext)->shape();
967
968   TopoDS_Shape aMainShape = aContextShape->impl<TopoDS_Shape>();
969   // searching for the latest main shape
970   if (theID > 0 &&
971       aContextShape && !aContextShape->isNull())
972   {
973     std::shared_ptr<Model_Document> aDoc =
974       std::dynamic_pointer_cast<Model_Document>(aContext->document());
975     if (aDoc.get()) {
976       Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
977       if (!aNS.IsNull()) {
978         aMainShape = TNaming_Tool::CurrentShape(aNS);
979       }
980     }
981
982     TopTools_IndexedMapOfShape aSubShapesMap;
983     TopExp::MapShapes(aMainShape, aSubShapesMap);
984     const TopoDS_Shape& aSelShape = aSubShapesMap.FindKey(theID);
985
986     std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
987     aResult->setImpl(new TopoDS_Shape(aSelShape));
988
989     aSelection = aResult;
990   }
991
992   setValue(aContext, aSelection);
993 }
994
995 std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const
996 {
997   std::string aResult;
998   if (owner()->document() != theContext->document()) {
999     if (theContext->document() == ModelAPI_Session::get()->moduleDocument()) {
1000       aResult = theContext->document()->kind() + "/";
1001     } else {
1002       ResultPtr aDocRes = ModelAPI_Tools::findPartResult(
1003         ModelAPI_Session::get()->moduleDocument(), theContext->document());
1004       if (aDocRes.get()) {
1005         aResult = aDocRes->data()->name() + "/";
1006       }
1007     }
1008   }
1009   aResult += theContext->data()->name();
1010   return aResult;
1011 }