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