// Functions to read/write a 2D grid of 3D points. #include "grid2DIO.h" #include #include #include #include #include const std::string GRID2D_POINTS3D_HEADER = "GRID2D_OF_POINTS3D"; // ******************************************************************************** // Internal helpers // ******************************************************************************** /// Trim leading and trailing whitespace from s. static std::string Trim(const std::string& s) { const std::string whitespace = " \t\r\n"; size_t start = s.find_first_not_of(whitespace); if (start == std::string::npos) { return ""; } size_t end = s.find_last_not_of(whitespace); return s.substr(start, end - start + 1); } /// Throw a read error with two descriptive lines. static void RaiseReadErrorII(int iline, const std::string& error_line1, const std::string& error_line2) { throw std::runtime_error( "Error reading line " + std::to_string(iline) + ": " + error_line1 + "\n " + error_line2); } // ******************************************************************************** // Read/Write helper predicates // ******************************************************************************** bool IsHeader(const std::string& line) { return Trim(line) == GRID2D_POINTS3D_HEADER; } bool IsCommentOrBlankLine(const std::string& line) { std::string s = Trim(line); if (s.empty()) { return true; } if (s[0] == '#') { return true; } return false; } // ******************************************************************************** // Read functions // ******************************************************************************** void ReadGrid2DPoints3D(std::istream& infile, GRID2D_POINTS3D& grid2D) { // Read coordinates of point [i,j] in grid. int i = 0, j = 0, iline = 1; std::string line; while (std::getline(infile, line)) { std::string trimmed = Trim(line); if (iline == 1) { if (!IsHeader(trimmed)) { RaiseReadErrorII(1, "Incorrect file header.", "Expected header: " + GRID2D_POINTS3D_HEADER); } } else if (!IsCommentOrBlankLine(trimmed)) { if (!grid2D.AreDimensionsSet()) { std::istringstream iss(trimmed); int n, m; if (!(iss >> n >> m)) { RaiseReadErrorII(iline, "Incorrect grid dimensions.", "Expecting two integers for grid dimensions."); } std::string extra; if (iss >> extra) { RaiseReadErrorII(iline, "Incorrect grid dimensions.", "Expecting two integers for grid dimensions."); } grid2D.SetDimensions(n, m); } else { std::istringstream iss(trimmed); double x, y, z; if (!(iss >> x >> y >> z)) { RaiseReadErrorII(iline, "Error reading point coordinates.", "Expecting three float coordinates for each point."); } if (i >= grid2D.NumRows()) { std::cerr << "Warning: More than " << grid2D.NumRows() << " x " << grid2D.NumCols() << " points in file.\n"; std::cerr << "Skipping remaining points after line " << iline << ".\n"; break; } grid2D.SetCoord(i, j, x, y, z); j++; if (j >= grid2D.NumCols()) { j = 0; i++; } } } iline++; } if (i < grid2D.NumRows()) { throw std::runtime_error( "Too few points in file. Expected coordinates of " + std::to_string(grid2D.NumPoints()) + " points.\n" + " Found coordinates of " + std::to_string(i * grid2D.NumCols() + j) + " points.\n" + " First missing point: [" + std::to_string(i) + "," + std::to_string(j) + "]."); } } void OpenReadGrid2DPoints3D(const std::string& filename, GRID2D_POINTS3D& grid2D) { try { std::ifstream infile(filename); if (!infile.is_open()) { std::cerr << "Input file " << filename << " not found.\n"; throw std::runtime_error( "Input file " + filename + " not found."); } ReadGrid2DPoints3D(infile, grid2D); } catch (const std::out_of_range& e) { std::cerr << "Error reading file " << filename << ".\n " << e.what() << "\n"; throw; } catch (const std::runtime_error& e) { std::cerr << "Error reading file " << filename << ".\n " << e.what() << "\n"; throw; } catch (const std::exception& e) { std::cerr << "Error reading file " << filename << ".\n " << e.what() << "\n"; throw; } } // ******************************************************************************** // Write functions // ******************************************************************************** void WriteGrid2DPoints3D(std::ostream& outfile, const GRID2D_POINTS3D& grid2D, const std::vector& comment_list) { // Write header outfile << GRID2D_POINTS3D_HEADER << "\n"; // Write dimensions outfile << grid2D.NumRows() << " " << grid2D.NumCols() << "\n"; // Write comments for (const auto& comment : comment_list) { outfile << "# " << comment << "\n"; } // Write point coordinates for (int irow = 0; irow < grid2D.NumRows(); irow++) { for (int icol = 0; icol < grid2D.NumCols(); icol++) { auto c = grid2D.Coord(irow, icol); outfile << c[0] << " " << c[1] << " " << c[2] << "\n"; } } } void OpenWriteGrid2DPoints3D(const std::string& filename, const GRID2D_POINTS3D& grid2D, const std::vector& comment_list) { try { std::ofstream outfile(filename); if (!outfile.is_open()) { std::cerr << "Cannot open file " << filename << " for writing.\n"; throw std::runtime_error( "Cannot open file " + filename + " for writing."); } WriteGrid2DPoints3D(outfile, grid2D, comment_list); } catch (const std::out_of_range& e) { std::cerr << "Error writing file " << filename << ".\n " << e.what() << "\n"; throw; } catch (const std::runtime_error& e) { std::cerr << "Error writing file " << filename << ".\n " << e.what() << "\n"; throw; } catch (const std::exception& e) { std::cerr << "Error writing file " << filename << ".\n " << e.what() << "\n"; throw; } }