/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * 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_POINT2C_H #define _GCTL_POINT2C_H #include "../core/macro.h" #include "../core/exceptions.h" #include "point2p.h" #include "iostream" #include "string" #include "cmath" #include "iomanip" #include "regex" namespace gctl { template struct point2c; template struct point2p; typedef point2c point2dc; typedef point2c point2fc; #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 2D Cartesian coordinates (aka. 2D vector). */ template struct point2c { T x; ///< x coordinate T y; ///< y coordinate /** * @brief Constructor */ point2c(); /** * @brief Construct a new object with initial parameters * * @param in_x Input x coordinate * @param in_y Input y coordinate */ point2c(T in_x, T in_y); /** * @brief Construct a new object from an existing object * * @param b Input point2c object */ point2c(const point2c &b); /** * @brief De-constructor */ virtual ~point2c(){} /** * @brief Whether the object is valid or not * * @return true. The object is valid. * @return false. The object is invalid. */ bool valid() const; /** * @brief Set coordinates of the point2c object * * @param in_x Input x coordinate * @param in_y Input y coordinate */ void set(T in_x, T in_y); /** * @brief Set coordinates of the point2c object * * @param b Input point2c object */ void set(const point2c &b); /** * @brief Set the point's mode to the given value * * @param mod Desired mode length. * @param cut_off The cut off to round down the zero values. */ void set2module(T mod, T cut_off = GCTL_ZERO); /** * @brief Return the mode length. * * @return mode length. */ T module() const; /** * @brief Return the normal vector. * * @return The normalized vector. */ point2c normal() const; /** * @brief Return a point2dp object at the same position. * * @return The point2dp object. */ point2p c2p() const; /** * @brief Set a point2c object from a string. The accepted format: (x, y) * * @note The function searchs coordinates from an input string. * The accepted format is (x, y). The space after the comma is optional. * * @param str The input string object. */ 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[in] arc 旋转的弧度,逆时针为正 * @param[in] origin 旋转的中心,默认为坐标原点 * * @return 旋转后的向量 */ point2c rotate(double arc, const point2c &origin = {0, 0}); /** * @brief 输出位置 * * @param os 输出流 */ void out_loc(std::ostream &os, char deli) const; /** * @brief 输入位置 * * @param os 输入流 */ void in_loc(std::istream &os); /** * @brief 返回位置 * * @return 位置 */ point2c get_loc() const; }; template gctl::point2c::point2c() { x = y = NAN; } template gctl::point2c::point2c(T in_x, T in_y) { set(in_x, in_y); } template gctl::point2c::point2c(const point2c &b) { set(b); } template bool gctl::point2c::valid() const { if (std::isnan(x) || std::isnan(y)) return false; if (std::isinf(x) || std::isinf(y)) return false; return true; } template void gctl::point2c::set(T in_x, T in_y) { if (std::isnan(in_x) || std::isnan(in_y) || std::isinf(in_x) || std::isinf(in_y)) { throw invalid_argument("Invalid value detected. From point2c::set(...)"); } x = in_x; y = in_y; return; } template void gctl::point2c::set(const point2c &b) { if (std::isnan(b.x) || std::isnan(b.y) || std::isinf(b.x) || std::isinf(b.y)) { throw invalid_argument("Invalid value detected. From point2c::set(...)"); } x = b.x; y = b.y; return; } template void gctl::point2c::set2module(T mod, T cut_off) { if (cut_off <= 0.0) { throw invalid_argument("Invalid cut-off value. From point2c::set2module(...)"); } if (mod <= cut_off && mod >= -1.0*cut_off) { x = y = 0.0; return; } T old_mod = module(); x = x*mod/old_mod; y = y*mod/old_mod; return; } template T gctl::point2c::module() const { return sqrt(x*x + y*y); } template gctl::point2c gctl::point2c::normal() const { return point2c(x/module(), y/module()); } template gctl::point2p gctl::point2c::c2p() const { point2p outp; outp.rad = module(); if (y >= 0.0) outp.arc= atan2(y, x); else outp.arc = atan2(y, x) + 2.0*GCTL_Pi; return outp; } template void gctl::point2c::str(std::string str) { std::smatch ret; std::regex pattern("\\((-?\\d*\\.?\\d+?),[ ]*(-?\\d*\\.?\\d+?)\\)"); if (regex_search(str, ret, pattern)) { x = atof(std::string(ret[1]).c_str()); y = atof(std::string(ret[2]).c_str()); return; } throw runtime_error("Fail to parse the input string: " + str + ". From point2c::str(...)"); } template void gctl::point2c::set_io_precision(int psn) { if (psn < 0) { throw invalid_argument("Invalid precision. From point2c::set_io_precision(...)"); } io_psn = psn; return; } template gctl::point2c gctl::point2c::rotate(double arc, const point2c &origin) { point2c out; out.x = origin.x + cos(arc)*(x - origin.x) - sin(arc)*(y - origin.y); out.y = origin.y + sin(arc)*(x - origin.x) + cos(arc)*(y - origin.y); return out; } template void gctl::point2c::out_loc(std::ostream &os, char deli) const { os << std::setprecision(io_psn) << x << deli << y; return; } template void gctl::point2c::in_loc(std::istream &os) { os >> x >> y; return; } template gctl::point2c gctl::point2c::get_loc() const { return point2c(x, y); } template bool operator ==(const point2c &a, const point2c &b) { if( fabs(a.x - b.x) < GCTL_ZERO && fabs(a.y - b.y) < GCTL_ZERO) { return true; } else return false; } template bool operator !=(const point2c &a, const point2c &b) { if( fabs(a.x - b.x) >= GCTL_ZERO || fabs(a.y - b.y) >= GCTL_ZERO) { return true; } else return false; } template point2c operator-(const point2c &a, const point2c &b) //二维矢量减法 { point2c out; out.x = a.x - b.x; out.y = a.y - b.y; return out; } template point2c operator+(const point2c &a, const point2c &b) //二维矢量加法 { point2c out; out.x = a.x + b.x; out.y = a.y + b.y; return out; } template point2c operator*(int t, const point2c &b) { point2c out; out.x = (T) t*b.x; out.y = (T) t*b.y; return out; } template point2c operator*(float t, const point2c &b) { point2c out; out.x = (T) t*b.x; out.y = (T) t*b.y; return out; } template point2c operator*(double t, const point2c &b) //标量乘矢量 { point2c out; out.x = t*b.x; out.y = t*b.y; return out; } template point2c operator*(const point2c &b, int t) { point2c out; out.x = (T) t*b.x; out.y = (T) t*b.y; return out; } template point2c operator*(const point2c &b, float t) { point2c out; out.x = (T) t*b.x; out.y = (T) t*b.y; return out; } template point2c operator*(const point2c &b, double t) { point2c out; out.x = t*b.x; out.y = t*b.y; return out; } template std::ostream &operator <<(std::ostream & os, const point2c &a) { os << std::setprecision(io_psn) << a.x << " " << a.y; return os; } template std::istream &operator >>(std::istream & os, point2c &a) { os >> a.x >> a.y; return os; } /** * @brief 计算两个向量的点乘 * * @param[in] a 点a的引用 * @param[in] b 点b的引用 * * @return 点乘值 */ template double dot(const point2c &a, const point2c &b) { return a.x*b.x + a.y*b.y; } /** * @brief 计算两个向量的叉乘,二维情况为结果是一个标量。 * * @param[in] a 点a的引用 * @param[in] b 点b的引用 * * @return 叉乘值 */ template double cross(const point2c &a, const point2c &b) { return a.x*b.y - a.y*b.x; } /** * @brief 两点距离 * * @param[in] a 第一个点的引用 * @param[in] b 第二个点的引用 * * @return 两点距离 */ template double distance(const point2c &a, const point2c &b) { return (a - b).module(); } /** * @brief 两个向量之间的夹角。 * * @param[in] a 向量a * @param[in] b 向量b * * @return 夹角弧度值。 */ template double angle(const point2c &a, const point2c &b) { return acos(dot(a, b)/(a.module()*b.module())); } /** * @brief 函数判断两个point2c类型是否等于 * * @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 point2c &a, const point2c &b, double cut_off = GCTL_ZERO) { if( fabs(a.x - b.x) < cut_off && fabs(a.y - b.y) < cut_off) { return true; } return false; } /** * @brief 函数判断两个point2c类型是否不等于 * * @param[in] a 二维空间内的一个向量或实点a。 * @param[in] b 二维空间内的一个向量或实点b。 * @param[in] cut_off 截断误差,默认值为 gctl_macro.h 中预设的 GCTL_ZERO 值,可在调用时改变。 * * @return 是否不相等。 */ template bool notequal(const point2c &a, const point2c &b, double cut_off = GCTL_ZERO) { if( fabs(a.x - b.x) >= cut_off || fabs(a.y - b.y) >= cut_off) { return true; } return false; } /** * @brief 生成一维网格节点数组,其中每一个点都是一个二维坐标点。 * * @param out_ps 返回网格节点数组 * @param[in] x_st x起始值 * @param[in] x_ed x终止值 * @param[in] dx x间隔 * @param[in] ele 高程值 */ template void grid_points_1d(array> &out_ps, T x_st, T x_ed, T dx, T ele) { int xnum = round(std::abs((x_ed - x_st)/dx)) + 1; out_ps.resize(xnum); for (int i = 0; i < xnum; i++) { out_ps[i].x = x_st + dx*i; out_ps[i].y = ele; } return; } } #endif // _GCTL_POINT2C_H