/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * 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. ******************************************************/ #ifndef _GCTL_POINT2P_H #define _GCTL_POINT2P_H #include "../core/macro.h" #include "../core/exceptions.h" #include "point2c.h" #include "iostream" #include "string" #include "cmath" #include "iomanip" #include "regex" namespace gctl { template struct point2c; template struct point2p; typedef point2p point2dp; typedef point2p point2fp; #ifndef IO_PSN #define IO_PSN // static variable for controlling the IO process static int io_psn = 6; #endif // IO_PSN /** * @brief A point under the 2-D Polar coordinates. */ template struct point2p { T rad; ///< Radius of the point T arc; ///< Radian between the point and the x-axis anticlock-wise. /** * @brief Construct a new point2p object */ point2p(); /** * @brief Construct a new point2p object * * @param in_r Input radius * @param in_a Input radian */ point2p(T in_r, T in_a); /** * @brief Construct a new point2p object * * @param b Input point2p object */ point2p(const point2p &b); /** * @brief Destroy the point2p object */ virtual ~point2p(){} /** * @brief Whether the object is nan or not * * @return true. The object is nan. * @return false. The object is not nan. */ bool valid() const; /** * @brief Set coordinates of the object * * @param in_r Input radius * @param in_a Input radian */ void set(T in_r, T in_a); /** * @brief Set coordinates of the object * * @param b Input point2p object */ void set(const point2p &b); /** * @brief Return the mode length. * * @return mode length. */ T module(); /** * @brief Round down the radian to zero to 2*pi */ void round_down(); /** * @brief Return a point2c object at the same position. * * @return The point2c object. */ point2c p2c() const; /** * @brief Parse the point's parameters from a string * * @param[in] str The input string */ void str(std::string str); /** * @brief Sets the i/o precision of the type. * * @param[in] psn The desired precision */ void set_io_precision(int psn); /** * @brief 输出位置 * * @param os 输出流 */ void out_loc(std::ostream &os, char deli) const; /** * @brief 输入位置 * * @param os 输入流 */ void in_loc(std::istream &os); /** * @brief 返回位置 * * @return 位置 */ point2p get_loc() const; }; template gctl::point2p::point2p() { rad = arc = NAN; } template gctl::point2p::point2p(T in_r, T in_a) { set(in_r, in_a); } template gctl::point2p::point2p(const point2p &b) { set(b); } template bool gctl::point2p::valid() const { if (std::isnan(rad) || std::isnan(arc)) return false; if (std::isinf(rad) || std::isinf(arc)) return false; return true; } template void gctl::point2p::set(T in_r, T in_a) { if (std::isnan(in_r) || std::isnan(in_a) || std::isinf(in_r) || std::isinf(in_a)) { throw invalid_argument("Invalid value detected. From point2p::set(...)"); } if (in_r < 0) { throw out_of_range("Invalid radius. From point2p::set(...)"); } rad = in_r; arc = in_a; return; } template void gctl::point2p::set(const point2p &b) { if (std::isnan(b.rad) || std::isnan(b.arc) || std::isinf(b.rad) || std::isinf(b.arc)) { throw invalid_argument("Invalid value detected. From point2p::set(...)"); } if (b.rad < 0) { throw out_of_range("Invalid radius. From point2p::set(...)"); } rad = b.rad; arc = b.arc; return; } template T gctl::point2p::module() { return rad; } template void gctl::point2p::round_down() { if (arc >= 2.0*GCTL_Pi) arc = fmod(arc, (2.0*GCTL_Pi)); else if (arc < 0.0) arc = fmod(arc, (2.0*GCTL_Pi)) + 2.0*GCTL_Pi; return; } template gctl::point2c gctl::point2p::p2c() const { point2c outc; outc.x = rad * cos(arc); outc.y = rad * sin(arc); return outc; } template void gctl::point2p::str(std::string str) { std::smatch ret; std::regex pattern("\\((-?\\d*\\.?\\d+?),[ ]*(-?\\d*\\.?\\d+?)\\)"); if (regex_search(str, ret, pattern)) { rad = atof(std::string(ret[1]).c_str()); arc = atof(std::string(ret[2]).c_str()); return; } throw runtime_error("Fail to parse the input string: " + str + ". From point2p::str(...)"); return; } template void gctl::point2p::set_io_precision(int psn) { if (psn < 0) { throw invalid_argument("Invalid precision. From point2p::set_io_precision(...)"); } io_psn = psn; return; } template void gctl::point2p::out_loc(std::ostream &os, char deli) const { os << std::setprecision(io_psn) << rad << deli << arc; return; } template void gctl::point2p::in_loc(std::istream &os) { os >> rad >> arc; return; } template gctl::point2p gctl::point2p::get_loc() const { return point2p(rad, arc); } template bool operator ==(const point2p &a, const point2p &b) { if( fabs(a.rad - b.rad) < GCTL_ZERO && fabs(a.arc - b.arc) < GCTL_ZERO) { return true; } else return false; } template bool operator !=(const point2p &a, const point2p &b) { if( fabs(a.rad - b.rad) >= GCTL_ZERO || fabs(a.arc - b.arc) >= GCTL_ZERO) { return true; } else return false; } template std::ostream &operator <<(std::ostream & os, const point2p &a) { os << std::setprecision(io_psn) << a.rad << " " << a.arc; return os; } template std::istream &operator >>(std::istream & os, point2p &a) { os >> a.rad >> a.arc; return os; } /** * @brief 两个极坐标点的夹角。 * * @note 表示从 a 到 b 的夹角 * * @param[in] a 第一个点 * @param[in] b 第二个点 * * @return 夹角弧度值。 */ template double angle(const point2p &a, const point2p &b) { return b.arc - a.arc; } /** * @brief 函数判断两个point2p类型是否等于 * * @param[in] a 二维空间内的一个向量或实点a。 * @param[in] b 二维空间内的一个向量或实点b。 * @param[in] cut_off 截断误差,默认值为 gctl_macro.h 中预设的 GCTL_ZERO 值,可在调用时改变。 * 注意比较的精度为 cut_off 减一位,比如 cut_off 为1e-10则比较的精度为小数点后9位。 * * @return 是否相等。 */ template bool isequal(const point2p &a, const point2p &b, double cut_off = GCTL_ZERO) { if( fabs(a.rad - b.rad) < cut_off && fabs(a.arc - b.arc) < cut_off) { return true; } return false; } /** * @brief 函数判断两个point2p类型是否不等于 * * @param[in] a 二维空间内的一个向量或实点a。 * @param[in] b 二维空间内的一个向量或实点b。 * @param[in] cut_off 截断误差,默认值为 gctl_macro.h 中预设的 GCTL_ZERO 值,可在调用时改变。 * * @return 是否不相等。 */ template bool notequal(const point2p &a, const point2p &b, double cut_off = GCTL_ZERO) { if( fabs(a.rad - b.rad) >= cut_off || fabs(a.arc - b.arc) >= cut_off) { return true; } return false; } template void grid_points_1d(array> &obsp, T deg_st, T deg_ed, T ddeg, T rad) { int m = round(std::abs((deg_st - deg_ed)/ddeg)) + 1; obsp.resize(m); for (size_t i = 0; i < m; i++) { obsp[i].arc = arc(deg_st + i*ddeg); obsp[i].rad = rad; } return; } } #endif // _GCTL_POINT2P_H