]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_ResultConstruction.cpp
Salome HOME
Make name of level-2 sub-shape in the sketch naming equal as it is named at level...
[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   //aName<<theContextFeature->name();
231   if (theSubShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole result for construction
232     //aName<<"/";
233     if (theSubShape.ShapeType() == TopAbs_FACE) aName<<"Face";
234     else if (theSubShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
235     else if (theSubShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
236     else if (theSubShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
237
238     // make a composite name from all sub-elements indexes: "1_2_3_4"
239     TColStd_MapIteratorOfPackedMapOfInteger aRef(aRefs);
240     for(; aRef.More(); aRef.Next()) {
241       aName<<"-"<<aSubNames[aRef.Key()];
242       if (anOrientations.find(aRef.Key()) != anOrientations.end()) {
243         if (anOrientations[aRef.Key()] == 1)
244           aName<<"f";
245         else if (anOrientations[aRef.Key()] == -1)
246           aName<<"r";
247       }
248     }
249   }
250   if (!theRefs.IsNull()) {
251     Handle(TColStd_HPackedMapOfInteger) aMap = new TColStd_HPackedMapOfInteger(aRefs);
252     theRefs->ChangeMap(aMap);
253   }
254   return aName.str();
255 }
256
257 // stores shape and name on sub-label of the main stored shape
258 static void saveSubName(TDF_Label& theLab, const bool isSelectionMode, const TopoDS_Shape& aSub,
259   std::shared_ptr<Model_Document> theDoc, std::string theFullName)
260 {
261   TNaming_Builder aBuilder(theLab);
262   if (isSelectionMode)
263     aBuilder.Select(aSub, aSub);
264   else
265     aBuilder.Generated(aSub);
266   theDoc->addNamingName(theLab, theFullName.c_str());
267   TDataStd_Name::Set(theLab, theFullName.c_str());
268 }
269
270
271 TDF_Label Model_ResultConstruction::startLabel(
272   const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theExternal)
273 {
274   theExternal = theExtDoc.get() && theExtDoc != document();
275   if (theExternal) { // external document is used
276     std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(theExtDoc);
277     return aDoc->extConstructionsLabel();
278   }
279   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
280   return aData->label();
281 }
282
283 int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSubShape,
284   const std::shared_ptr<ModelAPI_Document> theExtDoc, const int theIndex)
285 {
286   int anIndex; // resulting index of the sub-label
287   TopoDS_Shape aSubShape;
288   if (theSubShape.get()) {
289     aSubShape = theSubShape->impl<TopoDS_Shape>();
290   } else if (shape().get()) {
291     aSubShape = shape()->impl<TopoDS_Shape>();
292   }
293   // if external document requires this selection, put the naming structures to this doc
294   // to support the naming mechanism in this document correctly
295   bool anExternal;
296   TDF_Label aDataLab = startLabel(theExtDoc, anExternal);
297   if (theIndex == -1) {
298     anIndex = anExternal ? 2 : 1; // for the external doc don't mind about the main shape
299
300     if (theSubShape.get() || anExternal) { // searching for already selected sub (or whole for ext)
301       // iterate all the already presented shapes to see the same
302       TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
303       for(; aSubsIter.More(); aSubsIter.Next()) {
304         const TDF_Label aLab = aSubsIter.Value();
305         if (aLab.Tag() == 1) // skip the root shape label
306           continue;
307         Handle(TNaming_NamedShape) aNS;
308         if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
309           if (aNS->Get().IsSame(aSubShape)) {
310             return aLab.Tag() - 1; // found exactly the needed shape, nothing else to do
311           }
312         }
313         anIndex = aLab.Tag(); // searching for the latest index
314       }
315       anIndex = (anIndex == 1) ? 2 : (anIndex + 1); // next after 1-root, or next after all
316     }
317   } else {
318     anIndex = theIndex + 1;
319   }
320
321   // set the naming structure at index
322   TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True);
323
324   // if the subshape is part of a result face, select the whole face (#1997)
325   bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label
326   if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) {
327     for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
328       TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
329       for(; anExp.More(); anExp.Next()) {
330         if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
331           // here just store the face index (to update face if update of edge is needed)
332           TNaming_Builder aBuilder(aLab);
333           aBuilder.Select(aSubShape, aSubShape);
334           int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
335           TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
336           isSelectionMode = true;
337           break;
338         }
339       }
340     }
341   }
342
343   // external full result is not identified by index == 0, so, add here the ID
344   if (!theSubShape.get()) {
345     TDataStd_UAttribute::Set(aLab, kFULL_RESULT_ID);
346     // empty NS
347     TNaming_Builder aBuilder(aLab);
348     // store all sub-faces naming since faces may be used for extrusion, where all edges are needed
349     Handle(TDataStd_IntPackedMap) anIndices = TDataStd_IntPackedMap::Set(aLab);
350     std::list<int> aFacesIndexes;
351     for(int a = 0; a < facesNum(); a++) {
352       anIndices->Add(select(face(a), theExtDoc, -1));
353     }
354     return anIndex - 1;
355   }
356
357   { // this to have erased Builder after the shape was generated (NS on this label may be changed)
358     TNaming_Builder aBuilder(aLab);
359     if (aSubShape.IsNull()) {
360       return anIndex - 1; // just keep empty named shape
361     }
362     // wire never happens as sub, it must be generated to be found
363     // by SelectionNaming TNaming_Tool::NamedShape
364     if (isSelectionMode && aSubShape.ShapeType() != TopAbs_WIRE) {
365       aBuilder.Select(aSubShape, aSubShape);
366     } else {
367       aBuilder.Generated(aSubShape);
368     }
369   }
370
371   if (anIndex == 1 && isInfinite()) { // infinitive results has no sub-selection
372     return anIndex - 1;
373   }
374   ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
375   FeaturePtr aThisFeature = document()->feature(aThisPtr);
376   CompositeFeaturePtr aComposite =
377     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
378   if (!aComposite || aComposite->numberOfSubs() == 0) {
379     // saving of context is enough: result construction contains exactly the needed shape
380     return anIndex - 1;
381   }
382
383   // identify the results of sub-object of the composite by edges
384   // save type of the selected shape in integer attribute
385   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
386   TDataStd_Integer::Set(aLab, (int)aShapeType);
387   gp_Pnt aVertexPos;
388   TColStd_MapOfTransient allCurves;
389   if (aShapeType == TopAbs_VERTEX) { // compare positions
390     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
391   } else {
392     for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
393       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
394       Standard_Real aFirst, aLast;
395       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
396       allCurves.Add(aCurve);
397     }
398   }
399   std::shared_ptr<Model_Document> aMyDoc =
400     std::dynamic_pointer_cast<Model_Document>(document());
401   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
402   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
403   const int aSubNum = aComposite->numberOfSubs();
404   for(int a = 0; a < aSubNum; a++) {
405     FeaturePtr aSub = aComposite->subFeature(a);
406     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
407     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
408     // there may be many shapes (circle and center): register if at least one is in selection
409     for(; aRes != aResults.cend(); aRes++) {
410       ResultConstructionPtr aConstr =
411         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
412       if (!aConstr->shape()) {
413         continue;
414       }
415       if (aShapeType != TopAbs_VERTEX) {
416         if (aConstr->shape()->isEdge()) {
417           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
418           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
419           if (!anEdge.IsNull()) {
420             Standard_Real aFirst, aLast;
421             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
422             if (allCurves.Contains(aCurve)) {
423               int anID = aComposite->subFeatureId(a);
424               if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
425                 // add edges to sub-label to support naming for edges selection
426                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
427                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
428                   TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
429                   Standard_Real aFirst, aLast;
430                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
431                   if (aFaceCurve == aCurve) {
432                     TDF_Label aSubLab = aLab.FindChild(anID);
433                     std::string aFullNameSub = fullName(aComposite, anEdge);
434                     saveSubName(aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub);
435
436                     int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
437                     if (anOrient != 0) {
438                       // store the orientation of edge relatively to face if needed
439                       TDataStd_Integer::Set(aSubLab, anOrient);
440                     }
441                   }
442                 }
443               } else { // put vertices of the selected edge to sub-labels
444                 // add edges to sub-label to support naming for edges selection
445                 int aTagIndex = anID + kSTART_VERTEX_DELTA;
446                 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
447                   anEdgeExp.More();
448                   anEdgeExp.Next(), aTagIndex += kSTART_VERTEX_DELTA) {
449                     TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
450                     TDF_Label aSubLab = aLab.FindChild(aTagIndex);
451                     std::string aFullNameSub = fullName(aComposite, aV);
452                     saveSubName(aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub);
453                 }
454               }
455             }
456           }
457         }
458       }
459     }
460   }
461   std::string aFullName = fullName(aComposite, aSubShape, aRefs);
462   // store the selected as primitive
463   registerSubShape(aLab, aSubShape, aFullName, 0, aMyDoc, isSelectionMode);
464   return anIndex - 1;
465 }
466
467 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape(const int theIndex,
468   const std::shared_ptr<ModelAPI_Document> theExtDoc)
469 {
470   std::shared_ptr<GeomAPI_Shape> aResult;
471   if (theIndex == 0)
472     return aResult; // the whole shape, so, NULL
473
474   bool isExt;
475   TDF_Label aLab = startLabel(theExtDoc, isExt).FindChild(theIndex + 1);
476   if (!aLab.IsNull()) { // index is not bad
477     Handle(TNaming_NamedShape) aSelection;
478     if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
479       TopoDS_Shape aSelShape = aSelection->Get();
480       if (aSelShape.IsNull())
481         return aResult; // shape equal to context => null
482       aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
483       aResult->setImpl(new TopoDS_Shape(aSelShape));
484     }
485   }
486
487   return aResult;
488 }
489
490 bool Model_ResultConstruction::update(const int theIndex,
491   const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theModified)
492 {
493   theModified = false;
494   bool anExt;
495   TDF_Label aLab = startLabel(theExtDoc, anExt).FindChild(theIndex + 1, Standard_True);
496   if (theIndex == 0 || aLab.IsAttribute(kFULL_RESULT_ID)) { // full for external same as index == 0
497     // it is just reference to construction, not sub-shape
498     // if there is a sketch, the sketch-naming must be updated
499     if (!isInfinite()) {
500       // update all faces named by the whole result
501       bool aRes = true;
502       Handle(TDataStd_IntPackedMap) anIndices;
503       if (aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), anIndices)) {
504         NCollection_Map<TopoDS_Shape> aFaces; // collect faces, updated in the tree
505         TColStd_MapIteratorOfPackedMapOfInteger anIndexIter(anIndices->GetMap());
506         Handle(TColStd_HPackedMapOfInteger) aNewPackedMap =
507           new TColStd_HPackedMapOfInteger; // with only faces that are ok
508         // iterate to find existing faces, updated
509         for(; anIndexIter.More(); anIndexIter.Next()) {
510           if (update(anIndexIter.Key(), theExtDoc, theModified)) {
511             GeomShapePtr aFace = shape(anIndexIter.Key(), theExtDoc);
512             if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
513               aNewPackedMap->ChangeMap().Add(anIndexIter.Key());
514               aFaces.Add(aFace->impl<TopoDS_Shape>());
515             }
516           }
517         }
518         // then iterate all existing faces to find new faces
519         int aCurrentFacesNum = facesNum();
520         for(int a = 0; a < aCurrentFacesNum; a++) {
521           GeomShapePtr aFace = face(a);
522           if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
523             // add this one
524             int aNewFaceIndex = select(aFace, theExtDoc, -1);
525             if (aNewFaceIndex > 0) {
526               aNewPackedMap->ChangeMap().Add(aNewFaceIndex);
527             }
528           }
529         }
530         anIndices->ChangeMap(aNewPackedMap);
531       }
532       return aRes;
533     } else {
534       // For correct naming selection, put the shape into the naming structure.
535       // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
536       TNaming_Builder aBuilder(aLab);
537       aBuilder.Generated(shape()->impl<TopoDS_Shape>());
538     }
539     return shape() && !shape()->isNull();
540   }
541   // construction: identification by the results indexes, recompute faces and
542   // take the face that more close by the indexes
543   ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
544   FeaturePtr aContextFeature = document()->feature(aThisPtr);
545
546   // sketch sub-element
547   if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature).get())
548   {
549     // update the referenced object if it is sub
550     Handle(TDF_Reference) aRef;
551     if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
552       int aFaceIndex = aRef->Get().Tag();
553       // don't check selection ,since face may disappear, but the shape stays correct
554       Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified);
555     }
556     // getting a type of selected shape
557     Handle(TDataStd_Integer) aTypeAttr;
558     if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
559       return false;
560     }
561     TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
562     // selected indexes will be needed in each "if"
563     Handle(TDataStd_IntPackedMap) aSubIds;
564     std::shared_ptr<GeomAPI_Shape> aNewSelected;
565     bool aNoIndexes =
566       !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
567     // for now working only with composite features
568     CompositeFeaturePtr aComposite =
569       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
570     if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
571       return false;
572     }
573
574     if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) {
575       // compound is for the whole sketch selection
576       // If this is a wire with plane defined then it is a sketch-like object
577       if (!facesNum()) // no faces, update can not work correctly
578         return false;
579       // if there is no edges indexes, any face can be used: take the first
580       std::shared_ptr<GeomAPI_Shape> aNewSelected;
581       if (aNoIndexes) {
582         aNewSelected = face(0);
583       } else { // searching for most looks-like initial face by the indexes
584         // prepare edges of the current result for the fast searching
585         // curves and orientations of edges
586         NCollection_DataMap<Handle(Geom_Curve), int> allCurves;
587         const int aSubNum = aComposite->numberOfSubs();
588         for(int a = 0; a < aSubNum; a++) {
589           int aSubID = aComposite->subFeatureId(a);
590           if (aSubIds->Contains(aSubID)) {
591             FeaturePtr aSub = aComposite->subFeature(a);
592             const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
593             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
594             for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
595               ResultConstructionPtr aConstr =
596                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
597               if (aConstr->shape() && aConstr->shape()->isEdge()) {
598                 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
599                 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
600                 if (!anEdge.IsNull()) {
601                   Standard_Real aFirst, aLast;
602                   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
603                   // searching for orientation information
604                   int anOrient = 0;
605                   Handle(TDataStd_Integer) anInt;
606                   if (aLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)) {
607                     anOrient = anInt->Get();
608                   }
609                   allCurves.Bind(aCurve, anOrient);
610                 }
611               }
612             }
613           }
614         }
615         aNewSelected = Model_SelectionNaming::findAppropriateFace(
616           aThisPtr, allCurves, aShapeType == TopAbs_WIRE);
617       }
618       if (aNewSelected) { // store this new selection
619         select(aNewSelected, theExtDoc, theIndex);
620         theModified = true;
621         return true;
622       } else {
623         // if the selection is not found, put the empty shape:
624         // it's better to have disappeared shape, than the old, the lost one
625         TNaming_Builder anEmptyBuilder(aLab);
626         return false;
627       }
628     } else if (aShapeType == TopAbs_EDGE) {
629       // just reselect the edge by the id
630       const int aSubNum = aComposite->numberOfSubs();
631       for(int a = 0; a < aSubNum; a++) {
632         // if aSubIds take any, the first appropriate
633         if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
634           // found the appropriate feature
635           FeaturePtr aFeature = aComposite->subFeature(a);
636           std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
637             aFeature->results().cbegin();
638           for(;aResIter != aFeature->results().cend(); aResIter++) {
639             ResultConstructionPtr aRes =
640               std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
641             if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
642               select(aRes->shape(), theExtDoc, theIndex);
643               theModified = true;
644               return true;
645             }
646           }
647         }
648       }
649     } else if (aShapeType == TopAbs_VERTEX) {
650       // just reselect the vertex by the id of edge
651       const int aSubNum = aComposite->numberOfSubs();
652       for(int a = 0; a < aSubNum; a++) {
653         // if aSubIds take any, the first appropriate
654         int aFeatureID = aComposite->subFeatureId(a);
655         if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
656           aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
657           aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
658             // searching for deltas
659             int aVertexNum = 0;
660             if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
661             else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
662             // found the feature with appropriate edge
663             FeaturePtr aFeature = aComposite->subFeature(a);
664             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
665               aFeature->results().cbegin();
666             for(;aResIter != aFeature->results().cend(); aResIter++) {
667               ResultConstructionPtr aRes =
668                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
669               if (aRes && aRes->shape()) {
670                 if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
671                   select(aRes->shape(), theExtDoc, theIndex);
672                   theModified = true;
673                   return true;
674                 } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
675                   const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
676                   int aVIndex = 1;
677                   for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
678                     if (aVIndex == aVertexNum) { // found!
679                       std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
680                       aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
681                       select(aVertex, theExtDoc, theIndex);
682                       theModified = true;
683                       return true;
684                     }
685                     aVIndex++;
686                   }
687                 }
688               }
689             }
690         }
691       }
692     }
693   } else { // simple construction element: the selected is that needed
694     select(shape(), theExtDoc, theIndex);
695     theModified = true;
696     return true;
697   }
698   return false; // unknown case
699 }