Commit dfd4f55f authored by Mathias Goldau's avatar Mathias Goldau
Browse files

[CHANGE] Refactored WLoaderFibers

parent 3f26bd45
......@@ -26,88 +26,124 @@
#include <fstream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include "WLoaderFibers.h"
#include "../WDataHandler.h"
#include "../../common/WStringUtils.hpp"
#include "../../math/WPosition.h"
WLoaderFibers::WLoaderFibers( std::string fname, boost::shared_ptr< WDataHandler > dataHandler )
WLoaderFibers::WLoaderFibers( std::string fname, boost::shared_ptr< WDataHandler > dataHandler ) throw( WDHIOFailure )
: WLoader( fname, dataHandler )
{
m_ifs = new std::ifstream( fname.c_str(), std::ifstream::in | std::ifstream::binary );
if( !( *m_ifs ) || m_ifs->bad() )
{
throw WDHIOFailure( "Load broken file '" + m_fileName + "'" );
}
}
WLoaderFibers::~WLoaderFibers() throw()
{
if( m_ifs )
{
m_ifs->close();
}
delete( m_ifs );
}
void WLoaderFibers::operator()() throw()
{
std::ifstream in( m_fileName.c_str(), std::ifstream::in | std::ifstream::binary );
try
{
if( !in || in.bad() )
{
throw WDHIOFailure( "Load broken file '" + m_fileName + "'" );
}
readHeader( &in );
if( !datasetTypeIs( "POLYDATA" ) )
{
throw WDHException( "Invalid VTK DATASET type: DATASET != POLYDATA not implemented" );
}
if( !isBinary() )
{
throw WDHException( "VTK files in ASCII format is not yet supported" );
}
readPoints( &in );
readHeader();
readPoints();
}
catch( WDHException e )
{
in.close();
m_ifs->close();
// TODO(math): we should print the file name also, since knowing that
// the file was malformated, doesn't give you the hint that there
// could be thousands of them
std::cerr << "Error :: DataHandler :: Abort loading VTK file due to: " << e.what() << std::endl;
}
in.close();
}
void WLoaderFibers::readHeader( std::ifstream* ifs ) throw( WDHIOFailure )
void WLoaderFibers::readHeader() throw( WDHIOFailure, WDHException )
{
std::string line;
try
{
for( int i = 0; i < 4; ++i ) // strip first four lines
{
std::getline( *ifs, line );
std::getline( *m_ifs, line );
if( !m_ifs->good() )
{
throw WDHException( "Unexpected end of file: " + m_fileName );
}
m_header.push_back( line );
}
}
catch( std::ios_base::failure e )
catch( const std::ios_base::failure &e )
{
throw WDHIOFailure( "Reading first 4 lines of '" + m_fileName + "': " + e.what() );
}
std::cout << m_fileName << std::endl;
std::cout << m_header << std::endl;
assert( m_header.size() == 4 );
}
bool WLoaderFibers::datasetTypeIs( const std::string& type ) const
{
assert( m_header.size() == 4 );
std::string lastLine = m_header.back();
std::vector< std::string > tokens = string_utils::tokenize( lastLine );
assert( tokens.size() >= 2 );
return tokens[1] == type;
}
bool WLoaderFibers::isBinary() const
{
assert( m_header.size() == 4 );
std::string thirdLine = string_utils::toUpper( string_utils::trim( m_header[2] ) );
if( thirdLine != "BINARY" )
// check if the header may be valid for the .fib format
if( m_header.at(0) != "# vtk DataFile Version 3.0" )
{
throw WDHIOFailure( "Unsupported format version string: " + m_header.at( 0 ) );
}
if( m_header.at(1).size() > 256 )
{
// TODO(math): This should be just a warning
throw WDHException( "VTK header too big: " + boost::lexical_cast< std::string >( m_header.at( 1 ).size() ) );
}
namespace su = string_utils;
if( su::toUpper( su::trim( m_header.at( 2 ) ) ) != "BINARY" )
{
throw WDHException( "VTK files in '" + m_header.at( 2 ) + "' format are not yet supported" );
}
if( su::tokenize( m_header.at( 3 ) ).size() < 2 ||
su::toUpper( su::tokenize( m_header.at( 3 ) )[1] ) != "POLYDATA" )
{
assert( thirdLine == "ASCII" );
throw WDHException( "Invalid VTK DATASET type: " + su::tokenize( m_header.back() )[1] );
}
return "BINARY" == thirdLine;
}
void WLoaderFibers::readPoints( std::ifstream* ifs )
void WLoaderFibers::readPoints()
{
std::string line;
try
{
std::getline( *m_ifs, line );
}
catch( const std::ios_base::failure &e )
{
throw WDHIOFailure( "Error reading POINTS declaration '" + m_fileName + "': " + e.what() );
}
// TODO(math): fix this since stylecheckers complains about long, and we want
// int64 not W_DT_INT64 so see dataHandler/WDataHandlerEnums.h:
// line 49: W_DT_INT64 = 1024, /* long long (64 bits) */
// namespace su = string_utils;
// long numPoints = 0;
// std::vector< std::string > tokens = su::tokenize( line );
// if( tokens.size() < 3 || su::toLower( tokens.at( 2 ) ) != "float" )
// {
// throw WDHException( "Invalid VTK POINTS declaration: " + line );
// }
// try
// {
// numPoints = boost::lexical_cast< long >( tokens.at( 1 ) );
// }
// catch( const boost::bad_lexical_cast &e )
// {
// throw WDHException( "Invalid number of points: " + tokens.at( 1 ) );
// }
//
// std::vector< wmath::WPosition > points( numPoints );
}
......@@ -28,6 +28,7 @@
#include <fstream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "../WLoader.h"
......@@ -51,7 +52,7 @@ public:
* Constructs and makes a new VTK loader for separate thread start.
*/
WLoaderFibers( std::string fname, boost::shared_ptr< WDataHandler >
dataHandler );
dataHandler ) throw( WDHIOFailure );
/**
* Destroys this instance and closes the file.
......@@ -70,30 +71,23 @@ protected:
*
* \return The offset where header ends, so we may skip this next operation.
*/
void readHeader( std::ifstream* ifs ) throw( WDHIOFailure );
/**
* Checks if the header defines the specified VTK DATASET type.
*
* \param type VTK DATASET type as string, to check for.
*/
bool datasetTypeIs( const std::string& type ) const;
/**
* Returns true if the VTK file is marked as BINARY format, otherwise false.
*/
bool isBinary() const;
void readHeader() throw( WDHIOFailure, WDHException );
/**
* Read points from file while starting at the given position.
*/
void readPoints( std::ifstream* ifs );
void readPoints();
/**
* First four lines of ASCII text describing this file
*/
std::vector< std::string > m_header;
/**
* Pointer to the input file stream reader.
*/
std::ifstream *m_ifs;
private:
};
......
......@@ -72,24 +72,6 @@ public:
void setUp( void )
{
m_dataHandler = boost::shared_ptr< WDataHandler >( new WDataHandler() );
m_vtkFile = boost::filesystem::path( "fixtures/VTK/ascii-2nd-order-tensor.vtk" );
m_ifs_ptr = NULL;
m_ifs_ptr = new std::ifstream( m_vtkFile.string().c_str(), std::ifstream::in | std::ifstream::binary );
assert( m_ifs_ptr );
m_fibLoader = new WLoaderFibers( m_vtkFile.string(), m_dataHandler );
assert( boost::filesystem::exists( m_vtkFile ) );
}
/**
* Tidy up things as e.g. open file streams.
*/
void tearDown( void )
{
assert( m_ifs_ptr );
m_ifs_ptr->close();
delete( m_ifs_ptr );
m_ifs_ptr = NULL;
delete( m_fibLoader );
}
/**
......@@ -109,64 +91,104 @@ public:
*/
void testReadHeader( void )
{
m_fibLoader->readHeader( m_ifs_ptr );
WLoaderFibers loader( "fixtures/Fibers/valid_small_example.fib", m_dataHandler );
std::vector< std::string > expected;
expected.push_back( "# vtk DataFile Version 3.0" );
expected.push_back( "vtk output" );
expected.push_back( "ASCII" );
expected.push_back( "DATASET STRUCTURED_POINTS" );
TS_ASSERT_EQUALS( m_fibLoader->m_header, expected );
expected.push_back( "Neural Pathways aka as fibers." );
expected.push_back( "BINARY" );
expected.push_back( "DATASET POLYDATA" );
loader.readHeader();
TS_ASSERT_EQUALS( loader.m_header, expected );
}
/**
* After reading the header the position in the stream should have
* changed
* A valid .fib header starts with "# vtk DataFile Version 3.0".
*/
void testReadHeaderReturnsCorrectStreamPosistion( void )
void testUnsupportedVTKFileFormatString( void )
{
m_fibLoader->readHeader( m_ifs_ptr );
TS_ASSERT_EQUALS( m_ifs_ptr->tellg(), 70 );
WLoaderFibers loader( "fixtures/Fibers/unsupported_format_version_string.fib", m_dataHandler );
TS_ASSERT_THROWS_EQUALS( loader.readHeader(),
const WDHException &e,
e.what(),
std::string( "Unsupported format version string: # vtk DataFile Version 9.0" ) );
}
/**
* If the header introduces a STRUCTURED_POINTS VTK DATASET then true
* should be returned.
* If the internal VTK header is too big an error is thrown
*/
void testCheckDatasetType( void )
void testReadHeaderOnTooBigVTKHeader( void )
{
m_fibLoader->readHeader( m_ifs_ptr );
TS_ASSERT_EQUALS( m_fibLoader->datasetTypeIs( "STRUCTURED_POINTS" ), true );
WLoaderFibers loader( "fixtures/Fibers/invalid_header_length.fib", m_dataHandler );
TS_ASSERT_THROWS_EQUALS( loader.readHeader(),
const WDHException &e,
e.what(),
std::string( "VTK header too big: 261" ) );
}
/**
* A VTK file is typically either in BINARY or ASCII format.
* ATM we only support BINARY VTK files.
*/
void testBinaryOrAscii( void )
{
m_fibLoader->readHeader( m_ifs_ptr );
TS_ASSERT_EQUALS( m_fibLoader->isBinary(), false );
WLoaderFibers loader( "fixtures/Fibers/ascii.fib", m_dataHandler );
TS_ASSERT_THROWS_EQUALS( loader.readHeader(),
const WDHException &e,
e.what(),
std::string( "VTK files in 'ASCII' format are not yet supported" ) );
}
private:
/**
* Dummy DataHandler instance
* If the header not introduces a POLYDATA DATASET an exception should be
* thrown.
*/
boost::shared_ptr< WDataHandler > m_dataHandler;
void testCheckDatasetType( void )
{
WLoaderFibers loader( "fixtures/Fibers/invalid_dataset.fib", m_dataHandler );
TS_ASSERT_THROWS_EQUALS( loader.readHeader(),
const WDHException &e,
e.what(),
std::string( "Invalid VTK DATASET type: STRUCTURED_POINTS" ) );
}
/**
* After reading the header the position in the stream should have
* changed
*/
void testStreamPosIsValidAfterReadHeaderCall( void )
{
WLoaderFibers loader( "fixtures/Fibers/valid_small_example.fib", m_dataHandler );
loader.readHeader();
TS_ASSERT_EQUALS( loader.m_ifs->tellg(), 82 );
}
/**
* A standard VTK file.
* If there is no header at all an exception should be thrown.
*/
boost::filesystem::path m_vtkFile;
void testNoHeaderThere( void )
{
WLoaderFibers loader( "fixtures/Fibers/no_header.fib", m_dataHandler );
TS_ASSERT_THROWS( loader.readHeader(), WDHException );
}
/**
* Emulation of ifstream
* If there is a crippled header then an exception should be thrown
*/
std::ifstream *m_ifs_ptr;
void testOnAbruptHeader( void )
{
WLoaderFibers loader( "fixtures/Fibers/crippled_header.fib", m_dataHandler );
TS_ASSERT_THROWS_EQUALS( loader.readHeader(),
const WDHException &e,
e.what(),
std::string( "Unexpected end of file: fixtures/Fibers/crippled_header.fib" ) );
}
private:
/**
* Instanciating an loader
* Dummy DataHandler instance
*/
WLoaderFibers *m_fibLoader;
boost::shared_ptr< WDataHandler > m_dataHandler;
};
#endif // WLOADERFIBERS_TEST_H
# vtk DataFile Version 3.0
vtk output
ASCII
DATASET POLYDATA
POINT_DATA 8
TENSORS tensors float
3 0 0 0 0.5 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
# vtk DataFile Version 3.0
comment
BINARY
# vtk DataFile Version 3.0
Neural Pathways aka as fibers.
BINARY
DATASET POLYDATA
POINTS 1224 float
# vtk DataFile Version 3.0
vtk output
ASCII
BINARY
DATASET STRUCTURED_POINTS
DIMENSIONS 2 2 2
SPACING 1 1 1
......
# vtk DataFile Version 9.0
vtk output
BINARY
DATASET STRUCTURED_POINTS
DIMENSIONS 2 2 2
SPACING 1 1 1
ORIGIN 0 0 0
CELL_DATA 1
POINT_DATA 8
TENSORS tensors float
3 0 0 0 0.5 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment