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
79static const char IMAGELIST_SUFFIX[] = ".txt";
80static const char IMAGELIST_FALLBACK[] = "image_list.txt";
81
82
83//== IMPLEMENTATION ==============================================
84
85
86static 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
113static 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
148bool 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
180void 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
193bool 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
229void 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
269void 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
319bool 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
420bool FileBundlePlugin::writeBundleFile( const char *_filename, const SplatCloud &_splatCloud ) /*const*/
421{
422 return false;
423}
424
425
426//----------------------------------------------------------------
427
428
429int 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 );
443
444 // get splatcloud and scenegraph splatcloud-node
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;
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
498bool FileBundlePlugin::saveObject( int _objectId, QString _filename )
499{
500 // get splatcloud-object by id
502 if( PluginFunctions::getObject( _objectId, splatCloudObject ) )
503 {
504 // change name of splatcloud-object to filename
505 splatCloudObject->setFromFileName( _filename );
507
508 // get 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
529QWidget *FileBundlePlugin::saveOptionsWidget( QString /*_currentFilter*/ )
530{
531 return 0;
532}
533
534
535//----------------------------------------------------------------
536
537
538QWidget *FileBundlePlugin::loadOptionsWidget( QString /*_currentFilter*/ )
539{
540 return 0;
541}
542
543
544//================================================================
545
#define DATA_CAMERA
Definition: Camera.hh:67
@ LOGERR
@ LOGINFO
#define DATA_SPLATCLOUD
Definition: SplatCloud.hh:59
bool containsAtomicDrawMode(const DrawMode &_atomicDrawMode) const
Check whether an Atomic DrawMode is active in this draw Mode.
Definition: DrawModes.cc:510
QString filename() const
return the filename of the object
Definition: BaseObject.cc:704
void setFromFileName(const QString &_filename)
Definition: BaseObject.cc:714
Predefined datatypes.
Definition: DataTypes.hh:83
QWidget * saveOptionsWidget(QString)
Definition: FileBundle.cc:529
QString name()
Return a name for the plugin.
Definition: FileBundle.hh:124
QWidget * loadOptionsWidget(QString)
Definition: FileBundle.cc:538
SplatCloudNode * splatCloudNode()
Get SplatCloud's scenegraph Node.
SplatCloud * splatCloud()
Get SplatCloud.
void setName(QString _name)
Set the name of the Object.
void resizeSplats(unsigned int _num)
Resize the data vector of all splat-properties.
Definition: SplatCloud.cc:246
Viewlist & viewlists(int _idx)
Get a reference of the predefined property's value.
Definition: SplatCloud.hh:641
CloudPropertyT< T > * requestCloudProperty(const PropertyHandleT< T > &_handle)
Request a new property.
unsigned int numSplats() const
Get the number of splats.
Definition: SplatCloud.hh:179
bool requestViewlists()
Request the predefined property.
Definition: SplatCloud.hh:566
Position & positions(int _idx)
Get a reference of the predefined property's value.
Definition: SplatCloud.hh:631
bool requestColors()
Request the predefined property.
Definition: SplatCloud.hh:562
Color & colors(int _idx)
Get a reference of the predefined property's value.
Definition: SplatCloud.hh:633
bool requestPositions()
Request the predefined property.
Definition: SplatCloud.hh:561
void clear()
Remove all properties and reset the number of splats.
Definition: SplatCloud.cc:184
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
const DrawMode & getDrawMode(const std::string &_name)
Get a custom DrawMode.
Definition: DrawModes.cc:797
DrawMode NONE
not a valid draw mode
Definition: DrawModes.cc:71
SplatCloudObject * splatCloudObject(BaseObjectData *_object)
Cast an SplatCloudObject to a SplatCloudObject if possible.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
ACG::SceneGraph::DrawModes::DrawMode drawMode(int _viewer)
Get the current draw Mode of a Viewer.
SplatCloud * splatCloud(BaseObjectData *_object)
Get a SplatCloud from an object.
void setDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, int _viewer)
Set the draw Mode of a Viewer. .
SplatCloudNode * splatCloudNode(BaseObjectData *_object)
Get a SplatCloudNode from an object.