vtkXGMLReader.cxx 13.2 KB
Newer Older
1
/*=========================================================================
2

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Program:   Visualization Toolkit
Module:    vtkXGMLReader.cxx

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
  -------------------------------------------------------------------------*/

#include "vtkXGMLReader.h"

#include "vtkCellData.h"
#include "vtkIntArray.h"
#include "vtkMutableUndirectedGraph.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkSmartPointer.h"
#include "vtkStdString.h"
#include "vtkStringArray.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"
#include "vtkAbstractArray.h"
#include "vtkIdTypeArray.h"


#include <cassert>
39 40 41
#include <fstream>
#include <sstream>
#include <map>
Sean McBride's avatar
Sean McBride committed
42
#include <cctype> // for isspace, isdigit
43 44

// Copied from vtkTulipReader.cxx ..
45
static int my_getline(std::istream& stream, vtkStdString &output, char delim='\n');
46 47 48 49 50 51

vtkStandardNewMacro(vtkXGMLReader);

vtkXGMLReader::vtkXGMLReader()
{
  // Default values for the origin vertex
52
  this->FileName = nullptr;
53 54 55 56 57
  this->SetNumberOfInputPorts(0);
}

vtkXGMLReader::~vtkXGMLReader()
{
58
  this->SetFileName(nullptr);
59 60
}

61
void vtkXGMLReader::PrintSelf(std::ostream& os, vtkIndent indent)
62 63
{
  this->Superclass::PrintSelf(os, indent);
64 65

  os << indent << "FileName: "
66 67 68 69 70 71 72
     << (this->FileName ? this->FileName : "(none)") << endl;
}

#define MAX_NR_PROPERTIES 50

struct vtkXGMLProperty
{
73 74 75
  enum {
    NODE_PROP,
    EDGE_PROP
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
  };
  int Kind;  // :: NODE_PROP or EDGE_PROP
  vtkAbstractArray *Data;
};

struct vtkXGMLReaderToken
{
  enum {
    OPEN_GROUP,
    CLOSE_GROUP,
    KEYWORD,
    INT,
    DOUBLE,
    TEXT,
    END_OF_FILE
  };
  int Type;
  vtkStdString StringValue;
  int IntValue;
  double DoubleValue;
};



100
static void vtkXGMLReaderNextToken(std::istream& in, vtkXGMLReaderToken& tok)
101 102 103
{
  char ch = in.peek();
  while (!in.eof() && (ch == ';' || isspace(ch)))
104
  {
105
    while (!in.eof() && ch == ';')
106
    {
107 108 109
      vtkStdString comment;
      my_getline(in, comment);
      ch = in.peek();
110
    }
111
    while (!in.eof() && isspace(ch))
112
    {
113 114 115
      in.get();
      ch = in.peek();
    }
116
  }
117

118
  if (in.eof())
119
  {
120 121
    tok.Type = vtkXGMLReaderToken::END_OF_FILE;
    return;
122
  }
123
  if (ch == '[')
124
  {
125 126
    in.get();
    tok.Type = vtkXGMLReaderToken::OPEN_GROUP;
127
  }
128
  else if (ch == ']')
129
  {
130 131
    in.get();
    tok.Type = vtkXGMLReaderToken::CLOSE_GROUP;
132
  }
133
  else if (isdigit(ch) || ch == '.')
134
  {
135
    bool isDouble = false;
136
    std::stringstream ss;
137
    while (isdigit(ch) || ch == '.')
138
    {
139 140 141 142
      in.get();
      isDouble = isDouble || ch == '.';
      ss << ch;
      ch = in.peek();
143
    }
144
    if (isDouble)
145
    {
146 147
      ss >> tok.DoubleValue;
      tok.Type = vtkXGMLReaderToken::DOUBLE;
148
    }
149
    else
150
    {
151 152 153
      ss >> tok.IntValue;
      tok.Type = vtkXGMLReaderToken::INT;
    }
154
  }
155
  else if (ch == '"')
156
  {
157 158 159 160
    in.get();
    tok.StringValue = "";
    ch = in.get();
    while (ch != '"')
161
    {
162 163 164
      tok.StringValue += ch;
      ch = in.get();
    }
165 166
    tok.Type = vtkXGMLReaderToken::TEXT;
  }
167
  else
168
  {
169 170
    in >> tok.StringValue;
    tok.Type = vtkXGMLReaderToken::KEYWORD;
171
  }
172 173 174 175 176 177 178 179 180 181 182 183 184 185
}

