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 <Geom_Surface.hxx>
35 #include <BRep_Tool.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TNaming_Tool.hxx>
38 #include <TNaming_SameShapeIterator.hxx>
39 #include <TNaming_Iterator.hxx>
40 #include <TDataStd_ReferenceArray.hxx>
41 #include <TDataStd_ExtStringList.hxx>
42 #include <TDataStd_Integer.hxx>
44 /// type of the selection, integer keeps the Selector_Type value
45 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
46 // geometrical naming indicator
47 static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
50 // reference attribute that contains the reference to labels where the "from" or "base" shapes
51 // of selection are located
52 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
53 // if the base array contains reference to the root label, this means that it refers to an
54 // external document and this list contains a tag in the document
55 static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a");
57 Selector_Algo::Selector_Algo()
59 myGeometricalNaming = false; // default values
60 myAlwaysGeometricalNaming = false;
63 #define SET_ALGO_FLAGS(algo) \
64 algo->myLab = theAccess; \
65 algo->myBaseDocumentLab = theBaseDocument; \
66 algo->myGeometricalNaming = theGeometricalNaming; \
67 algo->myUseNeighbors = theUseNeighbors; \
68 algo->myUseIntersections = theUseIntersections; \
69 algo->myAlwaysGeometricalNaming = theAlwaysGeometricalNaming;
71 Selector_Algo* Selector_Algo::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
72 const TDF_Label theAccess, const TDF_Label theBaseDocument,
73 const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections,
74 const bool theAlwaysGeometricalNaming)
76 Selector_Algo* aResult = NULL;
77 if (theValue.IsNull() || theContext.IsNull())
80 // check the value shape can be named as it is, or it is needed to construct it from the
81 // higher level shapes (like a box vertex by faces that form this vertex)
82 bool aIsFound = TNaming_Tool::HasLabel(theAccess, theValue);
83 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
85 for(TNaming_SameShapeIterator aShapes(theValue, theAccess); aShapes.More(); aShapes.Next())
87 Handle(TNaming_NamedShape) aNS;
88 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
89 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
90 aNS->Evolution() == TNaming_PRIMITIVE) {
97 // searching in the base document
98 if (!aIsFound && !theBaseDocument.IsNull() && TNaming_Tool::HasLabel(theBaseDocument, theValue))
100 TNaming_SameShapeIterator aShapes(theValue, theBaseDocument);
101 for(; aShapes.More(); aShapes.Next())
103 Handle(TNaming_NamedShape) aNS;
104 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
105 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
106 aNS->Evolution() == TNaming_PRIMITIVE) {
114 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
115 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
116 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
118 Selector_Container* aContainer = new Selector_Container;
119 SET_ALGO_FLAGS(aContainer);
120 if (aContainer->select(theContext, theValue))
125 Selector_Intersect* anIntersect = new Selector_Intersect;
126 SET_ALGO_FLAGS(anIntersect);
127 bool aGoodIntersector = anIntersect->select(theContext, theValue);
128 // weak intersector is bad for not use neighbors and has lower priority than neighbors
129 if (aGoodIntersector && anIntersect->myWeakIndex == -1) {
132 if (!theUseNeighbors) {
136 // searching by neighbors
137 Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
138 SET_ALGO_FLAGS(aNBs);
139 if (aNBs->select(theContext, theValue)) {
144 if (aGoodIntersector) { // if neighbors are bad, use intersector with weak index
149 // pure weak naming: there is no sense to use pure weak naming for neighbors selection
150 if (theUseNeighbors) {
151 Selector_WeakName* aWeak = new Selector_WeakName;
152 SET_ALGO_FLAGS(aWeak);
153 if (aWeak->select(theContext, theValue)) {
158 return NULL; // not found value in the tree, not found context shape in the tree also
160 // searching for the base shapes of the value
161 Handle(TNaming_NamedShape) aPrimitiveNS;
162 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
163 for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
164 TDF_Label aLab = aUseExternal == 0 ? theAccess : theBaseDocument;
165 if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
167 for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
169 Handle(TNaming_NamedShape) aNS;
170 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
171 TNaming_Evolution anEvolution = aNS->Evolution();
172 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
175 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
176 // check this is a new shape
177 TNaming_Iterator aNSIter(aNS);
178 for(; aNSIter.More(); aNSIter.Next())
179 if (aNSIter.NewShape().IsSame(theValue))
181 if (aNSIter.More()) // new was found
182 aModifList.Append(aNS);
188 if (!aPrimitiveNS.IsNull()) {
189 Selector_Primitive* aPrimitive = new Selector_Primitive;
190 SET_ALGO_FLAGS(aPrimitive);
191 aPrimitive->select(aPrimitiveNS->Label());
194 Selector_Modify* aModify = new Selector_Modify;
195 SET_ALGO_FLAGS(aModify);
196 bool aGoodModify = aModify->select(aModifList, theContext, theValue);
197 // weak intersector is bad for not use neighbors and has lower priority than neighbors
198 if (aGoodModify && aModify->myWeakIndex == -1) {
201 if (!theUseNeighbors) {
205 // searching by neighbors
206 Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
207 SET_ALGO_FLAGS(aNBs);
208 if (aNBs->select(theContext, theValue)) {
214 if (aGoodModify) { // if neighbors are bad, use modify algo with weak index
220 return NULL; // invalid case
223 Selector_Algo* Selector_Algo::relesectWithAllGeometry(
224 Selector_Algo* theOldAlgo, const TopoDS_Shape theContext)
226 return select(theContext, theOldAlgo->value(),
227 theOldAlgo->myLab, theOldAlgo->myBaseDocumentLab, true, true, true, true);
230 void Selector_Algo::storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast)
232 Handle(TDataStd_ReferenceArray) anArray =
233 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, theRef.Extent());
234 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
235 const TDF_Label aThisDocRoot = myLab.Root();
236 TDF_LabelList::Iterator aBIter(theRef);
237 for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
238 const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
239 // check this is a label of this document
240 if (aLab.Root().IsEqual(aThisDocRoot)) {
241 anArray->SetValue(anIndex, aLab);
242 } else { // store reference to external document as an entry-string
243 if (anEntries.IsNull()) {
244 anEntries = TDataStd_ExtStringList::Set(myLab, kBASE_LIST);
246 TCollection_AsciiString anEntry;
247 TDF_Tool::Entry(aLab, anEntry);
248 anEntries->Append(anEntry);
249 anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
256 bool Selector_Algo::restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast)
258 const TDF_Label aThisDocRoot = myLab.Root();
259 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
260 TDataStd_ListOfExtendedString::Iterator anIter;
261 Handle(TDataStd_ReferenceArray) anArray;
262 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
263 int anUpper = anArray->Upper();
264 for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
265 TDF_Label aLab = anArray->Value(anIndex);
266 if (aLab.IsEqual(aThisDocRoot)) { // external document reference
267 if (myBaseDocumentLab.IsNull())
269 if (anEntries.IsNull()) {
270 if (!myLab.FindAttribute(kBASE_LIST, anEntries))
272 anIter.Initialize(anEntries->List());
276 TDF_Tool::Label(myBaseDocumentLab.Data(), anIter.Value(), aLab);
279 if (anIndex == anUpper) {
290 void Selector_Algo::store(const TopoDS_Shape theShape)
292 TNaming_Builder aBuilder(myLab);
293 aBuilder.Select(theShape, theShape);
296 bool Selector_Algo::sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) {
297 if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType())
299 if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces
300 TopLoc_Location aLoc1, aLoc2;
301 TopoDS_Face aFace1 = TopoDS::Face(theShape1);
302 Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1);
303 TopoDS_Face aFace2 = TopoDS::Face(theShape2);
304 Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2);
305 return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2);
306 } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves
307 TopLoc_Location aLoc1, aLoc2;
308 Standard_Real aFirst, aLast;
309 TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1);
310 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast);
311 TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2);
312 Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast);
313 return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2);
319 TopoDS_Shape Selector_Algo::value()
321 Handle(TNaming_NamedShape) aNS;
322 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
324 return TopoDS_Shape(); // empty, error shape
327 Selector_Algo* Selector_Algo::restoreByLab(TDF_Label theLab, TDF_Label theBaseDocLab)
329 Handle(TDataStd_Integer) aTypeAttr;
330 if (!theLab.FindAttribute(kSEL_TYPE, aTypeAttr))
332 Selector_Type aType = Selector_Type(aTypeAttr->Get());
333 Selector_Algo* aResult = NULL;
335 case SELTYPE_CONTAINER: {
336 aResult = new Selector_Container;
339 case SELTYPE_INTERSECT: {
340 aResult = new Selector_Intersect;
343 case SELTYPE_MODIFICATION: {
344 aResult = new Selector_Modify;
347 case SELTYPE_PRIMITIVE: {
348 aResult = new Selector_Primitive;
351 case SELTYPE_FILTER_BY_NEIGHBOR: {
352 aResult = new Selector_FilterByNeighbors;
355 case SELTYPE_WEAK_NAMING: {
356 aResult = new Selector_WeakName;
359 default: { // unknown case
363 aResult->myLab = theLab;
364 aResult->myBaseDocumentLab = theBaseDocLab;
365 aResult->myGeometricalNaming = theLab.IsAttribute(kGEOMETRICAL_NAMING);
366 if (!aResult->restore()) {
374 Selector_Algo* Selector_Algo::restoreByName(TDF_Label theLab, TDF_Label theBaseDocLab,
375 std::string theName, const TopAbs_ShapeEnum theShapeType,
376 Selector_NameGenerator* theNameGenerator, TDF_Label& theContextLab)
378 Selector_Algo* aResult = NULL;
379 if (theName[0] == '[') { // intersection or container
380 switch(theShapeType) {
381 case TopAbs_COMPOUND:
382 case TopAbs_COMPSOLID:
385 aResult = new Selector_Container;
390 aResult = new Selector_Intersect;
394 } else if (theName[0] == '(') { // filter by neighbors
395 aResult = new Selector_FilterByNeighbors;
396 } else if (theName.find(pureWeakNameID()) == 0) { // weak naming identifier
397 aResult = new Selector_WeakName;
398 } else if (theName.find('&') != std::string::npos) { // modification
399 aResult = new Selector_Modify;
400 } else { // primitive
401 aResult = new Selector_Primitive;
404 aResult->myLab = theLab;
405 aResult->myBaseDocumentLab = theBaseDocLab;
406 theContextLab = aResult->restoreByName(theName, theShapeType, theNameGenerator);
407 if (theContextLab.IsNull()) {
415 void Selector_Algo::storeType(const Selector_Type theType)
417 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)(theType));