diff --git a/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h b/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h index adef22d2e2a9..a2781e000a75 100644 --- a/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h +++ b/Modules/IO/MeshVTK/include/itkVTKPolyDataMeshIO.h @@ -275,6 +275,20 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase itkExceptionStringMacro("UnExpected end of line while trying to read LOOKUP_TABLE"); } } + /** For FIELD entries the next line is the array header + * (` `); consume it + * before reading the component values. */ + else if (line.find("FIELD") != std::string::npos) + { + if (!inputFile.eof()) + { + std::getline(inputFile, line, '\n'); + } + else + { + itkExceptionStringMacro("UnExpected end of line while trying to read FIELD array header"); + } + } /** for VECTORS or NORMALS or TENSORS, we could read them directly */ Self::ReadComponentsAsASCII( @@ -319,6 +333,20 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase itkExceptionStringMacro("UnExpected end of line while trying to read LOOKUP_TABLE"); } } + /** For FIELD entries the next line is the array header + * (` `); consume it + * before reading the binary block. */ + else if (line.find("FIELD") != std::string::npos) + { + if (!inputFile.eof()) + { + std::getline(inputFile, line, '\n'); + } + else + { + itkExceptionStringMacro("UnExpected end of line while trying to read FIELD array header"); + } + } /** for VECTORS or NORMALS or TENSORS, we could read them directly */ const SizeValueType numberOfComponents = this->m_NumberOfPointPixels * this->m_NumberOfPointPixelComponents; @@ -367,6 +395,18 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase itkExceptionStringMacro("UnExpected end of line while trying to read LOOKUP_TABLE"); } } + /** For FIELD entries the next line is the array header; consume it. */ + else if (line.find("FIELD") != std::string::npos) + { + if (!inputFile.eof()) + { + std::getline(inputFile, line, '\n'); + } + else + { + itkExceptionStringMacro("UnExpected end of line while trying to read FIELD array header"); + } + } /** for VECTORS or NORMALS or TENSORS, we could read them directly */ Self::ReadComponentsAsASCII( @@ -411,6 +451,18 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase itkExceptionStringMacro("UnExpected end of line while trying to read LOOKUP_TABLE"); } } + /** For FIELD entries the next line is the array header; consume it. */ + else if (line.find("FIELD") != std::string::npos) + { + if (!inputFile.eof()) + { + std::getline(inputFile, line, '\n'); + } + else + { + itkExceptionStringMacro("UnExpected end of line while trying to read FIELD array header"); + } + } /** For VECTORS or NORMALS or TENSORS, we could read them directly */ const SizeValueType numberOfComponents = this->m_NumberOfCellPixels * this->m_NumberOfCellPixelComponents; @@ -929,13 +981,15 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase while (i < num) { // row 1 - outputFile << *ptr++ << indent; + outputFile << ConvertNumberToString(*ptr++) << indent; e12 = *ptr++; - outputFile << e12 << indent << zero << '\n'; + outputFile << ConvertNumberToString(e12) << indent << ConvertNumberToString(zero) << '\n'; // row 2 - outputFile << e12 << indent << *ptr++ << indent << zero << '\n'; + outputFile << ConvertNumberToString(e12) << indent << ConvertNumberToString(*ptr++) << indent + << ConvertNumberToString(zero) << '\n'; // row 3 - outputFile << zero << indent << zero << indent << zero << "\n\n"; + outputFile << ConvertNumberToString(zero) << indent << ConvertNumberToString(zero) << indent + << ConvertNumberToString(zero) << "\n\n"; i += 3; } } @@ -947,17 +1001,18 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase while (i < num) { // row 1 - outputFile << *ptr++ << indent; + outputFile << ConvertNumberToString(*ptr++) << indent; e12 = *ptr++; - outputFile << e12 << indent; + outputFile << ConvertNumberToString(e12) << indent; e13 = *ptr++; - outputFile << e13 << '\n'; + outputFile << ConvertNumberToString(e13) << '\n'; // row 2 - outputFile << e12 << indent << *ptr++ << indent; + outputFile << ConvertNumberToString(e12) << indent << ConvertNumberToString(*ptr++) << indent; e23 = *ptr++; - outputFile << e23 << '\n'; + outputFile << ConvertNumberToString(e23) << '\n'; // row 3 - outputFile << e13 << indent << e23 << indent << *ptr++ << "\n\n"; + outputFile << ConvertNumberToString(e13) << indent << ConvertNumberToString(e23) << indent + << ConvertNumberToString(*ptr++) << "\n\n"; i += 6; } } @@ -977,9 +1032,9 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase unsigned int jj = 0; for (; jj < this->m_NumberOfCellPixelComponents - 1; ++jj) { - outputFile << buffer[ii * this->m_NumberOfCellPixelComponents + jj] << indent; + outputFile << ConvertNumberToString(buffer[ii * this->m_NumberOfCellPixelComponents + jj]) << indent; } - outputFile << buffer[ii * this->m_NumberOfCellPixelComponents + jj] << '\n'; + outputFile << ConvertNumberToString(buffer[ii * this->m_NumberOfCellPixelComponents + jj]) << '\n'; } } } @@ -1059,7 +1114,7 @@ class ITKIOMeshVTK_EXPORT VTKPolyDataMeshIO : public MeshIOBase { for (unsigned int jj = 0; jj < numberOfPixelComponents; ++jj) { - outputFile << ConvertNumberToString(static_cast(buffer[ii * numberOfPixelComponents + jj])) << indent; + outputFile << ConvertNumberToString(buffer[ii * numberOfPixelComponents + jj]) << indent; } outputFile << '\n'; diff --git a/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx b/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx index 7e1b94a1af80..4a26cddff1be 100644 --- a/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx +++ b/Modules/IO/MeshVTK/src/itkVTKPolyDataMeshIO.cxx @@ -651,6 +651,50 @@ VTKPolyDataMeshIO::ReadMeshInformation() this->m_NumberOfPointPixelComponents = this->m_PointDimension * (this->m_PointDimension + 1) / 2; this->m_UpdatePointData = true; } + if (line.find("FIELD") != std::string::npos) + { + StringStreamType sss; + sss << line; + + sss >> item; // should be "FIELD" + if (item == "FIELD") + { + sss >> item; // field data name (e.g. "FieldData") + sss >> item; // number of field data arrays + const std::int32_t numArrays = StringToInt32(item, "VTK FIELD numArrays (POINT_DATA)"); + if (numArrays >= 1) + { + // Read the first field data array header. + // Additional arrays are silently skipped. + std::getline(inputFile, line, '\n'); + + StringStreamType fieldStream; + fieldStream << line; + fieldStream >> item; // array name + + fieldStream >> item; // numComponents + const std::uint32_t numComponents = StringToUInt32(item, "VTK FIELD numComponents (POINT_DATA)"); + + fieldStream >> item; // numTuples + const std::uint32_t numTuples = StringToUInt32(item, "VTK FIELD numTuples (POINT_DATA)"); + + fieldStream >> item; // data type + const IOComponentEnum componentType = this->GetComponentTypeFromString(item); + + if (this->m_NumberOfPoints == numTuples) + { + this->m_NumberOfPointPixelComponents = numComponents; + this->m_PointPixelType = IOPixelEnum::VARIABLELENGTHVECTOR; + this->m_PointPixelComponentType = componentType; + if (this->m_PointPixelComponentType == IOComponentEnum::UNKNOWNCOMPONENTTYPE) + { + itkExceptionMacro("Unknown point pixel component type"); + } + this->m_UpdatePointData = true; + } + } + } + } } else if (line.find("CELL_DATA") != std::string::npos) { @@ -784,6 +828,50 @@ VTKPolyDataMeshIO::ReadMeshInformation() this->m_NumberOfCellPixelComponents = this->m_PointDimension * (this->m_PointDimension + 1) / 2; this->m_UpdateCellData = true; } + if (line.find("FIELD") != std::string::npos) + { + StringStreamType sss; + sss << line; + + sss >> item; // should be "FIELD" + if (item == "FIELD") + { + sss >> item; // field data name (e.g. "FieldData") + sss >> item; // number of field data arrays + const std::int32_t numArrays = StringToInt32(item, "VTK FIELD numArrays (CELL_DATA)"); + if (numArrays >= 1) + { + // Read the first field data array header. + // Additional arrays are silently skipped. + std::getline(inputFile, line, '\n'); + + StringStreamType fieldStream; + fieldStream << line; + fieldStream >> item; // array name + + fieldStream >> item; // numComponents + const std::uint32_t numComponents = StringToUInt32(item, "VTK FIELD numComponents (CELL_DATA)"); + + fieldStream >> item; // numTuples + const std::uint32_t numTuples = StringToUInt32(item, "VTK FIELD numTuples (CELL_DATA)"); + + fieldStream >> item; // data type + const IOComponentEnum componentType = this->GetComponentTypeFromString(item); + + if (this->m_NumberOfCells == numTuples) + { + this->m_NumberOfCellPixelComponents = numComponents; + this->m_CellPixelType = IOPixelEnum::VARIABLELENGTHVECTOR; + this->m_CellPixelComponentType = componentType; + if (this->m_CellPixelComponentType == IOComponentEnum::UNKNOWNCOMPONENTTYPE) + { + itkExceptionMacro("Unknown cell pixel component type"); + } + this->m_UpdateCellData = true; + } + } + } + } } else if (line.find("OFFSETS") != std::string::npos) { diff --git a/Modules/IO/MeshVTK/test/CMakeLists.txt b/Modules/IO/MeshVTK/test/CMakeLists.txt index 9ff3647c0d6e..ff078e4fa0af 100644 --- a/Modules/IO/MeshVTK/test/CMakeLists.txt +++ b/Modules/IO/MeshVTK/test/CMakeLists.txt @@ -178,6 +178,14 @@ itk_add_test( 1 1 ) +itk_add_test( + NAME itkMeshFileReadWriteTestField + COMMAND + ITKIOMeshVTKTestDriver + itkMeshFileReadWriteTest + DATA{Input/gourd.vtk} + ${ITK_TEST_OUTPUT_DIR}/gourd.vtk +) set(ITKIOMeshVTKGTests itkVTKPolyDataMeshIOGTest.cxx) diff --git a/Modules/IO/MeshVTK/test/Input/gourd.vtk.cid b/Modules/IO/MeshVTK/test/Input/gourd.vtk.cid new file mode 100644 index 000000000000..fb4ea5395517 --- /dev/null +++ b/Modules/IO/MeshVTK/test/Input/gourd.vtk.cid @@ -0,0 +1 @@ +bafkreidv66i2s5mleluikmvcpq32yziqt7qo3tvc5imncrx4auoimwtdua