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