int vtkXGMLReader::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  vtkIdType nr_of_nodes = 0;       // as read from file
  vtkIdType nr_of_edges = 0;       // as read from file
  int nr_of_properties = 0;
  vtkXGMLProperty property_table[MAX_NR_PROPERTIES];
  vtkStdString name;
  int kind;
  int i;
186
  vtkIdType dst, id = 0, src = 0;
187
  double d = 0.;
188
  vtkIdTypeArray *edgeIds, *nodeIds;
189 190


191
  if (this->FileName == nullptr)
192
  {
193 194
    vtkErrorMacro("File name undefined");
    return 0;
195
  }
196

197
  std::ifstream fin(this->FileName);
198
  if(!fin.is_open())
199
  {
200 201
    vtkErrorMacro("Could not open file " << this->FileName << ".");
    return 0;
202
  }
203

204 205 206
  // Get the output graph
  vtkSmartPointer<vtkMutableUndirectedGraph> builder =
    vtkSmartPointer<vtkMutableUndirectedGraph>::New();
207

208 209
  std::map<int, vtkIdType> nodeIdMap;
  std::map<int, vtkIdType> edgeIdMap;
210
  vtkXGMLReaderToken tok;
211

212 213 214
  // expect graph
  vtkXGMLReaderNextToken(fin, tok);
  assert(tok.Type == vtkXGMLReaderToken::KEYWORD && tok.StringValue == "graph");
215

216
  // expect [
217
  vtkXGMLReaderNextToken(fin, tok);
218
  assert(tok.Type == vtkXGMLReaderToken::OPEN_GROUP);
219

220 221
  vtkXGMLReaderNextToken(fin, tok);
  while (tok.Type == vtkXGMLReaderToken::KEYWORD && tok.StringValue != "node")
222
  {
223
    if (tok.StringValue == "node_count")
224
    {
225 226 227
      vtkXGMLReaderNextToken(fin, tok);
      assert(tok.Type == vtkXGMLReaderToken::INT);
      nr_of_nodes = tok.IntValue;
228
    }
229
    else if (tok.StringValue == "edge_count")
230
    {
231 232 233
      vtkXGMLReaderNextToken(fin, tok);
      assert(tok.Type == vtkXGMLReaderToken::INT);
      nr_of_edges = tok.IntValue;
234
    }
235
    else if (tok.StringValue == "node_data" || tok.StringValue == "edge_data")
236
    {
237
      if (nr_of_properties == MAX_NR_PROPERTIES)
238
      {
239 240
        vtkErrorMacro(<<"Too many properties in file.");
        return 0;
241
      }
242
      kind = (tok.StringValue == "node_data") ? vtkXGMLProperty::NODE_PROP
243 244 245 246
        : vtkXGMLProperty::EDGE_PROP;
      vtkXGMLReaderNextToken(fin, tok);
      assert(tok.Type == vtkXGMLReaderToken::KEYWORD);
      name = tok.StringValue;
247

248 249 250
      vtkXGMLReaderNextToken(fin, tok);
      assert(tok.Type == vtkXGMLReaderToken::KEYWORD);
      if (tok.StringValue == "float")
251
      {
252
        property_table[nr_of_properties].Data = vtkDoubleArray::New();
253
      }
254
      else if (tok.StringValue == "int")
255
      {
256
        property_table[nr_of_properties].Data = vtkIntArray::New();
257
      }
258
      else if (tok.StringValue == "string")
259
      {
260
        property_table[nr_of_properties].Data = vtkStringArray::New();
261
      }
262 263 264 265 266
      property_table[nr_of_properties].Kind = kind;
      property_table[nr_of_properties].Data->SetName(name);
      property_table[nr_of_properties].Data->SetNumberOfTuples(
        kind == vtkXGMLProperty::NODE_PROP ? nr_of_nodes : nr_of_edges);
      nr_of_properties++;
267
    }
268
    else
269
    {
270 271 272
      vtkErrorMacro(<<"Parse error (header): unexpected token ")
        return 0;
    }
273 274
    vtkXGMLReaderNextToken(fin, tok);
  }
275

276
  while (tok.Type == vtkXGMLReaderToken::KEYWORD && tok.StringValue == "node")
