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

#include "geometry3d.h"

namespace gctl
{
    /**
	 * @brief      一维线性插值
	 *
	 * @param[in]  x1    x1值
	 * @param[in]  x2    x2值
	 * @param[in]  y1    y1值
	 * @param[in]  y2    y2值
	 * @param[in]  x     待插值点坐标
	 *
	 * @return     插值结果
	 */
	double line_interpolate(double x1, double x2, double y1, double y2, double x);

	/**
	 * @brief 一维线性插值 假设数据点是均匀分布的
	 * 
	 * @param xmin x的最小值
	 * @param xmax x的最大值
	 * @param y_arr 一维数据数组
	 * @param x 插值点
	 * @return 插值点的数值
	 */
	double line_interpolate(double xmin, double xmax, const array<double> &y_arr, double x);

	/**
	 * @brief 一维线性插值
	 * 
	 * @param x_arr 一维坐标数组（坐标值依次增加）
	 * @param y_arr 一维数据数组
	 * @param x 插值点
	 * @return 插值点的数值
	 */
	double line_interpolate(const array<double> &x_arr, const array<double> &y_arr, double x);

	/**
	 * @brief      球面双线性插值函数（单位为弧度）
	 * 
	 * @warning 注意纬度为余纬度
	 * 
	 * lat
	 * |
	 * |
	 * h21----h22
	 * |       |
	 * |       |
	 * h11----h12----> lon
	 *
	 * @param[in]  CoLat1  较大的余纬度
	 * @param[in]  CoLat2  较小的余纬度
	 * @param[in]  Lon1    自西向东较小的经度
	 * @param[in]  Lon2    自西向东较大的经度
	 * @param[in]  CoLat0  待插值点的余纬度
	 * @param[in]  Lon0    待插值点的经度
	 * @param[in]  h11     h11点值
	 * @param[in]  h12     h12点值
	 * @param[in]  h21     h21点值
	 * @param[in]  h22     h22点值
	 *
	 * @return     插值点值
	 */
	double sph_linear_interpolate(double CoLat1, double CoLat2, double Lon1, double Lon2, 
		double CoLat0, double Lon0, double h11, double h12, double h21, double h22);

	/**
	 * @brief      球面双线性插值函数 以度为单位的版本
	 * 
	 * @warning 注意纬度为余纬度
	 * 
	 * lat
	 * |
	 * |
	 * h21----h22
	 * |       |
	 * |       |
	 * h11----h12----> lon
	 *
	 * @param[in]  CoLat1  较大的余纬度
	 * @param[in]  CoLat2  较小的余纬度
	 * @param[in]  Lon1    自西向东较小的经度
	 * @param[in]  Lon2    自西向东较大的经度
	 * @param[in]  CoLat0  待插值点的余纬度
	 * @param[in]  Lon0    待插值点的经度
	 * @param[in]  h11     h11点值
	 * @param[in]  h12     h12点值
	 * @param[in]  h21     h21点值
	 * @param[in]  h22     h22点值
	 *
	 * @return     插值点值
	 */
	double sph_linear_interpolate_deg(double CoLat1, double CoLat2, double Lon1, double Lon2, 
		double CoLat0, double Lon0, double h11, double h12, double h21, double h22);

	/**
	 * @brief      规则网络插值 长方形内数据插值
	 * 
	 * @note 默认为距离平方反比
	 * 
	 * y
	 * |
	 * |
	 * d3-----------d2
	 * |            |
	 * |            |
	 * |            |
	 * d0-----------d1--->x
	 * 左下角坐标x0 y0
	 * 块体尺寸dx dy
	 * 插值点坐标x y
	 *
	 * @param[in]  x0    左下角坐标x0
	 * @param[in]  y0    左下角坐标y0
	 * @param[in]  dx    块体尺寸dx
	 * @param[in]  dy    块体尺寸dy
	 * @param[in]  x     待插值点x
	 * @param[in]  y     待插值点y
	 * @param[in]  d0    d0值
	 * @param[in]  d1    d1值
	 * @param[in]  d2    d2值
	 * @param[in]  d3    d3值
	 * @param[in]  p     距离次方值 默认为2
	 *
	 * @return     插值点值
	 */
	double rect_interpolate(double x0, double y0, double dx, double dy, double x, double y,
		double d0, double d1, double d2, double d3, double p = 2.0);

	/**
	 * @brief      规则网络插值 长方体内数据插值
	 * 
	 * @note 距离平方反比
	 * 
	 *        y
	 *       /
	 *      /
	 *     3------------2
	 *    /|           /|
	 *   / |          / |
	 *  0------------1------> x
	 *  |  7         |  6
	 *  | /          | /
	 *  |/           |/
	 *  4------------5
	 *  |
	 *  |
	 *  z
	 *  左上角坐标x0 y0 z0
	 *  块体尺寸dx dy dz
	 *  插值点坐标x y z
	 *  八个角点值
	 *
	 * @param[in]  x0    左上角坐标x0
	 * @param[in]  y0    左上角坐标y0
	 * @param[in]  z0    左上角坐标z0
	 * @param[in]  dx    块体尺寸dx
	 * @param[in]  dy    块体尺寸dy
	 * @param[in]  dz    块体尺寸dz
	 * @param[in]  x     插值点坐标x
	 * @param[in]  y     插值点坐标y
	 * @param[in]  z     插值点坐标z
	 * @param[in]  d0    角点值d0
	 * @param[in]  d1    角点值d1
	 * @param[in]  d2    角点值d2
	 * @param[in]  d3    角点值d3
	 * @param[in]  d4    角点值d4
	 * @param[in]  d5    角点值d5
	 * @param[in]  d6    角点值d6
	 * @param[in]  d7    角点值d7
	 *
	 * @return     插值点值
	 */
	double cube_interpolate(double x0, double y0, double z0, double dx, double dy, double dz, 
		double x, double y, double z, double d0, double d1, double d2, double d3, double d4, 
		double d5, double d6, double d7);

