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 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
70 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
71 bool aMustBeAtFinal, TDF_LabelList& theResult)
73 TNaming_SameShapeIterator aLabIter(theValue, theFinal->Label());
74 for(; aLabIter.More(); aLabIter.Next()) {
75 Handle(TNaming_NamedShape) aNS;
76 if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
77 if (aMustBeAtFinal && aNS != theFinal)
78 continue; // looking for old at the same final label only
79 TNaming_Evolution anEvolution = aNS->Evolution();
80 if (anEvolution == TNaming_PRIMITIVE) {
81 // check that this is not in the results already
82 const TDF_Label aResult = aNS->Label();
83 TDF_LabelList::Iterator aResIter(theResult);
84 for(; aResIter.More(); aResIter.Next()) {
85 if (aResIter.Value().IsEqual(aResult))
88 if (!aResIter.More()) // not found, so add this new
89 theResult.Append(aResult);
91 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
92 for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
93 if (aThisIter.NewShape().IsSame(theValue)) {
94 // continue recursively, null NS means that any NS are ok
95 findBases(theFinal, aThisIter.OldShape(), false, theResult);
103 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
104 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
105 TopoDS_ListOfShape& theResults)
107 TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
108 for(; aSubSel != theShapes.end(); aSubSel++) {
109 TopTools_MapOfShape aCurrentMap;
110 for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
111 if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
112 theResults.Append(anExp.Current());
114 if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
115 for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
116 if (aCurrentMap.Contains(aComIter.Value()))
119 theResults.Remove(aComIter);
125 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
126 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
127 const int theLevel, TopTools_MapOfShape& theResult)
129 TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
130 if (theValue.ShapeType() == TopAbs_FACE)
131 aConnectorType = TopAbs_EDGE;
132 TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
133 for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
134 aNBConnectors.Add(aValExp.Current());
137 TopTools_MapOfShape alreadyProcessed;
138 alreadyProcessed.Add(theValue);
140 for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
141 TopoDS_ListOfShape aGoodCandidates;
142 TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
143 for(; aCandidate.More(); aCandidate.Next()) {
144 if (alreadyProcessed.Contains(aCandidate.Current()))
146 TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
147 for(; aCandConnector.More(); aCandConnector.Next()) {
148 if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
151 if (aCandConnector.More()) {
152 if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
153 theResult.Add(aCandidate.Current());
154 } else { // add to the NB of the current level
155 aGoodCandidates.Append(aCandidate.Current());
159 if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
160 for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
161 TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
162 for(; aGoodConnector.More(); aGoodConnector.Next()) {
163 aNBConnectors.Add(aGoodConnector.Current());
165 alreadyProcessed.Add(aGood.Value());
171 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
172 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
173 const std::list<std::pair<TopoDS_Shape, int> >& theNB)
175 // searching for neighbors with minimum level
177 std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
178 for(; aNBIter != theNB.cend(); aNBIter++) {
179 if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
180 aMinLevel = aNBIter->second;
183 // collect all neighbors which are neighbors of sub-shapes with minimum level
185 TopoDS_ListOfShape aMatches;
186 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
187 if (aNBIter->second == aMinLevel) {
188 TopTools_MapOfShape aThisNBs;
189 findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
190 // aMatches must contain common part of all NBs lists
191 for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
193 aMatches.Append(aThisNB.Value());
195 // remove all in aMatches which are not in this NBs
196 for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
197 if (aThisNBs.Contains(aMatch.Value())) {
200 aMatches.Remove(aMatch);
208 if (aMatches.IsEmpty())
209 return TopoDS_Shape(); // not found any candidate
210 if (aMatches.Extent() == 1)
211 return aMatches.First(); // already found good candidate
212 // iterate all matches to find by other (higher level) neighbors the best candidate
213 TopoDS_Shape aGoodCandidate;
214 for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
215 bool aValidCadidate = true;
216 for(int aLevel = aMinLevel + 1; true; aLevel++) {
217 bool aFooundHigherLevel = false;
218 TopoDS_ListOfShape aLevelNBs;
219 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
220 if (aNBIter->second == aLevel)
221 aLevelNBs.Append(aNBIter->first);
222 else if (aNBIter->second >= aLevel)
223 aFooundHigherLevel = true;
225 if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
226 if (aGoodCandidate.IsNull()) {
227 aGoodCandidate = aCandidate.Value();
228 } else { // too many good candidates
229 return TopoDS_Shape();
232 if (!aLevelNBs.IsEmpty()) {
233 TopTools_MapOfShape aNBsOfCandidate;
234 findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
235 // check all stored neighbors are in the map of real neighbors
236 for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
237 if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
238 aValidCadidate = false;
243 if (!aValidCadidate) // candidate is not valid, break the checking
247 return aGoodCandidate;
250 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
251 const bool theUseNeighbors, const bool theUseIntersections)
253 if (theValue.IsNull() || theContext.IsNull())
255 // check the value shape can be named as it is, or it is needed to construct it from the
256 // higher level shapes (like a box vertex by faces that form this vertex)
257 bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
258 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
260 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
262 Handle(TNaming_NamedShape) aNS;
263 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
264 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
265 aNS->Evolution() == TNaming_PRIMITIVE) {
273 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
274 myShapeType = aSelectionType;
275 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
276 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
277 { // iterate all sub-shapes and select them on sublabels
278 for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
279 if (!selectBySubSelector(
280 theContext, aSubIter.Value(), theUseNeighbors, theUseIntersections)) {
281 return false; // if some selector is failed, everything is failed
284 myType = SELTYPE_CONTAINER;
288 // try to find the shape of the higher level type in the context shape
289 bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
290 TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
291 TopoDS_ListOfShape aLastIntersectors;
292 while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) {
293 if (aSelectionType == TopAbs_FACE) {
294 if (theValue.ShapeType() != TopAbs_VERTEX)
297 aSelectionType = TopAbs_EDGE;
299 aSelectionType = TopAbs_FACE;
300 TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
301 TopoDS_ListOfShape anIntList; // same as anIntersectors
302 for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
303 if (aSelectionType == TopAbs_EDGE &&
304 BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
306 TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
307 for(; aSubExp.More(); aSubExp.Next()) {
308 if (aSubExp.Current().IsSame(theValue)) {
309 if (anIntersectors.Add(aSelExp.Current()))
310 anIntList.Append(aSelExp.Current());
315 // check that solution is only one
316 TopoDS_ListOfShape aCommon;
317 commonShapes(anIntList, theValue.ShapeType(), aCommon);
318 if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
319 // name the intersectors
320 mySubSelList.clear();
321 TopoDS_ListOfShape::Iterator anInt(anIntList);
322 for (; anInt.More(); anInt.Next()) {
323 if (!selectBySubSelector(theContext, anInt.Value(), theUseNeighbors, false)) {
324 break; // if some selector is failed, stop and search another solution
327 if (!anInt.More()) { // all intersectors were correctly named
328 myType = SELTYPE_INTERSECT;
331 } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) {
332 aLastCommon = aCommon;
333 aLastIntersectors = anIntList;
337 if (!theUseNeighbors)
340 // searching by neighbors
341 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
342 for(int aLevel = 1; true; aLevel++) {
343 TopTools_MapOfShape aNewNB;
344 findNeighbors(theContext, theValue, aLevel, aNewNB);
345 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
348 // iterate by the order in theContext to keep same naming names
349 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
350 for (; anOrder.More(); anOrder.Next()) {
351 if (aNewNB.Contains(anOrder.Current())) {
352 TopoDS_Shape aNewNBShape = anOrder.Current();
353 // check which can be named correctly, without "by neighbors" type
354 Selector_Selector aSelector(myLab.FindChild(1));
355 if (aSelector.select(theContext, aNewNBShape, false, false)) { // add to list of good NBs
356 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
360 TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
361 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
362 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
363 for(; aNBIter != aNBs.end(); aNBIter++) {
364 if (!selectBySubSelector(theContext, aNBIter->first, false, false)) {
365 return false; // something is wrong because before this selection was ok
367 myNBLevel.push_back(aNBIter->second);
370 myType = SELTYPE_FILTER_BY_NEIGHBOR;
375 // weak naming to distinguish commons coming from intersection
376 if (aLastCommon.Extent() > 1) {
377 Selector_NExplode aNexp(aLastCommon);
378 myWeakIndex = aNexp.index(theValue);
379 if (myWeakIndex != -1) {
380 // name the intersectors
381 mySubSelList.clear();
382 TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
383 for (; anInt.More(); anInt.Next()) {
384 if (!selectBySubSelector(
385 theContext, anInt.Value(), theUseNeighbors, theUseIntersections)) {
386 break; // if some selector is failed, stop and search another solution
389 if (!anInt.More()) { // all intersectors were correctly named
390 myType = SELTYPE_INTERSECT;
396 // pure weak naming: there is no sense to use pure weak naming for neighbors selection
397 if (theUseNeighbors) {
398 myType = SELTYPE_WEAK_NAMING;
399 Selector_NExplode aNexp(theContext, theValue.ShapeType());
400 myWeakIndex = aNexp.index(theValue);
401 if (myWeakIndex != -1) {
402 myShapeType = theValue.ShapeType();
403 // searching for context shape label to store in myFinal
405 if (TNaming_Tool::HasLabel(myLab, theContext)) {
406 for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
408 Handle(TNaming_NamedShape) aNS;
409 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
410 TNaming_Evolution anEvolution = aNS->Evolution();
411 if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
412 anEvolution == TNaming_MODIFY) {
413 // check this is a new shape
414 for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
415 if (aNSIter.NewShape().IsSame(theContext)) {
416 myFinal = aNS->Label();
424 return true; // could be final empty (in case it is called recursively) or not
430 // searching for the base shapes of the value
431 Handle(TNaming_NamedShape) aPrimitiveNS;
432 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
433 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
435 Handle(TNaming_NamedShape) aNS;
436 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
437 TNaming_Evolution anEvolution = aNS->Evolution();
438 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
441 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
442 // check this is a new shape
443 TNaming_Iterator aNSIter(aNS);
444 for(; aNSIter.More(); aNSIter.Next())
445 if (aNSIter.NewShape().IsSame(theValue))
447 if (aNSIter.More()) // new was found
448 aModifList.Append(aNS);
453 if (!aPrimitiveNS.IsNull()) {
454 myType = SELTYPE_PRIMITIVE;
455 myFinal = aPrimitiveNS->Label();
459 if (aModifList.Extent() > 1) { // searching for the best modification result: by context
460 Handle(TNaming_NamedShape) aCandidate;
461 NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
462 for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
463 aCandidate = aModIter.Value();
464 TDF_Label aFatherLab = aCandidate->Label().Father();
465 Handle(TNaming_NamedShape) aFatherNS;
466 if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
467 for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
468 if (theContext.IsSame(anIter.NewShape())) { // found the best modification
475 // take the best candidate, or the last in the iteration
477 aModifList.Append(aCandidate);
480 if (!aModifList.IsEmpty()) {
481 // searching for all the base shapes of this modification
482 findBases(aModifList.First(), theValue, true, myBases);
483 if (!myBases.IsEmpty()) {
484 myFinal = aModifList.First()->Label();
485 TopoDS_ListOfShape aCommon;
486 findModificationResult(aCommon);
487 // trying to search by neighbors
488 if (aCommon.Extent() > 1) { // more complicated selection
489 if (!theUseNeighbors)
492 // searching by neighbors
493 std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
494 for(int aLevel = 1; true; aLevel++) {
495 TopTools_MapOfShape aNewNB;
496 findNeighbors(theContext, theValue, aLevel, aNewNB);
497 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
500 // iterate by the order in theContext to keep same naming names
501 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
502 for (; anOrder.More(); anOrder.Next()) {
503 if (aNewNB.Contains(anOrder.Current())) {
504 TopoDS_Shape aNewNBShape = anOrder.Current();
505 // check which can be named correctly, without "by neighbors" type
506 Selector_Selector aSelector(myLab.FindChild(1));
507 if (aSelector.select(theContext, aNewNBShape, false)) {// add to list of good NBs
508 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
512 TopoDS_Shape aResult = findNeighbor(theContext, aNBs);
513 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
514 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
515 for(; aNBIter != aNBs.end(); aNBIter++) {
516 if (!selectBySubSelector(
517 theContext, aNBIter->first, theUseNeighbors, theUseIntersections)) {
518 return false; // something is wrong because before this selection was ok
520 myNBLevel.push_back(aNBIter->second);
523 myType = SELTYPE_FILTER_BY_NEIGHBOR;
527 // filter by neighbors did not help
528 if (aCommon.Extent() > 1) { // weak naming between the common results
529 Selector_NExplode aNexp(aCommon);
530 myWeakIndex = aNexp.index(theValue);
531 if (myWeakIndex == -1)
536 myType = SELTYPE_MODIFICATION;
537 if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
538 TopoDS_ListOfShape aCommon;
539 myFinal = aModifList.First()->Label();
540 Handle(TNaming_NamedShape) aNS;
541 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
542 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
543 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
544 if (!aNewShape.IsNull())
545 aCommon.Append(aNewShape);
548 Selector_NExplode aNexp(aCommon);
549 myWeakIndex = aNexp.index(theValue);
550 if (myWeakIndex == -1)
556 // not found a good result
560 void Selector_Selector::store()
562 myLab.ForgetAllAttributes(true); // remove old naming data
563 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
565 case SELTYPE_CONTAINER:
566 case SELTYPE_INTERSECT: {
567 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
568 // store also all sub-selectors
569 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
570 for(; aSubSel != mySubSelList.end(); aSubSel++) {
573 if (myWeakIndex != -1) {
574 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
578 case SELTYPE_PRIMITIVE: {
579 Handle(TDataStd_ReferenceArray) anArray =
580 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
581 anArray->SetValue(0, myFinal);
584 case SELTYPE_MODIFICATION: {
585 Handle(TDataStd_ReferenceArray) anArray =
586 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
587 TDF_LabelList::Iterator aBIter(myBases);
588 for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
589 anArray->SetValue(anIndex, aBIter.Value());
591 anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
592 if (myWeakIndex != -1) {
593 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
597 case SELTYPE_FILTER_BY_NEIGHBOR: {
598 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
599 // store numbers of levels corresponded to the neighbors in sub-selectors
600 Handle(TDataStd_IntegerArray) anArray =
601 TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
602 std::list<int>::iterator aLevel = myNBLevel.begin();
603 for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
604 anArray->SetValue(anIndex, *aLevel);
606 // store all sub-selectors
607 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
608 for(; aSubSel != mySubSelList.end(); aSubSel++) {
613 case SELTYPE_WEAK_NAMING: {
614 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
615 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
616 // store myFinal in the base array
617 if (!myFinal.IsNull()) {
618 Handle(TDataStd_ReferenceArray) anArray =
619 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
620 anArray->SetValue(0, myFinal);
624 default: { // unknown case
630 bool Selector_Selector::restore()
632 Handle(TDataStd_Integer) aTypeAttr;
633 if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
635 myType = Selector_Type(aTypeAttr->Get());
637 case SELTYPE_CONTAINER:
638 case SELTYPE_INTERSECT: {
639 Handle(TDataStd_Integer) aShapeTypeAttr;
640 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
642 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
643 // restore sub-selectors
644 bool aSubResult = true;
645 mySubSelList.clear();
646 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
647 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
648 if (!mySubSelList.back().restore())
651 Handle(TDataStd_Integer) aWeakInt;
652 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
653 myWeakIndex = aWeakInt->Get();
657 case SELTYPE_PRIMITIVE: {
658 Handle(TDataStd_ReferenceArray) anArray;
659 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
660 myFinal = anArray->Value(0);
665 case SELTYPE_MODIFICATION: {
666 Handle(TDataStd_ReferenceArray) anArray;
667 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
668 int anUpper = anArray->Upper();
669 for(int anIndex = 0; anIndex < anUpper; anIndex++) {
670 myBases.Append(anArray->Value(anIndex));
672 myFinal = anArray->Value(anUpper);
673 Handle(TDataStd_Integer) aWeakInt;
674 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
675 myWeakIndex = aWeakInt->Get();
681 case SELTYPE_FILTER_BY_NEIGHBOR: {
682 Handle(TDataStd_Integer) aShapeTypeAttr;
683 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
685 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
686 // restore sub-selectors
687 bool aSubResult = true;
688 mySubSelList.clear();
689 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
690 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
691 if (!mySubSelList.back().restore())
694 // restore levels indices
695 Handle(TDataStd_IntegerArray) anArray;
696 if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
698 for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
699 myNBLevel.push_back(anArray->Value(anIndex));
703 case SELTYPE_WEAK_NAMING: {
704 Handle(TDataStd_Integer) aWeakInt;
705 if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
707 myWeakIndex = aWeakInt->Get();
708 Handle(TDataStd_Integer) aShapeTypeAttr;
709 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
711 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
712 Handle(TDataStd_ReferenceArray) anArray;
713 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
714 myFinal = anArray->Value(0);
718 default: { // unknown case
724 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
725 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
726 TopTools_MapOfShape& theResults)
728 for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
729 TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
730 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
731 if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
732 theResults.Add(aBaseIter.Shape());
734 findFinals(aBaseIter.Shape(), theFinal, theResults);
740 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
741 for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
742 TopTools_MapOfShape aFinals;
743 for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
744 findFinals(aBaseShape.NewShape(), myFinal, aFinals);
745 if (!aFinals.IsEmpty()) {
746 if (theCommon.IsEmpty()) { // just copy all to common
747 for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
748 theCommon.Append(aFinal.Key());
750 } else { // keep only shapes presented in both lists
751 for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
752 if (aFinals.Contains(aCommon.Value())) {
754 } else { // common is not found, remove it
755 theCommon.Remove(aCommon);
763 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
765 TopoDS_Shape aResult; // null if invalid
767 case SELTYPE_CONTAINER: {
768 TopoDS_Builder aBuilder;
769 switch(myShapeType) {
770 case TopAbs_COMPOUND: {
771 TopoDS_Compound aComp;
772 aBuilder.MakeCompound(aComp);
776 case TopAbs_COMPSOLID: {
777 TopoDS_CompSolid aComp;
778 aBuilder.MakeCompSolid(aComp);
784 aBuilder.MakeShell(aShell);
790 aBuilder.MakeWire(aWire);
795 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
796 for(; aSubSel != mySubSelList.end(); aSubSel++) {
797 if (!aSubSel->solve(theContext)) {
800 aBuilder.Add(aResult, aSubSel->value());
804 case SELTYPE_INTERSECT: {
805 TopoDS_ListOfShape aSubSelectorShapes;
806 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
807 for(; aSubSel != mySubSelList.end(); aSubSel++) {
808 if (!aSubSel->solve(theContext)) {
811 aSubSelectorShapes.Append(aSubSel->value());
813 TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
814 commonShapes(aSubSelectorShapes, myShapeType, aCommon);
815 if (aCommon.Extent() != 1) {
816 if (myWeakIndex != -1) {
817 Selector_NExplode aNexp(aCommon);
818 aResult = aNexp.shape(myWeakIndex);
823 aResult = aCommon.First();
827 case SELTYPE_PRIMITIVE: {
828 Handle(TNaming_NamedShape) aNS;
829 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
830 aResult = aNS->Get();
834 case SELTYPE_MODIFICATION: {
835 if (myBases.IsEmpty() && myWeakIndex) { // weak name by the final shapes index
836 TopoDS_ListOfShape aCommon;
837 Handle(TNaming_NamedShape) aNS;
838 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
839 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
840 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
841 if (!aNewShape.IsNull())
842 aCommon.Append(aNewShape);
845 Selector_NExplode aNexp(aCommon);
846 aResult = aNexp.shape(myWeakIndex);
847 } else { // standard case
848 TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
849 findModificationResult(aFinalsCommon);
850 if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
851 aResult = aFinalsCommon.First();
852 else if (aFinalsCommon.Extent() > 1 && myWeakIndex) {
853 Selector_NExplode aNExp(aFinalsCommon);
854 aResult = aNExp.shape(myWeakIndex);
859 case SELTYPE_FILTER_BY_NEIGHBOR: {
860 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
861 std::list<int>::iterator aLevel = myNBLevel.begin();
862 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
863 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
864 if (!aSubSel->solve(theContext)) {
867 aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
869 aResult = findNeighbor(theContext, aNBs);
872 case SELTYPE_WEAK_NAMING: {
873 TopoDS_Shape aContext;
874 if (myFinal.IsNull()) {
875 aContext = theContext;
877 Handle(TNaming_NamedShape) aNS;
878 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
879 aContext = aNS->Get();
882 if (!aContext.IsNull()) {
883 Selector_NExplode aNexp(aContext, myShapeType);
884 aResult = aNexp.shape(myWeakIndex);
887 default: { // unknown case
891 TNaming_Builder aBuilder(myLab);
892 if (!aResult.IsNull()) {
893 aBuilder.Select(aResult, aResult);
896 return false; // builder just erases the named shape in case of error
899 TopoDS_Shape Selector_Selector::value()
901 Handle(TNaming_NamedShape) aNS;
902 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
904 return TopoDS_Shape(); // empty, error shape
907 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
908 static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
910 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
912 case SELTYPE_CONTAINER:
913 case SELTYPE_INTERSECT: {
915 // add names of sub-components one by one in "[]" +optionally [weak_name_1]
916 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
917 for(; aSubSel != mySubSelList.end(); aSubSel++) {
919 aResult += aSubSel->name(theNameGenerator);
921 TopoDS_Shape aSubVal = aSubSel->value();
922 if (!aSubVal.IsNull()) {
923 TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
924 if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
926 case TopAbs_COMPOUND: aResult += "c"; break;
927 case TopAbs_COMPSOLID: aResult += "o"; break;
928 case TopAbs_SOLID: aResult += "s"; break;
929 case TopAbs_SHELL: aResult += "h"; break;
930 case TopAbs_WIRE: aResult += "w"; break;
931 case TopAbs_EDGE: aResult += "e"; break;
932 case TopAbs_VERTEX: aResult += "v"; break;
939 if (myWeakIndex != -1) {
940 std::ostringstream aWeakStr;
941 aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
942 aResult += aWeakStr.str();
946 case SELTYPE_PRIMITIVE: {
947 Handle(TDataStd_Name) aName;
948 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
950 return theNameGenerator->contextName(myFinal) + "/" +
951 std::string(TCollection_AsciiString(aName->Get()).ToCString());
953 case SELTYPE_MODIFICATION: {
954 // final&base1&base2 +optionally: [weak_name_1]
956 Handle(TDataStd_Name) aName;
957 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
959 aResult += theNameGenerator->contextName(myFinal) + "/" +
960 std::string(TCollection_AsciiString(aName->Get()).ToCString());
961 for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
962 if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
965 aResult += theNameGenerator->contextName(*aBase) + "/" +
966 std::string(TCollection_AsciiString(aName->Get()).ToCString());
968 if (myWeakIndex != -1) {
969 std::ostringstream aWeakStr;
970 aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
971 aResult += aWeakStr.str();
975 case SELTYPE_FILTER_BY_NEIGHBOR: {
976 // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
978 std::list<int>::iterator aLevel = myNBLevel.begin();
979 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
980 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
981 aResult += "(" + aSubSel->name(theNameGenerator) + ")";
983 std::ostringstream aLevelStr;
985 aResult += aLevelStr.str();
990 case SELTYPE_WEAK_NAMING: {
991 // _weak_naming_1_Context
992 std::ostringstream aWeakStr;
993 aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
994 std::string aResult = aWeakStr.str();
995 if (!myFinal.IsNull())
996 aResult += "_" + theNameGenerator->contextName(myFinal);
999 default: { // unknown case
1005 TDF_Label Selector_Selector::restoreByName(
1006 std::string theName, const TopAbs_ShapeEnum theShapeType,
1007 Selector_NameGenerator* theNameGenerator)
1009 if (theName[0] == '[') { // intersection or container
1010 switch(theShapeType) {
1011 case TopAbs_COMPOUND:
1012 case TopAbs_COMPSOLID:
1015 myType = SELTYPE_CONTAINER;
1020 myType = SELTYPE_INTERSECT;
1023 return TDF_Label(); // unknown case
1025 myShapeType = theShapeType;
1027 for(size_t aStart = 0; aStart != std::string::npos;
1028 aStart = theName.find('[', aStart + 1)) {
1029 size_t anEndPos = theName.find(']', aStart + 1);
1030 if (anEndPos != std::string::npos) {
1031 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1032 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1033 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1034 myWeakIndex = atoi(aWeakIndex.c_str());
1037 TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
1038 if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
1039 char aShapeChar = theName[anEndPos + 1];
1040 if (theName[anEndPos + 1] != '[') {
1041 switch(aShapeChar) {
1042 case 'c': aSubShapeType = TopAbs_COMPOUND; break;
1043 case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
1044 case 's': aSubShapeType = TopAbs_SOLID; break;
1045 case 'h': aSubShapeType = TopAbs_SHELL; break;
1046 case 'w': aSubShapeType = TopAbs_WIRE; break;
1047 case 'e': aSubShapeType = TopAbs_EDGE; break;
1048 case 'v': aSubShapeType = TopAbs_VERTEX; break;
1053 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1054 TDF_Label aSubContext =
1055 mySubSelList.back().restoreByName(aSubStr, aSubShapeType, theNameGenerator);
1056 if (aSubContext.IsNull())
1057 return aSubContext; // invalid sub-selection parsing
1058 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1059 if (!theNameGenerator->isLater(aContext, aSubContext))
1060 aContext = aSubContext;
1062 aContext = aSubContext;
1065 return TDF_Label(); // invalid parentheses
1068 } else if (theName[0] == '(') { // filter by neighbors
1069 myType = SELTYPE_FILTER_BY_NEIGHBOR;
1071 for(size_t aStart = 0; aStart != std::string::npos;
1072 aStart = theName.find('(', aStart + 1)) {
1073 size_t anEndPos = theName.find(')', aStart + 1);
1074 if (anEndPos != std::string::npos) {
1075 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1076 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1077 TDF_Label aSubContext =
1078 mySubSelList.back().restoreByName(aSubStr, theShapeType, theNameGenerator);
1079 if (aSubContext.IsNull())
1080 return aSubContext; // invalid sub-selection parsing
1081 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1082 if (!theNameGenerator->isLater(aContext, aSubContext))
1083 aContext = aSubContext;
1085 aContext = aSubContext;
1087 if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
1088 aContext = theNameGenerator->newestContext(aContext);
1090 // searching for the level index
1092 for(anEndPos++; anEndPos != std::string::npos &&
1093 theName[anEndPos] != '(' && theName[anEndPos] != 0;
1095 aLevel += theName[anEndPos];
1098 myNBLevel.push_back(1); // by default it is 1
1100 int aNum = atoi(aLevel.c_str());
1102 myNBLevel.push_back(aNum);
1104 return TDF_Label(); // invalid number
1107 return TDF_Label(); // invalid parentheses
1110 } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1111 myType = SELTYPE_WEAK_NAMING;
1112 std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1113 std::size_t aContextPosition = aWeakIndex.find("_");
1114 myWeakIndex = atoi(aWeakIndex.c_str());
1115 myShapeType = theShapeType;
1117 if (aContextPosition != std::string::npos) { // context is also defined
1118 std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1119 theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1122 } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive
1123 myType = SELTYPE_PRIMITIVE;
1125 if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1126 if (!myFinal.IsNull())
1129 } else { // modification
1130 myType = SELTYPE_MODIFICATION;
1132 for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1135 anEnd = theName.find('&', aStart);
1136 std::string aSubStr =
1137 theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1138 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1139 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1140 myWeakIndex = atoi(aWeakIndex.c_str());
1143 TDF_Label aSubContext, aValue;
1144 if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1145 return TDF_Label(); // can not restore
1146 if(aSubContext.IsNull() || aValue.IsNull())
1147 return TDF_Label(); // can not restore
1148 if (myFinal.IsNull()) {
1150 aContext = aSubContext;
1152 myBases.Append(aValue);
1159 bool Selector_Selector::selectBySubSelector(
1160 const TopoDS_Shape theContext, const TopoDS_Shape theValue,
1161 const bool theUseNeighbors, const bool theUseIntersections)
1163 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1164 if (!mySubSelList.back().select(theContext, theValue, theUseNeighbors, theUseIntersections)) {
1165 mySubSelList.clear(); // if one of the selector is failed, all become invalid