Developer Documentation
FilePTS.cc
1 //================================================================
2 //
3 /*===========================================================================*\
4 * *
5  * OpenFlipper *
6  * Copyright (c) 2001-2015, RWTH-Aachen University *
7  * Department of Computer Graphics and Multimedia *
8  * All rights reserved. *
9  * www.openflipper.org *
10  * *
11  *---------------------------------------------------------------------------*
12  * This file is part of OpenFlipper. *
13  *---------------------------------------------------------------------------*
14  * *
15  * Redistribution and use in source and binary forms, with or without *
16  * modification, are permitted provided that the following conditions *
17  * are met: *
18  * *
19  * 1. Redistributions of source code must retain the above copyright notice, *
20  * this list of conditions and the following disclaimer. *
21  * *
22  * 2. Redistributions in binary form must reproduce the above copyright *
23  * notice, this list of conditions and the following disclaimer in the *
24  * documentation and/or other materials provided with the distribution. *
25  * *
26  * 3. Neither the name of the copyright holder nor the names of its *
27  * contributors may be used to endorse or promote products derived from *
28  * this software without specific prior written permission. *
29  * *
30  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
31  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
32  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
33  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
34  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
35  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
36  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
37  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
38  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
39  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
40  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
41  * *
42  \*===========================================================================*/
43 
44 
45 
46 //================================================================
47 //
48 // CLASS FilePTSPlugin - IMPLEMENTATION
49 //
50 //================================================================
51 
52 
53 //== INCLUDES ====================================================
54 
55 
56 #include "FilePTS.hh"
57 
58 #include "Snappy/snappy.h"
59 
60  #include <QtWidgets>
61 
64 
65 
66 //== CONSTANTS ===================================================
67 
68 
69 // constants of color range drop down box
70 static const int COLORRANGE_0_1 = 0;
71 //static const int COLORRANGE_0_255 = 1;
72 
73 
74 //== IMPLEMENTATION ==============================================
75 
76 
77 FilePTSPlugin::FilePTSPlugin() :
78  loadOptions_( 0 ),
79  saveOptions_( 0 ),
80  loadBinaryFile_( 0 ),
81  loadNormals_ ( 0 ),
82  loadPointsizes_( 0 ),
83  loadColors_ ( 0 ),
84  loadColorRange_( 0 ),
85  loadIndices_ ( 0 ),
86  saveBinaryFile_( 0 ),
87  saveNormals_ ( 0 ),
88  savePointsizes_( 0 ),
89  saveColors_ ( 0 ),
90  saveColorRange_( 0 ),
91  saveIndices_ ( 0 ),
92  loadMakeDefaultButton_( 0 ),
93  saveMakeDefaultButton_( 0 )
94 { }
95 
96 //----------------------------------------------------------------
97 
98 void FilePTSPlugin::initializePlugin()
99 {
100  QString info =
101  "This plugin is based on the Snappy compression library by google<br> "
102  "<br> "
103  "The following license applies to their code: <br> "
104  "Copyright 2005 Google Inc.All Rights Reserved. <br>"
105  " <br>"
106  "Redistribution and use in source and binary forms, with or without <br>"
107  "modification, are permitted provided that the following conditions are <br>"
108  "met : <br>"
109  " <br>"
110  " *Redistributions of source code must retain the above copyright <br>"
111  "notice, this list of conditions and the following disclaimer. <br>"
112  " * Redistributions in binary form must reproduce the above <br>"
113  "copyright notice, this list of conditions and the following disclaimer <br>"
114  "in the documentation and / or other materials provided with the <br>"
115  "distribution. <br>"
116  " * Neither the name of Google Inc.nor the names of its <br>"
117  "contributors may be used to endorse or promote products derived from <br>"
118  "this software without specific prior written permission. <br>"
119  " <br>"
120  "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS <br>"
121  "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT <br>"
122  "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR <br>"
123  "A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT <br>"
124  "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, <br>"
125  "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT <br>"
126  "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, <br>"
127  "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY <br>"
128  "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT <br>"
129  "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE <br>"
130  "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
131 
132  emit addAboutInfo(info, "FilePTS");
133 }
134 
135 //----------------------------------------------------------------
136 
137 namespace SplatDataFileFormat
138 {
139  // Standard Property Types (File Format)
140  enum STDPropTypes
141  {
142  FLOAT = 0,
143  FLOATVEC2 = 1,
144  FLOATVEC3 = 2,
145  DOUBLE = 3,
146  DOUBLEVEC2 = 4,
147  DOUBLEVEC3 = 5,
148  INT32 = 6,
149  INT32VEC2 = 7,
150  INT32VEC3 = 8,
151  INT16 = 9,
152  INT16VEC2 = 10,
153  INT16VEC3 = 11,
154  INT8 = 12,
155  INT8VEC2 = 13,
156  INT8VEC3 = 14,
157  UINT32 = 15,
158  UINT32VEC2 = 16,
159  UINT32VEC3 = 17,
160  UINT16 = 18,
161  UINT16VEC2 = 19,
162  UINT16VEC3 = 20,
163  UINT8 = 21,
164  UINT8VEC2 = 22,
165  UINT8VEC3 = 23,
166  INT32ARRAY = 24,
167  FLOATVEC2ARRAY = 25,
168  FLOATVEC3ARRAY = 26,
169  };
170 }
171 
172 
173 bool FilePTSPlugin::readBinaryFile( const char *_filename, SplatCloud &_splatCloud ) /*const*/
174 {
175  // clear splatcloud
176  _splatCloud.clear();
177 
178  // set default options
179  bool loadNormals = OpenFlipperSettings().value( "FilePTS/Load/Normals", true ).toBool();
180  bool loadPointsizes = OpenFlipperSettings().value( "FilePTS/Load/Pointsizes", false ).toBool();
181  bool loadColors = OpenFlipperSettings().value( "FilePTS/Load/Colors", false ).toBool();
182 //int loadColorRange = 0;
183  bool loadIndices = OpenFlipperSettings().value( "FilePTS/Load/Indices", false ).toBool();
184 
185  // get options
186  if( OpenFlipper::Options::gui() && loadOptions_ )
187  {
188  loadNormals = loadNormals_-> isChecked();
189  loadPointsizes = loadPointsizes_->isChecked();
190  loadColors = loadColors_-> isChecked();
191 // loadColorRange = loadColorRange_->currentIndex();
192  loadIndices = loadIndices_-> isChecked();
193  }
194 
195  // request properties
196  bool success = true;
197  { if( !_splatCloud.requestPositions() ) success = false; }
198  if( loadNormals ) { if( !_splatCloud.requestNormals() ) success = false; }
199  if( loadPointsizes ) { if( !_splatCloud.requestPointsizes() ) success = false; }
200  if( loadColors ) { if( !_splatCloud.requestColors() ) success = false; }
201  if( loadIndices ) { if( !_splatCloud.requestIndices() ) success = false; }
202 
203  // check success of requests
204  if( !success )
205  {
206  emit log( LOGERR, tr("Out of memory for input file \"%1\".\n").arg( _filename ) );
207  return false; // return failure
208  }
209 
210  // open file
211  FILE *file = fopen( _filename, "rb" );
212  if( !file )
213  {
214  emit log( LOGERR, tr("Could not open input file \"%1\".\n").arg( _filename ) );
215  return false;
216  }
217 
218  // read file type
219  int fileType = 0;
220  fread( &fileType, sizeof(int), 1, file );
221 
222  // check file type
223  if( fileType != 1 && fileType != 2 && fileType != 3 )
224  {
225  emit log( LOGERR, tr("Bad filetype (%1) in input file \"%2\".\n").arg( QString::number( fileType ), _filename ) );
226  fclose( file );
227  return false; // return failure
228  }
229 
230  // read number of splats
231  unsigned int numSplats = 0;
232  fread( &numSplats, sizeof(unsigned int), 1, file );
233 
234  // set number of splats
235  _splatCloud.resizeSplats( numSplats );
236 
237  if (fileType < 3)
238  {
239  // read positions
240  {
241  unsigned int i;
242  for (i = 0; i < numSplats; ++i)
243  {
244  float pos[3];
245  fread(pos, sizeof(float), 3, file);
246 
247  SplatCloud::Position position;
248  position[0] = pos[0];
249  position[1] = pos[1];
250  position[2] = pos[2];
251 
252  _splatCloud.positions(i) = position;
253  }
254  }
255 
256  // read normals
257  if (loadNormals)
258  {
259  unsigned int i;
260  for (i = 0; i < numSplats; ++i)
261  {
262  float nrm[3];
263  fread(nrm, sizeof(float), 3, file);
264 
265  SplatCloud::Normal normal;
266  normal[0] = nrm[0];
267  normal[1] = nrm[1];
268  normal[2] = nrm[2];
269 
270  _splatCloud.normals(i) = normal;
271  }
272  }
273 
274  // read pointsizes
275  if (loadPointsizes)
276  {
277  unsigned int i;
278  for (i = 0; i < numSplats; ++i)
279  {
280  float ps = 0.0f;
281  fread(&ps, sizeof(float), 1, file);
282 
283  SplatCloud::Pointsize pointsize;
284  pointsize = ps;
285 
286  _splatCloud.pointsizes(i) = pointsize;
287  }
288  }
289 
290  // read colors
291  if (loadColors)
292  {
293  unsigned int i;
294  for (i = 0; i < numSplats; ++i)
295  {
296  unsigned int col = 0;
297  fread(&col, sizeof(unsigned int), 1, file);
298 
299  SplatCloud::Color color; // ignore colorrange
300  color[0] = (unsigned char)((col >> 16) & 0xFF);
301  color[1] = (unsigned char)((col >> 8) & 0xFF);
302  color[2] = (unsigned char)((col) & 0xFF);
303 
304  _splatCloud.colors(i) = color;
305  }
306  }
307 
308  // read indices
309  if (loadIndices)
310  {
311  unsigned int i;
312  for (i = 0; i < numSplats; ++i)
313  {
314  int idx = -1;
315  fread(&idx, sizeof(idx), 1, file);
316 
317  SplatCloud::Index index;
318  index = idx;
319 
320  _splatCloud.indices(i) = index;
321  }
322  }
323  }
324  else if (fileType == 3)
325  {
326  // file contains named property containers
327 
328  int numProperties = 0;
329  fread(&numProperties, sizeof(int), 1, file);
330 
331  for (int propID = 0; propID < numProperties; ++propID)
332  {
333  // read property chunk
334 
335  // property name
336  int propNameLen = 0;
337  fread(&propNameLen, sizeof(int), 1, file);
338  std::string propName(propNameLen, 0);
339  if (propNameLen > 0)
340  fread(&propName[0], 1, propNameLen, file);
341 
342  // property data type
343  int dataType = 0;
344  fread(&dataType, sizeof(int), 1, file);
345 
346  // size of compressed data chunk
347  quint64 compressedSize = 0;
348  fread(&compressedSize, sizeof(quint64), 1, file);
349  size_t compressedSizeT = static_cast<size_t>(compressedSize);
350 
351  if (compressedSize)
352  {
353  // read data
354  if (dataType == SplatDataFileFormat::FLOATVEC3)
355  {
356  if (propName == "Points")
357  readCompressedBinaryChunk(file, compressedSizeT, reinterpret_cast<char*>(&_splatCloud.positions(0)));
358  else if (propName == "Normals" && loadNormals)
359  readCompressedBinaryChunk(file, compressedSizeT, reinterpret_cast<char*>(&_splatCloud.normals(0)));
360  else
361  fseek(file, static_cast<long>(compressedSizeT), SEEK_CUR);
362  }
363  else if (dataType == SplatDataFileFormat::FLOAT)
364  {
365  if (propName == "Radii" && loadPointsizes)
366  readCompressedBinaryChunk(file, compressedSizeT, reinterpret_cast<char*>(&_splatCloud.pointsizes(0)));
367  else
368  fseek(file, static_cast<long>(compressedSizeT), SEEK_CUR);
369  }
370  else if (dataType == SplatDataFileFormat::UINT16)
371  {
372  fseek(file, static_cast<long>(compressedSizeT), SEEK_CUR);
373  }
374  else if (dataType == SplatDataFileFormat::UINT32)
375  {
376  if (propName == "Colors" && loadColors)
377  {
378  std::vector<ACG::Vec4uc> fileColors(numSplats);
379  readCompressedBinaryChunk(file, compressedSizeT, reinterpret_cast<char*>(&fileColors[0]));
380 
381  for (uint i = 0; i < numSplats; ++i)
382  {
383  for (int k = 0; k < 3; ++k)
384  _splatCloud.colors(i)[k] = fileColors[i][k];
385  }
386  }
387  else
388  fseek(file, static_cast<long>(compressedSizeT), SEEK_CUR);
389  }
390  else if (dataType == SplatDataFileFormat::INT32)
391  {
392  fseek(file, static_cast<long>(compressedSizeT), SEEK_CUR);
393  }
394  else
395  {
396  emit log(LOGWARN, tr("Unknown Property type. \"%1\".\n").arg(_filename));
397  fseek(file, static_cast<long>(compressedSizeT), SEEK_CUR);
398  }
399  }
400  }
401  }
402 
403 
404 
405  // check for errors
406  if( ferror( file ) )
407  {
408  emit log( LOGERR, tr("Could not read input file \"%1\".\n").arg( _filename ) );
409  fclose( file );
410  return false; // return failure
411  }
412  if( feof( file ) )
413  {
414  emit log( LOGERR, tr("Unexpected end in input file \"%1\".\n").arg( _filename ) );
415  fclose( file );
416  return false; // return failure
417  }
418 
419  // close file
420  fclose( file );
421 
422  // return success
423  return true;
424 }
425 
426 
427 //----------------------------------------------------------------
428 
429 
430 bool FilePTSPlugin::readTextFile( const char *_filename, SplatCloud &_splatCloud ) /*const*/
431 {
432  // clear splatcloud
433  _splatCloud.clear();
434 
435  // set default options
436  bool loadNormals = OpenFlipperSettings().value( "FilePTS/Load/Normals", true ).toBool();
437  bool loadPointsizes = OpenFlipperSettings().value( "FilePTS/Load/Pointsizes", false ).toBool();
438  bool loadColors = OpenFlipperSettings().value( "FilePTS/Load/Colors", false ).toBool();
439  int loadColorRange = OpenFlipperSettings().value( "FilePTS/Load/ColorRange",0 ).toInt();
440  bool loadIndices = OpenFlipperSettings().value( "FilePTS/Load/Indices", false ).toBool();
441 
442  // get options
443  if( OpenFlipper::Options::gui() && loadOptions_ )
444  {
445  loadNormals = loadNormals_ ->isChecked();
446  loadPointsizes = loadPointsizes_->isChecked();
447  loadColors = loadColors_ ->isChecked();
448  loadColorRange = loadColorRange_->currentIndex();
449  loadIndices = loadIndices_ ->isChecked();
450  }
451 
452  // request properties
453  bool success = true;
454  { if( !_splatCloud.requestPositions() ) success = false; }
455  if( loadNormals ) { if( !_splatCloud.requestNormals() ) success = false; }
456  if( loadPointsizes ) { if( !_splatCloud.requestPointsizes() ) success = false; }
457  if( loadColors ) { if( !_splatCloud.requestColors() ) success = false; }
458  if( loadIndices ) { if( !_splatCloud.requestIndices() ) success = false; }
459 
460  // check success of requests
461  if( !success )
462  {
463  emit log( LOGERR, tr("Out of memory for input file \"%1\".\n").arg( _filename ) );
464  return false; // return failure
465  }
466 
467  // open file
468  FILE *file = fopen( _filename, "rb" );
469  if( !file )
470  {
471  emit log( LOGERR, tr("Could not open input file \"%1\".\n").arg( _filename ) );
472  return false;
473  }
474 
475 
476  int splatIdx;
477  for( splatIdx = 0; ; ++splatIdx )
478  {
479  // read position
480  {
481  float pos[3];
482 
483  const int read = fscanf( file, "%32f %32f %32f", &pos[0], &pos[1], &pos[2] );
484  if( read != 3 ) {
485  emit log( LOGERR, tr("Scanned for 3 coordinates but got %1 at Index %2.\n").arg( read ).arg(splatIdx) );
486  break;
487  }
488 
489  // increase number of splats
490  _splatCloud.pushbackSplat();
491 
492  SplatCloud::Position position;
493  position[0] = pos[0];
494  position[1] = pos[1];
495  position[2] = pos[2];
496 
497  _splatCloud.positions( splatIdx ) = position;
498  }
499 
500  // read color
501  if( loadColors )
502  {
503  float col[3];
504 
505  const int read = fscanf( file, "%32f %32f %32f", &col[0], &col[1], &col[2] );
506  if( read != 3 ) {
507  emit log( LOGERR, tr("Scanned for 3 colors but got %1 at Index %2.\n").arg( read ).arg(splatIdx) );
508  break;
509  }
510 
511  SplatCloud::Color color;
512 
513  if( loadColorRange == COLORRANGE_0_1 )
514  {
515  color[0] = (unsigned char) (255.999f * col[0]);
516  color[1] = (unsigned char) (255.999f * col[1]);
517  color[2] = (unsigned char) (255.999f * col[2]);
518  }
519  else // loadColorRange == COLORRANGE_0_255
520  {
521  color[0] = (unsigned char) col[0];
522  color[1] = (unsigned char) col[1];
523  color[2] = (unsigned char) col[2];
524  }
525 
526  _splatCloud.colors( splatIdx ) = color;
527  }
528 
529  // read normal
530  if( loadNormals )
531  {
532  float nrm[3];
533  fscanf( file, "%32f %32f %32f", &nrm[0], &nrm[1], &nrm[2] );
534 
535  SplatCloud::Normal normal;
536  normal[0] = nrm[0];
537  normal[1] = nrm[1];
538  normal[2] = nrm[2];
539 
540  _splatCloud.normals( splatIdx ) = normal;
541  }
542 
543  // read pointsize
544  if( loadPointsizes )
545  {
546  float ps = 0.0f;
547  fscanf( file, "%32f", &ps );
548 
549  SplatCloud::Pointsize pointsize;
550  pointsize = ps;
551 
552  _splatCloud.pointsizes( splatIdx ) = pointsize;
553  }
554 
555  // read index
556  if( loadIndices )
557  {
558  int idx = -1;
559  fscanf( file, "%16i", &idx );
560 
561  SplatCloud::Index index;
562  index = idx;
563 
564  _splatCloud.indices( splatIdx ) = index;
565  }
566 
567  // check for errors
568  if( ferror( file ) )
569  {
570  emit log( LOGERR, tr("Could not read input file \"%1\".\n").arg( _filename ) );
571  fclose( file );
572  return false; // return failure
573  }
574  if( feof( file ) )
575  {
576  emit log( LOGERR, tr("Unexpected end in input file \"%1\".\n").arg( _filename ) );
577  fclose( file );
578  return false; // return failure
579  }
580 
581  }
582 
583  // check for errors
584  if( !feof( file ) ) // if end-of-file is *not* reached, something went wrong
585  {
586  emit log( LOGERR, tr("Bad file format of input file \"%1\".\n").arg( _filename ) );
587  fclose( file );
588  return false; // return failure
589  }
590 
591  // close file
592  fclose( file );
593 
594  // return success
595  return true;
596 }
597 
598 
599 //----------------------------------------------------------------
600 
601 
602 bool FilePTSPlugin::writeBinaryFile( const char *_filename, const SplatCloudNode *_splatCloudNode ) /*const*/
603 {
604  // set default options
605  bool saveNormals = OpenFlipperSettings().value( "FilePTS/Save/Normals", true ).toBool();
606  bool savePointsizes = OpenFlipperSettings().value( "FilePTS/Save/Pointsizes", false ).toBool();
607  bool saveColors = OpenFlipperSettings().value( "FilePTS/Save/Colors", false ).toBool();
608 //int saveColorRange = 0;
609  bool saveIndices = OpenFlipperSettings().value( "FilePTS/Save/Indices", false ).toBool();
610 
611  // get options
612  if( OpenFlipper::Options::gui() && saveOptions_ )
613  {
614  saveNormals = saveNormals_-> isChecked();
615  savePointsizes = savePointsizes_->isChecked();
616  saveColors = saveColors_-> isChecked();
617 // saveColorRange = saveColorRange_->currentIndex();
618  saveIndices = saveIndices_-> isChecked();
619  }
620 
621  // use default values instead of returning a failure
622 
624 //if( ( !_splatCloudNode->splatCloud().hasPositions() ) ||
625 // (saveNormals && !_splatCloudNode->splatCloud().hasNormals()) ) ||
626 // (savePointsizes && !_splatCloudNode->splatCloud().hasPointsizes()) ||
627 // (saveColors && !_splatCloudNode->splatCloud().hasColors() ) ||
628 // (saveIndices && !_splatCloudNode->splatCloud().hasIndices() )
629 //{
630 // emit log( LOGERR, tr("Desired properties not available for output file \"%1\".\n").arg( _filename ) );
631 // return false; // return failure
632 //}
633 
634  // open file
635  FILE *file = fopen( _filename, "wb" );
636  if( !file )
637  {
638  emit log( LOGERR, tr("Could not open output file \"%1\".\n").arg( _filename ) );
639  return false;
640  }
641 
642  // write file type
643  int fileType = 1;
644  fwrite( &fileType, sizeof(int), 1, file );
645 
646  // write number of splats
647  unsigned int numSplats = _splatCloudNode->splatCloud().numSplats();
648  fwrite( &numSplats, sizeof(unsigned int), 1, file );
649 
650  // write positions
651  {
652  unsigned int i;
653  for( i=0; i<numSplats; ++i )
654  {
655  const SplatCloud::Position &position = _splatCloudNode->getPosition( i );
656 
657  float pos[3];
658  pos[0] = position[0];
659  pos[1] = position[1];
660  pos[2] = position[2];
661 
662  fwrite( pos, sizeof(float), 3, file );
663  }
664  }
665 
666  // write normals
667  if( saveNormals )
668  {
669  unsigned int i;
670  for( i=0; i<numSplats; ++i )
671  {
672  const SplatCloud::Normal &normal = _splatCloudNode->getNormal( i );
673 
674  float nrm[3];
675  nrm[0] = normal[0];
676  nrm[1] = normal[1];
677  nrm[2] = normal[2];
678 
679  fwrite( nrm, sizeof(float), 3, file );
680  }
681  }
682 
683  // write pointsizes
684  if( savePointsizes )
685  {
686  unsigned int i;
687  for( i=0; i<numSplats; ++i )
688  {
689  const SplatCloud::Pointsize &pointsize = _splatCloudNode->getPointsize( i );
690 
691  float ps;
692  ps = pointsize;
693 
694  fwrite( &ps, sizeof(float), 1, file );
695  }
696  }
697 
698  // write colors
699  if( saveColors )
700  {
701  unsigned int i;
702  for( i=0; i<numSplats; ++i )
703  {
704  const SplatCloud::Color &color = _splatCloudNode->getColor( i );
705 
706  unsigned int col; // ignore colorrange
707  col = (0xFF << 24) | (color[0] << 16) | (color[1] << 8) | (color[2]);
708 
709  fwrite( &col, sizeof(unsigned int), 1, file );
710  }
711  }
712 
713  // write indices
714  if( saveIndices )
715  {
716  unsigned int i;
717  for( i=0; i<numSplats; ++i )
718  {
719  const SplatCloud::Index &index = _splatCloudNode->getIndex( i );
720 
721  int idx;
722  idx = index;
723 
724  fwrite( &idx, sizeof(int), 1, file );
725  }
726  }
727 
728  // check for errors
729  if( ferror( file ) )
730  {
731  emit log( LOGERR, tr("Could not write output file \"%1\".\n").arg( _filename ) );
732  fclose( file );
733  return false; // return failure
734  }
735 
736  // close file
737  fclose( file );
738 
739  // return success
740  return true;
741 }
742 
743 
744 //----------------------------------------------------------------
745 
746 
747 bool FilePTSPlugin::writeTextFile( const char *_filename, const SplatCloudNode *_splatCloudNode ) /*const*/
748 {
749  // set default options
750  bool saveNormals = OpenFlipperSettings().value( "FilePTS/Save/Normals", true ).toBool();
751  bool savePointsizes = OpenFlipperSettings().value( "FilePTS/Save/Pointsizes", false ).toBool();
752  bool saveColors = OpenFlipperSettings().value( "FilePTS/Save/Colors", false ).toBool();
753  int saveColorRange = OpenFlipperSettings().value( "FilePTS/Save/ColorRange",0 ).toInt();
754  bool saveIndices = OpenFlipperSettings().value( "FilePTS/Save/Indices", false ).toBool();
755 
756  // get options
757  if( OpenFlipper::Options::gui() && saveOptions_ )
758  {
759  saveNormals = saveNormals_-> isChecked();
760  savePointsizes = savePointsizes_->isChecked();
761  saveColors = saveColors_-> isChecked();
762  saveColorRange = saveColorRange_->currentIndex();
763  saveIndices = saveIndices_-> isChecked();
764  }
765 
766  // use default values instead of returning a failure
767 
769 //if( ( !_splatCloudNode->splatCloud().hasPositions() ) ||
770 // (saveNormals && !_splatCloudNode->splatCloud().hasNormals()) ) ||
771 // (savePointsizes && !_splatCloudNode->splatCloud().hasPointsizes()) ||
772 // (saveColors && !_splatCloudNode->splatCloud().hasColors() ) ||
773 // (saveIndices && !_splatCloudNode->splatCloud().hasIndices() )
774 //{
775 // emit log( LOGERR, tr("Desired properties not available for output file \"%1\".\n").arg( _filename) );
776 // return false; // return failure
777 //}
778 
779  // open file
780  FILE *file = fopen( _filename, "wt" );
781  if( !file )
782  {
783  emit log( LOGERR, tr("Could not open output file \"%1\".\n").arg( _filename ) );
784  return false;
785  }
786 
787  // for all splats...
788  unsigned int i, numSplats = _splatCloudNode->splatCloud().numSplats();
789  for( i=0; i<numSplats; ++i )
790  {
791  // write position
792  {
793  const SplatCloud::Position &position = _splatCloudNode->getPosition( i );
794 
795  float pos[3];
796  pos[0] = position[0];
797  pos[1] = position[1];
798  pos[2] = position[2];
799 
800  fprintf( file, "%.6g %.6g %.6g", pos[0], pos[1], pos[2] );
801  }
802 
803  // write color
804  if( saveColors )
805  {
806  const SplatCloud::Color &color = _splatCloudNode->getColor( i );
807 
808  if( saveColorRange == COLORRANGE_0_1 )
809  {
810  static const float RCP255 = 1.0f / 255.0f;
811 
812  float col[3];
813  col[0] = RCP255 * color[0];
814  col[1] = RCP255 * color[1];
815  col[2] = RCP255 * color[2];
816 
817  fprintf( file, " %.6g %.6g %.6g", col[0], col[1], col[2] );
818  }
819  else // saveColorRange == COLORRANGE_0_255
820  {
821  int col[3]; // use int, *not* unsigned char !
822  col[0] = color[0];
823  col[1] = color[1];
824  col[2] = color[2];
825 
826  fprintf( file, " %i %i %i", col[0], col[1], col[2] );
827  }
828  }
829 
830  // write normal
831  if( saveNormals )
832  {
833  const SplatCloud::Normal &normal = _splatCloudNode->getNormal( i );
834 
835  float nrm[3];
836  nrm[0] = normal[0];
837  nrm[1] = normal[1];
838  nrm[2] = normal[2];
839 
840  fprintf( file, " %.6g %.6g %.6g", nrm[0], nrm[1], nrm[2] );
841  }
842 
843  // write pointsize
844  if( savePointsizes )
845  {
846  const SplatCloud::Pointsize &pointsize = _splatCloudNode->getPointsize( i );
847 
848  float ps;
849  ps = pointsize;
850 
851  fprintf( file, " %.6g", ps );
852  }
853 
854  // write index
855  if( saveIndices )
856  {
857  const SplatCloud::Index &index = _splatCloudNode->getIndex( i );
858 
859  int idx;
860  idx = index;
861 
862  fprintf( file, " %i", idx );
863  }
864 
865  fprintf( file, "\n" );
866  }
867 
868  // check for errors
869  if( ferror( file ) )
870  {
871  emit log( LOGERR, tr("Could not write output file \"%1\".\n").arg( _filename ) );
872  fclose( file );
873  return false; // return failure
874  }
875 
876  // close file
877  fclose( file );
878 
879  // return success
880  return true;
881 }
882 
883 
884 //----------------------------------------------------------------
885 
886 
887 bool FilePTSPlugin::readCompressedBinaryChunk(FILE* _file, size_t _compressedSize, char* _dst)
888 {
889  std::vector<char> compressedData(_compressedSize);
890  fread(&compressedData[0], 1, _compressedSize, _file);
891  return snappy::RawUncompress(&compressedData[0], _compressedSize, _dst);
892 }
893 
894 //----------------------------------------------------------------
895 
896 
897 int FilePTSPlugin::loadObject( QString _filename )
898 {
899  // set default options
900  bool loadBinaryFile = OpenFlipperSettings().value( "FilePTS/Load/BinaryFile", false ).toBool();
901 
902  // get options
903  if( OpenFlipper::Options::gui() && loadOptions_ )
904  {
905  loadBinaryFile = loadBinaryFile_->isChecked();
906  }
907 
908  // add a new, empty splatcloud-object
909  int splatCloudObjectId = -1;
910  emit addEmptyObject( DATA_SPLATCLOUD, splatCloudObjectId );
911  if( splatCloudObjectId != -1 )
912  {
913  // create list of ids and add id of splatcloud-object
914  IdList objectIDs;
915  objectIDs.push_back( splatCloudObjectId );
916 
917  // get splatcloud-object by id
919  if( PluginFunctions::getObject( splatCloudObjectId, splatCloudObject ) )
920  {
921  // set name of splatcloud-object to filename
922  splatCloudObject->setFromFileName( _filename );
923  splatCloudObject->setName( splatCloudObject->filename() );
924 
925  // get splatcloud and scenegraph splatcloud-node
926  SplatCloud *splatCloud = splatCloudObject->splatCloud();
927  SplatCloudNode *splatCloudNode = splatCloudObject->splatCloudNode();
928  if( (splatCloud != 0) && (splatCloudNode != 0) )
929  {
930  // read splatcloud from disk
931  if( loadBinaryFile ? readBinaryFile( _filename.toLatin1(), *splatCloud ) : readTextFile( _filename.toLatin1(), *splatCloud ) )
932  {
933  // emit signals that the object has to be updated and that a file was opened
934  emit updatedObject( splatCloudObjectId, UPDATE_ALL );
935  emit openedFile( splatCloudObjectId );
936 
937  // get drawmodes
941 
942  // if drawmodes don't exist something went wrong
943  if( splatsDrawMode == ACG::SceneGraph::DrawModes::NONE ||
944  dotsDrawMode == ACG::SceneGraph::DrawModes::NONE ||
945  pointsDrawMode == ACG::SceneGraph::DrawModes::NONE )
946  {
947  emit log( LOGERR, tr("Shader DrawModes for SplatCloud not existent!") );
948  }
949  else
950  {
951  // get global drawmode
953 
954  // if global drawmode does *not* contain any of 'Splats', 'Dots' or 'Points' drawmode, add 'Points'
955  if( !drawmode.containsAtomicDrawMode( splatsDrawMode ) &&
956  !drawmode.containsAtomicDrawMode( dotsDrawMode ) &&
957  !drawmode.containsAtomicDrawMode( pointsDrawMode ) )
958  {
959  drawmode |= pointsDrawMode;
960  PluginFunctions::setDrawMode( drawmode );
961  }
962  }
963 
964  // group objects
965  int groupObjectId = RPC::callFunctionValue<int>( "datacontrol", "groupObjects", objectIDs );
966  if( groupObjectId != -1 )
967  {
968  // everything is okay, so return id of group-object
969  return groupObjectId;
970  }
971  }
972  }
973  }
974 
975  // something went wrong, so delete objects
976  size_t i, num = objectIDs.size();
977  for( i=0; i<num; ++i )
978  emit deleteObject( objectIDs[ i ] );
979  }
980 
981  // return failure
982  return -1;
983 }
984 
985 
986 //----------------------------------------------------------------
987 
988 
989 bool FilePTSPlugin::saveObject( int _objectId, QString _filename )
990 {
991  // set default options
992  bool saveBinaryFile = OpenFlipperSettings().value( "FilePTS/Save/BinaryFile", false ).toBool();
993 
994  // get options
995  if( OpenFlipper::Options::gui() && saveOptions_ )
996  {
997  saveBinaryFile = saveBinaryFile_->isChecked();
998  }
999 
1000  // get splatcloud-object by id
1001  SplatCloudObject *splatCloudObject = 0;
1002  if( PluginFunctions::getObject( _objectId, splatCloudObject ) )
1003  {
1004  // change name of splatcloud-object to filename
1005  splatCloudObject->setFromFileName( _filename );
1006  splatCloudObject->setName( splatCloudObject->filename() );
1007 
1008  // get splatcloud-node
1009  const SplatCloudNode *splatCloudNode = splatCloudObject->splatCloudNode();
1010  if( splatCloudNode != 0 )
1011  {
1012  // write splatcloud to disk
1013  if( saveBinaryFile ? writeBinaryFile( _filename.toLatin1(), splatCloudNode ) : writeTextFile( _filename.toLatin1(), splatCloudNode ) )
1014  {
1015  // return success
1016  return true;
1017  }
1018  }
1019  }
1020 
1021  // return failure
1022  return false;
1023 }
1024 
1025 
1026 //----------------------------------------------------------------
1027 
1028 
1029 QWidget *FilePTSPlugin::loadOptionsWidget( QString /*_currentFilter*/ )
1030 {
1031  if( loadOptions_ == 0 )
1032  {
1033  // create new widget (including Load Options and buttons)
1034 
1035  loadBinaryFile_ = new QCheckBox( tr("Load as Binary File") );
1036 
1037  loadNormals_ = new QCheckBox( tr("Contains Normals") );
1038  loadPointsizes_ = new QCheckBox( tr("Contains Pointsizes") );
1039  loadColors_ = new QCheckBox( tr("Contains Colors") );
1040 
1041  loadColorRange_ = new QComboBox();
1042  loadColorRange_->addItem( "[0..1]" );
1043  loadColorRange_->addItem( "[0..255]" );
1044  slotUpdateLoadColorRange();
1045 
1046  QHBoxLayout *loadColorsLayout = new QHBoxLayout();
1047  loadColorsLayout->setSpacing( 6 );
1048  loadColorsLayout->addWidget( loadColors_ );
1049  loadColorsLayout->addWidget( loadColorRange_ );
1050 
1051  loadIndices_ = new QCheckBox( tr("Contains Indices") );
1052 
1053  QVBoxLayout *loadStructureLayout = new QVBoxLayout();
1054  loadStructureLayout->setSpacing( 6 );
1055  loadStructureLayout->addWidget( loadNormals_ );
1056  loadStructureLayout->addWidget( loadPointsizes_ );
1057  loadStructureLayout->addItem ( loadColorsLayout );
1058  loadStructureLayout->addWidget( loadIndices_ );
1059 
1060  QGroupBox *loadStructureGroupBox = new QGroupBox( tr("Internal File Structure") );
1061  loadStructureGroupBox->setLayout( loadStructureLayout );
1062 
1063  loadMakeDefaultButton_ = new QPushButton( tr("Make Default") );
1064 
1065  QVBoxLayout *loadLayout = new QVBoxLayout();
1066  loadLayout->setAlignment( Qt::AlignTop );
1067  loadLayout->setSpacing( 6 );
1068  loadLayout->addWidget( loadBinaryFile_ );
1069  loadLayout->addWidget( loadStructureGroupBox );
1070  loadLayout->addWidget( loadMakeDefaultButton_ );
1071 
1072  loadOptions_ = new QWidget();
1073  loadOptions_->setLayout( loadLayout );
1074 
1075  // connect events to slots
1076  connect( loadBinaryFile_, SIGNAL( stateChanged(int) ), this, SLOT( slotUpdateLoadColorRange() ) );
1077  connect( loadColors_, SIGNAL( stateChanged(int) ), this, SLOT( slotUpdateLoadColorRange() ) );
1078  connect( loadMakeDefaultButton_, SIGNAL( clicked() ), this, SLOT( slotLoadMakeDefaultButtonClicked() ) );
1079 
1080  // get Load Options from OpenFlipper (from disc)
1081  loadBinaryFile_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Load/BinaryFile", true ).toBool() );
1082  loadNormals_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Load/Normals", true ).toBool() );
1083  loadPointsizes_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Load/Pointsizes", true ).toBool() );
1084  loadColors_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Load/Colors", true ).toBool() );
1085  loadColorRange_-> setCurrentIndex( OpenFlipperSettings().value( "FilePTS/Load/ColorRange", 0 ).toInt() );
1086  loadIndices_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Load/Indices", true ).toBool() );
1087  }
1088 
1089  return loadOptions_;
1090 }
1091 
1092 
1093 //----------------------------------------------------------------
1094 
1095 
1096 QWidget *FilePTSPlugin::saveOptionsWidget( QString _currentFilter )
1097 {
1098  if( saveOptions_ == 0 )
1099  {
1100  // create new widget (including Save Options and buttons)
1101 
1102  saveBinaryFile_ = new QCheckBox( tr("Save as Binary File") );
1103 
1104  saveNormals_ = new QCheckBox( tr("Save Normals") );
1105  savePointsizes_ = new QCheckBox( tr("Save Pointsizes") );
1106  saveColors_ = new QCheckBox( tr("Save Colors") );
1107 
1108  saveColorRange_ = new QComboBox();
1109  saveColorRange_->addItem( "[0..1]" );
1110  saveColorRange_->addItem( "[0..255]" );
1111  slotUpdateSaveColorRange();
1112 
1113  QHBoxLayout *saveColorsLayout = new QHBoxLayout();
1114  saveColorsLayout->setSpacing( 6 );
1115  saveColorsLayout->addWidget( saveColors_ );
1116  saveColorsLayout->addWidget( saveColorRange_ );
1117 
1118  saveIndices_ = new QCheckBox( tr("Save Indices") );
1119 
1120  QVBoxLayout *saveStructureLayout = new QVBoxLayout();
1121  saveStructureLayout->setSpacing( 6 );
1122  saveStructureLayout->addWidget( saveNormals_ );
1123  saveStructureLayout->addWidget( savePointsizes_ );
1124  saveStructureLayout->addItem ( saveColorsLayout );
1125  saveStructureLayout->addWidget( saveIndices_ );
1126 
1127  QGroupBox *saveStructureGroupBox = new QGroupBox( tr("Internal File Structure") );
1128  saveStructureGroupBox->setLayout( saveStructureLayout );
1129 
1130  saveMakeDefaultButton_ = new QPushButton( tr("Make Default") );
1131 
1132  QVBoxLayout *saveLayout = new QVBoxLayout();
1133  saveLayout->setAlignment( Qt::AlignTop );
1134  saveLayout->setSpacing( 6 );
1135  saveLayout->addWidget( saveBinaryFile_ );
1136  saveLayout->addWidget( saveStructureGroupBox );
1137  saveLayout->addWidget( saveMakeDefaultButton_ );
1138 
1139  saveOptions_ = new QWidget();
1140  saveOptions_->setLayout( saveLayout );
1141 
1142  // connect events to slots
1143  connect( saveBinaryFile_, SIGNAL( stateChanged(int) ), this, SLOT( slotUpdateSaveColorRange() ) );
1144  connect( saveColors_, SIGNAL( stateChanged(int) ), this, SLOT( slotUpdateSaveColorRange() ) );
1145  connect( saveMakeDefaultButton_, SIGNAL( clicked() ), this, SLOT( slotSaveMakeDefaultButtonClicked() ) );
1146 
1147  // get Save Options from OpenFlipper (from disc)
1148  saveBinaryFile_->setChecked ( OpenFlipperSettings().value( "FilePTS/Save/BinaryFile", true ).toBool() );
1149  saveNormals_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Save/Normals", true ).toBool() );
1150  savePointsizes_->setChecked ( OpenFlipperSettings().value( "FilePTS/Save/Pointsizes", true ).toBool() );
1151  saveColors_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Save/Colors", true ).toBool() );
1152  saveColorRange_->setCurrentIndex( OpenFlipperSettings().value( "FilePTS/Save/ColorRange", 0 ).toInt() );
1153  saveIndices_-> setChecked ( OpenFlipperSettings().value( "FilePTS/Save/Indices", true ).toBool() );
1154  }
1155 
1156  return saveOptions_;
1157 }
1158 
1159 
1160 //----------------------------------------------------------------
1161 
1162 
1163 void FilePTSPlugin::slotUpdateLoadColorRange()
1164 {
1165  loadColorRange_->setEnabled( loadColors_->isChecked() && !loadBinaryFile_->isChecked() );
1166 }
1167 
1168 
1169 //----------------------------------------------------------------
1170 
1171 
1172 void FilePTSPlugin::slotUpdateSaveColorRange()
1173 {
1174  saveColorRange_->setEnabled( saveColors_->isChecked() && !saveBinaryFile_->isChecked() );
1175 }
1176 
1177 
1178 //----------------------------------------------------------------
1179 
1180 
1181 void FilePTSPlugin::slotLoadMakeDefaultButtonClicked()
1182 {
1183  // pass our Load Options to OpenFlipper (to disc)
1184  OpenFlipperSettings().setValue( "FilePTS/Load/BinaryFile", loadBinaryFile_->isChecked() );
1185  OpenFlipperSettings().setValue( "FilePTS/Load/Normals", loadNormals_-> isChecked() );
1186  OpenFlipperSettings().setValue( "FilePTS/Load/Pointsizes", loadPointsizes_->isChecked() );
1187  OpenFlipperSettings().setValue( "FilePTS/Load/Colors", loadColors_-> isChecked() );
1188  OpenFlipperSettings().setValue( "FilePTS/Load/ColorRange", loadColorRange_->currentIndex() );
1189  OpenFlipperSettings().setValue( "FilePTS/Load/Indices", loadIndices_-> isChecked() );
1190 
1191 // OpenFlipperSettings().setValue( "Core/File/UseLoadDefaults", true );
1192 }
1193 
1194 
1195 //----------------------------------------------------------------
1196 
1197 
1198 void FilePTSPlugin::slotSaveMakeDefaultButtonClicked()
1199 {
1200  // pass our Save Options to OpenFlipper (to disc)
1201  OpenFlipperSettings().setValue( "FilePTS/Save/BinaryFile", saveBinaryFile_->isChecked() );
1202  OpenFlipperSettings().setValue( "FilePTS/Save/Normals", saveNormals_-> isChecked() );
1203  OpenFlipperSettings().setValue( "FilePTS/Save/Pointsizes", savePointsizes_->isChecked() );
1204  OpenFlipperSettings().setValue( "FilePTS/Save/Colors", saveColors_-> isChecked() );
1205  OpenFlipperSettings().setValue( "FilePTS/Save/ColorRange", saveColorRange_->currentIndex() );
1206  OpenFlipperSettings().setValue( "FilePTS/Save/Indices", saveIndices_-> isChecked() );
1207 }
1208 
1209 
1210 //================================================================
1211 
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
QWidget * loadOptionsWidget(QString)
Definition: FilePTS.cc:1029
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void setName(QString _name)
Set the name of the Object.
bool requestIndices()
Request the predefined property.
Definition: SplatCloud.hh:565
QWidget * saveOptionsWidget(QString)
Definition: FilePTS.cc:1096
const DrawMode & getDrawMode(const std::string &_name)
Get a custom DrawMode.
Definition: DrawModes.cc:807
Color & colors(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:633
void setFromFileName(const QString &_filename)
Definition: BaseObject.cc:716
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
Normal & normals(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:635
virtual void updatedObject(int _objectId)
An object has been changed or added by this plugin.
bool requestPositions()
Request the predefined property.
Definition: SplatCloud.hh:561
virtual void deleteObject(int _id)
Delete an object This signal can be called from any thread. .
void setDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, int _viewer)
Set the draw Mode of a Viewer. .
Position & positions(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:631
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Index & indices(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:639
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
unsigned int numSplats() const
Get the number of splats.
Definition: SplatCloud.hh:179
DrawMode NONE
not a valid draw mode
Definition: DrawModes.cc:71
ACG::SceneGraph::DrawModes::DrawMode drawMode(int _viewer)
Get the current draw Mode of a Viewer.
SplatCloud * splatCloud()
Get SplatCloud.
void clear()
Remove all properties and reset the number of splats.
Definition: SplatCloud.cc:184
SplatCloud * splatCloud(BaseObjectData *_object)
Get a SplatCloud from an object.
void pushbackSplat()
Add one element at the end of the data vector of all splat-properties.
Definition: SplatCloud.cc:231
bool requestNormals()
Request the predefined property.
Definition: SplatCloud.hh:563
bool requestColors()
Request the predefined property.
Definition: SplatCloud.hh:562
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void resizeSplats(unsigned int _num)
Resize the data vector of all splat-properties.
Definition: SplatCloud.cc:246
SplatCloudObject * splatCloudObject(BaseObjectData *_object)
Cast an SplatCloudObject to a SplatCloudObject if possible.
SplatCloudNode * splatCloudNode(BaseObjectData *_object)
Get a SplatCloudNode from an object.
bool containsAtomicDrawMode(const DrawMode &_atomicDrawMode) const
Check whether an Atomic DrawMode is active in this draw Mode.
Definition: DrawModes.cc:520
SplatCloudNode * splatCloudNode()
Get SplatCloud&#39;s scenegraph Node.
const Position & getPosition(int _idx) const
if the data array exists, the entry with the given index is returned, otherwise the default value is ...
Pointsize & pointsizes(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:637
#define DATA_SPLATCLOUD
Definition: SplatCloud.hh:59
bool requestPointsizes()
Request the predefined property.
Definition: SplatCloud.hh:564