vtkMNITagPointWriter.cxx 13.7 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMNITagPointWriter.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 (c) 2006 Atamai, Inc.

Use, modification and redistribution of the software, in source or
binary forms, are permitted provided that the following terms and
conditions are met:

1) Redistribution of the source code, in verbatim or modified
   form, must retain the above copyright notice, this license,
   the following disclaimer, and any notices that refer to this
   license and/or the following disclaimer.

2) Redistribution in binary form must include the above copyright
   notice, a copy of this license and the following disclaimer
   in the documentation or with other materials provided with the
   distribution.

3) Modified copies of the source code must be clearly marked as such,
   and must not be misrepresented as verbatim copies of the source code.

THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

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

#include "vtkMNITagPointWriter.h"

#include "vtkObjectFactory.h"

53
#include "vtkInformationVector.h"
54 55 56 57 58 59 60 61 62 63 64
#include "vtkInformation.h"
#include "vtkPointSet.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkStringArray.h"
#include "vtkDoubleArray.h"
#include "vtkIntArray.h"
#include "vtkMath.h"
#include "vtkErrorCode.h"
#include "vtkCommand.h"

Sean McBride's avatar
Sean McBride committed
65 66
#include <cctype>
#include <cmath>
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

#if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h> /* unlink */
#else
# include <io.h> /* unlink */
#endif

//--------------------------------------------------------------------------
vtkStandardNewMacro(vtkMNITagPointWriter);

vtkCxxSetObjectMacro(vtkMNITagPointWriter, LabelText, vtkStringArray);
vtkCxxSetObjectMacro(vtkMNITagPointWriter, Weights, vtkDoubleArray);
vtkCxxSetObjectMacro(vtkMNITagPointWriter, StructureIds, vtkIntArray);
vtkCxxSetObjectMacro(vtkMNITagPointWriter, PatientIds, vtkIntArray);

//-------------------------------------------------------------------------
vtkMNITagPointWriter::vtkMNITagPointWriter()
{
85 86
  this->Points[0] = nullptr;
  this->Points[1] = nullptr;
87

88 89 90 91
  this->LabelText = nullptr;
  this->Weights = nullptr;
  this->StructureIds = nullptr;
  this->PatientIds = nullptr;
92

93
  this->Comments = nullptr;
94 95 96

  this->SetNumberOfInputPorts(2);
  this->SetNumberOfOutputPorts(0);
97

98
  this->FileName = nullptr;
99 100 101 102 103 104 105 106 107 108 109 110 111 112
}

//-------------------------------------------------------------------------
vtkMNITagPointWriter::~vtkMNITagPointWriter()
{
  vtkObject *objects[6];
  objects[0] = this->Points[0];
  objects[1] = this->Points[1];
  objects[2] = this->LabelText;
  objects[3] = this->Weights;
  objects[4] = this->StructureIds;
  objects[5] = this->PatientIds;

  for (int i = 0; i < 6; i++)
113
  {
114
    if (objects[i])
115
    {
116 117
      objects[i]->Delete();
    }
118
  }
119

120
  delete [] this->Comments;
121 122

  delete[] this->FileName;
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
}

//-------------------------------------------------------------------------
void vtkMNITagPointWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Points: " << this->Points[0] << " "
     << this->Points[1] << "\n";
  os << indent << "LabelText: " << this->LabelText << "\n";
  os << indent << "Weights: " << this->Weights << "\n";
  os << indent << "StructureIds: " << this->StructureIds << "\n";
  os << indent << "PatientIds: " << this->PatientIds << "\n";

  os << indent << "Comments: "
     << (this->Comments ? this->Comments : "none") << "\n";
}

//----------------------------------------------------------------------------
int vtkMNITagPointWriter::FillInputPortInformation(
  int, vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPointSet");
  info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
  return 1;
}

