-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathGeometryWriter.h
More file actions
248 lines (207 loc) · 10.2 KB
/
GeometryWriter.h
File metadata and controls
248 lines (207 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#ifndef PPP_GEOMETRY_WRITER_H
#define PPP_GEOMETRY_WRITER_H
#include "GeometryProcessor.h"
#include "OccUtils.h"
#include "PPP/Writer.h"
namespace Geom
{
using namespace PPP;
/// \ingroup Geom
/**
* \brief write out processed geometry into files
*/
class GeometryWriter : public Writer
{
TYPESYSTEM_HEADER();
private:
/// @{
Handle(XCAFDoc_ShapeTool) myShapeTool;
Handle(XCAFDoc_ColorTool) myColorTool;
Handle(XCAFDoc_MaterialTool) myMaterialTool;
std::vector<TDF_Label> myShapeLabels;
std::set<Standard_Integer> myRefShapes;
/// @}
bool mergeResultShapes = true;
std::shared_ptr<const ItemContainerType> mySolids;
std::shared_ptr<const MapType<ItemHashType, ShapeErrorType>> myShapeErrors;
public:
virtual void prepareInput() override final
{
/// NOTE: currently only deal with solid shapes
if (myInputData->contains("mySolids"))
mySolids = myInputData->getConst<ItemContainerType>("mySolids");
else
LOG_F(ERROR, "there is no mySolids property in myGeometryData");
// GeometryWriter is not derived from GeometryProcessor, so "myShapeErrors" is not available
if (myInputData->contains("myShapeErrors"))
myShapeErrors = myInputData->getConst<MapType<ItemHashType, ShapeErrorType>>("myShapeErrors");
else
LOG_F(ERROR, "myShapeErrors data entry is not available in the inputData");
}
virtual void process() override final
{
mergeResultShapes = parameterValue<bool>("mergeResultShapes", true);
std::string file_name = parameterValue<std::string>("dataFileName");
if (not fs::path(file_name).is_absolute())
file_name = dataStoragePath(file_name);
if (file_name.size())
{
exportGeometry(file_name);
LOG_F(INFO, "output the processed geometry as %s \n", file_name.c_str());
}
else
LOG_F(INFO, "output file name in configuration is empty, skip save geometry. \n");
}
protected:
void exportCompSolid(const std::string& file_name)
{
summary();
// actual merge happends here, instead of GeometryImprinter
TopoDS_Shape finalShape;
if (mergeResultShapes)
finalShape = OccUtils::glueFaces(OccUtils::createCompSolid(*mySolids, myShapeErrors));
else
{
LOG_F(INFO, "result is not merged (duplicated face removed) for result brep file");
finalShape = OccUtils::createCompSolid(*mySolids, myShapeErrors);
}
BRepTools::Write(finalShape, file_name.c_str()); // progress reporter can be the last arg
/// NOTE: exportMetaData() is done in the second GeometryPropertyBuilder processor
LOG_F(INFO, "save the processed geometry compoSolid into file: %s", file_name.c_str());
}
/** print loaded shapes statistics, before moved into propertyContainer
* this info could be output to log stream,*/
void summary()
{
auto count = 0UL;
for (const auto& p : (*myShapeErrors))
if (p.second == ShapeErrorType::NoError)
count++;
if (count == 0UL)
LOG_F(WARNING, "result solid count is zero");
std::stringstream sout;
sout << " ======= write geometry summary =======" << std::endl;
sout << "count of result solids is " << count << " out of total " << mySolids->size() << std::endl;
LOG_F(INFO, "%s", sout.str().c_str());
}
// TODO: query inputData() metadata for inputUnit
/// return 1 which means no scaling is needed
/// not quite useful for
double calcOutputScale(const std::string& outputUnit)
{
const std::string inputUnit = "MM";
if (outputUnit == inputUnit)
return 1;
else if ("MM" == inputUnit && outputUnit == "M")
return 0.001;
else
{
LOG_F(ERROR, "scaling for input length unit %s and output unit %s is not supported", inputUnit.c_str(),
outputUnit.c_str());
return 1;
}
}
/// can export floating shapes which can not be compoSolid
void exportCompound(const std::string& file_name, double scale = 1.0)
{
summary();
// actual merge happends here, instead of GeometryImprinter
TopoDS_Shape finalShape;
if (mergeResultShapes)
{
finalShape = OccUtils::glueFaces(OccUtils::createCompound(*mySolids, myShapeErrors));
VLOG_F(LOGLEVEL_DEBUG, "result shap is merged (duplicated face removed)");
}
else
{
LOG_F(INFO, "result is not merged (duplicated face removed) for result brep file");
finalShape = OccUtils::createCompound(*mySolids, myShapeErrors);
}
if (scale != 1) // double type has integer value can be compared with integer by ==
finalShape = OccUtils::scaleShape(finalShape, scale);
/// NOTE: exportMetaData() is done in the second GeometryPropertyBuilder processor
BRepTools::Write(finalShape, file_name.c_str()); // progress reporter can be the last arg
}
/** export result shape, only brep format can keep shared face topology during imprinting
* #export is a c++ keyword can not be used as function name
* */
bool exportGeometry(const std::string file_name)
{
std::string defaultLengthUnit = "MM";
auto outputUnit = parameterValue<std::string>("outputUnit", defaultLengthUnit);
double scale = calcOutputScale(outputUnit);
if (Utilities::hasFileExt(file_name, "brp") || Utilities::hasFileExt(file_name, "brep"))
{
exportCompound(file_name, scale);
return true;
}
else if (Utilities::hasFileExt(file_name, "stp") || Utilities::hasFileExt(file_name, "step"))
{
// LOG_F(INFO, "export Dataset pointed by member hDoc");
Handle(TDocStd_Document) aDoc = createDocument(scale);
/// the user can work with an already prepared WorkSession or create a new one
Standard_Boolean scratch = Standard_False;
Handle(XSControl_WorkSession) WS = new XSControl_WorkSession();
/// NOTE: length unit is controlled here, default "MM", PrecisionMode
STEPControl_StepModelType mode = STEPControl_AsIs;
// recommended value, others shape mode are available
// Interface_Static::SetCVal("write.step.schema", "AP214IS");
Interface_Static::SetIVal("write.step.assembly", 1); // global variable
// Interface_Static::SetIVal ("write.step.nonmanifold", 1);
// "write.precision.val" = 0.0001 is the default value
if (outputUnit != defaultLengthUnit)
{
Interface_Static::SetCVal("xstep.cascade.unit", outputUnit.c_str());
Interface_Static::SetCVal("write.step.unit", outputUnit.c_str());
// all vertex coordinate will not be scaled during writing out, change unit,
// but it causes scaling at reading back
}
STEPCAFControl_Writer writer(WS, scratch);
// this writer contains a STEPControl_Writer class, not by inheritance
// writer.SetColorMode(mode);
if (!writer.Transfer(aDoc, mode))
{
LOG_F(ERROR, "The Dataset cannot be translated or gives no result");
}
IFSelect_ReturnStatus stat = writer.Write(file_name.c_str());
return (IFSelect_RetDone == stat);
}
else
{
LOG_F(ERROR, "The Dataset cannot be exported in the suffix format");
return false;
}
return false;
}
Handle(TDocStd_Document) createDocument(double scale = 1)
{
Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication();
Handle(TDocStd_Document) newDoc; // the new doc
/// NOTE: "MDTV-CAF" is deprecated, readonly, using xml or binary format
hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), newDoc);
Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(newDoc->Main());
Handle(XCAFDoc_ColorTool) colorTool = XCAFDoc_DocumentTool::ColorTool(newDoc->Main());
Handle(XCAFDoc_MaterialTool) materialTool = XCAFDoc_DocumentTool::MaterialTool(newDoc->Main());
auto myColorMap = myInputData->get<MapType<Standard_Integer, Quantity_Color>>("myColorMap");
auto myNameMap = myInputData->get<MapType<Standard_Integer, std::string>>("myNameMap");
/// material is not supported yet: auto myMaterialMap =
/// see: https://www.opencascade.com/content/exporting-step-assembly-what-am-i-doing-wrong
size_t i = 0U;
for (auto& item : *mySolids)
{
TDF_Label partLabel = shapeTool->NewShape();
if (scale != 1)
shapeTool->SetShape(partLabel, OccUtils::scaleShape(item.second, scale));
else
shapeTool->SetShape(partLabel, item.second);
colorTool->SetColor(partLabel, (*myColorMap)[item.first], XCAFDoc_ColorGen);
TDataStd_Name::Set(partLabel, TCollection_ExtendedString((*myNameMap)[item.first].c_str(), true));
/// Material not yet supported
i++;
}
shapeTool->UpdateAssemblies(); // OCCT 7.2 will not automatically update, so must explicitly call this func
return newDoc;
}
}; // end of class
} // namespace Geom
#endif