225 lines
7.2 KiB
C++
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;
|
|
}
|
|
}
|