277
  {
278 279 280
    // Expect [
    vtkXGMLReaderNextToken(fin, tok);
    assert(tok.Type == vtkXGMLReaderToken::OPEN_GROUP);
281

282 283
    vtkXGMLReaderNextToken(fin, tok);
    while (tok.Type == vtkXGMLReaderToken::KEYWORD)
284
    {
285
      if (tok.StringValue == "id")
286
      {
287 288 289 290
        vtkXGMLReaderNextToken(fin, tok);
        assert(tok.Type == vtkXGMLReaderToken::INT);
        id = builder->AddVertex();
        nodeIdMap[tok.IntValue] = id;
291
      }
292
      else if (tok.StringValue == "degree")
293
      {
294 295
        vtkXGMLReaderNextToken(fin, tok);
        // Read degree and ignore
296
      }
297
      else
298
      {
299
        for (i = 0; i < nr_of_properties; i++)
300
        {
301
          if (property_table[i].Kind == vtkXGMLProperty::NODE_PROP &&
302
              property_table[i].Data->GetName() == tok.StringValue) { break; }
303
        }
304
        if (i == nr_of_properties)
305
        {
306 307 308
          vtkErrorMacro(<<"Undefined node property ");
          cout << tok.StringValue<<"\n";
          return 0;
309
        }
310 311
        vtkXGMLReaderNextToken(fin, tok);
        if (property_table[i].Data->GetDataType() == VTK_INT)
312
        {
313
          assert(tok.Type == vtkXGMLReaderToken::INT);
314
          vtkArrayDownCast<vtkIntArray>(property_table[i].Data)->SetValue(nodeIdMap[id], tok.IntValue);
315
        }
316
        else if (property_table[i].Data->GetDataType() == VTK_DOUBLE)
317
        {
318 319 320 321 322 323
          if (tok.Type == vtkXGMLReaderToken::DOUBLE)
            d = tok.DoubleValue;
          else if (tok.Type == vtkXGMLReaderToken::INT)
            d = (double)tok.IntValue;
          else
            vtkErrorMacro(<<"Expected double or int.\n");
324
          vtkArrayDownCast<vtkDoubleArray>(property_table[i].Data)->SetValue(nodeIdMap[id], d);
325
        }
326
        else
327
        {
328
          assert(tok.Type == vtkXGMLReaderToken::TEXT);
329
          vtkArrayDownCast<vtkStringArray>(property_table[i].Data)->SetValue(nodeIdMap[id], tok.StringValue);
330 331
        }
      }
332 333
      vtkXGMLReaderNextToken(fin, tok);
    }
334 335
    assert(tok.Type == vtkXGMLReaderToken::CLOSE_GROUP);
    vtkXGMLReaderNextToken(fin, tok);
336
  }
337

338
  while (tok.Type == vtkXGMLReaderToken::KEYWORD && tok.StringValue == "edge")
339
  {
340 341 342
    // Expect [
    vtkXGMLReaderNextToken(fin, tok);
    assert(tok.Type == vtkXGMLReaderToken::OPEN_GROUP);
343

344 345
    vtkXGMLReaderNextToken(fin, tok);
    while (tok.Type == vtkXGMLReaderToken::KEYWORD)
346
    {
Kyle Lutz's avatar
Kyle Lutz committed
347
      // Assume that all edge groups will list id, source, and dest fields
348 349
      // before any edge property.
      if (tok.StringValue == "id")
350
      {
351 352 353
        vtkXGMLReaderNextToken(fin, tok);
        assert(tok.Type == vtkXGMLReaderToken::INT);
        id = tok.IntValue;
354
      }
355
      else if (tok.StringValue == "source")
356
      {
357 358 359
        vtkXGMLReaderNextToken(fin, tok);
        assert(tok.Type == vtkXGMLReaderToken::INT);
        src = tok.IntValue;
360
      }
361
      else if (tok.StringValue == "target")
362
      {
363 364 365 366 367
        vtkXGMLReaderNextToken(fin, tok);
        assert(tok.Type == vtkXGMLReaderToken::INT);
        dst = tok.IntValue;
        vtkEdgeType e = builder->AddEdge(nodeIdMap[src], nodeIdMap[dst]);
        edgeIdMap[id] = e.Id;
368
      }
369
      else
370
      {
371
        for (i = 0; i < nr_of_properties; i++)
372
        {
373
          if (property_table[i].Kind == vtkXGMLProperty::EDGE_PROP &&
374
              property_table[i].Data->GetName() == tok.StringValue) { break; }
375
        }
376
        if (i == nr_of_properties)
377
        {
378 379
          vtkErrorMacro(<<"Undefined node property ");
          return 0;
380
        }
381 382
        vtkXGMLReaderNextToken(fin, tok);
        if (property_table[i].Data->GetDataType() == VTK_INT)
383
        {
384
          assert(tok.Type == vtkXGMLReaderToken::INT);
385
          vtkArrayDownCast<vtkIntArray>(property_table[i].Data)->SetValue(edgeIdMap[id], tok.IntValue);
386
        }
387
        else if (property_table[i].Data->GetDataType() == VTK_DOUBLE)
388
        {
389 390 391 392 393 394
          if (tok.Type == vtkXGMLReaderToken::DOUBLE)
            d = tok.DoubleValue;
          else if (tok.Type == vtkXGMLReaderToken::INT)
            d = (double)tok.IntValue;
          else
            vtkErrorMacro(<<"Expected double or int.\n");
395
          vtkArrayDownCast<vtkDoubleArray>(property_table[i].Data)->SetValue(nodeIdMap[id], d);
396
        }
397
        else
398
        {
399
          assert(tok.Type == vtkXGMLReaderToken::TEXT);
400
          vtkArrayDownCast<vtkStringArray>(property_table[i].Data)->SetValue(edgeIdMap[id], tok.StringValue);
401 402
        }
      }
403 404
      vtkXGMLReaderNextToken(fin, tok);
    }
405 406
    assert(tok.Type == vtkXGMLReaderToken::CLOSE_GROUP);
    vtkXGMLReaderNextToken(fin, tok);
407
  }
