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