Salome HOME
Issue #2811: Update content of Object node on creation moment
[modules/shaper.git] / src / Selector / Selector_Algo.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include <Selector_Algo.h>
22
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>
29
30 #include <TDF_Tool.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <TopoDS_Edge.hxx>
33 #include <TopoDS.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>
43 #include <TDataStd_UAttribute.hxx>
44
45
46 /// type of the selection, integer keeps the Selector_Type value
47 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
48 // geometrical naming indicator
49 static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
50
51
52 //  reference attribute that contains the reference to labels where the "from" or "base" shapes
53 // of selection are located
54 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
55 // if the base array contains reference to the root label, this means that it refers to an
56 // external document and this list contains a tag in the document
57 static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a");
58
59 Selector_Algo::Selector_Algo()
60 {
61   myGeometricalNaming = false; // default values
62   myAlwaysGeometricalNaming = false;
63 }
64
65 #define SET_ALGO_FLAGS(algo) \
66   algo->myLab = theAccess; \
67   algo->myBaseDocumentLab = theBaseDocument; \
68   algo->myGeometricalNaming = theGeometricalNaming; \
69   algo->myUseNeighbors = theUseNeighbors; \
70   algo->myUseIntersections = theUseIntersections; \
71   algo->myAlwaysGeometricalNaming = theAlwaysGeometricalNaming;
72
73 Selector_Algo* Selector_Algo::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
74   const TDF_Label theAccess, const TDF_Label theBaseDocument,
75   const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections,
76   const bool theAlwaysGeometricalNaming)
77 {
78   Selector_Algo* aResult = NULL;
79   if (theValue.IsNull() || theContext.IsNull())
80     return aResult;
81
82   // check the value shape can be named as it is, or it is needed to construct it from the
83   // higher level shapes (like a box vertex by faces that form this vertex)
84   bool aIsFound = TNaming_Tool::HasLabel(theAccess, theValue);
85   if (aIsFound) { // additional check for selection and delete evolution only: also could not use
86     aIsFound = false;
87     for(TNaming_SameShapeIterator aShapes(theValue, theAccess); aShapes.More(); aShapes.Next())
88     {
89       Handle(TNaming_NamedShape) aNS;
90       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
91         if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
92           aNS->Evolution() == TNaming_PRIMITIVE) {
93           aIsFound = true;
94           break;
95         }
96       }
97     }
98   }
99   // searching in the base document
100   if (!aIsFound && !theBaseDocument.IsNull() && TNaming_Tool::HasLabel(theBaseDocument, theValue))
101   {
102     TNaming_SameShapeIterator aShapes(theValue, theBaseDocument);
103     for(; aShapes.More(); aShapes.Next())
104     {
105       Handle(TNaming_NamedShape) aNS;
106       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
107         if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
108           aNS->Evolution() == TNaming_PRIMITIVE) {
109           aIsFound = true;
110           break;
111         }
112       }
113     }
114   }
115   if (!aIsFound) {
116     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
117     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
118       aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
119     {
120       Selector_Container* aContainer = new Selector_Container;
121       SET_ALGO_FLAGS(aContainer);
122       if (aContainer->select(theContext, theValue))
123         return aContainer;
124       delete aContainer;
125       return NULL;
126     }
127
128     Selector_Intersect* anIntersect = new Selector_Intersect;
129     SET_ALGO_FLAGS(anIntersect);
130     bool aGoodIntersector = anIntersect->select(theContext, theValue);
131     // weak intersector is bad for not use neighbors and has lower priority than neighbors
132     if (aGoodIntersector && anIntersect->myWeakIndex == -1) {
133       return anIntersect;
134     }
135     if (!theUseNeighbors) {
136       delete anIntersect;
137       return NULL;
138     }
139     // searching by neighbors
140     Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
141     SET_ALGO_FLAGS(aNBs);
142     if (aNBs->select(theContext, theValue)) {
143       delete anIntersect;
144       return aNBs;
145     }
146     delete aNBs;
147     if (aGoodIntersector) { // if neighbors are bad, use intersector with weak index
148       return anIntersect;
149     }
150     delete anIntersect;
151
152     // pure weak naming: there is no sense to use pure weak naming for neighbors selection
153     if (theUseNeighbors) {
154       Selector_WeakName* aWeak = new Selector_WeakName;
155       SET_ALGO_FLAGS(aWeak);
156       if (aWeak->select(theContext, theValue)) {
157         return aWeak;
158       }
159       delete aWeak;
160     }
161     return NULL; // not found value in the tree, not found context shape in the tree also
162   }
163   // searching for the base shapes of the value
164   Handle(TNaming_NamedShape) aPrimitiveNS;
165   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
166   for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
167     TDF_Label aLab = aUseExternal == 0 ? theAccess : theBaseDocument;
168     if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
169       continue;
170     for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
171     {
172       Handle(TNaming_NamedShape) aNS;
173       if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
174         TNaming_Evolution anEvolution = aNS->Evolution();
175         if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
176           aPrimitiveNS = aNS;
177           break;
178         } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
179           // check this is a new shape
180           TNaming_Iterator aNSIter(aNS);
181           for(; aNSIter.More(); aNSIter.Next())
182             if (aNSIter.NewShape().IsSame(theValue))
183               break;
184           if (aNSIter.More()) // new was found
185             aModifList.Append(aNS);
186         }
187       }
188     }
189   }
190
191   if (!aPrimitiveNS.IsNull()) {
192     Selector_Primitive* aPrimitive = new Selector_Primitive;
193     SET_ALGO_FLAGS(aPrimitive);
194     aPrimitive->select(aPrimitiveNS->Label());
195     return aPrimitive;
196   } else {
197     Selector_Modify* aModify = new Selector_Modify;
198     SET_ALGO_FLAGS(aModify);
199     bool aGoodModify = aModify->select(aModifList, theContext, theValue);
200     // weak intersector is bad for not use neighbors and has lower priority than neighbors
201     if (aGoodModify && aModify->myWeakIndex == -1) {
202       return aModify;
203     }
204     if (!theUseNeighbors) {
205       delete aModify;
206       return NULL;
207     }
208     // searching by neighbors
209     Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
210     SET_ALGO_FLAGS(aNBs);
211     if (aNBs->select(theContext, theValue)) {
212       delete aModify;
213       return aNBs;
214     }
215     delete aNBs;
216
217     if (aGoodModify) { // if neighbors are bad, use modify algo with weak index
218       return aModify;
219     }
220     delete aModify;
221   }
222
223   return NULL; // invalid case
224 }
225
226 Selector_Algo* Selector_Algo::relesectWithAllGeometry(
227   Selector_Algo* theOldAlgo, const TopoDS_Shape theContext)
228 {
229   return select(theContext, theOldAlgo->value(),
230     theOldAlgo->myLab, theOldAlgo->myBaseDocumentLab, true, true, true, true);
231 }
232
233 void Selector_Algo::storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast)
234 {
235   Handle(TDataStd_ReferenceArray) anArray =
236     TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, theRef.Extent());
237   Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
238   const TDF_Label aThisDocRoot = myLab.Root();
239   TDF_LabelList::Iterator aBIter(theRef);
240   for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
241     const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
242     // check this is a label of this document
243     if (aLab.Root().IsEqual(aThisDocRoot)) {
244       anArray->SetValue(anIndex, aLab);
245     } else { // store reference to external document as an entry-string
246       if (anEntries.IsNull()) {
247         anEntries = TDataStd_ExtStringList::Set(myLab, kBASE_LIST);
248       }
249       TCollection_AsciiString anEntry;
250       TDF_Tool::Entry(aLab, anEntry);
251       anEntries->Append(anEntry);
252       anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
253     }
254     if (!aBIter.More())
255       break;
256   }
257 }
258
259 bool Selector_Algo::restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast)
260 {
261   const TDF_Label aThisDocRoot = myLab.Root();
262   Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
263   TDataStd_ListOfExtendedString::Iterator anIter;
264   Handle(TDataStd_ReferenceArray) anArray;
265   if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
266     int anUpper = anArray->Upper();
267     for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
268       TDF_Label aLab = anArray->Value(anIndex);
269       if (aLab.IsEqual(aThisDocRoot)) { // external document reference
270         if (myBaseDocumentLab.IsNull())
271           return false;
272         if (anEntries.IsNull()) {
273           if (!myLab.FindAttribute(kBASE_LIST, anEntries))
274             return false;
275           anIter.Initialize(anEntries->List());
276         }
277         if (!anIter.More())
278           return false;
279         TDF_Tool::Label(myBaseDocumentLab.Data(), anIter.Value(), aLab);
280         anIter.Next();
281       }
282       if (anIndex == anUpper) {
283         theLast = aLab;
284       } else {
285         theRef.Append(aLab);
286       }
287     }
288     return true;
289   }
290   return false;
291 }
292
293 void Selector_Algo::store(const TopoDS_Shape theShape)
294 {
295   TNaming_Builder aBuilder(myLab);
296   aBuilder.Select(theShape, theShape);
297 }
298
299 bool Selector_Algo::sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) {
300   if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType())
301   {
302     if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces
303       TopLoc_Location aLoc1, aLoc2;
304       TopoDS_Face aFace1 = TopoDS::Face(theShape1);
305       Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1);
306       TopoDS_Face aFace2 = TopoDS::Face(theShape2);
307       Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2);
308       return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2);
309     } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves
310       TopLoc_Location aLoc1, aLoc2;
311       Standard_Real aFirst, aLast;
312       TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1);
313       Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast);
314       TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2);
315       Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast);
316       return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2);
317     }
318   }
319   return false;
320 }
321
322 TopoDS_Shape Selector_Algo::value()
323 {
324   Handle(TNaming_NamedShape) aNS;
325   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
326     return aNS->Get();
327   return TopoDS_Shape(); // empty, error shape
328 }
329
330 Selector_Algo* Selector_Algo::restoreByLab(TDF_Label theLab, TDF_Label theBaseDocLab)
331 {
332   Handle(TDataStd_Integer) aTypeAttr;
333   if (!theLab.FindAttribute(kSEL_TYPE, aTypeAttr))
334     return NULL;
335   Selector_Type aType = Selector_Type(aTypeAttr->Get());
336   Selector_Algo* aResult = NULL;
337   switch (aType) {
338   case SELTYPE_CONTAINER: {
339     aResult = new Selector_Container;
340     break;
341   }
342   case SELTYPE_INTERSECT: {
343     aResult = new Selector_Intersect;
344     break;
345   }
346   case SELTYPE_MODIFICATION: {
347     aResult = new Selector_Modify;
348     break;
349   }
350   case SELTYPE_PRIMITIVE: {
351     aResult = new Selector_Primitive;
352     break;
353   }
354   case SELTYPE_FILTER_BY_NEIGHBOR: {
355     aResult = new Selector_FilterByNeighbors;
356     break;
357   }
358   case SELTYPE_WEAK_NAMING: {
359     aResult = new Selector_WeakName;
360     break;
361   }
362   default: { // unknown case
363   }
364   }
365   if (aResult) {
366     aResult->myLab = theLab;
367     aResult->myBaseDocumentLab = theBaseDocLab;
368     aResult->myGeometricalNaming = theLab.IsAttribute(kGEOMETRICAL_NAMING);
369     if (!aResult->restore()) {
370       delete aResult;
371       aResult = NULL;
372     }
373   }
374   return aResult;
375 }
376
377 Selector_Algo* Selector_Algo::restoreByName(TDF_Label theLab, TDF_Label theBaseDocLab,
378   std::string theName, const TopAbs_ShapeEnum theShapeType,
379   Selector_NameGenerator* theNameGenerator, TDF_Label& theContextLab)
380 {
381   Selector_Algo* aResult = NULL;
382   if (theName[0] == '[') { // intersection or container
383     switch(theShapeType) {
384     case TopAbs_COMPOUND:
385     case TopAbs_COMPSOLID:
386     case TopAbs_SHELL:
387     case TopAbs_WIRE:
388       aResult = new Selector_Container;
389       break;
390     case TopAbs_VERTEX:
391     case TopAbs_EDGE:
392     case TopAbs_FACE:
393       aResult = new Selector_Intersect;
394       break;
395     default:;
396     }
397   } else if (theName[0] == '(') { // filter by neighbors
398     aResult = new Selector_FilterByNeighbors;
399   } else if (theName.find(pureWeakNameID()) == 0) { // weak naming identifier
400     aResult = new Selector_WeakName;
401   } else if (theName.find('&') != std::string::npos) { // modification
402     aResult = new Selector_Modify;
403   } else { // primitive
404     aResult = new Selector_Primitive;
405   }
406   if (aResult) {
407     aResult->myLab = theLab;
408     aResult->myBaseDocumentLab = theBaseDocLab;
409     theContextLab = aResult->restoreByName(theName, theShapeType, theNameGenerator);
410     if (theContextLab.IsNull()) {
411       delete aResult;
412       aResult = NULL;
413     }
414   }
415   return aResult;
416 }
417
418 void Selector_Algo::storeType(const Selector_Type theType)
419 {
420   myLab.ForgetAllAttributes(true);
421   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)(theType));
422   if (myGeometricalNaming)
423     TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING);
424 }