gctl/lib/math/gmath.h
2025-04-23 13:43:40 +08:00

442 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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 <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.
******************************************************/
#ifndef _GCTL_GMATH_H
#define _GCTL_GMATH_H
#include <cmath>
#include <random>
#include <vector>
#include "../core/macro.h"
#include "../core/spmat.h"
namespace gctl
{
template <typename T>
inline int sign(T d)
{
return (T(0) < d) - (d < T(0));
}
template <typename T>
inline T arc(T deg)
{
return deg*GCTL_Pi/180.0L;
}
template <typename T>
inline T deg(T arc)
{
return arc*180.0L/GCTL_Pi;
}
template <typename T>
inline T sind(T deg)
{
return sin(deg*GCTL_Pi/180.0L);
}
template <typename T>
inline T cosd(T deg)
{
return cos(deg*GCTL_Pi/180.0L);
}
template <typename T>
inline T tand(T deg)
{
return tan(deg*GCTL_Pi/180.0L);
}
template <typename T>
inline T power2(T in)
{
return (in)*(in);
}
template <typename T>
inline T power3(T in)
{
return (in)*(in)*(in);
}
template <typename T>
inline T power4(T in)
{
return (in)*(in)*(in)*(in);
}
template <typename T>
inline T power5(T in)
{
return (in)*(in)*(in)*(in)*(in);
}
template <typename T>
inline T jacoby2(T x00, T x01, T x10, T x11)
{
return x00*x11-x01*x10;
}
template <typename T>
inline T jacoby3(T x00, T x01, T x02, T x10, T x11,
T x12, T x20, T x21, T x22)
{
return x00*x11*x22+x01*x12*x20+x10*x21*x02
-x02*x11*x20-x01*x10*x22-x00*x12*x21;
}
/**
* @brief Calculate the inverse matrix of a 3x3 matrix
*
* @tparam T Type name
* @param A Pointer of the input matrix, must be stored in an array of the nine coefficients in a row-major fashion
* @param invA Pointer of the output matrix, must be stored in an array of the nine coefficients in a row-major fashion
* @return true Success
* @return false Fail
*/
template <typename T>
bool inverse3x3(T *A, T *invA)
{
T det = jacoby3(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[8]);
if (det <= GCTL_ZERO && det >= -1*GCTL_ZERO) return false;
invA[0] = jacoby2(A[4], A[7], A[5], A[8])/det;
invA[1] = -1.0*jacoby2(A[1], A[7], A[2], A[8])/det;
invA[2] = jacoby2(A[1], A[4], A[2], A[5])/det;
invA[3] = -1.0*jacoby2(A[3], A[6], A[5], A[8])/det;
invA[4] = jacoby2(A[0], A[6], A[2], A[8])/det;
invA[5] = -1.0*jacoby2(A[0], A[3], A[2], A[5])/det;
invA[6] = jacoby2(A[3], A[6], A[4], A[7])/det;
invA[7] = -1.0*jacoby2(A[0], A[6], A[1], A[7])/det;
invA[8] = jacoby2(A[0], A[3], A[1], A[4])/det;
return true;
}
template <typename T>
T arctg(T v)
{
T ang;
if(v>=0) ang=atan(v);
else ang=atan(v)+GCTL_Pi;
return ang;
}
template <typename T>
T arctg2(T v, T f)
{
T ang;
if(f>=0)
{
if(atan(v)>0) ang=atan(v);
else ang=atan(v) + GCTL_Pi;
}
else if(f<0)
{
if(atan(v)<0) ang=atan(v);
else ang=atan(v) - GCTL_Pi;
}
return ang;
}
/**
* @brief Return a random number in the range [low, hig]
*
* @note Call srand(seed) to initiate the random squence before using this function.
*
* @param low Lower bound
* @param hig Higher bound
* @return Random value
*/
int random(int low, int hig);
/**
* @brief Return a random number in the range [low, hig]
*
* @note Call srand(seed) to initiate the random squence before using this function.
*
* @param low Lower bound
* @param hig Higher bound
* @return Random value
*/
double random(double low, double hig);
/**
* @brief Return a random number in the range [low, hig]
*
* @note Call srand(seed) to initiate the random squence before using this function.
*
* @param low Lower bound
* @param hig Higher bound
* @return Random value
*/
std::complex<double> random(std::complex<double> low, std::complex<double> hig);
/**
* @brief 比较两个浮点数。注意比较的精度为 eps 减一位,比如 eps 为1e-10则比较的精度为小数点后9位。
*
* @param f 第一个浮点数
* @param v 第二个浮点数
* @param eps 比较的精度
* @return true 两个浮点数相等
* @return false 两个浮点数不相等
*/
bool isequal(double f, double v, double eps = GCTL_ZERO);
/**
* @brief 符号函数
*
* @param[in] a 输入值
*
* @return 大于零返回1 否则返回-1 等于0则返回0
*/
double sign(double a);
/**
* @brief 二分法求一个正数的n次方根
*
* @param[in] val 输入值
* @param[in] order 开方次数
* @param[in] eps 终止精度
*
* @return 开方值
*/
double sqrtn(double val, int order, double eps = 1e-5);
/**
* @brief 计算经纬度网格的面积
*
* @param lon1 经度起点
* @param lon2 经度终点
* @param lat1 纬度起点
* @param lat2 纬度终点
* @param R 半径
* @return 面积
*/
double geographic_area(double lon1, double lon2, double lat1, double lat2, double R);
/**
* @brief 计算两个经纬度点之间的距离
*
* @param lon1 经度起点
* @param lon2 经度终点
* @param lat1 纬度起点
* @param lat2 纬度终点
* @param R 半径
* @return 面积
*/
double geographic_distance(double lon1, double lon2, double lat1, double lat2, double R);
/**
* @brief 计算一个椭圆在不同位置的半径
*
* @param[in] x_len x方向半径
* @param[in] y_len y方向半径
* @param[in] arc 计算方向与x轴正方向的夹角弧度 逆时针为正
* @param[in] x_arc x轴正方向绕原点逆时针旋转的角度 (弧度)
*
* @return 半径值
*/
double ellipse_radius_2d(double x_len, double y_len, double arc, double x_arc = 0.0);
/**
* @brief 计算已椭圆为基准面的高程数据的绝对坐标位置。
*
* 假设高程数据的测量方向(如大地水准面)为椭圆切线的垂直方向(与切点与坐标原点的连线方向不一致)
* 则高程点的绝对空间位置的维度值与切点的维度值也不一致。此函数可以计算校正后的维度值与球心半径。
*
* @param x_len 椭圆的x方向半径一般为长轴
* @param y_len 椭圆的y方向半径一般为短轴
* @param arc 计算方向与x轴正方向的夹角弧度 逆时针为正(等于纬度)
* @param elev 切点的高程值
* @param out_arc 校正后的维度值
* @param out_rad 校正后高程点的球心半径
* @param x_arc x轴正方向绕原点逆时针旋转的角度 弧度默认为0
*/
void ellipse_plus_elevation_2d(double x_len, double y_len, double arc, double elev,
double &out_arc, double &out_rad, double x_arc = 0.0);
/**
* @brief 椭球或者球在不同球面位置的半径
*
* @param[in] x_len x方向半径
* @param[in] y_len y方向半径
* @param[in] z_len z方向半径
* @param[in] phi 计算方向与x轴正方向的夹角弧度 逆时针为正
* @param[in] theta 计算方向与z轴正方向的夹角弧度 逆时针为正
*
* @return 半径值
*/
double ellipsoid_radius(double x_len, double y_len, double z_len, double phi, double theta);
/**
* @brief 使用牛顿迭代法计算一个矩阵的近似逆
*
* 此方法适合用于对角占优的方阵求逆。
*
* @param[in] in_mat 输入矩阵
* @param inverse_mat 逆矩阵
* @param[in] epsilon 迭代的终止精度
* @param[in] iter_times 迭代的次数。默认为10
* @param[in] initiate 对逆矩阵进行初始化
*
* @return 最终的迭代精度
*/
double newton_inverse(const _2d_matrix &in_mat, _2d_matrix &inverse_mat,
double epsilon = 1e-8, int iter_times = 10, bool initiate = true);
/**
* @brief 使用牛顿迭代法计算一个矩阵的近似逆
*
* 此方法适合用于对角占优的方阵求逆。
*
* @param[in] in_mat 输入矩阵(稀疏的)
* @param inverse_mat 逆矩阵
* @param[in] epsilon 迭代的终止精度
* @param[in] iter_times 迭代的次数。默认为10
* @param[in] initiate 对逆矩阵进行初始化
*
* @return 最终的迭代精度
*/
double newton_inverse(const spmat<double> &in_mat, _2d_matrix &inverse_mat,
double epsilon = 1e-8, int iter_times = 10, bool initiate = true);
/**
* @brief 使用施密特正交化将线性无关的向量组a转换为标准正交向量组e
*
* @note 经过正交变化的向量组中任意两个向量正交。
*
* @param[in] a 个数为a_s的线性无关的向量组的指针这里将向量组保存为一个连续的一维数组
* @param e 输出的转换后的标准正交向量组(保存为一个连续的一维数组)
* @param[in] a_s 向量的个数
*/
void schmidt_orthogonal(const array<double> &a, array<double> &e, int a_s);
/**
* @brief 按距离反比加权计算均值
*
* @param dis_vec 距离向量
* @param val_vec 数值向量
* @param[in] order 距离加权的阶次 默认为1
*
* @return 加权平均值
*/
double dist_inverse_weight(std::vector<double> *dis_vec, std::vector<double> *val_vec, int order = 1);
/**
* @brief 查找一个数在已排序的数组中的位置,即找到包含该数的最小区间
*
* @param[in] in_array 输入数组
* @param[in] array_size 数组大小
* @param[in] in_val 查找值
* @param index 返回的索引值
*
* @return 成功0失败-1
*/
int find_index(const double *in_array, int array_size, double in_val, int &index);
/**
* @brief 查找一个数在已排序的数组中的位置,即找到包含该数的最小区间
*
* @param in_array 输入数组
* @param[in] in_val 查找值
* @param index 返回的索引值
*
* @return 成功0失败-1
*/
int find_index(array<double> *in_array, double in_val, int &index);
/**
* @brief 计算一维分形模型
*
* @param out_arr 输出数组
* @param[in] l_val 分形计算的左端点值
* @param[in] r_val 分形计算的右端点值
* @param[in] maxi_range 最大变化值
* @param[in] smoothness 变化光滑度
*/
void fractal_model_1d(array<double> &out_arr, int out_size, double l_val,
double r_val, double maxi_range, double smoothness);
/**
* @brief 计算二维分形模型
*
* @param out_arr 输出数组
* @param[in] dl_val 分形计算的左下角端点值
* @param[in] dr_val 分形计算的右下角端点值
* @param[in] ul_val 分形计算的左上角端点值
* @param[in] ur_val 分形计算的右上角端点值
* @param[in] maxi_range 最大变化值
* @param[in] smoothness 变化光滑度
*/
void fractal_model_2d(_2d_matrix &out_arr, int r_size, int c_size, double dl_val,
double dr_val, double ul_val, double ur_val, double maxi_range, double smoothness, unsigned int seed = 0);
/**
* @brief 一维数组差分(使用二阶差分公式)
*
* 计算一个一维数组中相邻元素间的差分结果(求导)。
*
* @param[in] in 输入数组
* @param diff 输出的差分结果
* @param[in] spacing 相邻元素的距离
* @param[in] order 求导的次数。最小为1默认最大为4。两边的数据将分别使用对应的向前或向后差分公式
*/
void difference_1d(const array<double> &in, array<double> &diff, double spacing, int order = 1);
/**
* @brief 二维数组差分(使用二阶差分公式)
*
* 计算一个二维数组中相邻元素间的差分结果(求导)。
*
* @param[in] in 输入数组
* @param diff 输出的差分结果
* @param[in] spacing 相邻元素对应方向的距离
* @param[in] d_type 求导的类型
* @param[in] order 求导的次数。最小为1默认最大为4。边缘的数据将分别使用对应的向前或向后差分公式
*/
void difference_2d(const _2d_matrix &in, _2d_matrix &diff, double spacing, gradient_type_e d_type, int order = 1);
/**
* @brief 二维数组差分(使用二阶差分公式)
*
* 计算一个二维数组中相邻元素间的差分结果(求导)。数组以列优先的方式储存为一个一维数组
*
* @param[in] in 输入数组
* @param diff 输出的差分结果
* @param[in] row_size 数组二维排列的行数
* @param[in] col_size 数组二维排列的列数
* @param[in] spacing 相邻元素对应方向的距离
* @param[in] d_type 求导的类型
* @param[in] order 求导的次数。最小为1默认最大为4。边缘的数据将分别使用对应的向前或向后差分公式
*/
void difference_2d(const array<double> &in, array<double> &diff, int row_size, int col_size,
double spacing, gradient_type_e d_type, int order = 1);
};
#endif // _GCTL_GMATH_H