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