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 <TopoDS_Iterator.hxx>
27 #include <TopoDS_Builder.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TopoDS_Edge.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <TNaming_Tool.hxx>
33 #include <TNaming_NewShapeIterator.hxx>
34 #include <TNaming_OldShapeIterator.hxx>
35 #include <TNaming_SameShapeIterator.hxx>
36 #include <TNaming_Iterator.hxx>
37 #include <TNaming_Builder.hxx>
38 #include <TopTools_MapOfShape.hxx>
39 #include <BRep_Tool.hxx>
41 #include <TDF_ChildIDIterator.hxx>
42 #include <TDF_Tool.hxx>
43 #include <TDataStd_Integer.hxx>
44 #include <TDataStd_ReferenceArray.hxx>
45 #include <TDataStd_IntegerArray.hxx>
46 #include <TDataStd_Name.hxx>
47 #include <TDataStd_UAttribute.hxx>
48 #include <TDataStd_ExtStringList.hxx>
52 /// type of the selection, integer keeps the Selector_Type value
53 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
54 /// type of the shape, stored in case it is intersection or container
55 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
56 // reference attribute that contains the reference to labels where the "from" or "base" shapes
57 // of selection are located
58 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
59 // if the base array contains reference to the root label, this means that it refers to an
60 // external document and this list contains a tag in the document
61 static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a");
62 // array of the neighbor levels
63 static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f");
64 // weak index (integer) of the sub-shape
65 static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87");
66 // geometrical naming indicator
67 static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
69 // string identifier of the weak name in modification or intersection types of algorithm
70 static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_";
71 // string identifier of the pure weak name algorithm
72 static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_";
75 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
78 myAlwaysGeometricalNaming = false;
81 TDF_Label Selector_Selector::label()
86 void Selector_Selector::setBaseDocument(const TDF_Label theAccess)
88 myBaseDocumentLab = theAccess;
91 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
92 static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal,
93 const TopoDS_Shape& theValue,
94 bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
96 bool aFoundAnyShape = false;
97 TNaming_SameShapeIterator aLabIter(theValue, theAccess);
98 for(; aLabIter.More(); aLabIter.Next()) {
99 Handle(TNaming_NamedShape) aNS;
100 if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
101 if (aMustBeAtFinal && aNS != theFinal)
102 continue; // looking for old at the same final label only
103 TNaming_Evolution anEvolution = aNS->Evolution();
104 if (anEvolution == TNaming_PRIMITIVE) {
105 // check that this is not in the results already
106 const TDF_Label aResult = aNS->Label();
107 TDF_LabelList::Iterator aResIter(theResult);
108 for(; aResIter.More(); aResIter.Next()) {
109 if (aResIter.Value().IsEqual(aResult))
112 if (!aResIter.More()) // not found, so add this new
113 theResult.Append(aResult);
114 aFoundAnyShape = true;
116 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
117 for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
118 if (aThisIter.NewShape().IsSame(theValue)) {
119 // continue recursively, null NS means that any NS are ok
120 findBases(theAccess, theFinal, aThisIter.OldShape(),
121 false, theAdditionalDocument, theResult);
122 aFoundAnyShape = true;
128 if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document
129 static TDF_Label anEmpty;
130 if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue))
131 findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue,
132 false, anEmpty, theResult);
136 // returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection)
137 static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType,
138 TopoDS_ListOfShape& theResults)
140 TopoDS_ListOfShape::iterator aSubSel = theShapes.begin();
141 for(; aSubSel != theShapes.end(); aSubSel++) {
142 TopTools_MapOfShape aCurrentMap;
143 for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) {
144 if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin())
145 theResults.Append(anExp.Current());
147 if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap
148 for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) {
149 if (aCurrentMap.Contains(aComIter.Value()))
152 theResults.Remove(aComIter);
158 /// Searches neighbor of theLevel of neighborhood to theValue in theContex
159 static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
160 const int theLevel, TopTools_MapOfShape& theResult)
162 TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes
163 if (theValue.ShapeType() == TopAbs_FACE)
164 aConnectorType = TopAbs_EDGE;
165 TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors
166 for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) {
167 aNBConnectors.Add(aValExp.Current());
170 TopTools_MapOfShape alreadyProcessed;
171 alreadyProcessed.Add(theValue);
173 for(int aLevel = 1; aLevel <= theLevel; aLevel++) {
174 TopoDS_ListOfShape aGoodCandidates;
175 TopExp_Explorer aCandidate(theContext, theValue.ShapeType());
176 for(; aCandidate.More(); aCandidate.Next()) {
177 if (alreadyProcessed.Contains(aCandidate.Current()))
179 TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType);
180 for(; aCandConnector.More(); aCandConnector.Next()) {
181 if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor
184 if (aCandConnector.More()) {
185 if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors
186 theResult.Add(aCandidate.Current());
187 } else { // add to the NB of the current level
188 aGoodCandidates.Append(aCandidate.Current());
192 if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors
193 for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) {
194 TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType);
195 for(; aGoodConnector.More(); aGoodConnector.Next()) {
196 aNBConnectors.Add(aGoodConnector.Current());
198 alreadyProcessed.Add(aGood.Value());
204 /// Returns true if the given shapes are based on the same geometry
205 static bool sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) {
206 if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType())
208 if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces
209 TopLoc_Location aLoc1, aLoc2;
210 TopoDS_Face aFace1 = TopoDS::Face(theShape1);
211 Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1);
212 TopoDS_Face aFace2 = TopoDS::Face(theShape2);
213 Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2);
214 return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2);
215 } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves
216 TopLoc_Location aLoc1, aLoc2;
217 Standard_Real aFirst, aLast;
218 TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1);
219 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast);
220 TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2);
221 Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast);
222 return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2);
228 /// Searches the neighbor shape by neighbors defined in theNB in theContext shape
229 static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext,
230 const std::list<std::pair<TopoDS_Shape, int> >& theNB, const bool theGeometrical)
232 // searching for neighbors with minimum level
234 std::list<std::pair<TopoDS_Shape, int> >::const_iterator aNBIter = theNB.cbegin();
235 for(; aNBIter != theNB.cend(); aNBIter++) {
236 if (aMinLevel == 0 || aNBIter->second < aMinLevel) {
237 aMinLevel = aNBIter->second;
240 // collect all neighbors which are neighbors of sub-shapes with minimum level
242 TopoDS_ListOfShape aMatches;
243 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
244 if (aNBIter->second == aMinLevel) {
245 TopTools_MapOfShape aThisNBs;
246 findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs);
247 // aMatches must contain common part of all NBs lists
248 for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) {
250 aMatches.Append(aThisNB.Value());
252 // remove all in aMatches which are not in this NBs
253 for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) {
254 if (aThisNBs.Contains(aMatch.Value())) {
257 aMatches.Remove(aMatch);
265 if (aMatches.IsEmpty())
266 return TopoDS_Shape(); // not found any candidate
267 if (aMatches.Extent() == 1)
268 return aMatches.First(); // already found good candidate
269 TopoDS_Compound aResultCompound; // in case of geometrical name and many candidates
270 // iterate all matches to find by other (higher level) neighbors the best candidate
271 TopoDS_Shape aGoodCandidate;
272 TopTools_MapOfShape aGoodCandidates; // already added good candidates to the map
273 for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) {
274 bool aValidCadidate = true;
275 for(int aLevel = aMinLevel + 1; true; aLevel++) {
276 bool aFooundHigherLevel = false;
277 TopoDS_ListOfShape aLevelNBs;
278 for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) {
279 if (aNBIter->second == aLevel)
280 aLevelNBs.Append(aNBIter->first);
281 else if (aNBIter->second >= aLevel)
282 aFooundHigherLevel = true;
284 if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate
285 if (aGoodCandidate.IsNull()) {
286 aGoodCandidate = aCandidate.Value();
287 } else { // another good candidate
288 if (theGeometrical && sameGeometry(aGoodCandidate, aCandidate.Value())) {
289 if (!aGoodCandidates.Add(aCandidate.Value()))
291 static TopoDS_Builder aBuilder;
292 if (aResultCompound.IsNull()) {
293 aBuilder.MakeCompound(aResultCompound);
294 aBuilder.Add(aResultCompound, aGoodCandidate);
296 aBuilder.Add(aResultCompound, aCandidate.Value());
298 return TopoDS_Shape();
301 if (!aLevelNBs.IsEmpty()) {
302 TopTools_MapOfShape aNBsOfCandidate;
303 findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate);
304 // check all stored neighbors are in the map of real neighbors
305 for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) {
306 if (!aNBsOfCandidate.Contains(aLevIter.Value())) {
307 aValidCadidate = false;
312 if (!aValidCadidate) // candidate is not valid, break the checking
316 if (!aResultCompound.IsNull())
317 return aResultCompound;
318 return aGoodCandidate;
321 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
322 const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections)
324 if (theValue.IsNull() || theContext.IsNull())
326 myGeometricalNaming = theGeometricalNaming;
327 // check the value shape can be named as it is, or it is needed to construct it from the
328 // higher level shapes (like a box vertex by faces that form this vertex)
329 bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue);
330 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
332 for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
334 Handle(TNaming_NamedShape) aNS;
335 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
336 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
337 aNS->Evolution() == TNaming_PRIMITIVE) {
344 // searching in the base document
345 if (!aIsFound && !myBaseDocumentLab.IsNull() &&
346 TNaming_Tool::HasLabel(myBaseDocumentLab, theValue))
348 TNaming_SameShapeIterator aShapes(theValue, myBaseDocumentLab);
349 for(; aShapes.More(); aShapes.Next())
351 Handle(TNaming_NamedShape) aNS;
352 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
353 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
354 aNS->Evolution() == TNaming_PRIMITIVE) {
362 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
363 myShapeType = aSelectionType;
364 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
365 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
366 { // iterate all sub-shapes and select them on sublabels
367 for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
368 if (!selectBySubSelector(theContext, aSubIter.Value(),
369 false, theUseNeighbors, theUseIntersections)) {//for subs no geometrical naming allowed
370 return false; // if some selector is failed, everything is failed
373 myType = SELTYPE_CONTAINER;
377 // try to find the shape of the higher level type in the context shape
378 bool aFacesTried = false; // for identification of vertices, faces are tried, then edges
379 TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak
380 TopoDS_ListOfShape aLastIntersectors;
381 while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) {
382 if (aSelectionType == TopAbs_FACE) {
383 if (theValue.ShapeType() != TopAbs_VERTEX)
386 aSelectionType = TopAbs_EDGE;
388 aSelectionType = TopAbs_FACE;
389 TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
390 TopoDS_ListOfShape anIntList; // same as anIntersectors
391 for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
392 if (aSelectionType == TopAbs_EDGE &&
393 BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current())))
395 TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
396 for(; aSubExp.More(); aSubExp.Next()) {
397 if (aSubExp.Current().IsSame(theValue)) {
398 if (anIntersectors.Add(aSelExp.Current()))
399 anIntList.Append(aSelExp.Current());
404 // check that solution is only one
405 TopoDS_ListOfShape aCommon;
406 commonShapes(anIntList, theValue.ShapeType(), aCommon);
407 if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) {
408 // name the intersectors
409 mySubSelList.clear();
410 TopoDS_ListOfShape::Iterator anInt(anIntList);
411 for (; anInt.More(); anInt.Next()) {
412 if (!selectBySubSelector(theContext, anInt.Value(),
413 theGeometricalNaming, theUseNeighbors, false)) {
414 break; // if some selector is failed, stop and search another solution
417 if (!anInt.More()) { // all intersectors were correctly named
418 myType = SELTYPE_INTERSECT;
421 } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) {
422 aLastCommon = aCommon;
423 aLastIntersectors = anIntList;
427 if (!theUseNeighbors)
430 // searching by neighbors
431 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
432 for(int aLevel = 1; true; aLevel++) {
433 TopTools_MapOfShape aNewNB;
434 findNeighbors(theContext, theValue, aLevel, aNewNB);
435 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
438 // iterate by the order in theContext to keep same naming names
439 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
440 for (; anOrder.More(); anOrder.Next()) {
441 if (aNewNB.Contains(anOrder.Current())) {
442 TopoDS_Shape aNewNBShape = anOrder.Current();
443 // check which can be named correctly, without "by neighbors" type
444 Selector_Selector aSelector(myLab.FindChild(1));
445 aSelector.setBaseDocument(myBaseDocumentLab);
446 if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false, false)) {
447 // add to list of good NBs
448 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
452 TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming);
453 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
454 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
455 for(; aNBIter != aNBs.end(); aNBIter++) {
456 if (!selectBySubSelector(theContext, aNBIter->first,
457 theGeometricalNaming, false, false)) {
458 return false; // something is wrong because before this selection was ok
460 myNBLevel.push_back(aNBIter->second);
463 myType = SELTYPE_FILTER_BY_NEIGHBOR;
468 if (aLastCommon.Extent() > 1) {
469 if (myAlwaysGeometricalNaming) {
470 TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon);
471 TopoDS_Shape aFirst = aCommonIter.Value();
472 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
473 if (!sameGeometry(aFirst, aCommonIter.Value()))
476 if (!aCommonIter.More()) { // all geometry is same, result is a compound
477 myType = SELTYPE_INTERSECT;
481 // weak naming to distinguish commons coming from intersection
482 Selector_NExplode aNexp(aLastCommon);
483 myWeakIndex = aNexp.index(theValue);
484 if (myWeakIndex != -1) {
485 // name the intersectors
486 mySubSelList.clear();
487 TopoDS_ListOfShape::Iterator anInt(aLastIntersectors);
488 for (; anInt.More(); anInt.Next()) {
489 if (!selectBySubSelector(theContext, anInt.Value(),
490 theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
491 break; // if some selector is failed, stop and search another solution
494 if (!anInt.More()) { // all intersectors were correctly named
495 myType = SELTYPE_INTERSECT;
501 // pure weak naming: there is no sense to use pure weak naming for neighbors selection
502 if (theUseNeighbors) {
503 myType = SELTYPE_WEAK_NAMING;
504 Selector_NExplode aNexp(theContext, theValue.ShapeType());
505 myWeakIndex = aNexp.index(theValue);
506 if (myWeakIndex != -1) {
507 myShapeType = theValue.ShapeType();
508 // searching for context shape label to store in myFinal
510 if (TNaming_Tool::HasLabel(myLab, theContext)) {
511 for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next())
513 Handle(TNaming_NamedShape) aNS;
514 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
515 TNaming_Evolution anEvolution = aNS->Evolution();
516 if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED ||
517 anEvolution == TNaming_MODIFY) {
518 // check this is a new shape
519 for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) {
520 if (aNSIter.NewShape().IsSame(theContext)) {
521 myFinal = aNS->Label();
529 return true; // could be final empty (in case it is called recursively) or not
535 // searching for the base shapes of the value
536 Handle(TNaming_NamedShape) aPrimitiveNS;
537 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
538 for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
539 TDF_Label aLab = aUseExternal == 0 ? myLab : myBaseDocumentLab;
540 if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
542 for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
544 Handle(TNaming_NamedShape) aNS;
545 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
546 TNaming_Evolution anEvolution = aNS->Evolution();
547 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
550 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
551 // check this is a new shape
552 TNaming_Iterator aNSIter(aNS);
553 for(; aNSIter.More(); aNSIter.Next())
554 if (aNSIter.NewShape().IsSame(theValue))
556 if (aNSIter.More()) // new was found
557 aModifList.Append(aNS);
563 if (!aPrimitiveNS.IsNull()) {
564 myType = SELTYPE_PRIMITIVE;
565 myFinal = aPrimitiveNS->Label();
569 if (aModifList.Extent() > 1) { // searching for the best modification result: by context
570 Handle(TNaming_NamedShape) aCandidate;
571 NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
572 for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
573 aCandidate = aModIter.Value();
574 TDF_Label aFatherLab = aCandidate->Label().Father();
575 Handle(TNaming_NamedShape) aFatherNS;
576 if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
577 for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
578 if (theContext.IsSame(anIter.NewShape())) { // found the best modification
585 // take the best candidate, or the last in the iteration
587 aModifList.Append(aCandidate);
590 if (!aModifList.IsEmpty()) {
591 // searching for all the base shapes of this modification
592 findBases(myLab, aModifList.First(), theValue, true, myBaseDocumentLab, myBases);
593 if (!myBases.IsEmpty()) {
594 myFinal = aModifList.First()->Label();
595 TopoDS_ListOfShape aCommon;
596 findModificationResult(aCommon);
597 // trying to search by neighbors
598 if (aCommon.Extent() > 1) { // more complicated selection
599 if (myAlwaysGeometricalNaming) {
600 TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
601 TopoDS_Shape aFirst = aCommonIter.Value();
602 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
603 if (!sameGeometry(aFirst, aCommonIter.Value()))
606 if (!aCommonIter.More()) { // all geometry is same, result is a compound
607 myType = SELTYPE_MODIFICATION;
611 if (!theUseNeighbors)
614 // searching by neighbors
615 std::list<std::pair<TopoDS_Shape, int> > aNBs;//neighbor sub-shape -> level of neighborhood
616 for(int aLevel = 1; true; aLevel++) {
617 TopTools_MapOfShape aNewNB;
618 findNeighbors(theContext, theValue, aLevel, aNewNB);
619 if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration
622 // iterate by the order in theContext to keep same naming names
623 TopExp_Explorer anOrder(theContext, theValue.ShapeType());
624 for (; anOrder.More(); anOrder.Next()) {
625 if (aNewNB.Contains(anOrder.Current())) {
626 TopoDS_Shape aNewNBShape = anOrder.Current();
627 // check which can be named correctly, without "by neighbors" type
628 Selector_Selector aSelector(myLab.FindChild(1));
629 if (!myBaseDocumentLab.IsNull())
630 aSelector.setBaseDocument(myBaseDocumentLab);
631 if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false)) {
632 // add to list of good NBs
633 aNBs.push_back(std::pair<TopoDS_Shape, int>(aNewNBShape, aLevel));
637 TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming);
638 if (!aResult.IsNull() && aResult.IsSame(theValue)) {
639 std::list<std::pair<TopoDS_Shape, int> >::iterator aNBIter = aNBs.begin();
640 for(; aNBIter != aNBs.end(); aNBIter++) {
641 if (!selectBySubSelector(theContext, aNBIter->first,
642 theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
643 return false; // something is wrong because before this selection was ok
645 myNBLevel.push_back(aNBIter->second);
648 myType = SELTYPE_FILTER_BY_NEIGHBOR;
652 // filter by neighbors did not help
653 if (aCommon.Extent() > 1) {
654 if (myAlwaysGeometricalNaming) {
655 TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
656 TopoDS_Shape aFirst = aCommonIter.Value();
657 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
658 if (!sameGeometry(aFirst, aCommonIter.Value()))
661 if (!aCommonIter.More()) { // all geometry is same, result is a compound
662 myType = SELTYPE_FILTER_BY_NEIGHBOR;
666 // weak naming between the common results
667 Selector_NExplode aNexp(aCommon);
668 myWeakIndex = aNexp.index(theValue);
669 if (myWeakIndex == -1)
674 myType = SELTYPE_MODIFICATION;
675 if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound
676 TopoDS_ListOfShape aCommon;
677 myFinal = aModifList.First()->Label();
678 Handle(TNaming_NamedShape) aNS;
679 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
680 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
681 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
682 if (!aNewShape.IsNull())
683 aCommon.Append(aNewShape);
686 Selector_NExplode aNexp(aCommon);
687 myWeakIndex = aNexp.index(theValue);
688 if (myWeakIndex == -1)
694 // not found a good result
698 /// Stores the array of references to the label: references to elements of ref-list, then the last
699 static void storeBaseArray(const TDF_Label& theLab,
700 const TDF_LabelList& theRef, const TDF_Label& theLast)
702 Handle(TDataStd_ReferenceArray) anArray =
703 TDataStd_ReferenceArray::Set(theLab, kBASE_ARRAY, 0, theRef.Extent());
704 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
705 const TDF_Label aThisDocRoot = theLab.Root();
706 TDF_LabelList::Iterator aBIter(theRef);
707 for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
708 const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
709 // check this is a label of this document
710 if (aLab.Root().IsEqual(aThisDocRoot)) {
711 anArray->SetValue(anIndex, aLab);
712 } else { // store reference to external document as an entry-string
713 if (anEntries.IsNull()) {
714 anEntries = TDataStd_ExtStringList::Set(theLab, kBASE_LIST);
716 TCollection_AsciiString anEntry;
717 TDF_Tool::Entry(aLab, anEntry);
718 anEntries->Append(anEntry);
719 anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
726 void Selector_Selector::store()
728 static const TDF_LabelList anEmptyRefList;
729 myLab.ForgetAllAttributes(true); // remove old naming data
730 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
731 if (myGeometricalNaming)
732 TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING);
734 case SELTYPE_CONTAINER:
735 case SELTYPE_INTERSECT: {
736 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
737 // store also all sub-selectors
738 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
739 for(; aSubSel != mySubSelList.end(); aSubSel++) {
742 if (myWeakIndex != -1) {
743 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
747 case SELTYPE_PRIMITIVE: {
748 storeBaseArray(myLab, anEmptyRefList, myFinal);
751 case SELTYPE_MODIFICATION: {
752 storeBaseArray(myLab, myBases, myFinal);
753 if (myWeakIndex != -1) {
754 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
758 case SELTYPE_FILTER_BY_NEIGHBOR: {
759 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
760 // store numbers of levels corresponded to the neighbors in sub-selectors
761 Handle(TDataStd_IntegerArray) anArray =
762 TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1);
763 std::list<int>::iterator aLevel = myNBLevel.begin();
764 for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) {
765 anArray->SetValue(anIndex, *aLevel);
767 // store all sub-selectors
768 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
769 for(; aSubSel != mySubSelList.end(); aSubSel++) {
774 case SELTYPE_WEAK_NAMING: {
775 TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex);
776 TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
777 if (!myFinal.IsNull()) {
778 storeBaseArray(myLab, anEmptyRefList, myFinal);
782 default: { // unknown case
788 /// Restores references to the labels: references to elements of ref-list, then the last
789 static bool restoreBaseArray(const TDF_Label& theLab, const TDF_Label& theBaseDocumetnLab,
790 TDF_LabelList& theRef, TDF_Label& theLast)
792 const TDF_Label aThisDocRoot = theLab.Root();
793 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
794 TDataStd_ListOfExtendedString::Iterator anIter;
795 Handle(TDataStd_ReferenceArray) anArray;
796 if (theLab.FindAttribute(kBASE_ARRAY, anArray)) {
797 int anUpper = anArray->Upper();
798 for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
799 TDF_Label aLab = anArray->Value(anIndex);
800 if (aLab.IsEqual(aThisDocRoot)) { // external document reference
801 if (theBaseDocumetnLab.IsNull())
803 if (anEntries.IsNull()) {
804 if (!theLab.FindAttribute(kBASE_LIST, anEntries))
806 anIter.Initialize(anEntries->List());
810 TDF_Tool::Label(theBaseDocumetnLab.Data(), anIter.Value(), aLab);
813 if (anIndex == anUpper) {
825 bool Selector_Selector::restore()
827 Handle(TDataStd_Integer) aTypeAttr;
828 if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
830 myGeometricalNaming = myLab.IsAttribute(kGEOMETRICAL_NAMING);
831 myType = Selector_Type(aTypeAttr->Get());
833 case SELTYPE_CONTAINER:
834 case SELTYPE_INTERSECT: {
835 Handle(TDataStd_Integer) aShapeTypeAttr;
836 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
838 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
839 // restore sub-selectors
840 bool aSubResult = true;
841 mySubSelList.clear();
842 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
843 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
844 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
845 if (!mySubSelList.back().restore())
848 Handle(TDataStd_Integer) aWeakInt;
849 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
850 myWeakIndex = aWeakInt->Get();
854 case SELTYPE_PRIMITIVE: {
855 return restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal);
857 case SELTYPE_MODIFICATION: {
858 if (restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) {
859 Handle(TDataStd_Integer) aWeakInt;
860 if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) {
861 myWeakIndex = aWeakInt->Get();
867 case SELTYPE_FILTER_BY_NEIGHBOR: {
868 Handle(TDataStd_Integer) aShapeTypeAttr;
869 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
871 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
872 // restore sub-selectors
873 bool aSubResult = true;
874 mySubSelList.clear();
875 for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
876 mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
877 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
878 if (!mySubSelList.back().restore())
881 // restore levels indices
882 Handle(TDataStd_IntegerArray) anArray;
883 if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray))
885 for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) {
886 myNBLevel.push_back(anArray->Value(anIndex));
890 case SELTYPE_WEAK_NAMING: {
891 Handle(TDataStd_Integer) aWeakInt;
892 if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt))
894 myWeakIndex = aWeakInt->Get();
895 Handle(TDataStd_Integer) aShapeTypeAttr;
896 if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
898 myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
899 if (!restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal))
903 default: { // unknown case
909 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
910 static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
911 const TDF_Label& theFinal,
912 const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults)
914 if (TNaming_Tool::HasLabel(anAccess, theBase)) {
915 for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
917 TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
918 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
919 if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
920 theResults.Add(aBaseIter.Shape());
922 findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults);
927 if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
928 static TDF_Label anEmpty;
929 findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults);
933 void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) {
934 for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
935 TDF_Label anAdditionalDoc; // this document if base is started in extra document
936 if (aBase.Value().Root() != myLab.Root()) {
937 anAdditionalDoc = myLab;
939 TopTools_MapOfShape aFinals;
940 for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
941 findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals);
943 if (!aFinals.IsEmpty()) {
944 if (theCommon.IsEmpty()) { // just copy all to common
945 for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
946 theCommon.Append(aFinal.Key());
948 } else { // keep only shapes presented in both lists
949 for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
950 if (aFinals.Contains(aCommon.Value())) {
952 } else { // common is not found, remove it
953 theCommon.Remove(aCommon);
961 bool Selector_Selector::solve(const TopoDS_Shape& theContext)
963 TopoDS_Shape aResult; // null if invalid
965 case SELTYPE_CONTAINER: {
966 TopoDS_Builder aBuilder;
967 switch(myShapeType) {
968 case TopAbs_COMPOUND: {
969 TopoDS_Compound aComp;
970 aBuilder.MakeCompound(aComp);
974 case TopAbs_COMPSOLID: {
975 TopoDS_CompSolid aComp;
976 aBuilder.MakeCompSolid(aComp);
982 aBuilder.MakeShell(aShell);
988 aBuilder.MakeWire(aWire);
993 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
994 for(; aSubSel != mySubSelList.end(); aSubSel++) {
995 if (!aSubSel->solve(theContext)) {
998 aBuilder.Add(aResult, aSubSel->value());
1002 case SELTYPE_INTERSECT: {
1003 TopoDS_ListOfShape aSubSelectorShapes;
1004 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1005 for(; aSubSel != mySubSelList.end(); aSubSel++) {
1006 if (!aSubSel->solve(theContext)) {
1009 aSubSelectorShapes.Append(aSubSel->value());
1011 TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
1012 commonShapes(aSubSelectorShapes, myShapeType, aCommon);
1013 if (aCommon.Extent() != 1) {
1014 if (myWeakIndex != -1) {
1015 Selector_NExplode aNexp(aCommon);
1016 aResult = aNexp.shape(myWeakIndex);
1017 } else if (myGeometricalNaming && aCommon.Extent() > 1) {
1018 // check results are on the same geometry, create compound
1019 TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
1020 TopoDS_Shape aFirst = aCommonIter.Value();
1021 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
1022 if (!sameGeometry(aFirst, aCommonIter.Value()))
1025 if (!aCommonIter.More()) { // all geometry is same, create a result compound
1026 TopoDS_Builder aBuilder;
1027 TopoDS_Compound aCompound;
1028 aBuilder.MakeCompound(aCompound);
1029 for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) {
1030 aBuilder.Add(aCompound, aCommonIter.Value());
1032 aResult = aCompound;
1038 aResult = aCommon.First();
1042 case SELTYPE_PRIMITIVE: {
1043 Handle(TNaming_NamedShape) aNS;
1044 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
1045 aResult = aNS->Get();
1049 case SELTYPE_MODIFICATION: {
1050 if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index
1051 TopoDS_ListOfShape aCommon;
1052 Handle(TNaming_NamedShape) aNS;
1053 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
1054 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
1055 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
1056 if (!aNewShape.IsNull())
1057 aCommon.Append(aNewShape);
1060 Selector_NExplode aNexp(aCommon);
1061 aResult = aNexp.shape(myWeakIndex);
1062 } else { // standard case
1063 TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
1064 findModificationResult(aFinalsCommon);
1065 if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape
1066 aResult = aFinalsCommon.First();
1067 } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) {
1068 Selector_NExplode aNExp(aFinalsCommon);
1069 aResult = aNExp.shape(myWeakIndex);
1070 } else if (aFinalsCommon.Extent() > 1 && myGeometricalNaming) {// if same geometry - compound
1071 TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon);
1072 TopoDS_Shape aFirst = aCommonIter.Value();
1073 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
1074 if (!sameGeometry(aFirst, aCommonIter.Value()))
1077 if (!aCommonIter.More()) { // all geometry is same, create a result compound
1078 TopoDS_Builder aBuilder;
1079 TopoDS_Compound aCompound;
1080 aBuilder.MakeCompound(aCompound);
1081 for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) {
1082 aBuilder.Add(aCompound, aCommonIter.Value());
1084 aResult = aCompound;
1091 case SELTYPE_FILTER_BY_NEIGHBOR: {
1092 std::list<std::pair<TopoDS_Shape, int> > aNBs; /// neighbor sub-shape -> level of neighborhood
1093 std::list<int>::iterator aLevel = myNBLevel.begin();
1094 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1095 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
1096 if (!aSubSel->solve(theContext)) {
1099 aNBs.push_back(std::pair<TopoDS_Shape, int>(aSubSel->value(), *aLevel));
1101 aResult = findNeighbor(theContext, aNBs, myGeometricalNaming);
1104 case SELTYPE_WEAK_NAMING: {
1105 TopoDS_Shape aContext;
1106 if (myFinal.IsNull()) {
1107 aContext = theContext;
1109 Handle(TNaming_NamedShape) aNS;
1110 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
1111 aContext = aNS->Get();
1114 if (!aContext.IsNull()) {
1115 Selector_NExplode aNexp(aContext, myShapeType);
1116 aResult = aNexp.shape(myWeakIndex);
1119 default: { // unknown case
1123 TNaming_Builder aBuilder(myLab);
1124 if (!aResult.IsNull()) {
1125 aBuilder.Select(aResult, aResult);
1128 return false; // builder just erases the named shape in case of error
1131 TopoDS_Shape Selector_Selector::value()
1133 Handle(TNaming_NamedShape) aNS;
1134 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
1136 return TopoDS_Shape(); // empty, error shape
1139 std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) {
1141 case SELTYPE_CONTAINER:
1142 case SELTYPE_INTERSECT: {
1143 std::string aResult;
1144 // add names of sub-components one by one in "[]" +optionally [weak_name_1]
1145 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1146 for(; aSubSel != mySubSelList.end(); aSubSel++) {
1148 aResult += aSubSel->name(theNameGenerator);
1150 TopoDS_Shape aSubVal = aSubSel->value();
1151 if (!aSubVal.IsNull()) {
1152 TopAbs_ShapeEnum aSubType = aSubVal.ShapeType();
1153 if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored
1155 case TopAbs_COMPOUND: aResult += "c"; break;
1156 case TopAbs_COMPSOLID: aResult += "o"; break;
1157 case TopAbs_SOLID: aResult += "s"; break;
1158 case TopAbs_SHELL: aResult += "h"; break;
1159 case TopAbs_WIRE: aResult += "w"; break;
1160 case TopAbs_EDGE: aResult += "e"; break;
1161 case TopAbs_VERTEX: aResult += "v"; break;
1168 if (myWeakIndex != -1) {
1169 std::ostringstream aWeakStr;
1170 aWeakStr<<"["<<kWEAK_NAME_IDENTIFIER<<myWeakIndex<<"]";
1171 aResult += aWeakStr.str();
1175 case SELTYPE_PRIMITIVE: {
1176 Handle(TDataStd_Name) aName;
1177 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
1179 return theNameGenerator->contextName(myFinal) + "/" +
1180 std::string(TCollection_AsciiString(aName->Get()).ToCString());
1182 case SELTYPE_MODIFICATION: {
1183 // final&base1&base2 +optionally: [weak_name_1]
1184 std::string aResult;
1185 Handle(TDataStd_Name) aName;
1186 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
1188 aResult += theNameGenerator->contextName(myFinal) + "/" +
1189 std::string(TCollection_AsciiString(aName->Get()).ToCString());
1190 for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
1191 if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
1194 aResult += theNameGenerator->contextName(*aBase) + "/" +
1195 std::string(TCollection_AsciiString(aName->Get()).ToCString());
1197 if (myWeakIndex != -1) {
1198 std::ostringstream aWeakStr;
1199 aWeakStr<<"&"<<kWEAK_NAME_IDENTIFIER<<myWeakIndex;
1200 aResult += aWeakStr.str();
1204 case SELTYPE_FILTER_BY_NEIGHBOR: {
1205 // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1
1206 std::string aResult;
1207 std::list<int>::iterator aLevel = myNBLevel.begin();
1208 std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
1209 for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) {
1210 aResult += "(" + aSubSel->name(theNameGenerator) + ")";
1212 std::ostringstream aLevelStr;
1214 aResult += aLevelStr.str();
1219 case SELTYPE_WEAK_NAMING: {
1220 // _weak_naming_1_Context
1221 std::ostringstream aWeakStr;
1222 aWeakStr<<kPUREWEAK_NAME_IDENTIFIER<<myWeakIndex;
1223 std::string aResult = aWeakStr.str();
1224 if (!myFinal.IsNull())
1225 aResult += "_" + theNameGenerator->contextName(myFinal);
1228 default: { // unknown case
1234 TDF_Label Selector_Selector::restoreByName(
1235 std::string theName, const TopAbs_ShapeEnum theShapeType,
1236 Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming)
1238 myGeometricalNaming = theGeometricalNaming;
1239 if (theName[0] == '[') { // intersection or container
1240 switch(theShapeType) {
1241 case TopAbs_COMPOUND:
1242 case TopAbs_COMPSOLID:
1245 myType = SELTYPE_CONTAINER;
1250 myType = SELTYPE_INTERSECT;
1253 return TDF_Label(); // unknown case
1255 myShapeType = theShapeType;
1257 for(size_t aStart = 0; aStart != std::string::npos;
1258 aStart = theName.find('[', aStart + 1)) {
1259 size_t anEndPos = theName.find(']', aStart + 1);
1260 if (anEndPos != std::string::npos) {
1261 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1262 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1263 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1264 myWeakIndex = atoi(aWeakIndex.c_str());
1267 TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE;
1268 if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) {
1269 char aShapeChar = theName[anEndPos + 1];
1270 if (theName[anEndPos + 1] != '[') {
1271 switch(aShapeChar) {
1272 case 'c': aSubShapeType = TopAbs_COMPOUND; break;
1273 case 'o': aSubShapeType = TopAbs_COMPSOLID; break;
1274 case 's': aSubShapeType = TopAbs_SOLID; break;
1275 case 'h': aSubShapeType = TopAbs_SHELL; break;
1276 case 'w': aSubShapeType = TopAbs_WIRE; break;
1277 case 'e': aSubShapeType = TopAbs_EDGE; break;
1278 case 'v': aSubShapeType = TopAbs_VERTEX; break;
1283 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1284 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1285 TDF_Label aSubContext = mySubSelList.back().restoreByName(
1286 aSubStr, aSubShapeType, theNameGenerator, theGeometricalNaming);
1287 if (aSubContext.IsNull())
1288 return aSubContext; // invalid sub-selection parsing
1289 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1290 if (!theNameGenerator->isLater(aContext, aSubContext))
1291 aContext = aSubContext;
1293 aContext = aSubContext;
1296 return TDF_Label(); // invalid parentheses
1299 } else if (theName[0] == '(') { // filter by neighbors
1300 myType = SELTYPE_FILTER_BY_NEIGHBOR;
1302 for(size_t aStart = 0; aStart != std::string::npos;
1303 aStart = theName.find('(', aStart + 1)) {
1304 size_t anEndPos = theName.find(')', aStart + 1);
1305 if (anEndPos != std::string::npos) {
1306 std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1);
1307 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1308 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1309 TDF_Label aSubContext = mySubSelList.back().restoreByName(
1310 aSubStr, theShapeType, theNameGenerator, theGeometricalNaming);
1311 if (aSubContext.IsNull())
1312 return aSubContext; // invalid sub-selection parsing
1313 if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) {
1314 if (!theNameGenerator->isLater(aContext, aSubContext))
1315 aContext = aSubContext;
1317 aContext = aSubContext;
1319 if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital
1320 aContext = theNameGenerator->newestContext(aContext);
1322 // searching for the level index
1324 for(anEndPos++; anEndPos != std::string::npos &&
1325 theName[anEndPos] != '(' && theName[anEndPos] != 0;
1327 aLevel += theName[anEndPos];
1330 myNBLevel.push_back(1); // by default it is 1
1332 int aNum = atoi(aLevel.c_str());
1334 myNBLevel.push_back(aNum);
1336 return TDF_Label(); // invalid number
1339 return TDF_Label(); // invalid parentheses
1342 } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier
1343 myType = SELTYPE_WEAK_NAMING;
1344 std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size());
1345 std::size_t aContextPosition = aWeakIndex.find("_");
1346 myWeakIndex = atoi(aWeakIndex.c_str());
1347 myShapeType = theShapeType;
1349 if (aContextPosition != std::string::npos) { // context is also defined
1350 std::string aContextName = aWeakIndex.substr(aContextPosition + 1);
1351 theNameGenerator->restoreContext(aContextName, aContext, myFinal);
1354 } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive
1355 myType = SELTYPE_PRIMITIVE;
1357 if (theNameGenerator->restoreContext(theName, aContext, myFinal)) {
1358 if (!myFinal.IsNull())
1361 } else { // modification
1362 myType = SELTYPE_MODIFICATION;
1364 for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
1367 anEnd = theName.find('&', aStart);
1368 std::string aSubStr =
1369 theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
1370 if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier
1371 std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size());
1372 myWeakIndex = atoi(aWeakIndex.c_str());
1375 TDF_Label aSubContext, aValue;
1376 if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
1377 return TDF_Label(); // can not restore
1378 if(aSubContext.IsNull() || aValue.IsNull())
1379 return TDF_Label(); // can not restore
1380 if (myFinal.IsNull()) {
1382 aContext = aSubContext;
1384 myBases.Append(aValue);
1391 bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext,
1392 const TopoDS_Shape theValue, const bool theGeometricalNaming,
1393 const bool theUseNeighbors, const bool theUseIntersections)
1395 mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
1396 if (!myBaseDocumentLab.IsNull())
1397 mySubSelList.back().setBaseDocument(myBaseDocumentLab);
1398 if (!mySubSelList.back().select(theContext, theValue,
1399 theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
1400 mySubSelList.clear(); // if one of the selector is failed, all become invalid
1406 void Selector_Selector::combineGeometrical(const TopoDS_Shape theContext)
1408 TopoDS_Shape aValue = value();
1409 if (aValue.IsNull() || aValue.ShapeType() == TopAbs_COMPOUND)
1411 myAlwaysGeometricalNaming = true;
1412 mySubSelList.clear();
1415 if (select(theContext, aValue, true)) {
1420 // if can not select, select the compound in a custom way
1421 TopTools_MapOfShape aMap;
1422 TopoDS_ListOfShape aList;
1423 for(TopExp_Explorer anExp(theContext, aValue.ShapeType()); anExp.More(); anExp.Next()) {
1424 if (aMap.Add(anExp.Current())) {
1425 if (sameGeometry(aValue, anExp.Current()))
1426 aList.Append(anExp.Current());
1429 if (aList.Size() > 1) {
1430 TopoDS_Builder aBuilder;
1431 TopoDS_Compound aCompound;
1432 aBuilder.MakeCompound(aCompound);
1433 for(TopoDS_ListIteratorOfListOfShape aListIter(aList); aListIter.More(); aListIter.Next()) {
1434 aBuilder.Add(aCompound, aListIter.Value());
1436 if (select(theContext, aCompound, true)) {