]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_AttributeSelection.cpp
Salome HOME
Issue #1664 In the Sketcher, add the function Split a segment
[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
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(aContext, allCurves);
510         }
511         if (aNewSelected) { // store this new selection
512           if (aShapeType == TopAbs_WIRE) { // just get a wire from face to have wire
513             TopExp_Explorer aWireExp(aNewSelected->impl<TopoDS_Shape>(), TopAbs_WIRE);
514             if (aWireExp.More()) {
515               aNewSelected.reset(new GeomAPI_Shape);
516               aNewSelected->setImpl<TopoDS_Shape>(new TopoDS_Shape(aWireExp.Current()));
517             }
518           }
519           selectConstruction(aContext, aNewSelected);
520           setInvalidIfFalse(aSelLab, true);
521           owner()->data()->sendAttributeUpdated(this);
522           return true;
523         } else { // if the selection is not found, put the empty shape: it's better to have disappeared shape, than the old, the lost one
524           TNaming_Builder anEmptyBuilder(selectionLabel());
525           return setInvalidIfFalse(aSelLab, false);
526         }
527       } else if (aShapeType == TopAbs_EDGE) {
528         // just reselect the edge by the id
529         const int aSubNum = aComposite->numberOfSubs();
530         for(int a = 0; a < aSubNum; a++) {
531           // if aSubIds take any, the first appropriate
532           if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
533             // found the appropriate feature
534             FeaturePtr aFeature = aComposite->subFeature(a);
535             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
536               aFeature->results().cbegin();
537             for(;aResIter != aFeature->results().cend(); aResIter++) {
538               ResultConstructionPtr aRes = 
539                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
540               if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
541                 selectConstruction(aContext, aRes->shape());
542                 setInvalidIfFalse(aSelLab, true);
543                 owner()->data()->sendAttributeUpdated(this);
544                 return true;
545               }
546             }
547           }
548         }
549       } else if (aShapeType == TopAbs_VERTEX) {
550         // just reselect the vertex by the id of edge
551         const int aSubNum = aComposite->numberOfSubs();
552         for(int a = 0; a < aSubNum; a++) {
553           // if aSubIds take any, the first appropriate
554           int aFeatureID = aComposite->subFeatureId(a);
555           if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
556             aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
557             aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
558               // searching for deltas
559               int aVertexNum = 0;
560               if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
561               else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
562               // found the feature with appropriate edge
563               FeaturePtr aFeature = aComposite->subFeature(a);
564               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
565                 aFeature->results().cbegin();
566               for(;aResIter != aFeature->results().cend(); aResIter++) {
567                 ResultConstructionPtr aRes = 
568                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
569                 if (aRes && aRes->shape()) {
570                   if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
571                     selectConstruction(aContext, aRes->shape());
572                     setInvalidIfFalse(aSelLab, true);
573                     owner()->data()->sendAttributeUpdated(this);
574                     return true;
575                   } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
576                     const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
577                     int aVIndex = 1;
578                     for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
579                       if (aVIndex == aVertexNum) { // found!
580                         std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
581                         aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
582                         selectConstruction(aContext, aVertex);
583                         setInvalidIfFalse(aSelLab, true);
584                         owner()->data()->sendAttributeUpdated(this);
585                         return true;
586                       }
587                       aVIndex++;
588                     }
589                   }
590                 }
591               }
592           }
593         }
594       }
595     } else { // simple construction element: the selected is that needed
596       selectConstruction(aContext, aContext->shape());
597       setInvalidIfFalse(aSelLab, true);
598       owner()->data()->sendAttributeUpdated(this);
599       return true;
600     }
601   }
602   return setInvalidIfFalse(aSelLab, false); // unknown case
603 }
604
605
606 void Model_AttributeSelection::selectBody(
607   const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape)
608 {
609   // perform the selection
610   TNaming_Selector aSel(selectionLabel());
611   TopoDS_Shape aContext;
612
613   ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
614   if (aBody) {
615     aContext = aBody->shape()->impl<TopoDS_Shape>();
616   } else {
617     ResultPtr aResult = 
618       std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
619     if (aResult) {
620       aContext = aResult->shape()->impl<TopoDS_Shape>();
621     } else {
622       Events_InfoMessage("Model_AttributeSelection", "A result with shape is expected").send();
623       return;
624     }
625   }
626   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : aContext;
627   /// fix for issue 411: result modified shapes must not participate in this selection mechanism
628   FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
629   if (aFeatureOwner.get())
630     aFeatureOwner->eraseResults();
631   if (!aContext.IsNull()) {
632     aSel.Select(aNewShape, aContext); 
633   }
634 }
635
636 /// registers the name of the shape in the label (theID == 0) of sub label (theID is a tag)
637 /// if theID is zero, 
638 /// theOrientation is additional information about the positioning of edge relatively to face
639 ///    it is stored in the integer attribute of the edge sub-label: 
640 ///    -1 is out, 1 is in, 0 is not needed
641 static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape,
642   const int theID, const FeaturePtr& theContextFeature, std::shared_ptr<Model_Document> theDoc,
643   std::string theAdditionalName, std::map<int, int>& theOrientations,
644   std::map<int, std::string>& theSubNames, // name of sub-elements by ID to be exported instead of indexes
645   Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)(),
646   const int theOrientation = 0)
647 {
648   TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
649   if (theOrientation != 0) { // store the orientation of edge relatively to face if needed
650     TDataStd_Integer::Set(aLab, theOrientation);
651   }
652   TNaming_Builder aBuilder(aLab);
653   aBuilder.Generated(theShape);
654   std::stringstream aName;
655   // add the part name if the selected object is located in other part
656   if (theDoc != theContextFeature->document()) {
657     if (theContextFeature->document() == ModelAPI_Session::get()->moduleDocument()) {
658       aName<<theContextFeature->document()->kind()<<"/";
659     } else {
660       ResultPtr aDocRes = ModelAPI_Tools::findPartResult(
661         ModelAPI_Session::get()->moduleDocument(), theContextFeature->document());
662       if (aDocRes.get()) {
663         aName<<aDocRes->data()->name()<<"/";
664       }
665     }
666   }
667   aName<<theContextFeature->name();
668   if (theShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction
669     aName<<"/";
670     if (!theAdditionalName.empty())
671       aName<<theAdditionalName<<"/";
672     if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face";
673     else if (theShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
674     else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
675     else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
676
677     if (theRefs.IsNull()) {
678       aName<<theID;
679       if (theOrientation == 1)
680         aName<<"f";
681       else if (theOrientation == -1)
682         aName<<"r";
683     } else { // make a composite name from all sub-elements indexes: "1_2_3_4"
684       TColStd_MapIteratorOfPackedMapOfInteger aRef(theRefs->GetMap());
685       for(; aRef.More(); aRef.Next()) {
686         aName<<"-"<<theSubNames[aRef.Key()];
687         if (theOrientations.find(aRef.Key()) != theOrientations.end()) {
688           if (theOrientations[aRef.Key()] == 1)
689             aName<<"f";
690           else if (theOrientations[aRef.Key()] == -1)
691             aName<<"r";
692         }
693       }
694     }
695   }
696
697   theDoc->addNamingName(aLab, aName.str());
698   TDataStd_Name::Set(aLab, aName.str().c_str());
699 }
700
701 void Model_AttributeSelection::selectConstruction(
702   const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape)
703 {
704   std::shared_ptr<Model_Document> aMyDoc = 
705     std::dynamic_pointer_cast<Model_Document>(owner()->document());
706   FeaturePtr aContextFeature = theContext->document()->feature(theContext);
707   CompositeFeaturePtr aComposite = 
708     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
709   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
710   if (!aComposite || aComposite->numberOfSubs() == 0) {
711     // saving of context is enough: result construction contains exactly the needed shape
712     TNaming_Builder aBuilder(selectionLabel());
713     aBuilder.Generated(aSubShape);
714     std::string aName = contextName(theContext);
715     aMyDoc->addNamingName(selectionLabel(), aName);
716     TDataStd_Name::Set(selectionLabel(), aName.c_str());
717     return;
718   }
719   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(owner()->data());
720   TDF_Label aLab = myRef.myRef->Label();
721   // identify the results of sub-object of the composite by edges
722   // save type of the selected shape in integer attribute
723   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
724   TDataStd_Integer::Set(aLab, (int)aShapeType);
725   gp_Pnt aVertexPos;
726   TColStd_MapOfTransient allCurves;
727   if (aShapeType == TopAbs_VERTEX) { // compare positions
728     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
729   } else { 
730     for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
731       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
732       Standard_Real aFirst, aLast;
733       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
734       allCurves.Add(aCurve);
735     }
736   }
737   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
738   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
739   std::map<int, int> anOrientations; //map from edges IDs to orientations of these edges in face
740   std::map<int, std::string> aSubNames; //map from edges IDs to names of edges
741   aRefs->Clear();
742   const int aSubNum = aComposite->numberOfSubs();
743   for(int a = 0; a < aSubNum; a++) {
744     FeaturePtr aSub = aComposite->subFeature(a);
745     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
746     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
747     // there may be many shapes (circle and center): register if at least one is in selection
748     for(; aRes != aResults.cend(); aRes++) {
749       ResultConstructionPtr aConstr = 
750         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
751       if (!aConstr->shape()) {
752         continue;
753       }
754       if (aShapeType == TopAbs_VERTEX) {
755         if (aConstr->shape()->isVertex()) { // compare vertices positions
756           const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
757           gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
758           if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
759             aRefs->Add(aComposite->subFeatureId(a));
760             aSubNames[aComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr);
761           }
762         } else { // get first or last vertex of the edge: last is stored with additional delta
763           const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
764           int aDelta = kSTART_VERTEX_DELTA;
765           for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
766             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
767             if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
768               aRefs->Add(aDelta + aComposite->subFeatureId(a));
769               aSubNames[aDelta + aComposite->subFeatureId(a)] =
770                 Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
771               break;
772             }
773             aDelta += kSTART_VERTEX_DELTA;
774           }
775         }
776       } else {
777         if (aConstr->shape()->isEdge()) {
778           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
779           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
780           if (!anEdge.IsNull()) {
781             Standard_Real aFirst, aLast;
782             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
783             if (allCurves.Contains(aCurve)) {
784               int anID = aComposite->subFeatureId(a);
785               aRefs->Add(anID);
786               aSubNames[anID] = Model_SelectionNaming::shortName(aConstr);
787               if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
788                 // add edges to sub-label to support naming for edges selection
789                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
790                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
791                   TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
792                   Standard_Real aFirst, aLast;
793                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
794                   if (aFaceCurve == aCurve) {
795                     int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
796                     anOrientations[anID] = anOrient;
797                     registerSubShape(
798                       selectionLabel(), anEdge, anID, aContextFeature, aMyDoc, "", anOrientations,
799                       aSubNames, Handle(TDataStd_IntPackedMap)(), anOrient);
800                   }
801                 }
802               } else { // put vertices of the selected edge to sub-labels
803                 // add edges to sub-label to support naming for edges selection
804                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
805                 int aTagIndex = anID + kSTART_VERTEX_DELTA;
806                 for(; anEdgeExp.More(); anEdgeExp.Next(), aTagIndex += kSTART_VERTEX_DELTA) {
807                   TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
808
809                   std::stringstream anAdditionalName; 
810                   registerSubShape(
811                     selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc, "", anOrientations,
812                     aSubNames);
813                 }
814               }
815             }
816           }
817         }
818       }
819     }
820   }
821   // store the selected as primitive
822   TNaming_Builder aBuilder(selectionLabel());
823   aBuilder.Generated(aSubShape);
824     registerSubShape(
825       selectionLabel(), aSubShape, 0, aContextFeature, aMyDoc, "", anOrientations, aSubNames, aRefs); 
826 }
827
828 bool Model_AttributeSelection::selectPart(
829   const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
830   const bool theUpdate)
831 {
832   ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(theContext);
833   if (!aPart.get() || !aPart->isActivated())
834     return true; // postponed naming
835   if (theUpdate) {
836     Handle(TDataStd_Integer) anIndex;
837     if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) { // by internal selection
838       if (anIndex->Get() > 0) {
839         // update the selection by index
840         return aPart->updateInPart(anIndex->Get());
841       } else {
842         return true; // nothing to do, referencing just by name
843       }
844     }
845     return true; // nothing to do, referencing just by name
846   }
847   // store the shape (in case part is not loaded it should be useful
848   TopoDS_Shape aShape;
849   std::string aName = theContext->data()->name();
850   if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected
851     aShape = theContext->shape()->impl<TopoDS_Shape>();
852   } else {
853     aShape = theSubShape->impl<TopoDS_Shape>();
854     int anIndex;
855     aName += "/" + aPart->nameInPart(theSubShape, anIndex);
856     TDataStd_Integer::Set(selectionLabel(), anIndex);
857   }
858   TNaming_Builder aBuilder(selectionLabel());
859   aBuilder.Select(aShape, aShape);
860   // identify by name in the part
861   TDataStd_Name::Set(selectionLabel(), aName.c_str());
862   return !aName.empty();
863 }
864
865 TDF_Label Model_AttributeSelection::selectionLabel()
866 {
867   return myRef.myRef->Label().FindChild(1);
868 }
869
870 std::string Model_AttributeSelection::namingName(const std::string& theDefaultName)
871 {
872   std::string aName("");
873   if(!this->isInitialized())
874     return !theDefaultName.empty() ? theDefaultName : aName;
875
876   std::shared_ptr<GeomAPI_Shape> aSubSh = value();
877   ResultPtr aCont = context();
878
879   Model_SelectionNaming aSelNaming(selectionLabel());
880   return aSelNaming.namingName(aCont, aSubSh, theDefaultName);
881 }
882
883 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
884 void Model_AttributeSelection::selectSubShape(
885   const std::string& theType, const std::string& theSubShapeName)
886 {
887   if(theSubShapeName.empty() || theType.empty()) return;
888
889   // check this is Part-name: 2 delimiters in the name
890   std::size_t aPartEnd = theSubShapeName.find('/');
891   if (aPartEnd != string::npos && aPartEnd != theSubShapeName.rfind('/')) {
892     std::string aPartName = theSubShapeName.substr(0, aPartEnd);
893     ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
894     if (aFound.get()) { // found such part, so asking it for the name
895       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFound);
896       string aNameInPart = theSubShapeName.substr(aPartEnd + 1);
897       int anIndex;
898       std::shared_ptr<GeomAPI_Shape> aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex);
899       if (aSelected.get()) {
900         setValue(aPart, aSelected);
901         TDataStd_Integer::Set(selectionLabel(), anIndex);
902         return;
903       }
904     }
905   }
906
907   Model_SelectionNaming aSelNaming(selectionLabel());
908   std::shared_ptr<Model_Document> aDoc = 
909     std::dynamic_pointer_cast<Model_Document>(owner()->document());
910   std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected;
911   ResultPtr aCont;
912   if (aSelNaming.selectSubShape(theType, theSubShapeName, aDoc, aShapeToBeSelected, aCont)) {
913     setValue(aCont, aShapeToBeSelected);
914   }
915 }
916
917 int Model_AttributeSelection::Id()
918 {
919   int anID = 0;
920   std::shared_ptr<GeomAPI_Shape> aSelection = value();
921   std::shared_ptr<GeomAPI_Shape> aContext = context()->shape();
922   // support for compsolids:
923   if (context().get() && ModelAPI_Tools::compSolidOwner(context()).get())
924     aContext = ModelAPI_Tools::compSolidOwner(context())->shape();
925
926
927   TopoDS_Shape aMainShape = aContext->impl<TopoDS_Shape>();
928   const TopoDS_Shape& aSubShape = aSelection->impl<TopoDS_Shape>();
929   // searching for the latest main shape
930   if (aSelection && !aSelection->isNull() &&
931     aContext   && !aContext->isNull())
932   {
933     std::shared_ptr<Model_Document> aDoc =
934       std::dynamic_pointer_cast<Model_Document>(context()->document());
935     if (aDoc.get()) {
936       Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
937       if (!aNS.IsNull()) {
938         aMainShape = TNaming_Tool::CurrentShape(aNS);
939       }
940     }
941
942     TopTools_IndexedMapOfShape aSubShapesMap;
943     TopExp::MapShapes(aMainShape, aSubShapesMap);
944     anID = aSubShapesMap.FindIndex(aSubShape);
945   }
946   return anID;
947 }
948
949 void Model_AttributeSelection::setId(int theID)
950 {
951   const ResultPtr& aContext = context();
952   std::shared_ptr<GeomAPI_Shape> aSelection;
953
954   std::shared_ptr<GeomAPI_Shape> aContextShape = aContext->shape();
955   // support for compsolids:
956   if (aContext.get() && ModelAPI_Tools::compSolidOwner(aContext).get())
957     aContextShape = ModelAPI_Tools::compSolidOwner(aContext)->shape();
958
959   TopoDS_Shape aMainShape = aContextShape->impl<TopoDS_Shape>();
960   // searching for the latest main shape
961   if (theID > 0 &&
962       aContextShape && !aContextShape->isNull())
963   {
964     std::shared_ptr<Model_Document> aDoc =
965       std::dynamic_pointer_cast<Model_Document>(aContext->document());
966     if (aDoc.get()) {
967       Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aMainShape, aDoc->generalLabel());
968       if (!aNS.IsNull()) {
969         aMainShape = TNaming_Tool::CurrentShape(aNS);
970       }
971     }
972
973     TopTools_IndexedMapOfShape aSubShapesMap;
974     TopExp::MapShapes(aMainShape, aSubShapesMap);
975     const TopoDS_Shape& aSelShape = aSubShapesMap.FindKey(theID);
976
977     std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
978     aResult->setImpl(new TopoDS_Shape(aSelShape));
979
980     aSelection = aResult;
981   }
982
983   setValue(aContext, aSelection);
984 }
985
986 std::string Model_AttributeSelection::contextName(const ResultPtr& theContext) const
987 {
988   std::string aResult;
989   if (owner()->document() != theContext->document()) {
990     if (theContext->document() == ModelAPI_Session::get()->moduleDocument()) {
991       aResult = theContext->document()->kind() + "/";
992     } else {
993       ResultPtr aDocRes = ModelAPI_Tools::findPartResult(
994         ModelAPI_Session::get()->moduleDocument(), theContext->document());
995       if (aDocRes.get()) {
996         aResult = aDocRes->data()->name() + "/";
997       }
998     }
999   }
1000   aResult += theContext->data()->name();
1001   return aResult;
1002 }