#ifndef _HEAD_FUNC_H
#define _HEAD_FUNC_H
#include "iostream"
#include "fstream"
#include "sstream"
#include "string.h"
#include "cmath"
#include "iomanip"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "vector"
#include "map"
#include "algorithm"
#include "ctime"
#include "omp.h"
#include "random"

using namespace std;

//数学常量
#define BDL_MAX 1e+30 ///< 定义变量的最大值
#define BDL_MIN -1e+30 ///< 定义变量的最小值
#define ZERO 1e-20 ///< 定义零值
//物理常量
#define Pi (4.0*atan(1.0)) ///< 圆周率
#define G0 6.67408e-3 ///< 万有引力常数。注意这里的量级本来应该是e-11，考虑到单位转换，取维度单位为m，密度单位为g/cm^3，乘以G0则重力单位即为mGal
#define T0 5e+4 ///< 地磁场平均强度
//宏函数
#define MAX(a,b) (a>b?a:b) ///< 返回a与b的最大值
#define MIN(a,b) (a<b?a:b) ///< 返回a与b的最小值
#define SetToBox(a,b,in) (MAX(a,MIN(b,in))) ///< 返回a与b之间的一个值，若in在a与b之间则直接返回，否则返回较近的边界值
//终端显示控制符
#define BOLDRED "\033[1m\033[31m" ///< 设置后续字符字体为红色加粗
#define BOLDGREEN "\033[1m\033[32m" ///< 设置后续字符字体为绿色加粗
#define BOLDYELLOW "\033[1m\033[33m" ///< 设置后续字符字体为黄色加粗
#define BOLDBLUE "\033[1m\033[34m" ///< 设置后续字符字体为蓝色加粗
#define UNDERLINE "\033[1m\033[4m" ///< 设置后续字符为添加下划线
#define RESET "\033[0m" ///< 重置字符设置
#define MOVEUP(x) printf("\033[%dA", (x)) ///< 将光标向上挪x行
#define MOVEDOWN(x) printf("\033[%dB", (x)) ///< 将光标向下娜x行
#define MOVELEFT(x) printf("\033[%dD", (x)) ///< 将光标向左娜x字符
#define MOVERIGHT(x) printf("\033[%dC", (x)) ///< 将光标向右娜x字符
#define MOVETO(y,x) printf("\033[%d;%dH", (y), (x)) ///< 将光标向右娜动y字符,向上挪动x字符
#define CLEARLINE "\033[K" ///< 清除本行
#define CLEARALL "\033[2J" ///< 清除终端满屏
//数据结构
typedef vector<int> _1iArray; ///< 整形一维向量
typedef vector<double> _1dArray; ///< 双精度浮点一维向量
typedef vector<string> _1sArray; ///< 字符串一维向量
typedef vector<vector<int> > _2iArray; ///< 整形浮点二维向量
typedef vector<vector<double> > _2dArray; ///< 双精度浮点二维向量
typedef map<int,int> int2intMap; ///< 整型到整形的映射
/**
 * @brief      点结构体
 * 
 * 直角坐标系下的一个实点，包含该点的坐标位置与点的编号。
 */
struct cpoint{
	int id = -1; ///< 点的索引值。初始值为-1，一般从0开始标号。
	double x = BDL_MAX; ///< 点的x坐标值。
	double y = BDL_MAX; ///< 点的y坐标值。
	double z = BDL_MAX; ///< 点的z坐标值。
};
/**
 *@brief cpoint结构体的向量。
 */
typedef vector<cpoint> cpointArray;
/**
 * @brief 观测点结构体
 * 
 * 直角坐标系下的一个观测点。该结构体由cpoint继承而来，增加了观测点的数值val与不确定度dev。
 */
struct obspoint : cpoint{
	double val = BDL_MAX; ///< 标量观测值，初始值为BDL_MAX。
	double dev = BDL_MAX; ///< 观测值的不确定度，初始值为BDL_MAX。
};
/**
 * @brief obspoint结构体的向量。
 */
typedef vector<obspoint> obspointArray;
/**
 * @brief      方块结构体
 * 
 * 直角坐标系下表示一个方块的结构体。
 */
struct block{
	int id = -1; ///< 块体的索引。初始值为-1，一般从0开始编号。
	int phy_group = -1; ///< 块体所属的物理组编号。初始值为-1。
	int vert[4] = {-1,-1,-1,-1}; ///< 块体的四个角点的索引值。初始值均为-1。
	double xmin = BDL_MAX; ///< 块体在x坐标轴的最小值。
	double xmax = BDL_MIN; ///< 块体在x坐标轴的最大值。
	double ymin = BDL_MAX; ///< 块体在y坐标轴的最小值。
	double ymax = BDL_MIN; ///< 块体在y坐标轴的最大值。
	double zmin = BDL_MAX; ///< 块体在z坐标轴的最小值。
	double zmax = BDL_MIN; ///< 块体在z坐标轴的最大值。
};
/**
 * @brief block结构体的向量
 */
typedef vector<block> blockArray;
/*************************矢量函数********************************/
/**
 * @brief      矢量减法
 *
 * @param[in]  <unnamed>  输入向量
 * @param[in]  <unnamed>  输入向量
 *
 * @return     两个向量的差值。
 */
cpoint operator -(cpoint,cpoint);
/**
 * @brief      矢量数乘法
 *
 * @param[in]  <unnamed>  输入标量值
 * @param[in]  <unnamed>  输入向量
 *
 * @return     标量与向量的乘积
 */
cpoint operator *(double,cpoint);
/**
 * @brief      求一个矢量的模
 *
 * @param[in]  <unnamed>  输入向量
 *
 * @return     向量的模
 */
double modCpoint(cpoint);
/**
 * @brief      求两个向量的夹角
 *
 * @param[in]  <unnamed>  输入向量
 * @param[in]  <unnamed>  输入向量
 *
 * @return     输入向量的夹角
 */
double angCpoint(cpoint,cpoint);
/*************************全局函数********************************/
/**
 * @brief      返回反正切角
 *
 * @param[in]  <unnamed>  一个double类型的浮点值
 *
 * @return     一个double类型的浮点值
 */
double arctg(double);
/**
 * @brief      将string转换为stringstream
 *
 * @param[in]  <unnamed>  输入字符串
 *
 * @return     CString类型字符串
 */
stringstream str2ss(string);
/**
 * @brief      打开输入文件并返回执行情况
 *
 * @param      <unnamed>  ifstream对象
 * @param      <unnamed>  文件名
 *
 * @return     执行成功返回0，不成功则返回-1并输出错误信息。
 */
int open_infile(ifstream&, const char*);
/**
 * @brief      打开输出文件并返回执行情况	
 *
 * @param      <unnamed>  ofstream对象
 * @param      <unnamed>  文件名
 *
 * @return     执行成功返回0，不成功则返回-1并输出错误信息。
 */
int open_outfile(ofstream&, const char*);
/**
 * @brief      规则网格内插值
 *
 * @param[in]  <unnamed>  输入参数
 *
 * @return     给定点位的插值
 */
double cube_interpolate(double, double, double, double, double, double, double, double, double, double); //四方块内的双线性插值
#endif