Salome HOME
Implementation of Open/Save and Break-Link functionality on SHAPER shapes
[modules/shaper.git] / src / Model / Model_Tools.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 <Model_Tools.h>
21 #include <Model_Data.h>
22
23 #include <ModelAPI_Document.h>
24 #include <ModelAPI_Feature.h>
25 #include <ModelAPI_Result.h>
26 #include <ModelAPI_Session.h>
27
28 #include <ConstructionPlugin_Axis.h>
29 #include <ConstructionPlugin_Plane.h>
30 #include <ConstructionPlugin_Point.h>
31
32 #include <Standard_GUID.hxx>
33
34 #include <TDataStd_Comment.hxx>
35 #include <TDataStd_AsciiString.hxx>
36
37 #include <TDF_AttributeIterator.hxx>
38 #include <TDF_ChildIterator.hxx>
39 #include <TDF_Reference.hxx>
40 #include <TDF_RelocationTable.hxx>
41 #include <TDF_Tool.hxx>
42
43 void Model_Tools::copyLabels(TDF_Label theSource, TDF_Label theDestination,
44                              Handle(TDF_RelocationTable) theRelocTable)
45 {
46   theRelocTable->SetRelocation(theSource, theDestination);
47   // copy the sub-labels hierarchy
48   TDF_ChildIterator aSubLabsIter(theSource);
49   for (; aSubLabsIter.More(); aSubLabsIter.Next()) {
50     copyLabels(aSubLabsIter.Value(),
51                theDestination.FindChild(aSubLabsIter.Value().Tag()),
52                theRelocTable);
53   }
54 }
55
56 void Model_Tools::copyAttrs(TDF_Label theSource, TDF_Label theDestination,
57                             Handle(TDF_RelocationTable) theRelocTable)
58 {
59   TDF_AttributeIterator anAttrIter(theSource);
60   for(; anAttrIter.More(); anAttrIter.Next()) {
61     Handle(TDF_Attribute) aTargetAttr;
62     if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
63       // create a new attribute if not yet exists in the destination
64             aTargetAttr = anAttrIter.Value()->NewEmpty();
65       theDestination.AddAttribute(aTargetAttr);
66     }
67     // no special relocation, empty map, but self-relocation is on: copy references w/o changes
68     Handle(TDF_RelocationTable) aRelocTable =
69         theRelocTable.IsNull() ? new TDF_RelocationTable(Standard_True) : theRelocTable;
70     anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
71     // an exception: if a source reference refers itself, a copy must also refer itself
72     if (aTargetAttr->ID() == TDF_Reference::GetID()) {
73       Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
74       if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label()))
75         aTargetRef->Set(aTargetRef->Label());
76     }
77   }
78   // copy the sub-labels content
79   TDF_ChildIterator aSubLabsIter(theSource);
80   for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
81     copyAttrs(aSubLabsIter.Value(),
82               theDestination.FindChild(aSubLabsIter.Value().Tag()),
83               theRelocTable);
84   }
85 }
86
87 static TCollection_AsciiString labelToString(TDF_Label theLabel)
88 {
89   TCollection_AsciiString aLabString;
90   TDF_Tool::Entry(theLabel, aLabString);
91   return aLabString;
92 }
93
94 static void makeExternalReference(TDF_Label theDestination, TDF_Label theReferred)
95 {
96   Handle(TDF_Attribute) aReference, aComment, aString;
97   theDestination.FindAttribute(TDF_Reference::GetID(), aReference);
98   // create new attributes if not yet exists in the destination
99   if (!theDestination.FindAttribute(TDataStd_Comment::GetID(), aComment)) {
100     aComment = new TDataStd_Comment;
101     theDestination.AddAttribute(aComment);
102   }
103   if (!theDestination.FindAttribute(TDataStd_AsciiString::GetID(), aString)) {
104     aString = new TDataStd_AsciiString;
105     theDestination.AddAttribute(aString);
106   }
107   // reference to itself
108   Handle(TDF_Reference)::DownCast(aReference)->Set(theDestination, theDestination);
109   // ID of the document
110   std::ostringstream aDocIdStr;
111   aDocIdStr << ModelAPI_Session::get()->moduleDocument()->id();
112   Handle(TDataStd_Comment)::DownCast(aComment)->Set(aDocIdStr.str().c_str());
113   // value of referred label
114   Handle(TDataStd_AsciiString)::DownCast(aString)->Set(labelToString(theReferred));
115 }
116
117 void Model_Tools::copyAttrsAndKeepRefsToCoordinates(
118     TDF_Label theSource,
119     TDF_Label theDestination,
120     const std::set<TCollection_AsciiString>& theCoordinateLabels,
121     Handle(TDF_RelocationTable) theRelocTable)
122 {
123   TDF_AttributeIterator anAttrIter(theSource);
124   for(; anAttrIter.More(); anAttrIter.Next()) {
125     Handle(TDF_Attribute) aTargetAttr;
126     if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
127       // create a new attribute if not yet exists in the destination
128             aTargetAttr = anAttrIter.Value()->NewEmpty();
129       theDestination.AddAttribute(aTargetAttr);
130     }
131     anAttrIter.Value()->Paste(aTargetAttr, theRelocTable);
132     if (aTargetAttr->ID() == TDF_Reference::GetID()) {
133       Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
134       if (aTargetRef->Get().IsNull()) {
135         // may be refer to a cartesian coordinate entity
136         Handle(TDF_Reference) aSourceRef = Handle(TDF_Reference)::DownCast(anAttrIter.Value());
137         if (!aSourceRef.IsNull() && !aSourceRef->Get().IsNull()) {
138           std::set<TCollection_AsciiString>::const_iterator aFound =
139               theCoordinateLabels.find(labelToString(aSourceRef->Get()));
140           if (aFound != theCoordinateLabels.end())
141             makeExternalReference(theDestination, aSourceRef->Get());
142         }
143       }
144       else if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label())) {
145         // a source reference refers itself, a copy must also refer itself
146         aTargetRef->Set(aTargetRef->Label());
147       }
148     }
149   }
150   // copy the sub-labels content
151   TDF_ChildIterator aSubLabsIter(theSource);
152   for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
153     copyAttrsAndKeepRefsToCoordinates(
154         aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()),
155         theCoordinateLabels, theRelocTable);
156   }
157 }
158
159 void Model_Tools::labelsOfCoordinates(std::set<TCollection_AsciiString>& theCoordinateLabels,
160                                       Handle(TDF_RelocationTable) theRelocTable)
161 {
162   DocumentPtr aPartSet = ModelAPI_Session::get()->moduleDocument();
163   std::list<FeaturePtr> aFeatures = aPartSet->allFeatures();
164   for (std::list<FeaturePtr>::iterator aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
165     FeaturePtr aCurFeat = *aFIt;
166     if (!aCurFeat->isInHistory() &&
167         (aCurFeat->getKind() == ConstructionPlugin_Point::ID() ||
168          aCurFeat->getKind() == ConstructionPlugin_Axis::ID() ||
169          aCurFeat->getKind() == ConstructionPlugin_Plane::ID())) {
170       ResultPtr aResult = aCurFeat->lastResult();
171       if (aResult) {
172         std::shared_ptr<Model_Data> aResData =
173             std::dynamic_pointer_cast<Model_Data>(aResult->data());
174         TDF_Label aLab = aResData->label().Father();
175         theCoordinateLabels.insert(labelToString(aLab));
176         // set relocation to empty, references will be set correctly while copying attributes
177         theRelocTable->SetRelocation(aLab, TDF_Label());
178       }
179     }
180   }
181 }