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.

smilingbuddha
  • 14,334
  • 33
  • 112
  • 189
  • 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. – Tony Oct 19 '11 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. – VoidStar Oct 19 '11 at 20:42
  • I have already included the example file in the code above – smilingbuddha Oct 19 '11 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? – Jerry Coffin Oct 19 '11 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`: http://www.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: http://www.vtk.org/doc/release/4.0/html/index.html – Tony Oct 19 '11 at 20:46
  • @Tony. I dont expect people to write the code for me. Even if people tell me some general C++ keywords/functions, to solve my problem that is fine. – smilingbuddha Oct 19 '11 at 20:47
  • @Tony Thank you for the useful information. – smilingbuddha Oct 19 '11 at 20:48
  • @JerryCoffin Yeah I just need to read the lines containing the numbers. – smilingbuddha Oct 19 '11 at 21:04
  • @smilingbuddha: why don't you use VTK itself to read its format? Or: why don't you just copy and paste its code? (It is open source, you could download previous versions source, too, if it is necesary.) – Naszta Oct 19 '11 at 21:14

3 Answers3

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);
    }

}
sehe
  • 374,641
  • 47
  • 450
  • 633
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)

anatolyg
  • 26,506
  • 9
  • 60
  • 134
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;
}
Kurtis Nusbaum
  • 30,445
  • 13
  • 78
  • 102