408

409 410
  // Should now recognise the end of graph group ..
  assert(tok.Type == vtkXGMLReaderToken::CLOSE_GROUP);
411

412 413
  // .. followed by end-of-file.
  vtkXGMLReaderNextToken(fin, tok);
414 415
  // do an extra read
  vtkXGMLReaderNextToken(fin, tok);
416
  assert(tok.Type == vtkXGMLReaderToken::END_OF_FILE);
417

418 419
  // Clean up
  fin.close();
420

421
  for (i = 0; i < nr_of_properties; i++)
422
  {
423
    if (property_table[i].Kind == vtkXGMLProperty::NODE_PROP)
424
    {
425 426
      builder->GetVertexData()->AddArray(property_table[i].Data);
      property_table[i].Data->Delete();
427
    }
428
    else
429
    {
430 431 432
      builder->GetEdgeData()->AddArray(property_table[i].Data);
      property_table[i].Data->Delete();
    }
433
  }
434 435 436 437 438 439 440
  vtkFloatArray *weights = vtkFloatArray::New();
  weights->SetName("edge weight");
  weights->SetNumberOfTuples(nr_of_edges);
  edgeIds = vtkIdTypeArray::New();
  edgeIds->SetName("edge id");
  edgeIds->SetNumberOfTuples(nr_of_edges);
  for (i = 0; i < nr_of_edges; i++)
441
  {
442 443
    weights->SetValue(i,1.0);
    edgeIds->SetValue(i,i);
444
  }
445

446 447 448 449
  nodeIds = vtkIdTypeArray::New();
  nodeIds->SetName("vertex id");
  nodeIds->SetNumberOfTuples(nr_of_nodes);
  for (i = 0; i < nr_of_nodes; i++)
450
  {
451
    nodeIds->SetValue(i,i);
452
  }
453 454 455 456 457 458 459 460 461
  builder->GetEdgeData()->AddArray(weights);
  builder->GetEdgeData()->SetPedigreeIds(edgeIds);
  builder->GetVertexData()->SetPedigreeIds(nodeIds);
  weights->Delete();
  nodeIds->Delete();
  edgeIds->Delete();
  // Move structure to output
  vtkGraph* output = vtkGraph::GetData(outputVector);
  if (!output->CheckedShallowCopy(builder))
462
  {
luz.paz's avatar
luz.paz committed
463
    vtkErrorMacro(<<"Invalid graph structure.");
464
    return 0;
465
  }
466

467 468 469 470
  return 1;
}

static int
471
my_getline(std::istream& in, vtkStdString &out, char delimiter)
472 473 474 475
{
  out = vtkStdString();
  unsigned int numCharactersRead = 0;
  int nextValue = 0;
476

477 478
  while ((nextValue = in.get()) != EOF &&
         numCharactersRead < out.max_size())
479
  {
480
    ++numCharactersRead;
481

482 483
    char downcast = static_cast<char>(nextValue);
    if (downcast != delimiter)
484
    {
485
      out += downcast;
486
    }
487
    else
488
    {
489 490
      return numCharactersRead;
    }
491
  }
492

493 494
  return numCharactersRead;
}