Salome HOME
Debug of move to the end of history
[modules/shaper.git] / src / Selector / Selector_Selector.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include <Selector_Selector.h>
22
23 #include <Selector_NameGenerator.h>
24 #include <Selector_NExplode.h>
25
26 #include <TDF_ChildIDIterator.hxx>
27 #include <TopoDS_Iterator.hxx>
28 #include <TopoDS_Builder.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TNaming_Tool.hxx>
31 #include <TNaming_NewShapeIterator.hxx>
32 #include <TNaming_OldShapeIterator.hxx>
33 #include <TNaming_SameShapeIterator.hxx>
34 #include <TNaming_Iterator.hxx>
35 #include <TNaming_Builder.hxx>
36 #include <TopTools_MapOfShape.hxx>
37
38 #include <TDataStd_Integer.hxx>
39 #include <TDataStd_ReferenceArray.hxx>
40 #include <TDataStd_IntegerArray.hxx>
41 #include <TDataStd_Name.hxx>
42
43 #include <list>
44
45 /// type of the selection, integerm keeps the Selector_Type value
46 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
47 /// type of the shape, stored in case it is intersection or container
48 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
49 //  reference attribute that contains the reference to labels where the "from" or "base" shapes
50 // of selection are located
51 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
52 // array of the neighbor levels
53 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
54 // weak index (integer) of the sub-shape
55 static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
56
57 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
58 {
59   myWeakIndex = -1;
60 }
61
62 TDF_Label Selector_Selector::label()
63 {
64   return myLab;
65 }
66
67 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
68 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
69   bool aMustBeAtFinal, TDF_LabelList& theResult)
70 {
71   TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
72   for(; aLabIter.More(); aLabIter.Next()) {
73     Handle(TNaming_NamedShape) aNS;
74     aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
75     if (aMustBeAtFinal && aNS != theFinal)
76       continue; // looking for old at the same final label only
77     TNaming_Evolution anEvolution = aNS->Evolution();
78     if (anEvolution == TNaming_PRIMITIVE) {
79       // check that this is not in the results already
80       const TDF_Label aResult = aNS->Label();
81       TDF_LabelList::Iterator aResIter(theResult);
82       for(; aResIter.More(); aResIter.Next()) {
83         if (aResIter.Value().IsEqual(aResult))
84           break;
85       }
86       if (!aResIter.More()) // not found, so add this new
87         theResult.Append(aResult);
88     }
89     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
90       for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
91         if (aThisIter.NewShape().IsSame(theValue)) {
92           // continue recursively, null NS means that any NS are ok
93           findBases(theFinal, aThisIter.OldShape(), false, theResult);
94         }
95       }
96     }
97   }
98 }
99
100 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
101 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
102   TopoDS_ListOfShape& theResults)
103 {
104   TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
105   for(; aSubSel != theShapes.end(); aSubSel++) {
106     TopTools_MapOfShape aCurrentMap;
107     for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
108       if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
109         theResults.Append(anExp.Current());
110     }
111     if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
112       for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
113         if (aCurrentMap.Contains(aComIter.Value()))
114           aComIter.Next();
115         else
116           theResults.Remove(aComIter);
117       }
118     }
119   }
120 }
121
122 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
123 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
124   const int theLevel, TopTools_MapOfShape& theResult)
125 {
126   TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
127   if (theValue.ShapeType() == TopAbs_FACE)
128     aConnectorType = TopAbs_EDGE;
129   TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
130   for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
131     aNBConnectors.Add(aValExp.Current());
132   }
133
134   TopTools_MapOfShape alreadyProcessed;
135   alreadyProcessed.Add(theValue);
136
137   for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
138     TopoDS_ListOfShape aGoodCandidates;
139     TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
140     for(; aCandidate.More(); aCandidate.Next()) {
141       if (alreadyProcessed.Contains(aCandidate.Current()))
142         continue;
143       TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
144       for(; aCandConnector.More(); aCandConnector.Next()) {
145         if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
146           break;
147       }
148       if (aCandConnector.More()) {
149         if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
150           theResult.Add(aCandidate.Current());
151         } else { // add to the NB of the current level
152           aGoodCandidates.Append(aCandidate.Current());
153         }
154       }
155     }
156     if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
157       for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
158         TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
159         for(; aGoodConnector.More(); aGoodConnector.Next()) {
160           aNBConnectors.Add(aGoodConnector.Current());
161         }
162         alreadyProcessed.Add(aGood.Value());
163       }
164     }
165   }
166 }
167
168 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
169 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
170   const std::list<std::pair<TopoDS_Shape, int> >& theNB)
171 {
172   // searching for neighbors with minimum level
173   int aMinLevel = 0;
174   std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
175   for(; aNBIter != theNB.cend(); aNBIter++) {
176     if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
177       aMinLevel = aNBIter->second;
178     }
179   }
180   // collect all neighbors which are neighbors of sub-shapes with minimum level
181   bool aFirst = true;
182   TopoDS_ListOfShape aMatches;
183   for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
184     if (aNBIter->second == aMinLevel) {
185       TopTools_MapOfShape aThisNBs;
186       findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
187       // aMatches must contain common part of all NBs lists
188       for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
189         if (aFirst) {
190           aMatches.Append(aThisNB.Value());
191         } else {
192           // remove all in aMatches which are not in this NBs
193           for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
194             if (aThisNBs.Contains(aMatch.Value())) {
195               aMatch.Next();
196             } else {
197               aMatches.Remove(aMatch);
198             }
199           }
200         }
201       }
202       aFirst = false;
203     }
204   }
205   if (aMatches.IsEmpty())
206     return TopoDS_Shape(); // not found any candidate
207   if (aMatches.Extent() == 1)
208     return aMatches.First(); // already found good candidate
209   // iterate all matches to find by other (higher level) neighbors the best candidate
210   TopoDS_Shape aGoodCandidate;
211   for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
212     bool aValidCadidate = true;
213     for(int aLevel = aMinLevel + 1; true; aLevel++) {
214       bool aFooundHigherLevel = false;
215       TopoDS_ListOfShape aLevelNBs;
216       for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
217         if (aNBIter->second == aLevel)
218           aLevelNBs.Append(aNBIter->first);
219         else if (aNBIter->second >= aLevel)
220           aFooundHigherLevel = true;
221       }
222       if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
223         if (aGoodCandidate.IsNull()) {
224           aGoodCandidate = aCandidate.Value();
225         } else { // too many good candidates
226           return TopoDS_Shape();
227         }
228       }
229       if (!aLevelNBs.IsEmpty()) {
230         TopTools_MapOfShape aNBsOfCandidate;
231         findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
232         // check all stored neighbors are in the map of real neighbors
233         for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
234           if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
235             aValidCadidate = false;
236             break;
237           }
238         }
239       }
240       if (!aValidCadidate) // candidate is not valid, break the checking
241         break;
242     }
243   }
244   return aGoodCandidate;
245 }
246
247 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
248   const bool theUseNeighbors)
249 {
250   if (theValue.IsNull() || theContext.IsNull())
251     return false;
252   // check the value shape can be named as it is, or it is needed to construct it from the
253   // higher level shapes (like a box vertex by faces that form this vertex)
254   if (!TNaming_Tool::HasLabel(myLab, theValue)) {
255     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
256     myShapeType = aSelectionType;
257     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
258         aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
259     { // iterate all sub-shapes and select them on sublabels
260       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
261         if (!selectBySubSelector(theContext, aSubIter.Value())) {
262           return false; // if some selector is failed, everything is failed
263         }
264       }
265       myType = SELTYPE_CONTAINER;
266       return true;
267     }
268
269     // try to find the shape of the higher level type in the context shape
270     bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
271     while(aSelectionType != TopAbs_FACE || !aFacesTried) {
272       if (aSelectionType == TopAbs_FACE) {
273         if (theValue.ShapeType() != TopAbs_VERTEX)
274           break;
275         aFacesTried = true;
276         aSelectionType = TopAbs_EDGE;
277       } else
278         aSelectionType = TopAbs_FACE;
279       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
280       TopoDS_ListOfShape anIntList; // same as anIntersectors
281       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
282         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
283         for(; aSubExp.More(); aSubExp.Next()) {
284           if (aSubExp.Current().IsSame(theValue)) {
285             if (anIntersectors.Add(aSelExp.Current()))
286               anIntList.Append(aSelExp.Current());
287             break;
288           }
289         }
290       }
291       // check that solution is only one
292       TopoDS_ListOfShape aCommon;
293       commonShapes(anIntList, theValue.ShapeType(), aCommon);
294       if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
295         // name the intersectors
296         std::list<Selector_Selector> aSubSelList;
297         TopTools_MapOfShape::Iterator anInt(anIntersectors);
298         for (; anInt.More(); anInt.Next()) {
299           if (!selectBySubSelector(theContext, anInt.Value())) {
300             break; // if some selector is failed, stop and search another solution
301           }
302         }
303         if (!anInt.More()) { // all intersectors were correctly named
304           myType = SELTYPE_INTERSECT;
305           return true;
306         }
307       }
308     }
309
310     if (!theUseNeighbors)
311       return false;
312
313     // searching by neighbours
314     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
315     for(int aLevel = 1; true; aLevel++) {
316       TopTools_MapOfShape aNewNB;
317       findNeighbors(theContext, theValue, aLevel, aNewNB);
318       if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
319         break;
320       }
321       // check which can be named correctly, without by neighbors type
322       for(TopTools_MapOfShape::Iterator aNBIter(aNewNB); aNBIter.More(); ) {
323         Selector_Selector aSelector(myLab.FindChild(1));
324         if (aSelector.select(theContext, aNBIter.Value(), false)) { // add to the list of good NBs
325           aNBs.push_back(std::pair<TopoDS_Shape, int>(aNBIter.Value(), aLevel));
326         }
327         aNewNB.Remove(aNBIter.Key());
328         aNBIter.Initialize(aNewNB);
329       }
330       TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
331       if (!aResult.IsNull() && aResult.IsSame(theValue)) {
332         std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
333         for(; aNBIter != aNBs.end(); aNBIter++) {
334           if (!selectBySubSelector(theContext, aNBIter->first, false)) {
335             return false; // something is wrong because before this selection was ok
336           }
337           myNBLevel.push_back(aNBIter->second);
338
339         }
340         myType = SELTYPE_FILTER_BY_NEIGHBOR;
341         return true;
342       }
343     }
344     return false;
345   }
346   // searching for the base shapes of the value
347   Handle(TNaming_NamedShape) aPrimitiveNS;
348   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
349   for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
350   {
351     Handle(TNaming_NamedShape) aNS;
352     if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
353       TNaming_Evolution anEvolution = aNS->Evolution();
354       if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
355         aPrimitiveNS = aNS;
356         break;
357       } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
358         // check this is a new shape
359         TNaming_Iterator aNSIter(aNS);
360         for(; aNSIter.More(); aNSIter.Next())
361           if (aNSIter.NewShape().IsSame(theValue))
362             break;
363         if (aNSIter.More()) // new was found
364           aModifList.Append(aNS);
365       }
366     }
367   }
368
369   if (!aPrimitiveNS.IsNull()) {
370     myType = SELTYPE_PRIMITIVE;
371     myFinal = aPrimitiveNS->Label();
372     return true;
373   }
374
375   if (aModifList.Extent() > 1) { // searching for the best modification result: by context
376     Handle(TNaming_NamedShape) aCandidate;
377     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
378     for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
379        aCandidate = aModIter.Value();
380       TDF_Label aFatherLab = aCandidate->Label().Father();
381       Handle(TNaming_NamedShape) aFatherNS;
382       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
383         for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
384           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
385             aModifList.Clear();
386             break;
387           }
388         }
389       }
390     }
391     // take the best candidate, or the last in the iteration
392     aModifList.Clear();
393     aModifList.Append(aCandidate);
394   }
395
396   if (!aModifList.IsEmpty()) {
397     // searching for all the base shapes of this modification
398     findBases(aModifList.First(), theValue, true, myBases);
399     if (!myBases.IsEmpty()) {
400       myFinal = aModifList.First()->Label();
401       TopoDS_ListOfShape aCommon;
402       findModificationResult(aCommon);
403       // trying to search by neighbours
404       if (aCommon.Extent() > 1) { // more complicated selection
405         if (!theUseNeighbors)
406           return false;
407
408         // searching by neighbours
409         std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
410         for(int aLevel = 1; true; aLevel++) {
411           TopTools_MapOfShape aNewNB;
412           findNeighbors(theContext, theValue, aLevel, aNewNB);
413           if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
414             break;
415           }
416           // check which can be named correctly, without by neighbors type
417           for(TopTools_MapOfShape::Iterator aNBIter(aNewNB); aNBIter.More(); ) {
418             Selector_Selector aSelector(myLab.FindChild(1));
419             if (aSelector.select(theContext, aNBIter.Value(), false)) { // add to the list of good NBs
420               aNBs.push_back(std::pair<TopoDS_Shape, int>(aNBIter.Value(), aLevel));
421             }
422             aNewNB.Remove(aNBIter.Key());
423             aNBIter.Initialize(aNewNB);
424           }
425           TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
426           if (!aResult.IsNull() && aResult.IsSame(theValue)) {
427             std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
428             for(; aNBIter != aNBs.end(); aNBIter++) {
429               if (!selectBySubSelector(theContext, aNBIter->first)) {
430                 return false; // something is wrong because before this selection was ok
431               }
432               myNBLevel.push_back(aNBIter->second);
433
434             }
435             myType = SELTYPE_FILTER_BY_NEIGHBOR;
436             return true;
437           }
438         }
439         // filter by neighbours did not help
440         if (aCommon.Extent() > 1) { // weak naming between the common results
441           Selector_NExplode aNexp(aCommon);
442           myWeakIndex = aNexp.index(theValue);
443           if (myWeakIndex == -1)
444             return false;
445         }
446       }
447     }
448     myType = SELTYPE_MODIFICATION;
449     return !myBases.IsEmpty();
450   }
451
452   // not found a good result
453   return false;
454 }
455
456 void Selector_Selector::store()
457 {
458   myLab.ForgetAllAttributes(true); // remove old naming data
459   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
460   switch(myType) {
461   case SELTYPE_CONTAINER:
462   case SELTYPE_INTERSECT: {
463     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
464     // store also all sub-selectors
465     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
466     for(; aSubSel != mySubSelList.end(); aSubSel++) {
467       aSubSel->store();
468     }
469     break;
470   }
471   case SELTYPE_PRIMITIVE: {
472     Handle(TDataStd_ReferenceArray) anArray =
473       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
474     anArray->SetValue(0, myFinal);
475     break;
476   }
477   case SELTYPE_MODIFICATION: {
478     Handle(TDataStd_ReferenceArray) anArray =
479       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
480     TDF_LabelList::Iterator aBIter(myBases);
481     for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
482       anArray->SetValue(anIndex, aBIter.Value());
483     }
484     anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
485     if (myWeakIndex != -1) {
486       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
487     }
488     break;
489   }
490   case SELTYPE_FILTER_BY_NEIGHBOR: {
491     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
492     // store numbers of levels corresponded to the neighbors in sub-selectors
493     Handle(TDataStd_IntegerArray) anArray =
494       TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
495     std::list<int>::iterator aLevel = myNBLevel.begin();
496     for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
497       anArray->SetValue(anIndex, *aLevel);
498     }
499     // store all sub-selectors
500     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
501     for(; aSubSel != mySubSelList.end(); aSubSel++) {
502       aSubSel->store();
503     }
504   }
505   default: { // unknown case
506     break;
507   }
508   }
509 }
510
511 bool Selector_Selector::restore()
512 {
513   Handle(TDataStd_Integer) aTypeAttr;
514   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
515     return false;
516   myType = Selector_Type(aTypeAttr->Get());
517   switch(myType) {
518   case SELTYPE_CONTAINER:
519   case SELTYPE_INTERSECT: {
520     Handle(TDataStd_Integer) aShapeTypeAttr;
521     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
522       return false;
523     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
524     // restore sub-selectors
525     bool aSubResult = true;
526     mySubSelList.clear();
527     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
528       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
529       if (!mySubSelList.back().restore())
530         aSubResult = false;
531     }
532     return aSubResult;
533   }
534   case SELTYPE_PRIMITIVE: {
535     Handle(TDataStd_ReferenceArray) anArray;
536     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
537       myFinal = anArray->Value(0);
538       return true;
539     }
540     return false;
541   }
542   case SELTYPE_MODIFICATION: {
543     Handle(TDataStd_ReferenceArray) anArray;
544     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
545       int anUpper = anArray->Upper();
546       for(int anIndex = 0; anIndex < anUpper; anIndex++) {
547         myBases.Append(anArray->Value(anIndex));
548       }
549       myFinal = anArray->Value(anUpper);
550       Handle(TDataStd_Integer) aWeakInt;
551       if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
552         myWeakIndex = aWeakInt->Get();
553       }
554       return true;
555     }
556     return false;
557   }
558   case SELTYPE_FILTER_BY_NEIGHBOR: {
559     Handle(TDataStd_Integer) aShapeTypeAttr;
560     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
561       return false;
562     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
563     // restore sub-selectors
564     bool aSubResult = true;
565     mySubSelList.clear();
566     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
567       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
568       if (!mySubSelList.back().restore())
569         aSubResult = false;
570     }
571     // restore levels indices
572     Handle(TDataStd_IntegerArray) anArray;
573     if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
574       return false;
575     for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
576       myNBLevel.push_back(anArray->Value(anIndex));
577     }
578     return true;
579   }
580   default: { // unknown case
581   }
582   }
583   return false;
584 }
585
586 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
587 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
588   TopTools_MapOfShape& theResults)
589 {
590   for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
591     TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
592     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
593       if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
594         theResults.Add(aBaseIter.Shape());
595       } else {
596         findFinals(aBaseIter.Shape(), theFinal, theResults);
597       }
598     }
599   }
600 }
601
602 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
603   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
604     TopTools_MapOfShape aFinals;
605     for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
606       findFinals(aBaseShape.NewShape(), myFinal, aFinals);
607     if (!aFinals.IsEmpty()) {
608       if (theCommon.IsEmpty()) { // just copy all to common
609         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
610           theCommon.Append(aFinal.Key());
611         }
612       } else { // keep only shapes presented in both lists
613         for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
614           if (aFinals.Contains(aCommon.Value())) {
615             aCommon.Next();
616           } else { // common is not found, remove it
617             theCommon.Remove(aCommon);
618           }
619         }
620       }
621     }
622   }
623 }
624
625 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
626 {
627   TopoDS_Shape aResult; // null if invalid
628   switch(myType) {
629   case SELTYPE_CONTAINER: {
630     TopoDS_Builder aBuilder;
631     switch(myShapeType) {
632     case TopAbs_COMPOUND: {
633       TopoDS_Compound aComp;
634       aBuilder.MakeCompound(aComp);
635       aResult = aComp;
636       break;
637       }
638     case TopAbs_COMPSOLID: {
639       TopoDS_CompSolid aComp;
640       aBuilder.MakeCompSolid(aComp);
641       aResult = aComp;
642       break;
643     }
644     case TopAbs_SHELL: {
645       TopoDS_Shell aShell;
646       aBuilder.MakeShell(aShell);
647       aResult = aShell;
648       break;
649     }
650     case TopAbs_WIRE: {
651       TopoDS_Wire aWire;
652       aBuilder.MakeWire(aWire);
653       aResult = aWire;
654       break;
655     }
656     }
657     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
658     for(; aSubSel != mySubSelList.end(); aSubSel++) {
659       if (!aSubSel->solve(theContext)) {
660         return false;
661       }
662       aBuilder.Add(aResult, aSubSel->value());
663     }
664     break;
665   }
666   case SELTYPE_INTERSECT: {
667     TopoDS_ListOfShape aSubSelectorShapes;
668     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
669     for(; aSubSel != mySubSelList.end(); aSubSel++) {
670       if (!aSubSel->solve(theContext)) {
671         return false;
672       }
673       aSubSelectorShapes.Append(aSubSel->value());
674     }
675     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
676     commonShapes(aSubSelectorShapes, myShapeType, aCommon);
677     if (aCommon.Extent() != 1)
678       return false;
679     aResult = aCommon.First();
680     break;
681   }
682   case SELTYPE_PRIMITIVE: {
683     Handle(TNaming_NamedShape) aNS;
684     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
685       aResult = aNS->Get();
686     }
687   }
688   case SELTYPE_MODIFICATION: {
689     TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
690     findModificationResult(aFinalsCommon);
691     if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
692       aResult = aFinalsCommon.First();
693     else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
694       Selector_NExplode aNExp(aFinalsCommon);
695       aResult = aNExp.shape(myWeakIndex);
696
697     }
698     break;
699   }
700   case SELTYPE_FILTER_BY_NEIGHBOR: {
701     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
702     std::list<int>::iterator aLevel = myNBLevel.begin();
703     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
704     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
705       if (!aSubSel->solve(theContext)) {
706         return false;
707       }
708       aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
709     }
710     aResult = findNeighbor(theContext, aNBs);
711   }
712   default: { // unknown case
713   }
714   }
715
716   TNaming_Builder aBuilder(myLab);
717   if (!aResult.IsNull()) {
718     aBuilder.Select(aResult, aResult);
719     return true;
720   }
721   return false; // builder just erases the named shape in case of error
722 }
723
724 TopoDS_Shape Selector_Selector::value()
725 {
726   Handle(TNaming_NamedShape) aNS;
727   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
728     return aNS->Get();
729   return TopoDS_Shape(); // empty, error shape
730 }
731
732 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
733
734 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
735   switch(myType) {
736   case SELTYPE_CONTAINER:
737   case SELTYPE_INTERSECT: {
738     std::string aResult;
739     // add names of sub-components one by one in "[]"
740     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
741     for(; aSubSel != mySubSelList.end(); aSubSel++) {
742       aResult += '[';
743       aResult += aSubSel->name(theNameGenerator);
744       aResult += ']';
745     }
746     return aResult;
747   }
748   case SELTYPE_PRIMITIVE: {
749     Handle(TDataStd_Name) aName;
750     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
751       return "";
752     return theNameGenerator->contextName(myFinal) + "/" +
753       std::string(TCollection_AsciiString(aName->Get()).ToCString());
754   }
755   case SELTYPE_MODIFICATION: {
756     // final&base1&base2 +optionally: [weak_name_1]
757     std::string aResult;
758     Handle(TDataStd_Name) aName;
759     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
760       return "";
761     aResult += theNameGenerator->contextName(myFinal) + "/" +
762       std::string(TCollection_AsciiString(aName->Get()).ToCString()) + "&";
763     for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
764       if (aBase != myBases.begin())
765         aResult += "&";
766       if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
767         return "";
768       aResult += theNameGenerator->contextName(*aBase) + "/" +
769         std::string(TCollection_AsciiString(aName->Get()).ToCString());
770       if (myWeakIndex != -1) {
771         std::ostringstream aWeakStr;
772         aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
773         aResult += aWeakStr.str();
774       }
775     }
776     return aResult;
777   }
778   case SELTYPE_FILTER_BY_NEIGHBOR: {
779     // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
780     std::string aResult;
781     std::list<int>::iterator aLevel = myNBLevel.begin();
782     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
783     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
784       aResult += "(" + aSubSel->name(theNameGenerator) + ")";
785       if (*aLevel > 1)
786         aResult += *aLevel;
787     }
788     return aResult;
789   }
790   default: { // unknown case
791   }
792   };
793   return "";
794 }
795
796 TDF_Label Selector_Selector::restoreByName(
797   std::string theName, const TopAbs_ShapeEnum theShapeType,
798   Selector_NameGenerator* theNameGenerator)
799 {
800   if (theName[0] == '[') { // intersection or container
801     switch(theShapeType) {
802     case TopAbs_COMPOUND:
803     case TopAbs_COMPSOLID:
804     case TopAbs_SHELL:
805     case TopAbs_WIRE:
806       myType = SELTYPE_CONTAINER;
807       break;
808     case TopAbs_VERTEX:
809     case TopAbs_EDGE:
810     case TopAbs_FACE:
811       myType = SELTYPE_INTERSECT;
812       break;
813     default:
814       return TDF_Label(); // unknown case
815     }
816     myShapeType = theShapeType;
817     TDF_Label aContext;
818     for(size_t aStart = 0; aStart != std::string::npos;
819         aStart = theName.find('[', aStart + 1)) {
820       size_t anEndPos = theName.find(']', aStart + 1);
821       if (anEndPos != std::string::npos) {
822         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
823         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
824         TDF_Label aSubContext =
825           mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
826         if (aSubContext.IsNull())
827           return aSubContext; // invalid sub-selection parsing
828         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
829           if (!theNameGenerator->isLater(aContext, aSubContext))
830             aContext = aSubContext;
831         } else {
832           aContext = aSubContext;
833         }
834       } else
835         return TDF_Label(); // invalid parentheses
836     }
837     return aContext;
838   } else if (theName[0] == '(') { // filter by neighbours
839     myType = SELTYPE_FILTER_BY_NEIGHBOR;
840     TDF_Label aContext;
841     for(size_t aStart = 0; aStart != std::string::npos;
842       aStart = theName.find('(', aStart + 1)) {
843       size_t anEndPos = theName.find(')', aStart + 1);
844       if (anEndPos != std::string::npos) {
845         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
846         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
847         TDF_Label aSubContext =
848           mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
849         if (aSubContext.IsNull())
850           return aSubContext; // invalid sub-selection parsing
851         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
852           if (!theNameGenerator->isLater(aContext, aSubContext))
853             aContext = aSubContext;
854         } else {
855           aContext = aSubContext;
856         }
857         // searching for the level index
858         std::string aLevel;
859         for(anEndPos++; anEndPos != std::string::npos &&
860                         theName[anEndPos] != '(' && theName[anEndPos] != 0;
861             anEndPos++) {
862           aLevel += theName[anEndPos];
863         }
864         if (aLevel.empty())
865           myNBLevel.push_back(1); // by default it is 1
866         else {
867           int aNum = atoi(aLevel.c_str());
868           if (aNum > 0)
869             myNBLevel.push_back(aNum);
870           else
871             return TDF_Label(); // invalid number
872         }
873       } else
874         return TDF_Label(); // invalid parentheses
875     }
876     return aContext;
877   } else if (theName.find('&') == std::string::npos) { // wihtout '&' it can be only primitive
878     myType = SELTYPE_PRIMITIVE;
879     TDF_Label aContext;
880     if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
881       if (!myFinal.IsNull())
882         return aContext;
883     }
884   } else { // modification
885     myType = SELTYPE_MODIFICATION;
886     TDF_Label aContext;
887     for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
888       if (aStart != 0)
889         aStart++;
890       anEnd = theName.find('&', aStart);
891       std::string aSubStr =
892         theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
893       if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
894         std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
895         myWeakIndex = atoi(aWeakIndex.c_str());
896         continue;
897       }
898       TDF_Label aSubContext, aValue;
899       if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
900         return TDF_Label(); // can not restore
901       if(aSubContext.IsNull() || aValue.IsNull())
902         return TDF_Label(); // can not restore
903       if (myFinal.IsNull()) {
904         myFinal = aValue;
905         aContext = aSubContext;
906       } else
907         myBases.Append(aValue);
908     }
909     return aContext;
910   }
911   return TDF_Label();
912 }
913
914 bool Selector_Selector::selectBySubSelector(
915   const TopoDS_Shape theContext, const TopoDS_Shape theValue, const bool theUseNeighbors)
916 {
917   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
918   if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors)) {
919     mySubSelList.clear(); // if one of the selector is failed, all become invalid
920     return false;
921   }
922   return true;
923 }