]> SALOME platform Git repositories - modules/shaper.git/blob - src/Selector/Selector_Selector.cpp
Salome HOME
Name generation in the selector
[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
25 #include <TDF_ChildIDIterator.hxx>
26 #include <TopoDS_Iterator.hxx>
27 #include <TopoDS_Builder.hxx>
28 #include <TopExp_Explorer.hxx>
29 #include <TNaming_Tool.hxx>
30 #include <TNaming_NewShapeIterator.hxx>
31 #include <TNaming_OldShapeIterator.hxx>
32 #include <TNaming_SameShapeIterator.hxx>
33 #include <TNaming_Iterator.hxx>
34 #include <TNaming_Builder.hxx>
35 #include <TopTools_MapOfShape.hxx>
36
37 #include <TDataStd_Integer.hxx>
38 #include <TDataStd_ReferenceArray.hxx>
39 #include <TDataStd_IntegerArray.hxx>
40 #include <TDataStd_Name.hxx>
41
42 #include <list>
43
44 /// type of the selection, integerm keeps the Selector_Type value
45 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
46 /// type of the shape, stored in case it is intersection or container
47 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
48 //  reference attribute that contains the reference to labels where the "from" or "base" shapes
49 // of selection are located
50 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
51 // array of the neighbor levels
52 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
53
54 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
55 {
56 }
57
58 TDF_Label Selector_Selector::label()
59 {
60   return myLab;
61 }
62
63 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
64 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
65   bool aMustBeAtFinal, TDF_LabelList& theResult)
66 {
67   TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
68   for(; aLabIter.More(); aLabIter.Next()) {
69     Handle(TNaming_NamedShape) aNS;
70     aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
71     if (aMustBeAtFinal && aNS != theFinal)
72       continue; // looking for old at the same final label only
73     TNaming_Evolution anEvolution = aNS->Evolution();
74     if (anEvolution == TNaming_PRIMITIVE) {
75       // check that this is not in the results already
76       const TDF_Label aResult = aNS->Label();
77       TDF_LabelList::Iterator aResIter(theResult);
78       for(; aResIter.More(); aResIter.Next()) {
79         if (aResIter.Value().IsEqual(aResult))
80           break;
81       }
82       if (!aResIter.More()) // not found, so add this new
83         theResult.Append(aResult);
84     }
85     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
86       for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
87         if (aThisIter.NewShape().IsSame(theValue)) {
88           // continue recursively, null NS means that any NS are ok
89           findBases(theFinal, aThisIter.OldShape(), false, theResult);
90         }
91       }
92     }
93   }
94 }
95
96 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
97 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
98   TopoDS_ListOfShape& theResults)
99 {
100   TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
101   for(; aSubSel != theShapes.end(); aSubSel++) {
102     TopTools_MapOfShape aCurrentMap;
103     for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
104       if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
105         theResults.Append(anExp.Current());
106     }
107     if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
108       for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
109         if (aCurrentMap.Contains(aComIter.Value()))
110           aComIter.Next();
111         else
112           theResults.Remove(aComIter);
113       }
114     }
115   }
116 }
117
118 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
119 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
120   const int theLevel, TopTools_MapOfShape& theResult)
121 {
122   TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
123   if (theValue.ShapeType() == TopAbs_FACE)
124     aConnectorType = TopAbs_EDGE;
125   TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
126   for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
127     aNBConnectors.Add(aValExp.Current());
128   }
129
130   for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
131     TopoDS_ListOfShape aGoodCandidates;
132     TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
133     for(; aCandidate.More(); aCandidate.Next()) {
134       TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
135       for(; aCandConnector.More(); aCandConnector.Next()) {
136         if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
137           break;
138       }
139       if (aCandConnector.More()) {
140         if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
141           theResult.Add(aCandidate.Current());
142         } else { // add to the NB of the current level
143           aGoodCandidates.Append(aCandidate.Current());
144         }
145       }
146     }
147     if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
148       for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
149         TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
150         for(; aGoodConnector.More(); aGoodConnector.Next()) {
151           aNBConnectors.Add(aGoodConnector.Current());
152         }
153       }
154     }
155   }
156 }
157
158 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
159 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
160   const std::list<std::pair<TopoDS_Shape, int> >& theNB)
161 {
162   // searching for neighbors with minimum level
163   int aMinLevel = 0;
164   std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
165   for(; aNBIter != theNB.cend(); aNBIter++) {
166     if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
167       aMinLevel = aNBIter->second;
168     }
169   }
170   // collect all neighbors which are neighbors of sub-shapes with minimum level
171   bool aFirst = true;
172   TopoDS_ListOfShape aMatches;
173   for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
174     if (aNBIter->second == aMinLevel) {
175       TopTools_MapOfShape aThisNBs;
176       findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
177       // aMatches must contain common part of all NBs lists
178       for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
179         if (aFirst) {
180           aMatches.Append(aThisNB.Value());
181         } else {
182           // remove all in aMatches which are not in this NBs
183           for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
184             if (aThisNBs.Contains(aMatch.Value())) {
185               aMatch.Next();
186             } else {
187               aMatches.Remove(aMatch);
188             }
189           }
190         }
191       }
192     }
193   }
194   if (aMatches.IsEmpty())
195     return TopoDS_Shape(); // not found any candidate
196   if (aMatches.Extent() == 1)
197     return aMatches.First(); // already found good candidate
198   // iterate all matches to find by other (higher level) neighbors the best candidate
199   TopoDS_Shape aGoodCandidate;
200   for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
201     bool aValidCadidate = true;
202     for(int aLevel = aMinLevel + 1; true; aLevel++) {
203       bool aFooundHigherLevel = false;
204       TopoDS_ListOfShape aLevelNBs;
205       for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
206         if (aNBIter->second == aLevel)
207           aLevelNBs.Append(aNBIter->first);
208         else if (aNBIter->second >= aLevel)
209           aFooundHigherLevel = true;
210       }
211       if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
212         if (aGoodCandidate.IsNull()) {
213           aGoodCandidate = aCandidate.Value();
214         } else { // too many good candidates
215           return TopoDS_Shape();
216         }
217       }
218       if (!aLevelNBs.IsEmpty()) {
219         TopTools_MapOfShape aNBsOfCandidate;
220         findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
221         // check all stored neighbors are in the map of real neighbors
222         for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
223           if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
224             aValidCadidate = false;
225             break;
226           }
227         }
228       }
229       if (!aValidCadidate) // candidate is not valid, break the checking
230         break;
231     }
232   }
233   return aGoodCandidate;
234 }
235
236 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
237   const bool theUseNeighbors)
238 {
239   if (theValue.IsNull() || theContext.IsNull())
240     return false;
241   // check the value shape can be named as it is, or it is needed to construct it from the
242   // higher level shapes (like a box vertex by faces that form this vertex)
243   if (!TNaming_Tool::HasLabel(myLab, theValue)) {
244     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
245     myShapeType = aSelectionType;
246     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
247         aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
248     { // iterate all sub-shapes and select them on sublabels
249       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
250         if (!selectBySubSelector(theContext, aSubIter.Value())) {
251           return false; // if some selector is failed, everything is failed
252         }
253       }
254       myType = SELTYPE_CONTAINER;
255       return true;
256     }
257
258     // try to find the shape of the higher level type in the context shape
259     bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
260     while(aSelectionType != TopAbs_FACE || !aFacesTried) {
261       if (aSelectionType == TopAbs_FACE && theValue.ShapeType() == TopAbs_VERTEX) {
262         aFacesTried = true;
263         aSelectionType = TopAbs_EDGE;
264       } else
265         aSelectionType = TopAbs_FACE;
266       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
267       TopoDS_ListOfShape anIntList; // same as anIntersectors
268       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
269         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
270         for(; aSubExp.More(); aSubExp.Next()) {
271           if (aSubExp.Current().IsSame(theValue)) {
272             if (anIntersectors.Add(aSelExp.Current()))
273               anIntList.Append(aSelExp.Current());
274             break;
275           }
276         }
277       }
278       // check that solution is only one
279       TopoDS_ListOfShape aCommon;
280       commonShapes(anIntList, theValue.ShapeType(), aCommon);
281       if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
282         // name the intersectors
283         std::list<Selector_Selector> aSubSelList;
284         TopTools_MapOfShape::Iterator anInt(anIntersectors);
285         for (; anInt.More(); anInt.Next()) {
286           if (!selectBySubSelector(theContext, anInt.Value())) {
287             break; // if some selector is failed, stop and search another solution
288           }
289         }
290         if (!anInt.More()) { // all intersectors were correctly named
291           myType = SELTYPE_INTERSECT;
292           return true;
293         }
294       }
295     }
296
297     if (!theUseNeighbors)
298       return false;
299
300     // searching by neighbours
301     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
302     for(int aLevel = 1; true; aLevel++) {
303       TopTools_MapOfShape aNewNB;
304       findNeighbors(theContext, theValue, aLevel, aNewNB);
305       if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
306         break;
307       }
308       // check which can be named correctly, without by neighbors type
309       for(TopTools_MapOfShape::Iterator aNBIter(aNewNB); aNBIter.More(); ) {
310         Selector_Selector aSelector(myLab.FindChild(1));
311         if (aSelector.select(theContext, aNBIter.Value(), false)) { // add to the list of good NBs
312           aNBs.push_back(std::pair<TopoDS_Shape, int>(aNBIter.Value(), aLevel));
313         }
314         aNewNB.Remove(aNBIter.Key());
315         aNBIter.Initialize(aNewNB);
316       }
317       TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
318       if (!aResult.IsNull() && aResult.IsSame(theValue)) {
319         std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
320         for(; aNBIter != aNBs.end(); aNBIter++) {
321           if (!selectBySubSelector(theContext, aNBIter->first)) {
322             return false; // something is wrong because before this selection was ok
323           }
324           myNBLevel.push_back(aNBIter->second);
325
326         }
327         myType = SELTYPE_FILTER_BY_NEIGHBOR;
328         return true;
329       }
330     }
331     return false;
332   }
333   // searching for the base shapes of the value
334   Handle(TNaming_NamedShape) aPrimitiveNS;
335   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
336   for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
337   {
338     Handle(TNaming_NamedShape) aNS;
339     if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
340       TNaming_Evolution anEvolution = aNS->Evolution();
341       if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
342         aPrimitiveNS = aNS;
343         break;
344       } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
345         // check this is a new shape
346         TNaming_Iterator aNSIter(aNS);
347         for(; aNSIter.More(); aNSIter.Next())
348           if (aNSIter.NewShape().IsSame(theValue))
349             break;
350         if (aNSIter.More()) // new was found
351           aModifList.Append(aNS);
352       }
353     }
354   }
355
356   if (!aPrimitiveNS.IsNull()) {
357     myType = SELTYPE_PRIMITIVE;
358     myFinal = aPrimitiveNS->Label();
359     return true;
360   }
361
362   if (aModifList.Extent() > 1) { // searching for the best modification result: by context
363     Handle(TNaming_NamedShape) aCandidate;
364     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
365     for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
366        aCandidate = aModIter.Value();
367       TDF_Label aFatherLab = aCandidate->Label().Father();
368       Handle(TNaming_NamedShape) aFatherNS;
369       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
370         for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
371           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
372             aModifList.Clear();
373             break;
374           }
375         }
376       }
377     }
378     // take the best candidate, or the last in the iteration
379     aModifList.Clear();
380     aModifList.Append(aCandidate);
381   }
382
383   if (!aModifList.IsEmpty()) {
384     // searching for all the base shapes of this modification
385     findBases(aModifList.First(), theValue, true, myBases);
386     if (!myBases.IsEmpty()) {
387       myFinal = aModifList.First()->Label();
388       myType = SELTYPE_MODIFICATION;
389       return !myBases.IsEmpty();
390     }
391   }
392
393   // not found a good result
394   return false;
395 }
396
397 void Selector_Selector::store()
398 {
399   myLab.ForgetAllAttributes(true); // remove old naming data
400   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
401   switch(myType) {
402   case SELTYPE_CONTAINER:
403   case SELTYPE_INTERSECT: {
404     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
405     // store also all sub-selectors
406     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
407     for(; aSubSel != mySubSelList.end(); aSubSel++) {
408       aSubSel->store();
409     }
410     break;
411   }
412   case SELTYPE_PRIMITIVE: {
413     Handle(TDataStd_ReferenceArray) anArray =
414       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
415     anArray->SetValue(0, myFinal);
416     break;
417   }
418   case SELTYPE_MODIFICATION: {
419     Handle(TDataStd_ReferenceArray) anArray =
420       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
421     TDF_LabelList::Iterator aBIter(myBases);
422     for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
423       anArray->SetValue(anIndex, aBIter.Value());
424     }
425     anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
426     break;
427   }
428   case SELTYPE_FILTER_BY_NEIGHBOR: {
429     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
430     // store numbers of levels corresponded to the neighbors in sub-selectors
431     Handle(TDataStd_IntegerArray) anArray =
432       TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
433     std::list<int>::iterator aLevel = myNBLevel.begin();
434     for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
435       anArray->SetValue(anIndex, *aLevel);
436     }
437     // store all sub-selectors
438     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
439     for(; aSubSel != mySubSelList.end(); aSubSel++) {
440       aSubSel->store();
441     }
442   }
443   default: { // unknown case
444     break;
445   }
446   }
447 }
448
449 bool Selector_Selector::restore()
450 {
451   Handle(TDataStd_Integer) aTypeAttr;
452   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
453     return false;
454   myType = Selector_Type(aTypeAttr->Get());
455   switch(myType) {
456   case SELTYPE_CONTAINER:
457   case SELTYPE_INTERSECT: {
458     Handle(TDataStd_Integer) aShapeTypeAttr;
459     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
460       return false;
461     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
462     // restore sub-selectors
463     bool aSubResult = true;
464     mySubSelList.clear();
465     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
466       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
467       if (!mySubSelList.back().restore())
468         aSubResult = false;
469     }
470     return aSubResult;
471   }
472   case SELTYPE_PRIMITIVE: {
473     Handle(TDataStd_ReferenceArray) anArray;
474     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
475       myFinal = anArray->Value(0);
476       return true;
477     }
478     return false;
479   }
480   case SELTYPE_MODIFICATION: {
481     Handle(TDataStd_ReferenceArray) anArray;
482     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
483       int anUpper = anArray->Upper();
484       for(int anIndex = 0; anIndex < anUpper; anIndex++) {
485         myBases.Append(anArray->Value(anIndex));
486       }
487       myFinal = anArray->Value(anUpper);
488       return true;
489     }
490     return false;
491   }
492   case SELTYPE_FILTER_BY_NEIGHBOR: {
493     Handle(TDataStd_Integer) aShapeTypeAttr;
494     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
495       return false;
496     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
497     // restore sub-selectors
498     bool aSubResult = true;
499     mySubSelList.clear();
500     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
501       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
502       if (!mySubSelList.back().restore())
503         aSubResult = false;
504     }
505     // restore levels indices
506     Handle(TDataStd_IntegerArray) anArray;
507     if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
508       return false;
509     for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
510       myNBLevel.push_back(anArray->Value(anIndex));
511     }
512     return true;
513   }
514   default: { // unknown case
515   }
516   }
517   return false;
518 }
519
520 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
521 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
522   TopTools_MapOfShape& theResults)
523 {
524   for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
525     TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
526     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
527       if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
528         theResults.Add(aBaseIter.Shape());
529       } else {
530         findFinals(aBaseIter.Shape(), theFinal, theResults);
531       }
532     }
533   }
534
535 }
536
537 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
538 {
539   TopoDS_Shape aResult; // null if invalid
540   switch(myType) {
541   case SELTYPE_CONTAINER: {
542     TopoDS_Builder aBuilder;
543     switch(myShapeType) {
544     case TopAbs_COMPOUND: {
545       TopoDS_Compound aComp;
546       aBuilder.MakeCompound(aComp);
547       aResult = aComp;
548       break;
549       }
550     case TopAbs_COMPSOLID: {
551       TopoDS_CompSolid aComp;
552       aBuilder.MakeCompSolid(aComp);
553       aResult = aComp;
554       break;
555     }
556     case TopAbs_SHELL: {
557       TopoDS_Shell aShell;
558       aBuilder.MakeShell(aShell);
559       aResult = aShell;
560       break;
561     }
562     case TopAbs_WIRE: {
563       TopoDS_Wire aWire;
564       aBuilder.MakeWire(aWire);
565       aResult = aWire;
566       break;
567     }
568     }
569     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
570     for(; aSubSel != mySubSelList.end(); aSubSel++) {
571       if (!aSubSel->solve(theContext)) {
572         return false;
573       }
574       aBuilder.Add(aResult, aSubSel->value());
575     }
576     break;
577   }
578   case SELTYPE_INTERSECT: {
579     TopoDS_ListOfShape aSubSelectorShapes;
580     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
581     for(; aSubSel != mySubSelList.end(); aSubSel++) {
582       if (!aSubSel->solve(theContext)) {
583         return false;
584       }
585       aSubSelectorShapes.Append(aSubSel->value());
586     }
587     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
588     commonShapes(aSubSelectorShapes, myShapeType, aCommon);
589     if (aCommon.Extent() != 1)
590       return false;
591     aResult = aCommon.First();
592     break;
593   }
594   case SELTYPE_PRIMITIVE: {
595     Handle(TNaming_NamedShape) aNS;
596     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
597       aResult = aNS->Get();
598     }
599   }
600   case SELTYPE_MODIFICATION: {
601     TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
602     for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
603       TopTools_MapOfShape aFinals;
604       for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
605         findFinals(aBaseShape.NewShape(), myFinal, aFinals);
606       if (!aFinals.IsEmpty()) {
607         if (aFinalsCommon.IsEmpty()) { // just copy all to common
608           for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
609             aFinalsCommon.Append(aFinal.Key());
610           }
611         } else { // keep only shapes presented in both lists
612           for(TopoDS_ListOfShape::Iterator aCommon(aFinalsCommon); aCommon.More(); ) {
613             if (aFinals.Contains(aCommon.Value())) {
614               aCommon.Next();
615             } else { // common is not found, remove it
616               aFinalsCommon.Remove(aCommon);
617             }
618           }
619         }
620       }
621     }
622     if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
623       aResult = aFinalsCommon.First();
624     break;
625   }
626   case SELTYPE_FILTER_BY_NEIGHBOR: {
627     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
628     std::list<int>::iterator aLevel = myNBLevel.begin();
629     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
630     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
631       if (!aSubSel->solve(theContext)) {
632         return false;
633       }
634       aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
635     }
636     aResult = findNeighbor(theContext, aNBs);
637   }
638   default: { // unknown case
639   }
640   }
641
642   TNaming_Builder aBuilder(myLab);
643   if (!aResult.IsNull()) {
644     aBuilder.Select(aResult, aResult);
645     return true;
646   }
647   return false; // builder just erases the named shape in case of error
648 }
649
650 TopoDS_Shape Selector_Selector::value()
651 {
652   Handle(TNaming_NamedShape) aNS;
653   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
654     return aNS->Get();
655   return TopoDS_Shape(); // empty, error shape
656 }
657
658 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
659   switch(myType) {
660   case SELTYPE_CONTAINER:
661   case SELTYPE_INTERSECT: {
662     std::string aResult;
663     // add names of sub-components one by one separated by "&"
664     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
665     for(; aSubSel != mySubSelList.end(); aSubSel++) {
666       if (aSubSel != mySubSelList.begin())
667         aResult += "&";
668       aResult += aSubSel->name(theNameGenerator);
669     }
670     return aResult;
671   }
672   case SELTYPE_PRIMITIVE: {
673     Handle(TDataStd_Name) aName;
674     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
675       return "";
676     return theNameGenerator->contextName(myFinal) + "/" +
677       std::string(TCollection_AsciiString(aName->Get()).ToCString());
678   }
679   case SELTYPE_MODIFICATION: {
680     // final&/base1&base2
681     std::string aResult;
682     Handle(TDataStd_Name) aName;
683     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
684       return "";
685     aResult += theNameGenerator->contextName(myFinal) + "/" +
686       std::string(TCollection_AsciiString(aName->Get()).ToCString()) + "&/";
687     for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
688       if (aBase != myBases.begin())
689         aResult += "&";
690       if (aBase->FindAttribute(TDataStd_Name::GetID(), aName))
691         return "";
692       aResult += theNameGenerator->contextName(*aBase) + "/" +
693         std::string(TCollection_AsciiString(aName->Get()).ToCString());
694     }
695     return aResult;
696   }
697   case SELTYPE_FILTER_BY_NEIGHBOR: {
698     // (nb1)level_if_more_than_1&(nb2)level_if_more_than_1&(nb3)level_if_more_than_1
699     std::string aResult;
700     std::list<int>::iterator aLevel = myNBLevel.begin();
701     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
702     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
703       if (aSubSel != mySubSelList.begin())
704         aResult += "&";
705       aResult += "(" + aSubSel->name(theNameGenerator) + ")";
706       if (*aLevel > 1)
707         aResult += *aLevel;
708     }
709     return aResult;
710   }
711   default: { // unknown case
712   }
713   };
714   return "";
715 }
716
717 bool Selector_Selector::selectBySubSelector(
718   const TopoDS_Shape theContext, const TopoDS_Shape theValue)
719 {
720   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
721   if (!mySubSelList.back().select(theContext, theValue)) {
722     mySubSelList.clear(); // if one of the selector is failed, all become invalid
723     return false;
724   }
725   return true;
726 }