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