#include "StdAfx.h"
#include "GetElevation.h"

// tiff文件读取
#include "gdal_priv.h"  
#include "cpl_conv.h" //for CPLMalloc()

// boost-1.56:准C++标准库
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

#include <vector>
using namespace std;


// 定义高程图像存储结构体
#pragma  pack(1)
struct struDemPic
{
	struDemPic() 
	{
		pDEMData = NULL;
	};

	virtual ~struDemPic()
	{
		if (pDEMData != NULL)
		{
			delete[] pDEMData;
			pDEMData = NULL;
		}
	}

	signed short int *pDEMData;
	string           strDemName;
	double           adfGeoTransform[6];
	int              iXSize;
	int              iYSize;
};
#pragma  pack()

// 定义类型: DEM_PIC_LIST
typedef vector<struDemPic*>  DEM_PIC_LIST;

// 全局变量
DEM_PIC_LIST g_DemPicList;

// 基于经纬度 计算tif文件名称
string  GetDemName( const float fLonDeg, const float fLatDeg )
{
	string sLatLon; // 输出

	int iLon = (int) fLonDeg;
	int iLat = (int) fLatDeg;

	//判断经纬度在正常范围之内
	if ((fLonDeg < -180) || (fLonDeg > 180))
	{
		return "";
	}

	if ((fLatDeg < -90) || (fLatDeg > 90))
	{
		return "";
	}

	string sLat, sLon;
	

	// 纬度 南北纬 区别对待
	boost::format fmt("S%02d");
	if (fLatDeg <= 0)
	{
		fmt % ((-iLat) + 1);
		sLat = fmt.str();
	}
	else
	{
		fmt = boost::format("N%02d");
		fmt % iLat;
		sLat = fmt.str();
	}

	// 经度 东西经 区别对待
	if (fLonDeg <= 0)
	{
		fmt = boost::format("W%03d");
		fmt % ((-iLon) + 1);
		sLon = fmt.str();
	}
	else
	{
		fmt = boost::format("E%03d");
		fmt % iLon;
		sLon = fmt.str();
	}

	sLatLon = "ASTGTM_" + sLat + sLon + "_dem.tif";
	return sLatLon;
}


//  搜寻文件路径是否已经存在
int FindDemDataSet( const string strDemName )
{
	for ( unsigned int i = 0; i < g_DemPicList.size(); i++ )
	{
		if ( g_DemPicList[i]->strDemName == strDemName )
		{
			return i;
		}
	}
	return -1;
}

bool GetDem( float& fElevator, const float fLonDeg, const float fLatDeg, struDemPic* pDemPic )
{
	// 空值判断
	if (pDemPic == NULL)
	{
		return false;
	}

	// 分辨率 判断
	if (pDemPic->adfGeoTransform[1] <= 0 || pDemPic->adfGeoTransform[5] >= 0)
	{
		return false;
	}

	// 计算像素坐标
	float px = float(( fLonDeg - pDemPic->adfGeoTransform[0] ) / pDemPic->adfGeoTransform[1]);
	float py = float(( pDemPic->adfGeoTransform[3] - fLatDeg ) / fabs(pDemPic->adfGeoTransform[5]));

	//防止越界
	if ((px < 0) || (px > pDemPic->iXSize - 1) || 
		(py < 0) || ( py > pDemPic->iYSize - 1))
	{
		return false;
	}

	// 规则:双线性内插 计算高程值
	int yt = 0, yb = 0; // y 上下
	int	xl = 0, xr = 0; // x 左右

	yt = int(py);
	yb = yt + 1;
	xl = int(px);
	xr = xl + 1;

	if ((xl < 0) || (xl > pDemPic->iXSize - 1) || 
		(xr < 0) || (xr > pDemPic->iYSize - 1))
	{
		return false;
	}

	if ((yt < 0) || (yt > pDemPic->iXSize - 1) || 
		(yb < 0) || (yb > pDemPic->iYSize - 1))
	{
		return false;
	}

	// 相邻四个像素的值
	signed short int DNlt = *(pDemPic->pDEMData + yt * pDemPic->iXSize + xl);
	signed short int DNrt = *(pDemPic->pDEMData + yt * pDemPic->iXSize + xr);
	signed short int DNlb = *(pDemPic->pDEMData + yb * pDemPic->iXSize + xl);
	signed short int DNrb = *(pDemPic->pDEMData + yb * pDemPic->iXSize + xr);

	// 间距
	float h, v;
	h = py - yt;
	v = px - xl;

	fElevator = DNlt * (1 - h) * (1 - v) + DNlb * h * (1 - v)+ DNrt * (1 - h) * v + DNrb * h * v;

	return true;
}



// 获取高程
bool GetDem( float& fElevator, float fLonDeg, float fLatDeg, string sDir)
{
	// tif文件 名称
	string strName = GetDemName(fLonDeg, fLatDeg);
	if (strName == "")
	{
		return false;
	}

	// tif文件 路径名称
	string strPathName; 

	if (sDir != "")
	{
		strPathName = sDir + "\\" + strName;
	}
	else
	{
		return false;
	}


	// 是否能在记录中找到
	int idx = FindDemDataSet(strPathName);
	if (idx >= 0)
	{
		return GetDem(fElevator, fLonDeg, fLatDeg, g_DemPicList[idx]);;
	}

	//如果在数据集数组中找不到 读取文件并添加到数据集
	// 注册
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");

	GDALDataset* tempdata = NULL;
	tempdata = (GDALDataset*) GDALOpen(strPathName.c_str(), GA_ReadOnly);
	if ( tempdata != NULL )
	{
		GDALDataType dataType = tempdata->GetRasterBand(1)->GetRasterDataType();
		int iXSzie = tempdata->GetRasterBand(1)->GetXSize();
		int iYSzie = tempdata->GetRasterBand(1)->GetYSize();
		struDemPic* temp = new struDemPic;
		temp->iXSize = iXSzie;
		temp->iYSize = iYSzie;
		tempdata->GetGeoTransform(temp->adfGeoTransform);
		temp->pDEMData = new signed short int[iXSzie * iYSzie];

		memset((void*) temp->pDEMData, 0, iXSzie * iYSzie * sizeof(signed short int));
		tempdata->GetRasterBand(1)->RasterIO( GF_Read, 0, 0, iXSzie, iYSzie, temp->pDEMData, iXSzie, iYSzie, GDT_Int16, 0, 0 );
		GDALClose(tempdata);

		// 入队 存储
		temp->strDemName = strPathName;
		g_DemPicList.push_back(temp);

		return GetDem(fElevator, fLonDeg, fLatDeg, g_DemPicList[g_DemPicList.size() - 1]);;
	}
	return false;
}


//功能:释放资源
void ReleaseDemMemory()
{
	// 高程数集
	for (unsigned int i = 0; i < g_DemPicList.size(); i++ )
	{
		if ( g_DemPicList[i] != NULL )
		{
			delete g_DemPicList[i];
		}
	}
	g_DemPicList.clear();
}