534 lines
19 KiB
C++
534 lines
19 KiB
C++
/********************************************************
|
|
* ██████╗ ██████╗████████╗██╗
|
|
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
|
* ██║ ███╗██║ ██║ ██║
|
|
* ██║ ██║██║ ██║ ██║
|
|
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
|
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
|
* 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.
|
|
******************************************************/
|
|
|
|
#include "interpolate.h"
|
|
|
|
//一维线性插值
|
|
double gctl::line_interpolate(double x1,double x2,double y1,double y2,double x)
|
|
{
|
|
if (x1 == x2) return 0.5*(y1 + y2);
|
|
else return (x - x1)*(y2 -y1)/(x2 - x1) + y1;
|
|
}
|
|
|
|
double gctl::line_interpolate(double xmin, double xmax, const array<double> &y_arr, double x)
|
|
{
|
|
int ynum = y_arr.size();
|
|
double dx = (xmax - xmin)/(ynum - 1);
|
|
int ix = floor((x - xmin)/dx);
|
|
|
|
return line_interpolate(xmin + ix*dx, xmin + (ix+1)*dx, y_arr[ix], y_arr[ix+1], x);
|
|
}
|
|
|
|
double gctl::line_interpolate(const array<double> &x_arr, const array<double> &y_arr, double x)
|
|
{
|
|
if (x_arr.size() != y_arr.size() || x_arr.empty() || y_arr.empty())
|
|
throw std::runtime_error("[gctl::line_interpolate] Invalid array sizes.");
|
|
|
|
for (size_t i = 0; i < x_arr.size() - 1; i++)
|
|
{
|
|
if (x_arr[i] > x_arr[i+1])
|
|
{
|
|
throw std::runtime_error("[gctl::line_interpolate] Invalid x coordinates.");
|
|
}
|
|
}
|
|
|
|
if (x_arr.front() >= x) return y_arr.front();
|
|
if (x_arr.back() <= x) return y_arr.back();
|
|
|
|
for (size_t i = 0; i < x_arr.size() - 1; i++)
|
|
{
|
|
if (x_arr[i] < x && x <= x_arr[i+1])
|
|
{
|
|
return line_interpolate(x_arr[i], x_arr[i+1], y_arr[i], y_arr[i+1], x);
|
|
}
|
|
}
|
|
|
|
return y_arr.front();
|
|
}
|
|
|
|
/*
|
|
lat
|
|
|
|
|
|
|
|
h21----h22
|
|
| |
|
|
| |
|
|
h11----h12----> lon
|
|
*/
|
|
// 球面双线性插值函数 单位为弧度 注意纬度为余纬度
|
|
double gctl::sph_linear_interpolate(double CoLat1, double CoLat2, double Lon1, double Lon2,
|
|
double CoLat0, double Lon0, double h11, double h12, double h21, double h22)
|
|
{
|
|
double Delta=(Lon2-Lon1)*(cos(CoLat2)-cos(CoLat1));
|
|
double A=(Lon1*(h12-h22)+Lon2*(h21-h11))/Delta;
|
|
double B=(cos(CoLat1)*(h21-h22)+cos(CoLat2)*(h12-h11))/Delta;
|
|
double C=(h11+h22-h21-h12)/Delta;
|
|
double D=(Lon2*cos(CoLat2)*h11-Lon2*cos(CoLat1)*h21+Lon1*cos(CoLat1)*h22-Lon1*cos(CoLat2)*h12)/Delta;
|
|
double h0=A*cos(CoLat0)+B*Lon0+C*Lon0*cos(CoLat0)+D;
|
|
return h0;
|
|
}
|
|
|
|
/*
|
|
lat
|
|
|
|
|
|
|
|
h21----h22
|
|
| |
|
|
| |
|
|
h11----h12----> lon
|
|
*/
|
|
// 球面双线性插值函数 以度为单位的版本 注意纬度为余纬度
|
|
double gctl::sph_linear_interpolate_deg(double CoLat1,double CoLat2,double Lon1,double Lon2,
|
|
double CoLat0,double Lon0,double h11,double h12,double h21,double h22)
|
|
{
|
|
double Delta=(Lon2-Lon1)*(cosd(CoLat2)-cosd(CoLat1));
|
|
double A=(Lon1*(h12-h22)+Lon2*(h21-h11))/Delta;
|
|
double B=(cosd(CoLat1)*(h21-h22)+cosd(CoLat2)*(h12-h11))/Delta;
|
|
double C=(h11+h22-h21-h12)/Delta;
|
|
double D=(Lon2*cosd(CoLat2)*h11-Lon2*cosd(CoLat1)*h21+Lon1*cosd(CoLat1)*h22-Lon1*cosd(CoLat2)*h12)/Delta;
|
|
double h0=A*cosd(CoLat0)+B*Lon0+C*Lon0*cosd(CoLat0)+D;
|
|
return h0;
|
|
}
|
|
|
|
//规则网络插值 长方形内数据插值 距离平方反比
|
|
/*长方体示意图*/
|
|
// y
|
|
// |
|
|
// |
|
|
// 3------------2
|
|
// | |
|
|
// | |
|
|
// | |
|
|
// 0------------1--->x
|
|
// 左下角坐标x0 y0
|
|
// 块体尺寸dx dy
|
|
// 插值点坐标x y
|
|
// 四个角点值
|
|
double gctl::rect_interpolate(double x0,double y0,double dx,double dy,double x,double y,
|
|
double d0,double d1,double d2,double d3, double p)
|
|
{
|
|
double res = 0;
|
|
double total_dist = 0;
|
|
double dist[4] = {0,0,0,0};
|
|
double val[4];
|
|
val[0] = d0; val[1] = d1; val[2] = d2; val[3] = d3;
|
|
dist[0] = 1.0/(1e-30 + pow((x-x0)*(x-x0)+(y-y0)*(y-y0), 0.5*p));
|
|
dist[1] = 1.0/(1e-30 + pow((x-dx-x0)*(x-dx-x0)+(y-y0)*(y-y0), 0.5*p));
|
|
dist[2] = 1.0/(1e-30 + pow((x-dx-x0)*(x-dx-x0)+(y-dy-y0)*(y-dy-y0), 0.5*p));
|
|
dist[3] = 1.0/(1e-30 + pow((x-x0)*(x-x0)+(y-dy-y0)*(y-dy-y0), 0.5*p));
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
total_dist += dist[i];
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
res += val[i]*dist[i]/total_dist;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
//规则网络插值 六面体内数据插值 距离平方反比
|
|
/*六面体示意图*/
|
|
// y
|
|
// /
|
|
// /
|
|
// 3------------2
|
|
// /| /|
|
|
// / | / |
|
|
// 0------------1------> x
|
|
// | 7 | 6
|
|
// | / | /
|
|
// |/ |/
|
|
// 4------------5
|
|
// |
|
|
// |
|
|
// z
|
|
// 左上角坐标x0 y0 z0
|
|
// 块体尺寸dx dy dz
|
|
// 插值点坐标x y z
|
|
// 八个角点值
|
|
double gctl::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)
|
|
{
|
|
double res = 0.0;
|
|
double total_dist = 0;
|
|
double dist[8] = {0,0,0,0,0,0,0,0};
|
|
double val[8];
|
|
val[0] = d0; val[1] = d1; val[2] = d2; val[3] = d3;
|
|
val[4] = d4; val[5] = d5; val[6] = d6; val[7] = d7;
|
|
//计算八个角点与待插值点的距离信息
|
|
dist[0] = 1.0/(1e-30+(x-x0)*(x-x0)+(y-y0)*(y-y0)+(z-z0)*(z-z0));
|
|
dist[1] = 1.0/(1e-30+(x-dx-x0)*(x-dx-x0)+(y-y0)*(y-y0)+(z-z0)*(z-z0));
|
|
dist[2] = 1.0/(1e-30+(x-dx-x0)*(x-dx-x0)+(y-dy-y0)*(y-dy-y0)+(z-z0)*(z-z0));
|
|
dist[3] = 1.0/(1e-30+(x-x0)*(x-x0)+(y-dy-y0)*(y-dy-y0)+(z-z0)*(z-z0));
|
|
dist[4] = 1.0/(1e-30+(x-x0)*(x-x0)+(y-y0)*(y-y0)+(z-dz-z0)*(z-dz-z0));
|
|
dist[5] = 1.0/(1e-30+(x-dx-x0)*(x-dx-x0)+(y-y0)*(y-y0)+(z-dz-z0)*(z-dz-z0));
|
|
dist[6] = 1.0/(1e-30+(x-dx-x0)*(x-dx-x0)+(y-dy-y0)*(y-dy-y0)+(z-dz-z0)*(z-dz-z0));
|
|
dist[7] = 1.0/(1e-30+(x-x0)*(x-x0)+(y-dy-y0)*(y-dy-y0)+(z-dz-z0)*(z-dz-z0));
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
total_dist += dist[i];
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
res += val[i]*dist[i]/total_dist;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
//球坐标下规则网络插值 六面体内数据插值
|
|
/*六面体示意图*/
|
|
// lat
|
|
// /
|
|
// /
|
|
// 7------------6
|
|
// /| /|
|
|
// / | / |
|
|
// 4------------5------> lon
|
|
// | 3 | 2
|
|
// | / | /
|
|
// |/ |/
|
|
// 0------------1
|
|
// |
|
|
// |
|
|
// rad
|
|
// 左下角坐标lon0 lat0 rad0
|
|
// 块体尺寸dlon dlat drad
|
|
// 插值点坐标lon lat rad
|
|
// 八个角点值
|
|
double gctl::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)
|
|
{
|
|
double d04 = line_interpolate(rad0, rad0+drad, d0, d4, rad);
|
|
double d15 = line_interpolate(rad0, rad0+drad, d1, d5, rad);
|
|
double d26 = line_interpolate(rad0, rad0+drad, d2, d6, rad);
|
|
double d37 = line_interpolate(rad0, rad0+drad, d3, d7, rad);
|
|
return sph_linear_interpolate_deg(90.0-lat0, 90.0-lat0-dlat, lon0, lon0+dlon, 90.0-lat, lon,
|
|
d04, d15, d37, d26);
|
|
}
|
|
|
|
gctl::array<double> *gctl::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)
|
|
{
|
|
if (out_posi == nullptr || in_posi == nullptr || in_val == nullptr)
|
|
throw domain_error("Invalid pointer. Thrown by gctl::p2p_dist_2d(...)");
|
|
|
|
if (out_num < 0 || in_num < 0)
|
|
throw invalid_argument("Negative array sizes. Thrown by gctl::p2p_dist_2d(...)");
|
|
|
|
if (search_xlen <= 0 || search_ylen <= 0)
|
|
throw invalid_argument("Negative search lengths. Thrown by gctl::p2p_dist_2d(...)");
|
|
|
|
// 将输入数据装入很多排列整齐的小盒子 盒子的边长为搜索半径中较大的值
|
|
double box_len = GCTL_MAX(search_xlen, search_ylen);
|
|
// 找出盒子的边界范围
|
|
double box_xmin = GCTL_BDL_MAX, box_xmax = GCTL_BDL_MIN;
|
|
double box_ymin = GCTL_BDL_MAX, box_ymax = GCTL_BDL_MIN;
|
|
for (int i = 0; i < in_num; i++)
|
|
{
|
|
box_xmin = GCTL_MIN(box_xmin, in_posi[i].x);
|
|
box_xmax = GCTL_MAX(box_xmax, in_posi[i].x);
|
|
box_ymin = GCTL_MIN(box_ymin, in_posi[i].y);
|
|
box_ymax = GCTL_MAX(box_ymax, in_posi[i].y);
|
|
}
|
|
// 计算盒子的维度 注意这里是盒子的维度 不是盒子顶点的维度 将盒子的维度往上下左右各推出一格
|
|
int box_xnum = std::ceil((box_xmax - box_xmin)/box_len) + 2;
|
|
int box_ynum = std::ceil((box_ymax - box_ymin)/box_len) + 2;
|
|
// 对盒子的范围重新赋值
|
|
box_xmin -= box_len; box_xmax += box_len;
|
|
box_ymin -= box_len; box_ymax += box_len;
|
|
// 初始化盒子内的顶点列表
|
|
std::vector<std::vector<int> > box_list(box_xnum*box_ynum);
|
|
// 将输入顶点装入盒子内
|
|
int tmp_m, tmp_n;
|
|
for (int i = 0; i < in_num; i++)
|
|
{
|
|
tmp_m = std::floor((in_posi[i].x - box_xmin)/box_len);
|
|
tmp_n = std::floor((in_posi[i].y - box_ymin)/box_len);
|
|
|
|
box_list[tmp_m + tmp_n * box_xnum].push_back(i);
|
|
}
|
|
|
|
// 下面开始计算规则节点的数值
|
|
array<double> *out_val = new array<double>(out_num, NAN);
|
|
std::vector<double> dist_list, val_list;
|
|
int tmp_id, search_id;
|
|
double x_ang, tmp_dist;
|
|
for (int i = 0; i < out_num; i++)
|
|
{
|
|
dist_list.clear();
|
|
val_list.clear();
|
|
|
|
// 计算节点在盒子中的位置
|
|
tmp_m = std::floor((out_posi[i].x - box_xmin)/box_len);
|
|
tmp_n = std::floor((out_posi[i].y - box_ymin)/box_len);
|
|
// 在节点所在的盒子以及相邻的盒子内查找搜索半径内的数据点
|
|
for (int n = -1; n <= 1; n++)
|
|
{
|
|
for (int m = -1; m <= 1; m++)
|
|
{
|
|
if (tmp_m+m >= 0 && tmp_m+m <= box_xnum-1 &&
|
|
tmp_n+n >= 0 && tmp_n+n <= box_ynum-1)
|
|
{
|
|
//当前盒子的索引号
|
|
search_id = tmp_m + m + (tmp_n + n)*box_xnum;
|
|
// 循环当前盒子内的输入点
|
|
for (int b = 0; b < box_list[search_id].size(); b++)
|
|
{
|
|
tmp_id = box_list[search_id][b];
|
|
// 如果点到节点的距离小于椭球的半径则添加到向量中
|
|
tmp_dist = distance(out_posi[i], in_posi[tmp_id]);
|
|
x_ang = std::atan2(in_posi[tmp_id].y - out_posi[i].y,
|
|
in_posi[tmp_id].x - out_posi[i].x);
|
|
|
|
if (tmp_dist <= ellipse_radius_2d(search_xlen, search_ylen, search_deg, x_ang))
|
|
{
|
|
dist_list.push_back(tmp_dist);
|
|
val_list.push_back(in_val[tmp_id]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dist_list.empty())
|
|
out_val->at(i) = dist_inverse_weight(&dist_list, &val_list, 2);
|
|
}
|
|
|
|
destroy_vector(box_list);
|
|
return out_val;
|
|
}
|
|
|
|
gctl::array<double> *gctl::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)
|
|
{
|
|
if (out_posi == nullptr || in_posi == nullptr || in_val == nullptr)
|
|
throw domain_error("Invalid pointer. Thrown by gctl::p2p_dist(...)");
|
|
|
|
if (out_num < 0 || in_num < 0)
|
|
throw invalid_argument("Negative array sizes. Thrown by gctl::p2p_dist(...)");
|
|
|
|
if (search_xlen <= 0 || search_ylen <= 0 || search_zlen <= 0)
|
|
throw invalid_argument("Negative search lengths. Thrown by gctl::p2p_dist(...)");
|
|
|
|
// 将输入数据装入很多排列整齐的小盒子 盒子的边长为搜索半径中较大的值
|
|
double box_len = GCTL_MAX(GCTL_MAX(search_xlen, search_ylen), search_zlen);
|
|
// 找出盒子的边界范围
|
|
double box_xmin = GCTL_BDL_MAX, box_xmax = GCTL_BDL_MIN;
|
|
double box_ymin = GCTL_BDL_MAX, box_ymax = GCTL_BDL_MIN;
|
|
double box_zmin = GCTL_BDL_MAX, box_zmax = GCTL_BDL_MIN;
|
|
for (int i = 0; i < in_num; i++)
|
|
{
|
|
box_xmin = GCTL_MIN(box_xmin, in_posi[i].x);
|
|
box_xmax = GCTL_MAX(box_xmax, in_posi[i].x);
|
|
box_ymin = GCTL_MIN(box_ymin, in_posi[i].y);
|
|
box_ymax = GCTL_MAX(box_ymax, in_posi[i].y);
|
|
box_zmin = GCTL_MIN(box_zmin, in_posi[i].z);
|
|
box_zmax = GCTL_MAX(box_zmax, in_posi[i].z);
|
|
}
|
|
// 计算盒子的维度 注意这里是盒子的维度 不是盒子顶点的维度 将盒子的维度往上下左右各推出一格
|
|
int box_xnum = std::ceil((box_xmax - box_xmin)/box_len) + 2;
|
|
int box_ynum = std::ceil((box_ymax - box_ymin)/box_len) + 2;
|
|
int box_znum = std::ceil((box_zmax - box_zmin)/box_len) + 2;
|
|
// 对盒子的范围重新赋值
|
|
box_xmin -= box_len; box_xmax += box_len;
|
|
box_ymin -= box_len; box_ymax += box_len;
|
|
box_zmin -= box_len; box_zmax += box_len;
|
|
// 初始化盒子内的顶点列表
|
|
std::vector<std::vector<int> > box_list(box_xnum*box_ynum*box_znum);
|
|
// 将输入顶点装入盒子内
|
|
int tmp_m, tmp_n, tmp_k;
|
|
for (int i = 0; i < in_num; i++)
|
|
{
|
|
tmp_m = std::floor((in_posi[i].x - box_xmin)/box_len);
|
|
tmp_n = std::floor((in_posi[i].y - box_ymin)/box_len);
|
|
tmp_k = std::floor((in_posi[i].z - box_zmin)/box_len);
|
|
|
|
box_list[tmp_m + tmp_n*box_xnum + tmp_k*box_xnum*box_ynum].push_back(i);
|
|
}
|
|
|
|
// 下面开始计算规则节点的数值
|
|
array<double> *out_val = new array<double>(out_num, NAN);
|
|
std::vector<double> dist_list, val_list;
|
|
int tmp_id, search_id;
|
|
double x_ang, z_ang, tmp_dist;
|
|
for (int i = 0; i < out_num; i++)
|
|
{
|
|
dist_list.clear();
|
|
val_list.clear();
|
|
|
|
// 计算节点在盒子中的位置
|
|
tmp_m = std::floor((out_posi[i].x - box_xmin)/box_len);
|
|
tmp_n = std::floor((out_posi[i].y - box_ymin)/box_len);
|
|
tmp_k = std::floor((out_posi[i].z - box_zmin)/box_len);
|
|
// 在节点所在的盒子以及相邻的盒子内查找搜索半径内的数据点
|
|
for (int k = -1; k <= 1; k++)
|
|
{
|
|
for (int n = -1; n <= 1; n++)
|
|
{
|
|
for (int m = -1; m <= 1; m++)
|
|
{
|
|
if (tmp_m+m >= 0 && tmp_m+m <= box_xnum-1 &&
|
|
tmp_n+n >= 0 && tmp_n+n <= box_ynum-1 &&
|
|
tmp_k+k >= 0 && tmp_k+k <= box_znum-1)
|
|
{
|
|
//当前盒子的索引号
|
|
search_id = tmp_m + m + (tmp_n + n)*box_xnum + (tmp_k + k)*box_xnum*box_ynum;
|
|
// 循环当前盒子内的输入点
|
|
for (int b = 0; b < box_list[search_id].size(); b++)
|
|
{
|
|
tmp_id = box_list[search_id][b];
|
|
// 如果点到节点的距离小于椭球的半径则添加到向量中
|
|
tmp_dist = distance(out_posi[i], in_posi[tmp_id]);
|
|
x_ang = std::atan2(in_posi[tmp_id].y - out_posi[i].y,
|
|
in_posi[tmp_id].x - out_posi[i].x);
|
|
z_ang = std::acos((in_posi[tmp_id].z - out_posi[i].z)/tmp_dist);
|
|
|
|
if (tmp_dist <= ellipsoid_radius(search_xlen, search_ylen, search_zlen, x_ang, z_ang))
|
|
{
|
|
dist_list.push_back(tmp_dist);
|
|
val_list.push_back(in_val[tmp_id]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dist_list.empty())
|
|
out_val->at(i) = dist_inverse_weight(&dist_list, &val_list, 2);
|
|
}
|
|
|
|
destroy_vector(box_list);
|
|
return out_val;
|
|
}
|
|
|
|
gctl::array<double> *gctl::p2p_dist_sph(point3ds * out_posi, int out_num, point3ds *in_posi,
|
|
double *in_val, int in_num, double search_rlen, double search_deg)
|
|
{
|
|
if (out_posi == nullptr || in_posi == nullptr || in_val == nullptr)
|
|
throw domain_error("Invalid pointer. Thrown by gctl::p2p_dist_sph(...)");
|
|
|
|
if (out_num < 0 || in_num < 0)
|
|
throw invalid_argument("Negative array sizes. Thrown by gctl::p2p_dist_sph(...)");
|
|
|
|
if (search_rlen <= 0 || search_deg <= 0)
|
|
throw invalid_argument("Negative search lengths. Thrown by gctl::p2p_dist_sph(...)");
|
|
|
|
// 找出盒子的边界范围
|
|
double box_lonmin = GCTL_BDL_MAX, box_lonmax = GCTL_BDL_MIN;
|
|
double box_latmin = GCTL_BDL_MAX, box_latmax = GCTL_BDL_MIN;
|
|
double box_radmin = GCTL_BDL_MAX, box_radmax = GCTL_BDL_MIN;
|
|
for (int i = 0; i < in_num; i++)
|
|
{
|
|
box_lonmin = GCTL_MIN(box_lonmin, in_posi[i].lon);
|
|
box_lonmax = GCTL_MAX(box_lonmax, in_posi[i].lon);
|
|
box_latmin = GCTL_MIN(box_latmin, in_posi[i].lat);
|
|
box_latmax = GCTL_MAX(box_latmax, in_posi[i].lat);
|
|
box_radmin = GCTL_MIN(box_radmin, in_posi[i].rad);
|
|
box_radmax = GCTL_MAX(box_radmax, in_posi[i].rad);
|
|
}
|
|
// 计算盒子的维度 注意这里是盒子的维度 不是盒子顶点的维度 将盒子的维度往上下左右各推出一格
|
|
int box_lonnum = std::ceil((box_lonmax - box_lonmin)/search_deg) + 2;
|
|
int box_latnum = std::ceil((box_latmax - box_latmin)/search_deg) + 2;
|
|
int box_radnum = std::ceil((box_radmax - box_radmin)/search_rlen) + 2;
|
|
// 对盒子的范围重新赋值
|
|
box_lonmin -= search_deg; box_lonmax += search_deg;
|
|
box_latmin -= search_deg; box_latmax += search_deg;
|
|
box_radmin -= search_rlen; box_radmax += search_rlen;
|
|
// 初始化盒子内的顶点列表
|
|
std::vector<std::vector<int> > box_list(box_lonnum*box_latnum*box_radnum);
|
|
// 将输入顶点装入盒子内
|
|
int tmp_m, tmp_n, tmp_k;
|
|
for (int i = 0; i < in_num; i++)
|
|
{
|
|
tmp_m = std::floor((in_posi[i].lon - box_lonmin)/search_deg);
|
|
tmp_n = std::floor((in_posi[i].lat - box_latmin)/search_deg);
|
|
tmp_k = std::floor((in_posi[i].rad - box_radmin)/search_rlen);
|
|
|
|
box_list[tmp_m + tmp_n*box_lonnum + tmp_k*box_lonnum*box_latnum].push_back(i);
|
|
}
|
|
|
|
// 下面开始计算规则节点的数值
|
|
array<double> *out_val = new array<double>(out_num, NAN);
|
|
std::vector<double> dist_list, val_list;
|
|
int tmp_id, search_id;
|
|
double tmp_dist;
|
|
point3dc tmp_pc1, tmp_pc2;
|
|
for (int i = 0; i < out_num; i++)
|
|
{
|
|
dist_list.clear();
|
|
val_list.clear();
|
|
|
|
// 计算节点在盒子中的位置
|
|
tmp_m = std::floor((out_posi[i].lon - box_lonmin)/search_deg);
|
|
tmp_n = std::floor((out_posi[i].lat - box_latmin)/search_deg);
|
|
tmp_k = std::floor((out_posi[i].rad - box_radmin)/search_rlen);
|
|
// 在节点所在的盒子以及相邻的盒子内查找搜索半径内的数据点
|
|
for (int k = -1; k <= 1; k++)
|
|
{
|
|
for (int n = -1; n <= 1; n++)
|
|
{
|
|
for (int m = -1; m <= 1; m++)
|
|
{
|
|
if (tmp_m+m >= 0 && tmp_m+m <= box_lonnum-1 &&
|
|
tmp_n+n >= 0 && tmp_n+n <= box_latnum-1 &&
|
|
tmp_k+k >= 0 && tmp_k+k <= box_radnum-1)
|
|
{
|
|
//当前盒子的索引号
|
|
search_id = tmp_m + m + (tmp_n + n)*box_lonnum + (tmp_k + k)*box_lonnum*box_latnum;
|
|
// 循环当前盒子内的输入点
|
|
for (int b = 0; b < box_list[search_id].size(); b++)
|
|
{
|
|
tmp_id = box_list[search_id][b];
|
|
// 如果点到节点的距离小于椭球的半径则添加到向量中
|
|
tmp_pc1 = s2c(out_posi[i]);
|
|
tmp_pc2 = s2c(in_posi[tmp_id]);
|
|
tmp_dist = distance(tmp_pc1, tmp_pc2);
|
|
|
|
if (geometry3d::angle(tmp_pc1, tmp_pc2) <= search_deg &&
|
|
std::fabs(in_posi[tmp_id].rad - out_posi[i].rad) <= search_rlen)
|
|
{
|
|
dist_list.push_back(tmp_dist);
|
|
val_list.push_back(in_val[tmp_id]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dist_list.empty())
|
|
out_val->at(i) = dist_inverse_weight(&dist_list, &val_list, 2);
|
|
}
|
|
|
|
destroy_vector(box_list);
|
|
return out_val;
|
|
} |