/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkVTKTetrahedralMeshReader.hxx,v $ Language: C++ Date: $Date: 2011-10-05 18:01:00 $ Version: $Revision: 1.19 $ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or https://www.itk.org/HTML/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 notices for more information. =========================================================================*/ #ifndef itkVTKTetrahedralMeshReader_hxx #define itkVTKTetrahedralMeshReader_hxx #include #include #include namespace itk { // // Constructor // template VTKTetrahedralMeshReader::VTKTetrahedralMeshReader() { // // Create the output // auto output = TOutputMesh::New(); this->ProcessObject::SetNumberOfRequiredOutputs(1); this->ProcessObject::SetNthOutput(0, output.GetPointer()); } // // Destructor // template VTKTetrahedralMeshReader::~VTKTetrahedralMeshReader() = default; template void VTKTetrahedralMeshReader::GenerateData() { OutputMeshType * outputMesh = this->GetOutput(); outputMesh->SetCellsAllocationMethod(MeshEnums::MeshClassCellsAllocationMethod::CellsAllocatedDynamicallyCellByCell); if (m_FileName.empty()) { itkExceptionMacro("No input FileName"); } // // Read input file // std::ifstream inputFile(m_FileName.c_str()); if (!inputFile.is_open()) { itkExceptionMacro("Unable to open file\n" << "inputFilename= " << m_FileName); } inputFile.imbue(std::locale::classic()); std::string line; // The first line must be "# vtk DataFile Version x.x" where x.x can // vary std::getline(inputFile, m_Version, '\n'); if (inputFile.fail()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file trying to read first line."); } if (m_Version.find("# vtk DataFile Version ") == std::string::npos) { itkExceptionMacro( << "Error reading file: " << m_FileName << "\nOnly vtk legacy format files can be read." << "\nThis file does not start with the line: # vtk DataFile Version x.x where x.x is the version."); } // Next is a one line description std::getline(inputFile, m_Header, '\n'); if (inputFile.eof()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file trying to read header."); } // Next is the file format std::getline(inputFile, line, '\n'); if (inputFile.eof()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file trying to file format."); } if (line.find("ASCII") == std::string::npos) { itkExceptionMacro("Error reading file: " << m_FileName << "\nFile format is " << line << " but only ASCII files can be read."); } bool foundPoints = false; while (!inputFile.eof()) { std::getline(inputFile, line, '\n'); if (line.find("POINTS") != std::string::npos) { foundPoints = true; break; } } if (!foundPoints) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file before finding POINTS."); } itkDebugMacro("POINTS line" << line); std::string pointLine(line, strlen("POINTS "), line.length()); itkDebugMacro("pointLine " << pointLine); unsigned long numberOfPoints{}; if (sscanf(pointLine.c_str(), "%lu", &numberOfPoints) != 1) { itkExceptionMacro("Error reading file: " << m_FileName << "\nFailed to read numberOfPoints.\n" << " pointLine= " << pointLine); } itkDebugMacro("numberOfPoints= " << numberOfPoints); if (numberOfPoints < 1) { itkExceptionMacro("Error reading file: " << m_FileName << "numberOfPoints < 1" << " numberOfPoints line= " << numberOfPoints); } PointsContainer * points = outputMesh->GetPoints(); points->Reserve(numberOfPoints); // // Load the point coordinates into the itk::Mesh // PointType point; for (PointIdentifier pointId = 0; pointId < numberOfPoints; ++pointId) { inputFile >> point; if (inputFile.eof()) { itkExceptionMacro("Error while reading file: " << m_FileName << "\nUnexpected end-of-file trying to read points."); } if (inputFile.fail()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nInput could not be interpreted as a point."); } outputMesh->SetPoint(pointId, point); } // Continue searching for the CELLS line bool foundCells = false; while (!inputFile.eof()) { std::getline(inputFile, line, '\n'); if (line.find("CELLS") != std::string::npos) { foundCells = true; break; } } if (!foundCells) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file before finding CELLS."); } itkDebugMacro("CELLS line" << line); std::string cellsLine(line, strlen("CELLS "), line.length()); itkDebugMacro("cellsLine " << cellsLine); // // Read the number of cells // unsigned long numberOfCells{}; unsigned long numberOfIndices{}; if (sscanf(cellsLine.c_str(), "%lu %lu", &numberOfCells, &numberOfIndices) != 2) { itkExceptionMacro("Error reading file: " << m_FileName << "\nFailed to read numberOfCells from subline2" << "\ncellsLine = " << cellsLine); } itkDebugMacro("numberOfCells " << numberOfCells); itkDebugMacro("numberOfIndices " << numberOfIndices); if (numberOfCells < 1) { itkExceptionMacro("Error reading file: " << m_FileName << "\nnumberOfCells < 1\nnumberOfCells= " << numberOfCells); } if (numberOfIndices < numberOfCells) { itkExceptionMacro("Error reading file: " << m_FileName << "\nnumberOfIndices < numberOfCells\n" << "numberOfIndices= " << numberOfIndices << '\n' << "numberOfCells= " << numberOfCells); } // // Load the cells into the itk::Mesh // unsigned long numberOfCellPoints; long ids[4]; for (CellIdentifier cellId = 0; cellId < numberOfCells; ++cellId) { std::getline(inputFile, line, '\n'); if (inputFile.eof()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nFailed to read " << numberOfCells << " cells before the end of file." << " Only read " << cellId + 1); } if (line.find("DATA") != std::string::npos) { itkExceptionMacro("Error reading file: " << m_FileName << "\nRead keyword DATA"); } unsigned long numberOfPointsFound; if ((numberOfPointsFound = sscanf(line.c_str(), "%lu %ld %ld %ld %ld", &numberOfCellPoints, &ids[0], &ids[1], &ids[2], &ids[3])) != 5) { itkExceptionMacro("Error reading file: " << m_FileName << "\nError parsing Tetrahedron CELLS . Expected 5 items but got " << numberOfPointsFound << std::endl << "Line is: " << line); } if (numberOfCellPoints != 4) { itkExceptionMacro("Error reading file: " << m_FileName << "\nnumberOfCellPoints != 4\n" << "numberOfCellPoints= " << numberOfCellPoints << "\ncellId = " << cellId << ". VTKTetrahedralMeshReader can only read tetrahedra"); } if (ids[0] < 0 || ids[1] < 0 || ids[2] < 0 || ids[3] < 0) { itkExceptionMacro("Error reading file: " << m_FileName << "point ids must be >= 0.\n" "ids=" << ids[0] << ' ' << ids[1] << ' ' << ids[2] << ' ' << ids[3]); } if (static_cast(ids[0]) >= numberOfPoints || static_cast(ids[1]) >= numberOfPoints || static_cast(ids[2]) >= numberOfPoints || static_cast(ids[3]) >= numberOfPoints) { itkExceptionMacro("Error reading file: " << m_FileName << "Point ids must be < number of points: " << numberOfPoints << "\nids= " << ids[0] << ' ' << ids[1] << ' ' << ids[2] << ' ' << ids[3]); } CellAutoPointer cell; auto * tetrahedronCell = new TetrahedronCellType; for (PointIdentifier pointId = 0; pointId < 4; ++pointId) { tetrahedronCell->SetPointId(pointId, ids[pointId]); } cell.TakeOwnership(tetrahedronCell); outputMesh->SetCell(cellId, cell); } // Continue searching for the CELL_TYPES line bool bfoundCellTypes = false; while (!inputFile.eof()) { std::getline(inputFile, line, '\n'); if (line.find("CELL_TYPES") != std::string::npos) { bfoundCellTypes = true; break; } } if (!bfoundCellTypes) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file before finding CELL_TYPES."); } itkDebugMacro("CELL_TYPES line" << line); std::string cellsTypesLine(line, strlen("CELL_TYPES "), line.length()); itkDebugMacro("cellsTypesLine " << cellsTypesLine); unsigned int numberOfCellTypes = 0; if (sscanf(cellsTypesLine.c_str(), "%u", &numberOfCellTypes) != 1) { itkExceptionMacro("Error reading file: " << m_FileName << "\nFailed to read numberOfCellTypes from subline2" << "\ncellsTypesLine = " << cellsTypesLine); } if (static_cast(numberOfCellTypes) != numberOfCells) { itkExceptionMacro("Error reading file: " << m_FileName << "\nnumberOfCellTypes < numberOfCells "); } for (CellIdentifier cellId = 0; cellId < numberOfCellTypes; ++cellId) { std::getline(inputFile, line, '\n'); if (inputFile.eof()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nFailed to read " << numberOfCellTypes << " cells before the end of file." << " Only read " << cellId + 1); } int cellTypeID = 0; int cellTypeFound; if ((cellTypeFound = sscanf(line.c_str(), "%d ", &cellTypeID)) != 1) { itkExceptionMacro("Error reading file: " << m_FileName << "\nError parsing Cells types. Expected 1 item but got " << cellTypeFound << std::endl << "Line is: " << line); } constexpr int tetrahedralCellTypeID = 10; if (cellTypeID != tetrahedralCellTypeID) { itkExceptionMacro("Error reading file: " << m_FileName << "\nCell type != 10\n" << "Cell type = " << cellTypeID << ". VTKTetrahedralMeshReader can only read tetrahedra"); } } bool foundPointData = false; while (!inputFile.eof()) { std::getline(inputFile, line, '\n'); if (line.find("POINT_DATA") != std::string::npos) { foundPointData = true; break; } } if (foundPointData) { using PointDataContainer = typename OutputMeshType::PointDataContainer; using PointDataContainerPointer = typename PointDataContainer::Pointer; PointDataContainerPointer pointDataContainer = PointDataContainer::New(); pointDataContainer->Reserve(numberOfPoints); outputMesh->SetPointData(pointDataContainer); itkDebugMacro("POINT_DATA line" << line); // Skip two lines for (int j = 0; j < 2; ++j) { if (!inputFile.eof()) { std::getline(inputFile, line, '\n'); } else { inputFile.close(); return; } } double pointData; for (PointIdentifier pid = 0; pid < numberOfPoints; ++pid) { if (inputFile.eof()) { itkExceptionMacro("Error reading file: " << m_FileName << "\nUnexpected end-of-file while trying to read POINT_DATA." << "Failed while trying to reading point data for id: " << pid); } inputFile >> pointData; outputMesh->SetPointData(pid, pointData); } } inputFile.close(); } template void VTKTetrahedralMeshReader::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "FileName: " << m_FileName << std::endl; os << indent << "Version: " << m_Version << std::endl; os << indent << "Header: " << m_Header << std::endl; } } // end of namespace itk #endif