]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_SelectionNaming.cpp
Salome HOME
Reading of the construction naming name support (in the frames of Dump Python issue...
[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
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 aName;
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 (true by default)
469 bool parseSubIndices(const std::string& theName, const char* theShapeType, 
470                      std::map<int, bool>& theIDs, const bool theOriented = false)
471 {
472   // collect all IDs in the name
473   std::set<int> anIDs;
474   size_t aPrevPos = theName.find("/") + 1, aLastNamePos;
475   bool isShape = false; // anyway the first world must be 'Vertex'
476   do {
477     aLastNamePos = theName.find('-', aPrevPos);
478     const std::string anID = theName.substr(aPrevPos, aLastNamePos - aPrevPos);
479     if (!isShape) {
480       if (anID != theShapeType)
481         return false;
482       isShape = true;
483     } else {
484       bool anOrientation = true; // default
485       if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r'
486         const char aSymbol = theName.back();
487         anOrientation = aSymbol == 'f';
488       }
489       int anInt = 0;
490       try {
491         anInt = std::stoi(anID, nullptr);
492       } catch (const std::invalid_argument&) {}
493       if (anInt != 0)
494         theIDs[anInt] = anOrientation;
495     }
496     aPrevPos = aLastNamePos + 1;
497   } while (aLastNamePos != std::string::npos);
498   return true;
499 }
500
501 /// produces theEdge orientation relatively to theContext face
502 int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge)
503 {
504   if (theContext.ShapeType() != TopAbs_FACE)
505     return 0;
506   TopoDS_Face aContext = TopoDS::Face(theContext);
507   if (theEdge.Orientation() == TopAbs_FORWARD) 
508     return 1;
509   if (theEdge.Orientation() == TopAbs_REVERSED) 
510     return -1;
511   return 0; // unknown
512 }
513
514 std::shared_ptr<GeomAPI_Shape> Model_SelectionNaming::findAppropriateFace(
515   std::shared_ptr<ModelAPI_Result>& theConstr, 
516   NCollection_DataMap<Handle(Geom_Curve), int>& theCurves)
517 {
518   int aBestFound = 0; // best number of found edges (not percentage: issue 1019)
519   int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation
520   std::shared_ptr<GeomAPI_Shape> aResult;
521   ResultConstructionPtr aConstructionContext = 
522       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theConstr);
523   if (!aConstructionContext.get())
524     return aResult;
525   for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) {
526     int aFound = 0, aNotFound = 0, aSameOrientation = 0;
527     TopoDS_Face aFace = 
528       TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl<TopoDS_Shape>());
529     TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE);
530     TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841)
531     for(; anEdgesExp.More(); anEdgesExp.Next()) {
532       TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
533       if (!anEdge.IsNull()) {
534         Standard_Real aFirst, aLast;
535         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
536         if (alreadyProcessed.Contains(aCurve))
537           continue;
538         alreadyProcessed.Add(aCurve);
539         if (theCurves.IsBound(aCurve)) {
540           aFound++;
541           int anOrient = theCurves.Find(aCurve);
542           if (anOrient != 0) {  // extra comparision score is orientation
543             if (edgeOrientation(aFace, anEdge) == anOrient)
544               aSameOrientation++;
545           }
546         } else {
547           aNotFound++;
548         }
549       }
550     }
551     if (aFound + aNotFound != 0) {
552       if (aFound > aBestFound || 
553         (aFound == aBestFound && aSameOrientation > aBestOrient)) {
554           aBestFound = aFound;
555           aBestOrient = aSameOrientation;
556           aResult = aConstructionContext->face(aFaceIndex);
557       }
558     }
559   }
560   return aResult;
561 }
562
563 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
564 bool Model_SelectionNaming::selectSubShape(const std::string& theType, 
565   const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc,
566   std::shared_ptr<GeomAPI_Shape>& theShapeToBeSelected, std::shared_ptr<ModelAPI_Result>& theCont)
567 {
568   if(theSubShapeName.empty() || theType.empty()) return false;
569   TopAbs_ShapeEnum aType = translateType(theType);
570   std::string aContName = getContextName(theSubShapeName);
571   if(aContName.empty()) return false;
572   ResultPtr aCont = theDoc->findByName(aContName);
573   //if(!aCont.get() || aCont->shape()->isNull()) return false;
574   //TopoDS_Shape aContext  = aCont->shape()->impl<TopoDS_Shape>();
575   //TopAbs_ShapeEnum aContType = aContext.ShapeType();
576   //if(aType <= aContType) return false; // not applicable
577
578
579   TopoDS_Shape aSelection;
580   switch (aType) 
581   {
582   case TopAbs_FACE:
583     {
584       aSelection = findFaceByName(theSubShapeName, theDoc);
585     }
586     break;
587   case TopAbs_EDGE:
588     {  
589       const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
590       if(!aLabel.IsNull()) {
591         Handle(TNaming_NamedShape) aNS;
592         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
593           aSelection = getShapeFromNS(theSubShapeName, aNS);
594         }
595       }
596     }
597     break;
598   case TopAbs_VERTEX:
599     {
600       const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
601       if(!aLabel.IsNull()) {
602         Handle(TNaming_NamedShape) aNS;
603         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
604           aSelection = getShapeFromNS(theSubShapeName, aNS);
605         }
606       }
607     }
608     break;
609   case TopAbs_COMPOUND:
610   case TopAbs_COMPSOLID:
611   case TopAbs_SOLID:
612   case TopAbs_SHELL:
613   case TopAbs_WIRE:
614   default: //TopAbs_SHAPE
615     return false;
616   }
617   // another try to find edge or vertex by faces
618   std::list<std::string> aListofNames;
619   size_t aN = aSelection.IsNull() ? ParseName(theSubShapeName, aListofNames) : 0;
620   if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) {
621     if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE
622       TopTools_ListOfShape aList;
623       std::list<std::string>::iterator it = aListofNames.begin();
624       for(; it != aListofNames.end(); it++){
625         const TopoDS_Shape aFace = findFaceByName(*it, theDoc);
626         if(!aFace.IsNull())
627           aList.Append(aFace);          
628       }
629       aSelection = findCommonShape(aType, aList);
630     }
631   }
632   if (!aSelection.IsNull()) {// Select it
633     std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
634     aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection));
635     theShapeToBeSelected = aShapeToBeSelected;
636     theCont = aCont;
637     return true;
638   }
639   // in case of construction, there is no registered names for all sub-elements,
640   // even for the main element; so, trying to find them by name (without "&" intersections)
641   if (aN == 0) {
642     size_t aConstrNamePos = theSubShapeName.find("/");
643     bool isFullName = aConstrNamePos == std::string::npos;
644     std::string aContrName = 
645       isFullName ? theSubShapeName : theSubShapeName.substr(0, aConstrNamePos);
646     ResultPtr aConstr = theDoc->findByName(aContrName);
647     if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) {
648       theCont = aConstr;
649       if (isFullName) {
650         theShapeToBeSelected = aConstr->shape();
651         return true;
652       }
653       // for sketch sub-elements selected
654       CompositeFeaturePtr aComposite = 
655         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theDoc->feature(aConstr));
656       if (aComposite.get()) {
657         if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
658           // collect all IDs in the name
659           std::map<int, bool> anIDs;
660           if (!parseSubIndices(theSubShapeName, aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs))
661             return false;
662
663           const int aSubNum = aComposite->numberOfSubs();
664           for(int a = 0; a < aSubNum; a++) {
665             int aCompID = aComposite->subFeatureId(a);
666             if (anIDs.find(aCompID) != anIDs.end()) { // found the vertex/edge shape
667               FeaturePtr aSub = aComposite->subFeature(a);
668               ResultConstructionPtr aV = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>
669                 (*(aSub->results().begin()));
670               if (aV) {
671                 theShapeToBeSelected = aV->shape();
672                 return true;
673               }
674             } else if (aType == TopAbs_VERTEX &&
675                        (anIDs.find(aCompID + kSTART_VERTEX_DELTA) != anIDs.end() ||
676                        anIDs.find(aCompID + 2 * kSTART_VERTEX_DELTA) != anIDs.end())) {
677               FeaturePtr aSub = aComposite->subFeature(a);
678               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
679               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
680               // there may be many shapes (circle and center)
681               for(; aRes != aResults.cend(); aRes++) {
682                 ResultConstructionPtr aE = 
683                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
684                 if (aE && aE->shape()->isEdge()) {
685                   const TopoDS_Shape& anEdge = aE->shape()->impl<TopoDS_Shape>();
686                   TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); // first vertex
687                   if (anIDs.find(aCompID + kSTART_VERTEX_DELTA) == anIDs.end())
688                     aVExp.Next(); // second vertex
689                   std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
690                   aShapeToBeSelected->setImpl(new TopoDS_Shape(aVExp.Current()));
691                   theShapeToBeSelected = aShapeToBeSelected;
692                   return true;
693                 }
694               }
695             }
696           }
697         } else if (aType == TopAbs_FACE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
698           std::map<int, bool> anIDs;
699           if (!parseSubIndices(theSubShapeName, "Face", anIDs, true))
700             return false;
701
702           NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
703           const int aSubNum = aComposite->numberOfSubs();
704           for(int a = 0; a < aSubNum; a++) {
705             int aSubID = aComposite->subFeatureId(a);
706             if (anIDs.find(aSubID) != anIDs.end()) {
707               FeaturePtr aSub = aComposite->subFeature(a);
708               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
709               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
710               for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
711                 ResultConstructionPtr aConstr = 
712                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
713                 if (aConstr->shape() && aConstr->shape()->isEdge()) {
714                   const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
715                   TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
716                   if (!anEdge.IsNull()) {
717                     Standard_Real aFirst, aLast;
718                     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
719                     allCurves.Bind(aCurve, anIDs[aSubID] ? 1 : -1);
720                   }
721                 }
722               }
723             }
724           }
725           std::shared_ptr<GeomAPI_Shape> aFoundFace = findAppropriateFace(aConstr, allCurves);
726           if (aFoundFace.get()) {
727             theShapeToBeSelected = aFoundFace;
728             return true;
729           }
730         }
731       }
732     }
733   }
734   return false;
735 }