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 //== INCLUDES ====================================================
52 
53 
54 #include "FileBundle.hh"
55 
56 
57  #include <QtWidgets>
58 
59 #include <fstream>
60 
63 
64 #include <OpenMesh/Core/IO/IOManager.hh>
65 
67 
68 
69 //== CONSTANTS ===================================================
70 
71 
72 static const char IMAGELIST_SUFFIX[] = ".txt";
73 static const char IMAGELIST_FALLBACK[] = "image_list.txt";
74 
75 
76 //== IMPLEMENTATION ==============================================
77 
78 
79 static std::string readLine( FILE *_file )
80 {
81  // create empty string
82  std::string result = "";
83 
84  while( true )
85  {
86  // read next char
87  char c;
88  fscanf( _file, "%c", &c );
89 
90  // if end of file or line is reached, break
91  if( feof( _file ) || c == '\0' || c == '\n' || c == '\r' )
92  break;
93 
94  // copy char to string
95  result += c;
96  }
97 
98  // return string
99  return result;
100 }
101 
102 
103 //----------------------------------------------------------------
104 
105 
106 static void splitFilename( const std::string &_str, std::string &_path, std::string &_name, std::string &_ext )
107 {
108  size_t i = _str.find_last_of( "/\\" );
109 
110  std::string rest;
111 
112  if( i == std::string::npos )
113  {
114  _path = "";
115  rest = _str;
116  }
117  else
118  {
119  _path = _str.substr( 0, i+1 ); // 0 .. i
120  rest = _str.substr( i+1 ); // i+1 .. end
121  }
122 
123  size_t j = rest.find_last_of( '.' );
124 
125  if( j == std::string::npos )
126  {
127  _name = rest;
128  _ext = "";
129  }
130  else
131  {
132  _name = rest.substr( 0, j ); // 0 .. j-1
133  _ext = rest.substr( j ); // j .. end
134  }
135 }
136 
137 
138 //----------------------------------------------------------------
139 
140 
141 bool FileBundlePlugin::addEmptyObjects( unsigned int _num, const DataType &_dataType, std::vector<int> &_objectIDs )
142 {
143  deleteObjects( _objectIDs );
144  _objectIDs.reserve( _num );
145 
146  OpenFlipper::Options::blockSceneGraphUpdates();
147 
148  unsigned int i;
149  for( i=0; i<_num; ++i )
150  {
151  int objectId = -1;
152  emit addEmptyObject( _dataType, objectId );
153 
154  if( objectId == -1 )
155  break;
156 
157  _objectIDs.push_back( objectId );
158  }
159 
160  OpenFlipper::Options::unblockSceneGraphUpdates();
161 
162  if( i == _num )
163  return true;
164 
165  deleteObjects( _objectIDs );
166  return false;
167 }
168 
169 
170 //----------------------------------------------------------------
171 
172 
173 void FileBundlePlugin::deleteObjects( std::vector<int> &_objectIDs )
174 {
175  unsigned int i, num = _objectIDs.size();
176  for( i=0; i<num; ++i )
177  emit deleteObject( _objectIDs[ i ] );
178 
179  _objectIDs.clear();
180 }
181 
182 
183 //----------------------------------------------------------------
184 
185 
186 bool FileBundlePlugin::readImagelistFile( const char *_filename, std::vector<std::string> &_imagePaths ) /*const*/
187 {
188  _imagePaths.clear();
189 
190  FILE *file = fopen( _filename, "rt" );
191  if( !file )
192  {
193  emit log( LOGINFO, tr("Could not open imagelist file \"%1\".\n").arg( _filename ) );
194  return false;
195  }
196 
197  char path[4096];
198  char temp[32];
199 
200  while( true )
201  {
202  fscanf( file, "%4095s", path );
203  fscanf( file, "%31s", temp );
204  fscanf( file, "%31s", temp );
205 
206  if( feof( file ) )
207  break;
208 
209  _imagePaths.push_back( std::string( path ) );
210  }
211 
212  fclose( file );
213 
214  emit log( LOGINFO, tr("Using imagelist file \"%1\".\n").arg( _filename ) );
215  return true;
216 }
217 
218 
219 //----------------------------------------------------------------
220 
221 
222 void FileBundlePlugin::readCameras( FILE *_file, const std::vector<int> &_cameraObjectIDs, SplatCloud_Cameras &_cameras ) /*const*/
223 {
224  char str[256];
225 
226  unsigned int cameraIdx = 0;
227  SplatCloud_Cameras::iterator cameraIter;
228  for( cameraIter = _cameras.begin(); cameraIter != _cameras.end(); ++cameraIter, ++cameraIdx )
229  {
230  SplatCloud_Camera &camera = *cameraIter;
231 
232  camera.objectId_ = _cameraObjectIDs[ cameraIdx ];
233 
234  SplatCloud_Projection &proj = camera.projection_;
235  fscanf( _file, "%32s", str ); proj.f_ = atof( str );
236  fscanf( _file, "%32s", str ); proj.k1_ = atof( str );
237  fscanf( _file, "%32s", str ); proj.k2_ = atof( str );
238  fscanf( _file, "%32s", str ); proj.r_[0][0] = atof( str );
239  fscanf( _file, "%32s", str ); proj.r_[0][1] = atof( str );
240  fscanf( _file, "%32s", str ); proj.r_[0][2] = atof( str );
241  fscanf( _file, "%32s", str ); proj.r_[1][0] = atof( str );
242  fscanf( _file, "%32s", str ); proj.r_[1][1] = atof( str );
243  fscanf( _file, "%32s", str ); proj.r_[1][2] = atof( str );
244  fscanf( _file, "%32s", str ); proj.r_[2][0] = atof( str );
245  fscanf( _file, "%32s", str ); proj.r_[2][1] = atof( str );
246  fscanf( _file, "%32s", str ); proj.r_[2][2] = atof( str );
247  fscanf( _file, "%32s", str ); proj.t_[0] = atof( str );
248  fscanf( _file, "%32s", str ); proj.t_[1] = atof( str );
249  fscanf( _file, "%32s", str ); proj.t_[2] = atof( str );
250 
251  camera.imagePath_ = "";
252 
253  camera.imageWidth_ = 0;
254  camera.imageHeight_ = 0;
255  }
256 }
257 
258 
259 //----------------------------------------------------------------
260 
261 
262 void FileBundlePlugin::readPoints( FILE *_file, const std::vector<int> &_cameraObjectIDs, SplatCloud &_splatCloud ) /*const*/
263 {
264  char str[256];
265 
266  int maxCamObjId = _cameraObjectIDs.size() - 1;
267 
268  unsigned int splatIdx;
269  for( splatIdx = 0; splatIdx < _splatCloud.numSplats(); ++splatIdx )
270  {
271  {
272  SplatCloud::Position &pos = _splatCloud.positions( splatIdx );
273  fscanf( _file, "%32s", str ); pos[0] = atof( str );
274  fscanf( _file, "%32s", str ); pos[1] = atof( str );
275  fscanf( _file, "%32s", str ); pos[2] = atof( str );
276  }
277 
278  {
279  SplatCloud::Color &col = _splatCloud.colors( splatIdx );
280  unsigned int r=0, g=0, b=0;
281  fscanf( _file, "%16u", &r ); col[0] = r;
282  fscanf( _file, "%16u", &g ); col[1] = g;
283  fscanf( _file, "%16u", &b ); col[2] = b;
284  }
285 
286  {
287  SplatCloud::Viewlist &viewlist = _splatCloud.viewlists( splatIdx );
288 
289  unsigned int numEntries = 0;
290  fscanf( _file, "%16u", &numEntries );
291 
292  viewlist.resize( numEntries );
293 
294  SplatCloud::Viewlist::iterator viewIter;
295  for( viewIter = viewlist.begin(); viewIter != viewlist.end(); ++viewIter )
296  {
297  int i = -1;
298  int j = -1;
299  fscanf( _file, "%16i", &i ); viewIter->cameraObjectId_ = ((i >= 0) && (i <= maxCamObjId)) ? _cameraObjectIDs[ i ] : -1;
300  fscanf( _file, "%16i", &j ); viewIter->featureIdx_ = j;
301  fscanf( _file, "%32s", str ); viewIter->x_ = atof( str );
302  fscanf( _file, "%32s", str ); viewIter->y_ = atof( str );
303  }
304  }
305  }
306 }
307 
308 
309 //----------------------------------------------------------------
310 
311 
312 bool FileBundlePlugin::readBundleFile( const char *_filename, SplatCloud &_splatCloud ) /*const*/
313 {
314  // clear splatcloud
315  _splatCloud.clear();
316 
317  // open file
318  FILE *file = fopen( _filename, "rt" );
319  if( !file )
320  {
321  emit log( LOGERR, tr("Could not open input file \"%1\".\n").arg( _filename ) );
322  return false; // return failure
323  }
324 
325  // read and check first line
326  std::string magicAndVersion = readLine( file );
327  if( magicAndVersion.compare( "# Bundle file v0.3" ) != 0 )
328  {
329  emit log( LOGERR, tr("Bad magic/version \"%1\" in input file \"%2\".\n").arg( magicAndVersion.c_str(), _filename ) );
330  fclose( file );
331  return false; // return failure
332  }
333 
334  // read counts
335  unsigned int numCameras = 0;
336  unsigned int numPoints = 0;
337  fscanf( file, "%16u", &numCameras );
338  fscanf( file, "%16u", &numPoints );
339 
340  // create camera object IDs
341  std::vector<int> cameraObjectIDs;
342  if( !addEmptyObjects( numCameras, DATA_CAMERA, cameraObjectIDs ) )
343  {
344  emit log( LOGERR, tr("Unable to add %1 cameras for input file \"%2\".\n").arg( QString::number( numCameras ), _filename ) );
345  fclose( file );
346  return false; // return failure
347  }
348 
349  // read cameras data block
350  if( numCameras != 0 )
351  {
352  SplatCloud_CameraManager &cameraManager = _splatCloud.requestCloudProperty( SPLATCLOUD_CAMERAMANAGER_HANDLE )->data();
353 
354  cameraManager.cameras_.resize( numCameras );
355  readCameras( file, cameraObjectIDs, cameraManager.cameras_ );
356 
357  // set image paths
358  {
359  std::vector<std::string> imagePaths;
360 
361  std::string path, name, ext;
362  splitFilename( _filename, path, name, ext );
363 
364  if( !readImagelistFile( (path + name + IMAGELIST_SUFFIX).c_str(), imagePaths ) )
365  readImagelistFile( (path + IMAGELIST_FALLBACK ).c_str(), imagePaths );
366 
367  bool hasImg = (cameraManager.cameras_.size() <= imagePaths.size());
368 
369  if( hasImg )
370  {
371  unsigned int cameraIdx = 0;
372  SplatCloud_Cameras::iterator cameraIter;
373  for( cameraIter = cameraManager.cameras_.begin(); cameraIter != cameraManager.cameras_.end(); ++cameraIter, ++cameraIdx )
374  cameraIter->imagePath_ = imagePaths[ cameraIdx ];
375  }
376 
377  _splatCloud.requestCloudProperty( SPLATCLOUD_GENERALMANAGER_HANDLE )->data().flags_.set( SPLATCLOUD_CAMERA_HAS_IMAGEPATH_FLAG, hasImg );
378  }
379  }
380 
381  // read points data block
382  if( numPoints != 0 )
383  {
384  _splatCloud.resizeSplats( numPoints );
385  _splatCloud.requestPositions();
386  _splatCloud.requestColors();
387  _splatCloud.requestViewlists();
388  readPoints( file, cameraObjectIDs, _splatCloud );
389 
390  _splatCloud.requestCloudProperty( SPLATCLOUD_GENERALMANAGER_HANDLE )->data().flags_.set( SPLATCLOUD_SPLAT_VIEWLIST_HAS_FEATURE_INDICES_FLAG, true );
391  _splatCloud.requestCloudProperty( SPLATCLOUD_GENERALMANAGER_HANDLE )->data().flags_.set( SPLATCLOUD_SPLAT_VIEWLIST_COORDS_NORMALIZED_FLAG, false );
392  }
393 
394  // check if reading error occured
395  if( feof( file ) )
396  {
397  emit log( LOGERR, tr("Unexpected end in input file \"%1\".\n" ).arg( _filename ) );
398  fclose( file );
399  return false; // return failure
400  }
401 
402  // close file
403  fclose( file );
404 
405  // return success
406  return true;
407 }
408 
409 
410 //----------------------------------------------------------------
411 
412 
413 bool FileBundlePlugin::writeBundleFile( const char *_filename, const SplatCloud &_splatCloud ) /*const*/
414 {
415  return false;
416 }
417 
418 
419 //----------------------------------------------------------------
420 
421 
422 int FileBundlePlugin::loadObject( QString _filename )
423 {
424  // add a new, empty splatcloud-object
425  int splatCloudObjectId = -1;
426  emit addEmptyObject( DATA_SPLATCLOUD, splatCloudObjectId );
427  if( splatCloudObjectId != -1 )
428  {
429  // get splatcloud-object by id
431  if( PluginFunctions::getObject( splatCloudObjectId, splatCloudObject ) )
432  {
433  // set name of splatcloud-object to filename
434  splatCloudObject->setFromFileName( _filename );
435  splatCloudObject->setName( splatCloudObject->filename() );
436 
437  // get splatcloud and scenegraph splatcloud-node
438  SplatCloud *splatCloud = splatCloudObject->splatCloud();
439  SplatCloudNode *splatCloudNode = splatCloudObject->splatCloudNode();
440  if( (splatCloud != 0) && (splatCloudNode != 0) )
441  {
442  // read splatcloud from disk
443  if( readBundleFile( _filename.toLatin1(), *splatCloud ) )
444  {
445  // emit signals that the splatcloud-object has to be updated and that a file was opened
446  emit updatedObject( splatCloudObjectId, UPDATE_ALL );
447  emit openedFile( splatCloudObjectId );
448 
449  // get drawmodes
453 
454  // if drawmodes don't exist something went wrong
455  if( splatsDrawMode == ACG::SceneGraph::DrawModes::NONE ||
456  dotsDrawMode == ACG::SceneGraph::DrawModes::NONE ||
457  pointsDrawMode == ACG::SceneGraph::DrawModes::NONE )
458  {
459  emit log( LOGERR, tr("Shader DrawModes for SplatCloud not existent!") );
460  }
461  else
462  {
463  // get global drawmode
465 
466  // if global drawmode does *not* contain any of 'Splats', 'Dots' or 'Points' drawmode, add 'Points'
467  if( !drawmode.containsAtomicDrawMode( splatsDrawMode ) &&
468  !drawmode.containsAtomicDrawMode( dotsDrawMode ) &&
469  !drawmode.containsAtomicDrawMode( pointsDrawMode ) )
470  {
471  drawmode |= pointsDrawMode;
472  PluginFunctions::setDrawMode( drawmode );
473  }
474  }
475 
476  // return success
477  return splatCloudObjectId;
478  }
479  }
480  }
481  }
482 
483  // return failure
484  return -1;
485 }
486 
487 
488 //----------------------------------------------------------------
489 
490 
491 bool FileBundlePlugin::saveObject( int _objectId, QString _filename )
492 {
493  // get splatcloud-object by id
494  SplatCloudObject *splatCloudObject = 0;
495  if( PluginFunctions::getObject( _objectId, splatCloudObject ) )
496  {
497  // change name of splatcloud-object to filename
498  splatCloudObject->setFromFileName( _filename );
499  splatCloudObject->setName( splatCloudObject->filename() );
500 
501  // get splatcloud
502  SplatCloud *splatCloud = splatCloudObject->splatCloud();
503  if( splatCloud != 0 )
504  {
505  // write splatcloud to disk
506  if( writeBundleFile( _filename.toLatin1(), *splatCloud ) )
507  {
508  // return success
509  return true;
510  }
511  }
512  }
513 
514  // return failure
515  return false;
516 }
517 
518 
519 //----------------------------------------------------------------
520 
521 
522 QWidget *FileBundlePlugin::saveOptionsWidget( QString /*_currentFilter*/ )
523 {
524  return 0;
525 }
526 
527 
528 //----------------------------------------------------------------
529 
530 
531 QWidget *FileBundlePlugin::loadOptionsWidget( QString /*_currentFilter*/ )
532 {
533  return 0;
534 }
535 
536 
537 //================================================================
538 
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool requestViewlists()
Request the predefined property.
Definition: SplatCloud.hh:566
QWidget * loadOptionsWidget(QString)
Definition: FileBundle.cc:531
CloudPropertyT< T > * requestCloudProperty(const PropertyHandleT< T > &_handle)
Request a new property.
void setName(QString _name)
Set the name of the Object.
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
QWidget * saveOptionsWidget(QString)
Definition: FileBundle.cc:522
bool requestPositions()
Request the predefined property.
Definition: SplatCloud.hh:561
void setDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, int _viewer)
Set the draw Mode of a Viewer. .
#define DATA_CAMERA
Definition: Camera.hh:67
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.
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
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.
QString name()
Return a name for the plugin.
Definition: FileBundle.hh:118
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.
bool requestColors()
Request the predefined property.
Definition: SplatCloud.hh:562
Predefined datatypes.
Definition: DataTypes.hh:83
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.
Viewlist & viewlists(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:641
#define DATA_SPLATCLOUD
Definition: SplatCloud.hh:59