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