]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_SelectionNaming.cpp
Salome HOME
Make naming name works on bodies with additional prefixes (extrusion solid in the...
[modules/shaper.git] / src / Model / Model_SelectionNaming.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_SelectionNaming.cpp
4 // Created:     11 Aug 2015
5 // Author:      Mikhail PONIKAROV
6
7 #include "Model_SelectionNaming.h"
8 #include "Model_Document.h"
9 #include <ModelAPI_Feature.h>
10 #include <Events_InfoMessage.h>
11
12 #include <TopoDS_Iterator.hxx>
13 #include <TopoDS.hxx>
14 #include <TopoDS_Compound.hxx>
15 #include <TopExp.hxx>
16 #include <TopExp_Explorer.hxx>
17 #include <TopTools_ListOfShape.hxx>
18 #include <TopTools_MapOfShape.hxx>
19 #include <TopTools_IndexedMapOfShape.hxx>
20 #include <TopTools_ListIteratorOfListOfShape.hxx>
21 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
22 #include <TopTools_MapIteratorOfMapOfShape.hxx>
23 #include <BRep_Builder.hxx>
24 #include <TNaming_Iterator.hxx>
25 #include <TNaming_Tool.hxx>
26 #include <TNaming_NamedShape.hxx>
27 #include <TNaming_Localizer.hxx>
28 #include <TDataStd_Name.hxx>
29 #include <ModelAPI_ResultConstruction.h>
30 #include <ModelAPI_CompositeFeature.h>
31 #include <TColStd_MapOfTransient.hxx>
32 #include <algorithm>
33
34 #ifdef DEB_NAMING
35 #include <BRepTools.hxx>
36 #endif
37
38 /// added to the index in the packed map to signalize that the vertex of edge is selected
39 /// (multiplied by the index of the edge)
40 static const int kSTART_VERTEX_DELTA = 1000000;
41
42 Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab)
43 {
44   myLab = theSelectionLab;
45 }
46
47
48 std::string Model_SelectionNaming::getShapeName(
49   std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape)
50 {
51   std::string aName;
52   // check if the subShape is already in DF
53   Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(theShape, myLab);
54   Handle(TDataStd_Name) anAttr;
55   if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document    
56     if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
57       aName = TCollection_AsciiString(anAttr->Get()).ToCString();
58       if(!aName.empty()) {          
59         const TDF_Label& aLabel = theDoc->findNamingName(aName);
60         /* MPV: the same shape with the same name may be duplicated on different labels (selection of the same construction object)
61         if(!aLabel.IsEqual(aNS->Label())) {
62         //aName.erase(); //something is wrong, to be checked!!!
63         aName += "_SomethingWrong";
64         return aName;
65         }*/
66
67         static const std::string aPostFix("_");
68         TNaming_Iterator anItL(aNS);
69         for(int i = 1; anItL.More(); anItL.Next(), i++) {
70           if(anItL.NewShape() == theShape) {
71             aName += aPostFix;
72             aName += TCollection_AsciiString (i).ToCString();
73             break;
74           }
75         }
76       } 
77     }
78   }
79   return aName;
80 }
81
82
83
84 bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap)
85 {
86   // a trivial case: F1 & F2,  aNumber = 1, i.e. intersection gives 1 edge.
87   TopoDS_Compound aCmp;
88   BRep_Builder BB;
89   BB.MakeCompound(aCmp);
90   TopTools_ListIteratorOfListOfShape it(theAncestors);
91   for(;it.More();it.Next()) {
92     BB.Add(aCmp, it.Value());
93     theSMap.Add(it.Value());
94   }
95   int aNumber(0);
96   TopTools_IndexedDataMapOfShapeListOfShape aMap2;
97   TopExp::MapShapesAndAncestors(aCmp, TopAbs_EDGE, TopAbs_FACE, aMap2);
98   for (int i = 1; i <= aMap2.Extent(); i++) {
99     const TopoDS_Shape& aKey = aMap2.FindKey(i);
100     const TopTools_ListOfShape& anAncestors = aMap2.FindFromIndex(i);
101     if(anAncestors.Extent() > 1) aNumber++;
102   }
103   if(aNumber > 1) return false;
104   return true;
105 }
106
107 std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
108   std::shared_ptr<GeomAPI_Shape> theSubSh, const std::string& theDefaultName)
109 {
110   std::string aName("Undefined name");
111   if(!theContext.get() || theContext->shape()->isNull()) 
112     return !theDefaultName.empty() ? theDefaultName : aName;
113   if (!theSubSh.get() || theSubSh->isNull()) { // no subshape, so just the whole feature name
114     return theContext->data()->name();
115   }
116   TopoDS_Shape aSubShape = theSubSh->impl<TopoDS_Shape>();
117   TopoDS_Shape aContext  = theContext->shape()->impl<TopoDS_Shape>();
118 #ifdef DEB_NAMING
119   if(aSubShape.ShapeType() == TopAbs_COMPOUND) {
120     BRepTools::Write(aSubShape, "Selection.brep");
121     BRepTools::Write(aContext, "Context.brep");
122   }
123 #endif
124   std::shared_ptr<Model_Document> aDoc = 
125     std::dynamic_pointer_cast<Model_Document>(theContext->document());
126
127   // check if the subShape is already in DF
128   aName = getShapeName(aDoc, aSubShape);
129   if(aName.empty() ) { // not in the document!
130     TopAbs_ShapeEnum aType = aSubShape.ShapeType();
131     switch (aType) {
132     case TopAbs_FACE:
133       // the Face should be in DF. If it is not the case, it is an error ==> to be debugged             
134       break;
135     case TopAbs_EDGE:
136       {
137         // name structure: F1 & F2 [& F3 & F4], where F1 & F2 the faces which gives the Edge in trivial case
138         // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces      
139         if (BRep_Tool::Degenerated(TopoDS::Edge(aSubShape))) {
140           aName = "Degenerated_Edge";
141           break;
142         }    
143         TopTools_IndexedDataMapOfShapeListOfShape aMap;
144         TopExp::MapShapesAndAncestors(aContext, TopAbs_EDGE, TopAbs_FACE, aMap);
145         TopTools_IndexedMapOfShape aSMap; // map for ancestors of the sub-shape
146         bool isTrivialCase(true);
147         if(aMap.Contains(aSubShape)) {
148           const TopTools_ListOfShape& anAncestors = aMap.FindFromKey(aSubShape);
149           // check that it is not a trivial case (F1 & F2: aNumber = 1)
150           isTrivialCase = isTrivial(anAncestors, aSMap);                
151         } else 
152           break;
153         TopTools_ListOfShape aListOfNbs;
154         if(!isTrivialCase) { // find Neighbors
155           TNaming_Localizer aLocalizer;
156           TopTools_MapOfShape aMap3;
157           aLocalizer.FindNeighbourg(aContext, aSubShape, aMap3);
158           //int n = aMap3.Extent();
159           TopTools_MapIteratorOfMapOfShape it(aMap3);
160           for(;it.More();it.Next()) {
161             const TopoDS_Shape& aNbShape = it.Key(); // neighbor edge
162             //TopAbs_ShapeEnum aType = aNbShape.ShapeType();
163             const TopTools_ListOfShape& aList  = aMap.FindFromKey(aNbShape);
164             TopTools_ListIteratorOfListOfShape it2(aList);
165             for(;it2.More();it2.Next()) {
166               if(aSMap.Contains(it2.Value())) continue; // skip this Face
167               aListOfNbs.Append(it2.Value());
168             }
169           }
170         }  // else a trivial case
171
172         // build name of the sub-shape Edge
173         for(int i=1; i <= aSMap.Extent(); i++) {
174           const TopoDS_Shape& aFace = aSMap.FindKey(i);
175           std::string aFaceName = getShapeName(aDoc, aFace);
176           if(i == 1)
177             aName = aFaceName;
178           else 
179             aName += "&" + aFaceName;
180         }
181         TopTools_ListIteratorOfListOfShape itl(aListOfNbs);
182         for (;itl.More();itl.Next()) {
183           std::string aFaceName = getShapeName(aDoc, itl.Value());
184           aName += "&" + aFaceName;
185         }                 
186       }
187       break;
188
189     case TopAbs_VERTEX:
190       // name structure (Monifold Topology): 
191       // 1) F1 | F2 | F3 - intersection of 3 faces defines a vertex - trivial case.
192       // 2) F1 | F2 | F3 [|F4 [|Fn]] - redundant definition, but it should be kept as is to obtain safe recomputation
193       // 2) F1 | F2      - intersection of 2 faces definses a vertex - applicable for case
194       //                   when 1 faces is cylindrical, conical, spherical or revolution and etc.
195       // 3) E1 | E2 | E3 - intersection of 3 edges defines a vertex - when we have case of a shell
196       //                   or compound of 2 open faces.
197       // 4) E1 | E2      - intesection of 2 edges defines a vertex - when we have a case of 
198       //                   two independent edges (wire or compound)
199       // implemented 2 first cases
200       {
201         TopTools_IndexedDataMapOfShapeListOfShape aMap;
202         TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_FACE, aMap);
203         const TopTools_ListOfShape& aList2  = aMap.FindFromKey(aSubShape);
204         TopTools_ListOfShape aList;
205         TopTools_MapOfShape aFMap;
206         // fix is below
207         TopTools_ListIteratorOfListOfShape itl2(aList2);
208         for (int i = 1;itl2.More();itl2.Next(),i++) {
209           if(aFMap.Add(itl2.Value()))
210             aList.Append(itl2.Value());
211         }
212         int n = aList.Extent();
213         bool isByFaces = n >= 3;
214         if(!isByFaces) { // open topology case or Compound case => via edges
215           TopTools_IndexedDataMapOfShapeListOfShape aMap;
216           TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_EDGE, aMap);
217           const TopTools_ListOfShape& aList22  = aMap.FindFromKey(aSubShape);
218           if(aList22.Extent() >= 2)  { // regular solution
219
220             // bug! duplication; fix is below
221             aFMap.Clear();
222             TopTools_ListOfShape aListE;
223             TopTools_ListIteratorOfListOfShape itl2(aList22);
224             for (int i = 1;itl2.More();itl2.Next(),i++) {
225               if(aFMap.Add(itl2.Value()))
226                 aListE.Append(itl2.Value());
227             }
228             n = aListE.Extent();
229             TopTools_ListIteratorOfListOfShape itl(aListE);
230             for (int i = 1;itl.More();itl.Next(),i++) {
231               const TopoDS_Shape& anEdge = itl.Value();
232               std::string anEdgeName = getShapeName(aDoc, anEdge);
233               if (anEdgeName.empty()) { // edge is not in DS, trying by faces anyway
234                 isByFaces = true;
235                 aName.clear();
236                 break;
237               }
238               if(i == 1)
239                 aName = anEdgeName;
240               else 
241                 aName += "&" + anEdgeName;
242             }
243           }//reg
244           else { // dangle vertex: if(aList22.Extent() == 1)
245             //it should be already in DF
246           }
247         } 
248         if (isByFaces) {
249           TopTools_ListIteratorOfListOfShape itl(aList);
250           for (int i = 1;itl.More();itl.Next(),i++) {
251             const TopoDS_Shape& aFace = itl.Value();
252             std::string aFaceName = getShapeName(aDoc, aFace);
253             if(i == 1)
254               aName = aFaceName;
255             else 
256               aName += "&" + aFaceName;
257           }
258         }
259       }
260       break;
261     }
262     // register name                    
263     // aDoc->addNamingName(selectionLabel(), aName);
264     // the selected sub-shape will not be shared and as result it will not require registration
265   }
266   return aName;
267 }
268
269 TopAbs_ShapeEnum translateType (const std::string& theType)
270 {
271   // map from the textual shape types to OCCT enumeration
272   static std::map<std::string, TopAbs_ShapeEnum> aShapeTypes;
273
274   if(aShapeTypes.size() == 0) {
275     aShapeTypes["compound"]   = TopAbs_COMPOUND;
276     aShapeTypes["compounds"]  = TopAbs_COMPOUND;
277     aShapeTypes["compsolid"]  = TopAbs_COMPSOLID;
278     aShapeTypes["compsolids"] = TopAbs_COMPSOLID;
279     aShapeTypes["solid"]      = TopAbs_SOLID;
280     aShapeTypes["solids"]     = TopAbs_SOLID;
281     aShapeTypes["shell"]      = TopAbs_SHELL;
282     aShapeTypes["shells"]     = TopAbs_SHELL;
283     aShapeTypes["face"]       = TopAbs_FACE;
284     aShapeTypes["faces"]      = TopAbs_FACE;
285     aShapeTypes["wire"]       = TopAbs_WIRE;
286     aShapeTypes["wires"]      = TopAbs_WIRE;
287     aShapeTypes["edge"]       = TopAbs_EDGE;
288     aShapeTypes["edges"]      = TopAbs_EDGE;
289     aShapeTypes["vertex"]     = TopAbs_VERTEX;
290     aShapeTypes["vertices"]   = TopAbs_VERTEX;
291     aShapeTypes["COMPOUND"]   = TopAbs_COMPOUND;
292     aShapeTypes["COMPOUNDS"]  = TopAbs_COMPOUND;
293     aShapeTypes["COMPSOLID"]  = TopAbs_COMPSOLID;
294     aShapeTypes["COMPSOLIDS"] = TopAbs_COMPSOLID;
295     aShapeTypes["SOLID"]      = TopAbs_SOLID;
296     aShapeTypes["SOLIDS"]     = TopAbs_SOLID;
297     aShapeTypes["SHELL"]      = TopAbs_SHELL;
298     aShapeTypes["SHELLS"]     = TopAbs_SHELL;
299     aShapeTypes["FACE"]       = TopAbs_FACE;
300     aShapeTypes["FACES"]      = TopAbs_FACE;
301     aShapeTypes["WIRE"]       = TopAbs_WIRE;
302     aShapeTypes["WIRES"]      = TopAbs_WIRE;
303     aShapeTypes["EDGE"]       = TopAbs_EDGE;
304     aShapeTypes["EDGES"]      = TopAbs_EDGE;
305     aShapeTypes["VERTEX"]     = TopAbs_VERTEX;
306     aShapeTypes["VERTICES"]   = TopAbs_VERTEX;
307   }
308   if (aShapeTypes.find(theType) != aShapeTypes.end())
309     return aShapeTypes[theType];
310   Events_InfoMessage("Model_SelectionNaming", "Shape type defined in XML is not implemented!").send();
311   return TopAbs_SHAPE;
312 }
313
314 const TopoDS_Shape getShapeFromNS(
315   const std::string& theSubShapeName, Handle(TNaming_NamedShape) theNS)
316 {
317   TopoDS_Shape aSelection;
318   std::string::size_type n = theSubShapeName.rfind('/');                        
319   if (n == std::string::npos) n = 0;
320   std::string aSubString = theSubShapeName.substr(n + 1);
321   n = aSubString.rfind('_');
322   if (n == std::string::npos) return aSelection;
323   aSubString = aSubString.substr(n+1);
324   int indx = atoi(aSubString.c_str());
325
326   TNaming_Iterator anItL(theNS);
327   for(int i = 1; anItL.More(); anItL.Next(), i++) {
328     if (i == indx) {
329       return anItL.NewShape();
330     }
331   }
332   return aSelection;    
333 }
334
335 const TopoDS_Shape findFaceByName(
336   const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc)
337 {
338   TopoDS_Shape aFace;
339   std::string::size_type n, nb = theSubShapeName.rfind('/');                    
340   if (nb == std::string::npos) nb = 0;
341   std::string aSubString = theSubShapeName.substr(nb + 1);
342   n = aSubString.rfind('_');
343   if (n != std::string::npos) {
344     std::string aSubStr2 = aSubString.substr(0, n);
345     aSubString  = theSubShapeName.substr(0, nb + 1);
346     aSubString = aSubString + aSubStr2; 
347   } else
348     aSubString = theSubShapeName;
349
350   const TDF_Label& aLabel = theDoc->findNamingName(aSubString);
351   if(aLabel.IsNull()) return aFace;
352   Handle(TNaming_NamedShape) aNS;
353   if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
354     aFace = getShapeFromNS(theSubShapeName, aNS);
355   }
356   return aFace;
357 }
358
359 size_t ParseName(const std::string& theSubShapeName,   std::list<std::string>& theList)
360 {
361   std::string aName = theSubShapeName;
362   std::string aLastName;
363   size_t n1(0), n2(0); // n1 - start position, n2 - position of the delimiter
364   while ((n2 = aName.find('&', n1)) != std::string::npos) {
365     const std::string aName1 = aName.substr(n1, n2 - n1); //name of face
366     theList.push_back(aName1);  
367     n1 = n2 + 1;
368     aLastName = aName.substr(n1);
369   }
370   if(!aLastName.empty())
371     theList.push_back(aLastName);
372   return theList.size();
373 }
374
375 const TopoDS_Shape findCommonShape(
376   const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList)
377 {
378   TopoDS_Shape aShape;
379   std::vector<TopTools_MapOfShape> aVec;
380   TopTools_MapOfShape aMap1, aMap2, aMap3, aMap4;
381   if(theList.Extent() > 1) {
382     aVec.push_back(aMap1);
383     aVec.push_back(aMap2);
384   }
385   if(theList.Extent() > 2)
386     aVec.push_back(aMap3);
387   if(theList.Extent() == 4)
388     aVec.push_back(aMap4);
389
390   //fill maps
391   TopTools_ListIteratorOfListOfShape it(theList);
392   for(int i = 0;it.More();it.Next(),i++) {
393     const TopoDS_Shape& aFace = it.Value();             
394     if(i < 2) {
395       TopExp_Explorer anExp (aFace, theType);
396       for(;anExp.More();anExp.Next()) {
397         const TopoDS_Shape& anEdge = anExp.Current();
398         if (!anEdge.IsNull())
399           aVec[i].Add(anExp.Current());
400       }
401     } else {
402       TopExp_Explorer anExp (aFace, TopAbs_VERTEX);
403       for(;anExp.More();anExp.Next()) {
404         const TopoDS_Shape& aVertex = anExp.Current();
405         if (!aVertex.IsNull())
406           aVec[i].Add(anExp.Current());
407       }
408     }
409   }
410   //trivial case: 2 faces
411   TopTools_ListOfShape aList;
412   TopTools_MapIteratorOfMapOfShape it2(aVec[0]);
413   for(;it2.More();it2.Next()) {
414     if(aVec[1].Contains(it2.Key())) {
415       aShape = it2.Key();
416       if(theList.Extent() == 2)
417         break;
418       else 
419         aList.Append(it2.Key());
420     }
421   }
422   if(aList.Extent() && aVec.size() > 3) {// list of common edges ==> search ny neighbors 
423     if(aVec[2].Extent() && aVec[3].Extent()) {
424       TopTools_ListIteratorOfListOfShape it(aList);
425       for(;it.More();it.Next()) {
426         const TopoDS_Shape& aCand = it.Value();
427         // not yet completelly implemented, to be rechecked
428         TopoDS_Vertex aV1, aV2;
429         TopExp::Vertices(TopoDS::Edge(aCand), aV1, aV2);
430         int aNum(0);
431         if(aVec[2].Contains(aV1)) aNum++;
432         else if(aVec[2].Contains(aV2)) aNum++;
433         if(aVec[3].Contains(aV1)) aNum++;
434         else if(aVec[3].Contains(aV2)) aNum++;
435         if(aNum == 2) {
436           aShape = aCand;
437           break;
438         }
439       }
440     }
441   }
442
443   if(aList.Extent() && aVec.size() == 3) {
444
445     TopTools_ListIteratorOfListOfShape it(aList);
446     for(;it.More();it.Next()) {
447       const TopoDS_Shape& aCand = it.Value();
448       if(aVec[2].Contains(aCand)) {
449         aShape = aCand;
450         break;
451       }
452     }
453   }
454   return aShape;
455 }
456
457 std::string getContextName(const std::string& theSubShapeName)
458 {
459   std::string aName;
460   std::string::size_type n = theSubShapeName.find('/');                 
461   if (n == std::string::npos) return theSubShapeName;
462   aName = theSubShapeName.substr(0, n);
463   return aName;
464 }
465
466 /// Parses naming name of sketch sub-elements: takes indices and orientation 
467 /// (if theOriented = true) from this name. Map theIDs constains indices -> 
468 /// orientations and start/end vertices: negative is reversed, 2 - start, 3 - end
469 bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names
470   const std::string& theName, const char* theShapeType, 
471   std::map<int, int>& theIDs, const bool theOriented = false)
472 {
473   // collect all IDs in the name
474   std::map<std::string, int> aNames; // short name of sub -> ID of sub of theComp
475   const int aSubNum = theComp->numberOfSubs();
476   for(int a = 0; a < aSubNum; a++) {
477     FeaturePtr aSub = theComp->subFeature(a);
478     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
479     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
480     // there may be many shapes (circle and center)
481     for(; aRes != aResults.cend(); aRes++) {
482       ResultConstructionPtr aConstr = 
483         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
484       if (aConstr.get()) {
485         aNames[Model_SelectionNaming::shortName(aConstr)] = theComp->subFeatureId(a);
486       }
487     }
488   }
489
490   size_t aPrevPos = theName.find("/") + 1, aLastNamePos;
491   bool isShape = false; // anyway the first world must be 'Vertex'
492   do {
493     aLastNamePos = theName.find('-', aPrevPos);
494     std::string anID = theName.substr(aPrevPos, aLastNamePos - aPrevPos);
495     if (!isShape) {
496       if (anID != theShapeType)
497         return false;
498       isShape = true;
499     } else {
500       int anOrientation = 1; // default
501       if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r'
502         const char aSymbol = anID.back();
503         if (aSymbol == 'r') anOrientation = -1;
504         anID.pop_back();
505       }
506       // check start/end symbols
507       if (anID.back() == 's') {
508         anOrientation *= 2;
509         anID.pop_back();
510       } else if (anID.back() == 'e') {
511         anOrientation *= 3;
512         anID.pop_back();
513       }
514
515       if (aNames.find(anID) != aNames.end()) {
516         theIDs[aNames[anID]] = anOrientation;
517       }
518     }
519     aPrevPos = aLastNamePos + 1;
520   } while (aLastNamePos != std::string::npos);
521   return true;
522 }
523
524 /// produces theEdge orientation relatively to theContext face
525 int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge)
526 {
527   if (theContext.ShapeType() != TopAbs_FACE)
528     return 0;
529   TopoDS_Face aContext = TopoDS::Face(theContext);
530   if (theEdge.Orientation() == TopAbs_FORWARD) 
531     return 1;
532   if (theEdge.Orientation() == TopAbs_REVERSED) 
533     return -1;
534   return 0; // unknown
535 }
536
537 std::shared_ptr<GeomAPI_Shape> Model_SelectionNaming::findAppropriateFace(
538   std::shared_ptr<ModelAPI_Result>& theConstr, 
539   NCollection_DataMap<Handle(Geom_Curve), int>& theCurves)
540 {
541   int aBestFound = 0; // best number of found edges (not percentage: issue 1019)
542   int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation
543   std::shared_ptr<GeomAPI_Shape> aResult;
544   ResultConstructionPtr aConstructionContext = 
545       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theConstr);
546   if (!aConstructionContext.get())
547     return aResult;
548   for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) {
549     int aFound = 0, aNotFound = 0, aSameOrientation = 0;
550     TopoDS_Face aFace = 
551       TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl<TopoDS_Shape>());
552     TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE);
553     TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841)
554     for(; anEdgesExp.More(); anEdgesExp.Next()) {
555       TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
556       if (!anEdge.IsNull()) {
557         Standard_Real aFirst, aLast;
558         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
559         if (alreadyProcessed.Contains(aCurve))
560           continue;
561         alreadyProcessed.Add(aCurve);
562         if (theCurves.IsBound(aCurve)) {
563           aFound++;
564           int anOrient = theCurves.Find(aCurve);
565           if (anOrient != 0) {  // extra comparision score is orientation
566             if (edgeOrientation(aFace, anEdge) == anOrient)
567               aSameOrientation++;
568           }
569         } else {
570           aNotFound++;
571         }
572       }
573     }
574     if (aFound + aNotFound != 0) {
575       if (aFound > aBestFound || 
576         (aFound == aBestFound && aSameOrientation > aBestOrient)) {
577           aBestFound = aFound;
578           aBestOrient = aSameOrientation;
579           aResult = aConstructionContext->face(aFaceIndex);
580       }
581     }
582   }
583   return aResult;
584 }
585
586 std::string Model_SelectionNaming::shortName(
587   std::shared_ptr<ModelAPI_ResultConstruction>& theConstr, const int theEdgeVertexPos)
588 {
589   std::string aName = theConstr->data()->name();
590   // remove "-", "/" and "&" command-symbols
591   aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end());
592   aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end());
593   aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
594   // remove the last 's', 'e', 'f' and 'r' symbols: they are used as markers of start/end/forward/rewersed indicators
595   static const std::string aSyms("sefr");
596   while(aSyms.find(aName.back()) != std::string::npos) {
597     aName.pop_back();
598   }
599   if (theEdgeVertexPos == 1) {
600     aName += "s"; // start
601   } else if (theEdgeVertexPos == 2) {
602     aName += "e"; // end
603   }
604   return aName;
605 }
606
607 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
608 bool Model_SelectionNaming::selectSubShape(const std::string& theType, 
609   const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc,
610   std::shared_ptr<GeomAPI_Shape>& theShapeToBeSelected, std::shared_ptr<ModelAPI_Result>& theCont)
611 {
612   if(theSubShapeName.empty() || theType.empty()) return false;
613   TopAbs_ShapeEnum aType = translateType(theType);
614   std::string aContName = getContextName(theSubShapeName);
615   if(aContName.empty()) return false;
616   ResultPtr aCont = theDoc->findByName(aContName);
617    // possible this is body where postfix is added to distinguish several shapes on the same label
618   int aSubShapeId = -1; // -1 means sub shape not found
619   if (!aCont.get() && aContName == theSubShapeName) {
620     size_t aPostIndex = aContName.rfind('_');
621     if (aPostIndex != std::string::npos) {
622       std::string aSubContName = aContName.substr(0, aPostIndex);
623       aCont = theDoc->findByName(aSubContName);
624       if (aCont.get()) {
625         try {
626           std::string aNum = aContName.substr(aPostIndex + 1);
627           aSubShapeId = std::stoi(aNum);
628         } catch (std::invalid_argument&) {
629           aSubShapeId = -1;
630         }
631         if (aSubShapeId > 0)
632           aContName = aSubContName;
633       }
634     }
635   }
636
637
638   TopoDS_Shape aSelection;
639   switch (aType) 
640   {
641   case TopAbs_FACE:
642     {
643       aSelection = findFaceByName(theSubShapeName, theDoc);
644     }
645     break;
646   case TopAbs_EDGE:
647     {  
648       const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
649       if(!aLabel.IsNull()) {
650         Handle(TNaming_NamedShape) aNS;
651         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
652           aSelection = getShapeFromNS(theSubShapeName, aNS);
653         }
654       }
655     }
656     break;
657   case TopAbs_VERTEX:
658     {
659       const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
660       if(!aLabel.IsNull()) {
661         Handle(TNaming_NamedShape) aNS;
662         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
663           aSelection = getShapeFromNS(theSubShapeName, aNS);
664         }
665       }
666     }
667     break;
668   case TopAbs_COMPOUND:
669   case TopAbs_COMPSOLID:
670   case TopAbs_SOLID:
671   case TopAbs_SHELL:
672   case TopAbs_WIRE:
673   default: {//TopAbs_SHAPE
674     /// case when the whole sketch is selected, so, selection type is compound, but there is no value
675     if (aCont.get() && aCont->shape().get()) {
676       if (aCont->shape()->impl<TopoDS_Shape>().ShapeType() == aType) {
677         theCont = aCont;
678         return true;
679       } else if (aSubShapeId > 0) { // try to find sub-shape by the index
680         TopExp_Explorer anExp(aCont->shape()->impl<TopoDS_Shape>(), aType);
681         for(; aSubShapeId > 0 && anExp.More(); aSubShapeId--) {
682           anExp.Next();
683         }
684         if (anExp.More()) {
685           std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
686           aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current()));
687           theShapeToBeSelected = aShapeToBeSelected;
688           theCont = aCont;
689           return true;
690         }
691       }
692     }
693     return false;
694     }
695   }
696   // another try to find edge or vertex by faces
697   std::list<std::string> aListofNames;
698   size_t aN = aSelection.IsNull() ? ParseName(theSubShapeName, aListofNames) : 0;
699   if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) {
700     if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE
701       TopTools_ListOfShape aList;
702       std::list<std::string>::iterator it = aListofNames.begin();
703       for(; it != aListofNames.end(); it++){
704         const TopoDS_Shape aFace = findFaceByName(*it, theDoc);
705         if(!aFace.IsNull())
706           aList.Append(aFace);          
707       }
708       aSelection = findCommonShape(aType, aList);
709     }
710   }
711   if (!aSelection.IsNull()) {// Select it
712     std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
713     aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection));
714     theShapeToBeSelected = aShapeToBeSelected;
715     theCont = aCont;
716     return true;
717   }
718   // in case of construction, there is no registered names for all sub-elements,
719   // even for the main element; so, trying to find them by name (without "&" intersections)
720   if (aN == 0) {
721     size_t aConstrNamePos = theSubShapeName.find("/");
722     bool isFullName = aConstrNamePos == std::string::npos;
723     std::string aContrName = aContName;
724     //  isFullName ? theSubShapeName : theSubShapeName.substr(0, aConstrNamePos);
725     ResultPtr aConstr = theDoc->findByName(aContrName);
726     if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) {
727       theCont = aConstr;
728       if (isFullName) {
729         theShapeToBeSelected = aConstr->shape();
730         return true;
731       }
732       // for sketch sub-elements selected
733       CompositeFeaturePtr aComposite = 
734         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theDoc->feature(aConstr));
735       if (aComposite.get()) {
736         if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
737           // collect all IDs in the name
738           std::map<int, int> anIDs;
739           if (!parseSubIndices(aComposite, theSubShapeName, 
740               aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs))
741             return false;
742
743           const int aSubNum = aComposite->numberOfSubs();
744           for(int a = 0; a < aSubNum; a++) {
745             int aCompID = aComposite->subFeatureId(a);
746             if (anIDs.find(aCompID) != anIDs.end()) { // found the vertex/edge shape
747               FeaturePtr aSub = aComposite->subFeature(a);
748               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
749               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIt = aResults.cbegin();
750               // there may be many shapes (circle and center)
751               for(; aRIt != aResults.cend(); aRIt++) {
752                 ResultConstructionPtr aRes = 
753                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRIt);
754                 if (aRes) {
755                   int anOrientation = abs(anIDs[aCompID]);
756                   TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
757                   if (anOrientation == 1) {
758                     if (aType == aShape.ShapeType()) {
759                       theShapeToBeSelected = aRes->shape();
760                       return true;
761                     }
762                   } else { // take first or second vertex of the edge
763                     TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
764                     TopExp_Explorer anExp(aShape, aType);
765                     for(; anExp.More() && anOrientation != 2; anOrientation--)
766                       anExp.Next();
767                     if (anExp.More()) {
768                       std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
769                       aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current()));
770                       theShapeToBeSelected = aShapeToBeSelected;
771                       return true;
772                     }
773                   }
774                 }
775               }
776             }
777           }
778         } else if (aType == TopAbs_FACE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
779           std::map<int, int> anIDs;
780           if (!parseSubIndices(aComposite, theSubShapeName, "Face", anIDs, true))
781             return false;
782
783           NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
784           const int aSubNum = aComposite->numberOfSubs();
785           for(int a = 0; a < aSubNum; a++) {
786             int aSubID = aComposite->subFeatureId(a);
787             if (anIDs.find(aSubID) != anIDs.end()) {
788               FeaturePtr aSub = aComposite->subFeature(a);
789               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
790               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
791               for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
792                 ResultConstructionPtr aConstr = 
793                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
794                 if (aConstr->shape() && aConstr->shape()->isEdge()) {
795                   const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
796                   TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
797                   if (!anEdge.IsNull()) {
798                     Standard_Real aFirst, aLast;
799                     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
800                     allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
801                   }
802                 }
803               }
804             }
805           }
806           std::shared_ptr<GeomAPI_Shape> aFoundFace = findAppropriateFace(aConstr, allCurves);
807           if (aFoundFace.get()) {
808             theShapeToBeSelected = aFoundFace;
809             return true;
810           }
811         }
812       }
813     }
814   }
815   return false;
816 }