1

Hi I want to read data from a VTK file into my C++ program. Here is how my files will typically look.

POINTS 2 double

1 2

3 4

POINT_DATA 2

SCALARS pressure double

LOOKUP_TABLE default

5

6

SCALARS density double

LOOKUP_TABLE default

7

8

I want to put the numerical data highlighted in bold into my C++ program but I dont know how to ignore the text lines in between the data.

To be more precise: I have arrays xp[2], yp[2], pressure[2] , density[2]

I want to put

 xp[0]=1 yp[0]=2 xp[1]=3 yp[1]=4 pressure[0]=5 pressure[1]=6 density[0]=7 density[1]=8 

I dont know how to do this since there is text between the numbers that I have to put into my arrays.

9
  • 2
    You need to read about parsing the text in the file to extract the data you want. Have a go at writing something and if you can't get it working post the code in to your question. As it is, we're not going to write your application for you. Commented Oct 19, 2011 at 20:41
  • I think you will need to post an example file you want parsed. The answer will depend on that unless you want a very general explanation of the techniques. Commented Oct 19, 2011 at 20:42
  • I have already included the example file in the code above Commented Oct 19, 2011 at 20:44
  • Based on what you've said so far, do you really need to do any more than discard each line if the first character isn't a digit? Commented Oct 19, 2011 at 20:45
  • 1
    I did a quick search for 'VTK file' (as I didn't know what it was) and there is a ton of information out there on the net about this file format. I even found there is a vtkPolyDataReader: vtk.org/doc/release/4.0/html/classvtkPolyDataReader.html so there may well already be code available to do what you are trying to do. EDIT: Here's a link to the main page of the VTK Documentation: vtk.org/doc/release/4.0/html/index.html Commented Oct 19, 2011 at 20:46

3 Answers 3

5

Once again I couldn't really resist the finger exercise in using Boost Spirit for this purpose.

Explanation

Behold this very adhoc and minimalistic sample that

  • parses the given text (using Spirit Qi) into

    • a points collection (vector of pair)
    • a dynamic map of lookup tables (identified by a name - e.g. "pressure") and containing vector)
  • does rudimentary error reporting on unpexpected input

  • prints the parsed data back into compact formatting (this uses Spirit Karma)

  • it is whitespace tolerant (though the newlines are required as in the input)

Flaws:

  • it is really quick and dirty: it should really be a grammar class with
    • separate rule definitions
      • more readable
      • more debuggable
    • explicit semantic input checks (lookup table names, number of elements in each data table (the counts in POINTS _n and POINT_DATA n are being handsomely ignored now)
    • use phoenix (or c++0x std::move) to prevent the copying of the lookup table data

Sample

Output of the code/input as shown (note the intentional 'bogus' input demonstrating the error reporting):

Parse failed remaining: 'bogus' Points: [1.0,2.0], [3.0,4.0] density: 7.0, 8.0 pressure: 5.0, 6.0 

And the code (c++, tested with boost 1_47_0):

#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/karma.hpp> #include <boost/fusion/adapted/std_pair.hpp> #include <map> namespace qi = boost::spirit::qi; namespace karma = boost::spirit::karma; typedef std::vector<double> lookuptable_t; typedef std::map<std::string, lookuptable_t> lookuptables_t; typedef std::pair<double, double> point_t; typedef std::vector<point_t> points_t; int main() { std::string input = "POINTS 2 double\n" "1 2\n" "3 4\n" "POINT_DATA 2\n" "SCALARS pressure double\n" "LOOKUP_TABLE default\n" "5\n" "6\n" "SCALARS density double\n" "LOOKUP_TABLE default\n" "7\n" "8 bogus"; points_t points; lookuptables_t lookuptables; { std::string::const_iterator f(input.begin()), l(input.end()); using namespace qi; bool ok = phrase_parse(f, l, "POINTS" > omit[ uint_ ] > "double" > eol >> (double_ >> double_) % eol > eol >> "POINT_DATA" > omit [ uint_ ], char_(" \t"), points); while (ok && f!=l) { std::string name; lookuptable_t table; ok = phrase_parse(f, l, eol >> "SCALARS" > +raw [ eps >> "pressure"|"density" ] > "double" > eol > "LOOKUP_TABLE" > "default" > eol > double_ % eol, char_(" \t"), name, table); if (ok && !lookuptables.insert(std::make_pair(name, table)).second) std::cerr << "duplicate table for '" << name << "' ignored" << std::endl; } if (!ok || (f!=l)) std::cerr << "Parse " << (ok?"success":"failed") << " remaining: '" << std::string(f, std::min(f+10, l)) << "'" << std::endl; } { using namespace karma; std::cout << format( "Points: " << ('[' << double_ << ',' << double_ << ']') % ", " << eol << +(string << ": " << auto_ % ", " << eol), points, lookuptables); } } 
Sign up to request clarification or add additional context in comments.

Comments

1

You can use the ignore function to throw away lines of text that are not numbers. Use cin >> x to read a value x from the input file. If that fails, the failbit is set in the input stream, which you must clear. Then, ignore the whole line.

std::vector<int> data; while (!cin.eof()) { int x; if (cin >> x) { data.push_back(x); if (data.size() == 8) { // do whatever you need with the 8 numbers data.clear(); } } else { cin.clear(); cin.ignore(1000, '\n'); // assuming maximum line length less than 1000 } } 

(This code assumes reading from cin, which is redirected to another input file)

Comments

0

You could try some code that looks like this. It's kind of a combo of C and C++:

int main () { //assuming that you've completely read in the file to a char* called myFileContents char * token; token = strtok (myFileContents," "); while (token != NULL) { istringstream iss( token ); int readInData; readInData << iss; if(!iss){ //this means that the data wasn't numeric so don't do anything with it } else{ //data was numeric, store it how ever you want } token = strtok (NULL, " "); } return 0; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.