mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
1020 lines
26 KiB
C++
1020 lines
26 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkMNITransformReader.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 "vtkMNITransformReader.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
|
|
#include "vtkImageData.h"
|
|
#include "vtkMINCImageReader.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
#include "vtkCollection.h"
|
|
#include "vtkTransform.h"
|
|
#include "vtkGeneralTransform.h"
|
|
#include "vtkThinPlateSplineTransform.h"
|
|
#include "vtkGridTransform.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkPoints.h"
|
|
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <vtksys/SystemTools.hxx>
|
|
|
|
//--------------------------------------------------------------------------
|
|
vtkStandardNewMacro(vtkMNITransformReader);
|
|
|
|
//-------------------------------------------------------------------------
|
|
vtkMNITransformReader::vtkMNITransformReader()
|
|
{
|
|
this->FileName = 0;
|
|
this->Transform = 0;
|
|
this->Transforms = vtkCollection::New();
|
|
this->LineNumber = 0;
|
|
this->Comments = 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
vtkMNITransformReader::~vtkMNITransformReader()
|
|
{
|
|
if (this->Transforms)
|
|
{
|
|
this->Transforms->Delete();
|
|
}
|
|
if (this->Transform)
|
|
{
|
|
this->Transform->Delete();
|
|
}
|
|
delete [] this->FileName;
|
|
delete [] this->Comments;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void vtkMNITransformReader::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "FileName: "
|
|
<< (this->FileName ? this->FileName : "none") << "\n";
|
|
os << indent << "Transform: " << this->Transform << "\n";
|
|
if (this->Transform)
|
|
{
|
|
this->Transform->PrintSelf(os, indent.GetNextIndent());
|
|
}
|
|
os << indent << "NumberOfTransforms: "
|
|
<< this->Transforms->GetNumberOfItems() << "\n";
|
|
os << indent << "Comments: "
|
|
<< (this->Comments ? this->Comments : "none") << "\n";
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::CanReadFile(const char* fname)
|
|
{
|
|
// First make sure the file exists. This prevents an empty file
|
|
// from being created on older compilers.
|
|
struct stat fs;
|
|
if(stat(fname, &fs) != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Try to read the first line of the file.
|
|
int status = 0;
|
|
|
|
ifstream infile(fname);
|
|
|
|
if (infile.good())
|
|
{
|
|
status = 1;
|
|
char linetext[256];
|
|
infile.getline(linetext, 256);
|
|
if (strncmp(linetext, "MNI Transform File", 18) != 0)
|
|
{
|
|
status = 0;
|
|
}
|
|
|
|
infile.close();
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Internal function to read in a line up to 256 characters and then
|
|
// skip to the next line in the file.
|
|
int vtkMNITransformReader::ReadLine(
|
|
istream &infile, char result[256])
|
|
{
|
|
this->LineNumber++;
|
|
|
|
infile.getline(result,256);
|
|
if (infile.fail())
|
|
{
|
|
if (infile.eof())
|
|
{
|
|
return 0;
|
|
}
|
|
if (infile.gcount() == 255)
|
|
{
|
|
// Read 256 chars; ignoring the rest of the line.
|
|
infile.clear();
|
|
infile.ignore(VTK_INT_MAX, '\n');
|
|
vtkWarningMacro("Overlength line (limit is 255) in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Skip all blank lines or comment lines and return the first useful line
|
|
int vtkMNITransformReader::ReadLineAfterComments(
|
|
istream &infile, char result[256])
|
|
{
|
|
// Skip over any comment lines or blank lines.
|
|
// Comment lines start with '%'
|
|
std::string comments;
|
|
do
|
|
{
|
|
this->ReadLine(infile, result);
|
|
const char *cp = result;
|
|
while (*cp && isspace(*cp))
|
|
{
|
|
cp++;
|
|
}
|
|
if (result[0] == '%')
|
|
{
|
|
if (comments.length() > 0)
|
|
{
|
|
comments.append("\n");
|
|
}
|
|
comments.append(result);
|
|
}
|
|
else if (*cp != '\0')
|
|
{
|
|
delete [] this->Comments;
|
|
this->Comments = new char[comments.length() + 1];
|
|
strcpy(this->Comments, comments.c_str());
|
|
return 1;
|
|
}
|
|
}
|
|
while (infile.good());
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Skip all whitespace, reading additional lines if necessary
|
|
int vtkMNITransformReader::SkipWhitespace(
|
|
istream &infile, char linetext[256], char **cpp)
|
|
{
|
|
char *cp = *cpp;
|
|
|
|
while (infile.good())
|
|
{
|
|
// Skip leading whitespace
|
|
while (isspace(*cp))
|
|
{
|
|
cp++;
|
|
}
|
|
|
|
if (*cp != '\0')
|
|
{
|
|
*cpp = cp;
|
|
return 1;
|
|
}
|
|
|
|
this->ReadLine(infile, linetext);
|
|
cp = linetext;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Read the left hand side of a statement, including the equals sign
|
|
// and any whitespace following the equals.
|
|
int vtkMNITransformReader::ParseLeftHandSide(
|
|
istream &infile, char linetext[256], char **cpp, char identifier[256])
|
|
{
|
|
int i = 0;
|
|
char *cp = *cpp;
|
|
|
|
// Read alphanumeric plus underscore
|
|
if (!isdigit(*cp))
|
|
{
|
|
while ((isalnum(*cp) || *cp == '_') && i < 255)
|
|
{
|
|
identifier[i++] = *cp++;
|
|
}
|
|
}
|
|
identifier[i] = '\0';
|
|
|
|
// Skip trailing whitespace
|
|
while (isspace(*cp))
|
|
{
|
|
cp++;
|
|
}
|
|
|
|
// Check for equals
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
if (*cp != '=')
|
|
{
|
|
vtkErrorMacro("Missing \'=\' " << this->FileName
|
|
<< ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
cp++;
|
|
|
|
// Skip ahead to the value part of the statement
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
|
|
*cpp = cp;
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Read a string value. The terminating semicolon will be read, but
|
|
// won't be included in the output string. Neither will any
|
|
// whitespace occurring before the semicolon. The string may not be
|
|
// split across multiple lines.
|
|
int vtkMNITransformReader::ParseStringValue(
|
|
istream &infile, char linetext[256], char **cpp, char data[256])
|
|
{
|
|
int i = 0;
|
|
char *cp = *cpp;
|
|
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
|
|
// Read until end of the line or semicolon
|
|
while (*cp && *cp != ';' && i < 255)
|
|
{
|
|
data[i++] = *cp++;
|
|
}
|
|
|
|
// Remove trailing whitespace
|
|
while (i > 0 && isspace(data[i-1]))
|
|
{
|
|
i--;
|
|
}
|
|
|
|
data[i] = '\0';
|
|
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
if (*cp != ';')
|
|
{
|
|
vtkErrorMacro("Missing semicolon " << this->FileName
|
|
<< ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
cp++;
|
|
|
|
*cpp = cp;
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Read floating-point values into a vtkDoubleArray until a semicolon
|
|
// is reached. The semicolon is also read.
|
|
int vtkMNITransformReader::ParseFloatValues(
|
|
istream &infile, char linetext[256], char **cpp, vtkDoubleArray *array)
|
|
{
|
|
char *cp = *cpp;
|
|
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
while (infile.good() && *cp != ';')
|
|
{
|
|
char *tmp = cp;
|
|
double val = strtod(cp, &cp);
|
|
if (cp == tmp)
|
|
{
|
|
vtkErrorMacro("Syntax error " << this->FileName
|
|
<< ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
array->InsertNextValue(val);
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
}
|
|
|
|
if (*cp != ';')
|
|
{
|
|
vtkErrorMacro("Missing semicolon " << this->FileName
|
|
<< ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
cp++;
|
|
|
|
*cpp = cp;
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ParseInvertFlagValue(
|
|
istream &infile, char linetext[256], char **cpp, int *invertFlag)
|
|
{
|
|
char data[256];
|
|
|
|
if (!this->ParseStringValue(infile, linetext, cpp, data))
|
|
{
|
|
return 0;
|
|
}
|
|
if (strcmp(data, "False") == 0)
|
|
{
|
|
*invertFlag = 0;
|
|
}
|
|
else if (strcmp(data, "True") == 0)
|
|
{
|
|
*invertFlag = 1;
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro("Invert_Flag must be \'True\' or \'False\' "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ReadLinearTransform(
|
|
istream &infile, char linetext[256], char **cpp)
|
|
{
|
|
// Read the first variable
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
char identifier[256];
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Check for Invert_Flag
|
|
int invertFlag = 0;
|
|
if (strcmp(identifier, "Invert_Flag") == 0)
|
|
{
|
|
if (!this->ParseInvertFlagValue(infile, linetext, cpp, &invertFlag))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Check for Linear_Transform
|
|
if (strcmp(identifier, "Linear_Transform") != 0)
|
|
{
|
|
vtkErrorMacro("Expected \'Linear_Transform\' in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
// Read twelve array elements from the file
|
|
vtkDoubleArray *array = vtkDoubleArray::New();
|
|
if (!this->ParseFloatValues(infile, linetext, cpp, array))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (array->GetNumberOfTuples() != 12)
|
|
{
|
|
vtkErrorMacro("Linear transform must have exactly 12 elements "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
array->Delete();
|
|
return 0;
|
|
}
|
|
|
|
// Fill in the last row of the 4x4 matrix
|
|
array->InsertNextValue(0.0);
|
|
array->InsertNextValue(0.0);
|
|
array->InsertNextValue(0.0);
|
|
array->InsertNextValue(1.0);
|
|
|
|
// Create the transform
|
|
vtkTransform *transform = vtkTransform::New();
|
|
transform->Concatenate(array->GetPointer(0));
|
|
array->Delete();
|
|
if (invertFlag)
|
|
{
|
|
transform->Inverse();
|
|
}
|
|
|
|
this->Transforms->AddItem(transform);
|
|
transform->Delete();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ReadThinPlateSplineTransform(
|
|
istream &infile, char linetext[256], char **cpp)
|
|
{
|
|
// Read the first variable
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
char identifier[256];
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Check for Invert_Flag
|
|
int invertFlag = 0;
|
|
if (strcmp(identifier, "Invert_Flag") == 0)
|
|
{
|
|
if (!this->ParseInvertFlagValue(infile, linetext, cpp, &invertFlag))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Number_Dimensions: vtkThinPlateSplineTransform supports 2 and 3
|
|
if (strcmp(identifier, "Number_Dimensions") != 0)
|
|
{
|
|
vtkErrorMacro("Expected \'Number_Dimensions\' in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
char data[256];
|
|
if (!this->ParseStringValue(infile, linetext, cpp, data))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int numDimensions = data[0] - '0';
|
|
if (data[1] != '\0' || numDimensions < 2 || numDimensions > 3)
|
|
{
|
|
vtkErrorMacro("Number_Dimensions must be 2 or 3 in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
// Read the points
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(identifier, "Points") != 0)
|
|
{
|
|
vtkErrorMacro("Expected \'Points\' in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
vtkDoubleArray *points = vtkDoubleArray::New();
|
|
if (!this->ParseFloatValues(infile, linetext, cpp, points))
|
|
{
|
|
points->Delete();
|
|
return 0;
|
|
}
|
|
|
|
if (points->GetNumberOfTuples() % numDimensions != 0)
|
|
{
|
|
points->Delete();
|
|
vtkErrorMacro("Points list not divisible by Number_Dimensions in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
// Read the displacements
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
points->Delete();
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(identifier, "Displacements") != 0)
|
|
{
|
|
points->Delete();
|
|
vtkErrorMacro("Expected \'Displacements\' in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
vtkDoubleArray *displacements = vtkDoubleArray::New();
|
|
if (!this->ParseFloatValues(infile, linetext, cpp, displacements))
|
|
{
|
|
displacements->Delete();
|
|
points->Delete();
|
|
return 0;
|
|
}
|
|
|
|
if (displacements->GetNumberOfTuples() !=
|
|
points->GetNumberOfTuples() + numDimensions*(numDimensions + 1))
|
|
{
|
|
displacements->Delete();
|
|
points->Delete();
|
|
vtkErrorMacro("Incorrect nubmer of Displacements in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
// The vtkThinPlateSplineTransform expects two sets of points,
|
|
// not a set of points and a set of displacements. We need
|
|
// to perform a thin-plate spline transform to get the points
|
|
// that we need.
|
|
|
|
int numPoints = points->GetNumberOfTuples()/numDimensions;
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
// Convert points and displacements to 3D
|
|
double (*q)[3] = new double[numPoints][3];
|
|
double (*W)[3] = new double[numPoints][3];
|
|
for (i = 0; i < numPoints; i++)
|
|
{
|
|
double *point = q[i];
|
|
double *displacement = W[i];
|
|
point[0] = point[1] = point[2] = 0.0;
|
|
displacement[0] = displacement[1] = displacement[2] = 0.0;
|
|
for (j = 0; j < numDimensions; j++)
|
|
{
|
|
point[j] = points->GetValue(i*numDimensions + j);
|
|
displacement[j] = displacements->GetValue(i*numDimensions + j);
|
|
}
|
|
}
|
|
|
|
// Get the translation from the TPS matrix
|
|
double C[3];
|
|
C[0] = C[1] = C[2] = 0.0;
|
|
for (j = 0; j < numDimensions; j++)
|
|
{
|
|
C[j] = displacements->GetValue(numPoints*numDimensions + j);
|
|
}
|
|
|
|
// Get the square matrix portion of the TPS matrix
|
|
double A[3][3];
|
|
A[0][1] = A[0][2] = A[1][0] = A[1][2] = A[2][0] = A[2][1] = 0.0;
|
|
A[0][0] = A[1][1] = A[2][2] = 1.0;
|
|
for (i = 0; i < numDimensions; i++)
|
|
{
|
|
for (j = 0; j < numDimensions; j++)
|
|
{
|
|
A[i][j] = displacements->GetValue(
|
|
(numPoints + 1 + i)*numDimensions + j);
|
|
}
|
|
}
|
|
|
|
displacements->Delete();
|
|
points->Delete();
|
|
|
|
// Create the source and target point lists
|
|
vtkPoints *source = vtkPoints::New();
|
|
vtkPoints *target = vtkPoints::New();
|
|
for (i = 0; i < numPoints; i++)
|
|
{
|
|
double *p = q[i];
|
|
double x = 0.0;
|
|
double y = 0.0;
|
|
double z = 0.0;
|
|
|
|
for (j = 0; j < numPoints; j++)
|
|
{
|
|
double dx = p[0] - q[j][0];
|
|
double dy = p[1] - q[j][1];
|
|
double dz = p[2] - q[j][2];
|
|
double r = sqrt(dx*dx + dy*dy + dz*dz);
|
|
double U = ((numDimensions == 2 && r != 0) ? r*r*log(r) : r);
|
|
x += U*W[j][0];
|
|
y += U*W[j][1];
|
|
z += U*W[j][2];
|
|
}
|
|
|
|
x += C[0] + p[0]*A[0][0] + p[1]*A[1][0] + p[2]*A[2][0];
|
|
y += C[1] + p[0]*A[0][1] + p[1]*A[1][1] + p[2]*A[2][1];
|
|
z += C[2] + p[0]*A[0][2] + p[1]*A[1][2] + p[2]*A[2][2];
|
|
|
|
source->InsertNextPoint(p);
|
|
target->InsertNextPoint(x, y, z);
|
|
}
|
|
|
|
delete [] q;
|
|
delete [] W;
|
|
|
|
// Create the thin plate spline transform
|
|
vtkThinPlateSplineTransform *transform = vtkThinPlateSplineTransform::New();
|
|
transform->SetSourceLandmarks(source);
|
|
transform->SetTargetLandmarks(target);
|
|
if (numDimensions == 2)
|
|
{
|
|
transform->SetBasisToR2LogR();
|
|
}
|
|
else
|
|
{
|
|
transform->SetBasisToR();
|
|
}
|
|
|
|
if (invertFlag)
|
|
{
|
|
transform->Inverse();
|
|
}
|
|
|
|
source->Delete();
|
|
target->Delete();
|
|
|
|
this->Transforms->AddItem(transform);
|
|
transform->Delete();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ReadGridTransform(
|
|
istream &infile, char linetext[256], char **cpp)
|
|
{
|
|
// Read the first variable
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
char identifier[256];
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Check for Invert_Flag
|
|
int invertFlag = 0;
|
|
if (strcmp(identifier, "Invert_Flag") == 0)
|
|
{
|
|
if (!this->ParseInvertFlagValue(infile, linetext, cpp, &invertFlag))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
this->SkipWhitespace(infile, linetext, cpp);
|
|
if (!this->ParseLeftHandSide(infile, linetext, cpp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Displacement_Volume must be a minc file
|
|
if (strcmp(identifier, "Displacement_Volume") != 0)
|
|
{
|
|
vtkErrorMacro("Expected \'Displacement_Volume\' in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
char filename[VTK_MAXPATH];
|
|
if (!this->ParseStringValue(infile, linetext, cpp, filename))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Create the minc reader
|
|
vtkMINCImageReader *reader = vtkMINCImageReader::New();
|
|
|
|
std::vector<std::string> xfmpath;
|
|
std::vector<std::string> mincpath;
|
|
|
|
vtksys::SystemTools::SplitPath(this->FileName, xfmpath);
|
|
vtksys::SystemTools::SplitPath(filename, mincpath);
|
|
|
|
// Join minc filename to this->FileName if filename is relative
|
|
if (mincpath[0] == "")
|
|
{
|
|
xfmpath.pop_back();
|
|
xfmpath.insert(xfmpath.end(), mincpath.begin()+1, mincpath.end());
|
|
reader->SetFileName(vtksys::SystemTools::JoinPath(xfmpath).c_str());
|
|
}
|
|
else
|
|
{
|
|
reader->SetFileName(filename);
|
|
}
|
|
|
|
// Read the minc file now, rather than later
|
|
reader->Update();
|
|
|
|
// Create the transform
|
|
vtkGridTransform *transform = vtkGridTransform::New();
|
|
transform->SetDisplacementGridConnection(reader->GetOutputPort());
|
|
transform->SetDisplacementShift(reader->GetRescaleIntercept());
|
|
transform->SetDisplacementScale(reader->GetRescaleSlope());
|
|
transform->SetInverseTolerance(0.05);
|
|
transform->SetInterpolationModeToCubic();
|
|
|
|
if (invertFlag)
|
|
{
|
|
transform->Inverse();
|
|
}
|
|
|
|
reader->Delete();
|
|
|
|
this->Transforms->AddItem(transform);
|
|
transform->Delete();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ReadNextTransform(istream &infile, char linetext[256])
|
|
{
|
|
// Check for errors
|
|
if (infile.eof())
|
|
{
|
|
return 1;
|
|
}
|
|
else if (infile.fail())
|
|
{
|
|
vtkErrorMacro("IO error while reading " << this->FileName);
|
|
return 0;
|
|
}
|
|
|
|
// Parse the file
|
|
char *cp = linetext;
|
|
|
|
// Check for Transform_Type
|
|
char identifier[256];
|
|
this->SkipWhitespace(infile, linetext, &cp);
|
|
if (!this->ParseLeftHandSide(infile, linetext, &cp, identifier))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(identifier, "Transform_Type") != 0)
|
|
{
|
|
vtkErrorMacro("Expected Transform_Type in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
// Read the transform type
|
|
char transformType[256];
|
|
if (!this->ParseStringValue(infile, linetext, &cp, transformType))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Check the transform type
|
|
if (strcmp(transformType, "Linear") == 0)
|
|
{
|
|
return this->ReadLinearTransform(infile, linetext, &cp);
|
|
}
|
|
else if (strcmp(transformType, "Thin_Plate_Spline_Transform") == 0)
|
|
{
|
|
return this->ReadThinPlateSplineTransform(infile, linetext, &cp);
|
|
}
|
|
else if (strcmp(transformType, "Grid_Transform") == 0)
|
|
{
|
|
return this->ReadGridTransform(infile, linetext, &cp);
|
|
}
|
|
|
|
vtkErrorMacro("Unrecognized type " << transformType << " in "
|
|
<< this->FileName << ":" << this->LineNumber);
|
|
return 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ReadFile()
|
|
{
|
|
this->Transforms->RemoveAllItems();
|
|
this->SetTransform(0);
|
|
|
|
// Check that the file name has been set.
|
|
if (!this->FileName)
|
|
{
|
|
vtkErrorMacro("ReadFile: No file name has been set");
|
|
return 0;
|
|
}
|
|
|
|
// Make sure that the file exists.
|
|
struct stat fs;
|
|
if(stat(this->FileName, &fs) != 0)
|
|
{
|
|
vtkErrorMacro("ReadFile: Can't open file " << this->FileName);
|
|
return 0;
|
|
}
|
|
|
|
// Make sure that the file is readable.
|
|
ifstream infile(this->FileName);
|
|
|
|
if (infile.fail())
|
|
{
|
|
vtkErrorMacro("ReadFile: Can't read the file " << this->FileName);
|
|
return 0;
|
|
}
|
|
|
|
// Read the first line
|
|
char linetext[256];
|
|
this->LineNumber = 0;
|
|
this->ReadLine(infile, linetext);
|
|
if (strncmp(linetext, "MNI Transform File", 18) != 0)
|
|
{
|
|
vtkErrorMacro("ReadFile: File is not a MNI xfm file: " << this->FileName);
|
|
infile.close();
|
|
return 0;
|
|
}
|
|
|
|
// Read the comments
|
|
this->ReadLineAfterComments(infile, linetext);
|
|
|
|
// Read the transforms
|
|
while (infile.good())
|
|
{
|
|
if (this->ReadNextTransform(infile, linetext) == 0)
|
|
{
|
|
this->Transforms->RemoveAllItems();
|
|
infile.close();
|
|
return 0;
|
|
}
|
|
this->ReadLine(infile, linetext);
|
|
}
|
|
|
|
// Close the file
|
|
infile.close();
|
|
|
|
// Create the output transform.
|
|
int n = this->Transforms->GetNumberOfItems();
|
|
if (n == 1)
|
|
{
|
|
this->SetTransform(
|
|
(vtkAbstractTransform *)this->Transforms->GetItemAsObject(0));
|
|
}
|
|
else
|
|
{
|
|
// Determine whether the full transform is linear
|
|
int linear = 1;
|
|
int i = 0;
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
if (!this->Transforms->GetItemAsObject(i)->IsA("vtkLinearTransform"))
|
|
{
|
|
linear = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If linear, use vtkTransform to concatenate,
|
|
// else use vtkGeneralTransform.
|
|
if (linear)
|
|
{
|
|
vtkTransform *transform = vtkTransform::New();
|
|
transform->PostMultiply();
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
vtkLinearTransform *linearTransform =
|
|
(vtkLinearTransform *)this->Transforms->GetItemAsObject(i);
|
|
transform->Concatenate(linearTransform->GetMatrix());
|
|
}
|
|
this->SetTransform(transform);
|
|
transform->Delete();
|
|
}
|
|
else
|
|
{
|
|
vtkGeneralTransform *transform = vtkGeneralTransform::New();
|
|
transform->PostMultiply();
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
vtkAbstractTransform *abstractTransform =
|
|
(vtkAbstractTransform *)this->Transforms->GetItemAsObject(i);
|
|
if (abstractTransform->IsA("vtkLinearTransform"))
|
|
{
|
|
transform->Concatenate(
|
|
((vtkLinearTransform *)abstractTransform)->GetMatrix());
|
|
}
|
|
else
|
|
{
|
|
transform->Concatenate(abstractTransform);
|
|
}
|
|
}
|
|
this->SetTransform(transform);
|
|
transform->Delete();
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::ProcessRequest(vtkInformation *request,
|
|
vtkInformationVector **inputVector,
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
|
|
{
|
|
return this->ReadFile();
|
|
}
|
|
|
|
return this->Superclass::ProcessRequest(request, inputVector, outputVector);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void vtkMNITransformReader::SetTransform(vtkAbstractTransform *transform)
|
|
{
|
|
if (this->Transform != transform)
|
|
{
|
|
if (this->Transform)
|
|
{
|
|
this->Transform->Delete();
|
|
}
|
|
if (transform)
|
|
{
|
|
transform->Register(this);
|
|
}
|
|
this->Transform = transform;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
vtkAbstractTransform *vtkMNITransformReader::GetTransform()
|
|
{
|
|
this->Update();
|
|
|
|
return this->Transform;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
int vtkMNITransformReader::GetNumberOfTransforms()
|
|
{
|
|
this->Update();
|
|
|
|
return this->Transforms->GetNumberOfItems();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
vtkAbstractTransform *vtkMNITransformReader::GetNthTransform(int i)
|
|
{
|
|
this->Update();
|
|
|
|
if (i < 0 || i >= this->Transforms->GetNumberOfItems())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return (vtkAbstractTransform *)this->Transforms->GetItemAsObject(i);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
const char *vtkMNITransformReader::GetComments()
|
|
{
|
|
this->Update();
|
|
|
|
return this->Comments;
|
|
}
|