ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
AutoIO.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 // LOCAL
9 #include "AutoIO.h"
10 
11 // CV_CORE_LIB
12 #include <CVTools.h>
13 #include <FileSystem.h>
14 #include <Logging.h>
15 #include <ProgressReporters.h>
16 
17 // CV_DB_LIB
18 #include <ecvHObject.h>
19 #include <ecvHObjectCaster.h>
20 #include <ecvMesh.h>
21 #include <ecvPointCloud.h>
22 
23 // CV_IO_LIB
24 #include <FileIOFilter.h>
25 
26 // SYSTEM
27 #include <unordered_map>
28 
29 // QT
30 #include <QFileInfo>
31 
32 namespace cloudViewer {
33 namespace io {
34 
35 static const std::unordered_map<
36  std::string,
37  std::function<bool(
38  const std::string&, ccHObject&, const ReadPointCloudOption&)>>
40  {"bin", AutoReadEntity}, {"ply", AutoReadEntity},
41  {"vtk", AutoReadEntity}, {"stl", AutoReadEntity},
42  {"pcd", AutoReadEntity}, {"off", AutoReadEntity},
43  {"dxf", AutoReadEntity}, {"txt", AutoReadEntity},
44  {"las", AutoReadEntity}, {"laz", AutoReadEntity},
45  {"mat", AutoReadEntity}, {"obj", AutoReadEntity},
46  {"ptx", AutoReadEntity}, {"pt", AutoReadEntity},
47  {"poly", AutoReadEntity}, {"shp", AutoReadEntity},
48  {"sbf", AutoReadEntity},
49  };
50 
51 static const std::unordered_map<
52  std::string,
53  std::function<bool(const std::string&,
54  const ccHObject&,
55  const WritePointCloudOption&)>>
57  {"bin", AutoWriteEntity}, {"ply", AutoWriteEntity},
58  {"vtk", AutoWriteEntity}, {"stl", AutoWriteEntity},
59  {"pcd", AutoWriteEntity}, {"off", AutoWriteEntity},
60  {"dxf", AutoWriteEntity}, {"txt", AutoWriteEntity},
61  {"las", AutoWriteEntity}, {"laz", AutoWriteEntity},
62  {"mat", AutoWriteEntity}, {"obj", AutoWriteEntity},
63  {"ptx", AutoWriteEntity}, {"pt", AutoWriteEntity},
64  {"poly", AutoWriteEntity}, {"shp", AutoWriteEntity},
65  {"sbf", AutoWriteEntity},
66  };
67 
68 bool AutoReadEntity(const std::string& filename,
69  ccHObject& entity,
70  const ReadPointCloudOption& params) {
71  // to use the same 'global shift' for multiple files
72  CCVector3d loadCoordinatesShift(0, 0, 0);
73  bool loadCoordinatesTransEnabled = false;
74 
76  {
77  parameters.alwaysDisplayLoadDialog = params.print_progress;
79  parameters.coordinatesShift = &loadCoordinatesShift;
80  parameters.coordinatesShiftEnabled = &loadCoordinatesTransEnabled;
81  parameters.parentWidget = nullptr;
82  parameters.autoComputeNormals = false;
83  }
84 
85  // the same for 'addToDB' (if the first one is not supported, or if the
86  // scale remains too big)
87  CCVector3d addCoordinatesShift(0, 0, 0);
88 
89  if (FileIOFilter::GetFilters().empty()) {
90  FileIOFilter::InitInternalFilters();
91  }
92 
94 
96  FileIOFilter::Shared filter(nullptr);
97 
98  // load file
99  auto container = std::make_shared<ccHObject>();
100 
101  while (true) {
102  // look for file extension (we trust Qt on this task)
103  QString file = CVTools::ToQString(filename);
104  QString extension = QFileInfo(file).suffix();
105  if (extension.isEmpty()) {
107  "[Load] Can't guess file format: no file extension");
109  break;
110  } else {
111  // convert extension to file format
112  filter = FileIOFilter::FindBestFilterForExtension(extension);
113 
114  // unknown extension?
115  if (!filter) {
117  "[Load] Can't guess file format: unhandled file "
118  "extension '%s'",
119  extension.toStdString().c_str());
121  break;
122  }
123 
124  // check file existence
125  QFileInfo fi(file);
126  if (!fi.exists()) {
128  "[Load] File '%s' doesn't exist!",
129  file.toStdString().c_str());
131  break;
132  }
133 
134  // we start a new 'action' inside the current sessions
135  unsigned sessionCounter = FileIOFilter::IncreaseSesionCounter();
136  parameters.sessionStart = (sessionCounter == 1);
137 
138  try {
139  if (entity.isA(CV_TYPES::HIERARCHY_OBJECT)) {
140  result = filter->loadFile(file, entity, parameters);
141  } else {
142  result = filter->loadFile(file, *container, parameters);
143  }
144  } catch (const std::exception& e) {
146  "[I/O] CC has caught an exception while loading file "
147  "'%s'!",
148  file.toStdString().c_str());
149  cloudViewer::utility::LogWarning("[I/O] Exception: %s",
150  e.what());
151  if (container) {
152  container->removeAllChildren();
153  }
155  } catch (...) {
157  "[I/O] CC has caught an unhandled exception while "
158  "loading file '%s'",
159  file.toStdString().c_str());
160  if (container) {
161  container->removeAllChildren();
162  }
164  }
165 
166  if (result != CC_FERR_NO_ERROR) {
168  fi.baseName());
169  }
170 
171  unsigned childCount = container->getChildrenNumber();
172  if (childCount != 0) {
173  // we set the main container name as the full filename (with
174  // path)
175  container->setName(QString("%1 (%2)").arg(fi.fileName(),
176  fi.absolutePath()));
177  for (unsigned i = 0; i < childCount; ++i) {
178  ccHObject* child = container->getChild(i);
179  child->setBaseName(fi.baseName());
180  child->setFullPath(file);
181  QString newName = child->getName();
182  if (newName.startsWith("unnamed")) {
183  // we automatically replace occurrences of 'unnamed' in
184  // entities names by the base filename (no path, no
185  // extension)
186  newName.replace(QString("unnamed"), fi.baseName());
187  child->setName(newName);
188  }
189  }
190  } else {
192  break;
193  }
194  }
195 
196  break;
197  }
198 
199  bool successFlag = true;
200  if (result == CC_FERR_NO_ERROR) {
201  if (entity.isKindOf(CV_TYPES::POINT_CLOUD)) {
202  ccPointCloud* outCloud = ccHObjectCaster::ToPointCloud(&entity);
203  for (unsigned i = 0; i < container->getChildrenNumber(); ++i) {
204  ccPointCloud* cloud =
205  ccHObjectCaster::ToPointCloud(container->getChild(i));
206  if (!cloud) continue;
207  outCloud->append(cloud, outCloud->size());
208  }
209  successFlag = true;
210  } else if (entity.isKindOf(CV_TYPES::MESH)) {
211  ccMesh* outMesh = ccHObjectCaster::ToMesh(&entity);
212 
213  for (unsigned i = 0; i < container->getChildrenNumber(); ++i) {
214  ccMesh* mesh = ccHObjectCaster::ToMesh(container->getChild(i));
215  if (!mesh || mesh->IsEmpty()) continue;
216  if (!outMesh || !outMesh->getAssociatedCloud()) continue;
217  if (!outMesh->merge(mesh, false)) {
219  "[AutoReadEntity] merge mesh child failed!");
220  }
221  }
222  successFlag = true;
223  } else if (entity.isA(CV_TYPES::HIERARCHY_OBJECT)) {
224  if (entity.getChildrenNumber() > 0) {
225  successFlag = true;
226  } else {
227  successFlag = false;
228  }
229  }
230  } else {
231  successFlag = false;
232  }
233 
234  container->removeAllChildren();
235  return successFlag;
236 }
237 
238 bool AutoWriteEntity(const std::string& filename,
239  const ccHObject& entity,
240  const WritePointCloudOption& params) {
241  FileIOFilter::SaveParameters parameters;
242  {
243  parameters.alwaysDisplaySaveDialog = params.print_progress;
244  parameters.parentWidget = nullptr;
245  }
246 
247  if (FileIOFilter::GetFilters().empty()) {
248  FileIOFilter::InitInternalFilters();
249  }
250 
252 
254  FileIOFilter::Shared filter(nullptr);
255 
256  // save file
257  while (true) {
258  // look for file extension (we trust Qt on this task)
259  QString completeFileName = CVTools::ToQString(filename);
260 
261  // if the file name has no extension, we had a default one!
262 
263  if (QFileInfo(completeFileName).suffix().isEmpty())
264  completeFileName +=
265  QString(".%1").arg(filter->getDefaultExtension());
266 
267  QString extension = QFileInfo(completeFileName).suffix();
269  {
270  // convert extension to file format
271  filter = FileIOFilter::FindBestFilterForExtension(extension);
272 
273  // unknown extension?
274  if (!filter) {
276  "[AutoWriteEntity] Can't guess file format: unhandled "
277  "file extension '%s'",
278  CVTools::FromQString(extension).c_str());
280  break;
281  }
282 
283  try {
284  result = filter->saveToFile(const_cast<ccHObject*>(&entity),
285  completeFileName, parameters);
286  } catch (...) {
288  "[AutoWriteEntity] CV has caught an unhandled "
289  "exception while saving file '%s'",
290  CVTools::FromQString(completeFileName).c_str());
292  }
293 
294  if (result != CC_FERR_NO_ERROR) {
296  completeFileName);
297  }
298  }
299 
300  break;
301  }
302 
303  return result == CC_FERR_NO_ERROR;
304 }
305 
306 bool AutoReadMesh(const std::string& filename,
307  ccMesh& mesh,
308  const ReadTriangleMeshOptions& params /*={}*/) {
310  p.print_progress = params.print_progress;
311  return AutoReadEntity(filename, mesh, p);
312 }
313 
314 bool AutoWriteMesh(const std::string& filename,
315  const ccMesh& mesh,
316  bool write_ascii /* = false*/,
317  bool compressed /* = false*/,
318  bool write_vertex_normals /* = true*/,
319  bool write_vertex_colors /* = true*/,
320  bool write_triangle_uvs /* = true*/,
321  bool print_progress) {
322  WritePointCloudOption params;
325  params.print_progress = print_progress;
326  return AutoWriteEntity(filename, mesh, params);
327 }
328 
329 using namespace cloudViewer;
330 std::shared_ptr<ccHObject> CreateEntityFromFile(const std::string& filename,
331  const std::string& format,
332  bool print_progress) {
333  auto entity = std::make_shared<ccHObject>("Group");
334  ReadEntity(filename, *entity, format, print_progress);
335  return entity;
336 }
337 
338 bool ReadEntity(const std::string& filename,
339  ccHObject& entity,
340  const std::string& format,
341  bool print_progress) {
342  std::string filename_ext;
343  if (format == "auto") {
344  filename_ext =
346  } else {
347  filename_ext = format;
348  }
349  if (filename_ext.empty()) {
350  utility::LogWarning("Read entity failed: unknown file extension.");
351  return false;
352  }
353  auto map_itr = file_extension_to_entity_read_function.find(filename_ext);
354  if (map_itr == file_extension_to_entity_read_function.end()) {
355  utility::LogWarning("Read entity failed: unknown file extension.");
356  return false;
357  }
358 
360  p.format = format;
361  utility::ConsoleProgressUpdater progress_updater(
362  std::string("Reading ") + utility::ToUpper(filename_ext) +
363  " file: " + filename,
364  print_progress);
365  p.update_progress = progress_updater;
366 
367  bool success = map_itr->second(filename, entity, p);
368  utility::LogDebug("[ReadEntity] load {:d} entities.",
369  (int)entity.getChildrenNumber());
370  return success;
371 }
372 
373 bool WriteEntity(const std::string& filename,
374  const ccHObject& entity,
375  bool write_ascii /* = false*/,
376  bool compressed /* = false*/,
377  bool print_progress) {
378  std::string filename_ext =
380  if (filename_ext.empty()) {
381  utility::LogWarning("Write entity failed: unknown file extension.");
382  return false;
383  }
384  auto map_itr = file_extension_to_entity_write_function.find(filename_ext);
385  if (map_itr == file_extension_to_entity_write_function.end()) {
386  utility::LogWarning("Write entity failed: unknown file extension.");
387  return false;
388  }
389 
393  utility::ConsoleProgressUpdater progress_updater(
394  std::string("Writing ") + utility::ToUpper(filename_ext) +
395  " file: " + filename,
396  print_progress);
397  p.update_progress = progress_updater;
398 
399  bool success = map_itr->second(filename, entity, p);
400  utility::LogDebug("[WriteEntity] Write {:d} entities.",
401  (int)entity.getChildrenNumber());
402  return success;
403 }
404 
405 } // namespace io
406 } // namespace cloudViewer
IsAscii write_ascii
Compressed compressed
std::string filename
filament::Texture::InternalFormat format
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_CONSOLE_ERROR
Definition: FileIOFilter.h:33
@ CC_FERR_NO_LOAD
Definition: FileIOFilter.h:28
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
core::Tensor result
Definition: VtkUtils.cpp:76
static std::string FromQString(const QString &qs)
Definition: CVTools.cpp:100
static QString ToQString(const std::string &s)
Definition: CVTools.cpp:92
static unsigned IncreaseSesionCounter()
static const FilterContainer & GetFilters()
Returns the set of all registered filters.
static Shared FindBestFilterForExtension(const QString &ext)
Returns the best filter (presumably) to open a given file extension.
QSharedPointer< FileIOFilter > Shared
Shared type.
Definition: FileIOFilter.h:97
static void ResetSesionCounter()
static void DisplayErrorMessage(CC_FILE_ERROR err, const QString &action, const QString &filename)
Displays (to console) the message corresponding to a given error code.
static ccMesh * ToMesh(ccHObject *obj)
Converts current object to ccMesh (if possible)
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Definition: ecvHObject.h:325
Triangular mesh.
Definition: ecvMesh.h:35
bool merge(const ccMesh *mesh, bool createSubMesh)
Merges another mesh into this one.
Definition: ecvMesh.cpp:1788
virtual bool IsEmpty() const override
Definition: ecvMesh.h:735
ccGenericPointCloud * getAssociatedCloud() const override
Returns the vertices cloud.
Definition: ecvMesh.h:143
void setBaseName(const QString &baseName)
Definition: ecvObject.h:186
virtual QString getName() const
Returns object name.
Definition: ecvObject.h:72
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
void setFullPath(const QString &fullPaht)
Definition: ecvObject.h:189
bool isKindOf(CV_CLASS_ENUM type) const
Definition: ecvObject.h:128
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
const ccPointCloud & append(ccPointCloud *cloud, unsigned pointCountBefore, bool ignoreChildren=false)
Appends a cloud to this one.
unsigned size() const override
Definition: PointCloudTpl.h:38
#define LogWarning(...)
Definition: Logging.h:72
#define LogDebug(...)
Definition: Logging.h:90
const double * e
@ HIERARCHY_OBJECT
Definition: CVTypes.h:103
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
bool AutoWriteMesh(const std::string &filename, const ccMesh &mesh, bool write_ascii=false, bool compressed=false, bool write_vertex_normals=true, bool write_vertex_colors=true, bool write_triangle_uvs=true, bool print_progress=false)
Definition: AutoIO.cpp:314
bool AutoReadEntity(const std::string &filename, ccHObject &entity, const ReadPointCloudOption &params)
Definition: AutoIO.cpp:68
bool AutoWriteEntity(const std::string &filename, const ccHObject &entity, const WritePointCloudOption &params)
Definition: AutoIO.cpp:238
bool ReadEntity(const std::string &filename, ccHObject &obj, const std::string &format="auto", bool print_progress=false)
Definition: AutoIO.cpp:338
static const std::unordered_map< std::string, std::function< bool(const std::string &, ccHObject &, const ReadPointCloudOption &)> > file_extension_to_entity_read_function
Definition: AutoIO.cpp:39
bool AutoReadMesh(const std::string &filename, ccMesh &mesh, const ReadTriangleMeshOptions &params={})
Definition: AutoIO.cpp:306
std::shared_ptr< ccHObject > CreateEntityFromFile(const std::string &filename, const std::string &format="auto", bool print_progress=false)
Definition: AutoIO.cpp:330
bool WriteEntity(const std::string &filename, const ccHObject &obj, bool write_ascii=false, bool compressed=false, bool print_progress=false)
Definition: AutoIO.cpp:373
static const std::unordered_map< std::string, std::function< bool(const std::string &, const ccHObject &, const WritePointCloudOption &)> > file_extension_to_entity_write_function
Definition: AutoIO.cpp:56
std::string GetFileExtensionInLowerCase(const std::string &filename)
Definition: FileSystem.cpp:281
std::string ToUpper(const std::string &s)
Convert string to the upper case.
Definition: Helper.cpp:249
Generic file read and write utility for python interface.
Generic loading parameters.
Definition: FileIOFilter.h:51
CCVector3d * coordinatesShift
If applicable, applied shift on load (optional)
Definition: FileIOFilter.h:71
ecvGlobalShiftManager::Mode shiftHandlingMode
How to handle big coordinates.
Definition: FileIOFilter.h:64
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:78
bool sessionStart
Session start (whether the load action is the first of a session)
Definition: FileIOFilter.h:80
bool * coordinatesShiftEnabled
Whether shift on load has been applied after loading (optional)
Definition: FileIOFilter.h:69
Generic saving parameters.
Definition: FileIOFilter.h:84
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:93
Optional parameters to ReadPointCloud.
Definition: FileIO.h:39
std::function< bool(double)> update_progress
Definition: FileIO.h:72
Optional parameters to WritePointCloud.
Definition: FileIO.h:77
std::function< bool(double)> update_progress
Definition: FileIO.h:135
update_progress(double percent) functor for ConsoleProgressBar