Salome HOME
updated copyright message
[modules/shaper.git] / src / Model / Model_Tools.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
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       if (aTargetAttr->ID() != anAttrIter.Value()->ID())
66         aTargetAttr->SetID(anAttrIter.Value()->ID());
67       theDestination.AddAttribute(aTargetAttr);
68     }
69     // no special relocation, empty map, but self-relocation is on: copy references w/o changes
70     Handle(TDF_RelocationTable) aRelocTable =
71         theRelocTable.IsNull() ? new TDF_RelocationTable(Standard_True) : theRelocTable;
72     anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
73     // an exception: if a source reference refers itself, a copy must also refer itself
74     if (aTargetAttr->ID() == TDF_Reference::GetID()) {
75       Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
76       if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label()))
77         aTargetRef->Set(aTargetRef->Label());
78     }
79   }
80   // copy the sub-labels content
81   TDF_ChildIterator aSubLabsIter(theSource);
82   for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
83     copyAttrs(aSubLabsIter.Value(),
84               theDestination.FindChild(aSubLabsIter.Value().Tag()),
85               theRelocTable);
86   }
87 }
88
89 static TCollection_AsciiString labelToString(TDF_Label theLabel)
90 {
91   TCollection_AsciiString aLabString;
92   TDF_Tool::Entry(theLabel, aLabString);
93   return aLabString;
94 }
95
96 static void makeExternalReference(TDF_Label theDestination, TDF_Label theReferred)
97 {
98   Handle(TDF_Attribute) aReference, aComment, aString;
99   theDestination.FindAttribute(TDF_Reference::GetID(), aReference);
100   // create new attributes if not yet exists in the destination
101   if (!theDestination.FindAttribute(TDataStd_Comment::GetID(), aComment)) {
102     aComment = new TDataStd_Comment;
103     theDestination.AddAttribute(aComment);
104   }
105   if (!theDestination.FindAttribute(TDataStd_AsciiString::GetID(), aString)) {
106     aString = new TDataStd_AsciiString;
107     theDestination.AddAttribute(aString);
108   }
109   // reference to itself
110   Handle(TDF_Reference)::DownCast(aReference)->Set(theDestination, theDestination);
111   // ID of the document
112   std::ostringstream aDocIdStr;
113   aDocIdStr << ModelAPI_Session::get()->moduleDocument()->id();
114   Handle(TDataStd_Comment)::DownCast(aComment)->Set(aDocIdStr.str().c_str());
115   // value of referred label
116   Handle(TDataStd_AsciiString)::DownCast(aString)->Set(labelToString(theReferred));
117 }
118
119 void Model_Tools::copyAttrsAndKeepRefsToCoordinates(
120     TDF_Label theSource,
121     TDF_Label theDestination,
122     const std::set<TCollection_AsciiString>& theCoordinateLabels,
123     Handle(TDF_RelocationTable) theRelocTable)
124 {
125   TDF_AttributeIterator anAttrIter(theSource);
126   for(; anAttrIter.More(); anAttrIter.Next()) {
127     Handle(TDF_Attribute) aTargetAttr;
128     if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
129       // create a new attribute if not yet exists in the destination
130             aTargetAttr = anAttrIter.Value()->NewEmpty();
131       if (aTargetAttr->ID() != anAttrIter.Value()->ID())
132         aTargetAttr->SetID(anAttrIter.Value()->ID());
133       theDestination.AddAttribute(aTargetAttr);
134     }
135     anAttrIter.Value()->Paste(aTargetAttr, theRelocTable);
136     if (aTargetAttr->ID() == TDF_Reference::GetID()) {
137       Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
138       if (aTargetRef->Get().IsNull()) {
139         // may be refer to a cartesian coordinate entity
140         Handle(TDF_Reference) aSourceRef = Handle(TDF_Reference)::DownCast(anAttrIter.Value());
141         if (!aSourceRef.IsNull() && !aSourceRef->Get().IsNull()) {
142           std::set<TCollection_AsciiString>::const_iterator aFound =
143               theCoordinateLabels.find(labelToString(aSourceRef->Get()));
144           if (aFound != theCoordinateLabels.end())
145             makeExternalReference(theDestination, aSourceRef->Get());
146         }
147       }
148       else if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label())) {
149         // a source reference refers itself, a copy must also refer itself
150         aTargetRef->Set(aTargetRef->Label());
151       }
152     }
153   }
154   // copy the sub-labels content
155   TDF_ChildIterator aSubLabsIter(theSource);
156   for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
157     copyAttrsAndKeepRefsToCoordinates(
158         aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()),
159         theCoordinateLabels, theRelocTable);
160   }
161 }
162
163 void Model_Tools::labelsOfCoordinates(std::set<TCollection_AsciiString>& theCoordinateLabels,
164                                       Handle(TDF_RelocationTable) theRelocTable)
165 {
166   DocumentPtr aPartSet = ModelAPI_Session::get()->moduleDocument();
167   std::list<FeaturePtr> aFeatures = aPartSet->allFeatures();
168   for (std::list<FeaturePtr>::iterator aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
169     FeaturePtr aCurFeat = *aFIt;
170     if (!aCurFeat->isInHistory() &&
171         (aCurFeat->getKind() == ConstructionPlugin_Point::ID() ||
172          aCurFeat->getKind() == ConstructionPlugin_Axis::ID() ||
173          aCurFeat->getKind() == ConstructionPlugin_Plane::ID())) {
174       ResultPtr aResult = aCurFeat->lastResult();
175       if (aResult) {
176         std::shared_ptr<Model_Data> aResData =
177             std::dynamic_pointer_cast<Model_Data>(aResult->data());
178         TDF_Label aLab = aResData->label().Father();
179         theCoordinateLabels.insert(labelToString(aLab));
180         // set relocation to empty, references will be set correctly while copying attributes
181         theRelocTable->SetRelocation(aLab, TDF_Label());
182       }
183     }
184   }
185 }