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