]> SALOME platform Git repositories - modules/shaper.git/blob - src/Selector/Selector_Modify.cpp
Salome HOME
Refactoring of the Selector package: split selection algorithms to separated classes.
[modules/shaper.git] / src / Selector / Selector_Modify.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_Modify.h>
22
23 #include <Selector_NameGenerator.h>
24 #include <Selector_NExplode.h>
25
26 #include <TNaming_NamedShape.hxx>
27 #include <TNaming_Iterator.hxx>
28 #include <TNaming_SameShapeIterator.hxx>
29 #include <TNaming_NewShapeIterator.hxx>
30 #include <TNaming_Tool.hxx>
31 #include <TDataStd_Name.hxx>
32 #include <TDataStd_Integer.hxx>
33 #include <TDF_ChildIterator.hxx>
34 #include <TopTools_MapOfShape.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <BRep_Tool.hxx>
37 #include <TopoDS.hxx>
38 #include <TopoDS_Builder.hxx>
39 #include <TopoDS_Compound.hxx>
40
41 Selector_Modify::Selector_Modify() : Selector_Algo()
42 {
43   myWeakIndex = -1; // no index by default
44 }
45
46 // adds to theResult all labels that contain initial shapes for theValue located in theFinal
47 static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal,
48   const TopoDS_Shape& theValue,
49   bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult)
50 {
51   bool aFoundAnyShape = false;
52   TNaming_SameShapeIterator aLabIter(theValue, theAccess);
53   for(; aLabIter.More(); aLabIter.Next()) {
54     Handle(TNaming_NamedShape) aNS;
55     if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
56       if (aMustBeAtFinal && aNS != theFinal)
57         continue; // looking for old at the same final label only
58       TNaming_Evolution anEvolution = aNS->Evolution();
59       if (anEvolution == TNaming_PRIMITIVE) {
60         // check that this is not in the results already
61         const TDF_Label aResult = aNS->Label();
62         TDF_LabelList::Iterator aResIter(theResult);
63         for(; aResIter.More(); aResIter.Next()) {
64           if (aResIter.Value().IsEqual(aResult))
65             break;
66         }
67         if (!aResIter.More()) // not found, so add this new
68           theResult.Append(aResult);
69         aFoundAnyShape = true;
70       }
71       if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
72         for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) {
73           if (aThisIter.NewShape().IsSame(theValue)) {
74             // continue recursively, null NS means that any NS are ok
75             findBases(theAccess, theFinal, aThisIter.OldShape(),
76               false, theAdditionalDocument, theResult);
77             aFoundAnyShape = true;
78           }
79         }
80       }
81     }
82   }
83   if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document
84     static TDF_Label anEmpty;
85     if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue))
86       findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue,
87         false, anEmpty, theResult);
88   }
89 }
90
91 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
92 static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
93   const TDF_Label& theFinal,
94   const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults)
95 {
96   if (TNaming_Tool::HasLabel(anAccess, theBase)) {
97     for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
98     {
99       TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
100       if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
101         if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
102           theResults.Add(aBaseIter.Shape());
103         } else {
104           findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults);
105         }
106       }
107     }
108   }
109   if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
110     static TDF_Label anEmpty;
111     findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults);
112   }
113 }
114
115 void Selector_Modify::findModificationResult(TopoDS_ListOfShape& theCommon) {
116   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
117     TDF_Label anAdditionalDoc; // this document if base is started in extra document
118     if (aBase.Value().Root() != label().Root()) {
119       anAdditionalDoc = label();
120     }
121     TopTools_MapOfShape aFinals;
122     for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
123       findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals);
124     }
125     if (!aFinals.IsEmpty()) {
126       if (theCommon.IsEmpty()) { // just copy all to common
127         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
128           theCommon.Append(aFinal.Key());
129         }
130       } else { // keep only shapes presented in both lists
131         for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
132           if (aFinals.Contains(aCommon.Value())) {
133             aCommon.Next();
134           } else { // common is not found, remove it
135             theCommon.Remove(aCommon);
136           }
137         }
138       }
139     }
140   }
141 }
142
143 bool Selector_Modify::select(NCollection_List<Handle(TNaming_NamedShape)>& theModifList,
144   const TopoDS_Shape theContext, const TopoDS_Shape theValue)
145 {
146   if (theModifList.Extent() > 1) { // searching for the best modification result: by context
147     Handle(TNaming_NamedShape) aCandidate;
148     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(theModifList);
149     for (; !theModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
150       aCandidate = aModIter.Value();
151       TDF_Label aFatherLab = aCandidate->Label().Father();
152       Handle(TNaming_NamedShape) aFatherNS;
153       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
154         for (TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
155           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
156             theModifList.Clear();
157             break;
158           }
159         }
160       }
161     }
162     // take the best candidate, or the last in the iteration
163     theModifList.Clear();
164     theModifList.Append(aCandidate);
165   }
166
167   if (!theModifList.IsEmpty()) {
168     // searching for all the base shapes of this modification
169     findBases(label(), theModifList.First(), theValue, true, baseDocument(), myBases);
170     if (!myBases.IsEmpty()) {
171       myFinal = theModifList.First()->Label();
172       TopoDS_ListOfShape aCommon;
173       findModificationResult(aCommon);
174       // trying to search by neighbors
175       if (aCommon.Extent() > 1) { // more complicated selection
176         if (alwaysGeometricalNaming()) {
177           TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
178           TopoDS_Shape aFirst = aCommonIter.Value();
179           for (aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
180             if (!sameGeometry(aFirst, aCommonIter.Value()))
181               break;
182           }
183           if (!aCommonIter.More()) { // all geometry is same, result is a compound
184             return true;
185           }
186         }
187       }
188     }
189     // weak naming case
190     TopoDS_ListOfShape aCommon;
191     myFinal = theModifList.First()->Label();
192     Handle(TNaming_NamedShape) aNS;
193     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
194       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
195         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
196         if (!aNewShape.IsNull())
197           aCommon.Append(aNewShape);
198       }
199     }
200     Selector_NExplode aNexp(aCommon);
201     myWeakIndex = aNexp.index(theValue);
202     return myWeakIndex != -1;
203   }
204   return false;
205 }
206
207 void Selector_Modify::store()
208 {
209   storeType(Selector_Algo::SELTYPE_MODIFICATION);
210   storeBaseArray(myBases, myFinal);
211   if (myWeakIndex != -1) {
212     TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
213   }
214 }
215
216 bool Selector_Modify::restore()
217 {
218   if (restoreBaseArray(myBases, myFinal)) {
219     Handle(TDataStd_Integer) aWeakInt;
220     if (label().FindAttribute(weakID(), aWeakInt)) {
221       myWeakIndex = aWeakInt->Get();
222     }
223     return true;
224   }
225   return false;
226 }
227
228 TDF_Label Selector_Modify::restoreByName(std::string theName,
229   const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
230 {
231   TDF_Label aContext;
232   for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
233     if (aStart != 0)
234       aStart++;
235     anEnd = theName.find('&', aStart);
236     std::string aSubStr =
237       theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
238     if (aSubStr.find(weakNameID()) == 0) { // weak name identifier
239       std::string aWeakIndex = aSubStr.substr(weakNameID().size());
240       myWeakIndex = atoi(aWeakIndex.c_str());
241       continue;
242     }
243     TDF_Label aSubContext, aValue;
244     if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
245       return TDF_Label(); // can not restore
246     if(aSubContext.IsNull() || aValue.IsNull())
247       return TDF_Label(); // can not restore
248     if (myFinal.IsNull()) {
249       myFinal = aValue;
250       aContext = aSubContext;
251     } else
252       myBases.Append(aValue);
253   }
254   return aContext;
255 }
256
257 bool Selector_Modify::solve(const TopoDS_Shape& theContext)
258 {
259   TopoDS_Shape aResult;
260   if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index
261     TopoDS_ListOfShape aCommon;
262     Handle(TNaming_NamedShape) aNS;
263     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
264       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
265         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
266         if (!aNewShape.IsNull())
267           aCommon.Append(aNewShape);
268       }
269     }
270     Selector_NExplode aNexp(aCommon);
271     aResult = aNexp.shape(myWeakIndex);
272   } else { // standard case
273     TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
274     findModificationResult(aFinalsCommon);
275     if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape
276       aResult = aFinalsCommon.First();
277     } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) {
278       Selector_NExplode aNExp(aFinalsCommon);
279       aResult = aNExp.shape(myWeakIndex);
280     } else if (aFinalsCommon.Extent() > 1 && geometricalNaming()) {// if same geometry - compound
281       TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon);
282       TopoDS_Shape aFirst = aCommonIter.Value();
283       for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
284         if (!sameGeometry(aFirst, aCommonIter.Value()))
285           break;
286       }
287       if (!aCommonIter.More()) { // all geometry is same, create a result compound
288         TopoDS_Builder aBuilder;
289         TopoDS_Compound aCompound;
290         aBuilder.MakeCompound(aCompound);
291         for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) {
292           aBuilder.Add(aCompound, aCommonIter.Value());
293         }
294         aResult = aCompound;
295       }
296
297     }
298   }
299
300   if (!aResult.IsNull()) {
301     Selector_Algo::store(aResult);
302     return true;
303   }
304   return false;
305 }
306
307 std::string Selector_Modify::name(Selector_NameGenerator* theNameGenerator)
308 {
309   // final&base1&base2 +optionally: [weak_name_1]
310   std::string aResult;
311   Handle(TDataStd_Name) aName;
312   if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
313     return "";
314   aResult += theNameGenerator->contextName(myFinal) + "/" +
315     std::string(TCollection_AsciiString(aName->Get()).ToCString());
316   for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
317     if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
318       return "";
319     aResult += "&";
320     aResult += theNameGenerator->contextName(*aBase) + "/" +
321       std::string(TCollection_AsciiString(aName->Get()).ToCString());
322   }
323   if (myWeakIndex != -1) {
324     std::ostringstream aWeakStr;
325     aWeakStr<<"&"<<weakNameID()<<myWeakIndex;
326     aResult += aWeakStr.str();
327   }
328   return aResult;
329 }