/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2023 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 . * * 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 "cliplot.h" gctl::cliplot::cliplot(size_t width, size_t height, double xmin, double xmax, double ymin, double ymax) { new_screen_ = false; digs_ = 4; xl_num_ = 5; yl_num_ = 5; wname_ = "X"; hname_ = "Y"; struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); width += digs_ + 1; width_ = w.ws_col= width_ || h >= height_) return; sym_[h*width_ + w] = sym; att_[h*width_ + w] = att; return; } void gctl::cliplot::set_axis(int xt_num, int yt_num) { xl_num_ = xt_num; yl_num_ = yt_num; return; } void gctl::cliplot::set_digs(int digs) { int old_digs = digs_; digs_ = digs; width_ += digs_ - old_digs; w0_ += digs_ - old_digs; sym_.resize(width_*height_); att_.resize(width_*height_); clear(); return; } void gctl::cliplot::set_new_screen(bool new_screen) { new_screen_ = new_screen; return; } void gctl::cliplot::set_wname(const std::string &wname) { wname_ = wname; return; } void gctl::cliplot::set_hname(const std::string &hname) { hname_ = hname; return; } void gctl::cliplot::plot_line(double x1, double x2, double y1, double y2, char s, const std::string &t) { if (x1 > x2) { std::swap(x1, x2); std::swap(y1, y2); } for (size_t w = w0_; w < width_; w++) { double x = xmin_ + (w - w0_)*(xmax_ - xmin_)/(width_ - 1 - w0_); if (x + 0.5*dx_ >= x1 && x - 0.5*dx_ <= x2) { double y; if (x2 - x1 < dx_) y = y1; else y = y1 + (y2 - y1)*(x - 0.25*dx_ - x1)/(x2 - x1); int h1 = round(h0_ - 1 - (y - ymin_)*(h0_ - 1)/(ymax_ - ymin_)); if (x2 - x1 < dx_) y = y2; else y = y1 + (y2 - y1)*(x + 0.25*dx_ - x1)/(x2 - x1); int h2 = round(h0_ - 1 - (y - ymin_)*(h0_ - 1)/(ymax_ - ymin_)); if (h1 > h2) std::swap(h1, h2); for (size_t h = h1; h <= h2; h++) set(w, h, s, t); } } return; } void gctl::cliplot::plot_data(const std::vector &x, const std::vector &y, char s, const std::string &t) { if (x.size() != y.size()) return; for (size_t i = 0; i < x.size() - 1; i++) { plot_line(x[i], x[i+1], y[i], y[i+1], s, t); } return; } void gctl::cliplot::display(std::ostream &os) { if (new_screen_) { os << GCTL_CLEARALL; GCTL_MOVEUP(os, height_); } plot_axis(); for (size_t i = 0; i < height_; i++) { for (size_t j = 0; j < width_; j++) { os << att_[i*width_ + j] << sym_[i*width_ + j] << GCTL_RESET; } os << std::endl; } return; } std::string gctl::cliplot::axis_label(double num, int digs, int &odr) { std::stringstream ss; if (floor(log10(abs(num))) >= digs) { ss << std::scientific << std::setprecision(digs) << num; odr = floor(log10(abs(num))); if (num < 0) odr *= -1; } else { ss << std::fixed << std::setprecision(digs) << num; odr = 0; } return ss.str(); } void gctl::cliplot::plot_axis() { for (size_t i = w0_; i < width_; i++) set(i, h0_, '-', GCTL_BOLD); std::vector xpos(xl_num_); int xtick = (width_ - w0_)/(xl_num_ - 1); xpos[0] = w0_; xpos[xl_num_ - 1] = width_ - 1; for (size_t i = 1; i <= xl_num_ - 2; i++) xpos[i] = w0_ + i*xtick; int h_digs = digs_/2; int odr; for (size_t i = 0; i < xl_num_; i++) { set(xpos[i], h0_, '|', GCTL_BOLD); std::string xlabel = axis_label(xmin_ + (xpos[i] - w0_)*(xmax_ - xmin_)/(width_ - 1 - w0_), digs_, odr); for (int c = -h_digs; c <= h_digs; c++) { set(xpos[i] + c, h0_ + 1, xlabel[c + h_digs], GCTL_BOLD); } if (odr > 0) { set(xpos[i] + h_digs + 1, h0_ + 1, 'e', GCTL_BOLD); set(xpos[i] + h_digs + 3, h0_ + 1, std::to_string(odr)[0], GCTL_BOLD); } else if (odr < 0) { set(xpos[i] + h_digs + 1, h0_ + 1, 'e', GCTL_BOLD); set(xpos[i] + h_digs + 2, h0_ + 1, std::to_string(odr)[0], GCTL_BOLD); set(xpos[i] + h_digs + 3, h0_ + 1, std::to_string(odr)[1], GCTL_BOLD); } } for (size_t j = 0; j < h0_; j++) { set(w0_, j, '|', GCTL_BOLD); } std::vector ypos(yl_num_); int ytick = h0_/(yl_num_ - 1); ypos[0] = 0; ypos[yl_num_ - 1] = h0_ - 1; for (size_t i = 1; i <= yl_num_ - 2; i++) ypos[i] = i*ytick; for (size_t i = 0; i < yl_num_; i++) { set(w0_, ypos[i], '-', GCTL_BOLD); std::string ylabel = axis_label(ymax_ - ypos[i]*(ymax_ - ymin_)/(h0_ - 1), digs_, odr); for (size_t c = 0; c < digs_; c++) { set(c, ypos[i], ylabel[c], GCTL_BOLD); } if (odr > 0) { set(digs_ + 3, ypos[i], 'e', GCTL_BOLD); set(digs_ + 4, ypos[i], std::to_string(odr)[0], GCTL_BOLD); } else if (odr < 0) { set(digs_ + 3, ypos[i], 'e', GCTL_BOLD); set(digs_ + 4, ypos[i], std::to_string(odr)[0], GCTL_BOLD); set(digs_ + 5, ypos[i], std::to_string(odr)[1], GCTL_BOLD); } } for (size_t i = 0; i < wname_.size(); i++) { set(width_ - wname_.size() + i, h0_ - 1, wname_[i], GCTL_BOLD); } for (size_t i = 0; i < hname_.size(); i++) { set(w0_ + 6 + i, 0, hname_[i], GCTL_BOLD); } return; }