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