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