/*========================================================================= * * 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. * *=========================================================================*/ #define ITK_TEMPLATE_EXPLICIT_TransformFileReader #include "itkTransformFileReader.h" #include "itkTransformIOFactory.h" #include "itkCompositeTransformIOHelper.h" #include "itkKernelTransform.h" #include "itksys/SystemTools.hxx" #ifndef ITK_TRANSFORM_FACTORY_MAX_DIM # define ITK_TRANSFORM_FACTORY_MAX_DIM 9 #endif namespace itk { namespace { // Class to initialize kernel transform for dimension D and lower template struct KernelTransformHelper { static int InitializeWMatrix(const typename TransformBaseTemplate::Pointer & transform) { if (transform->GetInputSpaceDimension() == Dimension) { using KernelTransformType = typename itk::KernelTransform; auto * kernelTransform = static_cast(transform.GetPointer()); kernelTransform->ComputeWMatrix(); return 0; } else { // try one less dimension return KernelTransformHelper::InitializeWMatrix(transform); } } }; // Template specialized class to stop initializing Kernel Transfoms. template struct KernelTransformHelper { static int InitializeWMatrix(const typename TransformBaseTemplate::Pointer & itkNotUsed(transform)) { return 1; } }; } // namespace template TransformFileReaderTemplate::TransformFileReaderTemplate() : m_FileName("") /* to be removed soon. See .h */ {} template TransformFileReaderTemplate::~TransformFileReaderTemplate() = default; template void TransformFileReaderTemplate::Update() { if (m_FileName.empty()) { itkExceptionMacro("No file name given"); } if (m_TransformIO.IsNull()) { using TransformFactoryIOType = TransformIOFactoryTemplate; m_TransformIO = TransformFactoryIOType::CreateTransformIO( m_FileName.c_str(), /*TransformIOFactoryTemplate::*/ IOFileModeEnum::ReadMode); if (m_TransformIO.IsNull()) { std::ostringstream msg; msg << "Could not create Transform IO object for reading file " << this->GetFileName() << std::endl; if (!itksys::SystemTools::FileExists(m_FileName.c_str())) { msg << " File does not exists!"; } std::list allobjects = ObjectFactoryBase::CreateAllInstance("itkTransformIOBaseTemplate"); if (!allobjects.empty()) { msg << " Tried to create one of the following:" << std::endl; for (auto & allobject : allobjects) { const Object * obj = dynamic_cast(allobject.GetPointer()); msg << " " << obj->GetNameOfClass() << std::endl; } msg << " You probably failed to set a file suffix, or" << std::endl << " set the suffix to an unsupported type." << std::endl; } else { msg << " There are no registered Transform IO factories." << std::endl << " Please visit https://www.itk.org/Wiki/ITK/FAQ#NoFactoryException to diagnose the problem." << std::endl; } itkExceptionMacro(<< msg.str().c_str()); } } typename TransformIOType::TransformListType & ioTransformList = m_TransformIO->GetTransformList(); // Clear old results. ioTransformList.clear(); m_TransformIO->SetFileName(m_FileName); m_TransformIO->Read(); if (ioTransformList.empty()) { std::ostringstream msg; msg << "Transform IO: " << m_TransformIO->GetNameOfClass() << std::endl << " failed to read file: " << this->GetFileName() << std::endl; itkExceptionMacro(<< msg.str()); } // Clear old results. this->m_TransformList.clear(); // If the transform is derived from itk::KernelTransform, the internal matrices // need to be initialized using the transform parameters. // kernelTransform->ComputeWMatrix() has to be called after the transform is read but // before the transform is used. std::string transformTypeName = ioTransformList.front()->GetNameOfClass(); const size_t len = strlen("KernelTransform"); // Computed at compile time in most cases if (transformTypeName.size() >= len && !transformTypeName.compare(transformTypeName.size() - len, len, "KernelTransform")) { if (KernelTransformHelper::InitializeWMatrix( ioTransformList.front().GetPointer())) { itkDebugMacro("KernelTransform with dimension " << ioTransformList.front()->GetInputSpaceDimension() << " is not automatically initialized. \"ComputeWMatrix()\"" " method has to be called."); } } // In the case where the first transform in the list is a // CompositeTransform, add all the transforms to that first // transform. and return a single composite item on the // m_TransformList const std::string firstTransformName = ioTransformList.front()->GetNameOfClass(); if (firstTransformName.find("CompositeTransform") != std::string::npos) { typename TransformListType::const_iterator tit = ioTransformList.begin(); typename TransformType::Pointer composite = tit->GetPointer(); // CompositeTransformIOHelperTemplate knows how to assign to the composite // transform's internal list CompositeTransformIOHelperTemplate helper; helper.SetTransformList(composite, ioTransformList); this->m_TransformList.push_back(composite); } else // Just return the entire list of elements { for (auto it = ioTransformList.begin(); it != ioTransformList.end(); ++it) { this->m_TransformList.push_back(it->GetPointer()); } } } template void TransformFileReaderTemplate::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "FileName: " << m_FileName << std::endl; } ITK_GCC_PRAGMA_DIAG_PUSH() ITK_GCC_PRAGMA_DIAG(ignored "-Wattributes") template class ITKIOTransformBase_EXPORT TransformFileReaderTemplate; template class ITKIOTransformBase_EXPORT TransformFileReaderTemplate; ITK_GCC_PRAGMA_DIAG_POP() } // end namespace itk