//-------------------------------------------------------------------------
Bill Lorensen's avatar
Bill Lorensen committed
151
vtkMTimeType vtkMNITagPointWriter::GetMTime()
152
{
Bill Lorensen's avatar
Bill Lorensen committed
153
  vtkMTimeType mtime = this->Superclass::GetMTime();
154 155 156 157 158 159 160 161 162 163

  vtkObject *objects[6];
  objects[0] = this->Points[0];
  objects[1] = this->Points[1];
  objects[2] = this->LabelText;
  objects[3] = this->Weights;
  objects[4] = this->StructureIds;
  objects[5] = this->PatientIds;

  for (int i = 0; i < 6; i++)
164
  {
165
    if (objects[i])
166
    {
Bill Lorensen's avatar
Bill Lorensen committed
167
      vtkMTimeType m = objects[i]->GetMTime();
168
      if (m > mtime)
169
      {
170 171 172
        mtime = m;
      }
    }
173
  }
174 175 176 177 178 179 180 181

  return mtime;
}

//-------------------------------------------------------------------------
void vtkMNITagPointWriter::SetPoints(int port, vtkPoints *points)
{
  if (port < 0 || port > 1)
182
  {
183
    return;
184
  }
185
  if (this->Points[port] == points)
186
  {
187
    return;
188
  }
189
  if (this->Points[port])
190
  {
191
    this->Points[port]->Delete();
192
  }
193 194
  this->Points[port] = points;
  if (this->Points[port])
195
  {
196
    this->Points[port]->Register(this);
197
  }
198 199 200 201 202 203 204
  this->Modified();
}

//-------------------------------------------------------------------------
vtkPoints *vtkMNITagPointWriter::GetPoints(int port)
{
  if (port < 0 || port > 1)
205
  {
206
    return nullptr;
207
  }
208 209 210 211
  return this->Points[port];
}

