Salome HOME
using a better solution to do compare doubles for shape physical properties
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_STEPExport.cpp
1 // Copyright (C) 2014-2024  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 <GeomAlgoAPI_STEPExport.h>
21
22 #include "GeomAlgoAPI_Tools.h"
23
24 #include <GeomAPI_Shape.h>
25 #include <ModelAPI_ResultBody.h>
26 #include <ModelAPI_AttributeIntArray.h>
27
28 #include <TDocStd_Document.hxx>
29 #include <TDataStd_Name.hxx>
30 #include <XCAFDoc_DocumentTool.hxx>
31 #include <XCAFDoc_ShapeTool.hxx>
32 #include <XCAFDoc_ColorTool.hxx>
33 #include <STEPCAFControl_Writer.hxx>
34 #include <StepData_StepModel.hxx>
35 #include <UnitsMethods.hxx>
36 #include <Interface_Static.hxx>
37 #include <Quantity_Color.hxx>
38
39 #include <Basics_OCCTVersion.hxx>
40
41 // a structure to manage step document exported attributes
42 struct GeomAlgoAPI_STEPAttributes {
43   bool myHasColor; ///< true if color is defined
44   Quantity_Color myColor;
45   std::wstring myName;
46   Handle(XCAFDoc_ShapeTool) myShapeTool;
47   Handle(XCAFDoc_ColorTool) myColorTool;
48
49   GeomAlgoAPI_STEPAttributes(const TDF_Label& theMain) : myHasColor(false)
50   {
51     myShapeTool = XCAFDoc_DocumentTool::ShapeTool(theMain);
52     myShapeTool->SetAutoNaming(Standard_False);
53     myColorTool = XCAFDoc_DocumentTool::ColorTool(theMain);
54   }
55 };
56
57 static TDF_Label exportShape(const GeomShapePtr theShape, GeomAlgoAPI_STEPAttributes& theAttrs,
58   const GeomShapePtr theFatherShape, TDF_Label& theFaterID) {
59   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
60   TDF_Label aShapeLab;
61   if (!theFaterID.IsNull()) { // make sub-component of father's assembly
62     gp_Trsf aFatherTrsf;
63     if (theFatherShape.get())
64       aFatherTrsf = theFatherShape->implPtr<TopoDS_Shape>()->Location().Transformation();
65     TopLoc_Location aLocation = aFatherTrsf.Inverted() * aShape.Location();
66     static const TopLoc_Location anEmptyLoc;
67     aShape.Location(anEmptyLoc);
68     aShapeLab = theAttrs.myShapeTool->AddShape(aShape, Standard_False);
69     TDF_Label aRetLabel = theAttrs.myShapeTool->AddComponent(theFaterID, aShapeLab, aLocation);
70     if (!aRetLabel.IsNull())
71       aRetLabel.ForgetAttribute(TDataStd_Name::GetID());
72   }
73   else { // make a single shape
74     aShapeLab = theAttrs.myShapeTool->AddShape(aShape, Standard_False);
75     TDF_Label aRefShapeLab;
76     if (theAttrs.myShapeTool->GetReferredShape(aShapeLab, aRefShapeLab))
77       aShapeLab = aRefShapeLab;
78   }
79   TDataStd_Name::Set(aShapeLab, TCollection_ExtendedString(theAttrs.myName.c_str()));
80   if (theAttrs.myHasColor) {
81     TDF_Label aColorLab = theAttrs.myColorTool->AddColor(theAttrs.myColor);
82     theAttrs.myColorTool->SetColor(aShapeLab, aColorLab, XCAFDoc_ColorGen);
83   }
84   return aShapeLab;
85 }
86
87 /// Returns the attributes of the result: names and color
88 static void getAttributes(const ResultPtr& theResult, GeomAlgoAPI_STEPAttributes& theAttrs)
89 {
90   theAttrs.myName = theResult->data()->name();
91   AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
92   if (aColorAttr.get() && aColorAttr->size() > 2) {
93     theAttrs.myHasColor = true;
94     theAttrs.myColor.SetValues(aColorAttr->value(0) / 255., aColorAttr->value(1) / 255.,
95                                aColorAttr->value(2) / 255., Quantity_TOC_RGB);
96   }
97   else
98     theAttrs.myHasColor = false;
99 }
100
101 /// Performs the whole result export: as an assembly or a single one, but with results attributes.
102 static void putResult(const ResultPtr& theResult, const GeomShapePtr theFatherShape,
103   TDF_Label& theFaterID, GeomAlgoAPI_STEPAttributes& theAttrs)
104 {
105   GeomShapePtr aShape = theResult->shape();
106   if (!aShape.get() || aShape->isNull())
107     return;
108   ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
109   if (aBody.get() && aBody->numberOfSubs()) { // make an assembly
110     getAttributes(theResult, theAttrs);
111     TDF_Label aBodyID = exportShape(aShape, theAttrs, theFatherShape, theFaterID);
112     int aNumSubs = aBody->numberOfSubs();
113     for (int a = 0; a < aNumSubs; a++) {
114       ResultBodyPtr aSub = aBody->subResult(a);
115       if (!aSub->isDisabled())
116         putResult(aSub, aShape, aBodyID, theAttrs);
117     }
118   }
119   else { // a simple shape-body
120     getAttributes(theResult, theAttrs);
121     exportShape(aShape, theAttrs, theFatherShape, theFaterID);
122   }
123 }
124
125 bool STEPExport(const std::string& theFileName,
126                 const std::list<std::shared_ptr<GeomAPI_Shape> >& theShapes,
127                 const std::list<std::shared_ptr<ModelAPI_Result> >& theResults,
128                 std::string& theError)
129 {
130   theError = "";
131   // prepare XCAF document to store the whole data structure there
132   Handle(TDocStd_Document) aDoc = new TDocStd_Document("BinXCAF");
133
134   GeomAlgoAPI_STEPAttributes anAttrs(aDoc->Main());
135
136   std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aShape = theShapes.cbegin();
137   std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResult = theResults.cbegin();
138   for (; aShape != theShapes.cend(); aShape++, aResult++) {
139     TDF_Label aNullLab;
140     if (aResult->get() && !(*aShape)->isSame((*aResult)->shape()))
141     { // simple sub-shape
142       getAttributes(*aResult, anAttrs);
143       exportShape(*aShape, anAttrs, GeomShapePtr(), aNullLab);
144     }
145     else { // whole result selection
146       putResult(*aResult, GeomShapePtr(), aNullLab, anAttrs);
147     }
148   }
149   // store the XCAF document to STEP file
150   try {
151     GeomAlgoAPI_Tools::Localizer aLocalizer; // Set "C" numeric locale to save numbers correctly
152
153 #if OCC_VERSION_LARGE < 0x07070000
154     STEPCAFControl_Writer aWriter;
155     Interface_Static::SetCVal("xstep.cascade.unit", "M");
156     Interface_Static::SetIVal("write.step.nonmanifold", 0); // 1 don't allow to export assemly tree
157     Interface_Static::SetCVal("write.step.unit", "M");
158 #elif OCC_VERSION_LARGE < 0x07080000
159     STEPCAFControl_Writer aWriterTmp;
160     Interface_Static::SetCVal("xstep.cascade.unit", "M");
161     Interface_Static::SetIVal("write.step.nonmanifold", 0); // 1 don't allow to export assemly tree
162     Interface_Static::SetCVal("write.step.unit", "M");
163     STEPCAFControl_Writer aWriter;
164 #else
165     STEPCAFControl_Writer aWriter;
166     Interface_Static::SetCVal("xstep.cascade.unit", "M");
167     Interface_Static::SetIVal("write.step.nonmanifold", 0); // 1 don't allow to export assemly tree
168     Interface_Static::SetCVal("write.step.unit", "M");
169     Handle(StepData_StepModel) aModel = aWriter.ChangeWriter().Model();
170     aModel->InternalParameters.InitFromStatic();
171     Standard_Integer aWriteUnitInt = Interface_Static::IVal("write.step.unit");
172     Standard_Real aWriteUnitReal = UnitsMethods::GetLengthFactorValue(aWriteUnitInt);
173     aModel->SetWriteLengthUnit(aWriteUnitReal);
174 #endif
175
176     auto aStatus = aWriter.Transfer(aDoc, STEPControl_AsIs);
177     if (aStatus == IFSelect_RetDone)
178       aStatus = aWriter.Write(theFileName.c_str());
179     if (aStatus != IFSelect_RetDone)
180       theError = "STEP Export failed";
181   }
182   catch (Standard_Failure&) {
183     theError = "Exception catched in STEPExport";
184   }
185   return theError.empty();
186 }