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_Algo.h>
23 #include <Selector_Primitive.h>
24 #include <Selector_Intersect.h>
25 #include <Selector_Modify.h>
26 #include <Selector_Container.h>
27 #include <Selector_FilterByNeighbors.h>
28 #include <Selector_WeakName.h>
30 #include <TDF_Tool.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <TopoDS_Edge.hxx>
34 #include <TopTools_MapOfShape.hxx>
35 #include <Geom_Surface.hxx>
36 #include <BRep_Tool.hxx>
37 #include <TNaming_Builder.hxx>
38 #include <TNaming_Tool.hxx>
39 #include <TNaming_SameShapeIterator.hxx>
40 #include <TNaming_Iterator.hxx>
41 #include <TNaming_NewShapeIterator.hxx>
42 #include <TDataStd_ReferenceArray.hxx>
43 #include <TDataStd_ExtStringList.hxx>
44 #include <TDataStd_Integer.hxx>
45 #include <TDataStd_UAttribute.hxx>
46 #include <TopoDS_Iterator.hxx>
47 #include <TopExp_Explorer.hxx>
48 #include <BRep_Builder.hxx>
51 /// type of the selection, integer keeps the Selector_Type value
52 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
53 // geometrical naming indicator
54 static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
57 // reference attribute that contains the reference to labels where the "from" or "base" shapes
58 // of selection are located
59 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
60 // if the base array contains reference to the root label, this means that it refers to an
61 // external document and this list contains a tag in the document
62 static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a");
64 Selector_Algo::Selector_Algo()
66 myGeometricalNaming = false; // default values
67 myAlwaysGeometricalNaming = false;
70 #define SET_ALGO_FLAGS(algo) \
71 algo->myLab = theAccess; \
72 algo->myBaseDocumentLab = theBaseDocument; \
73 algo->myGeometricalNaming = theGeometricalNaming; \
74 algo->myUseNeighbors = theUseNeighbors; \
75 algo->myUseIntersections = theUseIntersections; \
76 algo->myAlwaysGeometricalNaming = theAlwaysGeometricalNaming;
78 Selector_Algo* Selector_Algo::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
79 const TDF_Label theAccess, const TDF_Label theBaseDocument,
80 const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections,
81 const bool theAlwaysGeometricalNaming)
83 Selector_Algo* aResult = NULL;
84 if (theValue.IsNull() || theContext.IsNull())
87 // check the value shape can be named as it is, or it is needed to construct it from the
88 // higher level shapes (like a box vertex by faces that form this vertex)
89 bool aIsFound = TNaming_Tool::HasLabel(theAccess, theValue);
90 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
92 for(TNaming_SameShapeIterator aShapes(theValue, theAccess); aShapes.More(); aShapes.Next())
94 Handle(TNaming_NamedShape) aNS;
95 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
96 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
97 aNS->Evolution() == TNaming_PRIMITIVE) {
104 // searching in the base document
105 if (!aIsFound && !theBaseDocument.IsNull() && TNaming_Tool::HasLabel(theBaseDocument, theValue))
107 TNaming_SameShapeIterator aShapes(theValue, theBaseDocument);
108 for(; aShapes.More(); aShapes.Next())
110 Handle(TNaming_NamedShape) aNS;
111 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
112 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
113 aNS->Evolution() == TNaming_PRIMITIVE) {
121 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
122 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
123 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
125 Selector_Container* aContainer = new Selector_Container;
126 SET_ALGO_FLAGS(aContainer);
127 if (aContainer->select(theContext, theValue))
133 Selector_Intersect* anIntersect = new Selector_Intersect;
134 SET_ALGO_FLAGS(anIntersect);
135 bool aGoodIntersector = anIntersect->select(theContext, theValue);
136 // weak intersector is bad for not use neighbors and has lower priority than neighbors
137 if (aGoodIntersector && anIntersect->myWeakIndex == -1) {
140 if (!theUseNeighbors) {
144 // searching by neighbors
145 Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
146 SET_ALGO_FLAGS(aNBs);
147 if (aNBs->select(theContext, theValue)) {
152 if (aGoodIntersector) { // if neighbors are bad, use intersector with weak index
157 // pure weak naming: there is no sense to use pure weak naming for neighbors selection
158 if (theUseNeighbors) {
159 Selector_WeakName* aWeak = new Selector_WeakName;
160 SET_ALGO_FLAGS(aWeak);
161 if (aWeak->select(theContext, theValue)) {
166 return NULL; // not found value in the tree, not found context shape in the tree also
168 // searching for the base shapes of the value
169 Handle(TNaming_NamedShape) aPrimitiveNS;
170 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
171 for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
172 TDF_Label aLab = aUseExternal == 0 ? theAccess : theBaseDocument;
173 if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
175 for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
177 Handle(TNaming_NamedShape) aNS;
178 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
179 TNaming_Evolution anEvolution = aNS->Evolution();
180 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
183 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
184 // check this is a new shape
185 TNaming_Iterator aNSIter(aNS);
186 for(; aNSIter.More(); aNSIter.Next())
187 if (aNSIter.NewShape().IsSame(theValue))
189 if (aNSIter.More()) // new was found
190 aModifList.Append(aNS);
196 if (!aPrimitiveNS.IsNull()) {
197 Selector_Primitive* aPrimitive = new Selector_Primitive;
198 SET_ALGO_FLAGS(aPrimitive);
199 aPrimitive->select(aPrimitiveNS->Label());
202 Selector_Modify* aModify = new Selector_Modify;
203 SET_ALGO_FLAGS(aModify);
204 bool aGoodModify = aModify->select(aModifList, theContext, theValue);
205 // weak intersector is bad for not use neighbors and has lower priority than neighbors
206 if (aGoodModify && aModify->myWeakIndex == -1) {
209 if (!theUseNeighbors) {
213 // searching by neighbors
214 Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
215 SET_ALGO_FLAGS(aNBs);
216 if (aNBs->select(theContext, theValue)) {
222 if (aGoodModify) { // if neighbors are bad, use modify algo with weak index
228 return NULL; // invalid case
231 Selector_Algo* Selector_Algo::relesectWithAllGeometry(
232 Selector_Algo* theOldAlgo, const TopoDS_Shape theContext)
234 return select(theContext, theOldAlgo->value(),
235 theOldAlgo->myLab, theOldAlgo->myBaseDocumentLab, true, true, true, true);
238 void Selector_Algo::storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast)
240 Handle(TDataStd_ReferenceArray) anArray =
241 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, theRef.Extent());
242 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
243 const TDF_Label aThisDocRoot = myLab.Root();
244 TDF_LabelList::Iterator aBIter(theRef);
245 for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
246 const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
247 // check this is a label of this document
248 if (aLab.Root().IsEqual(aThisDocRoot)) {
249 anArray->SetValue(anIndex, aLab);
250 } else { // store reference to external document as an entry-string
251 if (anEntries.IsNull()) {
252 anEntries = TDataStd_ExtStringList::Set(myLab, kBASE_LIST);
254 TCollection_AsciiString anEntry;
255 TDF_Tool::Entry(aLab, anEntry);
256 anEntries->Append(anEntry);
257 anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
264 bool Selector_Algo::restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast)
266 const TDF_Label aThisDocRoot = myLab.Root();
267 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
268 TDataStd_ListOfExtendedString::Iterator anIter;
269 Handle(TDataStd_ReferenceArray) anArray;
270 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
271 int anUpper = anArray->Upper();
272 for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
273 TDF_Label aLab = anArray->Value(anIndex);
274 if (aLab.IsEqual(aThisDocRoot)) { // external document reference
275 if (myBaseDocumentLab.IsNull())
277 if (anEntries.IsNull()) {
278 if (!myLab.FindAttribute(kBASE_LIST, anEntries))
280 anIter.Initialize(anEntries->List());
284 TDF_Tool::Label(myBaseDocumentLab.Data(), anIter.Value(), aLab);
287 if (anIndex == anUpper) {
298 void Selector_Algo::store(const TopoDS_Shape theShape)
300 TNaming_Builder aBuilder(myLab);
301 aBuilder.Select(theShape, theShape);
304 bool Selector_Algo::sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) {
305 if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType())
307 if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces
308 TopLoc_Location aLoc1, aLoc2;
309 TopoDS_Face aFace1 = TopoDS::Face(theShape1);
310 Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1);
311 TopoDS_Face aFace2 = TopoDS::Face(theShape2);
312 Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2);
313 return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2);
314 } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves
315 TopLoc_Location aLoc1, aLoc2;
316 Standard_Real aFirst, aLast;
317 TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1);
318 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast);
319 TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2);
320 Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast);
321 return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2);
327 TopoDS_Shape Selector_Algo::value()
329 Handle(TNaming_NamedShape) aNS;
330 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
332 return TopoDS_Shape(); // empty, error shape
335 Selector_Algo* Selector_Algo::restoreByLab(TDF_Label theLab, TDF_Label theBaseDocLab)
337 Handle(TDataStd_Integer) aTypeAttr;
338 if (!theLab.FindAttribute(kSEL_TYPE, aTypeAttr))
340 Selector_Type aType = Selector_Type(aTypeAttr->Get());
341 Selector_Algo* aResult = NULL;
343 case SELTYPE_CONTAINER: {
344 aResult = new Selector_Container;
347 case SELTYPE_INTERSECT: {
348 aResult = new Selector_Intersect;
351 case SELTYPE_MODIFICATION: {
352 aResult = new Selector_Modify;
355 case SELTYPE_PRIMITIVE: {
356 aResult = new Selector_Primitive;
359 case SELTYPE_FILTER_BY_NEIGHBOR: {
360 aResult = new Selector_FilterByNeighbors;
363 case SELTYPE_WEAK_NAMING: {
364 aResult = new Selector_WeakName;
367 default: { // unknown case
371 aResult->myLab = theLab;
372 aResult->myBaseDocumentLab = theBaseDocLab;
373 aResult->myGeometricalNaming = theLab.IsAttribute(kGEOMETRICAL_NAMING);
374 if (!aResult->restore()) {
382 Selector_Algo* Selector_Algo::restoreByName(TDF_Label theLab, TDF_Label theBaseDocLab,
383 std::string theName, const TopAbs_ShapeEnum theShapeType, const bool theGeomNaming,
384 Selector_NameGenerator* theNameGenerator, TDF_Label& theContextLab)
386 Selector_Algo* aResult = NULL;
387 if (theName[0] == '[') { // intersection or container
388 switch(theShapeType) {
389 case TopAbs_COMPOUND:
390 case TopAbs_COMPSOLID:
393 aResult = new Selector_Container;
398 aResult = new Selector_Intersect;
402 } else if (theName[0] == '(') { // filter by neighbors
403 aResult = new Selector_FilterByNeighbors;
404 } else if (theName.find(pureWeakNameID()) == 0) { // weak naming identifier
405 aResult = new Selector_WeakName;
406 } else if (theName.find('&') != std::string::npos) { // modification
407 aResult = new Selector_Modify;
408 } else { // primitive
409 aResult = new Selector_Primitive;
412 aResult->myLab = theLab;
413 aResult->myBaseDocumentLab = theBaseDocLab;
414 aResult->myGeometricalNaming = theGeomNaming;
415 theContextLab = aResult->restoreByName(theName, theShapeType, theNameGenerator);
416 if (theContextLab.IsNull()) {
424 void Selector_Algo::storeType(const Selector_Type theType)
426 myLab.ForgetAllAttributes(true);
427 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)(theType));
428 if (myGeometricalNaming)
429 TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING);
432 /// Returns true if theSub is in theContext shape
433 static bool isInContext(const TopoDS_Shape& theContext, const TopoDS_Shape& theSub) {
434 for(TopExp_Explorer anExp(theContext, theSub.ShapeType()); anExp.More(); anExp.Next()) {
435 if (anExp.Current().IsSame(theSub))
441 bool Selector_Algo::findNewVersion(const TopoDS_Shape& theContext, TopoDS_Shape& theResult) const
443 if (theResult.IsNull())
445 if (!TNaming_Tool::HasLabel(myLab, theResult)) {
446 if (theResult.ShapeType() == TopAbs_COMPOUND) { // do it for all elements of compound
447 BRep_Builder aBuilder;
448 TopoDS_Compound aResultingCompound;
449 aBuilder.MakeCompound(aResultingCompound);
450 bool aWasChanged = false;
451 for (TopoDS_Iterator anIter(theResult); anIter.More(); anIter.Next()) {
452 TopoDS_Shape aSub = anIter.Value();
453 if (findNewVersion(theContext, aSub))
455 aBuilder.Add(aResultingCompound, aSub);
458 theResult = aResultingCompound;
462 // check theResult is in theContext
463 if (isInContext(theContext, theResult))
465 // searching the next modifications of the result shape in document
466 TopTools_MapOfShape aResultShapes;
467 for(TNaming_NewShapeIterator aBaseIter(theResult, myLab); aBaseIter.More(); aBaseIter.Next())
469 TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
470 if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
471 TopoDS_Shape aNextModification = aBaseIter.Shape();
472 if (aNextModification.IsNull())
474 if (isInContext(theContext, aNextModification))
475 aResultShapes.Add(aNextModification);
476 else if (findNewVersion(theContext, aNextModification))
477 aResultShapes.Add(aNextModification);
480 if (aResultShapes.IsEmpty())
482 if (aResultShapes.Size() == 1) {
483 theResult = TopTools_MapIteratorOfMapOfShape(aResultShapes).Value();
484 } else { // make a compound of all results
485 BRep_Builder aBuilder;
486 TopoDS_Compound aResultingCompound;
487 aBuilder.MakeCompound(aResultingCompound);
488 for(TopTools_MapIteratorOfMapOfShape anIter(aResultShapes); anIter.More(); anIter.Next())
489 aBuilder.Add(aResultingCompound, anIter.Value());
490 theResult = aResultingCompound;