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