]> SALOME platform Git repositories - modules/shaper.git/blob - src/Selector/Selector_Modify.cpp
Salome HOME
Merge remote-tracking branch 'remotes/origin/vsr/18858'
[modules/shaper.git] / src / Selector / Selector_Modify.cpp
1 // Copyright (C) 2014-2020  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   if (TNaming_Tool::HasLabel(theAccess, theValue)) {
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   }
84   if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document
85     static TDF_Label anEmpty;
86     if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue))
87       findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue,
88         false, anEmpty, theResult);
89   }
90 }
91
92 /// Returns in theResults all shapes with history started in theBase and ended in theFinal
93 static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase,
94   const TDF_Label& theFinal,
95   const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& thePass, TopTools_MapOfShape& theResults)
96 {
97   if (TNaming_Tool::HasLabel(anAccess, theBase)) {
98     for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
99     {
100       TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution();
101       if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
102         if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) {
103           theResults.Add(aBaseIter.Shape());
104         } else {
105           if (thePass.Add(aBaseIter.Shape()))
106             findFinals(
107               anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, thePass, theResults);
108         }
109       }
110     }
111   }
112   if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
113     static TDF_Label anEmpty;
114     TopTools_MapOfShape aPass;
115     findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, aPass, theResults);
116   }
117 }
118
119 void Selector_Modify::findModificationResult(TopoDS_ListOfShape& theCommon) {
120   for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) {
121     TDF_Label anAdditionalDoc; // this document if base is started in extra document
122     if (aBase.Value().Root() != label().Root()) {
123       anAdditionalDoc = label();
124     }
125     TopTools_MapOfShape aFinals;
126     TopTools_MapOfShape aPass;
127     for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
128       findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aPass, aFinals);
129     }
130     if (!aFinals.IsEmpty()) {
131       if (theCommon.IsEmpty()) { // just copy all to common
132         for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) {
133           theCommon.Append(aFinal.Key());
134         }
135       } else { // keep only shapes presented in both lists
136         for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
137           if (aFinals.Contains(aCommon.Value())) {
138             aCommon.Next();
139           } else { // common is not found, remove it
140             theCommon.Remove(aCommon);
141           }
142         }
143       }
144     }
145   }
146 }
147
148 bool Selector_Modify::select(NCollection_List<Handle(TNaming_NamedShape)>& theModifList,
149   const TopoDS_Shape theContext, const TopoDS_Shape theValue)
150 {
151   if (theModifList.Extent() > 1) { // searching for the best modification result: by context
152     Handle(TNaming_NamedShape) aCandidate;
153     NCollection_List<Handle(TNaming_NamedShape)>::Iterator aModIter(theModifList);
154     for (; !theModifList.IsEmpty() && aModIter.More(); aModIter.Next()) {
155       aCandidate = aModIter.Value();
156       TDF_Label aFatherLab = aCandidate->Label().Father();
157       Handle(TNaming_NamedShape) aFatherNS;
158       if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) {
159         for (TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) {
160           if (theContext.IsSame(anIter.NewShape())) { // found the best modification
161             theModifList.Clear();
162             break;
163           }
164         }
165       }
166     }
167     // take the best candidate, or the last in the iteration
168     theModifList.Clear();
169     theModifList.Append(aCandidate);
170   }
171
172   if (!theModifList.IsEmpty()) {
173     // searching for all the base shapes of this modification
174     findBases(label(), theModifList.First(), theValue, true, baseDocument(), myBases);
175     if (!myBases.IsEmpty()) {
176       myFinal = theModifList.First()->Label();
177       TopoDS_ListOfShape aCommon;
178       findModificationResult(aCommon);
179       // trying to search by neighbors
180       if (aCommon.Extent() > 1) { // more complicated selection
181         if (alwaysGeometricalNaming()) {
182           TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
183           TopoDS_Shape aFirst = aCommonIter.Value();
184           for (aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
185             if (!sameGeometry(aFirst, aCommonIter.Value()))
186               break;
187           }
188           if (!aCommonIter.More()) { // all geometry is same, result is a compound
189             return true;
190           }
191         }
192       } else if (aCommon.Extent() == 1) {
193         return true; // simple modification
194       }
195       if (useNeighbors()) { // optimization: for the current moment only in one case this method is
196                             //  called where this is not needed if neighbors option is disabled
197         // weak naming between the common results
198         Selector_NExplode aNexp(aCommon);
199         myWeakIndex = aNexp.index(theValue);
200       } else
201         myWeakIndex = 0;
202       return myWeakIndex != -1;
203     }
204     // weak naming case
205     TopoDS_ListOfShape aCommon;
206     myFinal = theModifList.First()->Label();
207     Handle(TNaming_NamedShape) aNS;
208     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
209       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
210         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
211         if (!aNewShape.IsNull())
212           aCommon.Append(aNewShape);
213       }
214     }
215     Selector_NExplode aNexp(aCommon);
216     myWeakIndex = aNexp.index(theValue);
217     return myWeakIndex != -1;
218   }
219   return false;
220 }
221
222 void Selector_Modify::store()
223 {
224   storeType(Selector_Algo::SELTYPE_MODIFICATION);
225   storeBaseArray(myBases, myFinal);
226   if (myWeakIndex != -1) {
227     TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
228   }
229 }
230
231 bool Selector_Modify::restore()
232 {
233   if (restoreBaseArray(myBases, myFinal)) {
234     Handle(TDataStd_Integer) aWeakInt;
235     if (label().FindAttribute(weakID(), aWeakInt)) {
236       myWeakIndex = aWeakInt->Get();
237     }
238     return true;
239   }
240   return false;
241 }
242
243 TDF_Label Selector_Modify::restoreByName(std::string theName,
244   const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
245 {
246   typedef NCollection_DataMap<TopoDS_Shape, bool, TopTools_ShapeMapHasher> MapOfCompsolids;
247   MapOfCompsolids aWrongSubsCompsolids;
248
249   TDF_Label aContext;
250   for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
251     if (aStart != 0)
252       aStart++;
253     anEnd = theName.find('&', aStart);
254     std::string aSubStr =
255       theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
256     if (aSubStr.find(weakNameID()) == 0) { // weak name identifier
257       std::string aWeakIndex = aSubStr.substr(weakNameID().size());
258       myWeakIndex = atoi(aWeakIndex.c_str());
259       continue;
260     }
261     TDF_Label aSubContext, aValue;
262     if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
263       return TDF_Label(); // can not restore
264     if (aSubContext.IsNull() || (aValue.IsNull() && theShapeType <= TopAbs_SHELL))
265       return TDF_Label(); // can not restore
266     if (myFinal.IsNull()) {
267       myFinal = aValue;
268       aContext = aSubContext;
269     } else {
270       // This could be a solid in a compsolid, which was not modified by the previous operation,
271       // however, the selected subshape is stored on its sub-label by mistake. Thus, wait until
272       // the end of processing to check whether the subshape is found in another solid.
273       TDF_Label aParent = aSubContext.Father().Father();
274       Handle(TNaming_NamedShape) aNS;
275       if (aParent.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
276         TopoDS_Shape aShape = aNS->Get();
277         if (aShape.ShapeType() == TopAbs_COMPSOLID) {
278           if (aWrongSubsCompsolids.IsBound(aShape)) {
279             if (!aValue.IsNull())
280               aWrongSubsCompsolids.Bind(aShape, true);
281           } else
282             aWrongSubsCompsolids.Bind(aShape, !aValue.IsNull());
283         }
284       } else if (aValue.IsNull())
285         return TDF_Label();
286
287       if (!aValue.IsNull())
288         myBases.Append(aValue);
289     }
290   }
291
292   // check all compsolids are processed and names are resolved
293   for (MapOfCompsolids::Iterator anIt(aWrongSubsCompsolids); anIt.More(); anIt.Next())
294     if (!anIt.Value())
295       return TDF_Label();
296
297   return aContext;
298 }
299
300 bool Selector_Modify::solve(const TopoDS_Shape& theContext)
301 {
302   TopoDS_Shape aResult;
303   if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index
304     TopoDS_ListOfShape aCommon;
305     Handle(TNaming_NamedShape) aNS;
306     if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
307       for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
308         const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
309         if (!aNewShape.IsNull())
310           aCommon.Append(aNewShape);
311       }
312     }
313     Selector_NExplode aNexp(aCommon);
314     aResult = aNexp.shape(myWeakIndex);
315   } else { // standard case
316     TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
317     findModificationResult(aFinalsCommon);
318     if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape
319       aResult = aFinalsCommon.First();
320       findNewVersion(theContext, aResult);
321     } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) {
322       Selector_NExplode aNExp(aFinalsCommon);
323       aResult = aNExp.shape(myWeakIndex);
324       findNewVersion(theContext, aResult);
325     } else if (aFinalsCommon.Extent() > 1 && geometricalNaming()) {// if same geometry - compound
326       TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon);
327       TopoDS_Shape aFirst = aCommonIter.Value();
328       for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
329         if (!sameGeometry(aFirst, aCommonIter.Value()))
330           break;
331       }
332       if (!aCommonIter.More()) { // all geometry is same, create a result compound
333         TopoDS_Builder aBuilder;
334         TopoDS_Compound aCompound;
335         aBuilder.MakeCompound(aCompound);
336         for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) {
337           TopoDS_Shape aSub = aCommonIter.Value();
338           findNewVersion(theContext, aSub);
339           aBuilder.Add(aCompound, aSub);
340         }
341         aResult = aCompound;
342       }
343
344     }
345   }
346
347   if (!aResult.IsNull()) {
348     Selector_Algo::store(aResult);
349     return true;
350   }
351   return false;
352 }
353
354 std::string Selector_Modify::name(Selector_NameGenerator* theNameGenerator)
355 {
356   // final&base1&base2 +optionally: [weak_name_1]
357   std::string aResult;
358   Handle(TDataStd_Name) aName;
359   if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
360     return "";
361   aResult += theNameGenerator->contextName(myFinal) + "/" +
362     std::string(TCollection_AsciiString(aName->Get()).ToCString());
363   for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
364     if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
365       return "";
366     aResult += "&";
367     aResult += theNameGenerator->contextName(*aBase) + "/" +
368       std::string(TCollection_AsciiString(aName->Get()).ToCString());
369   }
370   if (myWeakIndex != -1) {
371     std::ostringstream aWeakStr;
372     aWeakStr<<"&"<<weakNameID()<<myWeakIndex;
373     aResult += aWeakStr.str();
374   }
375   return aResult;
376 }