/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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