/*========================================================================= * * 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. * *=========================================================================*/ #include "itkBYUMeshIO.h" #include "itksys/SystemTools.hxx" namespace itk { BYUMeshIO::BYUMeshIO() : m_PartId(NumericTraits::max()) , m_FirstCellId(NumericTraits::OneValue()) , m_LastCellId(NumericTraits::max()) { this->AddSupportedWriteExtension(".byu"); } BYUMeshIO::~BYUMeshIO() = default; bool BYUMeshIO::CanReadFile(const char * fileName) { if (!itksys::SystemTools::FileExists(fileName, true)) { return false; } if (itksys::SystemTools::GetFilenameLastExtension(fileName) != ".byu") { return false; } return true; } bool BYUMeshIO::CanWriteFile(const char * fileName) { if (itksys::SystemTools::GetFilenameLastExtension(fileName) != ".byu") { return false; } return true; } void BYUMeshIO::ReadMeshInformation() { // Define input file stream and attach it to input file std::ifstream inputFile; // Due to the windows couldn't work well for tellg() and seekg() for ASCII mode, hence we // open the file with std::ios::binary inputFile.open(this->m_FileName.c_str(), std::ios::in | std::ios::binary); if (!inputFile.is_open()) { itkExceptionMacro("Unable to open input file " << this->m_FileName); } // Read the ASCII file information unsigned int numberOfParts = 0; unsigned int numberOfConnectivityEntries = 0; // Read the number of points and number of cells inputFile >> numberOfParts; inputFile >> this->m_NumberOfPoints; inputFile >> this->m_NumberOfCells; inputFile >> numberOfConnectivityEntries; // Determine which part to read, default is to read all parts if (m_PartId > numberOfParts) { for (unsigned int ii = 0; ii < numberOfParts; ++ii) { inputFile >> m_FirstCellId >> m_LastCellId; } m_FirstCellId = 1; m_LastCellId = this->m_NumberOfCells; } else { unsigned int firstId; unsigned int lastId; for (unsigned int ii = 0; ii < m_PartId; ++ii) { inputFile >> firstId >> lastId; } inputFile >> m_FirstCellId; inputFile >> m_LastCellId; for (unsigned int ii = m_PartId + 1; ii < numberOfParts; ++ii) { inputFile >> firstId >> lastId; } } // Determine the start position of points m_FilePosition = inputFile.tellg(); /** 6. Set default parameters */ this->m_PointDimension = 3; this->m_FileType = IOFileEnum::ASCII; // If number of points is not equal zero, update points if (this->m_NumberOfPoints) { this->m_UpdatePoints = true; } // If number of cells is not equal zero, update points if (this->m_NumberOfCells) { this->m_UpdateCells = true; } // Set default point component type this->m_PointComponentType = IOComponentEnum::DOUBLE; // Read and omit points double x; for (SizeValueType ii = 0; ii < this->m_NumberOfPoints; ++ii) { for (unsigned int jj = 0; jj < this->m_PointDimension; ++jj) { inputFile >> x; } } // Determine cellbuffersize int ptId; this->m_CellBufferSize = 0; SizeValueType numLines = 0; while (numLines < this->m_NumberOfCells) { inputFile >> ptId; this->m_CellBufferSize++; if (ptId < 0) { ++numLines; } } // Set default cell component type this->m_CellComponentType = IOComponentEnum::UINT; this->m_CellBufferSize += this->m_NumberOfCells * 2; // Set default point pixel component and point pixel type this->m_PointPixelComponentType = IOComponentEnum::FLOAT; this->m_PointPixelType = IOPixelEnum::SCALAR; this->m_NumberOfPointPixelComponents = 1; // Set default cell pixel component and point pixel type this->m_CellPixelComponentType = IOComponentEnum::FLOAT; this->m_CellPixelType = IOPixelEnum::SCALAR; this->m_NumberOfCellPixelComponents = 1; inputFile.close(); } void BYUMeshIO::ReadPoints(void * buffer) { // Define input file stream and attach it to input file std::ifstream inputFile; /** Due to the windows couldn't work well for tellg() and seekg() for ASCII mode, hence we open the file with std::ios::binary */ inputFile.open(this->m_FileName.c_str(), std::ios::in | std::ios::binary); if (!inputFile.is_open()) { itkExceptionMacro("Unable to open input file " << this->m_FileName); } // Set the position to points start inputFile.seekg(m_FilePosition, std::ios::beg); // Number of data array auto * data = static_cast(buffer); // Read points inputFile.precision(12); SizeValueType index = 0; for (SizeValueType id = 0; id < this->m_NumberOfPoints; ++id) { for (unsigned int ii = 0; ii < this->m_PointDimension; ++ii) { inputFile >> data[index++]; } } // Determine cells start position m_FilePosition = inputFile.tellg(); inputFile.close(); } void BYUMeshIO::ReadCells(void * buffer) { // Define input file stream and attach it to input file std::ifstream inputFile; inputFile.open(this->m_FileName.c_str(), std::ios::in | std::ios::binary); if (!inputFile.is_open()) { itkExceptionMacro("Unable to open input file " << this->m_FileName); } // Set the position to current position inputFile.seekg(m_FilePosition, std::ios::beg); // Get cell buffer inputFile.precision(12); auto * data = static_cast(buffer); SizeValueType numPoints = 0; SizeValueType id{}; SizeValueType index = 2; int ptId; m_FirstCellId -= 1; m_LastCellId -= 1; while (id < this->m_NumberOfCells) { inputFile >> ptId; if (ptId >= 0) { if (id >= m_FirstCellId && id <= m_LastCellId) { data[index++] = ptId - 1; ++numPoints; } } else { if (id >= m_FirstCellId && id <= m_LastCellId) { data[index++] = -(ptId + 1); ++numPoints; data[index - numPoints - 2] = static_cast(CellGeometryEnum::POLYGON_CELL); data[index - numPoints - 1] = numPoints; numPoints = 0; index += 2; } ++id; } } inputFile.close(); } void BYUMeshIO::ReadPointData(void * itkNotUsed(buffer)) {} void BYUMeshIO::ReadCellData(void * itkNotUsed(buffer)) {} void BYUMeshIO::WriteMeshInformation() { // Check file name if (this->m_FileName.empty()) { itkExceptionMacro("No Input FileName"); } // Write to output file std::ofstream outputFile(this->m_FileName.c_str(), std::ios::out); if (!outputFile.is_open()) { itkExceptionMacro("Unable to open file\n" "outputFilename= " << this->m_FileName); } // Write BYU file header Indent indent(7); outputFile << indent << 1 << indent << this->m_NumberOfPoints << indent << this->m_NumberOfCells << indent << this->m_CellBufferSize - 2 * this->m_NumberOfCells << std::endl << indent << 1 << indent << this->m_NumberOfCells << std::endl; outputFile.close(); } void BYUMeshIO::WritePoints(void * buffer) { // check file name if (this->m_FileName.empty()) { itkExceptionMacro("No Input FileName"); } // Write to output file std::ofstream outputFile(this->m_FileName.c_str(), std::ios_base::app); if (!outputFile.is_open()) { itkExceptionMacro("Unable to open file\n" "outputFilename= " << this->m_FileName); } // Write points switch (this->m_PointComponentType) { case IOComponentEnum::UCHAR: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::CHAR: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::USHORT: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::SHORT: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::UINT: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::INT: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::ULONG: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::LONG: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::ULONGLONG: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::LONGLONG: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::FLOAT: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::DOUBLE: { WritePoints(static_cast(buffer), outputFile); break; } case IOComponentEnum::LDOUBLE: { WritePoints(static_cast(buffer), outputFile); break; } default: { itkExceptionMacro("Unknown point pixel component type" << std::endl); } } outputFile.close(); } void BYUMeshIO::WriteCells(void * buffer) { // Check file name if (this->m_FileName.empty()) { itkExceptionMacro("No Input FileName"); } // Write to output file std::ofstream outputFile(this->m_FileName.c_str(), std::ios_base::app); if (!outputFile.is_open()) { itkExceptionMacro("Unable to open file\n" "outputFilename= " << this->m_FileName); } // Write polygons switch (this->m_CellComponentType) { case IOComponentEnum::UCHAR: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::CHAR: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::USHORT: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::SHORT: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::UINT: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::INT: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::ULONG: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::LONG: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::ULONGLONG: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::LONGLONG: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::FLOAT: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::DOUBLE: { WriteCells(static_cast(buffer), outputFile); break; } case IOComponentEnum::LDOUBLE: { WriteCells(static_cast(buffer), outputFile); break; } default: { itkExceptionMacro("Unknown cell pixel component type" << std::endl); } } outputFile.close(); } void BYUMeshIO::WritePointData(void * itkNotUsed(buffer)) {} void BYUMeshIO::WriteCellData(void * itkNotUsed(buffer)) {} void BYUMeshIO::Write() {} void BYUMeshIO::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "FilePosition: " << static_cast::PrintType>(m_FilePosition) << std::endl; os << indent << "PartId: " << m_PartId << std::endl; os << indent << "First Cell Id: " << m_FirstCellId << std::endl; os << indent << "Last Cell Id: " << m_LastCellId << std::endl; } } // namespace itk