ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
STEPFilter.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "../include/STEPFilter.h"
9 
10 // Qt
11 #include <QFile>
12 #include <QFileInfo>
13 #include <QInputDialog>
14 
15 // CV_CORE_LIB
16 #include <CVLog.h>
17 
18 // CV_DB_LIB
19 #include <ecvMesh.h>
20 #include <ecvPointCloud.h>
21 
22 // Include OpenCascade :
23 #include "BRepBuilderAPI_MakeFace.hxx"
24 #include "BRepBuilderAPI_MakePolygon.hxx"
25 #include "BRepBuilderAPI_MakeSolid.hxx"
26 #include "BRepBuilderAPI_Sewing.hxx"
27 #include "BRepMesh_FastDiscret.hxx"
28 #include "BRepMesh_IncrementalMesh.hxx"
29 #include "BRepTools.hxx"
30 #include "BRep_Builder.hxx"
31 #include "IFSelect_PrintCount.hxx"
32 #include "IFSelect_ReturnStatus.hxx"
33 #include "Interface_Static.hxx"
34 #include "NCollection_List.hxx"
35 #include "Poly_Triangulation.hxx"
36 #include "STEPControl_Reader.hxx"
37 #include "TColgp_Array1OfPnt.hxx"
38 #include "TopAbs_ShapeEnum.hxx"
39 #include "TopExp.hxx"
40 #include "TopExp_Explorer.hxx"
41 #include "TopTools.hxx"
42 #include "TopTools_ListOfShape.hxx"
43 #include "TopoDS.hxx"
44 #include "TopoDS_Compound.hxx"
45 #include "TopoDS_Shell.hxx"
46 #include "TopoDS_Solid.hxx"
47 
48 using namespace std;
49 
50 static std::map<TopAbs_ShapeEnum, QString> ShapeTypes{
51  {TopAbs_COMPOUND, "TopAbs_COMPOUND"},
52  {TopAbs_COMPSOLID, "TopAbs_COMPSOLID"},
53  {TopAbs_SOLID, "TopAbs_SOLID"},
54  {TopAbs_SHELL, "TopAbs_SHELL"},
55  {TopAbs_FACE, "TopAbs_FACE"},
56  {TopAbs_WIRE, "TopAbs_WIRE"},
57  {TopAbs_EDGE, "TopAbs_EDGE"},
58  {TopAbs_VERTEX, "TopAbs_VERTEX"},
59  {TopAbs_SHAPE, "TopAbs_SHAPE"}};
60 
62  : FileIOFilter({"_STEP OpenCascade Filter",
63  DEFAULT_PRIORITY, // priority
64  QStringList{"step", "stp"}, "step",
65  QStringList{"STEP CAD file (*.step *.stp)"}, QStringList(),
66  Import}) {}
67 
68 static double s_defaultLinearDeflection = 1.0e-3;
69 
71  if (value < 1.0e-6) {
72  CVLog::Warning("[STEP] Input linear deflection is too small");
73  return;
74  }
75  if (value > 1.0e-2) {
76  CVLog::Warning("[STEP] Input linear deflection is too big");
77  return;
78  }
80 }
81 
82 CC_FILE_ERROR STEPFilter::loadFile(const QString& fullFilename,
83  ccHObject& container,
84  LoadParameters& parameters) {
85  // check for the file existence
86  QFileInfo fi(fullFilename);
87  if (!fi.exists()) {
88  return CC_FERR_UNKNOWN_FILE;
89  }
90 
91  double linearDeflection = s_defaultLinearDeflection;
92  if (parameters.parentWidget) {
93  bool ok = false;
94  linearDeflection = QInputDialog::getDouble(
95  parameters.parentWidget, "Linear deflection",
96  "Linear deflection", s_defaultLinearDeflection, 1.0e-6, 1.0e-2,
97  6, &ok);
98  if (!ok) {
100  }
101  }
102 
104  try {
105  error = importStepFile(container, fullFilename, linearDeflection,
106  parameters);
107  } catch (...) {
109  }
110 
111  return error;
112 }
113 
115  const QString& fullFileName,
116  double linearDeflection,
117  LoadParameters& parameters) {
118  Interface_Static::SetCVal("xstep.cascade.unit", "M");
119 
120  STEPControl_Reader aReader;
121  IFSelect_ReturnStatus aStatus =
122  aReader.ReadFile(qUtf8Printable(fullFileName));
123  if (aStatus != IFSelect_ReturnStatus::IFSelect_RetDone) {
125  }
126 
127  // bool isFailsonly = false;
128  // aReader.PrintCheckLoad(isFailsonly,
129  // IFSelect_PrintCount::IFSelect_ItemsByEntity);
130  // aReader.PrintCheckTransfer(isFailsonly,
131  // IFSelect_PrintCount::IFSelect_ItemsByEntity);
132 
133  // Collecting entities inside the STEP file
134  int rootCount = aReader.NbRootsForTransfer();
135  if (rootCount < 1) {
136  CVLog::Warning("No root found in the STEP file.");
137  return CC_FERR_NO_LOAD;
138  }
139  CVLog::Print(QString("[STEP] Number of root(s): %1").arg(rootCount));
140 
141  for (Standard_Integer n = 1; n <= rootCount; n++) {
142  if (!aReader.TransferRoot(n)) {
144  QString("[STEP] Failed to transfer root #%1").arg(n));
145  }
146  }
147  // Root transfers
148  int transferredRootCount = aReader.TransferRoots();
149  if (transferredRootCount < 1) {
150  CVLog::Warning("No root could be transferred from the STEP file.");
151  return CC_FERR_NO_LOAD;
152  }
153 
154  Standard_Integer shapeCount = aReader.NbShapes();
155  if (shapeCount == 0) {
156  CVLog::Warning("No shape found in the STEP file.");
157  return CC_FERR_NO_LOAD;
158  }
159  CVLog::Print(QString("[STEP] Number of shapes: %1").arg(shapeCount));
160 
161  TopoDS_Shape aShape = aReader.OneShape();
162  CVLog::Print("[STEP] Shape type: " + ShapeTypes[aShape.ShapeType()]);
163 
164  BRepMesh_IncrementalMesh incrementalMesh(
165  aShape, linearDeflection,
166  Standard_True); // not explicitly used, but still needs to be
167  // instantiated
168 
169  // Creation of the CC vertices and mesh
170  ccPointCloud* vertices = new ccPointCloud("vertices");
171  vertices->setEnabled(false);
172  ccMesh* mesh = new ccMesh(vertices);
173  mesh->addChild(vertices);
174  mesh->setName("unnamed - tesselated");
175 
176  // Notice that the nodes are duplicated during CAD tesslation : if a node is
177  // belonging to N triangles, it's duplicated N times.
178  unsigned faceCount = 0;
179  unsigned triCount =
180  0; // Number of triangles of the tesselated CAD shape imported
181  unsigned vertCount = 0;
182  TopExp_Explorer expFaces;
183  for (expFaces.Init(aShape, TopAbs_FACE); expFaces.More(); expFaces.Next()) {
184  const TopoDS_Face& face = TopoDS::Face(expFaces.Current());
185  ++faceCount;
186 
187  TopLoc_Location location;
188  Poly_Triangulation facing = BRep_Tool::Triangulation(face, location);
189 
190  vertCount += static_cast<unsigned>(facing.NbNodes());
191  triCount += static_cast<unsigned>(facing.NbTriangles());
192 
193  if (triCount > mesh->capacity() && !mesh->reserve(triCount + 65536)) {
194  delete mesh;
196  }
197  if (vertCount > vertices->capacity() &&
198  !vertices->reserve(vertCount + 65536)) {
199  delete mesh;
201  }
202 
203  gp_Trsf nodeTransformation = location;
204  TColgp_Array1OfPnt nodes = facing.Nodes();
205  Poly_Array1OfTriangle tri = facing.Triangles();
206 
207  for (int j = 1; j <= facing.NbTriangles(); j++) {
208  Standard_Integer index1, index2, index3;
209  tri.Value(j).Get(index1, index2, index3);
210  gp_Pnt p1 = nodes.Value(index1).Transformed(nodeTransformation);
211  gp_Pnt p2 = nodes.Value(index2).Transformed(nodeTransformation);
212  gp_Pnt p3 = nodes.Value(index3).Transformed(nodeTransformation);
213 
214  unsigned vertIndexes[3];
215  vertIndexes[0] = vertices->size();
216  vertices->addPoint(CCVector3(p1.X(), p1.Y(), p1.Z()));
217  vertIndexes[1] = vertices->size();
218  vertices->addPoint(CCVector3(p2.X(), p2.Y(), p2.Z()));
219  vertIndexes[2] = vertices->size();
220  vertices->addPoint(CCVector3(p3.X(), p3.Y(), p3.Z()));
221 
222  mesh->addTriangle(vertIndexes[0], vertIndexes[1], vertIndexes[2]);
223  }
224  }
225 
226  mesh->shrinkToFit();
227  vertices->shrinkToFit();
228 
229  CVLog::Print("[STEP] Number of CAD faces = " + QString::number(faceCount));
230  CVLog::Print("[STEP] Number of triangles (after tesselation) = " +
231  QString::number(triCount));
232  CVLog::Print("[STEP] Number of vertices (after tesselation) = " +
233  QString::number(vertCount));
234 
236  parameters.parentWidget);
237  vertices = nullptr; // warning, after this point, 'vertices' is not valid
238  // anymore
239 
240  if (mesh->computePerTriangleNormals()) {
241  mesh->showNormals(true);
242  }
243 
244  container.addChild(mesh);
245 
246  return CC_FERR_NO_ERROR;
247 }
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_CANCELED_BY_USER
Definition: FileIOFilter.h:30
@ CC_FERR_THIRD_PARTY_LIB_FAILURE
Definition: FileIOFilter.h:36
@ CC_FERR_NO_LOAD
Definition: FileIOFilter.h:28
@ CC_FERR_THIRD_PARTY_LIB_EXCEPTION
Definition: FileIOFilter.h:37
@ CC_FERR_UNKNOWN_FILE
Definition: FileIOFilter.h:23
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
@ CC_FERR_NOT_ENOUGH_MEMORY
Definition: FileIOFilter.h:31
static double s_defaultLinearDeflection
Definition: STEPFilter.cpp:68
static std::map< TopAbs_ShapeEnum, QString > ShapeTypes
Definition: STEPFilter.cpp:50
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
Generic file I/O filter.
Definition: FileIOFilter.h:46
static constexpr float DEFAULT_PRIORITY
Definition: FileIOFilter.h:313
static void SetDefaultLinearDeflection(double value)
Sets the default linear deflection.
Definition: STEPFilter.cpp:70
CC_FILE_ERROR loadFile(const QString &fullFilename, ccHObject &container, LoadParameters &parameters) override
Loads one or more entities from a file.
Definition: STEPFilter.cpp:82
CC_FILE_ERROR importStepFile(ccHObject &container, const QString &fullFilename, double linearDeflection, LoadParameters &parameters)
Specific loading method.
Definition: STEPFilter.cpp:114
void showNormals(bool state) override
Sets normals visibility.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Triangular mesh.
Definition: ecvMesh.h:35
bool computePerTriangleNormals()
Computes per-triangle normals.
bool reserve(std::size_t n)
Reserves the memory to store the vertex indexes (3 per triangle)
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
Adds a triangle to the mesh.
static const unsigned char DefaultMergeDulicateVerticesLevel
Default octree level for the 'mergeDuplicatedVertices' algorithm.
Definition: ecvMesh.h:612
bool mergeDuplicatedVertices(unsigned char octreeLevel=DefaultMergeDulicateVerticesLevel, QWidget *parentWidget=nullptr)
Merges duplicated vertices.
void shrinkToFit()
Removes unused capacity.
Definition: ecvMesh.h:302
unsigned capacity() const override
Returns max capacity.
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
void shrinkToFit()
Removes unused capacity.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
Definition: PointCloudTpl.h:38
unsigned capacity() const
Returns cloud capacity (i.e. reserved size)
std::vector< unsigned int > face
static void error(char *msg)
Definition: lsd.c:159
Definition: Eigen.h:85
Generic loading parameters.
Definition: FileIOFilter.h:51
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:78