Salome HOME
fd7b72f131e29469f04d806565593f611249aaf2
[modules/shaper.git] / src / Model / Model_SelectionNaming.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "Model_SelectionNaming.h"
22 #include "Model_Document.h"
23 #include "Model_Objects.h"
24 #include "Model_Data.h"
25 #include <ModelAPI_Feature.h>
26 #include <Events_InfoMessage.h>
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_ResultPart.h>
29 #include <ModelAPI_ResultConstruction.h>
30 #include <ModelAPI_CompositeFeature.h>
31 #include <ModelAPI_ResultBody.h>
32 #include <GeomAPI_Wire.h>
33
34 #include <TopoDS_Iterator.hxx>
35 #include <TopoDS.hxx>
36 #include <TopoDS_Compound.hxx>
37 #include <TopExp.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopTools_ListOfShape.hxx>
40 #include <TopTools_MapOfShape.hxx>
41 #include <TopTools_IndexedMapOfShape.hxx>
42 #include <TopTools_ListIteratorOfListOfShape.hxx>
43 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
44 #include <TopTools_MapIteratorOfMapOfShape.hxx>
45 #include <BRep_Builder.hxx>
46 #include <TNaming_Iterator.hxx>
47 #include <TNaming_Tool.hxx>
48 #include <TNaming_NamedShape.hxx>
49 #include <TNaming_Localizer.hxx>
50 #include <TNaming_SameShapeIterator.hxx>
51 #include <TDataStd_Name.hxx>
52 #include <TColStd_MapOfTransient.hxx>
53 #include <algorithm>
54 #include <stdexcept>
55
56 #ifdef DEB_NAMING
57 #include <BRepTools.hxx>
58 #endif
59
60 Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab)
61 {
62   myLab = theSelectionLab;
63 }
64
65 // searches named shape by the shape in the given document (identified by the label)
66 // tries to find s shape nearest to the context-label
67 static Handle(TNaming_NamedShape) shapeToNS(const TDF_Label theLabAccess,
68   const TopoDS_Shape& theShape, const TDF_Label& theContextLab)
69 {
70   Handle(TNaming_NamedShape) aResult;
71   if (!TNaming_Tool::HasLabel(theLabAccess, theShape)) // no shape in the document
72     return aResult;
73   int aContextLabDepth = theContextLab.IsNull() ? 100 : theContextLab.Depth();
74   TNaming_SameShapeIterator aNSIter(theShape, theLabAccess);
75   for(; aNSIter.More(); aNSIter.Next()) {
76     TDF_Label aLabel = aNSIter.Label();
77     Handle(TNaming_NamedShape) aNS;
78     if (aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
79       if (aNS->Evolution() != TNaming_SELECTED && aNS->Evolution() != TNaming_DELETE) {
80         // check this is new shape in this named shape
81         bool aIsNew = false;
82         for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next())
83           if (!aNSIter.NewShape().IsNull() && aNSIter.NewShape().IsSame(theShape))
84             aIsNew = true;
85         if (!aIsNew)
86           continue;
87         // check this is the context-shape
88         while(aLabel.Depth() > aContextLabDepth)
89           aLabel = aLabel.Father();
90         if (aLabel.IsEqual(theContextLab))
91           return aNS;
92         if (aResult.IsNull()) // take the first, otherwise it will get shapes from results, etc
93           aResult = aNS; // keep some result anyway - if there are no context labels return any
94       }
95     }
96   }
97   return aResult;
98 }
99
100 std::string Model_SelectionNaming::getShapeName(
101   std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape,
102   ResultPtr& theContext, const bool theAnotherDoc, const bool theWholeContext)
103 {
104   std::string aName;
105   // add the result name to the name of the shape
106   // (it was in BodyBuilder, but did not work on Result rename)
107   bool isNeedContextName = theContext->shape().get() != NULL;
108   // check if the subShape is already in DF
109   std::shared_ptr<Model_Data> aData =
110     std::dynamic_pointer_cast<Model_Data>(theContext->data());
111   TDF_Label aContextDataLab(aData.get() && aData->isValid() ? aData->label() : TDF_Label());
112   Handle(TNaming_NamedShape) aNS = shapeToNS(myLab, theShape, aContextDataLab);
113   Handle(TDataStd_Name) anAttr;
114   if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document
115     if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
116       if (isNeedContextName && aData && aContextDataLab.IsEqual(aNS->Label())) {
117         // do nothing because this context name will be added later in this method
118       } else {
119         aName = TCollection_AsciiString(anAttr->Get()).ToCString();
120         // indexes are added to sub-shapes not primitives
121         // (primitives must not be located at the same label)
122         if(!aName.empty() && aNS->Evolution() != TNaming_PRIMITIVE && isNeedContextName) {
123           const TDF_Label& aLabel = aNS->Label();
124           static const std::string aPostFix("_");
125           TNaming_Iterator anItL(aNS);
126           for(int i = 1; anItL.More(); anItL.Next(), i++) {
127             // in #1766 IsEqual produced no index of the face
128             if(anItL.NewShape().IsSame(theShape)) {
129               aName += aPostFix;
130               aName += TCollection_AsciiString (i).ToCString();
131               break;
132             }
133           }
134         }
135         // if a shape is under another context, use this name, not theContext
136         std::shared_ptr<Model_Data> aContextData =
137           std::dynamic_pointer_cast<Model_Data>(theContext->data());
138         // for constructions the naming is in arguments and has no evolution, so, apply this only
139         // for bodies
140         if (isNeedContextName && theContext->groupName() == ModelAPI_ResultBody::group() &&
141             !aNS->Label().IsDescendant(aContextData->label())) {
142           isNeedContextName = false;
143           TDF_Label aNSDataLab = aNS->Label();
144           while(aNSDataLab.Depth() != 7 && aNSDataLab.Depth() > 5)
145             aNSDataLab = aNSDataLab.Father();
146           ObjectPtr aNewContext = theDoc->objects()->object(aNSDataLab);
147           if (!aNewContext.get() && aNSDataLab.Depth() == 7) {
148             aNSDataLab = aNSDataLab.Father().Father();
149             aNewContext = theDoc->objects()->object(aNSDataLab);
150           }
151           if (aNewContext.get()) {
152             // this is to avoid duplicated names of results problem
153             std::string aContextName = aNewContext->data()->name();
154             // myLab corresponds to the current time
155             TDF_Label aCurrentLab = myLab;
156             while(aCurrentLab.Depth() > 3)
157               aCurrentLab = aCurrentLab.Father();
158
159             int aNumInHistoryNames =
160               theDoc->numberOfNameInHistory(aNewContext, aCurrentLab);
161             while(aNumInHistoryNames > 1) { // add "_" before name the needed number of times
162               aContextName = "_" + aContextName;
163               aNumInHistoryNames--;
164             }
165
166             aName = aContextName + "/" + aName;
167           }
168         }
169       }
170     }
171   }
172
173   // Name is empty and this is full context, it just add the whole context name that must be added
174   bool isEmptyName = aName.empty();
175   if (isNeedContextName && (!isEmptyName || theWholeContext)) {
176     aName = theContext->data()->name() + (isEmptyName ? "" : ("/" + aName));
177     if (theAnotherDoc)
178       aName = theContext->document()->kind() + "/" + aName; // PartSet
179   }
180   return aName;
181 }
182
183 bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap)
184 {
185   // a trivial case: F1 & F2,  aNumber = 1, i.e. intersection gives 1 edge.
186   TopoDS_Compound aCmp;
187   BRep_Builder BB;
188   BB.MakeCompound(aCmp);
189   TopTools_ListIteratorOfListOfShape it(theAncestors);
190   for(;it.More();it.Next()) {
191     if (theSMap.Contains(it.Value()))
192       continue;
193     BB.Add(aCmp, it.Value());
194     theSMap.Add(it.Value());
195   }
196   int aNumber(0);
197   TopTools_IndexedDataMapOfShapeListOfShape aMap2;
198   TopExp::MapShapesAndAncestors(aCmp, TopAbs_EDGE, TopAbs_FACE, aMap2);
199   for (int i = 1; i <= aMap2.Extent(); i++) {
200     const TopoDS_Shape& aKey = aMap2.FindKey(i);
201     const TopTools_ListOfShape& anAncestors = aMap2.FindFromIndex(i);
202     if(anAncestors.Extent() > 1) aNumber++;
203   }
204   if(aNumber > 1) return false;
205   return true;
206 }
207
208 const TopoDS_Shape findCommonShape(
209   const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList)
210 {
211   if(theList.Extent() < 1) {
212     return TopoDS_Shape();
213   } else if (theList.Extent() == 1) { // check that sub-shape is bounded by this alone shape
214     TopTools_MapOfShape aSubsInShape;
215     TopExp_Explorer anExp(theList.First(), theType);
216     for(; anExp.More(); anExp.Next()) {
217       if (aSubsInShape.Contains(anExp.Current())) { // found duplicate
218         return anExp.Current();
219       }
220       aSubsInShape.Add(anExp.Current());
221     }
222   }
223
224   // Store in maps sub-shapes from each face.
225   std::vector<TopTools_MapOfShape> aVec;
226   for(TopTools_ListIteratorOfListOfShape anIt(theList); anIt.More(); anIt.Next()) {
227     const TopoDS_Shape aFace = anIt.Value();
228     TopTools_MapOfShape aMap;
229     for(TopExp_Explorer anExp(aFace, theType); anExp.More(); anExp.Next()) {
230       const TopoDS_Shape& aSubShape = anExp.Current();
231       aMap.Add(anExp.Current());
232     }
233     aVec.push_back(aMap);
234   }
235
236   // Find sub-shape shared between all faces.
237   TopoDS_Shape aSharedShape;
238   for(TopTools_MapIteratorOfMapOfShape anIt(aVec[0]); anIt.More(); anIt.Next()) {
239     const TopoDS_Shape& aSubShape = anIt.Value();
240     int aSharedNb = 1;
241     for(int anIndex = 1; anIndex < aVec.size(); ++anIndex) {
242       if(aVec[anIndex].Contains(aSubShape)) {
243         ++aSharedNb;
244       }
245     }
246     if(aSharedNb == theList.Extent()) {
247       if(aSharedShape.IsNull()) {
248         aSharedShape = aSubShape;
249       } else {
250         // More than one shape shared between all faces, return null shape in this case.
251         return TopoDS_Shape();
252       }
253     }
254   }
255
256   return aSharedShape;
257 }
258
259 std::string Model_SelectionNaming::vertexNameByEdges(TopoDS_Shape theContext, TopoDS_Shape theSub,
260   std::shared_ptr<Model_Document> theDoc, ResultPtr& theContextRes, const bool theAnotherDoc)
261 {
262   std::string aResult;
263   TopTools_IndexedDataMapOfShapeListOfShape aMap;
264   TopExp::MapShapesAndAncestors(theContext, TopAbs_VERTEX, TopAbs_EDGE, aMap);
265   const TopTools_ListOfShape& aList22  = aMap.FindFromKey(theSub);
266   if(aList22.Extent() >= 2)  { // regular solution
267     TopTools_MapOfShape aFMap;
268     TopTools_ListOfShape aListE;
269     TopTools_ListIteratorOfListOfShape itl2(aList22);
270     for (int i = 1;itl2.More();itl2.Next(),i++) {
271       if(aFMap.Add(itl2.Value()))
272         aListE.Append(itl2.Value());
273     }
274     TopTools_ListIteratorOfListOfShape itl(aListE);
275     for (int i = 1;itl.More();itl.Next(),i++) {
276       const TopoDS_Shape& anEdge = itl.Value();
277       std::string anEdgeName = getShapeName(theDoc, anEdge, theContextRes, theAnotherDoc, false);
278       if (anEdgeName.empty()) { // edge is not in DS
279         aResult.clear();
280         return aResult;
281       }
282       if(i == 1)
283         aResult = anEdgeName;
284       else
285         aResult += "&" + anEdgeName;
286     }
287   }
288   return aResult;
289 }
290
291 std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
292   std::shared_ptr<GeomAPI_Shape> theSubSh, const std::string& theDefaultName,
293   const bool theAnotherDoc)
294 {
295   std::string aName("Undefined name");
296   if(!theContext.get()
297       || !theContext->shape().get()
298       || theContext->shape()->isNull()) {
299     return !theDefaultName.empty() ? theDefaultName : aName;
300   }
301
302   // if it is in result of another part
303   std::shared_ptr<Model_Document> aDoc =
304     std::dynamic_pointer_cast<Model_Document>(theContext->document());
305   if (theContext->groupName() == ModelAPI_ResultPart::group()) {
306     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(theContext);
307     int anIndex;
308     if (theSubSh.get())
309       return aPart->data()->name() + "/" + aPart->nameInPart(theSubSh, anIndex);
310     else
311       return aPart->data()->name();
312   }
313
314   if (!theSubSh.get() || theSubSh->isNull()) { // no subshape, so just the whole feature name
315     // but if it is in another Part, add this part name
316     std::string aPartName;
317     if (theAnotherDoc)
318       aPartName = theContext->document()->kind() + "/"; // PartSet
319     return aPartName + theContext->data()->name();
320   }
321   TopoDS_Shape aSubShape = theSubSh->impl<TopoDS_Shape>();
322   TopoDS_Shape aContext  = theContext->shape()->impl<TopoDS_Shape>();
323 #ifdef DEB_NAMING
324   if(aSubShape.ShapeType() == TopAbs_COMPOUND) {
325     BRepTools::Write(aSubShape, "Selection.brep");
326     BRepTools::Write(aContext, "Context.brep");
327   }
328 #endif
329   aName = getShapeName(aDoc, aSubShape, theContext, theAnotherDoc,
330     theContext->shape()->isEqual(theSubSh));
331
332   if(aName.empty() ) { // not in the document!
333     TopAbs_ShapeEnum aType = aSubShape.ShapeType();
334     switch (aType) {
335     case TopAbs_FACE:
336       // the Face should be in DF. If it is not the case, it is an error ==> to be debugged
337       break;
338     case TopAbs_EDGE:
339       {
340         // name structure: F1 & F2 [& F3 & F4],
341         // where F1 & F2 the faces which gives the Edge in trivial case
342         // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces
343         if (BRep_Tool::Degenerated(TopoDS::Edge(aSubShape))) {
344           aName = "Degenerated_Edge";
345           break;
346         }
347         TopTools_IndexedDataMapOfShapeListOfShape aMap;
348         TopExp::MapShapesAndAncestors(aContext, TopAbs_EDGE, TopAbs_FACE, aMap);
349         TopTools_IndexedMapOfShape aSMap; // map for ancestors of the sub-shape
350         bool isTrivialCase(true);
351         if(aMap.Contains(aSubShape)) {
352           const TopTools_ListOfShape& anAncestors = aMap.FindFromKey(aSubShape);
353           // check that it is not a trivial case (F1 & F2: aNumber = 1)
354           isTrivialCase = isTrivial(anAncestors, aSMap);
355           if (!isTrivialCase) { // another try: check that common shape can be processed anyway
356             isTrivialCase = !findCommonShape(TopAbs_EDGE, anAncestors).IsNull();
357           }
358         } else
359           break;
360         TopTools_ListOfShape aListOfNbs;
361         if(!isTrivialCase) { // find Neighbors
362           TNaming_Localizer aLocalizer;
363           TopTools_MapOfShape aMap3;
364           aLocalizer.FindNeighbourg(aContext, aSubShape, aMap3);
365           //int n = aMap3.Extent();
366           TopTools_MapIteratorOfMapOfShape it(aMap3);
367           for(;it.More();it.Next()) {
368             const TopoDS_Shape& aNbShape = it.Key(); // neighbor edge
369             //TopAbs_ShapeEnum aType = aNbShape.ShapeType();
370             const TopTools_ListOfShape& aList  = aMap.FindFromKey(aNbShape);
371             TopTools_ListIteratorOfListOfShape it2(aList);
372             for(;it2.More();it2.Next()) {
373               if(aSMap.Contains(it2.Value())) continue; // skip this Face
374               aListOfNbs.Append(it2.Value());
375             }
376           }
377         }  // else a trivial case
378
379         // build name of the sub-shape Edge
380         for(int i=1; i <= aSMap.Extent(); i++) {
381           const TopoDS_Shape& aFace = aSMap.FindKey(i);
382           std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false);
383           if(i == 1)
384             aName = aFaceName;
385           else
386             aName += "&" + aFaceName;
387         }
388         TopTools_ListIteratorOfListOfShape itl(aListOfNbs);
389         for (;itl.More();itl.Next()) {
390           std::string aFaceName = getShapeName(aDoc, itl.Value(), theContext, theAnotherDoc, false);
391           aName += "&" + aFaceName;
392         }
393       }
394       break;
395
396     case TopAbs_VERTEX:
397       // name structure (Monifold Topology):
398       // 1) F1 | F2 | F3 - intersection of 3 faces defines a vertex - trivial case.
399       // 2) F1 | F2 | F3 [|F4 [|Fn]] - redundant definition,
400       //                               but it should be kept as is to obtain safe recomputation
401       // 2) F1 | F2      - intersection of 2 faces definses a vertex - applicable for case
402       //                   when 1 faces is cylindrical, conical, spherical or revolution and etc.
403       // 3) E1 | E2 | E3 - intersection of 3 edges defines a vertex - when we have case of a shell
404       //                   or compound of 2 open faces.
405       // 4) E1 | E2      - intesection of 2 edges defines a vertex - when we have a case of
406       //                   two independent edges (wire or compound)
407       // implemented 2 first cases
408       {
409         TopTools_IndexedDataMapOfShapeListOfShape aMap;
410         TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_FACE, aMap);
411         TopTools_ListOfShape aList;
412         TopTools_MapOfShape aFMap;
413         // simetimes when group is moved in history, naming may be badly updated, so
414         // avoid crash in FindFromKey (issue 1842)
415         if (aMap.Contains(aSubShape)) {
416           const TopTools_ListOfShape& aList2  = aMap.FindFromKey(aSubShape);
417           // fix is below
418           TopTools_ListIteratorOfListOfShape itl2(aList2);
419           for (int i = 1;itl2.More();itl2.Next(),i++) {
420             if(aFMap.Add(itl2.Value()))
421               aList.Append(itl2.Value());
422           }
423         } else
424           break;
425         int n = aList.Extent();
426         bool isByFaces = n >= 3;
427         if (isByFaces) { // check that by faces vertex is identified uniquly (2317)
428           TopoDS_Shape aVertex = findCommonShape(TopAbs_VERTEX, aList);
429           isByFaces = !aVertex.IsNull() && aVertex.ShapeType() == TopAbs_VERTEX;
430         }
431
432         if(!isByFaces) { // open topology case or Compound case => via edges
433           aName = vertexNameByEdges(aContext, aSubShape, aDoc, theContext, theAnotherDoc);
434           isByFaces = aName.empty();
435           if (isByFaces) { // try to find a vertex in sketch faces
436             ResultConstructionPtr aConstr =
437               std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theContext);
438             if (aConstr.get() && aConstr->facesNum()) {
439               for(int aFace = aConstr->facesNum() - 1; isByFaces && aFace >= 0; aFace--) {
440                 std::shared_ptr<GeomAPI_Face> aGFace = aConstr->face(aFace);
441                 aName = vertexNameByEdges(aGFace->impl<TopoDS_Face>(), aSubShape,
442                   aDoc, theContext, theAnotherDoc);
443                 isByFaces = aName.empty();
444               }
445             }
446           }
447         }
448
449         if (isByFaces) {
450           TopTools_ListIteratorOfListOfShape itl(aList);
451           for (int i = 1;itl.More();itl.Next(),i++) {
452             const TopoDS_Shape& aFace = itl.Value();
453             std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false);
454             if(i == 1)
455               aName = aFaceName;
456             else
457               aName += "&" + aFaceName;
458           }
459         }
460       }
461       break;
462     }
463   }
464   return aName;
465 }
466
467 TopAbs_ShapeEnum translateType (const std::string& theType)
468 {
469   // map from the textual shape types to OCCT enumeration
470   static std::map<std::string, TopAbs_ShapeEnum> aShapeTypes;
471
472   if(aShapeTypes.size() == 0) {
473     aShapeTypes["compound"]   = TopAbs_COMPOUND;
474     aShapeTypes["compounds"]  = TopAbs_COMPOUND;
475     aShapeTypes["compsolid"]  = TopAbs_COMPSOLID;
476     aShapeTypes["compsolids"] = TopAbs_COMPSOLID;
477     aShapeTypes["solid"]      = TopAbs_SOLID;
478     aShapeTypes["solids"]     = TopAbs_SOLID;
479     aShapeTypes["shell"]      = TopAbs_SHELL;
480     aShapeTypes["shells"]     = TopAbs_SHELL;
481     aShapeTypes["face"]       = TopAbs_FACE;
482     aShapeTypes["faces"]      = TopAbs_FACE;
483     aShapeTypes["wire"]       = TopAbs_WIRE;
484     aShapeTypes["wires"]      = TopAbs_WIRE;
485     aShapeTypes["edge"]       = TopAbs_EDGE;
486     aShapeTypes["edges"]      = TopAbs_EDGE;
487     aShapeTypes["vertex"]     = TopAbs_VERTEX;
488     aShapeTypes["vertices"]   = TopAbs_VERTEX;
489     aShapeTypes["COMPOUND"]   = TopAbs_COMPOUND;
490     aShapeTypes["COMPOUNDS"]  = TopAbs_COMPOUND;
491     aShapeTypes["COMPSOLID"]  = TopAbs_COMPSOLID;
492     aShapeTypes["COMPSOLIDS"] = TopAbs_COMPSOLID;
493     aShapeTypes["SOLID"]      = TopAbs_SOLID;
494     aShapeTypes["SOLIDS"]     = TopAbs_SOLID;
495     aShapeTypes["SHELL"]      = TopAbs_SHELL;
496     aShapeTypes["SHELLS"]     = TopAbs_SHELL;
497     aShapeTypes["FACE"]       = TopAbs_FACE;
498     aShapeTypes["FACES"]      = TopAbs_FACE;
499     aShapeTypes["WIRE"]       = TopAbs_WIRE;
500     aShapeTypes["WIRES"]      = TopAbs_WIRE;
501     aShapeTypes["EDGE"]       = TopAbs_EDGE;
502     aShapeTypes["EDGES"]      = TopAbs_EDGE;
503     aShapeTypes["VERTEX"]     = TopAbs_VERTEX;
504     aShapeTypes["VERTICES"]   = TopAbs_VERTEX;
505   }
506   if (aShapeTypes.find(theType) != aShapeTypes.end())
507     return aShapeTypes[theType];
508   Events_InfoMessage("Model_SelectionNaming",
509     "Shape type defined in XML is not implemented!").send();
510   return TopAbs_SHAPE;
511 }
512
513 const TopoDS_Shape getShapeFromNS(
514   const std::string& theSubShapeName, Handle(TNaming_NamedShape) theNS)
515 {
516   TopoDS_Shape aSelection;
517   std::string::size_type n = theSubShapeName.rfind('/');
518   if (n == std::string::npos) n = -1;
519   std::string aSubString = theSubShapeName.substr(n + 1);
520   n = aSubString.rfind('_');
521   int indx = 1;
522   if (n != std::string::npos) {// for primitives this is a first
523     // if we have here the same name as theSubShapeName, there is no index in compound, it is whole
524     Handle(TDataStd_Name) aName;
525     if (!theNS->Label().FindAttribute(TDataStd_Name::GetID(), aName) ||
526         aName->Get() != aSubString.c_str()) {
527       aSubString = aSubString.substr(n+1);
528       indx = atoi(aSubString.c_str());
529     }
530   }
531
532   TNaming_Iterator anItL(theNS);
533   for(int i = 1; anItL.More(); anItL.Next(), i++) {
534     if (i == indx) {
535       return anItL.NewShape();
536     }
537   }
538   return aSelection;
539 }
540
541 const TopoDS_Shape findFaceByName(
542   const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc,
543   const ResultPtr theDetectedContext, bool theContextIsUnique)
544 {
545   TopoDS_Shape aFace;
546   std::string aSubString = theSubShapeName;
547
548   static const ResultPtr anEmpty;
549   TDF_Label aLabel = theDoc->findNamingName(aSubString,
550     theContextIsUnique ? theDetectedContext : anEmpty);
551   if (aLabel.IsNull()) { // try to remove additional artificial suffix
552     std::string::size_type n = aSubString.rfind('_');
553     if (n != std::string::npos) {
554       aSubString = aSubString.substr(0, n);
555       aLabel = theDoc->findNamingName(aSubString,
556         theContextIsUnique ? theDetectedContext : anEmpty);
557     }
558   }
559   if(aLabel.IsNull()) return aFace;
560   Handle(TNaming_NamedShape) aNS;
561   if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
562     aFace = getShapeFromNS(theSubShapeName, aNS);
563   }
564   return aFace;
565 }
566
567 size_t ParseName(const std::string& theSubShapeName,   std::list<std::string>& theList)
568 {
569   std::string aName = theSubShapeName;
570   std::string aLastName = aName;
571   size_t n1(0), n2(0); // n1 - start position, n2 - position of the delimiter
572   while ((n2 = aName.find('&', n1)) != std::string::npos) {
573     const std::string aName1 = aName.substr(n1, n2 - n1); //name of face
574     theList.push_back(aName1);
575     n1 = n2 + 1;
576     aLastName = aName.substr(n1);
577   }
578   if(!aLastName.empty())
579     theList.push_back(aLastName);
580   return theList.size();
581 }
582
583 std::string getContextName(const std::string& theSubShapeName)
584 {
585   std::string aName;
586   std::string::size_type n = theSubShapeName.find('/');
587   if (n == std::string::npos) return theSubShapeName;
588   aName = theSubShapeName.substr(0, n);
589   return aName;
590 }
591
592 /// Parses naming name of sketch sub-elements: takes indices and orientation
593 /// (if theOriented = true) from this name. Map theIDs constains indices ->
594 /// orientations and start/end vertices: negative is reversed, 2 - start, 3 - end
595 bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names
596   const std::string& theName, const char* theShapeType,
597   std::map<int, int>& theIDs, const bool theOriented = false)
598 {
599   // collect all IDs in the name
600   std::map<std::string, int> aNames; // short name of sub -> ID of sub of theComp
601   const int aSubNum = theComp->numberOfSubs();
602   for(int a = 0; a < aSubNum; a++) {
603     FeaturePtr aSub = theComp->subFeature(a);
604     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
605     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
606     // there may be many shapes (circle and center)
607     for(; aRes != aResults.cend(); aRes++) {
608       ResultConstructionPtr aConstr =
609         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
610       if (aConstr.get()) {
611         aNames[Model_SelectionNaming::shortName(aConstr)] = theComp->subFeatureId(a);
612       }
613     }
614   }
615
616   size_t aPrevPos = theName.find("/") + 1, aLastNamePos;
617   bool isShape = false; // anyway the first world must be 'Vertex'
618   do {
619     aLastNamePos = theName.find('-', aPrevPos);
620     std::string anID = theName.substr(aPrevPos, aLastNamePos - aPrevPos);
621     if (!isShape) {
622       if (anID != theShapeType)
623         return false;
624       isShape = true;
625     } else {
626       int anOrientation = 1; // default
627       if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r'
628         std::string::iterator aSymbol = anID.end() - 1;
629         if (*aSymbol == 'r') anOrientation = -1;
630         anID.erase(aSymbol); // remove last symbol
631       }
632       // check start/end symbols
633       std::string::iterator aBack = anID.end() - 1;
634       if (*aBack == 's') {
635         anOrientation *= 2;
636         anID.erase(aBack); // remove last symbol
637       } else if (*aBack == 'e') {
638         anOrientation *= 3;
639         anID.erase(aBack); // remove last symbol
640       }
641
642       if (aNames.find(anID) != aNames.end()) {
643         theIDs[aNames[anID]] = anOrientation;
644       }
645     }
646     aPrevPos = aLastNamePos + 1;
647   } while (aLastNamePos != std::string::npos);
648   return true;
649 }
650
651 /// produces theEdge orientation relatively to theContext face
652 int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge)
653 {
654   if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE)
655     return 0;
656   if (theEdge.Orientation() == TopAbs_FORWARD)
657     return 1;
658   if (theEdge.Orientation() == TopAbs_REVERSED)
659     return -1;
660   return 0; // unknown
661 }
662
663 std::shared_ptr<GeomAPI_Shape> Model_SelectionNaming::findAppropriateFace(
664   std::shared_ptr<ModelAPI_Result>& theConstr,
665   NCollection_DataMap<Handle(Geom_Curve), int>& theCurves, const bool theIsWire)
666 {
667   int aBestFound = 0; // best number of found edges (not percentage: issue 1019)
668   int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation
669   std::shared_ptr<GeomAPI_Shape> aResult;
670   ResultConstructionPtr aConstructionContext =
671       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theConstr);
672   if (!aConstructionContext.get())
673     return aResult;
674   for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) {
675     int aFound = 0, aNotFound = 0, aSameOrientation = 0;
676     TopoDS_Face aFace =
677       TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl<TopoDS_Shape>());
678     std::list<TopoDS_Shape> aFacesWires; // faces or wires to iterate
679     if (theIsWire) {
680       for(TopExp_Explorer aWires(aFace, TopAbs_WIRE); aWires.More(); aWires.Next()) {
681         aFacesWires.push_back(aWires.Current());
682       }
683     } else {
684       aFacesWires.push_back(aFace);
685     }
686     std::list<TopoDS_Shape>::iterator aFW = aFacesWires.begin();
687     for(; aFW != aFacesWires.end(); aFW++) {
688       TopExp_Explorer anEdgesExp(*aFW, TopAbs_EDGE);
689       TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841)
690       for(; anEdgesExp.More(); anEdgesExp.Next()) {
691         TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
692         if (!anEdge.IsNull()) {
693           Standard_Real aFirst, aLast;
694           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
695           if (alreadyProcessed.Contains(aCurve))
696             continue;
697           alreadyProcessed.Add(aCurve);
698           if (theCurves.IsBound(aCurve)) {
699             aFound++;
700             int anOrient = theCurves.Find(aCurve);
701             if (anOrient != 0) {  // extra comparision score is orientation
702               if (edgeOrientation(aFace, anEdge) == anOrient)
703                 aSameOrientation++;
704             }
705           } else {
706             aNotFound++;
707           }
708         }
709       }
710       if (aFound + aNotFound != 0) {
711         if (aFound > aBestFound ||
712           (aFound == aBestFound && aSameOrientation > aBestOrient)) {
713             aBestFound = aFound;
714             aBestOrient = aSameOrientation;
715             if (theIsWire) {
716               std::shared_ptr<GeomAPI_Wire> aWire(new GeomAPI_Wire);
717               aWire->setImpl(new TopoDS_Shape(*aFW));
718               aResult = aWire;
719             } else {
720               aResult = aConstructionContext->face(aFaceIndex);
721             }
722         }
723       }
724     }
725   }
726   return aResult;
727 }
728
729 std::string Model_SelectionNaming::shortName(
730   std::shared_ptr<ModelAPI_ResultConstruction>& theConstr, const int theEdgeVertexPos)
731 {
732   std::string aName = theConstr->data()->name();
733   // remove "-", "/" and "&" command-symbols
734   aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end());
735   aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end());
736   aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
737   // remove the last 's', 'e', 'f' and 'r' symbols:
738   // they are used as markers of start/end/forward/rewersed indicators
739   static const std::string aSyms("sefr");
740   std::string::iterator aSuffix = aName.end() - 1;
741   while(aSyms.find(*aSuffix) != std::string::npos) {
742     --aSuffix;
743   }
744   aName.erase(aSuffix + 1, aName.end());
745
746   if (theEdgeVertexPos == 1) {
747     aName += "s"; // start
748   } else if (theEdgeVertexPos == 2) {
749     aName += "e"; // end
750   }
751   return aName;
752 }
753
754 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
755 bool Model_SelectionNaming::selectSubShape(const std::string& theType,
756   const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc,
757   std::shared_ptr<GeomAPI_Shape>& theShapeToBeSelected, std::shared_ptr<ModelAPI_Result>& theCont)
758 {
759   if(theSubShapeName.empty() || theType.empty()) return false;
760   TopAbs_ShapeEnum aType = translateType(theType);
761
762   // check that it was selected in another document
763   size_t aSlash = theSubShapeName.find("/");
764   std::string aSubShapeName = theSubShapeName;
765   std::shared_ptr<Model_Document> aDoc = theDoc;
766   if (aSlash != std::string::npos) {
767     std::string aDocName = theSubShapeName.substr(0, aSlash);
768     ResultPartPtr aFoundPart;
769     DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
770     if (aDocName == aRootDoc->kind()) {
771       aDoc = std::dynamic_pointer_cast<Model_Document>(aRootDoc);
772     } else {
773       for (int a = aRootDoc->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) {
774         ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(
775             aRootDoc->object(ModelAPI_ResultPart::group(), a));
776         if (aPart.get() && aPart->isActivated() && aPart->data()->name() == aDocName) {
777           aDoc = std::dynamic_pointer_cast<Model_Document>(aPart->partDoc());
778           aFoundPart = aPart;
779           break;
780         }
781       }
782     }
783     if (aDoc != theDoc) {
784       // so, the first word is the document name => reduce the string for the next manips
785       aSubShapeName = theSubShapeName.substr(aSlash + 1);
786       if (aSubShapeName.empty() && aFoundPart.get()) { // the whole Part result
787         theCont = aFoundPart;
788         return true;
789       }
790     }
791   }
792
793   std::string aContName = getContextName(aSubShapeName);
794   if(aContName.empty()) return false;
795   bool anUniqueContext = false;
796   ResultPtr aCont = aDoc->findByName(aContName, aSubShapeName, anUniqueContext);
797    // possible this is body where postfix is added to distinguish several shapes on the same label
798   int aSubShapeId = -1; // -1 means sub shape not found
799   // for result body the name wihtout "_" has higher priority than with it: it is always added
800   if ((!aCont.get()/* || (aCont->groupName() == ModelAPI_ResultBody::group())*/) &&
801        aContName == aSubShapeName) {
802     size_t aPostIndex = aContName.rfind('_');
803     if (aPostIndex != std::string::npos) {
804       std::string anEmpty, aSubContName = aContName.substr(0, aPostIndex);
805       ResultPtr aSubCont = aDoc->findByName(aSubContName, anEmpty, anUniqueContext);
806       if (aSubCont.get()) {
807         try {
808           std::string aNum = aContName.substr(aPostIndex + 1);
809           aSubShapeId = std::stoi(aNum);
810         } catch (std::invalid_argument&) {
811           aSubShapeId = -1;
812         }
813         if (aSubShapeId > 0) {
814           aContName = aSubContName;
815           aCont = aSubCont;
816         }
817       }
818     }
819   }
820
821
822   static const ResultPtr anEmpty;
823   TopoDS_Shape aSelection;
824   switch (aType)
825   {
826   case TopAbs_FACE:
827   case TopAbs_WIRE:
828     {
829       aSelection = findFaceByName(aSubShapeName, aDoc, aCont, anUniqueContext);
830     }
831     break;
832   case TopAbs_EDGE:
833     {
834       const TDF_Label& aLabel =
835         aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty);
836       if(!aLabel.IsNull()) {
837         Handle(TNaming_NamedShape) aNS;
838         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
839           aSelection = getShapeFromNS(aSubShapeName, aNS);
840         }
841       }
842     }
843     break;
844   case TopAbs_VERTEX:
845     {
846       const TDF_Label& aLabel =
847         aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty);
848       if(!aLabel.IsNull()) {
849         Handle(TNaming_NamedShape) aNS;
850         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
851           aSelection = getShapeFromNS(aSubShapeName, aNS);
852         }
853       }
854     }
855     break;
856   case TopAbs_COMPOUND:
857   case TopAbs_COMPSOLID:
858   case TopAbs_SOLID:
859   case TopAbs_SHELL:
860   default: {//TopAbs_SHAPE
861     /// case when the whole sketch is selected, so,
862     /// selection type is compound, but there is no value
863     if (aCont.get() && aCont->shape().get()) {
864       if (aCont->shape()->impl<TopoDS_Shape>().ShapeType() == aType) {
865         theCont = aCont;
866         return true;
867       } else if (aSubShapeId > 0) { // try to find sub-shape by the index
868         TopExp_Explorer anExp(aCont->shape()->impl<TopoDS_Shape>(), aType);
869         for(; aSubShapeId > 1 && anExp.More(); aSubShapeId--) {
870           anExp.Next();
871         }
872         if (anExp.More()) {
873           std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
874           aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current()));
875           theShapeToBeSelected = aShapeToBeSelected;
876           theCont = aCont;
877           return true;
878         }
879       }
880     }
881     return false;
882     }
883   }
884   if (!aSelection.IsNull() &&
885       aSelection.ShapeType() != aType && aSelection.ShapeType() != TopAbs_COMPOUND)
886       aSelection.Nullify(); // to avoid selection of face instead of edge that is described by face
887   // another try to find edge or vertex by faces
888   std::list<std::string> aListofNames;
889   size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0;
890   if ((aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) ||
891       (!aSelection.IsNull() && aSelection.ShapeType() != aType)) { // edge by one face as example
892     if(aN >= 1) {
893       TopTools_ListOfShape aList;
894       std::list<std::string>::iterator it = aListofNames.begin();
895       for(; it != aListofNames.end(); it++) {
896         ResultPtr aFaceContext = aCont;
897         if (it != aListofNames.begin()) { // there may be other context for different sub-faces
898           std::string aContName = getContextName(*it);
899           if(!aContName.empty()) {
900             aFaceContext = aDoc->findByName(aContName, *it, anUniqueContext);
901           }
902         }
903         TopoDS_Shape aFace = findFaceByName(*it, aDoc, aFaceContext, anUniqueContext);
904         if (aFace.IsNull() && aFaceContext.get() &&
905             aFaceContext->groupName() == ModelAPI_ResultConstruction::group() ) {
906           // search the construction sub-elements for the intersection if they are in the tree
907           size_t aSlash = it->find("/");
908           if (aSlash != std::string::npos) {
909             std::string aSubShapeName = it->substr(aSlash + 1);
910             aFace = findFaceByName(aSubShapeName, aDoc, aFaceContext, true);
911           }
912         }
913         if(!aFace.IsNull())
914           aList.Append(aFace);
915       }
916       aSelection = findCommonShape(aType, aList);
917     }
918   }
919   // in case of construction, there is no registered names for all sub-elements,
920   // even for the main element; so, trying to find them by name (without "&" intersections)
921   if (aSelection.IsNull() && aN < 2) {
922     size_t aConstrNamePos = aSubShapeName.find("/");
923     bool isFullName = aConstrNamePos == std::string::npos;
924     std::string anEmpty, aContrName = aContName;
925     ResultPtr aConstr = aDoc->findByName(aContrName, anEmpty, anUniqueContext);
926     if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) {
927       theCont = aConstr;
928       if (isFullName) {
929         // For the full construction selection shape must be empty.
930         //theShapeToBeSelected = aConstr->shape();
931         return true;
932       }
933       // for sketch sub-elements selected
934       CompositeFeaturePtr aComposite =
935         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aDoc->feature(aConstr));
936       if (aComposite.get()) {
937         if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
938           // collect all IDs in the name
939           bool isVertexByEdge = false;
940           std::map<int, int> anIDs;
941           if (!parseSubIndices(aComposite, aSubShapeName,
942               aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs)) {
943             // there is a case when vertex is identified by one circle-edge (2253)
944             if (aType == TopAbs_VERTEX &&
945                 parseSubIndices(aComposite, aSubShapeName, "Edge", anIDs))
946               isVertexByEdge = true;
947             else
948               return false;
949           }
950
951           const int aSubNum = aComposite->numberOfSubs();
952           for(int a = 0; a < aSubNum; a++) {
953             int aCompID = aComposite->subFeatureId(a);
954             if (anIDs.find(aCompID) != anIDs.end()) { // found the vertex/edge shape
955               FeaturePtr aSub = aComposite->subFeature(a);
956               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
957               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIt = aResults.cbegin();
958               // there may be many shapes (circle and center)
959               for(; aRIt != aResults.cend(); aRIt++) {
960                 ResultConstructionPtr aRes =
961                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRIt);
962                 if (aRes) {
963                   int anOrientation = abs(anIDs[aCompID]);
964                   TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
965                   if (anOrientation == 1) {
966                     if (!isVertexByEdge && aType == aShape.ShapeType()) {
967                       theShapeToBeSelected = aRes->shape();
968                       return true;
969                     } else if (isVertexByEdge && aType != aShape.ShapeType()) {
970                       // check that there is only one vertex produces by and circular edge
971                       TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
972                       TopExp_Explorer anExp(aShape, TopAbs_VERTEX);
973                       if (anExp.More())
974                         aShape = anExp.Current();
975                       anExp.Next();
976                       if (!anExp.More() || anExp.Current().IsSame(aShape)) {
977                         std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
978                         aShapeToBeSelected->setImpl(new TopoDS_Shape(aShape));
979                         theShapeToBeSelected = aShapeToBeSelected;
980                         return true;
981                       }
982                     }
983                   } else { // take first or second vertex of the edge
984                     TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
985                     if (aShape.ShapeType() == TopAbs_VERTEX) continue;
986                     TopExp_Explorer anExp(aShape, aType);
987                     for(; anExp.More() && anOrientation != 2; anOrientation--)
988                       anExp.Next();
989                     if (anExp.More()) {
990                       std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
991                       aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current()));
992                       theShapeToBeSelected = aShapeToBeSelected;
993                       return true;
994                     }
995                   }
996                 }
997               }
998             }
999           }
1000           // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
1001         } else if (aType == TopAbs_FACE || aType == TopAbs_WIRE) {
1002           std::map<int, int> anIDs;
1003           if (!parseSubIndices(aComposite, aSubShapeName,
1004               aType == TopAbs_FACE ? "Face" : "Wire", anIDs, true))
1005             return false;
1006
1007           // curves and orientations of edges
1008           NCollection_DataMap<Handle(Geom_Curve), int> allCurves;
1009           const int aSubNum = aComposite->numberOfSubs();
1010           for(int a = 0; a < aSubNum; a++) {
1011             int aSubID = aComposite->subFeatureId(a);
1012             if (anIDs.find(aSubID) != anIDs.end()) {
1013               FeaturePtr aSub = aComposite->subFeature(a);
1014               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
1015               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
1016               for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
1017                 ResultConstructionPtr aConstr =
1018                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
1019                 if (aConstr->shape() && aConstr->shape()->isEdge()) {
1020                   const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
1021                   TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
1022                   if (!anEdge.IsNull()) {
1023                     Standard_Real aFirst, aLast;
1024                     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
1025                     allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
1026                   }
1027                 }
1028               }
1029             }
1030           }
1031           std::shared_ptr<GeomAPI_Shape> aFoundFW =
1032             findAppropriateFace(aConstr, allCurves, aType == TopAbs_WIRE);
1033           if (aFoundFW.get()) {
1034             theShapeToBeSelected = aFoundFW;
1035             return true;
1036           }
1037         } else if (aType == TopAbs_WIRE) {
1038           // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
1039           std::map<int, int> anIDs;
1040           if (!parseSubIndices(aComposite, aSubShapeName, "Wire", anIDs))
1041             return false;
1042
1043            // curves and orientations of edges
1044           NCollection_DataMap<Handle(Geom_Curve), int> allCurves;
1045           const int aSubNum = aComposite->numberOfSubs();
1046           for(int a = 0; a < aSubNum; a++) {
1047             int aSubID = aComposite->subFeatureId(a);
1048             if (anIDs.find(aSubID) != anIDs.end()) {
1049               FeaturePtr aSub = aComposite->subFeature(a);
1050               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
1051               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
1052               for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
1053                 ResultConstructionPtr aConstr =
1054                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
1055                 if (aConstr->shape() && aConstr->shape()->isEdge()) {
1056                   const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
1057                   TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
1058                   if (!anEdge.IsNull()) {
1059                     Standard_Real aFirst, aLast;
1060                     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
1061                     allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
1062                   }
1063                 }
1064               }
1065             }
1066           }
1067           std::shared_ptr<GeomAPI_Shape> aFoundFW =
1068             findAppropriateFace(aConstr, allCurves, aType == TopAbs_WIRE);
1069           if (aFoundFW.get()) {
1070             theShapeToBeSelected = aFoundFW;
1071             return true;
1072           }
1073         }
1074       }
1075     }
1076   } else if (aSelection.IsNull() && aN >= 2 && aType == TopAbs_VERTEX) {
1077     // support of shape name as intersection separated by "&"
1078     static std::string anEdgeType = "edge"; // for now it works only with su-edges
1079     std::list<std::string>::iterator aSubNames = aListofNames.begin();
1080     TopTools_ListOfShape aSubsList;
1081     for(; aSubNames != aListofNames.end(); aSubNames++) {
1082       std::string aSubName = *aSubNames;
1083       std::shared_ptr<GeomAPI_Shape> aSubShapeFound;
1084       std::shared_ptr<ModelAPI_Result> aContextFound;
1085       if (selectSubShape(anEdgeType, aSubName, theDoc, aSubShapeFound, aContextFound)) {
1086         if (aSubShapeFound.get())
1087           aSubsList.Append(aSubShapeFound->impl<TopoDS_Shape>());
1088       }
1089     }
1090     aSelection = findCommonShape(TopAbs_VERTEX, aSubsList);
1091   }
1092   if (!aSelection.IsNull()) {
1093     // Select it (must be after N=0 checking,
1094     // since for simple constructions the shape must be null)
1095     std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
1096     aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection));
1097     theShapeToBeSelected = aShapeToBeSelected;
1098     theCont = aCont;
1099     return true;
1100   }
1101
1102   return false;
1103 }