//-------------------------------------------------------------------------
212
void vtkMNITagPointWriter::WriteData(vtkPointSet *inputs[2])
213 214 215 216 217 218 219 220 221
{
  static const char *arrayNames[3] = {
    "Weights",
    "StructureIds",
    "PatientIds"
  };

  vtkPoints *points[2];

222
  vtkStringArray *labels = nullptr;
223
  vtkDataArray *darray[3];
224 225 226
  darray[0] = nullptr;
  darray[1] = nullptr;
  darray[2] = nullptr;
227 228 229 230 231 232 233

  vtkDataArray *ivarArrays[3];
  ivarArrays[0] = this->Weights;
  ivarArrays[1] = this->StructureIds;
  ivarArrays[2] = this->PatientIds;

  for (int ii = 1; ii >= 0; --ii)
234
  {
235
    points[ii] = nullptr;
236
    if (inputs[ii])
237
    {
238 239
      points[ii] = inputs[ii]->GetPoints();

240
      vtkStringArray *stringArray = vtkArrayDownCast<vtkStringArray>(
241 242
        inputs[ii]->GetPointData()->GetAbstractArray("LabelText"));
      if (stringArray)
243
      {
244
        labels = stringArray;
245
      }
246 247

      for (int j = 0; j < 3; j++)
248
      {
249 250 251
        vtkDataArray *dataArray =
          inputs[ii]->GetPointData()->GetArray(arrayNames[j]);
        if (dataArray)
252
        {
253 254 255
          darray[j] = dataArray;
        }
      }
256
    }
257 258

    if (this->Points[ii])
259
    {
260 261
      points[ii] = this->Points[ii];
    }
262
  }
263 264

  if (this->LabelText)
265
  {
266
    labels = this->LabelText;
267
  }
268 269

  for (int j = 0; j < 3; j++)
270
  {
271
    if (ivarArrays[j])
272
    {
273 274
      darray[j] = ivarArrays[j];
    }
275
  }
276

277
  if (points[0] == nullptr)
278
  {
279 280
    vtkErrorMacro("No input points have been provided");
    return;
281
  }
282 283 284 285 286

  // numVolumes is 1 if there is only one set of points
  int numVolumes = 1;
  vtkIdType n = points[0]->GetNumberOfPoints();
  if (points[1])
287
  {
288 289
    numVolumes = 2;
    if (points[1]->GetNumberOfPoints() != n)
290
    {
291 292 293 294
      vtkErrorMacro("Input point counts do not match: " << n << " versus "
                    << points[1]->GetNumberOfPoints());
      return;
    }
295
  }
296 297 298

  // labels is null if there are no labels
  if (labels && labels->GetNumberOfValues() != n)
299
  {
300 301 302
    vtkErrorMacro("LabelText count does not match point count: "
                  << labels->GetNumberOfValues() << " versus " << n);
    return;
303
  }
304 305

  // dataArrays is null if there are no data arrays
306
  vtkDataArray **dataArrays = nullptr;
307
  for (int jj = 0; jj < 3; jj++)
308
  {
309
    if (darray[jj])
310
    {
311 312
      dataArrays = darray;
      if (darray[jj]->GetNumberOfTuples() != n)
313
      {
314 315 316 317 318 319
        vtkErrorMacro("" << arrayNames[jj]
                      << " count does not match point count: "
                      << darray[jj]->GetNumberOfTuples() << " versus " << n);
        return;
      }
    }
320
  }
321 322

  // If we got this far, the data seems to be okay
323
  ostream *outfilep = this->OpenFile();
324
  if (!outfilep)
325
  {
326
    return;
327
  }
328 329 330 331 332 333 334 335 336

  ostream &outfile = *outfilep;

  // Write the header
  outfile << "MNI Tag Point File\n";
  outfile << "Volumes = " << numVolumes << ";\n";

  // Write user comments
  if (this->Comments)
337
  {
338 339
    char *cp = this->Comments;
    while (*cp)
340
    {
341
      if (*cp != '%')
342
      {
343
        outfile << "% ";
344
      }
345
      while (*cp && *cp != '\n')
346
      {
347
        if (isprint(*cp) || *cp == '\t')
348
        {
349 350
          outfile << *cp;
        }
351 352
        cp++;
      }
353 354
      outfile << "\n";
      if (*cp == '\n')
355
      {
356 357 358
        cp++;
      }
    }
359
  }
360
  else
361
  {
362
    for (int k = 0; k < numVolumes; k++)
363
    {
364 365
      outfile << "% Volume " << (k + 1) << " produced by VTK\n";
    }
366
  }
367 368 369 370 371 372 373 374 375

  // Add a blank line
  outfile << "\n";

  // Write the points
  outfile << "Points =\n";

  char text[256];
  for (int i = 0; i < n; i++)
376
  {
377
    for (int kk = 0; kk < 2; kk++)
378
    {
379
      if (points[kk])
380
      {
381 382
        double point[3];
        points[kk]->GetPoint(i, point);
383
        snprintf(text, sizeof(text), " %.15g %.15g %.15g", point[0], point[1], point[2]);
384 385
        outfile << text;
      }
386
    }
387 388

    if (dataArrays)
389
    {
390 391 392 393
      double w = 0.0;
      int s = -1;
      int p = -1;
      if (dataArrays[0])
394
      {
395
        w = dataArrays[0]->GetComponent(i, 0);
396
      }
397
      if (dataArrays[1])
398
      {
399
        s = static_cast<int>(dataArrays[1]->GetComponent(i, 0));
400
      }
401
      if (dataArrays[2])
402
      {
403
        p = static_cast<int>(dataArrays[2]->GetComponent(i, 0));
404
      }
405

406
      snprintf(text, sizeof(text), " %.15g %d %d", w, s, p);
407
      outfile << text;
408
    }
409 410

    if (labels)
411
    {
412 413
      vtkStdString l = labels->GetValue(i);
      outfile << " \"";
414
      for (std::string::iterator si = l.begin(); si != l.end(); ++si)
415
      {
416
        if (isprint(*si) && *si != '\"' && *si != '\\')
417
        {
418
          outfile.put(*si);
419
        }
420
        else
421
        {
422 423 424 425 426 427 428
          outfile.put('\\');
          char c = '\0';
          static char ctrltable[] = {
            '\a', 'a', '\b', 'b', '\f', 'f', '\n', 'n', '\r', 'r',
            '\t', 't', '\v', 'v', '\\', '\\', '\"', '\"', '\0', '\0'
            };
          for (int ci = 0; ctrltable[ci] != '\0'; ci += 2)
429
          {
430
            if (*si == ctrltable[ci])
431
            {
432 433 434
              c = ctrltable[ci + 1];
              break;
            }
435
          }
436
          if (c != '\0')
437
          {
438
            outfile.put(c);
439
          }
440
          else
441
          {
442
            snprintf(text, sizeof(text), "x%2.2x", (static_cast<int>(*si) & 0x00ff));
443 444 445
            outfile << text;
          }
        }
446
      }
447 448

      outfile << "\"";
449
    }
450 451

    if (i < n-1)
452
    {
453 454
      outfile << "\n";
    }
455
  }
456 457 458 459 460

  outfile << ";\n";
  outfile.flush();

  // Close the file
461
  this->CloseFile(outfilep);
462 463 464

  // Delete the file if an error occurred
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
465
  {
466 467 468
    vtkErrorMacro("Ran out of disk space; deleting file: "
                  << this->FileName);
    unlink(this->FileName);
469
  }
470 471 472 473 474 475 476 477 478 479 480 481 482
}

