]> SALOME platform Git repositories - modules/shaper.git/blob - src/Selector/Selector_Selector.cpp
Salome HOME
2b651c030e8ed949f6738a8c8a2ca6ce529344b5
[modules/shaper.git] / src / Selector / Selector_Selector.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 <Selector_Selector.h>
22
23 #include <Selector_NameGenerator.h>
24 #include <Selector_NExplode.h>
25
26 #include <TDF_ChildIDIterator.hxx>
27 #include <TopoDS_Iterator.hxx>
28 #include <TopoDS_Builder.hxx>
29 #include <TopoDS.hxx>
30 #include <TopExp_Explorer.hxx>
31 #include <TNaming_Tool.hxx>
32 #include <TNaming_NewShapeIterator.hxx>
33 #include <TNaming_OldShapeIterator.hxx>
34 #include <TNaming_SameShapeIterator.hxx>
35 #include <TNaming_Iterator.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TopTools_MapOfShape.hxx>
38 #include <BRep_Tool.hxx>
39
40 #include <TDataStd_Integer.hxx>
41 #include <TDataStd_ReferenceArray.hxx>
42 #include <TDataStd_IntegerArray.hxx>
43 #include <TDataStd_Name.hxx>
44
45 #include <list>
46
47 /// type of the selection, integerm keeps the Selector_Type value
48 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
49 /// type of the shape, stored in case it is intersection or container
50 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
51 //  reference attribute that contains the reference to labels where the "from" or "base" shapes
52 // of selection are located
53 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
54 // array of the neighbor levels
55 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
56 // weak index (integer) of the sub-shape
57 static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
58
59 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
60 {
61   myWeakIndex = -1;
62 }
63
64 TDF_Label Selector_Selector::label()
65 {
66   return myLab;
67 }
68
69 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
70 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
71   bool aMustBeAtFinal, TDF_LabelList& theResult)
72 {
73   TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
74   for(; aLabIter.More(); aLabIter.Next()) {
75     Handle(TNaming_NamedShape) aNS;
76     aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
77     if (aMustBeAtFinal && aNS != theFinal)
78       continue; // looking for old at the same final label only
79     TNaming_Evolution anEvolution = aNS->Evolution();
80     if (anEvolution == TNaming_PRIMITIVE) {
81       // check that this is not in the results already
82       const TDF_Label aResult = aNS->Label();
83       TDF_LabelList::Iterator aResIter(theResult);
84       for(; aResIter.More(); aResIter.Next()) {
85         if (aResIter.Value().IsEqual(aResult))
86           break;
87       }
88       if (!aResIter.More()) // not found, so add this new
89         theResult.Append(aResult);
90     }
91     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
92       for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
93         if (aThisIter.NewShape().IsSame(theValue)) {
94           // continue recursively, null NS means that any NS are ok
95           findBases(theFinal, aThisIter.OldShape(), false, theResult);
96         }
97       }
98     }
99   }
100 }
101
102 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
103 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
104   TopoDS_ListOfShape& theResults)
105 {
106   TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
107   for(; aSubSel != theShapes.end(); aSubSel++) {
108     TopTools_MapOfShape aCurrentMap;
109     for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
110       if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
111         theResults.Append(anExp.Current());
112     }
113     if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
114       for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
115         if (aCurrentMap.Contains(aComIter.Value()))
116           aComIter.Next();
117         else
118           theResults.Remove(aComIter);
119       }
120     }
121   }
122 }
123
124 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
125 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
126   const int theLevel, TopTools_MapOfShape& theResult)
127 {
128   TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
129   if (theValue.ShapeType() == TopAbs_FACE)
130     aConnectorType = TopAbs_EDGE;
131   TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
132   for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
133     aNBConnectors.Add(aValExp.Current());
134   }
135
136   TopTools_MapOfShape alreadyProcessed;
137   alreadyProcessed.Add(theValue);
138
139   for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
140     TopoDS_ListOfShape aGoodCandidates;
141     TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
142     for(; aCandidate.More(); aCandidate.Next()) {
143       if (alreadyProcessed.Contains(aCandidate.Current()))
144         continue;
145       TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
146       for(; aCandConnector.More(); aCandConnector.Next()) {
147         if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
148           break;
149       }
150       if (aCandConnector.More()) {
151         if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
152           theResult.Add(aCandidate.Current());
153         } else { // add to the NB of the current level
154           aGoodCandidates.Append(aCandidate.Current());
155         }
156       }
157     }
158     if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
159       for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
160         TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
161         for(; aGoodConnector.More(); aGoodConnector.Next()) {
162           aNBConnectors.Add(aGoodConnector.Current());
163         }
164         alreadyProcessed.Add(aGood.Value());
165       }
166     }
167   }
168 }
169
170 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
171 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
172   const std::list<std::pair<TopoDS_Shape, int> >& theNB)
173 {
174   // searching for neighbors with minimum level
175   int aMinLevel = 0;
176   std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
177   for(; aNBIter != theNB.cend(); aNBIter++) {
178     if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
179       aMinLevel = aNBIter->second;
180     }
181   }
182   // collect all neighbors which are neighbors of sub-shapes with minimum level
183   bool aFirst = true;
184   TopoDS_ListOfShape aMatches;
185   for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
186     if (aNBIter->second == aMinLevel) {
187       TopTools_MapOfShape aThisNBs;
188       findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
189       // aMatches must contain common part of all NBs lists
190       for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
191         if (aFirst) {
192           aMatches.Append(aThisNB.Value());
193         } else {
194           // remove all in aMatches which are not in this NBs
195           for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
196             if (aThisNBs.Contains(aMatch.Value())) {
197               aMatch.Next();
198             } else {
199               aMatches.Remove(aMatch);
200             }
201           }
202         }
203       }
204       aFirst = false;
205     }
206   }
207   if (aMatches.IsEmpty())
208     return TopoDS_Shape(); // not found any candidate
209   if (aMatches.Extent() == 1)
210     return aMatches.First(); // already found good candidate
211   // iterate all matches to find by other (higher level) neighbors the best candidate
212   TopoDS_Shape aGoodCandidate;
213   for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
214     bool aValidCadidate = true;
215     for(int aLevel = aMinLevel + 1; true; aLevel++) {
216       bool aFooundHigherLevel = false;
217       TopoDS_ListOfShape aLevelNBs;
218       for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
219         if (aNBIter->second == aLevel)
220           aLevelNBs.Append(aNBIter->first);
221         else if (aNBIter->second >= aLevel)
222           aFooundHigherLevel = true;
223       }
224       if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
225         if (aGoodCandidate.IsNull()) {
226           aGoodCandidate = aCandidate.Value();
227         } else { // too many good candidates
228           return TopoDS_Shape();
229         }
230       }
231       if (!aLevelNBs.IsEmpty()) {
232         TopTools_MapOfShape aNBsOfCandidate;
233         findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
234         // check all stored neighbors are in the map of real neighbors
235         for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
236           if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
237             aValidCadidate = false;
238             break;
239           }
240         }
241       }
242       if (!aValidCadidate) // candidate is not valid, break the checking
243         break;
244     }
245   }
246   return aGoodCandidate;
247 }
248
249 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
250   const bool theUseNeighbors)
251 {
252   if (theValue.IsNull() || theContext.IsNull())
253     return false;
254   // check the value shape can be named as it is, or it is needed to construct it from the
255   // higher level shapes (like a box vertex by faces that form this vertex)
256   bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
257   if (aIsFound) { // additional check for selection and delete evolution only: also could not use
258     aIsFound = false;
259     for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
260     {
261       Handle(TNaming_NamedShape) aNS;
262       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
263         if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
264             aNS->Evolution() == TNaming_PRIMITIVE) {
265           aIsFound = true;
266           break;
267         }
268       }
269     }
270   }
271   if (!aIsFound) {
272     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
273     myShapeType = aSelectionType;
274     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
275         aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
276     { // iterate all sub-shapes and select them on sublabels
277       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
278         if (!selectBySubSelector(theContext, aSubIter.Value(), theUseNeighbors)) {
279           return false; // if some selector is failed, everything is failed
280         }
281       }
282       myType = SELTYPE_CONTAINER;
283       return true;
284     }
285
286     // try to find the shape of the higher level type in the context shape
287     bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
288     TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
289     TopoDS_ListOfShape aLastIntersectors;
290     while(aSelectionType != TopAbs_FACE || !aFacesTried) {
291       if (aSelectionType == TopAbs_FACE) {
292         if (theValue.ShapeType() != TopAbs_VERTEX)
293           break;
294         aFacesTried = true;
295         aSelectionType = TopAbs_EDGE;
296       } else
297         aSelectionType = TopAbs_FACE;
298       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
299       TopoDS_ListOfShape anIntList; // same as anIntersectors
300       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
301         if (aSelectionType == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
302           continue;
303         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
304         for(; aSubExp.More(); aSubExp.Next()) {
305           if (aSubExp.Current().IsSame(theValue)) {
306             if (anIntersectors.Add(aSelExp.Current()))
307               anIntList.Append(aSelExp.Current());
308             break;
309           }
310         }
311       }
312       // check that solution is only one
313       TopoDS_ListOfShape aCommon;
314       commonShapes(anIntList, theValue.ShapeType(), aCommon);
315       if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
316         // name the intersectors
317         mySubSelList.clear();
318         TopoDS_ListOfShape::Iterator anInt(anIntList);
319         for (; anInt.More(); anInt.Next()) {
320           if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors)) {
321             break; // if some selector is failed, stop and search another solution
322           }
323         }
324         if (!anInt.More()) { // all intersectors were correctly named
325           myType = SELTYPE_INTERSECT;
326           return true;
327           }
328       } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty())  {
329         aLastCommon = aCommon;
330         aLastIntersectors = anIntList;
331       }
332     }
333
334     if (!theUseNeighbors)
335       return false;
336
337     // searching by neighbours
338     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
339     for(int aLevel = 1; true; aLevel++) {
340       TopTools_MapOfShape aNewNB;
341       findNeighbors(theContext, theValue, aLevel, aNewNB);
342       if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
343         break;
344       }
345       // iterate by the order in theContext to keep same naming names
346       TopExp_Explorer anOrder(theContext, theValue.ShapeType());
347       for (; anOrder.More(); anOrder.Next()) {
348         if (aNewNB.Contains(anOrder.Current())) {
349           TopoDS_Shape aNewNBShape = anOrder.Current();
350           // check which can be named correctly, without "by neighbors" type
351           Selector_Selector aSelector(myLab.FindChild(1));
352           if (aSelector.select(theContext, aNewNBShape, false)) { // add to the list of good NBs
353             aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
354           }
355         }
356       }
357       TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
358       if (!aResult.IsNull() && aResult.IsSame(theValue)) {
359         std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
360         for(; aNBIter != aNBs.end(); aNBIter++) {
361           if (!selectBySubSelector(theContext, aNBIter->first, false)) {
362             return false; // something is wrong because before this selection was ok
363           }
364           myNBLevel.push_back(aNBIter->second);
365
366         }
367         myType = SELTYPE_FILTER_BY_NEIGHBOR;
368         return true;
369       }
370     }
371
372     // weak naming to distinguish commons coming from intersection
373     if (aLastCommon.Extent() > 1) {
374       Selector_NExplode aNexp(aLastCommon);
375       myWeakIndex = aNexp.index(theValue);
376       if (myWeakIndex != -1) {
377         // name the intersectors
378         mySubSelList.clear();
379         TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
380         for (; anInt.More(); anInt.Next()) {
381           if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors)) {
382             break; // if some selector is failed, stop and search another solution
383           }
384         }
385         if (!anInt.More()) { // all intersectors were correctly named
386           myType = SELTYPE_INTERSECT;
387           return true;
388         }
389       }
390     }
391
392     // pure weak naming
393     myType = SELTYPE_WEAK_NAMING;
394     Selector_NExplode aNexp(theContext, theValue.ShapeType());
395     myWeakIndex = aNexp.index(theValue);
396     if (myWeakIndex != -1) {
397       myShapeType = theValue.ShapeType();
398       // searching for context shape label to store in myFinal
399       myFinal.Nullify();
400       if (TNaming_Tool::HasLabel(myLab, theContext)) {
401         for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
402         {
403           Handle(TNaming_NamedShape) aNS;
404           if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
405             TNaming_Evolution anEvolution = aNS->Evolution();
406             if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
407                 anEvolution == TNaming_MODIFY) {
408               // check this is a new shape
409               for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
410                 if (aNSIter.NewShape().IsSame(theContext)) {
411                   myFinal = aNS->Label();
412                   break;
413                 }
414               }
415             }
416           }
417         }
418       }
419       return true; // could be final empty (in case it is called recursively) or not
420     }
421
422     return false;
423   }
424   // searching for the base shapes of the value
425   Handle(TNaming_NamedShape) aPrimitiveNS;
426   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
427   for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
428   {
429     Handle(TNaming_NamedShape) aNS;
430     if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
431       TNaming_Evolution anEvolution = aNS->Evolution();
432       if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
433         aPrimitiveNS = aNS;
434         break;
435       } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
436         // check this is a new shape
437         TNaming_Iterator aNSIter(aNS);
438         for(; aNSIter.More(); aNSIter.Next())
439           if (aNSIter.NewShape().IsSame(theValue))
440             break;
441         if (aNSIter.More()) // new was found
442           aModifList.Append(aNS);
443       }
444     }
445   }
446
447   if (!aPrimitiveNS.IsNull()) {
448     myType = SELTYPE_PRIMITIVE;
449     myFinal = aPrimitiveNS->Label();
450     return true;
451   }
452
453   if (aModifList.Extent() > 1) { // searching for the best modification result: by context
454     Handle(TNaming_NamedShape) aCandidate;
455     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
456     for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
457        aCandidate = aModIter.Value();
458       TDF_Label aFatherLab = aCandidate->Label().Father();
459       Handle(TNaming_NamedShape) aFatherNS;
460       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
461         for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
462           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
463             aModifList.Clear();
464             break;
465           }
466         }
467       }
468     }
469     // take the best candidate, or the last in the iteration
470     aModifList.Clear();
471     aModifList.Append(aCandidate);
472   }
473
474   if (!aModifList.IsEmpty()) {
475     // searching for all the base shapes of this modification
476     findBases(aModifList.First(), theValue, true, myBases);
477     if (!myBases.IsEmpty()) {
478       myFinal = aModifList.First()->Label();
479       TopoDS_ListOfShape aCommon;
480       findModificationResult(aCommon);
481       // trying to search by neighbours
482       if (aCommon.Extent() > 1) { // more complicated selection
483         if (!theUseNeighbors)
484           return false;
485
486         // searching by neighbours
487         std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
488         for(int aLevel = 1; true; aLevel++) {
489           TopTools_MapOfShape aNewNB;
490           findNeighbors(theContext, theValue, aLevel, aNewNB);
491           if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
492             break;
493           }
494           // iterate by the order in theContext to keep same naming names
495           TopExp_Explorer anOrder(theContext, theValue.ShapeType());
496           for (; anOrder.More(); anOrder.Next()) {
497             if (aNewNB.Contains(anOrder.Current())) {
498               TopoDS_Shape aNewNBShape = anOrder.Current();
499               // check which can be named correctly, without "by neighbors" type
500               Selector_Selector aSelector(myLab.FindChild(1));
501               if (aSelector.select(theContext, aNewNBShape, false)) {// add to list of good NBs
502                 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
503               }
504             }
505           }
506           TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
507           if (!aResult.IsNull() && aResult.IsSame(theValue)) {
508             std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
509             for(; aNBIter != aNBs.end(); aNBIter++) {
510               if (!selectBySubSelector(theContext, aNBIter->first, theUseNeighbors)) {
511                 return false; // something is wrong because before this selection was ok
512               }
513               myNBLevel.push_back(aNBIter->second);
514
515             }
516             myType = SELTYPE_FILTER_BY_NEIGHBOR;
517             return true;
518           }
519         }
520         // filter by neighbours did not help
521         if (aCommon.Extent() > 1) { // weak naming between the common results
522           Selector_NExplode aNexp(aCommon);
523           myWeakIndex = aNexp.index(theValue);
524           if (myWeakIndex == -1)
525             return false;
526         }
527       }
528     }
529     myType = SELTYPE_MODIFICATION;
530     if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
531       TopoDS_ListOfShape aCommon;
532       myFinal = aModifList.First()->Label();
533       Handle(TNaming_NamedShape) aNS;
534       myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS);
535       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
536         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
537         if (!aNewShape.IsNull())
538           aCommon.Append(aNewShape);
539       }
540       Selector_NExplode aNexp(aCommon);
541       myWeakIndex = aNexp.index(theValue);
542       if (myWeakIndex == -1)
543         return false;
544     }
545     return true;
546   }
547
548   // not found a good result
549   return false;
550 }
551
552 void Selector_Selector::store()
553 {
554   myLab.ForgetAllAttributes(true); // remove old naming data
555   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
556   switch(myType) {
557   case SELTYPE_CONTAINER:
558   case SELTYPE_INTERSECT: {
559     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
560     // store also all sub-selectors
561     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
562     for(; aSubSel != mySubSelList.end(); aSubSel++) {
563       aSubSel->store();
564     }
565     if (myWeakIndex != -1) {
566       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
567     }
568     break;
569   }
570   case SELTYPE_PRIMITIVE: {
571     Handle(TDataStd_ReferenceArray) anArray =
572       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
573     anArray->SetValue(0, myFinal);
574     break;
575   }
576   case SELTYPE_MODIFICATION: {
577     Handle(TDataStd_ReferenceArray) anArray =
578       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
579     TDF_LabelList::Iterator aBIter(myBases);
580     for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
581       anArray->SetValue(anIndex, aBIter.Value());
582     }
583     anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
584     if (myWeakIndex != -1) {
585       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
586     }
587     break;
588   }
589   case SELTYPE_FILTER_BY_NEIGHBOR: {
590     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
591     // store numbers of levels corresponded to the neighbors in sub-selectors
592     Handle(TDataStd_IntegerArray) anArray =
593       TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
594     std::list<int>::iterator aLevel = myNBLevel.begin();
595     for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
596       anArray->SetValue(anIndex, *aLevel);
597     }
598     // store all sub-selectors
599     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
600     for(; aSubSel != mySubSelList.end(); aSubSel++) {
601       aSubSel->store();
602     }
603     break;
604   }
605   case SELTYPE_WEAK_NAMING: {
606     TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
607     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
608     // store myFinal in the base array
609     if (!myFinal.IsNull()) {
610       Handle(TDataStd_ReferenceArray) anArray =
611         TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
612       anArray->SetValue(0, myFinal);
613     }
614     break;
615   }
616   default: { // unknown case
617     break;
618   }
619   }
620 }
621
622 bool Selector_Selector::restore()
623 {
624   Handle(TDataStd_Integer) aTypeAttr;
625   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
626     return false;
627   myType = Selector_Type(aTypeAttr->Get());
628   switch(myType) {
629   case SELTYPE_CONTAINER:
630   case SELTYPE_INTERSECT: {
631     Handle(TDataStd_Integer) aShapeTypeAttr;
632     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
633       return false;
634     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
635     // restore sub-selectors
636     bool aSubResult = true;
637     mySubSelList.clear();
638     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
639       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
640       if (!mySubSelList.back().restore())
641         aSubResult = false;
642     }
643     Handle(TDataStd_Integer) aWeakInt;
644     if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
645       myWeakIndex = aWeakInt->Get();
646     }
647     return aSubResult;
648   }
649   case SELTYPE_PRIMITIVE: {
650     Handle(TDataStd_ReferenceArray) anArray;
651     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
652       myFinal = anArray->Value(0);
653       return true;
654     }
655     return false;
656   }
657   case SELTYPE_MODIFICATION: {
658     Handle(TDataStd_ReferenceArray) anArray;
659     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
660       int anUpper = anArray->Upper();
661       for(int anIndex = 0; anIndex < anUpper; anIndex++) {
662         myBases.Append(anArray->Value(anIndex));
663       }
664       myFinal = anArray->Value(anUpper);
665       Handle(TDataStd_Integer) aWeakInt;
666       if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
667         myWeakIndex = aWeakInt->Get();
668       }
669       return true;
670     }
671     return false;
672   }
673   case SELTYPE_FILTER_BY_NEIGHBOR: {
674     Handle(TDataStd_Integer) aShapeTypeAttr;
675     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
676       return false;
677     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
678     // restore sub-selectors
679     bool aSubResult = true;
680     mySubSelList.clear();
681     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
682       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
683       if (!mySubSelList.back().restore())
684         aSubResult = false;
685     }
686     // restore levels indices
687     Handle(TDataStd_IntegerArray) anArray;
688     if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
689       return false;
690     for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
691       myNBLevel.push_back(anArray->Value(anIndex));
692     }
693     return true;
694   }
695   case SELTYPE_WEAK_NAMING: {
696     Handle(TDataStd_Integer) aWeakInt;
697     if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
698       return false;
699     myWeakIndex = aWeakInt->Get();
700     Handle(TDataStd_Integer) aShapeTypeAttr;
701     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
702       return false;
703     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
704     Handle(TDataStd_ReferenceArray) anArray;
705     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
706       myFinal = anArray->Value(0);
707     }
708     return true;
709   }
710   default: { // unknown case
711   }
712   }
713   return false;
714 }
715
716 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
717 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
718   TopTools_MapOfShape& theResults)
719 {
720   for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
721     TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
722     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
723       if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
724         theResults.Add(aBaseIter.Shape());
725       } else {
726         findFinals(aBaseIter.Shape(), theFinal, theResults);
727       }
728     }
729   }
730 }
731
732 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
733   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
734     TopTools_MapOfShape aFinals;
735     for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
736       findFinals(aBaseShape.NewShape(), myFinal, aFinals);
737     if (!aFinals.IsEmpty()) {
738       if (theCommon.IsEmpty()) { // just copy all to common
739         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
740           theCommon.Append(aFinal.Key());
741         }
742       } else { // keep only shapes presented in both lists
743         for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
744           if (aFinals.Contains(aCommon.Value())) {
745             aCommon.Next();
746           } else { // common is not found, remove it
747             theCommon.Remove(aCommon);
748           }
749         }
750       }
751     }
752   }
753 }
754
755 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
756 {
757   TopoDS_Shape aResult; // null if invalid
758   switch(myType) {
759   case SELTYPE_CONTAINER: {
760     TopoDS_Builder aBuilder;
761     switch(myShapeType) {
762     case TopAbs_COMPOUND: {
763       TopoDS_Compound aComp;
764       aBuilder.MakeCompound(aComp);
765       aResult = aComp;
766       break;
767       }
768     case TopAbs_COMPSOLID: {
769       TopoDS_CompSolid aComp;
770       aBuilder.MakeCompSolid(aComp);
771       aResult = aComp;
772       break;
773     }
774     case TopAbs_SHELL: {
775       TopoDS_Shell aShell;
776       aBuilder.MakeShell(aShell);
777       aResult = aShell;
778       break;
779     }
780     case TopAbs_WIRE: {
781       TopoDS_Wire aWire;
782       aBuilder.MakeWire(aWire);
783       aResult = aWire;
784       break;
785     }
786     }
787     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
788     for(; aSubSel != mySubSelList.end(); aSubSel++) {
789       if (!aSubSel->solve(theContext)) {
790         return false;
791       }
792       aBuilder.Add(aResult, aSubSel->value());
793     }
794     break;
795   }
796   case SELTYPE_INTERSECT: {
797     TopoDS_ListOfShape aSubSelectorShapes;
798     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
799     for(; aSubSel != mySubSelList.end(); aSubSel++) {
800       if (!aSubSel->solve(theContext)) {
801         return false;
802       }
803       aSubSelectorShapes.Append(aSubSel->value());
804     }
805     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
806     commonShapes(aSubSelectorShapes, myShapeType, aCommon);
807     if (aCommon.Extent() != 1) {
808       if (myWeakIndex != -1) {
809         Selector_NExplode aNexp(aCommon);
810         aResult = aNexp.shape(myWeakIndex);
811       } else {
812         return false;
813       }
814     } else {
815       aResult = aCommon.First();
816     }
817     break;
818   }
819   case SELTYPE_PRIMITIVE: {
820     Handle(TNaming_NamedShape) aNS;
821     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
822       aResult = aNS->Get();
823     }
824     break;
825   }
826   case SELTYPE_MODIFICATION: {
827     if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index
828       TopoDS_ListOfShape aCommon;
829       Handle(TNaming_NamedShape) aNS;
830       myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS);
831       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
832         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
833         if (!aNewShape.IsNull())
834           aCommon.Append(aNewShape);
835       }
836       Selector_NExplode aNexp(aCommon);
837       aResult = aNexp.shape(myWeakIndex);
838     } else { // standard case
839       TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
840       findModificationResult(aFinalsCommon);
841       if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
842         aResult = aFinalsCommon.First();
843       else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
844         Selector_NExplode aNExp(aFinalsCommon);
845         aResult = aNExp.shape(myWeakIndex);
846       }
847     }
848     break;
849   }
850   case SELTYPE_FILTER_BY_NEIGHBOR: {
851     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
852     std::list<int>::iterator aLevel = myNBLevel.begin();
853     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
854     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
855       if (!aSubSel->solve(theContext)) {
856         return false;
857       }
858       aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
859     }
860     aResult = findNeighbor(theContext, aNBs);
861     break;
862   }
863   case SELTYPE_WEAK_NAMING: {
864     TopoDS_Shape aContext;
865     if (myFinal.IsNull()) {
866       aContext = theContext;
867     } else {
868       Handle(TNaming_NamedShape) aNS;
869       if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
870         aContext = aNS->Get();
871       }
872     }
873     if (!aContext.IsNull()) {
874       Selector_NExplode aNexp(aContext, myShapeType);
875       aResult = aNexp.shape(myWeakIndex);
876     }
877   }
878   default: { // unknown case
879   }
880   }
881
882   TNaming_Builder aBuilder(myLab);
883   if (!aResult.IsNull()) {
884     aBuilder.Select(aResult, aResult);
885     return true;
886   }
887   return false; // builder just erases the named shape in case of error
888 }
889
890 TopoDS_Shape Selector_Selector::value()
891 {
892   Handle(TNaming_NamedShape) aNS;
893   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
894     return aNS->Get();
895   return TopoDS_Shape(); // empty, error shape
896 }
897
898 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
899 static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
900
901 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
902   switch(myType) {
903   case SELTYPE_CONTAINER:
904   case SELTYPE_INTERSECT: {
905     std::string aResult;
906     // add names of sub-components one by one in "[]" +optionally [weak_name_1]
907     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
908     for(; aSubSel != mySubSelList.end(); aSubSel++) {
909       aResult += '[';
910       aResult += aSubSel->name(theNameGenerator);
911       aResult += ']';
912       TopAbs_ShapeEnum aSubType = aSubSel->value().ShapeType();
913       if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
914         switch(aSubType) {
915         case TopAbs_COMPOUND: aResult += "c"; break;
916         case TopAbs_COMPSOLID: aResult += "o"; break;
917         case TopAbs_SOLID: aResult += "s"; break;
918         case TopAbs_SHELL: aResult += "h"; break;
919         case TopAbs_WIRE: aResult += "w"; break;
920         case TopAbs_EDGE: aResult += "e"; break;
921         case TopAbs_VERTEX: aResult += "v"; break;
922         default:
923           ;
924         }
925       }
926     }
927     if (myWeakIndex != -1) {
928       std::ostringstream aWeakStr;
929       aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
930       aResult += aWeakStr.str();
931     }
932     return aResult;
933   }
934   case SELTYPE_PRIMITIVE: {
935     Handle(TDataStd_Name) aName;
936     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
937       return "";
938     return theNameGenerator->contextName(myFinal) + "/" +
939       std::string(TCollection_AsciiString(aName->Get()).ToCString());
940   }
941   case SELTYPE_MODIFICATION: {
942     // final&base1&base2 +optionally: [weak_name_1]
943     std::string aResult;
944     Handle(TDataStd_Name) aName;
945     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
946       return "";
947     aResult += theNameGenerator->contextName(myFinal) + "/" +
948       std::string(TCollection_AsciiString(aName->Get()).ToCString());
949     for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
950       if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
951         return "";
952       aResult += "&";
953       aResult += theNameGenerator->contextName(*aBase) + "/" +
954         std::string(TCollection_AsciiString(aName->Get()).ToCString());
955     }
956     if (myWeakIndex != -1) {
957       std::ostringstream aWeakStr;
958       aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
959       aResult += aWeakStr.str();
960     }
961     return aResult;
962   }
963   case SELTYPE_FILTER_BY_NEIGHBOR: {
964     // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
965     std::string aResult;
966     std::list<int>::iterator aLevel = myNBLevel.begin();
967     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
968     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
969       aResult += "(" + aSubSel->name(theNameGenerator) + ")";
970       if (*aLevel > 1) {
971         std::ostringstream aLevelStr;
972         aLevelStr<<*aLevel;
973         aResult += aLevelStr.str();
974       }
975     }
976     return aResult;
977   }
978   case SELTYPE_WEAK_NAMING: {
979     // _weak_naming_1_Context
980     std::ostringstream aWeakStr;
981     aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
982     std::string aResult = aWeakStr.str();
983     if (!myFinal.IsNull())
984       aResult += "_" + theNameGenerator->contextName(myFinal);
985     return aResult;
986   }
987   default: { // unknown case
988   }
989   };
990   return "";
991 }
992
993 TDF_Label Selector_Selector::restoreByName(
994   std::string theName, const TopAbs_ShapeEnum theShapeType,
995   Selector_NameGenerator* theNameGenerator)
996 {
997   if (theName[0] == '[') { // intersection or container
998     switch(theShapeType) {
999     case TopAbs_COMPOUND:
1000     case TopAbs_COMPSOLID:
1001     case TopAbs_SHELL:
1002     case TopAbs_WIRE:
1003       myType = SELTYPE_CONTAINER;
1004       break;
1005     case TopAbs_VERTEX:
1006     case TopAbs_EDGE:
1007     case TopAbs_FACE:
1008       myType = SELTYPE_INTERSECT;
1009       break;
1010     default:
1011       return TDF_Label(); // unknown case
1012     }
1013     myShapeType = theShapeType;
1014     TDF_Label aContext;
1015     for(size_t aStart = 0; aStart != std::string::npos;
1016         aStart = theName.find('[', aStart + 1)) {
1017       size_t anEndPos = theName.find(']', aStart + 1);
1018       if (anEndPos != std::string::npos) {
1019         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1020         if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1021           std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1022           myWeakIndex = atoi(aWeakIndex.c_str());
1023           continue;
1024         }
1025         TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
1026         if (anEndPos != std::string::npos && anEndPos + 1 > theName.size()) {
1027           char aShapeChar = theName[anEndPos + 1];
1028           if (theName[anEndPos + 1] != '[') {
1029             switch(aShapeChar) {
1030             case 'c': aSubShapeType = TopAbs_COMPOUND; break;
1031             case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
1032             case 's': aSubShapeType = TopAbs_SOLID; break;
1033             case 'h': aSubShapeType = TopAbs_SHELL; break;
1034             case 'w': aSubShapeType = TopAbs_WIRE; break;
1035             case 'e': aSubShapeType = TopAbs_EDGE; break;
1036             case 'v': aSubShapeType = TopAbs_VERTEX; break;
1037             default:;
1038             }
1039           }
1040         }
1041         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1042         TDF_Label aSubContext =
1043           mySubSelList.back().restoreByName(aSubStr, aSubShapeType, theNameGenerator);
1044         if (aSubContext.IsNull())
1045           return aSubContext; // invalid sub-selection parsing
1046         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1047           if (!theNameGenerator->isLater(aContext, aSubContext))
1048             aContext = aSubContext;
1049         } else {
1050           aContext = aSubContext;
1051         }
1052       } else
1053         return TDF_Label(); // invalid parentheses
1054     }
1055     return aContext;
1056   } else if (theName[0] == '(') { // filter by neighbours
1057     myType = SELTYPE_FILTER_BY_NEIGHBOR;
1058     TDF_Label aContext;
1059     for(size_t aStart = 0; aStart != std::string::npos;
1060       aStart = theName.find('(', aStart + 1)) {
1061       size_t anEndPos = theName.find(')', aStart + 1);
1062       if (anEndPos != std::string::npos) {
1063         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1064         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1065         TDF_Label aSubContext =
1066           mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
1067         if (aSubContext.IsNull())
1068           return aSubContext; // invalid sub-selection parsing
1069         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1070           if (!theNameGenerator->isLater(aContext, aSubContext))
1071             aContext = aSubContext;
1072         } else {
1073           aContext = aSubContext;
1074         }
1075         if (!aContext.IsNull()) // for filters by neighbour the latest context shape is vital
1076           aContext = theNameGenerator->newestContext(aContext);
1077
1078         // searching for the level index
1079         std::string aLevel;
1080         for(anEndPos++; anEndPos != std::string::npos &&
1081                         theName[anEndPos] != '(' && theName[anEndPos] != 0;
1082             anEndPos++) {
1083           aLevel += theName[anEndPos];
1084         }
1085         if (aLevel.empty())
1086           myNBLevel.push_back(1); // by default it is 1
1087         else {
1088           int aNum = atoi(aLevel.c_str());
1089           if (aNum > 0)
1090             myNBLevel.push_back(aNum);
1091           else
1092             return TDF_Label(); // invalid number
1093         }
1094       } else
1095         return TDF_Label(); // invalid parentheses
1096     }
1097     return aContext;
1098   } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1099     myType = SELTYPE_WEAK_NAMING;
1100     std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1101     std::size_t aContextPosition = aWeakIndex.find("_");
1102     myWeakIndex = atoi(aWeakIndex.c_str());
1103     myShapeType = theShapeType;
1104     TDF_Label aContext;
1105     if (aContextPosition != std::string::npos) { // context is also defined
1106       std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1107       theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1108     }
1109     return aContext;
1110   } else if (theName.find('&') == std::string::npos) { // wihtout '&' it can be only primitive
1111     myType = SELTYPE_PRIMITIVE;
1112     TDF_Label aContext;
1113     if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1114       if (!myFinal.IsNull())
1115         return aContext;
1116     }
1117   } else { // modification
1118     myType = SELTYPE_MODIFICATION;
1119     TDF_Label aContext;
1120     for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1121       if (aStart != 0)
1122         aStart++;
1123       anEnd = theName.find('&', aStart);
1124       std::string aSubStr =
1125         theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1126       if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1127         std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1128         myWeakIndex = atoi(aWeakIndex.c_str());
1129         continue;
1130       }
1131       TDF_Label aSubContext, aValue;
1132       if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1133         return TDF_Label(); // can not restore
1134       if(aSubContext.IsNull() || aValue.IsNull())
1135         return TDF_Label(); // can not restore
1136       if (myFinal.IsNull()) {
1137         myFinal = aValue;
1138         aContext = aSubContext;
1139       } else
1140         myBases.Append(aValue);
1141     }
1142     return aContext;
1143   }
1144   return TDF_Label();
1145 }
1146
1147 bool Selector_Selector::selectBySubSelector(
1148   const TopoDS_Shape theContext, const TopoDS_Shape theValue, const bool theUseNeighbors)
1149 {
1150   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1151   if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors)) {
1152     mySubSelList.clear(); // if one of the selector is failed, all become invalid
1153     return false;
1154   }
1155   return true;
1156 }