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