Commit 2ec0dd7f authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[ADD] reader for ultra-simple text-based line datasets. Small format description inside the code.

parent 42c694ff
......@@ -4,6 +4,7 @@ ADD_MODULE( readAmiraMesh )
ADD_MODULE( readLAS )
ADD_MODULE( readMesh )
ADD_MODULE( readRawData )
ADD_MODULE( readSimpleTextLineData )
ADD_MODULE( readVIM )
ADD_MODULE( writeAmiraMesh )
ADD_MODULE( writeDendrogram )
......
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <fstream>
#include <string>
#include <vector>
#include "core/kernel/WKernel.h"
#include "core/kernel/WDataModuleInputFile.h"
#include "core/kernel/WDataModuleInputFilterFile.h"
#include "core/common/WPathHelper.h"
#include "core/common/WStringUtils.h"
#include "WMReadSimpleTextLineData.h"
// This line is needed by the module loader to actually find your module. You need to add this to your module too. Do NOT add a ";" here.
W_LOADABLE_MODULE( WMReadSimpleTextLineData )
WMReadSimpleTextLineData::WMReadSimpleTextLineData():
WDataModule(),
m_reload( false )
{
// Init
}
WMReadSimpleTextLineData::~WMReadSimpleTextLineData()
{
// Cleanup!
}
boost::shared_ptr< WModule > WMReadSimpleTextLineData::factory() const
{
return boost::shared_ptr< WModule >( new WMReadSimpleTextLineData() );
}
const std::string WMReadSimpleTextLineData::getName() const
{
// Specify your module name here. This name must be UNIQUE!
return "Read Simple Text Line Data";
}
const std::string WMReadSimpleTextLineData::getDescription() const
{
// Specify your module description here. Be detailed. This text is read by the user.
return "This module reads simple text-based line files.";
}
void WMReadSimpleTextLineData::connectors()
{
m_output = WModuleOutputData < WDataSetFibers >::createAndAdd( shared_from_this(), "out", "The loaded dataset" );
// call WModule's initialization
WModule::connectors();
}
void WMReadSimpleTextLineData::moduleMain()
{
m_moduleState.setResetable( true, true );
// Signal ready state. Now your module can be connected by the container, which owns the module.
ready();
waitRestored();
// main loop
while( !m_shutdownFlag() )
{
m_moduleState.wait();
// woke up since the module is requested to finish
if( m_shutdownFlag() )
{
break;
}
if( m_reload )
{
load();
}
}
}
std::vector< WDataModuleInputFilter::ConstSPtr > WMReadSimpleTextLineData::getInputFilter() const
{
std::vector< WDataModuleInputFilter::ConstSPtr > filters;
// NOTE: plain extension. No wildcards or prefixing "."!
filters.push_back( WDataModuleInputFilter::ConstSPtr( new WDataModuleInputFilterFile( "stld", "Simple text-based line data files" ) ) );
return filters;
}
void WMReadSimpleTextLineData::handleInputChange()
{
// notify the module only
m_reload = true;
m_moduleState.notify();
}
void WMReadSimpleTextLineData::load()
{
/*
* Tiny Format Description
*
* Purpose: easy write, easy read -> interchange data between different tools.
*
* Storing line-strips as a bunch of points and the corresponding point-index-list per strip.
*
* A point in the file starts with "P", followed by space and three coordinates (space separated too).
* A line strip starts with "L", followed by space and a list of indices (to points).
* Everything else is ignored right now.
*
* Example:
*
* # Comment
* P 134 123.55 122.4563213123
* P 1.34 1.2355 1.2245
* P 3.34 14.2355 12.2
* L 0 2 1
* L 0 1
* L 2 0
*/
m_reload = false;
// open file
WDataModuleInputFile::SPtr inputFile = getInputAs< WDataModuleInputFile >();
if( !inputFile )
{
// No input? Reset output too.
m_output->updateData( WDataSetFibers::SPtr() );
return;
}
boost::filesystem::path p = inputFile->getFilename();
std::ifstream ifs;
ifs.open( p.string().c_str(), std::ifstream::in );
if( !ifs || ifs.bad() )
{
errorLog() << "Could not open file \"" << p.string() << "\".";
return;
}
boost::shared_ptr< WProgress > progress1( new WProgress( "Loading" ) );
m_progress->addSubProgress( progress1 );
// Keep track of the BB
WBoundingBox bb;
// Walk through the file -> line by line
std::string line;
std::vector< std::string > tokens;
size_t numLines = 0;
// Some storage for loading the data
std::vector< WVector3f > loadedVertices;
typedef std::vector< size_t > LineStrip;
std::vector< LineStrip > loadedLineStrips;
while( !ifs.eof() )
{
std::getline( ifs, line );
tokens = string_utils::tokenize( string_utils::trim( line ) );
numLines++;
// first token describes meaning.
// NOTE: be kind and ignore unknown tokens (like comments)
if( tokens.size() < 2 ) // < 2? Each line is at least a describing token and a value for it == 2
{
continue;
}
// It is a point.
if( string_utils::toLower( tokens[0] ) == "p" )
{
WVector3f coord(
string_utils::fromString< float >( tokens[1] ),
string_utils::fromString< float >( tokens[2] ),
string_utils::fromString< float >( tokens[3] )
);
// expand bb
bb.expandBy( coord );
loadedVertices.push_back( coord );
}
if( string_utils::toLower( tokens[0] ) == "l" )
{
LineStrip ls;
// Copy all the indices into the linestrip vector
for( size_t i = 1; i < tokens.size(); ++i )
{
size_t idx = string_utils::fromString< size_t >( tokens[i] );
ls.push_back( idx );
}
// NOTE: a lot of copying, but when considering overall bad performance of hard disk IO vs RAM ...
loadedLineStrips.push_back( ls );
}
}
// As the DataSetFibers uses run-length encoded linestrips, we need to transform the stuff now.
// target memory
WDataSetFibers::VertexArray vertices( new WDataSetFibers::VertexArray::element_type() );
WDataSetFibers::LengthArray lengths( new WDataSetFibers::LengthArray::element_type() );
WDataSetFibers::IndexArray lineStartIndices( new WDataSetFibers::IndexArray::element_type() );
WDataSetFibers::IndexArray verticesReverse( new WDataSetFibers::IndexArray::element_type() );
WDataSetFibers::VertexParemeterArray attribs( new WDataSetFibers::VertexParemeterArray::element_type() );
size_t currentStartIndex = 0;
// For each lineStrip, we need to add vertices and fill the run-lenght info in lengths and lineStartIndices.
for( std::vector< LineStrip >::const_iterator iter = loadedLineStrips.begin(); iter != loadedLineStrips.end(); ++iter )
{
const LineStrip& ls = *iter;
// For each index in the strip, resolve the indexed point coordinates.
for( LineStrip::const_iterator indexIter = ls.begin(); ls.end() != indexIter; ++indexIter )
{
// Get loaded data
size_t pIdx = *indexIter;
WVector3f p = loadedVertices[ pIdx ];
// Add point to vertices
vertices->push_back( p[ 0 ] );
vertices->push_back( p[ 1 ] );
vertices->push_back( p[ 2 ] );
// store the current line index for each vertex
verticesReverse->push_back( iter - loadedLineStrips.begin() );
}
// set length of the strip
lengths->push_back( ls.size() );
// index where it starts inside the vertex array
lineStartIndices->push_back( currentStartIndex );
currentStartIndex += ls.size();
}
m_output->updateData( WDataSetFibers::SPtr( new WDataSetFibers( vertices, lineStartIndices, lengths, verticesReverse, bb ) ) );
// done. close file and report finish
progress1->finish();
ifs.close();
infoLog() << "Loaded " << loadedLineStrips.size() << " line strips from file. Done.";
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WMREADSIMPLETEXTLINEDATA_H
#define WMREADSIMPLETEXTLINEDATA_H
#include <string>
#include <vector>
#include "core/dataHandler/WDataSetFibers.h"
#include "core/kernel/WDataModule.h"
#include "core/kernel/WModuleOutputData.h"
/**
* This module loads simple text-based line data files.
*
* \ingroup modules
*/
class WMReadSimpleTextLineData: public WDataModule
{
public:
/**
* Default constructor.
*/
WMReadSimpleTextLineData();
/**
* Destructor.
*/
virtual ~WMReadSimpleTextLineData();
/**
* Gives back the name of this module.
* \return the module's name.
*/
virtual const std::string getName() const;
/**
* Gives back a description of this module.
* \return description to module.
*/
virtual const std::string getDescription() const;
/**
* Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
* should never be initialized or modified in some other way. A simple new instance is required.
*
* \return the prototype used to create every module in OpenWalnut.
*/
virtual boost::shared_ptr< WModule > factory() const;
/**
* Define a list of file filters we support.
*
* \return the list of filters
*/
virtual std::vector< WDataModuleInputFilter::ConstSPtr > getInputFilter() const;
protected:
/**
* Entry point after loading the module. Runs in separate thread.
*/
virtual void moduleMain();
/**
* Initialize the connectors this module is using.
*/
virtual void connectors();
/**
* Load data.
*/
virtual void load();
/**
* Handle a newly set input. Implement this method to load the newly set input. You can get the input using the \ref getInput and \ref getInputAs
* methods. Please remember that it is possible to get a NULL pointer here.
* This happens when the user explicitly sets no input. In this case, you should clean up and reset your output connectors.
*
* \note it is very important to NOT load the data inside of this method. It is usually called in the GUI thread. This would block the whole GUI.
* Instead, use this method for firing a condition, which then wakes your module thread.
*/
virtual void handleInputChange();
private:
/**
* The output connector for the data.
*/
boost::shared_ptr< WModuleOutputData< WDataSetFibers > > m_output;
/**
* True if the load function needs to be called. Usually set by handleInputChange or the reload trigger
*/
bool m_reload;
};
#endif // WMREADSIMPLETEXTLINEDATA_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
// Provide additional material and descriptions for your module. You can
// provide this for multiple modules if you like.
// NOTE: everything but the module name is optional, even if this makes no
// sense at all.
"Read Simple Text Line Data"
{
// Provide an icon. If the icon exists, it overrides the one provided by your
// getXPMIcon method. This path is relative to your module's resource directory.
icon="icon.png";
// Where to find the module?
website = "http://www.openwalnut.org";
// Provide a description, If you do so, this description overrides the one
// provided by your getDescription method.
// HINT: multi-line strings are not supported. Please provide long texts in
// one line.
description = "This module reads a rather simple text-based line data file.";
// Provide a list of authors. These authors can have further information associated with them.
author = "OpenWalnut Project";
// Provide author information. Especially a contact address is very handy.
// This associates some URL and Mail contact info to "OpenWalnut Project".
"OpenWalnut Project"
{
url="http://www.openwalnut.org";
email="contact@openwalnut.org";
what="Design, Development and Bug fixing";
};
};
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