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