	/**
	 * @brief      球坐标下规则网络插值 Tesseroid 内数据插值
	 * 
	 * @note 首先是线性插值 然后是球面线性插值
	 * 
	 * 六面体示意图
	 *        lat
	 *       /
	 *      /
	 *     7------------6
	 *    /|           /|
	 *   / |          / |
	 *  4------------5------> lon
	 *  |  3         |  2
	 *  | /          | /
	 *  |/           |/
	 *  0------------1
	 *  |
	 *  |
	 *  rad
	 *  左下角坐标lon0 lat0 rad0
	 *  块体尺寸dlon dlat drad
	 *  插值点坐标lon lat rad
	 *  八个角点值
	 *
	 * @param[in]  lon0  左下角坐标rad0
	 * @param[in]  lat0  左下角坐标lat0
	 * @param[in]  rad0  左下角坐标rad0
	 * @param[in]  dlon  块体尺寸dlon
	 * @param[in]  dlat  块体尺寸dlat
	 * @param[in]  drad  块体尺寸drad
	 * @param[in]  lon   插值点坐标lon
	 * @param[in]  lat   插值点坐标lat
	 * @param[in]  rad   插值点坐标rad
	 * @param[in]  d0    角点值d0
	 * @param[in]  d1    角点值d1
	 * @param[in]  d2    角点值d2
	 * @param[in]  d3    角点值d3
	 * @param[in]  d4    角点值d4
	 * @param[in]  d5    角点值d5
	 * @param[in]  d6    角点值d6
	 * @param[in]  d7    角点值d7
	 *
	 * @return     插值点值
	 */
	double cube_interpolate_sph(double lon0, double lat0, double rad0, double dlon, double dlat, 
		double drad, double lon, double lat, double rad, double d0, double d1, double d2, 
		double d3, double d4, double d5, double d6, double d7);

	/**
	 * @brief      将随机位置的平面数据以距离平方反比的方式插值到输出节点位置上
	 * 
	 * @note       此函数的搜索区域形状为椭圆 适合用于二维直角坐标系下的数据规则化或者切割剖面等
	 *
	 * @param      out_posi      输出顶点位置指针
	 * @param[in]  out_num       输出顶点个数
	 * @param      in_posi       输入数据的位置指针
	 * @param      in_val        输入数据的数值指针
	 * @param[in]  in_num        输入数据的个数
	 * @param[in]  search_xlen   搜索椭圆的x轴长度
	 * @param[in]  search_ylen   搜索椭圆的y轴长度
	 * @param[in]  search_deg    搜索椭圆绕中心逆时针旋转的角度
	 *
	 * @return     规则节点位置的数值 排列顺序从左下上右上
	 */
	array<double> *p2p_dist_2d(point2dc * out_posi, int out_num, point2dc *in_posi, double *in_val, 
		int in_num, double search_xlen, double search_ylen, double search_deg);

	/**
	 * @brief      将随机位置的平面数据以距离平方反比的方式插值到输出节点位置上
	 * 
	 * @note       此函数的搜索区域形状为椭球 适合用于三维直角坐标系下的数据规则化或者切割剖面等
	 *
	 * @param      out_posi      输出顶点位置指针
	 * @param[in]  out_num       输出顶点个数
	 * @param      in_posi       输入数据的位置指针
	 * @param      in_val        输入数据的数值指针
	 * @param[in]  in_num        输入数据的个数
	 * @param[in]  search_xlen   搜索半径的x方向长度
	 * @param[in]  search_ylen   搜索半径的y方向长度
	 * @param[in]  search_zlen   搜索半径的z方向长度
	 *
	 * @return     规则节点位置的数值 排列顺序从左下上右上
	 */
	array<double> *p2p_dist(point3dc * out_posi, int out_num, point3dc *in_posi, double *in_val, 
		int in_num, double search_xlen, double search_ylen, double search_zlen);

	/**
	 * @brief      将随机位置的平面数据以距离平方反比的方式插值到输出节点位置上
	 * 
	 * @note       此函数的搜索区域形状为球面底的圆锥台 适合用于三维球坐标系下的数据规则化或者切割剖面等
	 *
	 * @param      out_posi      输出顶点位置指针
	 * @param[in]  out_num       输出顶点个数
	 * @param      in_posi       输入数据的位置指针
	 * @param      in_val        输入数据的数值指针
	 * @param[in]  in_num        输入数据的个数
	 * @param[in]  search_rlen   搜索区域的半径方向长度
	 * @param[in]  search_deg    搜索区域的球心角度大小
	 *
	 * @return     规则节点位置的数值 排列顺序从左下上右上
	 */
	array<double> *p2p_dist_sph(point3ds * out_posi, int out_num, point3ds *in_posi, double *in_val, 
		int in_num, double search_rlen, double search_deg);
};

#endif // _GCTL_INTERPOLATE_H