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>
29 #include <TopExp_Explorer.hxx>
30 #include <TNaming_Tool.hxx>
31 #include <TNaming_NewShapeIterator.hxx>
32 #include <TNaming_OldShapeIterator.hxx>
33 #include <TNaming_SameShapeIterator.hxx>
34 #include <TNaming_Iterator.hxx>
35 #include <TNaming_Builder.hxx>
36 #include <TopTools_MapOfShape.hxx>
38 #include <TDataStd_Integer.hxx>
39 #include <TDataStd_ReferenceArray.hxx>
40 #include <TDataStd_IntegerArray.hxx>
41 #include <TDataStd_Name.hxx>
45 /// type of the selection, integerm keeps the Selector_Type value
46 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
47 /// type of the shape, stored in case it is intersection or container
48 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
49 // reference attribute that contains the reference to labels where the "from" or "base" shapes
50 // of selection are located
51 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
52 // array of the neighbor levels
53 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
54 // weak index (integer) of the sub-shape
55 static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
57 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
62 TDF_Label Selector_Selector::label()
67 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
68 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
69 bool aMustBeAtFinal, TDF_LabelList& theResult)
71 TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
72 for(; aLabIter.More(); aLabIter.Next()) {
73 Handle(TNaming_NamedShape) aNS;
74 aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
75 if (aMustBeAtFinal && aNS != theFinal)
76 continue; // looking for old at the same final label only
77 TNaming_Evolution anEvolution = aNS->Evolution();
78 if (anEvolution == TNaming_PRIMITIVE) {
79 // check that this is not in the results already
80 const TDF_Label aResult = aNS->Label();
81 TDF_LabelList::Iterator aResIter(theResult);
82 for(; aResIter.More(); aResIter.Next()) {
83 if (aResIter.Value().IsEqual(aResult))
86 if (!aResIter.More()) // not found, so add this new
87 theResult.Append(aResult);
89 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
90 for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
91 if (aThisIter.NewShape().IsSame(theValue)) {
92 // continue recursively, null NS means that any NS are ok
93 findBases(theFinal, aThisIter.OldShape(), false, theResult);
100 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
101 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
102 TopoDS_ListOfShape& theResults)
104 TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
105 for(; aSubSel != theShapes.end(); aSubSel++) {
106 TopTools_MapOfShape aCurrentMap;
107 for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
108 if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
109 theResults.Append(anExp.Current());
111 if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
112 for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
113 if (aCurrentMap.Contains(aComIter.Value()))
116 theResults.Remove(aComIter);
122 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
123 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
124 const int theLevel, TopTools_MapOfShape& theResult)
126 TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
127 if (theValue.ShapeType() == TopAbs_FACE)
128 aConnectorType = TopAbs_EDGE;
129 TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
130 for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
131 aNBConnectors.Add(aValExp.Current());
134 TopTools_MapOfShape alreadyProcessed;
135 alreadyProcessed.Add(theValue);
137 for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
138 TopoDS_ListOfShape aGoodCandidates;
139 TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
140 for(; aCandidate.More(); aCandidate.Next()) {
141 if (alreadyProcessed.Contains(aCandidate.Current()))
143 TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
144 for(; aCandConnector.More(); aCandConnector.Next()) {
145 if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
148 if (aCandConnector.More()) {
149 if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
150 theResult.Add(aCandidate.Current());
151 } else { // add to the NB of the current level
152 aGoodCandidates.Append(aCandidate.Current());
156 if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
157 for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
158 TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
159 for(; aGoodConnector.More(); aGoodConnector.Next()) {
160 aNBConnectors.Add(aGoodConnector.Current());
162 alreadyProcessed.Add(aGood.Value());
168 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
169 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
170 const std::list<std::pair<TopoDS_Shape, int> >& theNB)
172 // searching for neighbors with minimum level
174 std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
175 for(; aNBIter != theNB.cend(); aNBIter++) {
176 if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
177 aMinLevel = aNBIter->second;
180 // collect all neighbors which are neighbors of sub-shapes with minimum level
182 TopoDS_ListOfShape aMatches;
183 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
184 if (aNBIter->second == aMinLevel) {
185 TopTools_MapOfShape aThisNBs;
186 findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
187 // aMatches must contain common part of all NBs lists
188 for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
190 aMatches.Append(aThisNB.Value());
192 // remove all in aMatches which are not in this NBs
193 for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
194 if (aThisNBs.Contains(aMatch.Value())) {
197 aMatches.Remove(aMatch);
205 if (aMatches.IsEmpty())
206 return TopoDS_Shape(); // not found any candidate
207 if (aMatches.Extent() == 1)
208 return aMatches.First(); // already found good candidate
209 // iterate all matches to find by other (higher level) neighbors the best candidate
210 TopoDS_Shape aGoodCandidate;
211 for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
212 bool aValidCadidate = true;
213 for(int aLevel = aMinLevel + 1; true; aLevel++) {
214 bool aFooundHigherLevel = false;
215 TopoDS_ListOfShape aLevelNBs;
216 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
217 if (aNBIter->second == aLevel)
218 aLevelNBs.Append(aNBIter->first);
219 else if (aNBIter->second >= aLevel)
220 aFooundHigherLevel = true;
222 if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
223 if (aGoodCandidate.IsNull()) {
224 aGoodCandidate = aCandidate.Value();
225 } else { // too many good candidates
226 return TopoDS_Shape();
229 if (!aLevelNBs.IsEmpty()) {
230 TopTools_MapOfShape aNBsOfCandidate;
231 findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
232 // check all stored neighbors are in the map of real neighbors
233 for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
234 if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
235 aValidCadidate = false;
240 if (!aValidCadidate) // candidate is not valid, break the checking
244 return aGoodCandidate;
247 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
248 const bool theUseNeighbors)
250 if (theValue.IsNull() || theContext.IsNull())
252 // check the value shape can be named as it is, or it is needed to construct it from the
253 // higher level shapes (like a box vertex by faces that form this vertex)
254 bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
255 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
257 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
259 Handle(TNaming_NamedShape) aNS;
260 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
261 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
262 aNS->Evolution() == TNaming_PRIMITIVE) {
270 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
271 myShapeType = aSelectionType;
272 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
273 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
274 { // iterate all sub-shapes and select them on sublabels
275 for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
276 if (!selectBySubSelector(theContext, aSubIter.Value(), theUseNeighbors)) {
277 return false; // if some selector is failed, everything is failed
280 myType = SELTYPE_CONTAINER;
284 // try to find the shape of the higher level type in the context shape
285 bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
286 TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
287 TopoDS_ListOfShape aLastIntersectors;
288 while(aSelectionType != TopAbs_FACE || !aFacesTried) {
289 if (aSelectionType == TopAbs_FACE) {
290 if (theValue.ShapeType() != TopAbs_VERTEX)
293 aSelectionType = TopAbs_EDGE;
295 aSelectionType = TopAbs_FACE;
296 TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
297 TopoDS_ListOfShape anIntList; // same as anIntersectors
298 for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
299 TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
300 for(; aSubExp.More(); aSubExp.Next()) {
301 if (aSubExp.Current().IsSame(theValue)) {
302 if (anIntersectors.Add(aSelExp.Current()))
303 anIntList.Append(aSelExp.Current());
308 // check that solution is only one
309 TopoDS_ListOfShape aCommon;
310 commonShapes(anIntList, theValue.ShapeType(), aCommon);
311 if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
312 // name the intersectors
313 mySubSelList.clear();
314 TopoDS_ListOfShape::Iterator anInt(anIntList);
315 for (; anInt.More(); anInt.Next()) {
316 if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors)) {
317 break; // if some selector is failed, stop and search another solution
320 if (!anInt.More()) { // all intersectors were correctly named
321 myType = SELTYPE_INTERSECT;
324 } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) {
325 aLastCommon = aCommon;
326 aLastIntersectors = anIntList;
330 if (!theUseNeighbors)
333 // searching by neighbours
334 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
335 for(int aLevel = 1; true; aLevel++) {
336 TopTools_MapOfShape aNewNB;
337 findNeighbors(theContext, theValue, aLevel, aNewNB);
338 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
341 // iterate by the order in theContext to keep same naming names
342 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
343 for (; anOrder.More(); anOrder.Next()) {
344 if (aNewNB.Contains(anOrder.Current())) {
345 TopoDS_Shape aNewNBShape = anOrder.Current();
346 // check which can be named correctly, without "by neighbors" type
347 Selector_Selector aSelector(myLab.FindChild(1));
348 if (aSelector.select(theContext, aNewNBShape, false)) { // add to the list of good NBs
349 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
353 TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
354 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
355 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
356 for(; aNBIter != aNBs.end(); aNBIter++) {
357 if (!selectBySubSelector(theContext, aNBIter->first, false)) {
358 return false; // something is wrong because before this selection was ok
360 myNBLevel.push_back(aNBIter->second);
363 myType = SELTYPE_FILTER_BY_NEIGHBOR;
368 // weak naming to distinguish commons coming from intersection
369 if (aLastCommon.Extent() > 1) {
370 Selector_NExplode aNexp(aLastCommon);
371 myWeakIndex = aNexp.index(theValue);
372 if (myWeakIndex != -1) {
373 // name the intersectors
374 mySubSelList.clear();
375 TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
376 for (; anInt.More(); anInt.Next()) {
377 if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors)) {
378 break; // if some selector is failed, stop and search another solution
381 if (!anInt.More()) { // all intersectors were correctly named
382 myType = SELTYPE_INTERSECT;
389 myType = SELTYPE_WEAK_NAMING;
390 Selector_NExplode aNexp(theContext, theValue.ShapeType());
391 myWeakIndex = aNexp.index(theValue);
392 if (myWeakIndex != -1) {
393 myShapeType = theValue.ShapeType();
394 // searching for context shape label to store in myFinal
396 if (TNaming_Tool::HasLabel(myLab, theContext)) {
397 for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
399 Handle(TNaming_NamedShape) aNS;
400 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
401 TNaming_Evolution anEvolution = aNS->Evolution();
402 if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
403 anEvolution == TNaming_MODIFY) {
404 // check this is a new shape
405 for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
406 if (aNSIter.NewShape().IsSame(theContext)) {
407 myFinal = aNS->Label();
415 return true; // could be final empty (in case it is called recursively) or not
420 // searching for the base shapes of the value
421 Handle(TNaming_NamedShape) aPrimitiveNS;
422 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
423 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
425 Handle(TNaming_NamedShape) aNS;
426 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
427 TNaming_Evolution anEvolution = aNS->Evolution();
428 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
431 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
432 // check this is a new shape
433 TNaming_Iterator aNSIter(aNS);
434 for(; aNSIter.More(); aNSIter.Next())
435 if (aNSIter.NewShape().IsSame(theValue))
437 if (aNSIter.More()) // new was found
438 aModifList.Append(aNS);
443 if (!aPrimitiveNS.IsNull()) {
444 myType = SELTYPE_PRIMITIVE;
445 myFinal = aPrimitiveNS->Label();
449 if (aModifList.Extent() > 1) { // searching for the best modification result: by context
450 Handle(TNaming_NamedShape) aCandidate;
451 NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
452 for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
453 aCandidate = aModIter.Value();
454 TDF_Label aFatherLab = aCandidate->Label().Father();
455 Handle(TNaming_NamedShape) aFatherNS;
456 if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
457 for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
458 if (theContext.IsSame(anIter.NewShape())) { // found the best modification
465 // take the best candidate, or the last in the iteration
467 aModifList.Append(aCandidate);
470 if (!aModifList.IsEmpty()) {
471 // searching for all the base shapes of this modification
472 findBases(aModifList.First(), theValue, true, myBases);
473 if (!myBases.IsEmpty()) {
474 myFinal = aModifList.First()->Label();
475 TopoDS_ListOfShape aCommon;
476 findModificationResult(aCommon);
477 // trying to search by neighbours
478 if (aCommon.Extent() > 1) { // more complicated selection
479 if (!theUseNeighbors)
482 // searching by neighbours
483 std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
484 for(int aLevel = 1; true; aLevel++) {
485 TopTools_MapOfShape aNewNB;
486 findNeighbors(theContext, theValue, aLevel, aNewNB);
487 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
490 // iterate by the order in theContext to keep same naming names
491 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
492 for (; anOrder.More(); anOrder.Next()) {
493 if (aNewNB.Contains(anOrder.Current())) {
494 TopoDS_Shape aNewNBShape = anOrder.Current();
495 // check which can be named correctly, without "by neighbors" type
496 Selector_Selector aSelector(myLab.FindChild(1));
497 if (aSelector.select(theContext, aNewNBShape, false)) {// add to list of good NBs
498 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
502 TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
503 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
504 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
505 for(; aNBIter != aNBs.end(); aNBIter++) {
506 if (!selectBySubSelector(theContext, aNBIter->first, theUseNeighbors)) {
507 return false; // something is wrong because before this selection was ok
509 myNBLevel.push_back(aNBIter->second);
512 myType = SELTYPE_FILTER_BY_NEIGHBOR;
516 // filter by neighbours did not help
517 if (aCommon.Extent() > 1) { // weak naming between the common results
518 Selector_NExplode aNexp(aCommon);
519 myWeakIndex = aNexp.index(theValue);
520 if (myWeakIndex == -1)
525 myType = SELTYPE_MODIFICATION;
526 if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
527 TopoDS_ListOfShape aCommon;
528 myFinal = aModifList.First()->Label();
529 Handle(TNaming_NamedShape) aNS;
530 myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS);
531 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
532 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
533 if (!aNewShape.IsNull())
534 aCommon.Append(aNewShape);
536 Selector_NExplode aNexp(aCommon);
537 myWeakIndex = aNexp.index(theValue);
538 if (myWeakIndex == -1)
544 // not found a good result
548 void Selector_Selector::store()
550 myLab.ForgetAllAttributes(true); // remove old naming data
551 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
553 case SELTYPE_CONTAINER:
554 case SELTYPE_INTERSECT: {
555 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
556 // store also all sub-selectors
557 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
558 for(; aSubSel != mySubSelList.end(); aSubSel++) {
561 if (myWeakIndex != -1) {
562 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
566 case SELTYPE_PRIMITIVE: {
567 Handle(TDataStd_ReferenceArray) anArray =
568 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
569 anArray->SetValue(0, myFinal);
572 case SELTYPE_MODIFICATION: {
573 Handle(TDataStd_ReferenceArray) anArray =
574 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
575 TDF_LabelList::Iterator aBIter(myBases);
576 for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
577 anArray->SetValue(anIndex, aBIter.Value());
579 anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
580 if (myWeakIndex != -1) {
581 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
585 case SELTYPE_FILTER_BY_NEIGHBOR: {
586 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
587 // store numbers of levels corresponded to the neighbors in sub-selectors
588 Handle(TDataStd_IntegerArray) anArray =
589 TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
590 std::list<int>::iterator aLevel = myNBLevel.begin();
591 for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
592 anArray->SetValue(anIndex, *aLevel);
594 // store all sub-selectors
595 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
596 for(; aSubSel != mySubSelList.end(); aSubSel++) {
601 case SELTYPE_WEAK_NAMING: {
602 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
603 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
604 // store myFinal in the base array
605 if (!myFinal.IsNull()) {
606 Handle(TDataStd_ReferenceArray) anArray =
607 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
608 anArray->SetValue(0, myFinal);
612 default: { // unknown case
618 bool Selector_Selector::restore()
620 Handle(TDataStd_Integer) aTypeAttr;
621 if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
623 myType = Selector_Type(aTypeAttr->Get());
625 case SELTYPE_CONTAINER:
626 case SELTYPE_INTERSECT: {
627 Handle(TDataStd_Integer) aShapeTypeAttr;
628 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
630 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
631 // restore sub-selectors
632 bool aSubResult = true;
633 mySubSelList.clear();
634 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
635 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
636 if (!mySubSelList.back().restore())
639 Handle(TDataStd_Integer) aWeakInt;
640 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
641 myWeakIndex = aWeakInt->Get();
645 case SELTYPE_PRIMITIVE: {
646 Handle(TDataStd_ReferenceArray) anArray;
647 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
648 myFinal = anArray->Value(0);
653 case SELTYPE_MODIFICATION: {
654 Handle(TDataStd_ReferenceArray) anArray;
655 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
656 int anUpper = anArray->Upper();
657 for(int anIndex = 0; anIndex < anUpper; anIndex++) {
658 myBases.Append(anArray->Value(anIndex));
660 myFinal = anArray->Value(anUpper);
661 Handle(TDataStd_Integer) aWeakInt;
662 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
663 myWeakIndex = aWeakInt->Get();
669 case SELTYPE_FILTER_BY_NEIGHBOR: {
670 Handle(TDataStd_Integer) aShapeTypeAttr;
671 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
673 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
674 // restore sub-selectors
675 bool aSubResult = true;
676 mySubSelList.clear();
677 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
678 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
679 if (!mySubSelList.back().restore())
682 // restore levels indices
683 Handle(TDataStd_IntegerArray) anArray;
684 if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
686 for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
687 myNBLevel.push_back(anArray->Value(anIndex));
691 case SELTYPE_WEAK_NAMING: {
692 Handle(TDataStd_Integer) aWeakInt;
693 if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
695 myWeakIndex = aWeakInt->Get();
696 Handle(TDataStd_Integer) aShapeTypeAttr;
697 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
699 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
700 Handle(TDataStd_ReferenceArray) anArray;
701 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
702 myFinal = anArray->Value(0);
706 default: { // unknown case
712 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
713 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
714 TopTools_MapOfShape& theResults)
716 for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
717 TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
718 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
719 if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
720 theResults.Add(aBaseIter.Shape());
722 findFinals(aBaseIter.Shape(), theFinal, theResults);
728 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
729 for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
730 TopTools_MapOfShape aFinals;
731 for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
732 findFinals(aBaseShape.NewShape(), myFinal, aFinals);
733 if (!aFinals.IsEmpty()) {
734 if (theCommon.IsEmpty()) { // just copy all to common
735 for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
736 theCommon.Append(aFinal.Key());
738 } else { // keep only shapes presented in both lists
739 for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
740 if (aFinals.Contains(aCommon.Value())) {
742 } else { // common is not found, remove it
743 theCommon.Remove(aCommon);
751 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
753 TopoDS_Shape aResult; // null if invalid
755 case SELTYPE_CONTAINER: {
756 TopoDS_Builder aBuilder;
757 switch(myShapeType) {
758 case TopAbs_COMPOUND: {
759 TopoDS_Compound aComp;
760 aBuilder.MakeCompound(aComp);
764 case TopAbs_COMPSOLID: {
765 TopoDS_CompSolid aComp;
766 aBuilder.MakeCompSolid(aComp);
772 aBuilder.MakeShell(aShell);
778 aBuilder.MakeWire(aWire);
783 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
784 for(; aSubSel != mySubSelList.end(); aSubSel++) {
785 if (!aSubSel->solve(theContext)) {
788 aBuilder.Add(aResult, aSubSel->value());
792 case SELTYPE_INTERSECT: {
793 TopoDS_ListOfShape aSubSelectorShapes;
794 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
795 for(; aSubSel != mySubSelList.end(); aSubSel++) {
796 if (!aSubSel->solve(theContext)) {
799 aSubSelectorShapes.Append(aSubSel->value());
801 TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
802 commonShapes(aSubSelectorShapes, myShapeType, aCommon);
803 if (aCommon.Extent() != 1) {
804 if (myWeakIndex != -1) {
805 Selector_NExplode aNexp(aCommon);
806 aResult = aNexp.shape(myWeakIndex);
811 aResult = aCommon.First();
815 case SELTYPE_PRIMITIVE: {
816 Handle(TNaming_NamedShape) aNS;
817 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
818 aResult = aNS->Get();
822 case SELTYPE_MODIFICATION: {
823 if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index
824 TopoDS_ListOfShape aCommon;
825 Handle(TNaming_NamedShape) aNS;
826 myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS);
827 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
828 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
829 if (!aNewShape.IsNull())
830 aCommon.Append(aNewShape);
832 Selector_NExplode aNexp(aCommon);
833 aResult = aNexp.shape(myWeakIndex);
834 } else { // standard case
835 TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
836 findModificationResult(aFinalsCommon);
837 if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
838 aResult = aFinalsCommon.First();
839 else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
840 Selector_NExplode aNExp(aFinalsCommon);
841 aResult = aNExp.shape(myWeakIndex);
846 case SELTYPE_FILTER_BY_NEIGHBOR: {
847 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
848 std::list<int>::iterator aLevel = myNBLevel.begin();
849 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
850 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
851 if (!aSubSel->solve(theContext)) {
854 aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
856 aResult = findNeighbor(theContext, aNBs);
859 case SELTYPE_WEAK_NAMING: {
860 TopoDS_Shape aContext;
861 if (myFinal.IsNull()) {
862 aContext = theContext;
864 Handle(TNaming_NamedShape) aNS;
865 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
866 aContext = aNS->Get();
869 if (!aContext.IsNull()) {
870 Selector_NExplode aNexp(aContext, myShapeType);
871 aResult = aNexp.shape(myWeakIndex);
874 default: { // unknown case
878 TNaming_Builder aBuilder(myLab);
879 if (!aResult.IsNull()) {
880 aBuilder.Select(aResult, aResult);
883 return false; // builder just erases the named shape in case of error
886 TopoDS_Shape Selector_Selector::value()
888 Handle(TNaming_NamedShape) aNS;
889 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
891 return TopoDS_Shape(); // empty, error shape
894 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
895 static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
897 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
899 case SELTYPE_CONTAINER:
900 case SELTYPE_INTERSECT: {
902 // add names of sub-components one by one in "[]" +optionally [weak_name_1]
903 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
904 for(; aSubSel != mySubSelList.end(); aSubSel++) {
906 aResult += aSubSel->name(theNameGenerator);
909 if (myWeakIndex != -1) {
910 std::ostringstream aWeakStr;
911 aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
912 aResult += aWeakStr.str();
916 case SELTYPE_PRIMITIVE: {
917 Handle(TDataStd_Name) aName;
918 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
920 return theNameGenerator->contextName(myFinal) + "/" +
921 std::string(TCollection_AsciiString(aName->Get()).ToCString());
923 case SELTYPE_MODIFICATION: {
924 // final&base1&base2 +optionally: [weak_name_1]
926 Handle(TDataStd_Name) aName;
927 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
929 aResult += theNameGenerator->contextName(myFinal) + "/" +
930 std::string(TCollection_AsciiString(aName->Get()).ToCString());
931 for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
932 if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
935 aResult += theNameGenerator->contextName(*aBase) + "/" +
936 std::string(TCollection_AsciiString(aName->Get()).ToCString());
938 if (myWeakIndex != -1) {
939 std::ostringstream aWeakStr;
940 aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
941 aResult += aWeakStr.str();
945 case SELTYPE_FILTER_BY_NEIGHBOR: {
946 // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
948 std::list<int>::iterator aLevel = myNBLevel.begin();
949 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
950 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
951 aResult += "(" + aSubSel->name(theNameGenerator) + ")";
953 std::ostringstream aLevelStr;
955 aResult += aLevelStr.str();
960 case SELTYPE_WEAK_NAMING: {
961 // _weak_naming_1_Context
962 std::ostringstream aWeakStr;
963 aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
964 std::string aResult = aWeakStr.str();
965 if (!myFinal.IsNull())
966 aResult += "_" + theNameGenerator->contextName(myFinal);
969 default: { // unknown case
975 TDF_Label Selector_Selector::restoreByName(
976 std::string theName, const TopAbs_ShapeEnum theShapeType,
977 Selector_NameGenerator* theNameGenerator)
979 if (theName[0] == '[') { // intersection or container
980 switch(theShapeType) {
981 case TopAbs_COMPOUND:
982 case TopAbs_COMPSOLID:
985 myType = SELTYPE_CONTAINER;
990 myType = SELTYPE_INTERSECT;
993 return TDF_Label(); // unknown case
995 myShapeType = theShapeType;
997 for(size_t aStart = 0; aStart != std::string::npos;
998 aStart = theName.find('[', aStart + 1)) {
999 size_t anEndPos = theName.find(']', aStart + 1);
1000 if (anEndPos != std::string::npos) {
1001 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1002 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1003 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1004 myWeakIndex = atoi(aWeakIndex.c_str());
1007 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1008 TDF_Label aSubContext =
1009 mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
1010 if (aSubContext.IsNull())
1011 return aSubContext; // invalid sub-selection parsing
1012 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1013 if (!theNameGenerator->isLater(aContext, aSubContext))
1014 aContext = aSubContext;
1016 aContext = aSubContext;
1019 return TDF_Label(); // invalid parentheses
1022 } else if (theName[0] == '(') { // filter by neighbours
1023 myType = SELTYPE_FILTER_BY_NEIGHBOR;
1025 for(size_t aStart = 0; aStart != std::string::npos;
1026 aStart = theName.find('(', aStart + 1)) {
1027 size_t anEndPos = theName.find(')', aStart + 1);
1028 if (anEndPos != std::string::npos) {
1029 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1030 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1031 TDF_Label aSubContext =
1032 mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
1033 if (aSubContext.IsNull())
1034 return aSubContext; // invalid sub-selection parsing
1035 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1036 if (!theNameGenerator->isLater(aContext, aSubContext))
1037 aContext = aSubContext;
1039 aContext = aSubContext;
1041 if (!aContext.IsNull()) // for filters by neighbour the latest context shape is vital
1042 aContext = theNameGenerator->newestContext(aContext);
1044 // searching for the level index
1046 for(anEndPos++; anEndPos != std::string::npos &&
1047 theName[anEndPos] != '(' && theName[anEndPos] != 0;
1049 aLevel += theName[anEndPos];
1052 myNBLevel.push_back(1); // by default it is 1
1054 int aNum = atoi(aLevel.c_str());
1056 myNBLevel.push_back(aNum);
1058 return TDF_Label(); // invalid number
1061 return TDF_Label(); // invalid parentheses
1064 } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1065 myType = SELTYPE_WEAK_NAMING;
1066 std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1067 std::size_t aContextPosition = aWeakIndex.find("_");
1068 myWeakIndex = atoi(aWeakIndex.c_str());
1069 myShapeType = theShapeType;
1071 if (aContextPosition != std::string::npos) { // context is also defined
1072 std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1073 theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1076 } else if (theName.find('&') == std::string::npos) { // wihtout '&' it can be only primitive
1077 myType = SELTYPE_PRIMITIVE;
1079 if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1080 if (!myFinal.IsNull())
1083 } else { // modification
1084 myType = SELTYPE_MODIFICATION;
1086 for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1089 anEnd = theName.find('&', aStart);
1090 std::string aSubStr =
1091 theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1092 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1093 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1094 myWeakIndex = atoi(aWeakIndex.c_str());
1097 TDF_Label aSubContext, aValue;
1098 if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1099 return TDF_Label(); // can not restore
1100 if(aSubContext.IsNull() || aValue.IsNull())
1101 return TDF_Label(); // can not restore
1102 if (myFinal.IsNull()) {
1104 aContext = aSubContext;
1106 myBases.Append(aValue);
1113 bool Selector_Selector::selectBySubSelector(
1114 const TopoDS_Shape theContext, const TopoDS_Shape theValue, const bool theUseNeighbors)
1116 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1117 if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors)) {
1118 mySubSelList.clear(); // if one of the selector is failed, all become invalid