Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

517 lines
15 KiB

2 years ago
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkImageMathematics.cxx,v $
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.
=========================================================================*/
#include "vtkImageMathematics.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include <math.h>
vtkCxxRevisionMacro(vtkImageMathematics, "$Revision: 1.53 $");
vtkStandardNewMacro(vtkImageMathematics);
//----------------------------------------------------------------------------
vtkImageMathematics::vtkImageMathematics()
{
this->Operation = VTK_ADD;
this->ConstantK = 1.0;
this->ConstantC = 0.0;
this->DivideByZeroToC = 0;
this->SetNumberOfInputPorts(2);
}
//----------------------------------------------------------------------------
// The output extent is the intersection.
int vtkImageMathematics::RequestInformation (
vtkInformation * vtkNotUsed(request),
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
// get the info objects
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation *inInfo2 = inputVector[1]->GetInformationObject(0);
int ext[6], ext2[6], idx;
inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),ext);
// two input take intersection
if (this->Operation == VTK_ADD || this->Operation == VTK_SUBTRACT ||
this->Operation == VTK_MULTIPLY || this->Operation == VTK_DIVIDE ||
this->Operation == VTK_MIN || this->Operation == VTK_MAX ||
this->Operation == VTK_ATAN2)
{
if (!inInfo2)
{
vtkErrorMacro(<< "Second input must be specified for this operation.");
return 1;
}
inInfo2->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),ext2);
for (idx = 0; idx < 3; ++idx)
{
if (ext2[idx*2] > ext[idx*2])
{
ext[idx*2] = ext2[idx*2];
}
if (ext2[idx*2+1] < ext[idx*2+1])
{
ext[idx*2+1] = ext2[idx*2+1];
}
}
}
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),ext,6);
return 1;
}
template <class TValue, class TIvar>
void vtkImageMathematicsClamp(TValue &value, TIvar ivar, vtkImageData *data)
{
if (ivar < (TIvar) data->GetScalarTypeMin())
{
value = (TValue) data->GetScalarTypeMin();
}
else if (ivar > (TIvar) data->GetScalarTypeMax())
{
value = (TValue) data->GetScalarTypeMax();
}
else
{
value = (TValue) ivar;
}
}
//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
// Handles the one input operations
template <class T>
void vtkImageMathematicsExecute1(vtkImageMathematics *self,
vtkImageData *in1Data, T *in1Ptr,
vtkImageData *outData, T *outPtr,
int outExt[6], int id)
{
int idxR, idxY, idxZ;
int maxY, maxZ;
vtkIdType inIncX, inIncY, inIncZ;
vtkIdType outIncX, outIncY, outIncZ;
int rowLength;
unsigned long count = 0;
unsigned long target;
int op = self->GetOperation();
// find the region to loop over
rowLength = (outExt[1] - outExt[0]+1)*in1Data->GetNumberOfScalarComponents();
// What a pain. Maybe I should just make another filter.
if (op == VTK_CONJUGATE)
{
rowLength = (outExt[1] - outExt[0] + 1);
}
maxY = outExt[3] - outExt[2];
maxZ = outExt[5] - outExt[4];
target = (unsigned long)((maxZ+1)*(maxY+1)/50.0);
target++;
// Get increments to march through data
in1Data->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
int DivideByZeroToC = self->GetDivideByZeroToC();
double doubleConstantk = self->GetConstantK();
// Avoid casts by making constants the same type as input/output
// Of course they must be clamped to a valid range for the scalar type
T constantk; vtkImageMathematicsClamp(constantk, self->GetConstantK(), in1Data);
T constantc; vtkImageMathematicsClamp(constantc, self->GetConstantC(), in1Data);
// Loop through output pixels
for (idxZ = 0; idxZ <= maxZ; idxZ++)
{
for (idxY = 0; idxY <= maxY; idxY++)
{
if (!id)
{
if (!(count%target))
{
self->UpdateProgress(count/(50.0*target));
}
count++;
}
for (idxR = 0; idxR < rowLength; idxR++)
{
// Pixel operaton
switch (op)
{
case VTK_INVERT:
if (*in1Ptr)
{
*outPtr = (T)(1.0 / *in1Ptr);
}
else
{
if ( DivideByZeroToC )
{
*outPtr = constantc;
}
else
{
*outPtr = (T)outData->GetScalarTypeMax();
}
}
break;
case VTK_SIN:
*outPtr = (T)(sin((double)*in1Ptr));
break;
case VTK_COS:
*outPtr = (T)(cos((double)*in1Ptr));
break;
case VTK_EXP:
*outPtr = (T)(exp((double)*in1Ptr));
break;
case VTK_LOG:
*outPtr = (T)(log((double)*in1Ptr));
break;
case VTK_ABS:
*outPtr = (T)(fabs((double)*in1Ptr));
break;
case VTK_SQR:
*outPtr = (T)(*in1Ptr * *in1Ptr);
break;
case VTK_SQRT:
*outPtr = (T)(sqrt((double)*in1Ptr));
break;
case VTK_ATAN:
*outPtr = (T)(atan((double)*in1Ptr));
break;
case VTK_MULTIPLYBYK:
*outPtr = (T)(doubleConstantk * (double) *in1Ptr);
break;
case VTK_ADDC:
*outPtr = constantc + *in1Ptr;
break;
case VTK_REPLACECBYK:
*outPtr = (*in1Ptr == constantc) ? constantk : *in1Ptr;
break;
case VTK_CONJUGATE:
outPtr[0] = in1Ptr[0];
outPtr[1] = (T)(-1.0*(double)(in1Ptr[1]));
// Why bother trying to figure out the continuous increments.
outPtr++;
in1Ptr++;
break;
}
outPtr++;
in1Ptr++;
}
outPtr += outIncY;
in1Ptr += inIncY;
}
outPtr += outIncZ;
in1Ptr += inIncZ;
}
}
//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
// Handles the two input operations
template <class T>
void vtkImageMathematicsExecute2(vtkImageMathematics *self,
vtkImageData *in1Data, T *in1Ptr,
vtkImageData *in2Data, T *in2Ptr,
vtkImageData *outData, T *outPtr,
int outExt[6], int id)
{
int idxR, idxY, idxZ;
int maxY, maxZ;
vtkIdType inIncX, inIncY, inIncZ;
vtkIdType in2IncX, in2IncY, in2IncZ;
vtkIdType outIncX, outIncY, outIncZ;
int rowLength;
unsigned long count = 0;
unsigned long target;
int op = self->GetOperation();
int DivideByZeroToC = self->GetDivideByZeroToC();
double constantc = self->GetConstantC();
// find the region to loop over
rowLength = (outExt[1] - outExt[0]+1)*in1Data->GetNumberOfScalarComponents();
// What a pain. Maybe I should just make another filter.
if (op == VTK_COMPLEX_MULTIPLY)
{
rowLength = (outExt[1] - outExt[0]+1);
}
maxY = outExt[3] - outExt[2];
maxZ = outExt[5] - outExt[4];
target = (unsigned long)((maxZ+1)*(maxY+1)/50.0);
target++;
// Get increments to march through data
in1Data->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
in2Data->GetContinuousIncrements(outExt, in2IncX, in2IncY, in2IncZ);
outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
// Loop through ouput pixels
for (idxZ = 0; idxZ <= maxZ; idxZ++)
{
for (idxY = 0; !self->AbortExecute && idxY <= maxY; idxY++)
{
if (!id)
{
if (!(count%target))
{
self->UpdateProgress(count/(50.0*target));
}
count++;
}
for (idxR = 0; idxR < rowLength; idxR++)
{
// Pixel operation
switch (op)
{
case VTK_ADD:
*outPtr = *in1Ptr + *in2Ptr;
break;
case VTK_SUBTRACT:
*outPtr = *in1Ptr - *in2Ptr;
break;
case VTK_MULTIPLY:
*outPtr = *in1Ptr * *in2Ptr;
break;
case VTK_DIVIDE:
if (*in2Ptr)
{
*outPtr = *in1Ptr / *in2Ptr;
}
else
{
if ( DivideByZeroToC )
{
*outPtr = (T) constantc;
}
else
{
// *outPtr = (T)(*in1Ptr / 0.00001);
*outPtr = (T)outData->GetScalarTypeMax();
}
}
break;
case VTK_MIN:
if (*in1Ptr < *in2Ptr)
{
*outPtr = *in1Ptr;
}
else
{
*outPtr = *in2Ptr;
}
break;
case VTK_MAX:
if (*in1Ptr > *in2Ptr)
{
*outPtr = *in1Ptr;
}
else
{
*outPtr = *in2Ptr;
}
break;
case VTK_ATAN2:
if (*in1Ptr == 0.0 && *in2Ptr == 0.0)
{
*outPtr = 0;
}
else
{
*outPtr = (T)atan2((double)*in1Ptr,(double)*in2Ptr);
}
break;
case VTK_COMPLEX_MULTIPLY:
outPtr[0] = in1Ptr[0] * in2Ptr[0] - in1Ptr[1] * in2Ptr[1];
outPtr[1] = in1Ptr[1] * in2Ptr[0] + in1Ptr[0] * in2Ptr[1];
// Why bother trtying to figure out the continuous increments.
outPtr++;
in1Ptr++;
in2Ptr++;
break;
}
outPtr++;
in1Ptr++;
in2Ptr++;
}
outPtr += outIncY;
in1Ptr += inIncY;
in2Ptr += in2IncY;
}
outPtr += outIncZ;
in1Ptr += inIncZ;
in2Ptr += in2IncZ;
}
}
//----------------------------------------------------------------------------
// This method is passed a input and output datas, and executes the filter
// algorithm to fill the output from the inputs.
// It just executes a switch statement to call the correct function for
// the datas data types.
void vtkImageMathematics::ThreadedRequestData(
vtkInformation * vtkNotUsed( request ),
vtkInformationVector ** vtkNotUsed( inputVector ),
vtkInformationVector * vtkNotUsed( outputVector ),
vtkImageData ***inData,
vtkImageData **outData,
int outExt[6], int id)
{
void *inPtr1;
void *outPtr;
inPtr1 = inData[0][0]->GetScalarPointerForExtent(outExt);
outPtr = outData[0]->GetScalarPointerForExtent(outExt);
if (this->Operation == VTK_ADD || this->Operation == VTK_SUBTRACT ||
this->Operation == VTK_MULTIPLY || this->Operation == VTK_DIVIDE ||
this->Operation == VTK_MIN || this->Operation == VTK_MAX ||
this->Operation == VTK_ATAN2 || this->Operation == VTK_COMPLEX_MULTIPLY)
{
void *inPtr2;
if ( this->Operation == VTK_COMPLEX_MULTIPLY )
{
if (inData[0][0]->GetNumberOfScalarComponents() != 2 ||
inData[1][0]->GetNumberOfScalarComponents() != 2)
{
vtkErrorMacro("Complex inputs must have two components.");
return;
}
}
if (!inData[1] || ! inData[1][0])
{
vtkErrorMacro("ImageMathematics requested to perform a two input operation with only one input\n");
return;
}
inPtr2 = inData[1][0]->GetScalarPointerForExtent(outExt);
// this filter expects that input is the same type as output.
if (inData[0][0]->GetScalarType() != outData[0]->GetScalarType())
{
vtkErrorMacro(<< "Execute: input1 ScalarType, "
<< inData[0][0]->GetScalarType()
<< ", must match output ScalarType "
<< outData[0]->GetScalarType());
return;
}
if (inData[1][0]->GetScalarType() != outData[0]->GetScalarType())
{
vtkErrorMacro(<< "Execute: input2 ScalarType, "
<< inData[1][0]->GetScalarType()
<< ", must match output ScalarType "
<< outData[0]->GetScalarType());
return;
}
// this filter expects that inputs that have the same number of components
if (inData[0][0]->GetNumberOfScalarComponents() !=
inData[1][0]->GetNumberOfScalarComponents())
{
vtkErrorMacro(<< "Execute: input1 NumberOfScalarComponents, "
<< inData[0][0]->GetNumberOfScalarComponents()
<< ", must match out input2 NumberOfScalarComponents "
<< inData[1][0]->GetNumberOfScalarComponents());
return;
}
switch (inData[0][0]->GetScalarType())
{
vtkTemplateMacro(
vtkImageMathematicsExecute2(this,inData[0][0], (VTK_TT *)(inPtr1),
inData[1][0], (VTK_TT *)(inPtr2),
outData[0], (VTK_TT *)(outPtr), outExt, id));
default:
vtkErrorMacro(<< "Execute: Unknown ScalarType");
return;
}
}
else
{
// this filter expects that input is the same type as output.
if (inData[0][0]->GetScalarType() != outData[0]->GetScalarType())
{
vtkErrorMacro(<< "Execute: input ScalarType, " << inData[0][0]->GetScalarType()
<< ", must match out ScalarType " << outData[0]->GetScalarType());
return;
}
if ( this->Operation == VTK_CONJUGATE )
{
if (inData[0][0]->GetNumberOfScalarComponents() != 2)
{
vtkErrorMacro("Complex inputs must have two components.");
return;
}
}
switch (inData[0][0]->GetScalarType())
{
vtkTemplateMacro(
vtkImageMathematicsExecute1(this, inData[0][0], (VTK_TT *)(inPtr1),
outData[0], (VTK_TT *)(outPtr), outExt, id));
default:
vtkErrorMacro(<< "Execute: Unknown ScalarType");
return;
}
}
}
int vtkImageMathematics::FillInputPortInformation(
int port, vtkInformation* info)
{
if (port == 1)
{
info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
}
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
return 1;
}
void vtkImageMathematics::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Operation: " << this->Operation << "\n";
os << indent << "ConstantK: " << this->ConstantK << "\n";
os << indent << "ConstantC: " << this->ConstantC << "\n";
os << indent << "DivideByZeroToC: ";
if ( this->DivideByZeroToC )
{
os << "On\n";
}
else
{
os << "Off\n";
}
}