]> SALOME platform Git repositories - modules/shaper.git/blob - src/Selector/Selector_Selector.cpp
Salome HOME
Simple implementation of all kinds of names except FILTER
[modules/shaper.git] / src / Selector / Selector_Selector.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_Selector.h>
22
23 #include <TDF_ChildIDIterator.hxx>
24 #include <TopoDS_Iterator.hxx>
25 #include <TopoDS_Builder.hxx>
26 #include <TopExp_Explorer.hxx>
27 #include <TNaming_Tool.hxx>
28 #include <TNaming_NewShapeIterator.hxx>
29 #include <TNaming_OldShapeIterator.hxx>
30 #include <TNaming_SameShapeIterator.hxx>
31 #include <TNaming_Iterator.hxx>
32 #include <TNaming_Builder.hxx>
33 #include <TopTools_MapOfShape.hxx>
34
35 #include <TDataStd_Integer.hxx>
36 #include <TDataStd_ReferenceArray.hxx>
37
38 #include <list>
39
40 /// type of the selection, integerm keeps the Selector_Type value
41 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
42 /// type of the shape, stored in case it is intersection or container
43 static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171");
44 //  reference attribute that contains the reference to labels where the "from" or "base" shapes
45 // of selection are located
46 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
47
48 Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
49 {
50 }
51
52 TDF_Label Selector_Selector::label()
53 {
54   return myLab;
55 }
56
57 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
58 static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& theValue,
59   TDF_LabelList& theResult)
60 {
61   for(TNaming_Iterator aThisIter(theFinal); aThisIter.More(); aThisIter.Next()) {
62     if (aThisIter.NewShape().IsSame(theValue)) {
63       const TopoDS_Shape& anOldShape = aThisIter.OldShape();
64       // searching for all old shapes in this sequence of modification
65       TNaming_OldShapeIterator anOldIter(anOldShape, theFinal->Label());
66       for(; anOldIter.More(); anOldIter.Next()) {
67         TNaming_Evolution anEvolution = anOldIter.NamedShape()->Evolution();
68         if (anEvolution == TNaming_PRIMITIVE) { // found a good candidate, a base shape
69           // check that this is not in the results already
70           const TDF_Label aResult = anOldIter.NamedShape()->Label();
71           TDF_LabelList::Iterator aResIter(theResult);
72           for(; aResIter.More(); aResIter.Next()) {
73             if (aResIter.Value().IsEqual(aResult))
74               break;
75           }
76           if (!aResIter.More()) // not found, so add this new
77             theResult.Append(aResult);
78         } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
79           // continue recursively
80           findBases(anOldIter.NamedShape(), anOldShape, theResult);
81         }
82       }
83     }
84   }
85 }
86
87 bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
88 {
89   if (theValue.IsNull() || theContext.IsNull())
90     return false;
91   // check the value shape can be named as it is, or it is needed to construct it from the
92   // higher level shapes (like a box vertex by faces that form this vertex)
93   if (!TNaming_Tool::HasLabel(myLab, theValue)) {
94     TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
95     myShapeType = aSelectionType;
96     if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
97         aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
98     { // iterate all sub-shapes and select them on sublabels
99       for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
100         if (!selectBySubSelector(theContext, aSubIter.Value())) {
101           return false; // if some selector is failed, everything is failed
102         }
103       }
104       myType = SELTYPE_CONTAINER;
105       return true;
106     }
107
108     // try to find the shape of the higher level type in the context shape
109     while(aSelectionType != TopAbs_FACE) {
110       if (aSelectionType == TopAbs_VERTEX) aSelectionType = TopAbs_EDGE;
111       else if (aSelectionType == TopAbs_EDGE) aSelectionType = TopAbs_FACE;
112       TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue
113       for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) {
114         TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType());
115         for(; aSubExp.More(); aSubExp.Next()) {
116           if (aSubExp.Current().IsSame(theValue)) {
117             anIntersectors.Add(aSelExp.Current());
118             break;
119           }
120         }
121       }
122       //TODO: check if intersectors produce several subs, try to remove one of the intersector
123
124       //TODO: check that solution is only one
125
126       // name the intersectors
127       std::list<Selector_Selector> aSubSelList;
128       TopTools_MapOfShape::Iterator anInt(anIntersectors);
129       for (; anInt.More(); anInt.Next()) {
130         if (!selectBySubSelector(theContext, anInt.Value())) {
131           break; // if some selector is failed, stop and search another solution
132         }
133       }
134       if (!anInt.More()) { // all intersectors were correctly named
135         myType = SELTYPE_INTERSECT;
136         return true;
137       }
138     }
139
140     // TODO: searching by neighbours
141     return false;
142   }
143   // searching for the base shapes of the value
144   Handle(TNaming_NamedShape) aPrimitiveNS;
145   NCollection_List<Handle(TNaming_NamedShape)> aModifList;
146   for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next())
147   {
148     Handle(TNaming_NamedShape) aNS;
149     if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
150       TNaming_Evolution anEvolution = aNS->Evolution();
151       if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
152         aPrimitiveNS = aNS;
153         break;
154       } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
155         // check this is a new shape
156         TNaming_Iterator aNSIter(aNS);
157         for(; aNSIter.More(); aNSIter.Next())
158           if (aNSIter.NewShape().IsSame(theValue))
159             break;
160         if (aNSIter.More()) // new was found
161           aModifList.Append(aNS);
162       }
163     }
164   }
165
166   if (!aPrimitiveNS.IsNull()) {
167     myType = SELTYPE_PRIMITIVE;
168     myFinal = aPrimitiveNS->Label();
169     return true;
170   }
171
172   if (aModifList.Extent() > 1) { // searching for the best modification result: by context
173     Handle(TNaming_NamedShape) aCandidate;
174     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(aModifList);
175     for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
176        aCandidate = aModIter.Value();
177       TDF_Label aFatherLab = aCandidate->Label().Father();
178       Handle(TNaming_NamedShape) aFatherNS;
179       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
180         for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
181           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
182             aModifList.Clear();
183             break;
184           }
185         }
186       }
187     }
188     // take the best candidate, or the last in the iteration
189     aModifList.Clear();
190     aModifList.Append(aCandidate);
191   }
192
193   if (!aModifList.IsEmpty()) {
194     // searching for all the base shapes of this modification
195     findBases(aModifList.First(), theValue, myBases);
196     myFinal = aModifList.First()->Label();
197     myType = SELTYPE_MODIFICATION;
198     return !myBases.IsEmpty();
199   }
200
201   // not found a good result
202   return false;
203 }
204
205 void Selector_Selector::store()
206 {
207   myLab.ForgetAllAttributes(true); // remove old naming data
208   TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType);
209   switch(myType) {
210   case SELTYPE_CONTAINER:
211   case SELTYPE_INTERSECT: {
212     TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType);
213     // store also all sub-selectors
214     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
215     for(; aSubSel != mySubSelList.end(); aSubSel++) {
216       aSubSel->store();
217     }
218     break;
219   }
220   case SELTYPE_PRIMITIVE: {
221     Handle(TDataStd_ReferenceArray) anArray =
222       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0);
223     anArray->SetValue(0, myFinal);
224     break;
225   }
226   case SELTYPE_MODIFICATION: {
227     Handle(TDataStd_ReferenceArray) anArray =
228       TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent());
229     TDF_LabelList::Iterator aBIter(myBases);
230     for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) {
231       anArray->SetValue(anIndex, aBIter.Value());
232     }
233     anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array
234     break;
235   }
236   default: { // unknown case
237     break;
238   }
239   }
240 }
241
242 bool Selector_Selector::restore()
243 {
244   Handle(TDataStd_Integer) aTypeAttr;
245   if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr))
246     return false;
247   myType = Selector_Type(aTypeAttr->Get());
248   switch(myType) {
249   case SELTYPE_CONTAINER:
250   case SELTYPE_INTERSECT: {
251     Handle(TDataStd_Integer) aShapeTypeAttr;
252     if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr))
253       return false;
254     myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get());
255     // restore sub-selectors
256     bool aSubResult = true;
257     mySubSelList.clear();
258     for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) {
259       mySubSelList.push_back(Selector_Selector(aSub.Value()->Label()));
260       if (!mySubSelList.back().restore())
261         aSubResult = false;
262     }
263     return aSubResult;
264   }
265   case SELTYPE_PRIMITIVE: {
266     Handle(TDataStd_ReferenceArray) anArray;
267     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
268       myFinal = anArray->Value(0);
269       return true;
270     }
271     return false;
272   }
273   case SELTYPE_MODIFICATION: {
274     Handle(TDataStd_ReferenceArray) anArray;
275     if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
276       int anUpper = anArray->Upper();
277       for(int anIndex = 0; anIndex < anUpper; anIndex++) {
278         myBases.Append(anArray->Value(anIndex));
279       }
280       myFinal = anArray->Value(anUpper);
281       return true;
282     }
283     return false;
284   }
285   default: { // unknown case
286   }
287   }
288   return false;
289 }
290
291 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
292 static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal,
293   TopTools_MapOfShape& theResults)
294 {
295   for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); aBaseIter.More(); aBaseIter.Next()) {
296     TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
297     if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
298       if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
299         theResults.Add(aBaseIter.Shape());
300       } else {
301         findFinals(aBaseIter.Shape(), theFinal, theResults);
302       }
303     }
304   }
305
306 }
307
308 bool Selector_Selector::solve()
309 {
310   TopoDS_Shape aResult; // null if invalid
311   switch(myType) {
312   case SELTYPE_CONTAINER: {
313     TopoDS_Builder aBuilder;
314     switch(myShapeType) {
315     case TopAbs_COMPOUND: {
316       TopoDS_Compound aComp;
317       aBuilder.MakeCompound(aComp);
318       aResult = aComp;
319       break;
320       }
321     case TopAbs_COMPSOLID: {
322       TopoDS_CompSolid aComp;
323       aBuilder.MakeCompSolid(aComp);
324       aResult = aComp;
325       break;
326     }
327     case TopAbs_SHELL: {
328       TopoDS_Shell aShell;
329       aBuilder.MakeShell(aShell);
330       aResult = aShell;
331       break;
332     }
333     case TopAbs_WIRE: {
334       TopoDS_Wire aWire;
335       aBuilder.MakeWire(aWire);
336       aResult = aWire;
337       break;
338     }
339     }
340     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
341     for(; aSubSel != mySubSelList.end(); aSubSel++) {
342       if (!aSubSel->solve()) {
343         return false;
344       }
345       aBuilder.Add(aResult, aSubSel->value());
346     }
347     break;
348   }
349   case SELTYPE_INTERSECT: {
350     TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result)
351     std::list<Selector_Selector>::iterator aSubSel = mySubSelList.begin();
352     for(; aSubSel != mySubSelList.end(); aSubSel++) {
353       if (!aSubSel->solve()) {
354         return false;
355       }
356       TopoDS_Shape anArg = aSubSel->value();
357       TopTools_MapOfShape aCurrentMap;
358       for(TopExp_Explorer anExp(anArg, myShapeType); anExp.More(); anExp.Next()) {
359         if (aCurrentMap.Add(anExp.Current()) && aSubSel == mySubSelList.begin())
360           aCommon.Append(anExp.Current());
361       }
362       if (aSubSel != mySubSelList.begin()) { // remove from common shapes not in aCurrentMap
363         for(TopoDS_ListOfShape::Iterator aComIter(aCommon); aComIter.More(); ) {
364           if (aCurrentMap.Contains(aComIter.Value()))
365             aComIter.Next();
366           else
367             aCommon.Remove(aComIter);
368         }
369       }
370     }
371     if (aCommon.Extent() != 1)
372       return false;
373     aResult = aCommon.First();
374     break;
375   }
376   case SELTYPE_PRIMITIVE: {
377     Handle(TNaming_NamedShape) aNS;
378     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
379       aResult = aNS->Get();
380     }
381   }
382   case SELTYPE_MODIFICATION: {
383     TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
384     TDF_LabelList::Iterator aBase(myBases);
385     for(; aBase.More(); aBase.Value()) {
386       TopTools_MapOfShape aFinals;
387       for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next())
388         findFinals(aBaseShape.NewShape(), myFinal, aFinals);
389       if (!aFinals.IsEmpty()) {
390         if (aFinalsCommon.IsEmpty()) { // just copy all to common
391           for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
392             aFinalsCommon.Append(aFinal.Key());
393           }
394         } else { // keep only shapes presented in both lists
395           TopoDS_ListOfShape::Iterator aCommon(aFinalsCommon);
396           for(; aCommon.More(); aCommon.Next()) {
397             if (aFinals.Contains(aCommon.Value())) {
398               aCommon.Next();
399             } else { // common is not found, remove it
400               aFinalsCommon.Remove(aCommon);
401             }
402           }
403         }
404       }
405     }
406     if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape
407       aResult = aFinalsCommon.First();
408   }
409   default: { // unknown case
410   }
411   }
412
413   TNaming_Builder aBuilder(myLab);
414   if (!aResult.IsNull()) {
415     aBuilder.Select(aResult, aResult);
416     return true;
417   }
418   return false; // builder just erases the named shape in case of error
419 }
420
421 TopoDS_Shape Selector_Selector::value()
422 {
423   Handle(TNaming_NamedShape) aNS;
424   if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
425     return aNS->Get();
426   return TopoDS_Shape(); // empty, error shape
427 }
428
429 bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue)
430 {
431   mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1)));
432   if (!mySubSelList.back().select(theContext, theValue)) {
433     mySubSelList.clear(); // if one of the selector is failed, all become invalid
434     return false;
435   }
436   return true;
437 }