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