Salome HOME
Fix for the issue #2693 : groups in error after loading dump (3-holes plate)
[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, integer 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, const bool theUseIntersections)
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(
279             theContext, aSubIter.Value(), theUseNeighbors, theUseIntersections)) {
280           return false; // if some selector is failed, everything is failed
281         }
282       }
283       myType = SELTYPE_CONTAINER;
284       return true;
285     }
286
287     // try to find the shape of the higher level type in the context shape
288     bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
289     TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
290     TopoDS_ListOfShape aLastIntersectors;
291     while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) {
292       if (aSelectionType == TopAbs_FACE) {
293         if (theValue.ShapeType() != TopAbs_VERTEX)
294           break;
295         aFacesTried = true;
296         aSelectionType = TopAbs_EDGE;
297       } else
298         aSelectionType = TopAbs_FACE;
299       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
300       TopoDS_ListOfShape anIntList; // same as anIntersectors
301       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
302         if (aSelectionType == TopAbs_EDGE &&
303             BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
304           continue;
305         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
306         for(; aSubExp.More(); aSubExp.Next()) {
307           if (aSubExp.Current().IsSame(theValue)) {
308             if (anIntersectors.Add(aSelExp.Current()))
309               anIntList.Append(aSelExp.Current());
310             break;
311           }
312         }
313       }
314       // check that solution is only one
315       TopoDS_ListOfShape aCommon;
316       commonShapes(anIntList, theValue.ShapeType(), aCommon);
317       if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
318         // name the intersectors
319         mySubSelList.clear();
320         TopoDS_ListOfShape::Iterator anInt(anIntList);
321         for (; anInt.More(); anInt.Next()) {
322           if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors, false)) {
323             break; // if some selector is failed, stop and search another solution
324           }
325         }
326         if (!anInt.More()) { // all intersectors were correctly named
327           myType = SELTYPE_INTERSECT;
328           return true;
329           }
330       } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty())  {
331         aLastCommon = aCommon;
332         aLastIntersectors = anIntList;
333       }
334     }
335
336     if (!theUseNeighbors)
337       return false;
338
339     // searching by neighbors
340     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
341     for(int aLevel = 1; true; aLevel++) {
342       TopTools_MapOfShape aNewNB;
343       findNeighbors(theContext, theValue, aLevel, aNewNB);
344       if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
345         break;
346       }
347       // iterate by the order in theContext to keep same naming names
348       TopExp_Explorer anOrder(theContext, theValue.ShapeType());
349       for (; anOrder.More(); anOrder.Next()) {
350         if (aNewNB.Contains(anOrder.Current())) {
351           TopoDS_Shape aNewNBShape = anOrder.Current();
352           // check which can be named correctly, without "by neighbors" type
353           Selector_Selector aSelector(myLab.FindChild(1));
354           if (aSelector.select(theContext, aNewNBShape, false, false)) { // add to list of good NBs
355             aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
356           }
357         }
358       }
359       TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
360       if (!aResult.IsNull() && aResult.IsSame(theValue)) {
361         std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
362         for(; aNBIter != aNBs.end(); aNBIter++) {
363           if (!selectBySubSelector(theContext, aNBIter->first, false, false)) {
364             return false; // something is wrong because before this selection was ok
365           }
366           myNBLevel.push_back(aNBIter->second);
367
368         }
369         myType = SELTYPE_FILTER_BY_NEIGHBOR;
370         return true;
371       }
372     }
373
374     // weak naming to distinguish commons coming from intersection
375     if (aLastCommon.Extent() > 1) {
376       Selector_NExplode aNexp(aLastCommon);
377       myWeakIndex = aNexp.index(theValue);
378       if (myWeakIndex != -1) {
379         // name the intersectors
380         mySubSelList.clear();
381         TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
382         for (; anInt.More(); anInt.Next()) {
383           if (!selectBySubSelector(
384               theContext, anInt.Value(), theUseNeighbors, theUseIntersections)) {
385             break; // if some selector is failed, stop and search another solution
386           }
387         }
388         if (!anInt.More()) { // all intersectors were correctly named
389           myType = SELTYPE_INTERSECT;
390           return true;
391         }
392       }
393     }
394
395     // pure weak naming: there is no sense to use pure weak naming for neighbors selection
396     if (theUseNeighbors) {
397       myType = SELTYPE_WEAK_NAMING;
398       Selector_NExplode aNexp(theContext, theValue.ShapeType());
399       myWeakIndex = aNexp.index(theValue);
400       if (myWeakIndex != -1) {
401         myShapeType = theValue.ShapeType();
402         // searching for context shape label to store in myFinal
403         myFinal.Nullify();
404         if (TNaming_Tool::HasLabel(myLab, theContext)) {
405           for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
406           {
407             Handle(TNaming_NamedShape) aNS;
408             if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
409               TNaming_Evolution anEvolution = aNS->Evolution();
410               if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
411                   anEvolution == TNaming_MODIFY) {
412                 // check this is a new shape
413                 for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
414                   if (aNSIter.NewShape().IsSame(theContext)) {
415                     myFinal = aNS->Label();
416                     break;
417                   }
418                 }
419               }
420             }
421           }
422         }
423         return true; // could be final empty (in case it is called recursively) or not
424       }
425     }
426
427     return false;
428   }
429   // searching for the base shapes of the value
430   Handle(TNaming_NamedShape) aPrimitiveNS;
431   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
432   for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
433   {
434     Handle(TNaming_NamedShape) aNS;
435     if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
436       TNaming_Evolution anEvolution = aNS->Evolution();
437       if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
438         aPrimitiveNS = aNS;
439         break;
440       } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
441         // check this is a new shape
442         TNaming_Iterator aNSIter(aNS);
443         for(; aNSIter.More(); aNSIter.Next())
444           if (aNSIter.NewShape().IsSame(theValue))
445             break;
446         if (aNSIter.More()) // new was found
447           aModifList.Append(aNS);
448       }
449     }
450   }
451
452   if (!aPrimitiveNS.IsNull()) {
453     myType = SELTYPE_PRIMITIVE;
454     myFinal = aPrimitiveNS->Label();
455     return true;
456   }
457
458   if (aModifList.Extent() > 1) { // searching for the best modification result: by context
459     Handle(TNaming_NamedShape) aCandidate;
460     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
461     for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
462        aCandidate = aModIter.Value();
463       TDF_Label aFatherLab = aCandidate->Label().Father();
464       Handle(TNaming_NamedShape) aFatherNS;
465       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
466         for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
467           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
468             aModifList.Clear();
469             break;
470           }
471         }
472       }
473     }
474     // take the best candidate, or the last in the iteration
475     aModifList.Clear();
476     aModifList.Append(aCandidate);
477   }
478
479   if (!aModifList.IsEmpty()) {
480     // searching for all the base shapes of this modification
481     findBases(aModifList.First(), theValue, true, myBases);
482     if (!myBases.IsEmpty()) {
483       myFinal = aModifList.First()->Label();
484       TopoDS_ListOfShape aCommon;
485       findModificationResult(aCommon);
486       // trying to search by neighbors
487       if (aCommon.Extent() > 1) { // more complicated selection
488         if (!theUseNeighbors)
489           return false;
490
491         // searching by neighbors
492         std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
493         for(int aLevel = 1; true; aLevel++) {
494           TopTools_MapOfShape aNewNB;
495           findNeighbors(theContext, theValue, aLevel, aNewNB);
496           if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
497             break;
498           }
499           // iterate by the order in theContext to keep same naming names
500           TopExp_Explorer anOrder(theContext, theValue.ShapeType());
501           for (; anOrder.More(); anOrder.Next()) {
502             if (aNewNB.Contains(anOrder.Current())) {
503               TopoDS_Shape aNewNBShape = anOrder.Current();
504               // check which can be named correctly, without "by neighbors" type
505               Selector_Selector aSelector(myLab.FindChild(1));
506               if (aSelector.select(theContext, aNewNBShape, false)) {// add to list of good NBs
507                 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
508               }
509             }
510           }
511           TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
512           if (!aResult.IsNull() && aResult.IsSame(theValue)) {
513             std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
514             for(; aNBIter != aNBs.end(); aNBIter++) {
515               if (!selectBySubSelector(
516                   theContext, aNBIter->first, theUseNeighbors, theUseIntersections)) {
517                 return false; // something is wrong because before this selection was ok
518               }
519               myNBLevel.push_back(aNBIter->second);
520
521             }
522             myType = SELTYPE_FILTER_BY_NEIGHBOR;
523             return true;
524           }
525         }
526         // filter by neighbors did not help
527         if (aCommon.Extent() > 1) { // weak naming between the common results
528           Selector_NExplode aNexp(aCommon);
529           myWeakIndex = aNexp.index(theValue);
530           if (myWeakIndex == -1)
531             return false;
532         }
533       }
534     }
535     myType = SELTYPE_MODIFICATION;
536     if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
537       TopoDS_ListOfShape aCommon;
538       myFinal = aModifList.First()->Label();
539       Handle(TNaming_NamedShape) aNS;
540       myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS);
541       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
542         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
543         if (!aNewShape.IsNull())
544           aCommon.Append(aNewShape);
545       }
546       Selector_NExplode aNexp(aCommon);
547       myWeakIndex = aNexp.index(theValue);
548       if (myWeakIndex == -1)
549         return false;
550     }
551     return true;
552   }
553
554   // not found a good result
555   return false;
556 }
557
558 void Selector_Selector::store()
559 {
560   myLab.ForgetAllAttributes(true); // remove old naming data
561   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
562   switch(myType) {
563   case SELTYPE_CONTAINER:
564   case SELTYPE_INTERSECT: {
565     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
566     // store also all sub-selectors
567     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
568     for(; aSubSel != mySubSelList.end(); aSubSel++) {
569       aSubSel->store();
570     }
571     if (myWeakIndex != -1) {
572       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
573     }
574     break;
575   }
576   case SELTYPE_PRIMITIVE: {
577     Handle(TDataStd_ReferenceArray) anArray =
578       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
579     anArray->SetValue(0, myFinal);
580     break;
581   }
582   case SELTYPE_MODIFICATION: {
583     Handle(TDataStd_ReferenceArray) anArray =
584       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
585     TDF_LabelList::Iterator aBIter(myBases);
586     for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
587       anArray->SetValue(anIndex, aBIter.Value());
588     }
589     anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
590     if (myWeakIndex != -1) {
591       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
592     }
593     break;
594   }
595   case SELTYPE_FILTER_BY_NEIGHBOR: {
596     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
597     // store numbers of levels corresponded to the neighbors in sub-selectors
598     Handle(TDataStd_IntegerArray) anArray =
599       TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
600     std::list<int>::iterator aLevel = myNBLevel.begin();
601     for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
602       anArray->SetValue(anIndex, *aLevel);
603     }
604     // store all sub-selectors
605     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
606     for(; aSubSel != mySubSelList.end(); aSubSel++) {
607       aSubSel->store();
608     }
609     break;
610   }
611   case SELTYPE_WEAK_NAMING: {
612     TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
613     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
614     // store myFinal in the base array
615     if (!myFinal.IsNull()) {
616       Handle(TDataStd_ReferenceArray) anArray =
617         TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
618       anArray->SetValue(0, myFinal);
619     }
620     break;
621   }
622   default: { // unknown case
623     break;
624   }
625   }
626 }
627
628 bool Selector_Selector::restore()
629 {
630   Handle(TDataStd_Integer) aTypeAttr;
631   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
632     return false;
633   myType = Selector_Type(aTypeAttr->Get());
634   switch(myType) {
635   case SELTYPE_CONTAINER:
636   case SELTYPE_INTERSECT: {
637     Handle(TDataStd_Integer) aShapeTypeAttr;
638     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
639       return false;
640     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
641     // restore sub-selectors
642     bool aSubResult = true;
643     mySubSelList.clear();
644     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
645       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
646       if (!mySubSelList.back().restore())
647         aSubResult = false;
648     }
649     Handle(TDataStd_Integer) aWeakInt;
650     if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
651       myWeakIndex = aWeakInt->Get();
652     }
653     return aSubResult;
654   }
655   case SELTYPE_PRIMITIVE: {
656     Handle(TDataStd_ReferenceArray) anArray;
657     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
658       myFinal = anArray->Value(0);
659       return true;
660     }
661     return false;
662   }
663   case SELTYPE_MODIFICATION: {
664     Handle(TDataStd_ReferenceArray) anArray;
665     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
666       int anUpper = anArray->Upper();
667       for(int anIndex = 0; anIndex < anUpper; anIndex++) {
668         myBases.Append(anArray->Value(anIndex));
669       }
670       myFinal = anArray->Value(anUpper);
671       Handle(TDataStd_Integer) aWeakInt;
672       if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
673         myWeakIndex = aWeakInt->Get();
674       }
675       return true;
676     }
677     return false;
678   }
679   case SELTYPE_FILTER_BY_NEIGHBOR: {
680     Handle(TDataStd_Integer) aShapeTypeAttr;
681     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
682       return false;
683     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
684     // restore sub-selectors
685     bool aSubResult = true;
686     mySubSelList.clear();
687     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
688       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
689       if (!mySubSelList.back().restore())
690         aSubResult = false;
691     }
692     // restore levels indices
693     Handle(TDataStd_IntegerArray) anArray;
694     if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
695       return false;
696     for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
697       myNBLevel.push_back(anArray->Value(anIndex));
698     }
699     return true;
700   }
701   case SELTYPE_WEAK_NAMING: {
702     Handle(TDataStd_Integer) aWeakInt;
703     if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
704       return false;
705     myWeakIndex = aWeakInt->Get();
706     Handle(TDataStd_Integer) aShapeTypeAttr;
707     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
708       return false;
709     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
710     Handle(TDataStd_ReferenceArray) anArray;
711     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
712       myFinal = anArray->Value(0);
713     }
714     return true;
715   }
716   default: { // unknown case
717   }
718   }
719   return false;
720 }
721
722 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
723 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
724   TopTools_MapOfShape& theResults)
725 {
726   for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
727     TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
728     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
729       if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
730         theResults.Add(aBaseIter.Shape());
731       } else {
732         findFinals(aBaseIter.Shape(), theFinal, theResults);
733       }
734     }
735   }
736 }
737
738 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
739   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
740     TopTools_MapOfShape aFinals;
741     for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
742       findFinals(aBaseShape.NewShape(), myFinal, aFinals);
743     if (!aFinals.IsEmpty()) {
744       if (theCommon.IsEmpty()) { // just copy all to common
745         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
746           theCommon.Append(aFinal.Key());
747         }
748       } else { // keep only shapes presented in both lists
749         for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
750           if (aFinals.Contains(aCommon.Value())) {
751             aCommon.Next();
752           } else { // common is not found, remove it
753             theCommon.Remove(aCommon);
754           }
755         }
756       }
757     }
758   }
759 }
760
761 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
762 {
763   TopoDS_Shape aResult; // null if invalid
764   switch(myType) {
765   case SELTYPE_CONTAINER: {
766     TopoDS_Builder aBuilder;
767     switch(myShapeType) {
768     case TopAbs_COMPOUND: {
769       TopoDS_Compound aComp;
770       aBuilder.MakeCompound(aComp);
771       aResult = aComp;
772       break;
773       }
774     case TopAbs_COMPSOLID: {
775       TopoDS_CompSolid aComp;
776       aBuilder.MakeCompSolid(aComp);
777       aResult = aComp;
778       break;
779     }
780     case TopAbs_SHELL: {
781       TopoDS_Shell aShell;
782       aBuilder.MakeShell(aShell);
783       aResult = aShell;
784       break;
785     }
786     case TopAbs_WIRE: {
787       TopoDS_Wire aWire;
788       aBuilder.MakeWire(aWire);
789       aResult = aWire;
790       break;
791     }
792     }
793     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
794     for(; aSubSel != mySubSelList.end(); aSubSel++) {
795       if (!aSubSel->solve(theContext)) {
796         return false;
797       }
798       aBuilder.Add(aResult, aSubSel->value());
799     }
800     break;
801   }
802   case SELTYPE_INTERSECT: {
803     TopoDS_ListOfShape aSubSelectorShapes;
804     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
805     for(; aSubSel != mySubSelList.end(); aSubSel++) {
806       if (!aSubSel->solve(theContext)) {
807         return false;
808       }
809       aSubSelectorShapes.Append(aSubSel->value());
810     }
811     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
812     commonShapes(aSubSelectorShapes, myShapeType, aCommon);
813     if (aCommon.Extent() != 1) {
814       if (myWeakIndex != -1) {
815         Selector_NExplode aNexp(aCommon);
816         aResult = aNexp.shape(myWeakIndex);
817       } else {
818         return false;
819       }
820     } else {
821       aResult = aCommon.First();
822     }
823     break;
824   }
825   case SELTYPE_PRIMITIVE: {
826     Handle(TNaming_NamedShape) aNS;
827     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
828       aResult = aNS->Get();
829     }
830     break;
831   }
832   case SELTYPE_MODIFICATION: {
833     if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index
834       TopoDS_ListOfShape aCommon;
835       Handle(TNaming_NamedShape) aNS;
836       myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS);
837       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
838         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
839         if (!aNewShape.IsNull())
840           aCommon.Append(aNewShape);
841       }
842       Selector_NExplode aNexp(aCommon);
843       aResult = aNexp.shape(myWeakIndex);
844     } else { // standard case
845       TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
846       findModificationResult(aFinalsCommon);
847       if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
848         aResult = aFinalsCommon.First();
849       else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
850         Selector_NExplode aNExp(aFinalsCommon);
851         aResult = aNExp.shape(myWeakIndex);
852       }
853     }
854     break;
855   }
856   case SELTYPE_FILTER_BY_NEIGHBOR: {
857     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
858     std::list<int>::iterator aLevel = myNBLevel.begin();
859     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
860     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
861       if (!aSubSel->solve(theContext)) {
862         return false;
863       }
864       aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
865     }
866     aResult = findNeighbor(theContext, aNBs);
867     break;
868   }
869   case SELTYPE_WEAK_NAMING: {
870     TopoDS_Shape aContext;
871     if (myFinal.IsNull()) {
872       aContext = theContext;
873     } else {
874       Handle(TNaming_NamedShape) aNS;
875       if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
876         aContext = aNS->Get();
877       }
878     }
879     if (!aContext.IsNull()) {
880       Selector_NExplode aNexp(aContext, myShapeType);
881       aResult = aNexp.shape(myWeakIndex);
882     }
883   }
884   default: { // unknown case
885   }
886   }
887
888   TNaming_Builder aBuilder(myLab);
889   if (!aResult.IsNull()) {
890     aBuilder.Select(aResult, aResult);
891     return true;
892   }
893   return false; // builder just erases the named shape in case of error
894 }
895
896 TopoDS_Shape Selector_Selector::value()
897 {
898   Handle(TNaming_NamedShape) aNS;
899   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
900     return aNS->Get();
901   return TopoDS_Shape(); // empty, error shape
902 }
903
904 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
905 static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
906
907 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
908   switch(myType) {
909   case SELTYPE_CONTAINER:
910   case SELTYPE_INTERSECT: {
911     std::string aResult;
912     // add names of sub-components one by one in "[]" +optionally [weak_name_1]
913     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
914     for(; aSubSel != mySubSelList.end(); aSubSel++) {
915       aResult += '[';
916       aResult += aSubSel->name(theNameGenerator);
917       aResult += ']';
918       TopAbs_ShapeEnum aSubType = aSubSel->value().ShapeType();
919       if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
920         switch(aSubType) {
921         case TopAbs_COMPOUND: aResult += "c"; break;
922         case TopAbs_COMPSOLID: aResult += "o"; break;
923         case TopAbs_SOLID: aResult += "s"; break;
924         case TopAbs_SHELL: aResult += "h"; break;
925         case TopAbs_WIRE: aResult += "w"; break;
926         case TopAbs_EDGE: aResult += "e"; break;
927         case TopAbs_VERTEX: aResult += "v"; break;
928         default:
929           ;
930         }
931       }
932     }
933     if (myWeakIndex != -1) {
934       std::ostringstream aWeakStr;
935       aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
936       aResult += aWeakStr.str();
937     }
938     return aResult;
939   }
940   case SELTYPE_PRIMITIVE: {
941     Handle(TDataStd_Name) aName;
942     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
943       return "";
944     return theNameGenerator->contextName(myFinal) + "/" +
945       std::string(TCollection_AsciiString(aName->Get()).ToCString());
946   }
947   case SELTYPE_MODIFICATION: {
948     // final&base1&base2 +optionally: [weak_name_1]
949     std::string aResult;
950     Handle(TDataStd_Name) aName;
951     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
952       return "";
953     aResult += theNameGenerator->contextName(myFinal) + "/" +
954       std::string(TCollection_AsciiString(aName->Get()).ToCString());
955     for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
956       if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
957         return "";
958       aResult += "&";
959       aResult += theNameGenerator->contextName(*aBase) + "/" +
960         std::string(TCollection_AsciiString(aName->Get()).ToCString());
961     }
962     if (myWeakIndex != -1) {
963       std::ostringstream aWeakStr;
964       aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
965       aResult += aWeakStr.str();
966     }
967     return aResult;
968   }
969   case SELTYPE_FILTER_BY_NEIGHBOR: {
970     // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
971     std::string aResult;
972     std::list<int>::iterator aLevel = myNBLevel.begin();
973     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
974     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
975       aResult += "(" + aSubSel->name(theNameGenerator) + ")";
976       if (*aLevel > 1) {
977         std::ostringstream aLevelStr;
978         aLevelStr<<*aLevel;
979         aResult += aLevelStr.str();
980       }
981     }
982     return aResult;
983   }
984   case SELTYPE_WEAK_NAMING: {
985     // _weak_naming_1_Context
986     std::ostringstream aWeakStr;
987     aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
988     std::string aResult = aWeakStr.str();
989     if (!myFinal.IsNull())
990       aResult += "_" + theNameGenerator->contextName(myFinal);
991     return aResult;
992   }
993   default: { // unknown case
994   }
995   };
996   return "";
997 }
998
999 TDF_Label Selector_Selector::restoreByName(
1000   std::string theName, const TopAbs_ShapeEnum theShapeType,
1001   Selector_NameGenerator* theNameGenerator)
1002 {
1003   if (theName[0] == '[') { // intersection or container
1004     switch(theShapeType) {
1005     case TopAbs_COMPOUND:
1006     case TopAbs_COMPSOLID:
1007     case TopAbs_SHELL:
1008     case TopAbs_WIRE:
1009       myType = SELTYPE_CONTAINER;
1010       break;
1011     case TopAbs_VERTEX:
1012     case TopAbs_EDGE:
1013     case TopAbs_FACE:
1014       myType = SELTYPE_INTERSECT;
1015       break;
1016     default:
1017       return TDF_Label(); // unknown case
1018     }
1019     myShapeType = theShapeType;
1020     TDF_Label aContext;
1021     for(size_t aStart = 0; aStart != std::string::npos;
1022         aStart = theName.find('[', aStart + 1)) {
1023       size_t anEndPos = theName.find(']', aStart + 1);
1024       if (anEndPos != std::string::npos) {
1025         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1026         if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1027           std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1028           myWeakIndex = atoi(aWeakIndex.c_str());
1029           continue;
1030         }
1031         TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
1032         if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
1033           char aShapeChar = theName[anEndPos + 1];
1034           if (theName[anEndPos + 1] != '[') {
1035             switch(aShapeChar) {
1036             case 'c': aSubShapeType = TopAbs_COMPOUND; break;
1037             case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
1038             case 's': aSubShapeType = TopAbs_SOLID; break;
1039             case 'h': aSubShapeType = TopAbs_SHELL; break;
1040             case 'w': aSubShapeType = TopAbs_WIRE; break;
1041             case 'e': aSubShapeType = TopAbs_EDGE; break;
1042             case 'v': aSubShapeType = TopAbs_VERTEX; break;
1043             default:;
1044             }
1045           }
1046         }
1047         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1048         TDF_Label aSubContext =
1049           mySubSelList.back().restoreByName(aSubStr, aSubShapeType, theNameGenerator);
1050         if (aSubContext.IsNull())
1051           return aSubContext; // invalid sub-selection parsing
1052         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1053           if (!theNameGenerator->isLater(aContext, aSubContext))
1054             aContext = aSubContext;
1055         } else {
1056           aContext = aSubContext;
1057         }
1058       } else
1059         return TDF_Label(); // invalid parentheses
1060     }
1061     return aContext;
1062   } else if (theName[0] == '(') { // filter by neighbors
1063     myType = SELTYPE_FILTER_BY_NEIGHBOR;
1064     TDF_Label aContext;
1065     for(size_t aStart = 0; aStart != std::string::npos;
1066       aStart = theName.find('(', aStart + 1)) {
1067       size_t anEndPos = theName.find(')', aStart + 1);
1068       if (anEndPos != std::string::npos) {
1069         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1070         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1071         TDF_Label aSubContext =
1072           mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
1073         if (aSubContext.IsNull())
1074           return aSubContext; // invalid sub-selection parsing
1075         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1076           if (!theNameGenerator->isLater(aContext, aSubContext))
1077             aContext = aSubContext;
1078         } else {
1079           aContext = aSubContext;
1080         }
1081         if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
1082           aContext = theNameGenerator->newestContext(aContext);
1083
1084         // searching for the level index
1085         std::string aLevel;
1086         for(anEndPos++; anEndPos != std::string::npos &&
1087                         theName[anEndPos] != '(' && theName[anEndPos] != 0;
1088             anEndPos++) {
1089           aLevel += theName[anEndPos];
1090         }
1091         if (aLevel.empty())
1092           myNBLevel.push_back(1); // by default it is 1
1093         else {
1094           int aNum = atoi(aLevel.c_str());
1095           if (aNum > 0)
1096             myNBLevel.push_back(aNum);
1097           else
1098             return TDF_Label(); // invalid number
1099         }
1100       } else
1101         return TDF_Label(); // invalid parentheses
1102     }
1103     return aContext;
1104   } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1105     myType = SELTYPE_WEAK_NAMING;
1106     std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1107     std::size_t aContextPosition = aWeakIndex.find("_");
1108     myWeakIndex = atoi(aWeakIndex.c_str());
1109     myShapeType = theShapeType;
1110     TDF_Label aContext;
1111     if (aContextPosition != std::string::npos) { // context is also defined
1112       std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1113       theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1114     }
1115     return aContext;
1116   } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive
1117     myType = SELTYPE_PRIMITIVE;
1118     TDF_Label aContext;
1119     if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1120       if (!myFinal.IsNull())
1121         return aContext;
1122     }
1123   } else { // modification
1124     myType = SELTYPE_MODIFICATION;
1125     TDF_Label aContext;
1126     for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1127       if (aStart != 0)
1128         aStart++;
1129       anEnd = theName.find('&', aStart);
1130       std::string aSubStr =
1131         theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1132       if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1133         std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1134         myWeakIndex = atoi(aWeakIndex.c_str());
1135         continue;
1136       }
1137       TDF_Label aSubContext, aValue;
1138       if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1139         return TDF_Label(); // can not restore
1140       if(aSubContext.IsNull() || aValue.IsNull())
1141         return TDF_Label(); // can not restore
1142       if (myFinal.IsNull()) {
1143         myFinal = aValue;
1144         aContext = aSubContext;
1145       } else
1146         myBases.Append(aValue);
1147     }
1148     return aContext;
1149   }
1150   return TDF_Label();
1151 }
1152
1153 bool Selector_Selector::selectBySubSelector(
1154   const TopoDS_Shape theContext, const TopoDS_Shape theValue,
1155   const bool theUseNeighbors, const bool theUseIntersections)
1156 {
1157   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1158   if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors, theUseIntersections)) {
1159     mySubSelList.clear(); // if one of the selector is failed, all become invalid
1160     return false;
1161   }
1162   return true;
1163 }