]> SALOME platform Git repositories - modules/shaper.git/blob - src/Selector/Selector_Selector.cpp
Salome HOME
Fix for the Rubick model placement
[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   TopTools_MapOfShape aGoodCandidates; // already added good candidates to the map
273   for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
274     bool aValidCadidate = true;
275     for(int aLevel = aMinLevel + 1; true; aLevel++) {
276       bool aFooundHigherLevel = false;
277       TopoDS_ListOfShape aLevelNBs;
278       for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
279         if (aNBIter->second == aLevel)
280           aLevelNBs.Append(aNBIter->first);
281         else if (aNBIter->second >= aLevel)
282           aFooundHigherLevel = true;
283       }
284       if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
285         if (aGoodCandidate.IsNull()) {
286           aGoodCandidate = aCandidate.Value();
287         } else { // another good candidate
288           if (theGeometrical && sameGeometry(aGoodCandidate, aCandidate.Value())) {
289             if (!aGoodCandidates.Add(aCandidate.Value()))
290               break;
291             static TopoDS_Builder aBuilder;
292             if (aResultCompound.IsNull()) {
293               aBuilder.MakeCompound(aResultCompound);
294               aBuilder.Add(aResultCompound, aGoodCandidate);
295             }
296             aBuilder.Add(aResultCompound, aCandidate.Value());
297           } else
298             return TopoDS_Shape();
299         }
300       }
301       if (!aLevelNBs.IsEmpty()) {
302         TopTools_MapOfShape aNBsOfCandidate;
303         findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
304         // check all stored neighbors are in the map of real neighbors
305         for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
306           if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
307             aValidCadidate = false;
308             break;
309           }
310         }
311       }
312       if (!aValidCadidate) // candidate is not valid, break the checking
313         break;
314     }
315   }
316   if (!aResultCompound.IsNull())
317     return aResultCompound;
318   return aGoodCandidate;
319 }
320
321 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
322   const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections)
323 {
324   if (theValue.IsNull() || theContext.IsNull())
325     return false;
326   myGeometricalNaming = theGeometricalNaming;
327   // check the value shape can be named as it is, or it is needed to construct it from the
328   // higher level shapes (like a box vertex by faces that form this vertex)
329   bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
330   if (aIsFound) { // additional check for selection and delete evolution only: also could not use
331     aIsFound = false;
332     for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
333     {
334       Handle(TNaming_NamedShape) aNS;
335       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
336         if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
337             aNS->Evolution() == TNaming_PRIMITIVE) {
338           aIsFound = true;
339           break;
340         }
341       }
342     }
343   }
344   // searching in the base document
345   if (!aIsFound && !myBaseDocumentLab.IsNull() &&
346       TNaming_Tool::HasLabel(myBaseDocumentLab, theValue))
347   {
348     TNaming_SameShapeIterator aShapes(theValue, myBaseDocumentLab);
349     for(; aShapes.More(); aShapes.Next())
350     {
351       Handle(TNaming_NamedShape) aNS;
352       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
353         if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
354           aNS->Evolution() == TNaming_PRIMITIVE) {
355           aIsFound = true;
356           break;
357         }
358       }
359     }
360   }
361   if (!aIsFound) {
362     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
363     myShapeType = aSelectionType;
364     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
365         aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
366     { // iterate all sub-shapes and select them on sublabels
367       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
368         if (!selectBySubSelector(theContext, aSubIter.Value(),
369             false, theUseNeighbors, theUseIntersections)) {//for subs no geometrical naming allowed
370           return false; // if some selector is failed, everything is failed
371         }
372       }
373       myType = SELTYPE_CONTAINER;
374       return true;
375     }
376
377     // try to find the shape of the higher level type in the context shape
378     bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
379     TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
380     TopoDS_ListOfShape aLastIntersectors;
381     while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) {
382       if (aSelectionType == TopAbs_FACE) {
383         if (theValue.ShapeType() != TopAbs_VERTEX)
384           break;
385         aFacesTried = true;
386         aSelectionType = TopAbs_EDGE;
387       } else
388         aSelectionType = TopAbs_FACE;
389       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
390       TopoDS_ListOfShape anIntList; // same as anIntersectors
391       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
392         if (aSelectionType == TopAbs_EDGE &&
393             BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
394           continue;
395         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
396         for(; aSubExp.More(); aSubExp.Next()) {
397           if (aSubExp.Current().IsSame(theValue)) {
398             if (anIntersectors.Add(aSelExp.Current()))
399               anIntList.Append(aSelExp.Current());
400             break;
401           }
402         }
403       }
404       // check that solution is only one
405       TopoDS_ListOfShape aCommon;
406       commonShapes(anIntList, theValue.ShapeType(), aCommon);
407       if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
408         // name the intersectors
409         mySubSelList.clear();
410         TopoDS_ListOfShape::Iterator anInt(anIntList);
411         for (; anInt.More(); anInt.Next()) {
412           if (!selectBySubSelector(theContext, anInt.Value(),
413               theGeometricalNaming, theUseNeighbors, false)) {
414             break; // if some selector is failed, stop and search another solution
415           }
416         }
417         if (!anInt.More()) { // all intersectors were correctly named
418           myType = SELTYPE_INTERSECT;
419           return true;
420           }
421       } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty())  {
422         aLastCommon = aCommon;
423         aLastIntersectors = anIntList;
424       }
425     }
426
427     if (!theUseNeighbors)
428       return false;
429
430     // searching by neighbors
431     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
432     for(int aLevel = 1; true; aLevel++) {
433       TopTools_MapOfShape aNewNB;
434       findNeighbors(theContext, theValue, aLevel, aNewNB);
435       if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
436         break;
437       }
438       // iterate by the order in theContext to keep same naming names
439       TopExp_Explorer anOrder(theContext, theValue.ShapeType());
440       for (; anOrder.More(); anOrder.Next()) {
441         if (aNewNB.Contains(anOrder.Current())) {
442           TopoDS_Shape aNewNBShape = anOrder.Current();
443           // check which can be named correctly, without "by neighbors" type
444           Selector_Selector aSelector(myLab.FindChild(1));
445           aSelector.setBaseDocument(myBaseDocumentLab);
446           if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false, false)) {
447             // add to list of good NBs
448             aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
449           }
450         }
451       }
452       TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming);
453       if (!aResult.IsNull() && aResult.IsSame(theValue)) {
454         std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
455         for(; aNBIter != aNBs.end(); aNBIter++) {
456           if (!selectBySubSelector(theContext, aNBIter->first,
457               theGeometricalNaming, false, false)) {
458             return false; // something is wrong because before this selection was ok
459           }
460           myNBLevel.push_back(aNBIter->second);
461
462         }
463         myType = SELTYPE_FILTER_BY_NEIGHBOR;
464         return true;
465       }
466     }
467
468     if (aLastCommon.Extent() > 1) {
469       if (myAlwaysGeometricalNaming) {
470         TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon);
471         TopoDS_Shape aFirst = aCommonIter.Value();
472         for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
473           if (!sameGeometry(aFirst, aCommonIter.Value()))
474             break;
475         }
476         if (!aCommonIter.More()) { // all geometry is same, result is a compound
477           myType = SELTYPE_INTERSECT;
478           return true;
479         }
480       }
481       // weak naming to distinguish commons coming from intersection
482       Selector_NExplode aNexp(aLastCommon);
483       myWeakIndex = aNexp.index(theValue);
484       if (myWeakIndex != -1) {
485         // name the intersectors
486         mySubSelList.clear();
487         TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
488         for (; anInt.More(); anInt.Next()) {
489           if (!selectBySubSelector(theContext, anInt.Value(),
490               theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
491             break; // if some selector is failed, stop and search another solution
492           }
493         }
494         if (!anInt.More()) { // all intersectors were correctly named
495           myType = SELTYPE_INTERSECT;
496           return true;
497         }
498       }
499     }
500
501     // pure weak naming: there is no sense to use pure weak naming for neighbors selection
502     if (theUseNeighbors) {
503       myType = SELTYPE_WEAK_NAMING;
504       Selector_NExplode aNexp(theContext, theValue.ShapeType());
505       myWeakIndex = aNexp.index(theValue);
506       if (myWeakIndex != -1) {
507         myShapeType = theValue.ShapeType();
508         // searching for context shape label to store in myFinal
509         myFinal.Nullify();
510         if (TNaming_Tool::HasLabel(myLab, theContext)) {
511           for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
512           {
513             Handle(TNaming_NamedShape) aNS;
514             if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
515               TNaming_Evolution anEvolution = aNS->Evolution();
516               if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
517                   anEvolution == TNaming_MODIFY) {
518                 // check this is a new shape
519                 for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
520                   if (aNSIter.NewShape().IsSame(theContext)) {
521                     myFinal = aNS->Label();
522                     break;
523                   }
524                 }
525               }
526             }
527           }
528         }
529         return true; // could be final empty (in case it is called recursively) or not
530       }
531     }
532
533     return false;
534   }
535   // searching for the base shapes of the value
536   Handle(TNaming_NamedShape) aPrimitiveNS;
537   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
538   for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
539     TDF_Label aLab = aUseExternal == 0 ? myLab : myBaseDocumentLab;
540     if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
541       continue;
542     for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
543     {
544       Handle(TNaming_NamedShape) aNS;
545       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
546         TNaming_Evolution anEvolution = aNS->Evolution();
547         if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
548           aPrimitiveNS = aNS;
549           break;
550         } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
551           // check this is a new shape
552           TNaming_Iterator aNSIter(aNS);
553           for(; aNSIter.More(); aNSIter.Next())
554             if (aNSIter.NewShape().IsSame(theValue))
555               break;
556           if (aNSIter.More()) // new was found
557             aModifList.Append(aNS);
558         }
559       }
560     }
561   }
562
563   if (!aPrimitiveNS.IsNull()) {
564     myType = SELTYPE_PRIMITIVE;
565     myFinal = aPrimitiveNS->Label();
566     return true;
567   }
568
569   if (aModifList.Extent() > 1) { // searching for the best modification result: by context
570     Handle(TNaming_NamedShape) aCandidate;
571     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
572     for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
573        aCandidate = aModIter.Value();
574       TDF_Label aFatherLab = aCandidate->Label().Father();
575       Handle(TNaming_NamedShape) aFatherNS;
576       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
577         for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
578           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
579             aModifList.Clear();
580             break;
581           }
582         }
583       }
584     }
585     // take the best candidate, or the last in the iteration
586     aModifList.Clear();
587     aModifList.Append(aCandidate);
588   }
589
590   if (!aModifList.IsEmpty()) {
591     // searching for all the base shapes of this modification
592     findBases(myLab, aModifList.First(), theValue, true, myBaseDocumentLab, myBases);
593     if (!myBases.IsEmpty()) {
594       myFinal = aModifList.First()->Label();
595       TopoDS_ListOfShape aCommon;
596       findModificationResult(aCommon);
597       // trying to search by neighbors
598       if (aCommon.Extent() > 1) { // more complicated selection
599         if (myAlwaysGeometricalNaming) {
600           TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
601           TopoDS_Shape aFirst = aCommonIter.Value();
602           for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
603             if (!sameGeometry(aFirst, aCommonIter.Value()))
604               break;
605           }
606           if (!aCommonIter.More()) { // all geometry is same, result is a compound
607             myType = SELTYPE_MODIFICATION;
608             return true;
609           }
610         }
611         if (!theUseNeighbors)
612           return false;
613
614         // searching by neighbors
615         std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
616         for(int aLevel = 1; true; aLevel++) {
617           TopTools_MapOfShape aNewNB;
618           findNeighbors(theContext, theValue, aLevel, aNewNB);
619           if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
620             break;
621           }
622           // iterate by the order in theContext to keep same naming names
623           TopExp_Explorer anOrder(theContext, theValue.ShapeType());
624           for (; anOrder.More(); anOrder.Next()) {
625             if (aNewNB.Contains(anOrder.Current())) {
626               TopoDS_Shape aNewNBShape = anOrder.Current();
627               // check which can be named correctly, without "by neighbors" type
628               Selector_Selector aSelector(myLab.FindChild(1));
629               if (!myBaseDocumentLab.IsNull())
630                 aSelector.setBaseDocument(myBaseDocumentLab);
631               if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false)) {
632                 // add to list of good NBs
633                 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
634               }
635             }
636           }
637           TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming);
638           if (!aResult.IsNull() && aResult.IsSame(theValue)) {
639             std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
640             for(; aNBIter != aNBs.end(); aNBIter++) {
641               if (!selectBySubSelector(theContext, aNBIter->first,
642                   theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
643                 return false; // something is wrong because before this selection was ok
644               }
645               myNBLevel.push_back(aNBIter->second);
646
647             }
648             myType = SELTYPE_FILTER_BY_NEIGHBOR;
649             return true;
650           }
651         }
652         // filter by neighbors did not help
653         if (aCommon.Extent() > 1) {
654           if (myAlwaysGeometricalNaming) {
655             TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
656             TopoDS_Shape aFirst = aCommonIter.Value();
657             for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
658               if (!sameGeometry(aFirst, aCommonIter.Value()))
659                 break;
660             }
661             if (!aCommonIter.More()) { // all geometry is same, result is a compound
662               myType = SELTYPE_FILTER_BY_NEIGHBOR;
663               return true;
664             }
665           }
666           // weak naming between the common results
667           Selector_NExplode aNexp(aCommon);
668           myWeakIndex = aNexp.index(theValue);
669           if (myWeakIndex == -1)
670             return false;
671         }
672       }
673     }
674     myType = SELTYPE_MODIFICATION;
675     if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
676       TopoDS_ListOfShape aCommon;
677       myFinal = aModifList.First()->Label();
678       Handle(TNaming_NamedShape) aNS;
679       if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
680         for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
681           const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
682           if (!aNewShape.IsNull())
683             aCommon.Append(aNewShape);
684         }
685       }
686       Selector_NExplode aNexp(aCommon);
687       myWeakIndex = aNexp.index(theValue);
688       if (myWeakIndex == -1)
689         return false;
690     }
691     return true;
692   }
693
694   // not found a good result
695   return false;
696 }
697
698 /// Stores the array of references to the label: references to elements of ref-list, then the last
699 static void storeBaseArray(const TDF_Label& theLab,
700   const TDF_LabelList& theRef, const TDF_Label& theLast)
701 {
702   Handle(TDataStd_ReferenceArray) anArray =
703     TDataStd_ReferenceArray::Set(theLab, kBASE_ARRAY, 0, theRef.Extent());
704   Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
705   const TDF_Label aThisDocRoot = theLab.Root();
706   TDF_LabelList::Iterator aBIter(theRef);
707   for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
708     const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
709     // check this is a label of this document
710     if (aLab.Root().IsEqual(aThisDocRoot)) {
711       anArray->SetValue(anIndex, aLab);
712     } else { // store reference to external document as an entry-string
713       if (anEntries.IsNull()) {
714         anEntries = TDataStd_ExtStringList::Set(theLab, kBASE_LIST);
715       }
716       TCollection_AsciiString anEntry;
717       TDF_Tool::Entry(aLab, anEntry);
718       anEntries->Append(anEntry);
719       anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
720     }
721     if (!aBIter.More())
722       break;
723   }
724 }
725
726 void Selector_Selector::store()
727 {
728   static const TDF_LabelList anEmptyRefList;
729   myLab.ForgetAllAttributes(true); // remove old naming data
730   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
731   if (myGeometricalNaming)
732     TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING);
733   switch(myType) {
734   case SELTYPE_CONTAINER:
735   case SELTYPE_INTERSECT: {
736     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
737     // store also all sub-selectors
738     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
739     for(; aSubSel != mySubSelList.end(); aSubSel++) {
740       aSubSel->store();
741     }
742     if (myWeakIndex != -1) {
743       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
744     }
745     break;
746   }
747   case SELTYPE_PRIMITIVE: {
748     storeBaseArray(myLab, anEmptyRefList, myFinal);
749     break;
750   }
751   case SELTYPE_MODIFICATION: {
752     storeBaseArray(myLab, myBases, myFinal);
753     if (myWeakIndex != -1) {
754       TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
755     }
756     break;
757   }
758   case SELTYPE_FILTER_BY_NEIGHBOR: {
759     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
760     // store numbers of levels corresponded to the neighbors in sub-selectors
761     Handle(TDataStd_IntegerArray) anArray =
762       TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
763     std::list<int>::iterator aLevel = myNBLevel.begin();
764     for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
765       anArray->SetValue(anIndex, *aLevel);
766     }
767     // store all sub-selectors
768     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
769     for(; aSubSel != mySubSelList.end(); aSubSel++) {
770       aSubSel->store();
771     }
772     break;
773   }
774   case SELTYPE_WEAK_NAMING: {
775     TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
776     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
777     if (!myFinal.IsNull()) {
778       storeBaseArray(myLab, anEmptyRefList, myFinal);
779     }
780     break;
781   }
782   default: { // unknown case
783     break;
784   }
785   }
786 }
787
788 /// Restores references to the labels: references to elements of ref-list, then the last
789 static bool restoreBaseArray(const TDF_Label& theLab, const TDF_Label& theBaseDocumetnLab,
790   TDF_LabelList& theRef, TDF_Label& theLast)
791 {
792   const TDF_Label aThisDocRoot = theLab.Root();
793   Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
794   TDataStd_ListOfExtendedString::Iterator anIter;
795   Handle(TDataStd_ReferenceArray) anArray;
796   if (theLab.FindAttribute(kBASE_ARRAY, anArray)) {
797     int anUpper = anArray->Upper();
798     for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
799       TDF_Label aLab = anArray->Value(anIndex);
800       if (aLab.IsEqual(aThisDocRoot)) { // external document reference
801         if (theBaseDocumetnLab.IsNull())
802           return false;
803         if (anEntries.IsNull()) {
804           if (!theLab.FindAttribute(kBASE_LIST, anEntries))
805             return false;
806           anIter.Initialize(anEntries->List());
807         }
808         if (!anIter.More())
809           return false;
810         TDF_Tool::Label(theBaseDocumetnLab.Data(), anIter.Value(), aLab);
811         anIter.Next();
812       }
813       if (anIndex == anUpper) {
814         theLast = aLab;
815       } else {
816         theRef.Append(aLab);
817       }
818     }
819     return true;
820   }
821   return false;
822 }
823
824
825 bool Selector_Selector::restore()
826 {
827   Handle(TDataStd_Integer) aTypeAttr;
828   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
829     return false;
830   myGeometricalNaming = myLab.IsAttribute(kGEOMETRICAL_NAMING);
831   myType = Selector_Type(aTypeAttr->Get());
832   switch(myType) {
833   case SELTYPE_CONTAINER:
834   case SELTYPE_INTERSECT: {
835     Handle(TDataStd_Integer) aShapeTypeAttr;
836     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
837       return false;
838     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
839     // restore sub-selectors
840     bool aSubResult = true;
841     mySubSelList.clear();
842     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
843       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
844       mySubSelList.back().setBaseDocument(myBaseDocumentLab);
845       if (!mySubSelList.back().restore())
846         aSubResult = false;
847     }
848     Handle(TDataStd_Integer) aWeakInt;
849     if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
850       myWeakIndex = aWeakInt->Get();
851     }
852     return aSubResult;
853   }
854   case SELTYPE_PRIMITIVE: {
855     return restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal);
856   }
857   case SELTYPE_MODIFICATION: {
858     if (restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) {
859       Handle(TDataStd_Integer) aWeakInt;
860       if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
861         myWeakIndex = aWeakInt->Get();
862       }
863       return true;
864     }
865     return false;
866   }
867   case SELTYPE_FILTER_BY_NEIGHBOR: {
868     Handle(TDataStd_Integer) aShapeTypeAttr;
869     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
870       return false;
871     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
872     // restore sub-selectors
873     bool aSubResult = true;
874     mySubSelList.clear();
875     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
876       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
877       mySubSelList.back().setBaseDocument(myBaseDocumentLab);
878       if (!mySubSelList.back().restore())
879         aSubResult = false;
880     }
881     // restore levels indices
882     Handle(TDataStd_IntegerArray) anArray;
883     if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
884       return false;
885     for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
886       myNBLevel.push_back(anArray->Value(anIndex));
887     }
888     return true;
889   }
890   case SELTYPE_WEAK_NAMING: {
891     Handle(TDataStd_Integer) aWeakInt;
892     if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
893       return false;
894     myWeakIndex = aWeakInt->Get();
895     Handle(TDataStd_Integer) aShapeTypeAttr;
896     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
897       return false;
898     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
899     if (!restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal))
900       return false;
901     return true;
902   }
903   default: { // unknown case
904   }
905   }
906   return false;
907 }
908
909 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
910 static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
911   const TDF_Label& theFinal,
912   const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults)
913 {
914   if (TNaming_Tool::HasLabel(anAccess, theBase)) {
915     for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
916     {
917       TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
918       if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
919         if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
920           theResults.Add(aBaseIter.Shape());
921         } else {
922           findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults);
923         }
924       }
925     }
926   }
927   if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
928     static TDF_Label anEmpty;
929     findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults);
930   }
931 }
932
933 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
934   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
935     TDF_Label anAdditionalDoc; // this document if base is started in extra document
936     if (aBase.Value().Root() != myLab.Root()) {
937       anAdditionalDoc = myLab;
938     }
939     TopTools_MapOfShape aFinals;
940     for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
941       findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals);
942     }
943     if (!aFinals.IsEmpty()) {
944       if (theCommon.IsEmpty()) { // just copy all to common
945         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
946           theCommon.Append(aFinal.Key());
947         }
948       } else { // keep only shapes presented in both lists
949         for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
950           if (aFinals.Contains(aCommon.Value())) {
951             aCommon.Next();
952           } else { // common is not found, remove it
953             theCommon.Remove(aCommon);
954           }
955         }
956       }
957     }
958   }
959 }
960
961 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
962 {
963   TopoDS_Shape aResult; // null if invalid
964   switch(myType) {
965   case SELTYPE_CONTAINER: {
966     TopoDS_Builder aBuilder;
967     switch(myShapeType) {
968     case TopAbs_COMPOUND: {
969       TopoDS_Compound aComp;
970       aBuilder.MakeCompound(aComp);
971       aResult = aComp;
972       break;
973       }
974     case TopAbs_COMPSOLID: {
975       TopoDS_CompSolid aComp;
976       aBuilder.MakeCompSolid(aComp);
977       aResult = aComp;
978       break;
979     }
980     case TopAbs_SHELL: {
981       TopoDS_Shell aShell;
982       aBuilder.MakeShell(aShell);
983       aResult = aShell;
984       break;
985     }
986     case TopAbs_WIRE: {
987       TopoDS_Wire aWire;
988       aBuilder.MakeWire(aWire);
989       aResult = aWire;
990       break;
991     }
992     }
993     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
994     for(; aSubSel != mySubSelList.end(); aSubSel++) {
995       if (!aSubSel->solve(theContext)) {
996         return false;
997       }
998       aBuilder.Add(aResult, aSubSel->value());
999     }
1000     break;
1001   }
1002   case SELTYPE_INTERSECT: {
1003     TopoDS_ListOfShape aSubSelectorShapes;
1004     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1005     for(; aSubSel != mySubSelList.end(); aSubSel++) {
1006       if (!aSubSel->solve(theContext)) {
1007         return false;
1008       }
1009       aSubSelectorShapes.Append(aSubSel->value());
1010     }
1011     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
1012     commonShapes(aSubSelectorShapes, myShapeType, aCommon);
1013     if (aCommon.Extent() != 1) {
1014       if (myWeakIndex != -1) {
1015         Selector_NExplode aNexp(aCommon);
1016         aResult = aNexp.shape(myWeakIndex);
1017       } else if (myGeometricalNaming && aCommon.Extent() > 1) {
1018         // check results are on the same geometry, create compound
1019         TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
1020         TopoDS_Shape aFirst = aCommonIter.Value();
1021         for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
1022           if (!sameGeometry(aFirst, aCommonIter.Value()))
1023             break;
1024         }
1025         if (!aCommonIter.More()) { // all geometry is same, create a result compound
1026           TopoDS_Builder aBuilder;
1027           TopoDS_Compound aCompound;
1028           aBuilder.MakeCompound(aCompound);
1029           for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) {
1030             aBuilder.Add(aCompound, aCommonIter.Value());
1031           }
1032           aResult = aCompound;
1033         }
1034       } else {
1035         return false;
1036       }
1037     } else {
1038       aResult = aCommon.First();
1039     }
1040     break;
1041   }
1042   case SELTYPE_PRIMITIVE: {
1043     Handle(TNaming_NamedShape) aNS;
1044     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
1045       aResult = aNS->Get();
1046     }
1047     break;
1048   }
1049   case SELTYPE_MODIFICATION: {
1050     if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index
1051       TopoDS_ListOfShape aCommon;
1052       Handle(TNaming_NamedShape) aNS;
1053       if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
1054         for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
1055           const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
1056           if (!aNewShape.IsNull())
1057             aCommon.Append(aNewShape);
1058         }
1059       }
1060       Selector_NExplode aNexp(aCommon);
1061       aResult = aNexp.shape(myWeakIndex);
1062     } else { // standard case
1063       TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
1064       findModificationResult(aFinalsCommon);
1065       if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape
1066         aResult = aFinalsCommon.First();
1067       } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) {
1068         Selector_NExplode aNExp(aFinalsCommon);
1069         aResult = aNExp.shape(myWeakIndex);
1070       } else if (aFinalsCommon.Extent() > 1 && myGeometricalNaming) {// if same geometry - compound
1071         TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon);
1072         TopoDS_Shape aFirst = aCommonIter.Value();
1073         for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
1074           if (!sameGeometry(aFirst, aCommonIter.Value()))
1075             break;
1076         }
1077         if (!aCommonIter.More()) { // all geometry is same, create a result compound
1078           TopoDS_Builder aBuilder;
1079           TopoDS_Compound aCompound;
1080           aBuilder.MakeCompound(aCompound);
1081           for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) {
1082             aBuilder.Add(aCompound, aCommonIter.Value());
1083           }
1084           aResult = aCompound;
1085         }
1086
1087       }
1088     }
1089     break;
1090   }
1091   case SELTYPE_FILTER_BY_NEIGHBOR: {
1092     std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
1093     std::list<int>::iterator aLevel = myNBLevel.begin();
1094     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1095     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
1096       if (!aSubSel->solve(theContext)) {
1097         return false;
1098       }
1099       aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
1100     }
1101     aResult = findNeighbor(theContext, aNBs, myGeometricalNaming);
1102     break;
1103   }
1104   case SELTYPE_WEAK_NAMING: {
1105     TopoDS_Shape aContext;
1106     if (myFinal.IsNull()) {
1107       aContext = theContext;
1108     } else {
1109       Handle(TNaming_NamedShape) aNS;
1110       if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
1111         aContext = aNS->Get();
1112       }
1113     }
1114     if (!aContext.IsNull()) {
1115       Selector_NExplode aNexp(aContext, myShapeType);
1116       aResult = aNexp.shape(myWeakIndex);
1117     }
1118   }
1119   default: { // unknown case
1120   }
1121   }
1122
1123   TNaming_Builder aBuilder(myLab);
1124   if (!aResult.IsNull()) {
1125     aBuilder.Select(aResult, aResult);
1126     return true;
1127   }
1128   return false; // builder just erases the named shape in case of error
1129 }
1130
1131 TopoDS_Shape Selector_Selector::value()
1132 {
1133   Handle(TNaming_NamedShape) aNS;
1134   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
1135     return aNS->Get();
1136   return TopoDS_Shape(); // empty, error shape
1137 }
1138
1139 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
1140   switch(myType) {
1141   case SELTYPE_CONTAINER:
1142   case SELTYPE_INTERSECT: {
1143     std::string aResult;
1144     // add names of sub-components one by one in "[]" +optionally [weak_name_1]
1145     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1146     for(; aSubSel != mySubSelList.end(); aSubSel++) {
1147       aResult += '[';
1148       aResult += aSubSel->name(theNameGenerator);
1149       aResult += ']';
1150       TopoDS_Shape aSubVal = aSubSel->value();
1151       if (!aSubVal.IsNull()) {
1152         TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
1153         if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
1154           switch(aSubType) {
1155           case TopAbs_COMPOUND: aResult += "c"; break;
1156           case TopAbs_COMPSOLID: aResult += "o"; break;
1157           case TopAbs_SOLID: aResult += "s"; break;
1158           case TopAbs_SHELL: aResult += "h"; break;
1159           case TopAbs_WIRE: aResult += "w"; break;
1160           case TopAbs_EDGE: aResult += "e"; break;
1161           case TopAbs_VERTEX: aResult += "v"; break;
1162           default:
1163             ;
1164           }
1165         }
1166       }
1167     }
1168     if (myWeakIndex != -1) {
1169       std::ostringstream aWeakStr;
1170       aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
1171       aResult += aWeakStr.str();
1172     }
1173     return aResult;
1174   }
1175   case SELTYPE_PRIMITIVE: {
1176     Handle(TDataStd_Name) aName;
1177     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
1178       return "";
1179     return theNameGenerator->contextName(myFinal) + "/" +
1180       std::string(TCollection_AsciiString(aName->Get()).ToCString());
1181   }
1182   case SELTYPE_MODIFICATION: {
1183     // final&base1&base2 +optionally: [weak_name_1]
1184     std::string aResult;
1185     Handle(TDataStd_Name) aName;
1186     if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
1187       return "";
1188     aResult += theNameGenerator->contextName(myFinal) + "/" +
1189       std::string(TCollection_AsciiString(aName->Get()).ToCString());
1190     for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
1191       if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
1192         return "";
1193       aResult += "&";
1194       aResult += theNameGenerator->contextName(*aBase) + "/" +
1195         std::string(TCollection_AsciiString(aName->Get()).ToCString());
1196     }
1197     if (myWeakIndex != -1) {
1198       std::ostringstream aWeakStr;
1199       aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
1200       aResult += aWeakStr.str();
1201     }
1202     return aResult;
1203   }
1204   case SELTYPE_FILTER_BY_NEIGHBOR: {
1205     // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
1206     std::string aResult;
1207     std::list<int>::iterator aLevel = myNBLevel.begin();
1208     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1209     for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
1210       aResult += "(" + aSubSel->name(theNameGenerator) + ")";
1211       if (*aLevel > 1) {
1212         std::ostringstream aLevelStr;
1213         aLevelStr<<*aLevel;
1214         aResult += aLevelStr.str();
1215       }
1216     }
1217     return aResult;
1218   }
1219   case SELTYPE_WEAK_NAMING: {
1220     // _weak_naming_1_Context
1221     std::ostringstream aWeakStr;
1222     aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
1223     std::string aResult = aWeakStr.str();
1224     if (!myFinal.IsNull())
1225       aResult += "_" + theNameGenerator->contextName(myFinal);
1226     return aResult;
1227   }
1228   default: { // unknown case
1229   }
1230   };
1231   return "";
1232 }
1233
1234 TDF_Label Selector_Selector::restoreByName(
1235   std::string theName, const TopAbs_ShapeEnum theShapeType,
1236   Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming)
1237 {
1238   myGeometricalNaming = theGeometricalNaming;
1239   if (theName[0] == '[') { // intersection or container
1240     switch(theShapeType) {
1241     case TopAbs_COMPOUND:
1242     case TopAbs_COMPSOLID:
1243     case TopAbs_SHELL:
1244     case TopAbs_WIRE:
1245       myType = SELTYPE_CONTAINER;
1246       break;
1247     case TopAbs_VERTEX:
1248     case TopAbs_EDGE:
1249     case TopAbs_FACE:
1250       myType = SELTYPE_INTERSECT;
1251       break;
1252     default:
1253       return TDF_Label(); // unknown case
1254     }
1255     myShapeType = theShapeType;
1256     TDF_Label aContext;
1257     for(size_t aStart = 0; aStart != std::string::npos;
1258         aStart = theName.find('[', aStart + 1)) {
1259       size_t anEndPos = theName.find(']', aStart + 1);
1260       if (anEndPos != std::string::npos) {
1261         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1262         if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1263           std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1264           myWeakIndex = atoi(aWeakIndex.c_str());
1265           continue;
1266         }
1267         TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
1268         if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
1269           char aShapeChar = theName[anEndPos + 1];
1270           if (theName[anEndPos + 1] != '[') {
1271             switch(aShapeChar) {
1272             case 'c': aSubShapeType = TopAbs_COMPOUND; break;
1273             case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
1274             case 's': aSubShapeType = TopAbs_SOLID; break;
1275             case 'h': aSubShapeType = TopAbs_SHELL; break;
1276             case 'w': aSubShapeType = TopAbs_WIRE; break;
1277             case 'e': aSubShapeType = TopAbs_EDGE; break;
1278             case 'v': aSubShapeType = TopAbs_VERTEX; break;
1279             default:;
1280             }
1281           }
1282         }
1283         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1284         mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1285         TDF_Label aSubContext = mySubSelList.back().restoreByName(
1286           aSubStr, aSubShapeType, theNameGenerator, theGeometricalNaming);
1287         if (aSubContext.IsNull())
1288           return aSubContext; // invalid sub-selection parsing
1289         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1290           if (!theNameGenerator->isLater(aContext, aSubContext))
1291             aContext = aSubContext;
1292         } else {
1293           aContext = aSubContext;
1294         }
1295       } else
1296         return TDF_Label(); // invalid parentheses
1297     }
1298     return aContext;
1299   } else if (theName[0] == '(') { // filter by neighbors
1300     myType = SELTYPE_FILTER_BY_NEIGHBOR;
1301     TDF_Label aContext;
1302     for(size_t aStart = 0; aStart != std::string::npos;
1303       aStart = theName.find('(', aStart + 1)) {
1304       size_t anEndPos = theName.find(')', aStart + 1);
1305       if (anEndPos != std::string::npos) {
1306         std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1307         mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1308         mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1309         TDF_Label aSubContext = mySubSelList.back().restoreByName(
1310           aSubStr, theShapeType, theNameGenerator, theGeometricalNaming);
1311         if (aSubContext.IsNull())
1312           return aSubContext; // invalid sub-selection parsing
1313         if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1314           if (!theNameGenerator->isLater(aContext, aSubContext))
1315             aContext = aSubContext;
1316         } else {
1317           aContext = aSubContext;
1318         }
1319         if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
1320           aContext = theNameGenerator->newestContext(aContext);
1321
1322         // searching for the level index
1323         std::string aLevel;
1324         for(anEndPos++; anEndPos != std::string::npos &&
1325                         theName[anEndPos] != '(' && theName[anEndPos] != 0;
1326             anEndPos++) {
1327           aLevel += theName[anEndPos];
1328         }
1329         if (aLevel.empty())
1330           myNBLevel.push_back(1); // by default it is 1
1331         else {
1332           int aNum = atoi(aLevel.c_str());
1333           if (aNum > 0)
1334             myNBLevel.push_back(aNum);
1335           else
1336             return TDF_Label(); // invalid number
1337         }
1338       } else
1339         return TDF_Label(); // invalid parentheses
1340     }
1341     return aContext;
1342   } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1343     myType = SELTYPE_WEAK_NAMING;
1344     std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1345     std::size_t aContextPosition = aWeakIndex.find("_");
1346     myWeakIndex = atoi(aWeakIndex.c_str());
1347     myShapeType = theShapeType;
1348     TDF_Label aContext;
1349     if (aContextPosition != std::string::npos) { // context is also defined
1350       std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1351       theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1352     }
1353     return aContext;
1354   } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive
1355     myType = SELTYPE_PRIMITIVE;
1356     TDF_Label aContext;
1357     if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1358       if (!myFinal.IsNull())
1359         return aContext;
1360     }
1361   } else { // modification
1362     myType = SELTYPE_MODIFICATION;
1363     TDF_Label aContext;
1364     for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1365       if (aStart != 0)
1366         aStart++;
1367       anEnd = theName.find('&', aStart);
1368       std::string aSubStr =
1369         theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1370       if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1371         std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1372         myWeakIndex = atoi(aWeakIndex.c_str());
1373         continue;
1374       }
1375       TDF_Label aSubContext, aValue;
1376       if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1377         return TDF_Label(); // can not restore
1378       if(aSubContext.IsNull() || aValue.IsNull())
1379         return TDF_Label(); // can not restore
1380       if (myFinal.IsNull()) {
1381         myFinal = aValue;
1382         aContext = aSubContext;
1383       } else
1384         myBases.Append(aValue);
1385     }
1386     return aContext;
1387   }
1388   return TDF_Label();
1389 }
1390
1391 bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext,
1392   const TopoDS_Shape theValue, const bool theGeometricalNaming,
1393   const bool theUseNeighbors, const bool theUseIntersections)
1394 {
1395   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1396   if (!myBaseDocumentLab.IsNull())
1397     mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1398   if (!mySubSelList.back().select(theContext, theValue,
1399       theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
1400     mySubSelList.clear(); // if one of the selector is failed, all become invalid
1401     return false;
1402   }
1403   return true;
1404 }
1405
1406 void Selector_Selector::combineGeometrical(const TopoDS_Shape theContext)
1407 {
1408   TopoDS_Shape aValue = value();
1409   if (aValue.IsNull() || aValue.ShapeType() == TopAbs_COMPOUND)
1410     return;
1411   myAlwaysGeometricalNaming = true;
1412   mySubSelList.clear();
1413   myBases.Clear();
1414   myWeakIndex = -1;
1415   if (select(theContext, aValue, true)) {
1416     store();
1417     solve(theContext);
1418     return;
1419   }
1420   // if can not select, select the compound in a custom way
1421   TopTools_MapOfShape aMap;
1422   TopoDS_ListOfShape aList;
1423   for(TopExp_Explorer anExp(theContext, aValue.ShapeType()); anExp.More(); anExp.Next()) {
1424     if (aMap.Add(anExp.Current())) {
1425       if (sameGeometry(aValue, anExp.Current()))
1426         aList.Append(anExp.Current());
1427     }
1428   }
1429   if (aList.Size() > 1) {
1430     TopoDS_Builder aBuilder;
1431     TopoDS_Compound aCompound;
1432     aBuilder.MakeCompound(aCompound);
1433     for(TopoDS_ListIteratorOfListOfShape aListIter(aList); aListIter.More(); aListIter.Next()) {
1434       aBuilder.Add(aCompound, aListIter.Value());
1435     }
1436     if (select(theContext, aCompound, true)) {
1437       store();
1438       solve(theContext);
1439     }
1440   }
1441 }