ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
MAFilter.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 "MAFilter.h"
9 
10 #include "FileIO.h"
11 
12 // qCC_db
13 #include <CVLog.h>
14 #include <ecvHObjectCaster.h>
15 #include <ecvMesh.h>
16 #include <ecvPointCloud.h>
17 #include <ecvProgressDialog.h>
18 
19 // Qt
20 #include <QDateTime>
21 #include <QFileInfo>
22 
23 // System
24 #include <assert.h>
25 #include <string.h>
26 
27 namespace {
28 struct edge {
29  int edgeIndex;
30  bool positif;
31  unsigned theOtherPoint;
32  edge* nextEdge;
33 };
34 
35 static void ReleaseEdgeList(
36  edge**& theEdges,
37  unsigned numberOfVertexes,
38  cloudViewer::NormalizedProgress* nprogress = nullptr) {
39  for (unsigned i = 0; i < numberOfVertexes; ++i) {
40  if (theEdges[i]) {
41  edge* e = theEdges[i]->nextEdge;
42  while (e) {
43  edge* nextE = e->nextEdge;
44  delete e;
45  e = nextE;
46  }
47  delete theEdges[i];
48  }
49 
50  if (nprogress) {
51  nprogress->oneStep();
52  }
53  }
54  delete[] theEdges;
55  theEdges = nullptr;
56 }
57 
58 struct faceIndexes {
59  int faceIndex;
60  faceIndexes* nextFace;
61 };
62 } // namespace
63 
65  : FileIOFilter({"_Maya ASCII Filter",
66  DEFAULT_PRIORITY, // priority
67  QStringList(), "ma", QStringList(),
68  QStringList{"Maya ASCII mesh (*.ma)"}, Export}) {}
69 
71  bool& multiple,
72  bool& exclusive) const {
73  if (type == CV_TYPES::MESH) {
74  multiple = false;
75  exclusive = true;
76  return true;
77  }
78  return false;
79 }
80 
82  const QString& filename,
83  const SaveParameters& parameters) {
84  if (!entity || filename.isEmpty()) return CC_FERR_BAD_ARGUMENT;
85 
86  // the mesh to save
88  if (!theMesh) {
89  CVLog::Error("[MA] This filter can only save one mesh at a time!");
91  }
92  // and its vertices
93  ccGenericPointCloud* theCloud = theMesh->getAssociatedCloud();
94 
95  unsigned numberOfTriangles = theMesh->size();
96  unsigned numberOfVertexes = theCloud->size();
97 
98  if (numberOfTriangles == 0 || numberOfVertexes == 0) {
99  CVLog::Error("Mesh is empty!");
101  }
102 
103  bool hasColors = false;
104  if (theCloud->isA(CV_TYPES::POINT_CLOUD))
105  static_cast<ccPointCloud*>(theCloud)->hasColors();
106 
107  // and its scalar field
108  // ccScalarField* sf = 0;
109  // if (theCloud->isA(CV_TYPES::POINT_CLOUD))
110  // sf =
111  // static_cast<ccPointCloud*>(theCloud)->getCurrentDisplayedScalarField();
112 
113  // if (!sf)
114  // CVLog::Warning("No displayed scalar field! Values will all be 0!\n");
115 
116  // open ASCII file for writing
117  FILE* fp = fopen(qPrintable(filename), "wt");
118 
119  if (!fp) return CC_FERR_WRITING;
120 
121  // progress dialog
122  QScopedPointer<ecvProgressDialog> pDlg(nullptr);
123  const int coloursAdjustment = (hasColors ? 1 : 0);
124  if (parameters.parentWidget) {
125  pDlg.reset(new ecvProgressDialog(
126  true, parameters.parentWidget)); // cancel available
127  pDlg->setMethodTitle(QObject::tr("Save MA file"));
128  pDlg->setInfo(QObject::tr("Triangles = %1").arg(numberOfTriangles));
129  pDlg->start();
130  }
132  pDlg.data(), ((2 + coloursAdjustment) * numberOfTriangles +
133  (3 + coloursAdjustment) * numberOfVertexes));
134 
135  // we extract the (short) filename from the whole path
136  QString baseFilename = QFileInfo(filename).fileName();
137 
138  // For details of the format, see:
139  // http://download.autodesk.com/us/support/files/fileformats.pdf
140 
141  // header
142  if (fprintf(fp, "//Maya ASCII 7.0 scene\n") < 0) {
143  fclose(fp);
144  return CC_FERR_WRITING;
145  }
146  if (fprintf(fp, "//Name: %s\n", qPrintable(baseFilename)) < 0) {
147  fclose(fp);
148  return CC_FERR_WRITING;
149  }
150  if (fprintf(fp, "//Last modified: %s\n",
151  qPrintable(QDateTime::currentDateTime().toString(
152  Qt::ISODateWithMs))) < 0) {
153  fclose(fp);
154  return CC_FERR_WRITING;
155  }
156  if (fprintf(fp, "requires maya \"4.0\";\n") < 0) {
157  fclose(fp);
158  return CC_FERR_WRITING;
159  }
160  if (fprintf(fp, "currentUnit -l %s -a degree -t film;\n", "centimeter") <
161  0) {
162  fclose(fp);
163  return CC_FERR_WRITING;
164  }
165 
166  // fileInfo
167  if (fprintf(fp, "fileInfo \"application\" \"%s\"\n",
168  qPrintable(FileIO::applicationName())) < 0) {
169  fclose(fp);
170  return CC_FERR_WRITING;
171  }
172 
173  if (fprintf(fp, "fileInfo \"product\" \"%s\"\n",
174  qPrintable(FileIO::writerInfo())) < 0) {
175  fclose(fp);
176  return CC_FERR_WRITING;
177  }
178 
179  if (fprintf(fp, "fileInfo \"version\" \"%s\"\n",
180  qPrintable(FileIO::version())) < 0) {
181  fclose(fp);
182  return CC_FERR_WRITING;
183  }
184 
185  // for multiple meshes handling (does not work yet)
186  unsigned char currentMesh = 0;
187 
188  // transformation node
189  if (fprintf(fp, "createNode transform -n \"Mesh%i\";\n", currentMesh + 1) <
190  0) {
191  fclose(fp);
192  return CC_FERR_WRITING;
193  }
194 
195  // main node
196  if (fprintf(fp, "createNode mesh -n \"MeshShape%i\" -p \"Mesh%i\";\n",
197  currentMesh + 1, currentMesh + 1) < 0) {
198  fclose(fp);
199  return CC_FERR_WRITING;
200  }
201 
202  if (fprintf(fp, "\tsetAttr -k off \".v\";\n") < 0) {
203  fclose(fp);
204  return CC_FERR_WRITING;
205  }
206 
207  if (fprintf(fp,
208  "\tsetAttr \".uvst[0].uvsn\" -type \"string\" \"map1\";\n") <
209  0) {
210  fclose(fp);
211  return CC_FERR_WRITING;
212  }
213  if (fprintf(fp, "\tsetAttr \".cuvs\" -type \"string\" \"map1\";\n") < 0) {
214  fclose(fp);
215  return CC_FERR_WRITING;
216  }
217  if (hasColors) {
218  if (fprintf(fp, "\tsetAttr \".dcol\" yes;\n") < 0) {
219  fclose(fp);
220  return CC_FERR_WRITING;
221  }
222  }
223  if (fprintf(fp,
224  "\tsetAttr \".dcc\" -type \"string\" \"Ambient+Diffuse\";\n") <
225  0) {
226  fclose(fp);
227  return CC_FERR_WRITING;
228  }
229  if (fprintf(fp, "\tsetAttr \".ccls\" -type \"string\" \"colorSet%i\";\n",
230  currentMesh + 1) < 0) {
231  fclose(fp);
232  return CC_FERR_WRITING;
233  }
234  if (fprintf(fp,
235  "\tsetAttr \".clst[0].clsn\" -type \"string\" "
236  "\"colorSet%i\";\n",
237  currentMesh + 1) < 0) {
238  fclose(fp);
239  return CC_FERR_WRITING;
240  }
241  if (hasColors) {
242  if (fprintf(fp, "\tsetAttr \".ndt\" 0;\n") < 0) {
243  fclose(fp);
244  return CC_FERR_WRITING;
245  }
246  if (fprintf(fp, "\tsetAttr \".tgsp\" 1;\n") < 0) {
247  fclose(fp);
248  return CC_FERR_WRITING;
249  }
250 
251  // insert a secondary nodes
252  if (fprintf(fp,
253  "createNode mesh -n \"polySurfaceShape%i\" -p "
254  "\"Mesh%i\";\n",
255  currentMesh + 1, currentMesh + 1) < 0) {
256  fclose(fp);
257  return CC_FERR_WRITING;
258  }
259 
260  if (fprintf(fp, "\tsetAttr -k off \".v\";\n") < 0) {
261  fclose(fp);
262  return CC_FERR_WRITING;
263  }
264  if (fprintf(fp, "\tsetAttr \".io\" yes;\n") < 0) {
265  fclose(fp);
266  return CC_FERR_WRITING;
267  }
268  if (fprintf(fp,
269  "\tsetAttr \".uvst[0].uvsn\" -type \"string\" "
270  "\"map1\";\n") < 0) {
271  fclose(fp);
272  return CC_FERR_WRITING;
273  }
274  if (fprintf(fp, "\tsetAttr \".cuvs\" -type \"string\" \"map1\";\n") <
275  0) {
276  fclose(fp);
277  return CC_FERR_WRITING;
278  }
279  if (fprintf(fp, "\tsetAttr \".dcol\" yes;\n") < 0) {
280  fclose(fp);
281  return CC_FERR_WRITING;
282  }
283  if (fprintf(fp,
284  "\tsetAttr \".dcc\" -type \"string\" "
285  "\"Ambient+Diffuse\";\n") < 0) {
286  fclose(fp);
287  return CC_FERR_WRITING;
288  }
289  if (fprintf(fp,
290  "\tsetAttr \".ccls\" -type \"string\" \"colorSet%i\";\n",
291  currentMesh + 1) < 0) {
292  fclose(fp);
293  return CC_FERR_WRITING;
294  }
295  if (fprintf(fp,
296  "\tsetAttr \".clst[0].clsn\" -type \"string\" "
297  "\"colorSet%i\";\n",
298  currentMesh + 1) < 0) {
299  fclose(fp);
300  return CC_FERR_WRITING;
301  }
302  }
303 
304  // save vertexes
305  if (fprintf(fp, "\tsetAttr -s %u \".vt[0:%u]\"\n", numberOfVertexes,
306  numberOfVertexes - 1) < 0) {
307  fclose(fp);
308  return CC_FERR_WRITING;
309  }
310  {
311  for (unsigned i = 0; i < numberOfVertexes; ++i) {
312  const CCVector3* P = theCloud->getPoint(i);
313  CCVector3d Pglobal = theCloud->toGlobal3d<PointCoordinateType>(*P);
314  if (fprintf(fp,
315  (i + 1 == numberOfVertexes ? "\t\t%f %f %f;\n"
316  : "\t\t%f %f %f\n"),
317  Pglobal.x, Pglobal.y, Pglobal.z) < 0) {
318  fclose(fp);
319  return CC_FERR_WRITING;
320  }
321 
322  if (pDlg) {
323  nprogress.oneStep();
324  }
325  }
326  }
327 
328  // save "edges"
329  edge** theEdges = new edge*[numberOfVertexes];
330  memset(theEdges, 0, sizeof(edge*) * numberOfVertexes);
331  unsigned ind[3]{0, 0, 0};
332  unsigned a = 0;
333  unsigned b = 0;
334  int lastEdgeIndexPushed = -1;
335 
336  int hard = 0; // Maya edges cab be "hard" or "soft" ...
337  {
338  theMesh->placeIteratorAtBeginning();
339  for (unsigned i = 0; i < numberOfTriangles; ++i) {
340  const cloudViewer::VerticesIndexes* tsi =
341  theMesh->getNextTriangleVertIndexes(); // DGM:
342  // getNextTriangleVertIndexes
343  // is faster for
344  // mesh groups!
345 
346  ind[0] = tsi->i1;
347  ind[1] = tsi->i2;
348  ind[2] = tsi->i3;
349 
350  for (unsigned char k = 0; k < 3; ++k) {
351  unsigned char l = (k < 2 ? k + 1 : 0);
352  a = (ind[k] < ind[l] ? ind[k] : ind[l]);
353  b = (a == ind[k] ? ind[l] : ind[k]);
354 
355  int currentEdgeIndex = -1;
356  edge* e = theEdges[a];
357  while (e) {
358  if (e->theOtherPoint == b) {
359  currentEdgeIndex = e->edgeIndex;
360  break;
361  }
362  e = e->nextEdge;
363  }
364 
365  if (currentEdgeIndex < 0) // create a new edge
366  {
367  edge* newEdge = new edge;
368  newEdge->nextEdge = nullptr;
369  newEdge->theOtherPoint = b;
370  newEdge->positif = (a == ind[k]);
371  // newEdge->edgeIndex = ++lastEdgeIndexPushed; //don't write
372  // the edge right now
373  newEdge->edgeIndex = 0;
374  ++lastEdgeIndexPushed;
375  // currentEdgeIndex = lastEdgeIndexPushed;
376 
377  // don't forget the node!
378  if (theEdges[a]) {
379  e = theEdges[a];
380  while (e->nextEdge) e = e->nextEdge;
381  e->nextEdge = newEdge;
382  } else {
383  theEdges[a] = newEdge;
384  }
385 
386  /*if (fprintf(fp,"\n \t\t%i %i %i",a,b,hard) < 0)
387  return CC_FERR_WRITING;*/
388  }
389  }
390 
391  if (pDlg) {
392  nprogress.oneStep();
393  }
394  }
395  }
396 
397  // now write the edges
398  {
399  unsigned numberOfEdges = static_cast<unsigned>(lastEdgeIndexPushed + 1);
400  if (fprintf(fp, "\tsetAttr -s %u \".ed[0:%u]\"", numberOfEdges,
401  numberOfEdges - 1) < 0) {
402  fclose(fp);
403  ReleaseEdgeList(theEdges, numberOfVertexes);
404  return CC_FERR_WRITING;
405  }
406 
407  lastEdgeIndexPushed = 0;
408  for (unsigned i = 0; i < numberOfVertexes; ++i) {
409  edge* e = theEdges[i];
410  while (e) {
411  e->edgeIndex = lastEdgeIndexPushed++;
412  if (fprintf(fp, "\n \t\t%u %u %i", i, e->theOtherPoint, hard) <
413  0) {
414  fclose(fp);
415  ReleaseEdgeList(theEdges, numberOfVertexes);
416  return CC_FERR_WRITING;
417  }
418  e = e->nextEdge;
419  }
420 
421  if (pDlg) {
422  nprogress.oneStep();
423  }
424  }
425  }
426 
427  if (fprintf(fp, ";\n") < 0) {
428  fclose(fp);
429  ReleaseEdgeList(theEdges, numberOfVertexes);
430  return CC_FERR_WRITING;
431  }
432 
433  // write faces
434  if (fprintf(fp, "\tsetAttr -s %u \".fc[0:%u]\" -type \"polyFaces\"\n",
435  numberOfTriangles, numberOfTriangles - 1) < 0) {
436  fclose(fp);
437  ReleaseEdgeList(theEdges, numberOfVertexes);
438  return CC_FERR_WRITING;
439  }
440 
441  theMesh->placeIteratorAtBeginning();
442  {
443  for (unsigned i = 0; i < numberOfTriangles; ++i) {
444  if (fprintf(fp, "\t\tf 3") < 0) {
445  fclose(fp);
446  ReleaseEdgeList(theEdges, numberOfVertexes);
447  return CC_FERR_WRITING;
448  }
449 
451  theMesh->getNextTriangleVertIndexes(); // DGM:
452  // getNextTriangleVertIndexes
453  // is faster for
454  // mesh groups!
455  ind[0] = tsi->i1;
456  ind[1] = tsi->i2;
457  ind[2] = tsi->i3;
458 
459  for (unsigned char k = 0; k < 3; ++k) {
460  unsigned char l = (k < 2 ? k + 1 : 0);
461  a = (ind[k] < ind[l] ? ind[k] : ind[l]);
462  b = (a == ind[k] ? ind[l] : ind[k]);
463 
464  edge* e = theEdges[a];
465  while (e->theOtherPoint != b) e = e->nextEdge;
466 
467  if (fprintf(fp, " %i",
468  ((e->positif && a == ind[k]) ||
469  (!e->positif && a == ind[l])
470  ? e->edgeIndex
471  : -(e->edgeIndex + 1))) < 0) {
472  fclose(fp);
473  ReleaseEdgeList(theEdges, numberOfVertexes);
474  return CC_FERR_WRITING;
475  }
476  }
477 
478  if (fprintf(fp, (i + 1 == numberOfTriangles ? ";\n" : "\n")) < 0) {
479  fclose(fp);
480  ReleaseEdgeList(theEdges, numberOfVertexes);
481  return CC_FERR_WRITING;
482  }
483 
484  if (pDlg) {
485  nprogress.oneStep();
486  }
487  }
488  }
489 
490  // free memory
491  {
492  ReleaseEdgeList(theEdges, numberOfVertexes,
493  pDlg ? &nprogress : nullptr);
494  }
495 
496  // bonus track
497  if (fprintf(fp,
498  "\tsetAttr \".cd\" -type \"dataPolyComponent\" Index_Data Edge "
499  "0 ;\n") < 0 ||
500  fprintf(fp, "\tsetAttr \".ndt\" 0;\n") < 0 ||
501  fprintf(fp, "\tsetAttr \".tgsp\" 1;\n") < 0) {
502  fclose(fp);
503  return CC_FERR_WRITING;
504  }
505 
506  // vertex colors
507  if (hasColors) {
508  assert(theCloud->isA(CV_TYPES::POINT_CLOUD));
509  ccPointCloud* pc = static_cast<ccPointCloud*>(theCloud);
510 
511  if (fprintf(fp,
512  "createNode polyColorPerVertex -n "
513  "\"polyColorPerVertex%i\";\n",
514  currentMesh + 1) < 0) {
515  fclose(fp);
516  return CC_FERR_WRITING;
517  }
518 
519  if (fprintf(fp, "\tsetAttr \".uopa\" yes;\n") < 0) {
520  fclose(fp);
521  return CC_FERR_WRITING;
522  }
523 
524  if (fprintf(fp, "\tsetAttr -s %u \".vclr\";\n", numberOfVertexes) < 0) {
525  fclose(fp);
526  return CC_FERR_WRITING;
527  }
528 
529  // association of each vertex with the faces it belongs to
530  faceIndexes** theFacesIndexes = new faceIndexes*[numberOfVertexes];
531  memset(theFacesIndexes, 0, sizeof(faceIndexes*) * numberOfVertexes);
532  theMesh->placeIteratorAtBeginning();
533  {
534  for (unsigned i = 0; i < numberOfTriangles; ++i) {
536  theMesh->getNextTriangleVertIndexes(); // DGM:
537  // getNextTriangleVertIndexes
538  // is faster for
539  // mesh groups!
540  ind[0] = tsi->i1;
541  ind[1] = tsi->i2;
542  ind[2] = tsi->i3;
543 
544  for (unsigned char j = 0; j < 3; ++j) {
545  if (!theFacesIndexes[ind[j]]) {
546  faceIndexes* f = new faceIndexes;
547  f->faceIndex = i;
548  f->nextFace = nullptr;
549  theFacesIndexes[ind[j]] = f;
550  } else {
551  faceIndexes* f = theFacesIndexes[ind[j]];
552  while (f->nextFace) f = f->nextFace;
553  f->nextFace = new faceIndexes;
554  f->nextFace->faceIndex = i;
555  f->nextFace->nextFace = nullptr;
556  }
557  }
558 
559  if (pDlg) {
560  nprogress.oneStep();
561  }
562  }
563  }
564 
565  // for each vertex
566  {
567  for (unsigned i = 0; i < numberOfVertexes; ++i) {
568  const ecvColor::Rgb& c = pc->getPointColor(i);
569  ecvColor::Rgbf col(static_cast<float>(c.r) / ecvColor::MAX,
570  static_cast<float>(c.g) / ecvColor::MAX,
571  static_cast<float>(c.b) / ecvColor::MAX);
572 
573  // on compte le nombre de faces
574  int nf = 0;
575  faceIndexes* f = theFacesIndexes[i];
576  while (f) {
577  ++nf;
578  f = f->nextFace;
579  }
580 
581  if (nf > 0) {
582  if (fprintf(fp, "\tsetAttr -s %i \".vclr[%u].vfcl\";\n", nf,
583  i) < 0) {
584  fclose(fp);
585  delete[] theFacesIndexes; // DGM: we are missing some
586  // faces here, aren't we?
587  return CC_FERR_WRITING;
588  }
589 
590  faceIndexes* f = theFacesIndexes[i];
591  while (f) {
592  if (fprintf(fp,
593  "\tsetAttr \".vclr[%u].vfcl[%i].frgb\" "
594  "-type \"float3\" %f %f %f;\n",
595  i, f->faceIndex, col.r, col.g, col.b) < 0) {
596  fclose(fp);
597  delete[] theFacesIndexes; // DGM: we are missing
598  // some faces here,
599  // aren't we?
600  return CC_FERR_WRITING;
601  }
602 
603  faceIndexes* oldf = f;
604  f = f->nextFace;
605  delete oldf;
606  }
607  theFacesIndexes[i] = nullptr;
608  }
609 
610  if (pDlg) {
611  nprogress.oneStep();
612  }
613  }
614  }
615  delete[] theFacesIndexes;
616  theFacesIndexes = nullptr;
617 
618  if (fprintf(fp, "\tsetAttr \".cn\" -type \"string\" \"colorSet%i\";\n",
619  currentMesh + 1) < 0) {
620  fclose(fp);
621  return CC_FERR_WRITING;
622  }
623  }
624 
625  // Maya connections
626  if (hasColors) {
627  if (fprintf(fp,
628  "connectAttr \"polyColorPerVertex%i.out\" "
629  "\"MeshShape%i.i\";\n",
630  currentMesh + 1, currentMesh + 1) < 0 ||
631  fprintf(fp,
632  "connectAttr \"polySurfaceShape%i.o\" "
633  "\"polyColorPerVertex%i.ip\";\n",
634  currentMesh + 1, currentMesh + 1) < 0) {
635  fclose(fp);
636  return CC_FERR_WRITING;
637  }
638  }
639 
640  if (fprintf(fp,
641  "connectAttr \"MeshShape%i.iog\" \":initialShadingGroup.dsm\" "
642  "-na;\n",
643  currentMesh + 1) < 0) {
644  fclose(fp);
645  return CC_FERR_WRITING;
646  }
647 
648  // end of file
649  if (fprintf(fp, "//End of %s\n", qPrintable(baseFilename)) < 0) {
650  fclose(fp);
651  return CC_FERR_WRITING;
652  }
653 
654  fclose(fp);
655 
656  return CC_FERR_NO_ERROR;
657 }
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
Definition: CVTypes.h:97
std::string filename
char type
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_WRITING
Definition: FileIOFilter.h:25
@ CC_FERR_BAD_ARGUMENT
Definition: FileIOFilter.h:22
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
@ CC_FERR_BAD_ENTITY_TYPE
Definition: FileIOFilter.h:29
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Generic file I/O filter.
Definition: FileIOFilter.h:46
static constexpr float DEFAULT_PRIORITY
Definition: FileIOFilter.h:313
static QString writerInfo()
static QString version()
static QString applicationName()
virtual bool canSave(CV_CLASS_ENUM type, bool &multiple, bool &exclusive) const override
Returns whether this I/O filter can save the specified type of entity.
Definition: MAFilter.cpp:70
virtual CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters &parameters) override
Saves an entity (or a group of) to a file.
Definition: MAFilter.cpp:81
MAFilter()
Definition: MAFilter.cpp:64
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Generic mesh interface.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
A 3D cloud interface with associated features (color, normals, octree, etc.)
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
CCVector3d toGlobal3d(const Vector3Tpl< T > &Plocal) const
Returns the point back-projected into the original coordinates system.
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
virtual VerticesIndexes * getNextTriangleVertIndexes()=0
virtual unsigned size() const =0
Returns the number of triangles.
virtual void placeIteratorAtBeginning()=0
Places the mesh iterator at the beginning.
bool oneStep()
Increments total progress value of a single unit.
RGB color structure.
Definition: ecvColorTypes.h:49
Graphical progress indicator (thread-safe)
@ MESH
Definition: CVTypes.h:105
@ POINT_CLOUD
Definition: CVTypes.h:104
std::string toString(T x)
Definition: Common.h:80
constexpr ColorCompType MAX
Max value of a single color component (default type)
Definition: ecvColorTypes.h:34
Generic saving parameters.
Definition: FileIOFilter.h:84
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:93
Triangle described by the indexes of its 3 vertices.