/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkVTKImageImport_hxx #define itkVTKImageImport_hxx #include "itkPixelTraits.h" #include "itkNumericTraits.h" #include "itkNumericTraitsArrayPixel.h" #include "itkNumericTraitsCovariantVectorPixel.h" #include "itkNumericTraitsDiffusionTensor3DPixel.h" #include "itkNumericTraitsFixedArrayPixel.h" #include "itkNumericTraitsPointPixel.h" #include "itkNumericTraitsRGBPixel.h" #include "itkNumericTraitsRGBAPixel.h" #include "itkNumericTraitsTensorPixel.h" #include "itkNumericTraitsVectorPixel.h" namespace itk { template VTKImageImport::VTKImageImport() { using PixelType = typename TOutputImage::PixelType; using ScalarType = typename PixelTraits::ValueType; if (typeid(ScalarType) == typeid(double)) { m_ScalarTypeName = "double"; } else if (typeid(ScalarType) == typeid(float)) { m_ScalarTypeName = "float"; } else if (typeid(ScalarType) == typeid(long long)) { m_ScalarTypeName = "long long"; } else if (typeid(ScalarType) == typeid(unsigned long long)) { m_ScalarTypeName = "unsigned long long"; } else if (typeid(ScalarType) == typeid(long)) { m_ScalarTypeName = "long"; } else if (typeid(ScalarType) == typeid(unsigned long)) { m_ScalarTypeName = "unsigned long"; } else if (typeid(ScalarType) == typeid(int)) { m_ScalarTypeName = "int"; } else if (typeid(ScalarType) == typeid(unsigned int)) { m_ScalarTypeName = "unsigned int"; } else if (typeid(ScalarType) == typeid(short)) { m_ScalarTypeName = "short"; } else if (typeid(ScalarType) == typeid(unsigned short)) { m_ScalarTypeName = "unsigned short"; } else if (typeid(ScalarType) == typeid(char)) { m_ScalarTypeName = "char"; } else if (typeid(ScalarType) == typeid(signed char)) { m_ScalarTypeName = "signed char"; } else if (typeid(ScalarType) == typeid(unsigned char)) { m_ScalarTypeName = "unsigned char"; } else { itkExceptionMacro("Type currently not supported"); } } /** * */ template void VTKImageImport::PropagateRequestedRegion(DataObject * outputPtr) { auto * output = dynamic_cast(outputPtr); if (!output) { itkExceptionMacro("Downcast from DataObject to my Image type failed."); } Superclass::PropagateRequestedRegion(output); if (m_PropagateUpdateExtentCallback) { OutputRegionType region = output->GetRequestedRegion(); OutputSizeType size = region.GetSize(); OutputIndexType index = region.GetIndex(); int updateExtent[6]; unsigned int i = 0; for (; i < OutputImageDimension; ++i) { updateExtent[i * 2] = static_cast(index[i]); updateExtent[i * 2 + 1] = static_cast(index[i] + size[i]) - 1; } for (; i < 3; ++i) { updateExtent[i * 2] = 0; updateExtent[i * 2 + 1] = 0; } (m_PropagateUpdateExtentCallback)(m_CallbackUserData, updateExtent); } } template void VTKImageImport::UpdateOutputInformation() { // If set, use the callbacks to propagate pipeline update information. if (m_UpdateInformationCallback) { (m_UpdateInformationCallback)(m_CallbackUserData); } if (m_PipelineModifiedCallback) { if ((m_PipelineModifiedCallback)(m_CallbackUserData)) { this->Modified(); } } Superclass::UpdateOutputInformation(); } /** * */ template void VTKImageImport::GenerateOutputInformation() { // call the superclass' implementation of this method Superclass::GenerateOutputInformation(); // get pointer to the output OutputImagePointer output = this->GetOutput(); if (m_WholeExtentCallback) { int * extent = (m_WholeExtentCallback)(m_CallbackUserData); OutputIndexType index; OutputSizeType size; for (unsigned int i = 0; i < OutputImageDimension; ++i) { index[i] = extent[i * 2]; size[i] = (extent[i * 2 + 1] - extent[i * 2]) + 1; } const OutputRegionType region(index, size); output->SetLargestPossibleRegion(region); } if (m_SpacingCallback) { double * inSpacing = (m_SpacingCallback)(m_CallbackUserData); typename TOutputImage::SpacingType outSpacing; for (unsigned int i = 0; i < OutputImageDimension; ++i) { outSpacing[i] = inSpacing[i]; } output->SetSpacing(outSpacing); } else if (m_FloatSpacingCallback) { float * inSpacing = (m_FloatSpacingCallback)(m_CallbackUserData); typename TOutputImage::SpacingType outSpacing; for (unsigned int i = 0; i < OutputImageDimension; ++i) { outSpacing[i] = inSpacing[i]; } output->SetSpacing(outSpacing); } if (m_OriginCallback) { double * inOrigin = (m_OriginCallback)(m_CallbackUserData); typename TOutputImage::PointType outOrigin; for (unsigned int i = 0; i < OutputImageDimension; ++i) { outOrigin[i] = inOrigin[i]; } output->SetOrigin(outOrigin); } else if (m_FloatOriginCallback) { float * inOrigin = (m_FloatOriginCallback)(m_CallbackUserData); typename TOutputImage::PointType outOrigin; for (unsigned int i = 0; i < OutputImageDimension; ++i) { outOrigin[i] = inOrigin[i]; } output->SetOrigin(outOrigin); } if (m_DirectionCallback) { double * inDirection = (m_DirectionCallback)(m_CallbackUserData); typename TOutputImage::DirectionType outDirection; for (unsigned int i = 0; i < 3; ++i) { for (unsigned int j = 0; j < 3; ++j) { if (i < OutputImageDimension && j < OutputImageDimension) { outDirection[i][j] = inDirection[i * 3 + j]; } else if ((i != j) && (inDirection[i * 3 + j] != 0.0)) { std::string ijk = "IJK"; std::string xyz = "XYZ"; itkExceptionMacro("Cannot convert a VTK image to an ITK image of dimension " << OutputImageDimension << " since the VTK image direction matrix element at (" << i << ',' << j << ") is not equal to 0.0:\n" << " I J K\n" << "X " << inDirection[0] << ", " << inDirection[1] << ", " << inDirection[2] << '\n' << "Y " << inDirection[3] << ", " << inDirection[4] << ", " << inDirection[5] << '\n' << "Z " << inDirection[6] << ", " << inDirection[7] << ", " << inDirection[8] << '\n' << "This means that the " << ijk[j] << " data axis has a " << xyz[i] << " component in physical space, but the ITK image can only represent values" << " along " << ijk.substr(0, OutputImageDimension) << " projected on " << xyz.substr(0, OutputImageDimension) << '.' << std::endl); } } } output->SetDirection(outDirection); } if (m_NumberOfComponentsCallback) { const unsigned int components = (m_NumberOfComponentsCallback)(m_CallbackUserData); using PixelType = typename TOutputImage::PixelType; const unsigned int estimatedNumberOfComponents = NumericTraits::GetLength(); if (components != estimatedNumberOfComponents) { itkExceptionMacro("Input number of components is " << components << " but should be " << estimatedNumberOfComponents); } } if (m_ScalarTypeCallback) { const char * scalarName = (m_ScalarTypeCallback)(m_CallbackUserData); if (scalarName != m_ScalarTypeName) { itkExceptionMacro("Input scalar type is " << scalarName << " but should be " << m_ScalarTypeName.c_str()); } } } /** * */ template void VTKImageImport::GenerateData() { // Normally, GenerateData() allocates memory. However, the application // provides the memory for this filter via the SetImportPointer() method. // Therefore, this filter does not call outputPtr->Allocate(). if (m_UpdateDataCallback) { (m_UpdateDataCallback)(m_CallbackUserData); } if (m_DataExtentCallback && m_BufferPointerCallback) { // get pointer to the output OutputImagePointer output = this->GetOutput(); int * extent = (m_DataExtentCallback)(m_CallbackUserData); OutputIndexType index; OutputSizeType size; SizeValueType importSize = 1; for (unsigned int i = 0; i < OutputImageDimension; ++i) { index[i] = extent[i * 2]; size[i] = (extent[i * 2 + 1] - extent[i * 2]) + 1; importSize *= size[i]; } const OutputRegionType region(index, size); output->SetBufferedRegion(region); void * data = (m_BufferPointerCallback)(m_CallbackUserData); auto * importPointer = reinterpret_cast(data); // pass the pointer down to the output container during each // Update() since a call to Initialize() causes the container to // forget the pointer. Note that we tell the container NOT to // manage memory itself. We leave the responsibility of // deallocating the pixel data to VTK. output->GetPixelContainer()->SetImportPointer(importPointer, importSize, false); } } template void VTKImageImport::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); if (m_DataExtentCallback) { os << indent << "DataExtentCallback: " << m_DataExtentCallback << std::endl; } if (m_WholeExtentCallback) { os << indent << "WholeExtentCallback: " << m_WholeExtentCallback << std::endl; } if (m_BufferPointerCallback) { os << indent << "BufferPointerCallback: " << m_BufferPointerCallback << std::endl; } if (m_UpdateDataCallback) { os << indent << "UpdateDataCallback: " << m_UpdateDataCallback << std::endl; } if (m_PipelineModifiedCallback) { os << indent << "PipelineModifiedCallback: " << m_PipelineModifiedCallback << std::endl; } if (m_NumberOfComponentsCallback) { os << indent << "NumberOfComponentsCallback: " << m_NumberOfComponentsCallback << std::endl; } if (m_SpacingCallback) { os << indent << "SpacingCallback: " << m_SpacingCallback << std::endl; } if (m_FloatSpacingCallback) { os << indent << "FloatSpacingCallback: " << m_FloatSpacingCallback << std::endl; } if (m_OriginCallback) { os << indent << "OriginCallback: " << m_OriginCallback << std::endl; } if (m_FloatOriginCallback) { os << indent << "FloatOriginCallback: " << m_FloatOriginCallback << std::endl; } if (m_DirectionCallback) { os << indent << "DirectionCallback: " << m_DirectionCallback << std::endl; } if (m_UpdateInformationCallback) { os << indent << "UpdateInformationCallback: " << m_UpdateInformationCallback << std::endl; } if (m_ScalarTypeCallback) { os << indent << "ScalarTypeCallback: " << m_ScalarTypeCallback << std::endl; } if (m_PropagateUpdateExtentCallback) { os << indent << "PropagateUpdateExtentCallback: " << m_PropagateUpdateExtentCallback << std::endl; } if (m_CallbackUserData) { os << indent << "CallbackUserData: " << m_CallbackUserData << std::endl; } } } // namespace itk #endif