//-------------------------------------------------------------------------
int vtkMNITagPointWriter::Write()
{
  // Allow writer to work when no inputs are provided
  this->Modified();
  this->Update();
  return 1;
}

//-------------------------------------------------------------------------
int vtkMNITagPointWriter::RequestData(
483
  vtkInformation *, vtkInformationVector **inputVector,
484 485 486 487
  vtkInformationVector *)
{
  this->SetErrorCode(vtkErrorCode::NoError);

488 489 490
  vtkInformation *inInfo[2];
  inInfo[0] = inputVector[0]->GetInformationObject(0);
  inInfo[1] = inputVector[1]->GetInformationObject(0);
491

492
  vtkPointSet *input[2];
493 494
  input[0] = nullptr;
  input[1] = nullptr;
495

Bill Lorensen's avatar
Bill Lorensen committed
496
  vtkMTimeType lastUpdateTime = 0;
497
  for (int idx = 0; idx < 2; ++idx)
498
  {
499
    if (inInfo[idx])
500
    {
501 502 503
      input[idx] = vtkPointSet::SafeDownCast(
        inInfo[idx]->Get(vtkDataObject::DATA_OBJECT()));
      if (input[idx])
504
      {
Bill Lorensen's avatar
Bill Lorensen committed
505
        vtkMTimeType updateTime = input[idx]->GetUpdateTime();
506
        if (updateTime > lastUpdateTime)
507
        {
508
          lastUpdateTime = updateTime;
509 510 511
        }
      }
    }
512
  }
513 514

  if (lastUpdateTime < this->WriteTime && this->GetMTime() < this->WriteTime)
515
  {
516 517
    // we are up to date
    return 1;
518
  }
519

520
  this->InvokeEvent(vtkCommand::StartEvent, nullptr);
521
  this->WriteData(input);
522
  this->InvokeEvent(vtkCommand::EndEvent, nullptr);
523 524 525 526 527

  this->WriteTime.Modified();

  return 1;
}
528 529 530 531 532 533 534

//-------------------------------------------------------------------------
ostream *vtkMNITagPointWriter::OpenFile()
{
  ostream *fptr;

  if (!this->FileName )
535
  {
536 537
    vtkErrorMacro(<< "No FileName specified! Can't write!");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
538
    return nullptr;
539
  }
540 541 542 543 544 545

  vtkDebugMacro(<<"Opening file for writing...");

  fptr = new ofstream(this->FileName, ios::out);

  if (fptr->fail())
546
  {
547 548 549
    vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    delete fptr;
550
    return nullptr;
551
  }
552 553 554 555 556 557 558 559 560

  return fptr;
}

//-------------------------------------------------------------------------
void vtkMNITagPointWriter::CloseFile(ostream *fp)
{
  vtkDebugMacro(<<"Closing file\n");

561
  delete fp;
562
}