gctl_toolkits/handyman/handyman.cpp
2025-02-11 10:43:28 +08:00

380 lines
11 KiB
C++

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2022 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#include "gctl/core.h"
#include "gctl/geometry.h"
#include "gctl/io.h"
#include "gctl/utility.h"
class HandyMan
{
public:
HandyMan();
virtual ~HandyMan();
void Routine(); // Caller of all sub-routines.
void SR_CalPlaneCoeff(); // Galculate 3D planes' coefficents.
void SR_RGB2CPT(); // Convert RGB series to color palette tables (.cpt) file.
void SR_MgNumber(); // Calculate the magnesium number (Mg#).
void SR_Sequent(); // Output sequent arrays in column formats.
void SR_GeoAngle(); // Calculate the geo-centric angle of two points on the sphere.
};
HandyMan::HandyMan(){}
HandyMan::~HandyMan(){}
void HandyMan::Routine()
{
int c;
std::cout << "What do you want to do?\n\
(0) Quit.\n\
(1) Calculate coefficients of a 3-D plane.\n\
(2) Convert RGB series to .cpt file.\n\
(3) Calculate the magnesium number (Mg#).\n\
(4) Output sequent arrays in column formats.\n\
(5) Calculate the geo-centric angle of two points on the sphere.\n";
std::cout << ">> ";
std::cin >> c;
switch (c)
{
case 1:
SR_CalPlaneCoeff(); break;
case 2:
SR_RGB2CPT(); break;
case 3:
SR_MgNumber(); break;
case 4:
SR_Sequent(); break;
case 5:
SR_GeoAngle(); break;
default:
throw std::runtime_error("Invalid choice. From gctl::handyman.");
break;
}
return;
}
void HandyMan::SR_CalPlaneCoeff()
{
int c;
std::cout << "Known points?\n\
(1) Three points in the Cartesian coordinates.\n\
(2) Two points on a spherical surface.\n";
std::cout << ">> ";
std::cin >> c;
double A, B, C, D;
if (c == 1)
{
std::cout << "Input x, y, and z coordinates of the points.\n";
gctl::point3dc c[3];
for (size_t i = 0; i < 3; i++)
{
std::cout << ">> ";
std::cin >> c[i];
}
gctl::geometry3d::get_plane_coeff(c[0].x, c[1].x, c[2].x, c[0].y, c[1].y, c[2].y, c[0].z, c[1].z, c[2].z, A, B, C, D);
}
else if (c == 2)
{
std::cout << "Input radius, longitude, and latitude coordinates of the points.\n";
gctl::point3ds c[2];
for (size_t i = 0; i < 2; i++)
{
std::cout << ">> ";
std::cin >> c[i];
}
gctl::geometry3d::get_plane_coeff(c[0], c[1], A, B, C, D);
}
else throw std::runtime_error("Invalid choice. From gctl::handyman.");
if (A != 0.0)
{
B /= A; C /= A; D /= A; A = 1.0;
}
else if (B != 0.0)
{
A /= B; C /= B; D /= B; B = 1.0;
}
else if (C != 0.0)
{
A /= C; B /= C; D /= C; C = 1.0;
}
else throw std::runtime_error("Invalid plane's coefficients. From gctl::handyman.");
std::cout << "Plane's equation:\n";
std::cout << std::fixed << std::setprecision(3) << A << "*x + " << B << "*y + " << C << "*z + " << D << " = 0\n";
return;
}
void HandyMan::SR_RGB2CPT()
{
gctl::dsv_io tc;
std::string rgb_file, cpt_file;
std::cout << "Name of the RGB series file (Each line of file contains a R G B group).\n>> ";
std::cin >> rgb_file;
std::cout << "Name of the output .cpt file.\n>> ";
std::cin >> cpt_file;
tc.load_text(rgb_file);
int c_size = tc.row_number();
gctl::array<double> R, G, B;
tc.get_column(R, 0);
tc.get_column(G, 1);
tc.get_column(B, 2);
int i_type;
std::cout << "Interpolation type of the interval values.\n(1) linear\n(2) data\n>> ";
std::cin >> i_type;
int sym_zero = 0;
std::cout << "symmetric w.r.t. zero value (1 for yes and 0 for no).\n>> ";
std::cin >> sym_zero;
std::ofstream ofile;
gctl::open_outfile(ofile, cpt_file, ".cpt");
double dn_val, up_val;
double mini, maxi;
if (i_type == 1)
{
if (sym_zero)
{
std::cout << "Maximal absolute value of the output .cpt file.\n>> ";
std::cin >> maxi;
mini = -1.0*maxi;
}
else
{
std::cout << "Minimal and maximal values of the output .cpt file.\n>> ";
std::cin >> mini >> maxi;
}
ofile << "# This file is generated by the tool 'handyman' of the GCTL package.\n";
ofile << "# Input file: " << rgb_file << "\n";
ofile << "# Interpolation type: linear\n";
ofile << "# symmetric w.r.t. zero value: " << sym_zero << "\n";
for (size_t i = 0; i < c_size - 1; i++)
{
dn_val = (maxi - mini)*i/(c_size - 1.0) + mini;
up_val = (maxi - mini)*(i + 1.0)/(c_size - 1.0) + mini;
ofile << dn_val << " " << R[i] << "/" << G[i] << "/" << B[i] << " ";
ofile << up_val << " " << R[i+1] << "/" << G[i+1] << "/" << B[i+1] << " L\n";
}
ofile << "B black\nF white\nN 128\n";
}
else if (i_type == 2)
{
std::string in_str, f_name;
std::cout << "Name of the .txt input file.\n>> ";
std::cin >> in_str;
gctl::parse_string_to_value(in_str, '+', true, f_name);
tc.clear();
tc.load_text(f_name);
gctl::array<double> D_ori;
tc.get_column(D_ori, 0);
std::vector<double> D;
D.reserve(D_ori.size());
for (size_t i = 0; i < D_ori.size(); i++)
{
if (!std::isnan(D_ori[i]))
{
D.push_back(D_ori[i]);
}
}
int d_size = D.size();
int box_size = ceil(d_size/(c_size - 1.0));
// 排序
std::sort(D.begin(), D.end());
mini = D.front(); maxi = D.back();
if (sym_zero)
{
if (abs(maxi) > abs(mini))
{
mini = -1.0*maxi;
D.insert(D.begin(), mini);
}
else if (abs(maxi) < abs(mini))
{
maxi = -1.0*mini;
D.push_back(maxi);
}
d_size = D.size();
box_size = ceil(d_size/(c_size - 1.0));
}
ofile << "# This file is generated by the tool 'handyman' of the GCTL package.\n";
ofile << "# Input file: " << rgb_file << "\n";
ofile << "# Interpolation type: data\n";
ofile << "# symmetric w.r.t. zero value: " << sym_zero << "\n";
ofile << "# data name: " << in_str << "\n";
int d_id;
dn_val = mini;
for (size_t i = 0; i < c_size - 1; i++)
{
d_id = box_size*(i+1) - 1;
if (d_id >= d_size) d_id = d_size - 1;
up_val = D[d_id];
ofile << dn_val << " " << R[i] << "/" << G[i] << "/" << B[i] << " ";
ofile << up_val << " " << R[i+1] << "/" << G[i+1] << "/" << B[i+1] << " L\n";
dn_val = up_val;
}
ofile << "B black\nF white\nN 128\n";
}
else throw std::runtime_error("Invalid choice. From gctl::handyman.");
ofile.close();
return;
}
void HandyMan::SR_MgNumber()
{
double feo, fe2o3, mgo;
std::cout << "Weight precents (wt%) of MgO (> 0), FeO (>= 0) and Fe2O3 (>= 0).\n>> ";
std::cin >> mgo >> feo >> fe2o3;
if (mgo <= 0.0 || feo < 0.0 || fe2o3 < 0.0)
{
throw std::runtime_error("Invalid inputs.");
}
feo += 0.8998*fe2o3;
std::cout << "Mg# = " << (mgo/40.3044)/(mgo/40.3044 + feo/71.8444) << "\n";
return;
}
void HandyMan::SR_Sequent()
{
double st, ed, inter;
std::vector<double> starts, ends, intervals;
std::cout << "Input column's start, end and interval values (one group per line, enter empty line to finish).\n";
std::string line;
std::getline(std::cin, line);
while (std::getline(std::cin, line))
{
if (line.empty()) break;
else
{
gctl::parse_string_to_value(line, ' ', true, st, ed, inter);
starts.push_back(st);
ends.push_back(ed);
intervals.push_back(inter);
}
}
int l = 0;
bool valid;
do
{
valid = false;
for (size_t i = 0; i < starts.size(); i++)
{
st = starts[i] + l*intervals[i];
if (starts[i] != ends[i] && st <= ends[i])
{
std::cout << st << " ";
valid = true;
}
else if (starts[i] == ends[i] && valid == true)
{
std::cout << st << " ";
}
}
std::cout << "\n";
l++;
}
while (valid);
return;
}
void HandyMan::SR_GeoAngle()
{
std::cout << "Input longitude, and latitude coordinates of the two points.\n";
gctl::point3ds c[2];
for (size_t i = 0; i < 2; i++)
{
std::cout << ">> ";
c[i].rad = 1.0;
std::cin >> c[i].lon >> c[i].lat;
}
std::cout << "The geo-centric angle is: " << gctl::geometry3d::angle(c[0].s2c(), c[1].s2c())*180.0/M_PI << " deg.\n";
return;
}
int main(int argc, char const *argv[]) try
{
HandyMan hm;
gctl::display_logo();
bool quit = false;
while (!quit)
{
hm.Routine();
std::cout << "Quit? (1 for yes and 0 for no)\n";
std::cout << ">> ";
std::cin >> quit;
}
return 0;
}
catch (std::exception &e)
{
GCTL_ShowWhatError(e.what(), GCTL_ERROR_ERROR, 0, 0, 0);
}