OpenWalnut  1.5.0dev
WMReadSimpleTextLineData.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <fstream>
27 #include <map>
28 #include <memory>
29 #include <string>
30 #include <vector>
31 
32 #include <boost/foreach.hpp>
33 
34 #include "WMReadSimpleTextLineData.h"
35 #include "core/common/WPathHelper.h"
36 #include "core/common/WStringUtils.h"
37 #include "core/kernel/WDataModuleInputFile.h"
38 #include "core/kernel/WDataModuleInputFilterFile.h"
39 #include "core/kernel/WKernel.h"
40 
41 // 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.
42 W_LOADABLE_MODULE( WMReadSimpleTextLineData )
43 
45  WDataModule(),
46  m_reload( false )
47 {
48  // Init
49 }
50 
52 {
53  // Cleanup!
54 }
55 
56 std::shared_ptr< WModule > WMReadSimpleTextLineData::factory() const
57 {
58  return std::shared_ptr< WModule >( new WMReadSimpleTextLineData() );
59 }
60 
61 const std::string WMReadSimpleTextLineData::getName() const
62 {
63  // Specify your module name here. This name must be UNIQUE!
64  return "Read Simple Text Line Data";
65 }
66 
68 {
69  // Specify your module description here. Be detailed. This text is read by the user.
70  return "This module reads simple text-based line files.";
71 }
72 
74 {
75  m_output = WModuleOutputData < WDataSetFibers >::createAndAdd( shared_from_this(), "out", "The loaded dataset" );
76 
77  // call WModule's initialization
79 }
80 
82 {
83  m_moduleState.setResetable( true, true );
84 
85  // Signal ready state. Now your module can be connected by the container, which owns the module.
86  ready();
87  waitRestored();
88 
89  // main loop
90  while( !m_shutdownFlag() )
91  {
93 
94  // woke up since the module is requested to finish
95  if( m_shutdownFlag() )
96  {
97  break;
98  }
99 
100  if( m_reload )
101  {
102  load();
103  }
104  }
105 }
106 
107 std::vector< WDataModuleInputFilter::ConstSPtr > WMReadSimpleTextLineData::getInputFilter() const
108 {
109  std::vector< WDataModuleInputFilter::ConstSPtr > filters;
110 
111  // NOTE: plain extension. No wildcards or prefixing "."!
112  filters.push_back( WDataModuleInputFilter::ConstSPtr( new WDataModuleInputFilterFile( "stld", "Simple text-based line data files" ) ) );
113 
114  return filters;
115 }
116 
118 {
119  // notify the module only
120  m_reload = true;
122 }
123 
125 {
126  /*
127  * Tiny Format Description
128  *
129  * Purpose: easy write, easy read -> interchange data between different tools.
130  *
131  * Storing line-strips as a bunch of points and the corresponding point-index-list per strip.
132  *
133  * A point in the file starts with "P", followed by space and three coordinates (space separated too).
134  * A line strip starts with "L", followed by space and a list of indices (to points).
135  * Everything else is ignored right now.
136  *
137  * Example:
138  *
139  * # Comment
140  * P 134 123.55 122.4563213123
141  * P 1.34 1.2355 1.2245
142  * P 3.34 14.2355 12.2
143  * L 0 2 1
144  * L 0 1
145  * L 2 0
146  */
147  m_reload = false;
148 
149  // open file
150  WDataModuleInputFile::SPtr inputFile = getInputAs< WDataModuleInputFile >();
151  if( !inputFile )
152  {
153  // No input? Reset output too.
154  m_output->updateData( WDataSetFibers::SPtr() );
155  return;
156  }
157  boost::filesystem::path p = inputFile->getFilename();
158 
159  std::ifstream ifs;
160  ifs.open( p.string().c_str(), std::ifstream::in );
161  if( !ifs || ifs.bad() )
162  {
163  errorLog() << "Could not open file \"" << p.string() << "\".";
164  return;
165  }
166 
167  std::shared_ptr< WProgress > progress1( new WProgress( "Loading" ) );
168  m_progress->addSubProgress( progress1 );
169 
170 
171  // Keep track of the BB
172  WBoundingBox bb;
173 
174  // Walk through the file -> line by line
175  std::string line;
176  std::vector< std::string > tokens;
177  size_t numLines = 0;
178 
179  // Some storage for loading the data
180  std::vector< WVector3f > loadedVertices;
181  typedef std::vector< size_t > LineStrip;
182  std::vector< LineStrip > loadedLineStrips;
183  std::map< size_t, std::vector< double > > loadedPointAttribs;
184  std::map< size_t, std::vector< double > > loadedLineAttribs;
185 
186  while( !ifs.eof() )
187  {
188  std::getline( ifs, line );
189  tokens = string_utils::tokenize( string_utils::trim( line ) );
190  numLines++;
191 
192  // first token describes meaning.
193  // NOTE: be kind and ignore unknown tokens (like comments)
194  if( tokens.size() < 2 ) // < 2? Each line is at least a describing token and a value for it == 2
195  {
196  continue;
197  }
198 
199  // It is a point.
200  if( string_utils::toLower( tokens[0] ) == "p" )
201  {
202  WVector3f coord(
203  string_utils::fromString< float >( tokens[1] ),
204  string_utils::fromString< float >( tokens[2] ),
205  string_utils::fromString< float >( tokens[3] )
206  );
207 
208  // expand bb
209  bb.expandBy( coord );
210 
211  loadedVertices.push_back( coord );
212  }
213 
214  // It is a line.
215  if( string_utils::toLower( tokens[0] ) == "l" )
216  {
217  LineStrip ls;
218 
219  // Copy all the indices into the linestrip vector
220  for( size_t i = 1; i < tokens.size(); ++i )
221  {
222  size_t idx = string_utils::fromString< size_t >( tokens[i] );
223  ls.push_back( idx );
224  }
225 
226  // NOTE: a lot of copying, but when considering overall bad performance of hard disk IO vs RAM ...
227  loadedLineStrips.push_back( ls );
228  }
229 
230  // It is a point attribute.
231  if( string_utils::toLower( tokens[0] ) == "pa" )
232  {
233  size_t attrIdx = string_utils::fromString< size_t >( tokens[1] );
234  loadedPointAttribs[ attrIdx ].push_back( string_utils::fromString< float >( tokens[2] ) );
235  }
236 
237  // It is a line attribute.
238  if( string_utils::toLower( tokens[0] ) == "la" )
239  {
240  size_t attrIdx = string_utils::fromString< size_t >( tokens[1] );
241  loadedLineAttribs[ attrIdx ].push_back( string_utils::fromString< float >( tokens[2] ) );
242  }
243  }
244 
245  // As the DataSetFibers uses run-length encoded linestrips, we need to transform the stuff now.
246 
247  // target memory
248  WDataSetFibers::VertexArray vertices( new WDataSetFibers::VertexArray::element_type() );
249  WDataSetFibers::LengthArray lengths( new WDataSetFibers::LengthArray::element_type() );
250  WDataSetFibers::IndexArray lineStartIndices( new WDataSetFibers::IndexArray::element_type() );
251  WDataSetFibers::IndexArray verticesReverse( new WDataSetFibers::IndexArray::element_type() );
252 
253  std::vector< WDataSetFibers::VertexParemeterArray > pAttribs;
254  std::vector< WDataSetFibers::LineParemeterArray > lAttribs;
255 
256  for( std::map< size_t, std::vector< double > >::const_iterator i = loadedLineAttribs.begin(); i != loadedLineAttribs.end(); ++i )
257  {
258  size_t desiredSize = loadedLineStrips.size();
259  size_t realSize = ( *i ).second.size();
260 
261  if( desiredSize != realSize )
262  {
263  warnLog() << "Ignoring line attribute " << ( *i ).first << " as there are too few/too much items.";
264  }
265 
266  // Create and copy
267  std::shared_ptr< WDataSetFibers::LineParemeterArray::element_type > vec(
268  new WDataSetFibers::LineParemeterArray::element_type( realSize ) );
269  std::copy( ( *i ).second.begin(), ( *i ).second.end(), vec->begin() );
270  lAttribs.push_back( vec );
271  }
272 
273  // map between the indices in the source attribute list and the really used attributes
274  std::map< size_t, size_t > pAttribIdxMap;
275  for( std::map< size_t, std::vector< double > >::const_iterator i = loadedPointAttribs.begin(); i != loadedPointAttribs.end(); ++i )
276  {
277  size_t desiredSize = loadedVertices.size();
278  size_t realSize = ( *i ).second.size();
279 
280  if( desiredSize != realSize )
281  {
282  warnLog() << "Ignoring point attribute " << ( *i ).first << " as there are too few/too much items.";
283  }
284 
285  // Create and do NOT copy -> why? The vertex attributes need to be "de-indexed" below. So only create the target vector and go on.
286  std::shared_ptr< WDataSetFibers::VertexParemeterArray::element_type > vec(
287  new WDataSetFibers::VertexParemeterArray::element_type() );
288  pAttribIdxMap[ pAttribs.size() ] = ( *i ).first;
289  pAttribs.push_back( vec );
290  }
291 
292 
293  size_t currentStartIndex = 0;
294 
295  // For each lineStrip, we need to add vertices and fill the run-lenght info in lengths and lineStartIndices.
296  for( std::vector< LineStrip >::const_iterator iter = loadedLineStrips.begin(); iter != loadedLineStrips.end(); ++iter )
297  {
298  const LineStrip& ls = *iter;
299 
300  // For each index in the strip, resolve the indexed point coordinates.
301  for( LineStrip::const_iterator indexIter = ls.begin(); ls.end() != indexIter; ++indexIter )
302  {
303  // Get loaded data
304  size_t pIdx = *indexIter;
305  WVector3f p = loadedVertices[ pIdx ];
306 
307  // Add point to vertices
308  vertices->push_back( p[ 0 ] );
309  vertices->push_back( p[ 1 ] );
310  vertices->push_back( p[ 2 ] );
311 
312  for( std::vector< WDataSetFibers::VertexParemeterArray >::const_iterator i = pAttribs.begin(); i != pAttribs.end(); ++i )
313  {
314  size_t attrIdx = pAttribIdxMap[ i - pAttribs.begin() ];
315  ( *i )->push_back( loadedPointAttribs[ attrIdx ][ pIdx ] );
316  }
317 
318  // store the current line index for each vertex
319  verticesReverse->push_back( iter - loadedLineStrips.begin() );
320  }
321 
322  // set length of the strip
323  lengths->push_back( ls.size() );
324  // index where it starts inside the vertex array
325  lineStartIndices->push_back( currentStartIndex );
326  currentStartIndex += ls.size();
327  }
328 
329  WDataSetFibers::SPtr ds( new WDataSetFibers( vertices, lineStartIndices, lengths, verticesReverse, bb ) );
330  ds->setVertexParameters( pAttribs );
331  ds->setLineParameters( lAttribs );
332 
333  m_output->updateData( ds );
334 
335  // done. close file and report finish
336  progress1->finish();
337  ifs.close();
338 
339  infoLog() << "Loaded " << loadedLineStrips.size() << " line strips from file, having " << pAttribs.size() << " point attributes and "
340  << lAttribs.size() << " line attributes. Done.";
341 }
342 
void expandBy(const WBoundingBoxImpl< VT > &bb)
Expands this bounding box to include the given bounding box.
Definition: WBoundingBox.h:240
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void notify()
Notifies all waiting threads.
std::shared_ptr< WDataModuleInputFile > SPtr
Convenience typedef for a std::shared_ptr< WDataModuleInputFile >.
Checks a given WDataModuleInput against a file type.
std::shared_ptr< const WDataModuleInputFilter > ConstSPtr
Convenience typedef for a std::shared_ptr< const WDataModuleInputFilter >.
Base for all data loader modules.
Definition: WDataModule.h:47
Represents a simple set of WFibers.
std::shared_ptr< std::vector< size_t > > IndexArray
Index list indexing fibers in VertexArray in terms of vertex numbers.
std::shared_ptr< std::vector< size_t > > LengthArray
Lengths of fibers in terms of vertices.
std::shared_ptr< WDataSetFibers > SPtr
Pointer to dataset.
std::shared_ptr< std::vector< float > > VertexArray
List of vertex coordinates in term of components of vertices.
This module loads simple text-based line data files.
virtual const std::string getName() const
Gives back the name of this module.
virtual void handleInputChange()
Handle a newly set input.
bool m_reload
True if the load function needs to be called.
virtual ~WMReadSimpleTextLineData()
Destructor.
std::shared_ptr< WModuleOutputData< WDataSetFibers > > m_output
The output connector for the data.
WMReadSimpleTextLineData()
Default constructor.
virtual void moduleMain()
Entry point after loading the module.
virtual const std::string getDescription() const
Gives back a description of this module.
virtual std::vector< WDataModuleInputFilter::ConstSPtr > getInputFilter() const
Define a list of file filters we support.
virtual void connectors()
Initialize the connectors this module is using.
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
A fixed size matrix class.
Definition: WMatrixFixed.h:150
size_t size() const
The number of entries.
Definition: WMatrixFixed.h:203
Class offering an instantiate-able data connection between modules.
wlog::WStreamedLogger warnLog() const
Logger instance for comfortable warning- logs.
Definition: WModule.cpp:580
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
wlog::WStreamedLogger errorLog() const
Logger instance for comfortable error logging.
Definition: WModule.cpp:570
std::shared_ptr< WProgressCombiner > m_progress
Progress indicator used as parent for all progress' of this module.
Definition: WModule.h:652
wlog::WStreamedLogger infoLog() const
Logger instance for comfortable info logging.
Definition: WModule.cpp:565
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
void waitRestored()
This method waits for the module to be restored completely.
Definition: WModule.cpp:625
Class managing progress inside of modules.
Definition: WProgress.h:42
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
std::string toLower(const std::string &source)
Transforms all characters in the given string into lower case characters.
std::vector< std::string > tokenize(const std::string &source, const std::string &delim=WHITESPACE, bool compress=true)
Splits the given string into a vector of strings (so called tokens).
std::string trim(const std::string &source, const std::string &t=WHITESPACE)
Trims any occurence of each character given in parameter t from both ends (right and left side) of th...