Salome HOME
Issue #2090: Line not selectable when creating an arc by its center
[modules/shaper.git] / src / Model / Model_ResultConstruction.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        ModelAPI_ResultConstruction.cpp
4 // Created:     07 Jul 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include <Model_ResultConstruction.h>
8
9 #include <Model_Data.h>
10 #include <ModelAPI_CompositeFeature.h>
11 #include <Model_SelectionNaming.h>
12 #include <ModelAPI_Events.h>
13 #include <Config_PropManager.h>
14 #include <GeomAPI_PlanarEdges.h>
15 #include <GeomAPI_Shape.h>
16 #include <GeomAlgoAPI_SketchBuilder.h>
17 #include <Events_Loop.h>
18
19 #include <TDF_Reference.hxx>
20 #include <TDF_ChildIterator.hxx>
21 #include <TNaming_NamedShape.hxx>
22 #include <TNaming_Builder.hxx>
23 #include <TDataStd_Integer.hxx>
24 #include <TDataStd_IntPackedMap.hxx>
25 #include <TDataStd_Name.hxx>
26 #include <TDataStd_UAttribute.hxx>
27 #include <TColStd_MapOfTransient.hxx>
28 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
29 #include <BRep_Tool.hxx>
30 #include <BRep_Builder.hxx>
31 #include <TopoDS.hxx>
32 #include <TopoDS_Shape.hxx>
33 #include <TopoDS_Edge.hxx>
34 #include <TopoDS_Vertex.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <Precision.hxx>
37
38 // identifier that it is full result selected, but in external document (for internal index is 0)
39 Standard_GUID kFULL_RESULT_ID("ee87e529-da6f-46af-be25-5e0fefde52f7");
40
41
42 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
43                                        std::string& theDefault)
44 {
45   theSection = "Visualization";
46   theName = "result_construction_color";
47   theDefault = DEFAULT_COLOR();
48 }
49
50 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
51 {
52   if (myShape != theShape && (!theShape.get() || !theShape->isEqual(myShape))) {
53     static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
54     ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
55     myShape = theShape;
56     if (theShape.get()) {
57       myFacesUpToDate = false;
58       myFaces.clear();
59     }
60   }
61 }
62
63 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
64 {
65   return myShape;
66 }
67
68 Model_ResultConstruction::Model_ResultConstruction()
69 {
70   myIsInHistory = true;
71   myIsInfinite = false;
72   myFacesUpToDate = false;
73 }
74
75 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
76 {
77   myIsInHistory = isInHistory;
78 }
79
80 int Model_ResultConstruction::facesNum()
81 {
82   if (!myFacesUpToDate) {
83     std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
84       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(myShape);
85     if (aWirePtr.get()) {
86       std::list<std::shared_ptr<GeomAPI_Shape> > aFaces;
87       GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
88         aWirePtr->norm(), aWirePtr, aFaces);
89       std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aFIter = aFaces.begin();
90       for(; aFIter != aFaces.end(); aFIter++) {
91         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(*aFIter));
92         if (aFace.get() && !aFace->isNull())
93           myFaces.push_back(aFace);
94       }
95     }
96     myFacesUpToDate = true;
97   }
98   return int(myFaces.size());
99 }
100
101 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
102 {
103   return myFaces[theIndex];
104 }
105
106 bool Model_ResultConstruction::isInfinite()
107 {
108   return myIsInfinite;
109 }
110
111 void Model_ResultConstruction::setInfinite(const bool theInfinite)
112 {
113   myIsInfinite = theInfinite;
114 }
115
116 void Model_ResultConstruction::setIsConcealed(const bool theValue)
117 {
118   // do nothing: the construction element is never consealed
119 }
120
121 static const int kSTART_VERTEX_DELTA = 1000000;
122
123 static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape,
124   const int theID, std::shared_ptr<Model_Document> theDoc,
125   bool theSelectionMode,
126   std::map<int, int>& theOrientations,
127   // name of sub-elements by ID to be exported instead of indexes
128   std::map<int, std::string>& theSubNames,
129   Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)(),
130   const int theOrientation = 0)
131 {
132   TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
133   if (theOrientation != 0) { // store the orientation of edge relatively to face if needed
134     TDataStd_Integer::Set(aLab, theOrientation);
135   }
136   TNaming_Builder aBuilder(aLab);
137   // wire never happens as sub, it must be generated to be found
138   // by SelectionNaming TNaming_Tool::NamedShape
139   if (theSelectionMode && theShape.ShapeType() != TopAbs_WIRE)
140     aBuilder.Select(theShape, theShape);
141   else
142     aBuilder.Generated(theShape);
143   std::stringstream aName;
144   // #1839 : do not store name of the feature in the tree, since this name could be changed
145   //aName<<theContextFeature->name();
146   if (theShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction
147     //aName<<"/";
148     if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face";
149     else if (theShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
150     else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
151     else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
152
153     if (theRefs.IsNull()) {
154       aName<<theID;
155       if (theOrientation == 1)
156         aName<<"f";
157       else if (theOrientation == -1)
158         aName<<"r";
159     } else { // make a composite name from all sub-elements indexes: "1_2_3_4"
160       TColStd_MapIteratorOfPackedMapOfInteger aRef(theRefs->GetMap());
161       for(; aRef.More(); aRef.Next()) {
162         aName<<"-"<<theSubNames[aRef.Key()];
163         if (theOrientations.find(aRef.Key()) != theOrientations.end()) {
164           if (theOrientations[aRef.Key()] == 1)
165             aName<<"f";
166           else if (theOrientations[aRef.Key()] == -1)
167             aName<<"r";
168         }
169       }
170     }
171   }
172
173   theDoc->addNamingName(aLab, aName.str());
174   TDataStd_Name::Set(aLab, aName.str().c_str());
175 }
176
177 TDF_Label Model_ResultConstruction::startLabel(
178   const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theExternal)
179 {
180   theExternal = theExtDoc.get() && theExtDoc != document();
181   if (theExternal) { // external document is used
182     std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(theExtDoc);
183     return aDoc->extConstructionsLabel();
184   }
185   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
186   return aData->label();
187 }
188
189 int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSubShape,
190   const std::shared_ptr<ModelAPI_Document> theExtDoc, const int theIndex)
191 {
192   int anIndex; // resulting index of the sub-label
193   TopoDS_Shape aSubShape;
194   if (theSubShape.get()) {
195     aSubShape = theSubShape->impl<TopoDS_Shape>();
196   } else if (shape().get()) {
197     aSubShape = shape()->impl<TopoDS_Shape>();
198   }
199   // if external document requires this selection, put the naming structures to this doc
200   // to support the naming mechanism in this document correctly
201   bool anExternal;
202   TDF_Label aDataLab = startLabel(theExtDoc, anExternal);
203   if (theIndex == -1) {
204     anIndex = anExternal ? 2 : 1; // for the external doc don't mind about the main shape
205
206     if (theSubShape.get() || anExternal) { // searching for already selected sub (or whole for ext)
207       // iterate all the already presented shapes to see the same
208       TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
209       for(; aSubsIter.More(); aSubsIter.Next()) {
210         const TDF_Label aLab = aSubsIter.Value();
211         if (aLab.Tag() == 1) // skip the root shape label
212           continue;
213         Handle(TNaming_NamedShape) aNS;
214         if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
215           if (aNS->Get().IsSame(aSubShape)) {
216             return aLab.Tag() - 1; // found exactly the needed shape, nothing else to do
217           }
218         }
219         anIndex = aLab.Tag(); // searching for the latest index
220       }
221       anIndex = (anIndex == 1) ? 2 : (anIndex + 1); // next after 1-root, or next after all
222     }
223   } else {
224     anIndex = theIndex + 1;
225   }
226
227   // set the naming structure at index
228   TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True);
229
230   // if the subshape is part of a result face, select the whole face (#1997)
231   bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label
232   if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) {
233     for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
234       TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
235       for(; anExp.More(); anExp.Next()) {
236         if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
237           // here just store the face index (to update face if update of edge is needed)
238           TNaming_Builder aBuilder(aLab);
239           aBuilder.Select(aSubShape, aSubShape);
240           int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
241           TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
242           isSelectionMode = true;
243           break;
244         }
245       }
246     }
247   }
248
249   // external full result is not identified by index == 0, so, add here the ID
250   if (!theSubShape.get()) {
251     TDataStd_UAttribute::Set(aLab, kFULL_RESULT_ID);
252     // empty NS
253     TNaming_Builder aBuilder(aLab);
254     // store all sub-faces naming since faces may be used for extrusion, where all edges are needed
255     Handle(TDataStd_IntPackedMap) anIndices = TDataStd_IntPackedMap::Set(aLab);
256     std::list<int> aFacesIndexes;
257     for(int a = 0; a < facesNum(); a++) {
258       anIndices->Add(select(face(a), theExtDoc, -1));
259     }
260     return anIndex - 1;
261   }
262
263   { // this to have erased Builder after the shape was generated (NS on this label may be changed)
264     TNaming_Builder aBuilder(aLab);
265     if (aSubShape.IsNull()) {
266       return anIndex - 1; // just keep empty named shape
267     }
268     // wire never happens as sub, it must be generated to be found
269     // by SelectionNaming TNaming_Tool::NamedShape
270     if (isSelectionMode && aSubShape.ShapeType() != TopAbs_WIRE) {
271       aBuilder.Select(aSubShape, aSubShape);
272     } else {
273       aBuilder.Generated(aSubShape);
274     }
275   }
276
277   if (anIndex == 1 && isInfinite()) { // infinitive results has no sub-selection
278     return anIndex - 1;
279   }
280   ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
281   FeaturePtr aThisFeature = document()->feature(aThisPtr);
282   CompositeFeaturePtr aComposite =
283     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
284   if (!aComposite || aComposite->numberOfSubs() == 0) {
285     // saving of context is enough: result construction contains exactly the needed shape
286     return anIndex - 1;
287   }
288
289   // identify the results of sub-object of the composite by edges
290   // save type of the selected shape in integer attribute
291   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
292   TDataStd_Integer::Set(aLab, (int)aShapeType);
293   gp_Pnt aVertexPos;
294   TColStd_MapOfTransient allCurves;
295   if (aShapeType == TopAbs_VERTEX) { // compare positions
296     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
297   } else {
298     for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
299       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
300       Standard_Real aFirst, aLast;
301       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
302       allCurves.Add(aCurve);
303     }
304   }
305   std::shared_ptr<Model_Document> aMyDoc =
306     std::dynamic_pointer_cast<Model_Document>(document());
307   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
308   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
309   std::map<int, int> anOrientations; //map from edges IDs to orientations of these edges in face
310   std::map<int, std::string> aSubNames; //map from edges IDs to names of edges
311   aRefs->Clear();
312   const int aSubNum = aComposite->numberOfSubs();
313   for(int a = 0; a < aSubNum; a++) {
314     FeaturePtr aSub = aComposite->subFeature(a);
315     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
316     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
317     // there may be many shapes (circle and center): register if at least one is in selection
318     for(; aRes != aResults.cend(); aRes++) {
319       ResultConstructionPtr aConstr =
320         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
321       if (!aConstr->shape()) {
322         continue;
323       }
324       if (aShapeType == TopAbs_VERTEX) {
325         if (aConstr->shape()->isVertex()) { // compare vertices positions
326           const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
327           gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
328           if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
329             aRefs->Add(aComposite->subFeatureId(a));
330             aSubNames[aComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr);
331           }
332         } else { // get first or last vertex of the edge: last is stored with additional delta
333           const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
334           int aDelta = kSTART_VERTEX_DELTA;
335           for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
336             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
337             if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
338               aRefs->Add(aDelta + aComposite->subFeatureId(a));
339               aSubNames[aDelta + aComposite->subFeatureId(a)] =
340                 Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
341               break;
342             }
343             aDelta += kSTART_VERTEX_DELTA;
344           }
345         }
346       } else {
347         if (aConstr->shape()->isEdge()) {
348           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
349           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
350           if (!anEdge.IsNull()) {
351             Standard_Real aFirst, aLast;
352             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
353             if (allCurves.Contains(aCurve)) {
354               int anID = aComposite->subFeatureId(a);
355               aRefs->Add(anID);
356               aSubNames[anID] = Model_SelectionNaming::shortName(aConstr);
357               if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
358                 // add edges to sub-label to support naming for edges selection
359                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
360                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
361                   TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
362                   Standard_Real aFirst, aLast;
363                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
364                   if (aFaceCurve == aCurve) {
365                     int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
366                     anOrientations[anID] = anOrient;
367
368                     TDF_Label aSubLab = aLab.FindChild(anID);
369                     std::string aName = "Edge-" + Model_SelectionNaming::shortName(aConstr, 0);
370                     TNaming_Builder aBuilder(aSubLab);
371                     if (isSelectionMode)
372                       aBuilder.Select(anEdge, anEdge);
373                     else
374                       aBuilder.Generated(anEdge);
375                     aMyDoc->addNamingName(aSubLab, aName.c_str());
376                     TDataStd_Name::Set(aSubLab, aName.c_str());
377
378                     if (anOrient != 0) {
379                       // store the orientation of edge relatively to face if needed
380                       TDataStd_Integer::Set(aSubLab, anOrient);
381                     }
382                   }
383                 }
384               } else { // put vertices of the selected edge to sub-labels
385                 // add edges to sub-label to support naming for edges selection
386                 int aDelta = kSTART_VERTEX_DELTA;
387                 int aTagIndex = anID + kSTART_VERTEX_DELTA;
388                 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
389                     anEdgeExp.More();
390                     anEdgeExp.Next(),
391                     aTagIndex += kSTART_VERTEX_DELTA,
392                     aDelta += kSTART_VERTEX_DELTA) {
393                   TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
394
395                   TDF_Label aSubLab = aLab.FindChild(aTagIndex);
396                   std::string aName = "Vertex-"
397                       + Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
398                   TNaming_Builder aBuilder(aLab);
399                   if (isSelectionMode)
400                     aBuilder.Select(aV, aV);
401                   else
402                     aBuilder.Generated(aV);
403                   aMyDoc->addNamingName(aLab, aName.c_str());
404                   TDataStd_Name::Set(aLab, aName.c_str());
405                 }
406               }
407             }
408           }
409         }
410       }
411     }
412   }
413   // store the selected as primitive
414   registerSubShape(aLab, aSubShape, 0, aMyDoc, isSelectionMode, anOrientations, aSubNames, aRefs);
415   return anIndex - 1;
416 }
417
418 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape(const int theIndex,
419   const std::shared_ptr<ModelAPI_Document> theExtDoc)
420 {
421   std::shared_ptr<GeomAPI_Shape> aResult;
422   if (theIndex == 0)
423     return aResult; // the whole shape, so, NULL
424
425   bool isExt;
426   TDF_Label aLab = startLabel(theExtDoc, isExt).FindChild(theIndex + 1);
427   if (!aLab.IsNull()) { // index is not bad
428     Handle(TNaming_NamedShape) aSelection;
429     if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
430       TopoDS_Shape aSelShape = aSelection->Get();
431       if (aSelShape.IsNull())
432         return aResult; // shape equal to context => null
433       aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
434       aResult->setImpl(new TopoDS_Shape(aSelShape));
435     }
436   }
437
438   return aResult;
439 }
440
441 bool Model_ResultConstruction::update(const int theIndex,
442   const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theModified)
443 {
444   theModified = false;
445   bool anExt;
446   TDF_Label aLab = startLabel(theExtDoc, anExt).FindChild(theIndex + 1, Standard_True);
447   if (theIndex == 0 || aLab.IsAttribute(kFULL_RESULT_ID)) { // full for external same as index == 0
448     // it is just reference to construction, not sub-shape
449     // if there is a sketch, the sketch-naming must be updated
450     if (!isInfinite()) {
451       // update all faces named by the whole result
452       bool aRes = true;
453       Handle(TDataStd_IntPackedMap) anIndices;
454       if (aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), anIndices)) {
455         NCollection_Map<TopoDS_Shape> aFaces; // collect faces, updated in the tree
456         TColStd_MapIteratorOfPackedMapOfInteger anIndexIter(anIndices->GetMap());
457         Handle(TColStd_HPackedMapOfInteger) aNewPackedMap =
458           new TColStd_HPackedMapOfInteger; // with only faces that are ok
459         // iterate to find existing faces, updated
460         for(; anIndexIter.More(); anIndexIter.Next()) {
461           if (update(anIndexIter.Key(), theExtDoc, theModified)) {
462             GeomShapePtr aFace = shape(anIndexIter.Key(), theExtDoc);
463             if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
464               aNewPackedMap->ChangeMap().Add(anIndexIter.Key());
465               aFaces.Add(aFace->impl<TopoDS_Shape>());
466             }
467           }
468         }
469         // then iterate all existing faces to find new faces
470         int aCurrentFacesNum = facesNum();
471         for(int a = 0; a < aCurrentFacesNum; a++) {
472           GeomShapePtr aFace = face(a);
473           if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
474             // add this one
475             int aNewFaceIndex = select(aFace, theExtDoc, -1);
476             if (aNewFaceIndex > 0) {
477               aNewPackedMap->ChangeMap().Add(aNewFaceIndex);
478             }
479           }
480         }
481         anIndices->ChangeMap(aNewPackedMap);
482       }
483       return aRes;
484     } else {
485       // For correct naming selection, put the shape into the naming structure.
486       // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
487       TNaming_Builder aBuilder(aLab);
488       aBuilder.Generated(shape()->impl<TopoDS_Shape>());
489     }
490     return shape() && !shape()->isNull();
491   }
492   // construction: identification by the results indexes, recompute faces and
493   // take the face that more close by the indexes
494   ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
495   FeaturePtr aContextFeature = document()->feature(aThisPtr);
496
497   // sketch sub-element
498   if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature).get())
499   {
500     // update the referenced object if it is sub
501     Handle(TDF_Reference) aRef;
502     if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
503       int aFaceIndex = aRef->Get().Tag();
504       // don't check selection ,since face may disappear, but the shape stays correct
505       Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified);
506     }
507     // getting a type of selected shape
508     Handle(TDataStd_Integer) aTypeAttr;
509     if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
510       return false;
511     }
512     TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
513     // selected indexes will be needed in each "if"
514     Handle(TDataStd_IntPackedMap) aSubIds;
515     std::shared_ptr<GeomAPI_Shape> aNewSelected;
516     bool aNoIndexes =
517       !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
518     // for now working only with composite features
519     CompositeFeaturePtr aComposite =
520       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
521     if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
522       return false;
523     }
524
525     if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) {
526       // compound is for the whole sketch selection
527       // If this is a wire with plane defined then it is a sketch-like object
528       if (!facesNum()) // no faces, update can not work correctly
529         return false;
530       // if there is no edges indexes, any face can be used: take the first
531       std::shared_ptr<GeomAPI_Shape> aNewSelected;
532       if (aNoIndexes) {
533         aNewSelected = face(0);
534       } else { // searching for most looks-like initial face by the indexes
535         // prepare edges of the current result for the fast searching
536         // curves and orientations of edges
537         NCollection_DataMap<Handle(Geom_Curve), int> allCurves;
538         const int aSubNum = aComposite->numberOfSubs();
539         for(int a = 0; a < aSubNum; a++) {
540           int aSubID = aComposite->subFeatureId(a);
541           if (aSubIds->Contains(aSubID)) {
542             FeaturePtr aSub = aComposite->subFeature(a);
543             const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
544             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
545             for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
546               ResultConstructionPtr aConstr =
547                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
548               if (aConstr->shape() && aConstr->shape()->isEdge()) {
549                 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
550                 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
551                 if (!anEdge.IsNull()) {
552                   Standard_Real aFirst, aLast;
553                   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
554                   // searching for orientation information
555                   int anOrient = 0;
556                   Handle(TDataStd_Integer) anInt;
557                   if (aLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)) {
558                     anOrient = anInt->Get();
559                   }
560                   allCurves.Bind(aCurve, anOrient);
561                 }
562               }
563             }
564           }
565         }
566         aNewSelected = Model_SelectionNaming::findAppropriateFace(
567           aThisPtr, allCurves, aShapeType == TopAbs_WIRE);
568       }
569       if (aNewSelected) { // store this new selection
570         select(aNewSelected, theExtDoc, theIndex);
571         theModified = true;
572         return true;
573       } else {
574         // if the selection is not found, put the empty shape:
575         // it's better to have disappeared shape, than the old, the lost one
576         TNaming_Builder anEmptyBuilder(aLab);
577         return false;
578       }
579     } else if (aShapeType == TopAbs_EDGE) {
580       // just reselect the edge by the id
581       const int aSubNum = aComposite->numberOfSubs();
582       for(int a = 0; a < aSubNum; a++) {
583         // if aSubIds take any, the first appropriate
584         if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
585           // found the appropriate feature
586           FeaturePtr aFeature = aComposite->subFeature(a);
587           std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
588             aFeature->results().cbegin();
589           for(;aResIter != aFeature->results().cend(); aResIter++) {
590             ResultConstructionPtr aRes =
591               std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
592             if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
593               select(aRes->shape(), theExtDoc, theIndex);
594               theModified = true;
595               return true;
596             }
597           }
598         }
599       }
600     } else if (aShapeType == TopAbs_VERTEX) {
601       // just reselect the vertex by the id of edge
602       const int aSubNum = aComposite->numberOfSubs();
603       for(int a = 0; a < aSubNum; a++) {
604         // if aSubIds take any, the first appropriate
605         int aFeatureID = aComposite->subFeatureId(a);
606         if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
607           aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
608           aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
609             // searching for deltas
610             int aVertexNum = 0;
611             if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
612             else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
613             // found the feature with appropriate edge
614             FeaturePtr aFeature = aComposite->subFeature(a);
615             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
616               aFeature->results().cbegin();
617             for(;aResIter != aFeature->results().cend(); aResIter++) {
618               ResultConstructionPtr aRes =
619                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
620               if (aRes && aRes->shape()) {
621                 if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
622                   select(aRes->shape(), theExtDoc, theIndex);
623                   theModified = true;
624                   return true;
625                 } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
626                   const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
627                   int aVIndex = 1;
628                   for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
629                     if (aVIndex == aVertexNum) { // found!
630                       std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
631                       aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
632                       select(aVertex, theExtDoc, theIndex);
633                       theModified = true;
634                       return true;
635                     }
636                     aVIndex++;
637                   }
638                 }
639               }
640             }
641         }
642       }
643     }
644   } else { // simple construction element: the selected is that needed
645     select(shape(), theExtDoc, theIndex);
646     theModified = true;
647     return true;
648   }
649   return false; // unknown case
650 }