Developer Documentation
FileBundle.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 
43 
44 //================================================================
45 //
46 // CLASS FileBundlePlugin - IMPLEMENTATION
47 //
48 //================================================================
49 
50 
51 #ifdef _MSC_VER
52  #if (_MSC_VER <= 1916)
53  #define QT_NO_FLOAT16_OPERATORS
54  #endif
55 #endif
56 
57 
58 //== INCLUDES ====================================================
59 
60 
61 #include "FileBundle.hh"
62 
63 
64 #include <QtWidgets>
65 
66 #include <fstream>
67 
70 
71 #include <OpenMesh/Core/IO/IOManager.hh>
72 
74 
75 
76 //== CONSTANTS ===================================================
77 
78 
79 static const char IMAGELIST_SUFFIX[] = ".txt";
80 static const char IMAGELIST_FALLBACK[] = "image_list.txt";
81 
82 
83 //== IMPLEMENTATION ==============================================
84 
85 
86 static std::string readLine( FILE *_file )
87 {
88  // create empty string
89  std::string result = "";
90 
91  while( true )
92  {
93  // read next char
94  char c;
95  fscanf( _file, "%c", &c );
96 
97  // if end of file or line is reached, break
98  if( feof( _file ) || c == '\0' || c == '\n' || c == '\r' )
99  break;
100 
101  // copy char to string
102  result += c;
103  }
104 
105  // return string
106  return result;
107 }
108 
109 
110 //----------------------------------------------------------------
111 
112 
113 static void splitFilename( const std::string &_str, std::string &_path, std::string &_name, std::string &_ext )
114 {
115  size_t i = _str.find_last_of( "/\\" );
116 
117  std::string rest;
118 
119  if( i == std::string::npos )
120  {
121  _path = "";
122  rest = _str;
123  }
124  else
125  {
126  _path = _str.substr( 0, i+1 ); // 0 .. i
127  rest = _str.substr( i+1 ); // i+1 .. end
128  }
129 
130  size_t j = rest.find_last_of( '.' );
131 
132  if( j == std::string::npos )
133  {
134  _name = rest;
135  _ext = "";
136  }
137  else
138  {
139  _name = rest.substr( 0, j ); // 0 .. j-1
140  _ext = rest.substr( j ); // j .. end
141  }
142 }
143 
144 
145 //----------------------------------------------------------------
146 
147 
148 bool FileBundlePlugin::addEmptyObjects( unsigned int _num, const DataType &_dataType, std::vector<int> &_objectIDs )
149 {
150  deleteObjects( _objectIDs );
151  _objectIDs.reserve( _num );
152 
153  OpenFlipper::Options::blockSceneGraphUpdates();
154 
155  unsigned int i;
156  for( i=0; i<_num; ++i )
157  {
158  int objectId = -1;
159  emit addEmptyObject( _dataType, objectId );
160 
161  if( objectId == -1 )
162  break;
163 
164  _objectIDs.push_back( objectId );
165  }
166 
167  OpenFlipper::Options::unblockSceneGraphUpdates();
168 
169  if( i == _num )
170  return true;
171 
172  deleteObjects( _objectIDs );
173  return false;
174 }
175 
176 
177 //----------------------------------------------------------------
178 
179 
180 void FileBundlePlugin::deleteObjects( std::vector<int> &_objectIDs )
181 {
182  unsigned int i, num = _objectIDs.size();
183  for( i=0; i<num; ++i )
184  emit deleteObject( _objectIDs[ i ] );
185 
186  _objectIDs.clear();
187 }
188 
189 
190 //----------------------------------------------------------------
191 
192 
193 bool FileBundlePlugin::readImagelistFile( const char *_filename, std::vector<std::string> &_imagePaths ) /*const*/
194 {
195  _imagePaths.clear();
196 
197  FILE *file = fopen( _filename, "rt" );
198  if( !file )
199  {
200  emit log( LOGINFO, tr("Could not open imagelist file \"%1\".\n").arg( _filename ) );
201  return false;
202  }
203 
204  char path[4096];
205  char temp[32];
206 
207  while( true )
208  {
209  fscanf( file, "%4095s", path );
210  fscanf( file, "%31s", temp );
211  fscanf( file, "%31s", temp );
212 
213  if( feof( file ) )
214  break;
215 
216  _imagePaths.push_back( std::string( path ) );
217  }
218 
219  fclose( file );
220 
221  emit log( LOGINFO, tr("Using imagelist file \"%1\".\n").arg( _filename ) );
222  return true;
223 }
224 
225 
226 //----------------------------------------------------------------
227 
228 
229 void FileBundlePlugin::readCameras( FILE *_file, const std::vector<int> &_cameraObjectIDs, SplatCloud_Cameras &_cameras ) /*const*/
230 {
231  char str[256];
232 
233  unsigned int cameraIdx = 0;
234  SplatCloud_Cameras::iterator cameraIter;
235  for( cameraIter = _cameras.begin(); cameraIter != _cameras.end(); ++cameraIter, ++cameraIdx )
236  {
237  SplatCloud_Camera &camera = *cameraIter;
238 
239  camera.objectId_ = _cameraObjectIDs[ cameraIdx ];
240 
241  SplatCloud_Projection &proj = camera.projection_;
242  fscanf( _file, "%32s", str ); proj.f_ = atof( str );
243  fscanf( _file, "%32s", str ); proj.k1_ = atof( str );
244  fscanf( _file, "%32s", str ); proj.k2_ = atof( str );
245  fscanf( _file, "%32s", str ); proj.r_[0][0] = atof( str );
246  fscanf( _file, "%32s", str ); proj.r_[0][1] = atof( str );
247  fscanf( _file, "%32s", str ); proj.r_[0][2] = atof( str );
248  fscanf( _file, "%32s", str ); proj.r_[1][0] = atof( str );
249  fscanf( _file, "%32s", str ); proj.r_[1][1] = atof( str );
250  fscanf( _file, "%32s", str ); proj.r_[1][2] = atof( str );
251  fscanf( _file, "%32s", str ); proj.r_[2][0] = atof( str );
252  fscanf( _file, "%32s", str ); proj.r_[2][1] = atof( str );
253  fscanf( _file, "%32s", str ); proj.r_[2][2] = atof( str );
254  fscanf( _file, "%32s", str ); proj.t_[0] = atof( str );
255  fscanf( _file, "%32s", str ); proj.t_[1] = atof( str );
256  fscanf( _file, "%32s", str ); proj.t_[2] = atof( str );
257 
258  camera.imagePath_ = "";
259 
260  camera.imageWidth_ = 0;
261  camera.imageHeight_ = 0;
262  }
263 }
264 
265 
266 //----------------------------------------------------------------
267 
268 
269 void FileBundlePlugin::readPoints( FILE *_file, const std::vector<int> &_cameraObjectIDs, SplatCloud &_splatCloud ) /*const*/
270 {
271  char str[256];
272 
273  int maxCamObjId = _cameraObjectIDs.size() - 1;
274 
275  unsigned int splatIdx;
276  for( splatIdx = 0; splatIdx < _splatCloud.numSplats(); ++splatIdx )
277  {
278  {
279  SplatCloud::Position &pos = _splatCloud.positions( splatIdx );
280  fscanf( _file, "%32s", str ); pos[0] = atof( str );
281  fscanf( _file, "%32s", str ); pos[1] = atof( str );
282  fscanf( _file, "%32s", str ); pos[2] = atof( str );
283  }
284 
285  {
286  SplatCloud::Color &col = _splatCloud.colors( splatIdx );
287  unsigned int r=0, g=0, b=0;
288  fscanf( _file, "%16u", &r ); col[0] = r;
289  fscanf( _file, "%16u", &g ); col[1] = g;
290  fscanf( _file, "%16u", &b ); col[2] = b;
291  }
292 
293  {
294  SplatCloud::Viewlist &viewlist = _splatCloud.viewlists( splatIdx );
295 
296  unsigned int numEntries = 0;
297  fscanf( _file, "%16u", &numEntries );
298 
299  viewlist.resize( numEntries );
300 
301  SplatCloud::Viewlist::iterator viewIter;
302  for( viewIter = viewlist.begin(); viewIter != viewlist.end(); ++viewIter )
303  {
304  int i = -1;
305  int j = -1;
306  fscanf( _file, "%16i", &i ); viewIter->cameraObjectId_ = ((i >= 0) && (i <= maxCamObjId)) ? _cameraObjectIDs[ i ] : -1;
307  fscanf( _file, "%16i", &j ); viewIter->featureIdx_ = j;
308  fscanf( _file, "%32s", str ); viewIter->x_ = atof( str );
309  fscanf( _file, "%32s", str ); viewIter->y_ = atof( str );
310  }
311  }
312  }
313 }
314 
315 
316 //----------------------------------------------------------------
317 
318 
319 bool FileBundlePlugin::readBundleFile( const char *_filename, SplatCloud &_splatCloud ) /*const*/
320 {
321  // clear splatcloud
322  _splatCloud.clear();
323 
324  // open file
325  FILE *file = fopen( _filename, "rt" );
326  if( !file )
327  {
328  emit log( LOGERR, tr("Could not open input file \"%1\".\n").arg( _filename ) );
329  return false; // return failure
330  }
331 
332  // read and check first line
333  std::string magicAndVersion = readLine( file );
334  if( magicAndVersion.compare( "# Bundle file v0.3" ) != 0 )
335  {
336  emit log( LOGERR, tr("Bad magic/version \"%1\" in input file \"%2\".\n").arg( magicAndVersion.c_str(), _filename ) );
337  fclose( file );
338  return false; // return failure
339  }
340 
341  // read counts
342  unsigned int numCameras = 0;
343  unsigned int numPoints = 0;
344  fscanf( file, "%16u", &numCameras );
345  fscanf( file, "%16u", &numPoints );
346 
347  // create camera object IDs
348  std::vector<int> cameraObjectIDs;
349  if( !addEmptyObjects( numCameras, DATA_CAMERA, cameraObjectIDs ) )
350  {
351  emit log( LOGERR, tr("Unable to add %1 cameras for input file \"%2\".\n").arg( QString::number( numCameras ), _filename ) );
352  fclose( file );
353  return false; // return failure
354  }
355 
356  // read cameras data block
357  if( numCameras != 0 )
358  {
359  SplatCloud_CameraManager &cameraManager = _splatCloud.requestCloudProperty( SPLATCLOUD_CAMERAMANAGER_HANDLE )->data();
360 
361  cameraManager.cameras_.resize( numCameras );
362  readCameras( file, cameraObjectIDs, cameraManager.cameras_ );
363 
364  // set image paths
365  {
366  std::vector<std::string> imagePaths;
367 
368  std::string path, name, ext;
369  splitFilename( _filename, path, name, ext );
370 
371  if( !readImagelistFile( (path + name + IMAGELIST_SUFFIX).c_str(), imagePaths ) )
372  readImagelistFile( (path + IMAGELIST_FALLBACK ).c_str(), imagePaths );
373 
374  bool hasImg = (cameraManager.cameras_.size() <= imagePaths.size());
375 
376  if( hasImg )
377  {
378  unsigned int cameraIdx = 0;
379  SplatCloud_Cameras::iterator cameraIter;
380  for( cameraIter = cameraManager.cameras_.begin(); cameraIter != cameraManager.cameras_.end(); ++cameraIter, ++cameraIdx )
381  cameraIter->imagePath_ = imagePaths[ cameraIdx ];
382  }
383 
384  _splatCloud.requestCloudProperty( SPLATCLOUD_GENERALMANAGER_HANDLE )->data().flags_.set( SPLATCLOUD_CAMERA_HAS_IMAGEPATH_FLAG, hasImg );
385  }
386  }
387 
388  // read points data block
389  if( numPoints != 0 )
390  {
391  _splatCloud.resizeSplats( numPoints );
392  _splatCloud.requestPositions();
393  _splatCloud.requestColors();
394  _splatCloud.requestViewlists();
395  readPoints( file, cameraObjectIDs, _splatCloud );
396 
397  _splatCloud.requestCloudProperty( SPLATCLOUD_GENERALMANAGER_HANDLE )->data().flags_.set( SPLATCLOUD_SPLAT_VIEWLIST_HAS_FEATURE_INDICES_FLAG, true );
398  _splatCloud.requestCloudProperty( SPLATCLOUD_GENERALMANAGER_HANDLE )->data().flags_.set( SPLATCLOUD_SPLAT_VIEWLIST_COORDS_NORMALIZED_FLAG, false );
399  }
400 
401  // check if reading error occured
402  if( feof( file ) )
403  {
404  emit log( LOGERR, tr("Unexpected end in input file \"%1\".\n" ).arg( _filename ) );
405  fclose( file );
406  return false; // return failure
407  }
408 
409  // close file
410  fclose( file );
411 
412  // return success
413  return true;
414 }
415 
416 
417 //----------------------------------------------------------------
418 
419 
420 bool FileBundlePlugin::writeBundleFile( const char *_filename, const SplatCloud &_splatCloud ) /*const*/
421 {
422  return false;
423 }
424 
425 
426 //----------------------------------------------------------------
427 
428 
429 int FileBundlePlugin::loadObject( QString _filename )
430 {
431  // add a new, empty splatcloud-object
432  int splatCloudObjectId = -1;
433  emit addEmptyObject( DATA_SPLATCLOUD, splatCloudObjectId );
434  if( splatCloudObjectId != -1 )
435  {
436  // get splatcloud-object by id
438  if( PluginFunctions::getObject( splatCloudObjectId, splatCloudObject ) )
439  {
440  // set name of splatcloud-object to filename
441  splatCloudObject->setFromFileName( _filename );
442  splatCloudObject->setName( splatCloudObject->filename() );
443 
444  // get splatcloud and scenegraph splatcloud-node
445  SplatCloud *splatCloud = splatCloudObject->splatCloud();
446  SplatCloudNode *splatCloudNode = splatCloudObject->splatCloudNode();
447  if( (splatCloud != 0) && (splatCloudNode != 0) )
448  {
449  // read splatcloud from disk
450  if( readBundleFile( _filename.toLatin1(), *splatCloud ) )
451  {
452  // emit signals that the splatcloud-object has to be updated and that a file was opened
453  emit updatedObject( splatCloudObjectId, UPDATE_ALL );
454  emit openedFile( splatCloudObjectId );
455 
456  // get drawmodes
460 
461  // if drawmodes don't exist something went wrong
462  if( splatsDrawMode == ACG::SceneGraph::DrawModes::NONE ||
463  dotsDrawMode == ACG::SceneGraph::DrawModes::NONE ||
464  pointsDrawMode == ACG::SceneGraph::DrawModes::NONE )
465  {
466  emit log( LOGERR, tr("Shader DrawModes for SplatCloud not existent!") );
467  }
468  else
469  {
470  // get global drawmode
472 
473  // if global drawmode does *not* contain any of 'Splats', 'Dots' or 'Points' drawmode, add 'Points'
474  if( !drawmode.containsAtomicDrawMode( splatsDrawMode ) &&
475  !drawmode.containsAtomicDrawMode( dotsDrawMode ) &&
476  !drawmode.containsAtomicDrawMode( pointsDrawMode ) )
477  {
478  drawmode |= pointsDrawMode;
479  PluginFunctions::setDrawMode( drawmode );
480  }
481  }
482 
483  // return success
484  return splatCloudObjectId;
485  }
486  }
487  }
488  }
489 
490  // return failure
491  return -1;
492 }
493 
494 
495 //----------------------------------------------------------------
496 
497 
498 bool FileBundlePlugin::saveObject( int _objectId, QString _filename )
499 {
500  // get splatcloud-object by id
501  SplatCloudObject *splatCloudObject = 0;
502  if( PluginFunctions::getObject( _objectId, splatCloudObject ) )
503  {
504  // change name of splatcloud-object to filename
505  splatCloudObject->setFromFileName( _filename );
506  splatCloudObject->setName( splatCloudObject->filename() );
507 
508  // get splatcloud
509  SplatCloud *splatCloud = splatCloudObject->splatCloud();
510  if( splatCloud != 0 )
511  {
512  // write splatcloud to disk
513  if( writeBundleFile( _filename.toLatin1(), *splatCloud ) )
514  {
515  // return success
516  return true;
517  }
518  }
519  }
520 
521  // return failure
522  return false;
523 }
524 
525 
526 //----------------------------------------------------------------
527 
528 
529 QWidget *FileBundlePlugin::saveOptionsWidget( QString /*_currentFilter*/ )
530 {
531  return 0;
532 }
533 
534 
535 //----------------------------------------------------------------
536 
537 
538 QWidget *FileBundlePlugin::loadOptionsWidget( QString /*_currentFilter*/ )
539 {
540  return 0;
541 }
542 
543 
544 //================================================================
545 
Position & positions(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:631
#define DATA_CAMERA
Definition: Camera.hh:67
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
unsigned int numSplats() const
Get the number of splats.
Definition: SplatCloud.hh:179
Color & colors(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:633
bool containsAtomicDrawMode(const DrawMode &_atomicDrawMode) const
Check whether an Atomic DrawMode is active in this draw Mode.
Definition: DrawModes.cc:512
QWidget * saveOptionsWidget(QString)
Definition: FileBundle.cc:529
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
bool requestPositions()
Request the predefined property.
Definition: SplatCloud.hh:561
CloudPropertyT< T > * requestCloudProperty(const PropertyHandleT< T > &_handle)
Request a new property.
ACG::SceneGraph::DrawModes::DrawMode drawMode(int _viewer)
Get the current draw Mode of a Viewer.
#define DATA_SPLATCLOUD
Definition: SplatCloud.hh:59
Predefined datatypes.
Definition: DataTypes.hh:83
QString name()
Return a name for the plugin.
Definition: FileBundle.hh:124
SplatCloud * splatCloud()
Get SplatCloud.
void setName(QString _name)
Set the name of the Object.
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
bool requestColors()
Request the predefined property.
Definition: SplatCloud.hh:562
SplatCloudObject * splatCloudObject(BaseObjectData *_object)
Cast an SplatCloudObject to a SplatCloudObject if possible.
const DrawMode & getDrawMode(const std::string &_name)
Get a custom DrawMode.
Definition: DrawModes.cc:799
QWidget * loadOptionsWidget(QString)
Definition: FileBundle.cc:538
SplatCloud * splatCloud(BaseObjectData *_object)
Get a SplatCloud from an object.
DrawMode NONE
not a valid draw mode
Definition: DrawModes.cc:71
bool requestViewlists()
Request the predefined property.
Definition: SplatCloud.hh:566
void clear()
Remove all properties and reset the number of splats.
Definition: SplatCloud.cc:184
SplatCloudNode * splatCloudNode(BaseObjectData *_object)
Get a SplatCloudNode from an object.
Viewlist & viewlists(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:641
void setDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, int _viewer)
Set the draw Mode of a Viewer. .
SplatCloudNode * splatCloudNode()
Get SplatCloud&#39;s scenegraph Node.
void resizeSplats(unsigned int _num)
Resize the data vector of all splat-properties.
Definition: SplatCloud.cc:246
void setFromFileName(const QString &_filename)
Definition: BaseObject.cc:716