1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <Selector_Selector.h>
23 #include <Selector_NameGenerator.h>
24 #include <Selector_NExplode.h>
26 #include <TDF_ChildIDIterator.hxx>
27 #include <TopoDS_Iterator.hxx>
28 #include <TopoDS_Builder.hxx>
30 #include <TopExp_Explorer.hxx>
31 #include <TNaming_Tool.hxx>
32 #include <TNaming_NewShapeIterator.hxx>
33 #include <TNaming_OldShapeIterator.hxx>
34 #include <TNaming_SameShapeIterator.hxx>
35 #include <TNaming_Iterator.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TopTools_MapOfShape.hxx>
38 #include <BRep_Tool.hxx>
40 #include <TDataStd_Integer.hxx>
41 #include <TDataStd_ReferenceArray.hxx>
42 #include <TDataStd_IntegerArray.hxx>
43 #include <TDataStd_Name.hxx>
47 /// type of the selection, integer keeps the Selector_Type value
48 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
49 /// type of the shape, stored in case it is intersection or container
50 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
51 // reference attribute that contains the reference to labels where the "from" or "base" shapes
52 // of selection are located
53 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
54 // array of the neighbor levels
55 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
56 // weak index (integer) of the sub-shape
57 static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
59 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
64 TDF_Label Selector_Selector::label()
69 void Selector_Selector::setBaseDocument(const TDF_Label theAccess)
71 myBaseDocumentLab = theAccess;
74 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
75 static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal,
76 const TopoDS_Shape& theValue,
77 bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
79 bool aFoundAnyShape = false;
80 TNaming_SameShapeIterator aLabIter(theValue, theAccess);
81 for(; aLabIter.More(); aLabIter.Next()) {
82 Handle(TNaming_NamedShape) aNS;
83 if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
84 if (aMustBeAtFinal && aNS != theFinal)
85 continue; // looking for old at the same final label only
86 TNaming_Evolution anEvolution = aNS->Evolution();
87 if (anEvolution == TNaming_PRIMITIVE) {
88 // check that this is not in the results already
89 const TDF_Label aResult = aNS->Label();
90 TDF_LabelList::Iterator aResIter(theResult);
91 for(; aResIter.More(); aResIter.Next()) {
92 if (aResIter.Value().IsEqual(aResult))
95 if (!aResIter.More()) // not found, so add this new
96 theResult.Append(aResult);
97 aFoundAnyShape = true;
99 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
100 for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
101 if (aThisIter.NewShape().IsSame(theValue)) {
102 // continue recursively, null NS means that any NS are ok
103 findBases(theAccess, theFinal, aThisIter.OldShape(),
104 false, theAdditionalDocument, theResult);
105 aFoundAnyShape = true;
111 if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document
112 static TDF_Label anEmpty;
113 if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue))
114 findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue,
115 false, anEmpty, theResult);
119 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
120 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
121 TopoDS_ListOfShape& theResults)
123 TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
124 for(; aSubSel != theShapes.end(); aSubSel++) {
125 TopTools_MapOfShape aCurrentMap;
126 for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
127 if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
128 theResults.Append(anExp.Current());
130 if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
131 for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
132 if (aCurrentMap.Contains(aComIter.Value()))
135 theResults.Remove(aComIter);
141 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
142 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
143 const int theLevel, TopTools_MapOfShape& theResult)
145 TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
146 if (theValue.ShapeType() == TopAbs_FACE)
147 aConnectorType = TopAbs_EDGE;
148 TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
149 for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
150 aNBConnectors.Add(aValExp.Current());
153 TopTools_MapOfShape alreadyProcessed;
154 alreadyProcessed.Add(theValue);
156 for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
157 TopoDS_ListOfShape aGoodCandidates;
158 TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
159 for(; aCandidate.More(); aCandidate.Next()) {
160 if (alreadyProcessed.Contains(aCandidate.Current()))
162 TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
163 for(; aCandConnector.More(); aCandConnector.Next()) {
164 if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
167 if (aCandConnector.More()) {
168 if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
169 theResult.Add(aCandidate.Current());
170 } else { // add to the NB of the current level
171 aGoodCandidates.Append(aCandidate.Current());
175 if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
176 for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
177 TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
178 for(; aGoodConnector.More(); aGoodConnector.Next()) {
179 aNBConnectors.Add(aGoodConnector.Current());
181 alreadyProcessed.Add(aGood.Value());
187 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
188 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
189 const std::list<std::pair<TopoDS_Shape, int> >& theNB)
191 // searching for neighbors with minimum level
193 std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
194 for(; aNBIter != theNB.cend(); aNBIter++) {
195 if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
196 aMinLevel = aNBIter->second;
199 // collect all neighbors which are neighbors of sub-shapes with minimum level
201 TopoDS_ListOfShape aMatches;
202 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
203 if (aNBIter->second == aMinLevel) {
204 TopTools_MapOfShape aThisNBs;
205 findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
206 // aMatches must contain common part of all NBs lists
207 for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
209 aMatches.Append(aThisNB.Value());
211 // remove all in aMatches which are not in this NBs
212 for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
213 if (aThisNBs.Contains(aMatch.Value())) {
216 aMatches.Remove(aMatch);
224 if (aMatches.IsEmpty())
225 return TopoDS_Shape(); // not found any candidate
226 if (aMatches.Extent() == 1)
227 return aMatches.First(); // already found good candidate
228 // iterate all matches to find by other (higher level) neighbors the best candidate
229 TopoDS_Shape aGoodCandidate;
230 for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
231 bool aValidCadidate = true;
232 for(int aLevel = aMinLevel + 1; true; aLevel++) {
233 bool aFooundHigherLevel = false;
234 TopoDS_ListOfShape aLevelNBs;
235 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
236 if (aNBIter->second == aLevel)
237 aLevelNBs.Append(aNBIter->first);
238 else if (aNBIter->second >= aLevel)
239 aFooundHigherLevel = true;
241 if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
242 if (aGoodCandidate.IsNull()) {
243 aGoodCandidate = aCandidate.Value();
244 } else { // too many good candidates
245 return TopoDS_Shape();
248 if (!aLevelNBs.IsEmpty()) {
249 TopTools_MapOfShape aNBsOfCandidate;
250 findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
251 // check all stored neighbors are in the map of real neighbors
252 for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
253 if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
254 aValidCadidate = false;
259 if (!aValidCadidate) // candidate is not valid, break the checking
263 return aGoodCandidate;
266 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
267 const bool theUseNeighbors, const bool theUseIntersections)
269 if (theValue.IsNull() || theContext.IsNull())
271 // check the value shape can be named as it is, or it is needed to construct it from the
272 // higher level shapes (like a box vertex by faces that form this vertex)
273 bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
274 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
276 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
278 Handle(TNaming_NamedShape) aNS;
279 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
280 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
281 aNS->Evolution() == TNaming_PRIMITIVE) {
288 // searching in the base document
289 if (!aIsFound && !myBaseDocumentLab.IsNull() &&
290 TNaming_Tool::HasLabel(myBaseDocumentLab, theValue))
292 TNaming_SameShapeIterator aShapes(theValue, myBaseDocumentLab);
293 for(; aShapes.More(); aShapes.Next())
295 Handle(TNaming_NamedShape) aNS;
296 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
297 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
298 aNS->Evolution() == TNaming_PRIMITIVE) {
306 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
307 myShapeType = aSelectionType;
308 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
309 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
310 { // iterate all sub-shapes and select them on sublabels
311 for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
312 if (!selectBySubSelector(
313 theContext, aSubIter.Value(), theUseNeighbors, theUseIntersections)) {
314 return false; // if some selector is failed, everything is failed
317 myType = SELTYPE_CONTAINER;
321 // try to find the shape of the higher level type in the context shape
322 bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
323 TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
324 TopoDS_ListOfShape aLastIntersectors;
325 while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) {
326 if (aSelectionType == TopAbs_FACE) {
327 if (theValue.ShapeType() != TopAbs_VERTEX)
330 aSelectionType = TopAbs_EDGE;
332 aSelectionType = TopAbs_FACE;
333 TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
334 TopoDS_ListOfShape anIntList; // same as anIntersectors
335 for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
336 if (aSelectionType == TopAbs_EDGE &&
337 BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
339 TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
340 for(; aSubExp.More(); aSubExp.Next()) {
341 if (aSubExp.Current().IsSame(theValue)) {
342 if (anIntersectors.Add(aSelExp.Current()))
343 anIntList.Append(aSelExp.Current());
348 // check that solution is only one
349 TopoDS_ListOfShape aCommon;
350 commonShapes(anIntList, theValue.ShapeType(), aCommon);
351 if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
352 // name the intersectors
353 mySubSelList.clear();
354 TopoDS_ListOfShape::Iterator anInt(anIntList);
355 for (; anInt.More(); anInt.Next()) {
356 if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors, false)) {
357 break; // if some selector is failed, stop and search another solution
360 if (!anInt.More()) { // all intersectors were correctly named
361 myType = SELTYPE_INTERSECT;
364 } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) {
365 aLastCommon = aCommon;
366 aLastIntersectors = anIntList;
370 if (!theUseNeighbors)
373 // searching by neighbors
374 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
375 for(int aLevel = 1; true; aLevel++) {
376 TopTools_MapOfShape aNewNB;
377 findNeighbors(theContext, theValue, aLevel, aNewNB);
378 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
381 // iterate by the order in theContext to keep same naming names
382 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
383 for (; anOrder.More(); anOrder.Next()) {
384 if (aNewNB.Contains(anOrder.Current())) {
385 TopoDS_Shape aNewNBShape = anOrder.Current();
386 // check which can be named correctly, without "by neighbors" type
387 Selector_Selector aSelector(myLab.FindChild(1));
388 aSelector.setBaseDocument(myBaseDocumentLab);
389 if (aSelector.select(theContext, aNewNBShape, false, false)) { // add to list of good NBs
390 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
394 TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
395 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
396 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
397 for(; aNBIter != aNBs.end(); aNBIter++) {
398 if (!selectBySubSelector(theContext, aNBIter->first, false, false)) {
399 return false; // something is wrong because before this selection was ok
401 myNBLevel.push_back(aNBIter->second);
404 myType = SELTYPE_FILTER_BY_NEIGHBOR;
409 // weak naming to distinguish commons coming from intersection
410 if (aLastCommon.Extent() > 1) {
411 Selector_NExplode aNexp(aLastCommon);
412 myWeakIndex = aNexp.index(theValue);
413 if (myWeakIndex != -1) {
414 // name the intersectors
415 mySubSelList.clear();
416 TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
417 for (; anInt.More(); anInt.Next()) {
418 if (!selectBySubSelector(
419 theContext, anInt.Value(), theUseNeighbors, theUseIntersections)) {
420 break; // if some selector is failed, stop and search another solution
423 if (!anInt.More()) { // all intersectors were correctly named
424 myType = SELTYPE_INTERSECT;
430 // pure weak naming: there is no sense to use pure weak naming for neighbors selection
431 if (theUseNeighbors) {
432 myType = SELTYPE_WEAK_NAMING;
433 Selector_NExplode aNexp(theContext, theValue.ShapeType());
434 myWeakIndex = aNexp.index(theValue);
435 if (myWeakIndex != -1) {
436 myShapeType = theValue.ShapeType();
437 // searching for context shape label to store in myFinal
439 if (TNaming_Tool::HasLabel(myLab, theContext)) {
440 for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
442 Handle(TNaming_NamedShape) aNS;
443 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
444 TNaming_Evolution anEvolution = aNS->Evolution();
445 if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
446 anEvolution == TNaming_MODIFY) {
447 // check this is a new shape
448 for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
449 if (aNSIter.NewShape().IsSame(theContext)) {
450 myFinal = aNS->Label();
458 return true; // could be final empty (in case it is called recursively) or not
464 // searching for the base shapes of the value
465 Handle(TNaming_NamedShape) aPrimitiveNS;
466 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
467 for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
468 TDF_Label aLab = aUseExternal == 0 ? myLab : myBaseDocumentLab;
469 if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
471 for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
473 Handle(TNaming_NamedShape) aNS;
474 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
475 TNaming_Evolution anEvolution = aNS->Evolution();
476 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
479 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
480 // check this is a new shape
481 TNaming_Iterator aNSIter(aNS);
482 for(; aNSIter.More(); aNSIter.Next())
483 if (aNSIter.NewShape().IsSame(theValue))
485 if (aNSIter.More()) // new was found
486 aModifList.Append(aNS);
492 if (!aPrimitiveNS.IsNull()) {
493 myType = SELTYPE_PRIMITIVE;
494 myFinal = aPrimitiveNS->Label();
498 if (aModifList.Extent() > 1) { // searching for the best modification result: by context
499 Handle(TNaming_NamedShape) aCandidate;
500 NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
501 for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
502 aCandidate = aModIter.Value();
503 TDF_Label aFatherLab = aCandidate->Label().Father();
504 Handle(TNaming_NamedShape) aFatherNS;
505 if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
506 for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
507 if (theContext.IsSame(anIter.NewShape())) { // found the best modification
514 // take the best candidate, or the last in the iteration
516 aModifList.Append(aCandidate);
519 if (!aModifList.IsEmpty()) {
520 // searching for all the base shapes of this modification
521 findBases(myLab, aModifList.First(), theValue, true, myBaseDocumentLab, myBases);
522 if (!myBases.IsEmpty()) {
523 myFinal = aModifList.First()->Label();
524 TopoDS_ListOfShape aCommon;
525 findModificationResult(aCommon);
526 // trying to search by neighbors
527 if (aCommon.Extent() > 1) { // more complicated selection
528 if (!theUseNeighbors)
531 // searching by neighbors
532 std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
533 for(int aLevel = 1; true; aLevel++) {
534 TopTools_MapOfShape aNewNB;
535 findNeighbors(theContext, theValue, aLevel, aNewNB);
536 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
539 // iterate by the order in theContext to keep same naming names
540 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
541 for (; anOrder.More(); anOrder.Next()) {
542 if (aNewNB.Contains(anOrder.Current())) {
543 TopoDS_Shape aNewNBShape = anOrder.Current();
544 // check which can be named correctly, without "by neighbors" type
545 Selector_Selector aSelector(myLab.FindChild(1));
546 if (!myBaseDocumentLab.IsNull())
547 aSelector.setBaseDocument(myBaseDocumentLab);
548 if (aSelector.select(theContext, aNewNBShape, false)) {// add to list of good NBs
549 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
553 TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
554 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
555 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
556 for(; aNBIter != aNBs.end(); aNBIter++) {
557 if (!selectBySubSelector(
558 theContext, aNBIter->first, theUseNeighbors, theUseIntersections)) {
559 return false; // something is wrong because before this selection was ok
561 myNBLevel.push_back(aNBIter->second);
564 myType = SELTYPE_FILTER_BY_NEIGHBOR;
568 // filter by neighbors did not help
569 if (aCommon.Extent() > 1) { // weak naming between the common results
570 Selector_NExplode aNexp(aCommon);
571 myWeakIndex = aNexp.index(theValue);
572 if (myWeakIndex == -1)
577 myType = SELTYPE_MODIFICATION;
578 if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
579 TopoDS_ListOfShape aCommon;
580 myFinal = aModifList.First()->Label();
581 Handle(TNaming_NamedShape) aNS;
582 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
583 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
584 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
585 if (!aNewShape.IsNull())
586 aCommon.Append(aNewShape);
589 Selector_NExplode aNexp(aCommon);
590 myWeakIndex = aNexp.index(theValue);
591 if (myWeakIndex == -1)
597 // not found a good result
601 void Selector_Selector::store()
603 myLab.ForgetAllAttributes(true); // remove old naming data
604 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
606 case SELTYPE_CONTAINER:
607 case SELTYPE_INTERSECT: {
608 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
609 // store also all sub-selectors
610 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
611 for(; aSubSel != mySubSelList.end(); aSubSel++) {
614 if (myWeakIndex != -1) {
615 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
619 case SELTYPE_PRIMITIVE: {
620 Handle(TDataStd_ReferenceArray) anArray =
621 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
622 anArray->SetValue(0, myFinal);
625 case SELTYPE_MODIFICATION: {
626 Handle(TDataStd_ReferenceArray) anArray =
627 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
628 TDF_LabelList::Iterator aBIter(myBases);
629 for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
630 anArray->SetValue(anIndex, aBIter.Value());
632 anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
633 if (myWeakIndex != -1) {
634 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
638 case SELTYPE_FILTER_BY_NEIGHBOR: {
639 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
640 // store numbers of levels corresponded to the neighbors in sub-selectors
641 Handle(TDataStd_IntegerArray) anArray =
642 TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
643 std::list<int>::iterator aLevel = myNBLevel.begin();
644 for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
645 anArray->SetValue(anIndex, *aLevel);
647 // store all sub-selectors
648 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
649 for(; aSubSel != mySubSelList.end(); aSubSel++) {
654 case SELTYPE_WEAK_NAMING: {
655 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
656 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
657 // store myFinal in the base array
658 if (!myFinal.IsNull()) {
659 Handle(TDataStd_ReferenceArray) anArray =
660 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
661 anArray->SetValue(0, myFinal);
665 default: { // unknown case
671 bool Selector_Selector::restore()
673 Handle(TDataStd_Integer) aTypeAttr;
674 if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
676 myType = Selector_Type(aTypeAttr->Get());
678 case SELTYPE_CONTAINER:
679 case SELTYPE_INTERSECT: {
680 Handle(TDataStd_Integer) aShapeTypeAttr;
681 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
683 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
684 // restore sub-selectors
685 bool aSubResult = true;
686 mySubSelList.clear();
687 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
688 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
689 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
690 if (!mySubSelList.back().restore())
693 Handle(TDataStd_Integer) aWeakInt;
694 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
695 myWeakIndex = aWeakInt->Get();
699 case SELTYPE_PRIMITIVE: {
700 Handle(TDataStd_ReferenceArray) anArray;
701 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
702 myFinal = anArray->Value(0);
707 case SELTYPE_MODIFICATION: {
708 Handle(TDataStd_ReferenceArray) anArray;
709 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
710 int anUpper = anArray->Upper();
711 for(int anIndex = 0; anIndex < anUpper; anIndex++) {
712 myBases.Append(anArray->Value(anIndex));
714 myFinal = anArray->Value(anUpper);
715 Handle(TDataStd_Integer) aWeakInt;
716 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
717 myWeakIndex = aWeakInt->Get();
723 case SELTYPE_FILTER_BY_NEIGHBOR: {
724 Handle(TDataStd_Integer) aShapeTypeAttr;
725 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
727 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
728 // restore sub-selectors
729 bool aSubResult = true;
730 mySubSelList.clear();
731 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
732 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
733 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
734 if (!mySubSelList.back().restore())
737 // restore levels indices
738 Handle(TDataStd_IntegerArray) anArray;
739 if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
741 for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
742 myNBLevel.push_back(anArray->Value(anIndex));
746 case SELTYPE_WEAK_NAMING: {
747 Handle(TDataStd_Integer) aWeakInt;
748 if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
750 myWeakIndex = aWeakInt->Get();
751 Handle(TDataStd_Integer) aShapeTypeAttr;
752 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
754 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
755 Handle(TDataStd_ReferenceArray) anArray;
756 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
757 myFinal = anArray->Value(0);
761 default: { // unknown case
767 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
768 static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
769 const TDF_Label& theFinal,
770 const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults)
772 if (TNaming_Tool::HasLabel(anAccess, theBase)) {
773 for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
775 TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
776 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
777 if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
778 theResults.Add(aBaseIter.Shape());
780 findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults);
785 if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
786 static TDF_Label anEmpty;
787 findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults);
791 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
792 for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
793 TDF_Label anAdditionalDoc; // this document if base is started in extra document
794 if (aBase.Value().Root() != myLab.Root()) {
795 anAdditionalDoc = myLab;
797 TopTools_MapOfShape aFinals;
798 for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
799 findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals);
801 if (!aFinals.IsEmpty()) {
802 if (theCommon.IsEmpty()) { // just copy all to common
803 for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
804 theCommon.Append(aFinal.Key());
806 } else { // keep only shapes presented in both lists
807 for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
808 if (aFinals.Contains(aCommon.Value())) {
810 } else { // common is not found, remove it
811 theCommon.Remove(aCommon);
819 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
821 TopoDS_Shape aResult; // null if invalid
823 case SELTYPE_CONTAINER: {
824 TopoDS_Builder aBuilder;
825 switch(myShapeType) {
826 case TopAbs_COMPOUND: {
827 TopoDS_Compound aComp;
828 aBuilder.MakeCompound(aComp);
832 case TopAbs_COMPSOLID: {
833 TopoDS_CompSolid aComp;
834 aBuilder.MakeCompSolid(aComp);
840 aBuilder.MakeShell(aShell);
846 aBuilder.MakeWire(aWire);
851 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
852 for(; aSubSel != mySubSelList.end(); aSubSel++) {
853 if (!aSubSel->solve(theContext)) {
856 aBuilder.Add(aResult, aSubSel->value());
860 case SELTYPE_INTERSECT: {
861 TopoDS_ListOfShape aSubSelectorShapes;
862 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
863 for(; aSubSel != mySubSelList.end(); aSubSel++) {
864 if (!aSubSel->solve(theContext)) {
867 aSubSelectorShapes.Append(aSubSel->value());
869 TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
870 commonShapes(aSubSelectorShapes, myShapeType, aCommon);
871 if (aCommon.Extent() != 1) {
872 if (myWeakIndex != -1) {
873 Selector_NExplode aNexp(aCommon);
874 aResult = aNexp.shape(myWeakIndex);
879 aResult = aCommon.First();
883 case SELTYPE_PRIMITIVE: {
884 Handle(TNaming_NamedShape) aNS;
885 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
886 aResult = aNS->Get();
890 case SELTYPE_MODIFICATION: {
891 if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index
892 TopoDS_ListOfShape aCommon;
893 Handle(TNaming_NamedShape) aNS;
894 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
895 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
896 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
897 if (!aNewShape.IsNull())
898 aCommon.Append(aNewShape);
901 Selector_NExplode aNexp(aCommon);
902 aResult = aNexp.shape(myWeakIndex);
903 } else { // standard case
904 TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
905 findModificationResult(aFinalsCommon);
906 if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
907 aResult = aFinalsCommon.First();
908 else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
909 Selector_NExplode aNExp(aFinalsCommon);
910 aResult = aNExp.shape(myWeakIndex);
915 case SELTYPE_FILTER_BY_NEIGHBOR: {
916 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
917 std::list<int>::iterator aLevel = myNBLevel.begin();
918 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
919 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
920 if (!aSubSel->solve(theContext)) {
923 aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
925 aResult = findNeighbor(theContext, aNBs);
928 case SELTYPE_WEAK_NAMING: {
929 TopoDS_Shape aContext;
930 if (myFinal.IsNull()) {
931 aContext = theContext;
933 Handle(TNaming_NamedShape) aNS;
934 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
935 aContext = aNS->Get();
938 if (!aContext.IsNull()) {
939 Selector_NExplode aNexp(aContext, myShapeType);
940 aResult = aNexp.shape(myWeakIndex);
943 default: { // unknown case
947 TNaming_Builder aBuilder(myLab);
948 if (!aResult.IsNull()) {
949 aBuilder.Select(aResult, aResult);
952 return false; // builder just erases the named shape in case of error
955 TopoDS_Shape Selector_Selector::value()
957 Handle(TNaming_NamedShape) aNS;
958 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
960 return TopoDS_Shape(); // empty, error shape
963 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
964 static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
966 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
968 case SELTYPE_CONTAINER:
969 case SELTYPE_INTERSECT: {
971 // add names of sub-components one by one in "[]" +optionally [weak_name_1]
972 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
973 for(; aSubSel != mySubSelList.end(); aSubSel++) {
975 aResult += aSubSel->name(theNameGenerator);
977 TopoDS_Shape aSubVal = aSubSel->value();
978 if (!aSubVal.IsNull()) {
979 TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
980 if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
982 case TopAbs_COMPOUND: aResult += "c"; break;
983 case TopAbs_COMPSOLID: aResult += "o"; break;
984 case TopAbs_SOLID: aResult += "s"; break;
985 case TopAbs_SHELL: aResult += "h"; break;
986 case TopAbs_WIRE: aResult += "w"; break;
987 case TopAbs_EDGE: aResult += "e"; break;
988 case TopAbs_VERTEX: aResult += "v"; break;
995 if (myWeakIndex != -1) {
996 std::ostringstream aWeakStr;
997 aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
998 aResult += aWeakStr.str();
1002 case SELTYPE_PRIMITIVE: {
1003 Handle(TDataStd_Name) aName;
1004 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
1006 return theNameGenerator->contextName(myFinal) + "/" +
1007 std::string(TCollection_AsciiString(aName->Get()).ToCString());
1009 case SELTYPE_MODIFICATION: {
1010 // final&base1&base2 +optionally: [weak_name_1]
1011 std::string aResult;
1012 Handle(TDataStd_Name) aName;
1013 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
1015 aResult += theNameGenerator->contextName(myFinal) + "/" +
1016 std::string(TCollection_AsciiString(aName->Get()).ToCString());
1017 for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
1018 if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
1021 aResult += theNameGenerator->contextName(*aBase) + "/" +
1022 std::string(TCollection_AsciiString(aName->Get()).ToCString());
1024 if (myWeakIndex != -1) {
1025 std::ostringstream aWeakStr;
1026 aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
1027 aResult += aWeakStr.str();
1031 case SELTYPE_FILTER_BY_NEIGHBOR: {
1032 // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
1033 std::string aResult;
1034 std::list<int>::iterator aLevel = myNBLevel.begin();
1035 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1036 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
1037 aResult += "(" + aSubSel->name(theNameGenerator) + ")";
1039 std::ostringstream aLevelStr;
1041 aResult += aLevelStr.str();
1046 case SELTYPE_WEAK_NAMING: {
1047 // _weak_naming_1_Context
1048 std::ostringstream aWeakStr;
1049 aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
1050 std::string aResult = aWeakStr.str();
1051 if (!myFinal.IsNull())
1052 aResult += "_" + theNameGenerator->contextName(myFinal);
1055 default: { // unknown case
1061 TDF_Label Selector_Selector::restoreByName(
1062 std::string theName, const TopAbs_ShapeEnum theShapeType,
1063 Selector_NameGenerator* theNameGenerator)
1065 if (theName[0] == '[') { // intersection or container
1066 switch(theShapeType) {
1067 case TopAbs_COMPOUND:
1068 case TopAbs_COMPSOLID:
1071 myType = SELTYPE_CONTAINER;
1076 myType = SELTYPE_INTERSECT;
1079 return TDF_Label(); // unknown case
1081 myShapeType = theShapeType;
1083 for(size_t aStart = 0; aStart != std::string::npos;
1084 aStart = theName.find('[', aStart + 1)) {
1085 size_t anEndPos = theName.find(']', aStart + 1);
1086 if (anEndPos != std::string::npos) {
1087 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1088 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1089 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1090 myWeakIndex = atoi(aWeakIndex.c_str());
1093 TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
1094 if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
1095 char aShapeChar = theName[anEndPos + 1];
1096 if (theName[anEndPos + 1] != '[') {
1097 switch(aShapeChar) {
1098 case 'c': aSubShapeType = TopAbs_COMPOUND; break;
1099 case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
1100 case 's': aSubShapeType = TopAbs_SOLID; break;
1101 case 'h': aSubShapeType = TopAbs_SHELL; break;
1102 case 'w': aSubShapeType = TopAbs_WIRE; break;
1103 case 'e': aSubShapeType = TopAbs_EDGE; break;
1104 case 'v': aSubShapeType = TopAbs_VERTEX; break;
1109 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1110 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1111 TDF_Label aSubContext =
1112 mySubSelList.back().restoreByName(aSubStr, aSubShapeType, theNameGenerator);
1113 if (aSubContext.IsNull())
1114 return aSubContext; // invalid sub-selection parsing
1115 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1116 if (!theNameGenerator->isLater(aContext, aSubContext))
1117 aContext = aSubContext;
1119 aContext = aSubContext;
1122 return TDF_Label(); // invalid parentheses
1125 } else if (theName[0] == '(') { // filter by neighbors
1126 myType = SELTYPE_FILTER_BY_NEIGHBOR;
1128 for(size_t aStart = 0; aStart != std::string::npos;
1129 aStart = theName.find('(', aStart + 1)) {
1130 size_t anEndPos = theName.find(')', aStart + 1);
1131 if (anEndPos != std::string::npos) {
1132 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1133 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1134 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1135 TDF_Label aSubContext =
1136 mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
1137 if (aSubContext.IsNull())
1138 return aSubContext; // invalid sub-selection parsing
1139 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1140 if (!theNameGenerator->isLater(aContext, aSubContext))
1141 aContext = aSubContext;
1143 aContext = aSubContext;
1145 if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
1146 aContext = theNameGenerator->newestContext(aContext);
1148 // searching for the level index
1150 for(anEndPos++; anEndPos != std::string::npos &&
1151 theName[anEndPos] != '(' && theName[anEndPos] != 0;
1153 aLevel += theName[anEndPos];
1156 myNBLevel.push_back(1); // by default it is 1
1158 int aNum = atoi(aLevel.c_str());
1160 myNBLevel.push_back(aNum);
1162 return TDF_Label(); // invalid number
1165 return TDF_Label(); // invalid parentheses
1168 } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1169 myType = SELTYPE_WEAK_NAMING;
1170 std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1171 std::size_t aContextPosition = aWeakIndex.find("_");
1172 myWeakIndex = atoi(aWeakIndex.c_str());
1173 myShapeType = theShapeType;
1175 if (aContextPosition != std::string::npos) { // context is also defined
1176 std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1177 theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1180 } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive
1181 myType = SELTYPE_PRIMITIVE;
1183 if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1184 if (!myFinal.IsNull())
1187 } else { // modification
1188 myType = SELTYPE_MODIFICATION;
1190 for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1193 anEnd = theName.find('&', aStart);
1194 std::string aSubStr =
1195 theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1196 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1197 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1198 myWeakIndex = atoi(aWeakIndex.c_str());
1201 TDF_Label aSubContext, aValue;
1202 if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1203 return TDF_Label(); // can not restore
1204 if(aSubContext.IsNull() || aValue.IsNull())
1205 return TDF_Label(); // can not restore
1206 if (myFinal.IsNull()) {
1208 aContext = aSubContext;
1210 myBases.Append(aValue);
1217 bool Selector_Selector::selectBySubSelector(
1218 const TopoDS_Shape theContext, const TopoDS_Shape theValue,
1219 const bool theUseNeighbors, const bool theUseIntersections)
1221 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1222 if (!myBaseDocumentLab.IsNull())
1223 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1224 if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors, theUseIntersections)) {
1225 mySubSelList.clear(); // if one of the selector is failed, all become invalid