1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <Selector_Modify.h>
23 #include <Selector_NameGenerator.h>
24 #include <Selector_NExplode.h>
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>
38 #include <TopoDS_Builder.hxx>
39 #include <TopoDS_Compound.hxx>
41 Selector_Modify::Selector_Modify() : Selector_Algo()
43 myWeakIndex = -1; // no index by default
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)
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))
67 if (!aResIter.More()) // not found, so add this new
68 theResult.Append(aResult);
69 aFoundAnyShape = true;
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;
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);
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)
96 if (TNaming_Tool::HasLabel(anAccess, theBase)) {
97 for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next())
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());
104 findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults);
109 if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label
110 static TDF_Label anEmpty;
111 findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults);
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();
121 TopTools_MapOfShape aFinals;
122 for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) {
123 findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals);
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());
130 } else { // keep only shapes presented in both lists
131 for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) {
132 if (aFinals.Contains(aCommon.Value())) {
134 } else { // common is not found, remove it
135 theCommon.Remove(aCommon);
143 bool Selector_Modify::select(NCollection_List<Handle(TNaming_NamedShape)>& theModifList,
144 const TopoDS_Shape theContext, const TopoDS_Shape theValue)
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();
162 // take the best candidate, or the last in the iteration
163 theModifList.Clear();
164 theModifList.Append(aCandidate);
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()))
183 if (!aCommonIter.More()) { // all geometry is same, result is a compound
187 } else if (aCommon.Extent() == 1) {
188 return true; // simple modification
192 TopoDS_ListOfShape aCommon;
193 myFinal = theModifList.First()->Label();
194 Handle(TNaming_NamedShape) aNS;
195 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
196 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
197 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
198 if (!aNewShape.IsNull())
199 aCommon.Append(aNewShape);
202 Selector_NExplode aNexp(aCommon);
203 myWeakIndex = aNexp.index(theValue);
204 return myWeakIndex != -1;
209 void Selector_Modify::store()
211 storeType(Selector_Algo::SELTYPE_MODIFICATION);
212 storeBaseArray(myBases, myFinal);
213 if (myWeakIndex != -1) {
214 TDataStd_Integer::Set(label(), weakID(), myWeakIndex);
218 bool Selector_Modify::restore()
220 if (restoreBaseArray(myBases, myFinal)) {
221 Handle(TDataStd_Integer) aWeakInt;
222 if (label().FindAttribute(weakID(), aWeakInt)) {
223 myWeakIndex = aWeakInt->Get();
230 TDF_Label Selector_Modify::restoreByName(std::string theName,
231 const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator)
234 for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) {
237 anEnd = theName.find('&', aStart);
238 std::string aSubStr =
239 theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart);
240 if (aSubStr.find(weakNameID()) == 0) { // weak name identifier
241 std::string aWeakIndex = aSubStr.substr(weakNameID().size());
242 myWeakIndex = atoi(aWeakIndex.c_str());
245 TDF_Label aSubContext, aValue;
246 if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue))
247 return TDF_Label(); // can not restore
248 if(aSubContext.IsNull() || aValue.IsNull())
249 return TDF_Label(); // can not restore
250 if (myFinal.IsNull()) {
252 aContext = aSubContext;
254 myBases.Append(aValue);
259 bool Selector_Modify::solve(const TopoDS_Shape& theContext)
261 TopoDS_Shape aResult;
262 if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index
263 TopoDS_ListOfShape aCommon;
264 Handle(TNaming_NamedShape) aNS;
265 if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
266 for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) {
267 const TopoDS_Shape& aNewShape = aFinalIter.NewShape();
268 if (!aNewShape.IsNull())
269 aCommon.Append(aNewShape);
272 Selector_NExplode aNexp(aCommon);
273 aResult = aNexp.shape(myWeakIndex);
274 } else { // standard case
275 TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases
276 findModificationResult(aFinalsCommon);
277 if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape
278 aResult = aFinalsCommon.First();
279 } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) {
280 Selector_NExplode aNExp(aFinalsCommon);
281 aResult = aNExp.shape(myWeakIndex);
282 } else if (aFinalsCommon.Extent() > 1 && geometricalNaming()) {// if same geometry - compound
283 TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon);
284 TopoDS_Shape aFirst = aCommonIter.Value();
285 for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
286 if (!sameGeometry(aFirst, aCommonIter.Value()))
289 if (!aCommonIter.More()) { // all geometry is same, create a result compound
290 TopoDS_Builder aBuilder;
291 TopoDS_Compound aCompound;
292 aBuilder.MakeCompound(aCompound);
293 for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) {
294 aBuilder.Add(aCompound, aCommonIter.Value());
302 if (!aResult.IsNull()) {
303 Selector_Algo::store(aResult);
309 std::string Selector_Modify::name(Selector_NameGenerator* theNameGenerator)
311 // final&base1&base2 +optionally: [weak_name_1]
313 Handle(TDataStd_Name) aName;
314 if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName))
316 aResult += theNameGenerator->contextName(myFinal) + "/" +
317 std::string(TCollection_AsciiString(aName->Get()).ToCString());
318 for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) {
319 if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName))
322 aResult += theNameGenerator->contextName(*aBase) + "/" +
323 std::string(TCollection_AsciiString(aName->Get()).ToCString());
325 if (myWeakIndex != -1) {
326 std::ostringstream aWeakStr;
327 aWeakStr<<"&"<<weakNameID()<<myWeakIndex;
328 aResult += aWeakStr.str();