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