Files
cse5543_homework/lab3/grid2DIO.cpp
2026-03-31 10:26:51 -04:00

225 lines
7.2 KiB
C++

// Functions to read/write a 2D grid of 3D points.
#include "grid2DIO.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
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<std::string>& 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<std::string>& 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;
}
}