// DlgLightRegion.cpp : 实现文件
//

#include "stdafx.h"
#include "DlgLightRegion.h"
#include "afxdialogex.h"

#include "MapElevation.h"
#include<io.h>

MapElevation m_mapElevation2;

HWND g_hwndDlgLight = nullptr;

//计算地球上两点间的斜率(假定地球是圆的)
double CalSlopeBetweenTwoPoint(const double fromPtLon, const double fromPtLat, const float fromPtAlt, const double endPtLon, const double endPtLat, const float endPtAlt)
{
	double _distance = 0.0;
	CalculateTwoPtsDistance(_distance,fromPtLon,fromPtLat,endPtLon,endPtLat,3);

	//考虑大气折射等原因,地球半径乘以系数4/3,作为等效半径
	double _radiusEarth = 6371137.0 * 4/3;

	//求解两点在地球表面的投影点连成的弧线对应的圆心角,单位为弧度
	double _centralAngle = _distance/_radiusEarth;

	double _slope = 0.0,d1 = 0.0, d2 = 0.0;

	//从起始点处水平看向终点处,能看到的终点的高度
	double _compareAlt = ((_radiusEarth + fromPtAlt)/cos(_centralAngle) - _radiusEarth);

	//斜率为正
	if ( _compareAlt < endPtAlt)
	{
		_compareAlt = endPtAlt - _compareAlt;

		d1 = _compareAlt * cos(_centralAngle);

		d2 = (_radiusEarth + fromPtAlt) * tan(_centralAngle) + _compareAlt * sin(_centralAngle);

		_slope = d1/d2;
	}
	else //斜率为负
	{
		_compareAlt = _compareAlt - endPtAlt;

		d1 = _compareAlt * cos(_centralAngle);

		d2 = (_radiusEarth + fromPtAlt) * tan(_centralAngle) - _compareAlt * sin(_centralAngle);

		_slope = -d1/d2;
	}

	return _slope;
}

//已知地球A点经纬度高,以及B点和A点连线相对于水平方向的斜率,求B点的高度
double CalAltFromSlope(const double fromPtLon, const double fromPtLat, const float fromPtAlt, const double endPtLon, const double endPtLat,const double slope)
{
	double _distance = 0.0;
	CalculateTwoPtsDistance(_distance,fromPtLon,fromPtLat,endPtLon,endPtLat,3);

	//考虑大气折射等原因,地球半径乘以系数4/3,作为等效半径
	double _radiusEarth = 6371137.0 * 4/3;

	//求解两点在地球表面的投影点连成的弧线对应的圆心角,单位为弧度
	double _centralAngle = _distance/_radiusEarth;

	double endPtAlt = 0.0;

	if (slope > 0.0)
	{
		endPtAlt = (_radiusEarth + fromPtAlt) * tan(_centralAngle) * slope / (cos(_centralAngle)-(sin(_centralAngle)*slope));

		endPtAlt = ((_radiusEarth + fromPtAlt)/cos(_centralAngle) - _radiusEarth) + endPtAlt;
	}
	else
	{
		endPtAlt = (_radiusEarth + fromPtAlt) * tan(_centralAngle) * (-slope) / (cos(_centralAngle)+(sin(_centralAngle)*(-slope)));
		endPtAlt = ((_radiusEarth + fromPtAlt)/cos(_centralAngle) - _radiusEarth) - endPtAlt;
	}

	return endPtAlt;
}

/*-------------------------------------------------------------------------------------------------------------
说明:可视域分析
-------------------------------------------------------------------------------------------------------------*/
//可视域分析线程开启标志
volatile bool m_bRunRegion = false;

double g_dGroundLonTemp = 0.0;  //地面站经度
double g_dGroundLatTemp = 0.0;  //地面站纬度
float  g_fGroundAltTemp = 0.0;  //地面站高度
int    g_iFlightAlt = 0;        //飞行高度
int    g_iRegionRadius = 0;     //分析半径
int    g_iAnalysisStep = 0;     //分析角度

//线程函数,处理可视域分析
void ThreadFuncLightRegion()
{
	while(m_bRunRegion)
	{
		//依次完成地面站0~360度方向的通视分析,每执行一次,分析1度
		if ((g_iAnalysisStep >= 0) && (g_iAnalysisStep < 360))
		{
			if (false == AnalysisLightRegion(g_iAnalysisStep,g_iRegionRadius))
			{
				//高程信息不全,终止分析
				g_iAnalysisStep = -1;

				m_bRunRegion = false;

				//发送消息到对话框,提示高程信息不全
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)1,(LPARAM)-1);

				continue ;
			}
			else
			{
				//发送消息到对话框,更新可视域分析进度
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)1,(LPARAM)g_iAnalysisStep);
			}

			g_iAnalysisStep++;
		}
		else if (360 == g_iAnalysisStep)
		{
			//终止分析
			g_iAnalysisStep = -1;

			g_structPointNotVisible[360] = g_structPointNotVisible[0];

			//通视分析后,需要将最外侧的圆逆时针逐个加入不可视区域图层,这样才能形成一个闭合的不可视区域
			for (int i=360;i>=0;i--)
			{
				structPoint _structPoint;
				CalculatePtCoordinate(_structPoint.lon,_structPoint.lat,g_dGroundLonTemp,g_dGroundLatTemp,i,g_iRegionRadius*1000,3);

				g_structPointNotVisible[720 - i + 1] = _structPoint;
			}

			//发送到地图,绘制可视域
			::PostMessage(g_mapHwnd,WM_SHOW_NOTVISIBLE,0,0);
			::PostMessage(g_mapHwnd,WM_SHOW_ISVISIBLE,0,0);

			m_bRunRegion = false;
		}

		Sleep(10);
	}
}

//给定飞行高度,进行通视分析并在地图上标绘可视域,iAngle 角度,iRadius 距离
bool AnalysisLightRegion(int iAngle, int iRadius)
{
	double dTanMaxAngle = 0.0; //最小通视角度
	double fMinLightAlt = 0.0; //最小通视高度

	//采样点位置
	double interPolLon = 0.0, interPolLat = 0.0;
	float interPolHight = 0.0;

	//中间变量
	double _tempAngle = 0.0;  //当前点与地面站的连线 与水平方向的夹角
	structPoint _structPoint;

	//以60为采样间距,计算插值个数
	int interPolDis = 60;
	int interPolNum = (iRadius*1000)/interPolDis;

	for(int i = 1; i <= interPolNum; i++)
	{
		CalculatePtCoordinate(interPolLon, interPolLat, g_dGroundLonTemp, g_dGroundLatTemp, iAngle, i*interPolDis, 3);

		//获取采样点的高程
		if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
		{
			//未获取到高程值
			return false;
		}

		_tempAngle = CalSlopeBetweenTwoPoint(g_dGroundLonTemp, g_dGroundLatTemp, g_fGroundAltTemp, interPolLon, interPolLat, interPolHight);

		dTanMaxAngle = max(_tempAngle,dTanMaxAngle);

		fMinLightAlt = (float)CalAltFromSlope(g_dGroundLonTemp, g_dGroundLatTemp, g_fGroundAltTemp, interPolLon, interPolLat, dTanMaxAngle);

		//给定飞行高度,判断是否可通视,若遇到第一个不通视的点,认为此点是通视与不通视的分割点,直接返回
		if (g_iFlightAlt < fMinLightAlt)
		{
			_structPoint.lon = interPolLon;
			_structPoint.lat = interPolLat;

			g_structPointVisible[iAngle] = _structPoint;
			g_structPointNotVisible[iAngle] = _structPoint;

			return true;
		}
	}

	CalculatePtCoordinate(_structPoint.lon,_structPoint.lat,g_dGroundLonTemp,g_dGroundLatTemp,iAngle,g_iRegionRadius*1000,3);

	g_structPointVisible[iAngle] = _structPoint;
	g_structPointNotVisible[iAngle] = _structPoint;

	return true;
}

/*-------------------------------------------------------------------------------------------------------------
说明:实时通视检测
-------------------------------------------------------------------------------------------------------------*/
//实时通视检测线程开启标志
volatile bool m_bRunDetect = false;

double g_dRealTime_GCSlon    = 0.0;  //地面站经度
double g_dRealTime_GCSlat    = 0.0;  //地面站纬度
float  g_fRealTime_GCSalt    = 0.0f; //地面站高度
double g_dRealTime_UavAlt    = 0.0;  //无人机高度
double g_dRealTime_AngToGCS  = 0.0;  //地面站-飞机方位
double g_dRealTime_DisToGCS  = 0.0;  //地面站-飞机距离
double g_dRealTime_MinAngle  = 0.0;
double g_dRealTime_AngleDiff = 0.0;
int    g_iRealTime_CurStep   = -1;
int    g_iPointNumInLayer = 0;      //实时通视检测中分析的点数

//线程函数,处理实时通视检测
void ThreadFuncRealTimeDetection()
{
	while(m_bRunDetect)
	{
		if (-1 == g_iRealTime_CurStep)
		{
			continue;
		}

		if (g_iRealTime_CurStep <= 12)
		{
			if (false == AnalysisVisiArea(g_dRealTime_UavAlt, g_dRealTime_MinAngle+g_iRealTime_CurStep*g_dRealTime_AngleDiff, g_dRealTime_DisToGCS-3000, g_dRealTime_DisToGCS+3000, g_dRealTime_GCSlon, g_dRealTime_GCSlat))
			{
				g_iRealTime_CurStep = -1;

				//发送消息到对话框,提示高程信息不全
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)2,(LPARAM)-1);

				continue;
			}

			g_iRealTime_CurStep++;
		}

		if (g_iRealTime_CurStep == (12 + 1))
		{
			g_iRealTime_CurStep++;
		}

		if (g_iRealTime_CurStep == (12 + 2))
		{
			for (int i=0; i<=12;i++)
			{
				g_iPointNumInLayer++;

				structPoint _structPoint;

				CalculatePtCoordinate(_structPoint.lon, _structPoint.lat, g_dRealTime_GCSlon, g_dRealTime_GCSlat, g_dRealTime_MinAngle+(12-i)*g_dRealTime_AngleDiff, g_dRealTime_DisToGCS-3000, 3);

				//插入可视图层
				g_structPointVisiReal[g_iPointNumInLayer] = _structPoint;

				CalculatePtCoordinate(_structPoint.lon, _structPoint.lat, g_dRealTime_GCSlon, g_dRealTime_GCSlat, g_dRealTime_MinAngle+(12-i)*g_dRealTime_AngleDiff, g_dRealTime_DisToGCS+3000, 3);

				//插入不可视图层
				g_structPointNotVisiReal[g_iPointNumInLayer] = _structPoint;
			}

			g_iRealTime_CurStep++;
		}

		if (g_iRealTime_CurStep == (12 + 3))
		{
			//清除实时可视域绘制图层
			::PostMessage(g_mapHwnd,WM_SHOW_VISI_DELETE,0,0);

			//绘制实时不可视域图层
			::PostMessage(g_mapHwnd,WM_SHOW_NOTVISI_REALTIME,(WPARAM)g_iPointNumInLayer,0);

			g_iRealTime_CurStep++;
		}

		if (g_iRealTime_CurStep == (12 + 4))
		{
			//绘制实时可视域图层
			::PostMessage(g_mapHwnd,WM_SHOW_VISI_REALTIME,(WPARAM)g_iPointNumInLayer,0);

			g_iRealTime_CurStep = -1;
		}

		Sleep(10);
	}
}

//给定角度和距离范围,进行通视检测
bool AnalysisVisiArea(double uavAlt, double dAngle, double dDistanceMin, double dDistanceMax, double lonGCS, double latGCS)
{
	double dTanMaxAngle = 0.0; //最小通视角度
	double fMinLightAlt = 0.0; //最小通视高度

	//采样点位置
	double interPolLon = 0.0, interPolLat = 0.0;
	float interPolHight = 0.0;

	//中间变量
	double _tempAngle = 0.0;  //当前点与地面站的连线 与水平方向的夹角
	structPoint _structPoint;

	//以30为采样间距,计算插值个数
	int interPolDis = 30;
	int interPolNum = (int)(floor((double)(dDistanceMax/interPolDis)));

	for(int i = 1; i <= interPolNum; i++)
	{
		CalculatePtCoordinate(interPolLon, interPolLat, lonGCS, latGCS, dAngle, i*interPolDis, 3);

		//获取采样点的高程
		if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
		{
			//未获取到高程值
			return false;
		}

		_tempAngle = CalSlopeBetweenTwoPoint(lonGCS, latGCS, g_fRealTime_GCSalt, interPolLon, interPolLat, interPolHight);

		dTanMaxAngle = max(_tempAngle,dTanMaxAngle);

		fMinLightAlt = (float)CalAltFromSlope(lonGCS, latGCS, g_fRealTime_GCSalt, interPolLon, interPolLat, dTanMaxAngle);

		//给定飞行高度,判断是否可通视,若遇到第一个不通视的点,认为此点是通视与不通视的分割点,直接返回
		if (uavAlt < fMinLightAlt)
		{
			if ((i*interPolDis) < dDistanceMin)
			{
				CalculatePtCoordinate(interPolLon, interPolLat, lonGCS, latGCS, dAngle, dDistanceMin, 3);

				_structPoint.lon = interPolLon;
				_structPoint.lat = interPolLat;

				//插入可视与不可视图层
				g_iPointNumInLayer++;
				g_structPointVisiReal[g_iPointNumInLayer] = _structPoint;
				g_structPointNotVisiReal[g_iPointNumInLayer] = _structPoint;

				return true;
			}
			else
			{
				_structPoint.lon = interPolLon;
				_structPoint.lat = interPolLat;

				//插入可视与不可视图层
				g_iPointNumInLayer++;
				g_structPointVisiReal[g_iPointNumInLayer] = _structPoint;
				g_structPointNotVisiReal[g_iPointNumInLayer] = _structPoint;

				return true;
			}
		}
	}

	CalculatePtCoordinate(interPolLon, interPolLat, lonGCS, latGCS, dAngle, dDistanceMax, 3);

	_structPoint.lon = interPolLon;
	_structPoint.lat = interPolLat;

	//插入可视与不可视图层
	g_iPointNumInLayer++;
	g_structPointVisiReal[g_iPointNumInLayer] = _structPoint;
	g_structPointNotVisiReal[g_iPointNumInLayer] = _structPoint;

	return true;
}

/*-------------------------------------------------------------------------------------------------------------
说明:实时碰撞检测
-------------------------------------------------------------------------------------------------------------*/
//实时碰撞检测线程开启标志
volatile bool m_bRunCrash = false;

bool   g_bCrashDetection = false;
double g_dCrashUavLon = 0.0;
double g_dCrashUavLat = 0.0;
float  g_fCrashUavAlt = 0.0f;

//线程函数,处理实时碰撞检测
void ThreadFuncRealTimeCrash()
{
	while(m_bRunCrash)
	{
		if (true == g_bCrashDetection)
		{
			//采样点位置
			double interPolLon = 0.0, interPolLat = 0.0;
			float interPolHight = 0.0;

			//0到360方向,依次分析飞机半径为3km内的高程信息
			for (int i=0;i<360;i++)
			{
				for (int j=0;j<=20;j++)
				{
					CalculatePtCoordinate(interPolLon, interPolLat, g_dCrashUavLon, g_dCrashUavLat, i, j*150, 3);

					//获取采样点的高程
					if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
					{
						//未获取到高程值
						g_bCrashDetection = false;
						m_bRunCrash = false;

						BCGPMessageBox(_T("高程信息不全!"));

						break;
					}

					if ((20 == j) || (interPolHight > (g_fCrashUavAlt - 200))) //200米为考虑GPS高度与DEM高程差等之后给出的余量
					{
						g_structPointCrashReal[i].lon = interPolLon;
						g_structPointCrashReal[i].lat = interPolLat;

						break;
					}
				}
			}

			//为避免关闭线程时,线程内语句尚未执行完,从而停止检测后,依然会执行到此处
			if (true == g_bCrashDetection)
			{
				//绘制碰撞检测后的结果
				::PostMessage(g_mapHwnd,WM_SHOW_CRASH_REALTIME,1,0);

				g_bCrashDetection = false;
			}
		}
	}
}

/*-------------------------------------------------------------------------------------------------------------
说明:航线通视分析
-------------------------------------------------------------------------------------------------------------*/
//航线通视分析线程开启标志
volatile bool m_bRunRoute = false;

double g_dRoute_GCSlon    = 0.0;  //地面站经度
double g_dRoute_GCSlat    = 0.0;  //地面站纬度
float  g_fRoute_GCSalt    = 0.0f; //地面站高度

#pragma pack(1)
typedef struct _PTSTRUCT
{
	unsigned char/*BYTE*/    lineID;          //航线号
	unsigned char/*BYTE*/    ptID;            //航点号

	double  lon;             //经度
	double  lat;             //纬度
	short  alt;             //高度

	unsigned char/*BYTE*/ speed;					//速度

	char   taskCharacter;       //任务特征字	
	char   lineCharacter;       //航路特征字

}PtStruct;
#pragma pack()

PtStruct pts[257];    //航线的航线信息
int g_iWayPointNum;   //航线的航点个数
int g_iCurWaypoint;   //当前在分析的航点号

int g_iTotalInterNum = 0; //航线中的插值总点数
int g_totalLinePtNum;     //航线中已分析的插值点数

int g_iInterNumSec = 0;   //航段中的插值点数

double *g_ptrArraySeries1 = nullptr; //航线上各点的高程值
double *g_ptrArraySeries2 = nullptr; //航线上各点的最小通视高度
int    *g_ptrArraySeries3 = nullptr; //航点所设置的高度

//线程函数,处理航线通视分析
void ThreadFuncAnalysisRoute()
{
	while (m_bRunRoute)
	{
		for (int i=0;i<(g_iWayPointNum-1);i++)
		{
			//航点高程
			g_ptrArraySeries3[i] = g_totalLinePtNum;

			double _dLineSecDis, _dLineSecDir; //航段两点的距离和方向

			//计算航段起点和终点的水平距离和方位角
			CalculateTwoPtsDistanceAzimuth(_dLineSecDis, _dLineSecDir, pts[i].lon, pts[i].lat, pts[i+1].lon,pts[i+1].lat, 3);

			//以100米为间距,计算插值个数
			g_iInterNumSec = (int)(floor(_dLineSecDis/100));

			for (int j=0;j<=g_iInterNumSec;j++)
			{
				//插值点位置
				double interPolLon = 0.0, interPolLat = 0.0;
				float interPolHight = 0.0;

				CalculatePtCoordinate(interPolLon, interPolLat, pts[i].lon, pts[i].lat, _dLineSecDir, j*100, 3);

				//获取插值点的高程
				if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
				{
					//发送消息到对话框,提示高程信息不全
					::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)3,(LPARAM)-1);

					//关闭线程
					m_bRunRoute = false;

					g_iInterNumSec = 0;
					g_iWayPointNum = 0;
					g_iCurWaypoint = 0;
					g_iTotalInterNum = 0;
					g_totalLinePtNum = 0;

					continue ;
				}
				g_ptrArraySeries1[g_totalLinePtNum] = interPolHight;

				//获取最小通视高度
				float _minVisiAlt = CalculateVisibleAlt(interPolLon, interPolLat);
				if (_minVisiAlt > 0.1f)
				{
					g_ptrArraySeries2[g_totalLinePtNum] = _minVisiAlt;
				}
				else
				{
					//关闭线程
					m_bRunRoute = false;

					g_iInterNumSec = 0;
					g_iWayPointNum = 0;
					g_iCurWaypoint = 0;
					g_iTotalInterNum = 0;
					g_totalLinePtNum = 0;

					continue ;
				}

				g_totalLinePtNum++;

				//发送消息到对话框,更新分析进度
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)3,(LPARAM)1);
			}
		}

		if (true == m_bRunRoute)
		{
			//航点高程
			g_ptrArraySeries3[g_iWayPointNum-1] = g_totalLinePtNum-1;

			//关闭线程
			m_bRunRoute = false;

			//完成航线分析,发送消息到对话框,绘制分析结果,并提示分析完成
			::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)3,(LPARAM)-2);
		}
	}
}

//给定某点的经度、纬度,计算该点相对于地面站的最小通视高度
float CalculateVisibleAlt(const double& lon, const double& lat)
{
	//计算两个点间的水平距离和方位角
	double dis = 0.0, angle = 0.0;
	CalculateTwoPtsDistanceAzimuth(dis, angle, g_dRoute_GCSlon, g_dRoute_GCSlat, lon, lat, 3);

	//以30米为间距,计算插值个数
	int interPolDis = 30;
	int interPolNum = (int)floor(dis/interPolDis);

	//插值点位置计算
	double interPolLon = 0.0, interPolLat = 0.0;
	float interPolHight = 0.0;

	double _dTanMaxAngle = 0.0;
	float _fMinLightAlt = 0.0f;

	double _tempAngle = 0.0;

	for(int i = 1; i <= interPolNum; i++)
	{
		CalculatePtCoordinate(interPolLon, interPolLat, g_dRoute_GCSlon, g_dRoute_GCSlat, angle, i*interPolDis, 3);

		if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
		{
			//发送消息到对话框,提示高程信息不全
			::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)3,(LPARAM)-1);

			return 0.0f;
		}

		_tempAngle = CalSlopeBetweenTwoPoint(g_dRoute_GCSlon, g_dRoute_GCSlat, g_fRoute_GCSalt, interPolLon, interPolLat, interPolHight);

		_dTanMaxAngle = max(_tempAngle,_dTanMaxAngle);

		_fMinLightAlt = (float)CalAltFromSlope(g_dRoute_GCSlon, g_dRoute_GCSlat, g_fRoute_GCSalt, interPolLon, interPolLat, _dTanMaxAngle);
	}

	return _fMinLightAlt;
}

/*-------------------------------------------------------------------------------------------------------------
说明:实时视线通视分析
-------------------------------------------------------------------------------------------------------------*/
//实时视线通视分析线程开启标志
volatile bool m_bRunRealTimeLOS = false;

bool g_bHandlingLOS = false;

double *g_ptrArrayLight1 = nullptr;
double *g_ptrArrayLight2 = nullptr;
int g_iTotalAnalyNum = 0;

double g_dLightGCSlon;  //地面站经度
double g_dLightGCSlat;  //地面站纬度
float  g_fLightGCSAlt;  //地面站高度(地面站处的高程加上方舱高度)
double g_dLightAngle;   //地面站-飞机方位
double g_dLightDis;     //地面站-飞机距离

double g_dLightUavAlt;  //飞机高度
float g_fUavLosAlt;     //飞机距离处的通视高度

//线程函数,处理实时视线通视分析
void ThreadFuncAnalysisLOS()
{
	while(m_bRunRealTimeLOS)
	{
		if (true == g_bHandlingLOS)
		{
			//插值点位置
			double interPolLon = 0.0, interPolLat = 0.0;
			float interPolHight = 0.0f;

			g_iTotalAnalyNum = (int)(g_dLightDis/30);

			if (g_ptrArrayLight1 != nullptr)
			{
				delete[] g_ptrArrayLight1;
				g_ptrArrayLight1 = nullptr;
			}

			g_ptrArrayLight1 = new double[g_iTotalAnalyNum + 1];
			g_ptrArrayLight2 = new double[g_iTotalAnalyNum + 1];

			memset(g_ptrArrayLight1, 0, sizeof(double) * (g_iTotalAnalyNum + 1));
			memset(g_ptrArrayLight2, 0, sizeof(double) * (g_iTotalAnalyNum + 1));

			g_ptrArrayLight1[0] = g_fLightGCSAlt;
			g_ptrArrayLight2[0] = g_fLightGCSAlt;

			double _dTanMaxSlope = -1000.0;  //最大斜率
			float _fMinLOSAlt = 0.0;         //最小通视高度
			double _tempSlope = 0.0;         //当前点与地面站的连线的斜率

			for (int i=1;i<=g_iTotalAnalyNum;i++)
			{
				//获取插值点经纬度
				CalculatePtCoordinate(interPolLon, interPolLat, g_dLightGCSlon, g_dLightGCSlat, g_dLightAngle, i*30, 3);

				//获取插值点高程值
				if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
				{
					//发送消息到对话框,提示高程信息不全
					::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)4,(LPARAM)-1);

					//关闭线程
					m_bRunRealTimeLOS = false;

					continue ;
				}
				g_ptrArrayLight1[i] = interPolHight;

				_tempSlope = CalSlopeBetweenTwoPoint(g_dLightGCSlon, g_dLightGCSlat, g_fLightGCSAlt, interPolLon, interPolLat, interPolHight);

				//若当前点-地面站的斜率,小于之前所有点中的最大值,则当前点-地面站可以通视的斜率取最大值
				_dTanMaxSlope = max(_tempSlope,_dTanMaxSlope);

				//计算当前插值点可以通视的最小高度
				_fMinLOSAlt = (float)CalAltFromSlope(g_dLightGCSlon, g_dLightGCSlat, g_fLightGCSAlt, interPolLon, interPolLat, _dTanMaxSlope);

				g_ptrArrayLight2[i] = _fMinLOSAlt;
			}

			g_fUavLosAlt = _fMinLOSAlt;

			//完成实时通视分析,发送消息到对话框,绘制分析结果
			::SendMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)4,(LPARAM)-2);

			g_bHandlingLOS = false;
		}
	}
}

/*-------------------------------------------------------------------------------------------------------------
说明:通视等高线分析
-------------------------------------------------------------------------------------------------------------*/
//通视等高线分析线程开启标志
volatile bool m_bRunContour = false;

double g_dGroundLonCountour = 0.0;  //地面站经度
double g_dGroundLatCountour = 0.0;  //地面站纬度
float  g_fGroundAltCountour = 0.0;  //地面站高度

float g_fLastLightAlt = 0.0f;

int g_iMaxLosAlt = 8000;

//线程函数,处理通视等高线分析
void ThreadFuncAnalysisContour()
{
	while (m_bRunContour)
	{
		for (int i=0;i<360;i++)
		{
			g_fLastLightAlt = g_fGroundAltCountour;

			if (false == AnalysisContourLine(i))
			{
				//发送消息到对话框,提示高程信息不全
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)5,(LPARAM)-1);

				//终止线程
				m_bRunContour = false;

				break;
			}
			else
			{
				//发送消息到对话框,提示进度
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)5,(LPARAM)i);
			}

			//线程已终止
			if (false == m_bRunContour)
			{
				::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)5,(LPARAM)-3);

				break;
			}
		}

		if (true == m_bRunContour)
		{
			//发送消息到对话框,提示分析完成
			::PostMessage(g_hwndDlgLight,WM_SEND_UPDATEDIALOG,(WPARAM)5,(LPARAM)-2);

			//终止线程
			m_bRunContour = false;
		}
	}
}

//通视等高线分析并在地图上标绘等高线,iAngle 角度
bool AnalysisContourLine(int iAngle)
{
	double _dTanMaxAngle = 0.0; //最小通视角度
	float  _fMinLightAlt = 0.0; //最小通视高度

	//采样点位置
	double interPolLon = 0.0, interPolLat = 0.0;
	float interPolHight = 0.0;

	//中间变量
	double _tempAngle = 0.0;  //当前点与地面站的连线 与水平方向的夹角

	int _iStep = 1;

	while (_fMinLightAlt < g_iMaxLosAlt)
	{
		CalculatePtCoordinate(interPolLon, interPolLat, g_dGroundLonCountour, g_dGroundLatCountour, iAngle, _iStep*30, 3); //30为采样间距

		//获取采样点的高程
		if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
		{
			//未获取到高程值
			return false;
		}

		_tempAngle = CalSlopeBetweenTwoPoint(g_dGroundLonCountour, g_dGroundLatCountour, g_fGroundAltCountour, interPolLon, interPolLat, interPolHight);

		_dTanMaxAngle = max(_tempAngle,_dTanMaxAngle);

		_fMinLightAlt = (float)CalAltFromSlope(g_dGroundLonCountour, g_dGroundLatCountour, g_fGroundAltCountour, interPolLon, interPolLat, _dTanMaxAngle);

		if (true == m_bRunContour)
		{
			//添加点到通视等高线图层
			InsertPtToContourLine(_fMinLightAlt, interPolLon, interPolLat);
		}

		_iStep++;
	}

	return true;
}

//添加点到通视等高线图层
void InsertPtToContourLine(float _fLightAlt, double _dPtLon, double _dPtLat)
{
	for (int i = 1;i<=20;i++)
	{
		if ((g_fLastLightAlt < (500*i)) && (_fLightAlt > (500*i)))
		{
			structPoint _pt;
			_pt.lon = _dPtLon;
			_pt.lat = _dPtLat;

			//添加点到通视等高线图层
			::SendMessage(g_mapHwnd,WM_ADD_LINELAYER,WPARAM(&_pt),LPARAM(i));

			g_fLastLightAlt = _fLightAlt;

			return;
		}
	}
}


// CDlgLightRegion 对话框

IMPLEMENT_DYNAMIC(CDlgLightRegion, CBCGPDialog)

CDlgLightRegion::CDlgLightRegion(CWnd* pParent /*=NULL*/)
	: CBCGPDialog(CDlgLightRegion::IDD, pParent)
{
	EnableVisualManagerStyle(TRUE, TRUE);

	m_dGroundLon = 107.4203869;
	m_dGroundLat = 37.8544731;
	m_fGroudAlt = 0.0f;
	m_dCabinHgt = 4.0;

	m_iFlightAlt = 3500;
	m_iRegionRadius = 30;

	m_bRTlight = FALSE;

	m_pLine1 = nullptr;
	m_strokeStyle.SetDashStyle(CBCGPStrokeStyle::BCGP_DASH_STYLE_DOT);

	m_pTextTip = nullptr;

	m_bRealTime_Visi = FALSE;
	m_bRealTime_Crash = FALSE;
	m_iMaxLosAlt = 8000;
	m_iFightRegion = 280;
}

CDlgLightRegion::~CDlgLightRegion()
{
	m_bRunRegion      = false;
	m_bRunDetect      = false;
	m_bRunRoute       = false;
	m_bRunRealTimeLOS = false;
	m_bRunCrash       = false;

	if (g_ptrArraySeries1 != nullptr)
	{
		delete[] g_ptrArraySeries1;
		g_ptrArraySeries1 = nullptr;
	}

	if (g_ptrArraySeries2 != nullptr)
	{
		delete[] g_ptrArraySeries2;
		g_ptrArraySeries2 = nullptr;
	}

	if (g_ptrArraySeries3 != nullptr)
	{
		delete[] g_ptrArraySeries3;
		g_ptrArraySeries3 = nullptr;
	}

	if (g_ptrArrayLight1 != nullptr)
	{
		delete[] g_ptrArrayLight1;
		g_ptrArrayLight1 = nullptr;
	}

	if (g_ptrArrayLight2 != nullptr)
	{
		delete[] g_ptrArrayLight2;
		g_ptrArrayLight2 = nullptr;
	}
}

void CDlgLightRegion::DoDataExchange(CDataExchange* pDX)
{
	CBCGPDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CONTAINER_ALTCHART, m_wndChart);
	DDX_Text(pDX, IDC_EDIT_GROUND_LON, m_dGroundLon);
	DDX_Text(pDX, IDC_EDIT_GROUND_LAT, m_dGroundLat);
	DDX_Text(pDX, IDC_EDIT_BASEALT, m_iFlightAlt);
	DDX_Text(pDX, IDC_EDIT_REGIONRADIUS, m_iRegionRadius);
	DDX_Check(pDX, IDC_CHECK_REALTIME, m_bRealTime_Visi);
	DDX_Check(pDX, IDC_CHECK_RT_DETECTION, m_bRealTime_Crash);
	DDX_Text(pDX, IDC_EDIT_CABINALT, m_dCabinHgt);
	DDX_Check(pDX, IDC_CHECK_RT_LIGHT, m_bRTlight);
	DDX_Control(pDX, IDC_GAUGE_PROMPT_LINE, m_LineTextContainer);
	DDX_Control(pDX, IDC_GAUGE_PROMPT_REGION, m_RegionTextContainer);
	DDX_Control(pDX, IDC_GAUGE_PROMPT_CONTOUR, m_ContourTextContainer);
	DDX_Text(pDX, IDC_EDIT_MAXLOSALT, m_iMaxLosAlt);
	DDX_Text(pDX, IDC_EDIT_FIGHTRADIUS, m_iFightRegion);
	DDV_MinMaxInt(pDX, m_iFightRegion, 0, 500);
}

BEGIN_MESSAGE_MAP(CDlgLightRegion, CBCGPDialog)
	ON_WM_TIMER()
	ON_WM_SIZE()
	ON_BN_CLICKED(IDC_BUTTON_DRAWPOINT, &CDlgLightRegion::OnBnClickedButtonDrawPoint)
	ON_BN_CLICKED(IDC_BUTTON_REGIONANAYLSIS, &CDlgLightRegion::OnBnClickedButtonRegionAnaylsis)
	ON_BN_CLICKED(IDC_CHECK_REALTIME, &CDlgLightRegion::OnBnClickedCheckRealtime)
	ON_BN_CLICKED(IDC_BUTTON_REGIONDELETE, &CDlgLightRegion::OnBnClickedButtonRegionDelete)
	ON_BN_CLICKED(IDC_CHECK_RT_LIGHT, &CDlgLightRegion::OnBnClickedCheckRtLight)
	ON_BN_CLICKED(IDC_BUTTON_LOADROUTE, &CDlgLightRegion::OnBnClickedButtonLoadRoute)
	ON_BN_CLICKED(IDC_BUTTON_SAVEIMAGE, &CDlgLightRegion::OnBnClickedButtonSaveImage)
	ON_BN_CLICKED(IDC_BUTTON_STOPROUTE, &CDlgLightRegion::OnBnClickedButtonStopRoute)
	ON_BN_CLICKED(IDC_BUTTON_CONTOURLINE, &CDlgLightRegion::OnBnClickedButtonContourline)
	ON_BN_CLICKED(IDC_BUTTON_CONTOURDELETE, &CDlgLightRegion::OnBnClickedButtonContourDelete)
	ON_MESSAGE(WM_SEND_UPDATEDIALOG, &CDlgLightRegion::OnSendUpdateDialog)
	ON_BN_CLICKED(IDC_BUTTON_SELECTPTINMAP, &CDlgLightRegion::OnBnClickedButtonSelectPtInMap)
	ON_BN_CLICKED(IDC_BUTTON_CLEARLINELAYER, &CDlgLightRegion::OnBnClickedButtonClearLineLayer)
	ON_BN_CLICKED(IDC_BUTTON_GETALTVALUE, &CDlgLightRegion::OnBnClickedButtonGetAltValue)
	ON_BN_CLICKED(IDC_BUTTON_REVERSE, &CDlgLightRegion::OnBnClickedButtonReverse)
	ON_REGISTERED_MESSAGE(BCGM_ON_CHART_MOUSE_DOWN, OnMouseDown)
	ON_BN_CLICKED(IDC_BUTTON_CLEARRESULT, &CDlgLightRegion::OnBnClickedButtonClearResult)
	ON_BN_CLICKED(IDC_CHECK_RT_DETECTION, &CDlgLightRegion::OnBnClickedCheckRtDetection)
	ON_BN_CLICKED(IDC_BUTTON_DRAWFIGHT, &CDlgLightRegion::OnBnClickedButtonDrawFight)
	ON_BN_CLICKED(IDC_BUTTON_DELETEFIGHT, &CDlgLightRegion::OnBnClickedButtonDeleteFight)
	ON_BN_CLICKED(IDC_BUTTON_GETDEMREGION, &CDlgLightRegion::OnBnClickedButtonGetDemRegion)
END_MESSAGE_MAP()

// CDlgLightRegion 消息处理程序

BOOL CDlgLightRegion::OnInitDialog()
{
	CBCGPDialog::OnInitDialog();

	g_hwndDlgLight = this->GetSafeHwnd();

	CenterWindow();

	pChart = m_wndChart.GetChart();
	ASSERT_VALID(pChart);

	//Release模式下,曲线背景会变白,在此设置颜色
#ifdef DEBUG
	//pChart->SetColors(CBCGPChartTheme::CT_DEFAULT);
#else
	pChart->SetColors(CBCGPChartTheme::CT_DEFAULT, TRUE);
#endif

	//设置放大缩小方式
	pChart->SetZoomScrollConfig(BCGPChartMouseConfig::ZSO_WHEEL_PAN, BCGPChartFormatSelection::ST_VERT_AXIS_ONLY);
	pChart->SetSelectionType(BCGPChartFormatSelection::ST_VERT_AXIS_ONLY);

	//曲线使能鼠标跟踪
	pChart->EnableMouseTrackingMode(
		BCGPChartHitInfo::HIT_DATA_POINT |
		BCGPChartHitInfo::HIT_DATA_LABEL |
		BCGPChartHitInfo::HIT_AXIS |
		BCGPChartHitInfo::HIT_AXIS_NAME |
		BCGPChartHitInfo::HIT_CHART_AREA |
		BCGPChartHitInfo::HIT_LEGEND |
		BCGPChartHitInfo::HIT_TITLE |
		BCGPChartHitInfo::HIT_DIAGRAM |
		BCGPChartHitInfo::HIT_DATA_TABLE |
		BCGPChartHitInfo::HIT_ALL_ELEMENTS);

	//设置:当鼠标移动到曲线上,会显示当前点的信息
	CBCGPInfoTipOptions infoTipOptions;
	infoTipOptions.m_StemLocation = CBCGPPopupWindow::BCGPPopupWindowStemLocation_BottomCenter;
	m_wndChart.EnableInfoTip(TRUE, &infoTipOptions);

	pXAxis = pChart->GetChartAxis(BCGP_CHART_X_PRIMARY_AXIS);
	pYAxis = pChart->GetChartAxis(BCGP_CHART_Y_PRIMARY_AXIS);

	//创建曲线1,绘制高程信息
	pSeries1 = pChart->CreateSeries(_T("DEM Alt"), CBCGPColor(), BCGP_CT_DEFAULT, BCGPChartArea);

	//创建曲线2,绘制最小通视高度
	pSeries2 = pChart->CreateSeries(_T("LOS Alt"), CBCGPColor(CBCGPColor::OrangeRed), BCGP_CT_DEFAULT, BCGPChartLine);
	pSeries2->SetSeriesLineWidth(2);

	//创建曲线3,绘制无人机位置
	pSeries3 = pChart->CreateSeries(_T("UAV Alt"), CBCGPColor(CBCGPColor::LimeGreen), BCGP_CT_DEFAULT, BCGPChartLine);
	BCGPChartFormatSeries style = pSeries3->GetSeriesFormat();
	style.m_curveType = BCGPChartFormatSeries::CCT_NO_LINE;
	pSeries3->SetSeriesFormat(style);

	pSeries3->ShowMarker(TRUE, 0);
	pSeries3->SetMarkerSize(4, 0);

	/*pSeries3->ShowDataLabel(TRUE,0);
	pSeries3->SetDataLabelAngle(60, 0);
	pSeries3->SetDataLabelDataFormat(_T("%.1f"),0);*/

	pChart->SetDirty(TRUE, TRUE);
	m_wndChart.RedrawWindow();

	//初始化可视域分析提示文字显示仪表
	InitRegionTextContainer();

	//初始化航线通视分析提示文字显示仪表
	InitLineTextContainer();

	//初始化通视等高线分析提示文字显示仪表
	InitContourTextContainer();

	return TRUE;
}

void CDlgLightRegion::OnSize(UINT nType, int cx, int cy)
{
	CBCGPDialog::OnSize(nType, cx, cy);

	//图表控件随对话框大小变化而变化
	if (m_wndChart.GetSafeHwnd())
	{
		CRect rect;
		GetClientRect(&rect);

		CRect rectChart;
		m_wndChart.GetWindowRect(rectChart);

		ScreenToClient(rectChart);

		rectChart.right  = rect.right - 5;
		rectChart.bottom = rect.bottom - 5;

		m_wndChart.MoveWindow(&rectChart,TRUE);
	}
}

//初始化可视域分析提示文字显示仪表
void CDlgLightRegion::InitRegionTextContainer()
{
	CBCGPVisualContainer* pContainer = m_RegionTextContainer.GetVisualContainer();
	ASSERT_VALID(pContainer);

	pContainer->SetFillBrush(CBCGPBrush());
	pContainer->SetOutlineBrush(CBCGPBrush());

	CBCGPBrush m_arBrushes(CBCGPColor::AliceBlue);
	m_pRegionTTextIndicator = new CBCGPTextGaugeImpl(_T("进度提示"), m_arBrushes, pContainer);

	CBCGPTextFormat m_TextFormat = m_pRegionTTextIndicator->GetTextFormat();
	m_TextFormat.SetFontSize(15);
	m_TextFormat.SetTextAlignment(CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER);
	m_TextFormat.SetTextVerticalAlignment(CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER);
	m_pRegionTTextIndicator->SetTextFormat(m_TextFormat);

	CBCGPRect rect = pContainer->GetRect();
	m_pRegionTTextIndicator->SetRect(rect);

	m_RegionTextContainer.RedrawWindow();
}

//初始化航线通视分析提示文字显示仪表
void CDlgLightRegion::InitLineTextContainer()
{
	CBCGPVisualContainer* pContainer = m_LineTextContainer.GetVisualContainer();
	ASSERT_VALID(pContainer);

	pContainer->SetFillBrush(CBCGPBrush());
	pContainer->SetOutlineBrush(CBCGPBrush());

	CBCGPBrush m_arBrushes(CBCGPColor::AliceBlue);
	m_pLineTextIndicator = new CBCGPTextGaugeImpl(_T("进度提示"), m_arBrushes, pContainer);

	CBCGPTextFormat m_TextFormat = m_pLineTextIndicator->GetTextFormat();
	m_TextFormat.SetFontSize(15);
	m_TextFormat.SetTextAlignment(CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER);
	m_TextFormat.SetTextVerticalAlignment(CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER);
	m_pLineTextIndicator->SetTextFormat(m_TextFormat);

	CBCGPRect rect = pContainer->GetRect();
	m_pLineTextIndicator->SetRect(rect);

	m_LineTextContainer.RedrawWindow();
}

//初始化通视等高线分析提示文字显示仪表
void CDlgLightRegion::InitContourTextContainer()
{
	CBCGPVisualContainer* pContainer = m_ContourTextContainer.GetVisualContainer();
	ASSERT_VALID(pContainer);

	pContainer->SetFillBrush(CBCGPBrush());
	pContainer->SetOutlineBrush(CBCGPBrush());

	CBCGPBrush m_arBrushes(CBCGPColor::AliceBlue);
	m_pContourTextIndicator = new CBCGPTextGaugeImpl(_T("进度提示"), m_arBrushes, pContainer);

	CBCGPTextFormat m_TextFormat = m_pContourTextIndicator->GetTextFormat();
	m_TextFormat.SetFontSize(15);
	m_TextFormat.SetTextAlignment(CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER);
	m_TextFormat.SetTextVerticalAlignment(CBCGPTextFormat::BCGP_TEXT_ALIGNMENT_CENTER);
	m_pContourTextIndicator->SetTextFormat(m_TextFormat);

	CBCGPRect rect = pContainer->GetRect();
	m_pContourTextIndicator->SetRect(rect);

	m_ContourTextContainer.RedrawWindow();
}

//接收其他线程来的消息,更新对话框内容
afx_msg LRESULT CDlgLightRegion::OnSendUpdateDialog(WPARAM wParam, LPARAM lParam)
{
	if (1 == (int)wParam) //可视域分析
	{
		if (-1 == int(lParam))
		{
			m_pRegionTTextIndicator->SetText(_T("高程不全!"));
			m_RegionTextContainer.RedrawWindow();

			GetDlgItem(IDC_BUTTON_REGIONANAYLSIS)->EnableWindow(TRUE);
		}
		else
		{
			CString str;
			str.Format(_T("%d%%"),(int)(((int)lParam+1) * 100 / 360));
			
			m_pRegionTTextIndicator->SetText(str);
			m_RegionTextContainer.RedrawWindow();

			if (359 == int(lParam))
			{
				GetDlgItem(IDC_BUTTON_REGIONANAYLSIS)->EnableWindow(TRUE);
			}
		}
	}
	else if (2 == (int)wParam) //实时通视检测
	{
		if (-1 == int(lParam))
		{
			BCGPMessageBox(_T("高程信息不全!"));
		}
	}
	else if (3 == (int)wParam) //航线通视分析
	{
		if (-1 == int(lParam))
		{
			//未获取到高程值
			m_pLineTextIndicator->SetText(_T("高程不全!"));
			m_LineTextContainer.RedrawWindow();
		}
		else if (-2 == int(lParam))
		{
			for (int i=0;i<g_iTotalInterNum;i++)
			{
				pSeries1->AddDataPoint(g_ptrArraySeries1[i],i);
				pSeries2->AddDataPoint(g_ptrArraySeries2[i],i);
			}

			//航点的高程
			for (int i=0;i<g_iWayPointNum;i++)
			{
				pSeries3->AddDataPoint(pts[i].alt,g_ptrArraySeries3[i]);

				pSeries1->ShowDataLabel(TRUE,g_ptrArraySeries3[i]);
				pSeries1->SetDataLabelAngle(0, g_ptrArraySeries3[i]);
				pSeries1->ShowMarker(TRUE, g_ptrArraySeries3[i]);
				pSeries1->SetMarkerSize(4, g_ptrArraySeries3[i]);

				CString str;
				str.Format(_T("%d-%d"),pts[i].lineID,pts[i].ptID);
				pSeries1->SetDataLabelDataFormat(str,g_ptrArraySeries3[i]);
			}

			pChart->SetAutoDisplayRange(TRUE, TRUE);
			pChart->SetDirty(TRUE, TRUE);
			m_wndChart.RedrawWindow();

			m_pLineTextIndicator->SetText(_T("分析完成!"));
			m_LineTextContainer.RedrawWindow();
		}
		else if (1 == int(lParam))
		{
			if (g_iTotalInterNum > 0)
			{
				CString str;
				str.Format(_T("%d%%"),(g_totalLinePtNum)*100/g_iTotalInterNum);

				m_pLineTextIndicator->SetText(str);
				m_LineTextContainer.RedrawWindow();
			}
		}
	}
	else if (4 == (int)wParam) //实时视线分析
	{
		if (-1 == int(lParam)) //未获取到高程值
		{
			m_bRTlight = FALSE;
			UpdateData(FALSE);

			GetDlgItem(IDC_BUTTON_LOADROUTE)->EnableWindow(TRUE);

			BCGPMessageBox(_T("高程信息不全!"));
		}
		else if (-2 == int(lParam)) //分析完成
		{
			pSeries1->AddDataPoint(g_ptrArrayLight1[0],0.0);
			pSeries2->AddDataPoint(g_ptrArrayLight2[0],0.0);

			for (int i=1;i<=g_iTotalAnalyNum;i++)
			{
				pSeries1->AddDataPoint(g_ptrArrayLight1[i],i*30);
				pSeries2->AddDataPoint(g_ptrArrayLight2[i],i*30);
			}

			//在Chart上更新无人机的位置(距离和高度)
			pSeries3->AddDataPoint(g_dLightUavAlt,30*g_iTotalAnalyNum);
			pSeries3->ShowMarker(TRUE, 30*g_iTotalAnalyNum);
			pSeries3->SetMarkerSize(4, 30*g_iTotalAnalyNum);

			pChart->RemoveAllChartObjects();

			//连接无人机高度和最小通视高度
			m_pLine1 = pChart->AddChartLineObject(30*g_iTotalAnalyNum, g_dLightUavAlt, 30*g_iTotalAnalyNum, g_fUavLosAlt, CBCGPBrush(CBCGPColor::Tomato), 1.5, &m_strokeStyle);

			CString str;
			str.Format(_T("%.1fm"),g_dLightUavAlt - g_fUavLosAlt);

			//显示无人机高度和最小通视高度的差值
			m_pTextTip = nullptr;
			m_pTextTip = new CBCGPChartTextObject(pChart, str, 30*g_iTotalAnalyNum, min(g_dLightUavAlt,g_fUavLosAlt) + abs(g_dLightUavAlt - g_fUavLosAlt)/2, 
				CBCGPBrush(CBCGPColor::White), CBCGPBrush(), CBCGPBrush(CBCGPColor::Tomato), 30, 90, TRUE);
			pChart->AddChartObject(m_pTextTip);

			pChart->SetAutoDisplayRange(TRUE, TRUE);
			pChart->SetDirty(TRUE, TRUE);
			m_wndChart.RedrawWindow();
		}
	}
	else if (5 == (int)wParam) //通视等高线分析
	{
		if (int(lParam) >= 0)
		{
			//进度提示
			CString str;
			str.Format(_T("%d%%"),(int)((int(lParam)+1) * 100 / 360));

			m_pContourTextIndicator->SetText(str);
			m_ContourTextContainer.RedrawWindow();
		}
		else if (-1 == int(lParam)) //未获取到高程值
		{
			m_pContourTextIndicator->SetText(_T("高程信息不全!"));
			m_ContourTextContainer.RedrawWindow();

			GetDlgItem(IDC_BUTTON_CONTOURLINE)->EnableWindow(TRUE);
		}
		else if (-2 == int(lParam))
		{
			m_pContourTextIndicator->SetText(_T("分析完成!"));
			m_ContourTextContainer.RedrawWindow();

			GetDlgItem(IDC_BUTTON_CONTOURLINE)->EnableWindow(TRUE);
		}
		else if (-3 == int(lParam))
		{
			//清除通视等高线分析结果
			OnBnClickedButtonContourDelete();
		}
	}

	return 0;
}

//在地图上标绘地面站位置
void CDlgLightRegion::OnBnClickedButtonDrawPoint()
{
	UpdateData(TRUE);

	::SendMessage(g_mapHwnd,WM_SHOW_POINTINMAP,0,0);

	//获取地面站的高程信息
	float ptAlt = 0.0f;
	if(!m_mapElevation2.getElevation(ptAlt, m_dGroundLon, m_dGroundLat))
	{
		ptAlt = 0.0f;
	}

	CString str;
	str.Format(_T("%.1f"),ptAlt);
	GetDlgItem(IDC_EDIT_GROUND_ALT)->SetWindowText(str);
}

/*-------------------------------------------------------------------------------------------------------------
说明:可视域分析
-------------------------------------------------------------------------------------------------------------*/

//点击“可视域分析”按钮
void CDlgLightRegion::OnBnClickedButtonRegionAnaylsis()
{
	UpdateData(TRUE);

	//获取地面站高程信息
	if(!m_mapElevation2.getElevation(g_fGroundAltTemp, m_dGroundLon, m_dGroundLat))
	{
		//未获取到高程值
		BCGPMessageBox(_T("地面站处无高程信息!"));

		return ;
	}
	else
	{
		//地面站位置的高度在地面站高程的基础上加上方舱高度
		g_fGroundAltTemp += (float)m_dCabinHgt;

		if (g_fGroundAltTemp > m_iFlightAlt)
		{
			BCGPMessageBox(_T("飞行高度应大于地面站高度!"));

			return ;
		}
	}

	//清除可视域绘制图层
	::SendMessage(g_mapHwnd,WM_SEND_CLEARSHAPE,0,0);

	GetDlgItem(IDC_BUTTON_REGIONANAYLSIS)->EnableWindow(FALSE);

	g_dGroundLonTemp = m_dGroundLon;
	g_dGroundLatTemp = m_dGroundLat;
	g_iFlightAlt = m_iFlightAlt;
	g_iRegionRadius = m_iRegionRadius;
	g_iAnalysisStep = 0;

	//开启线程
	hThreadRegion = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncLightRegion, NULL, 0, &ThreadIDRegion);

	m_bRunRegion = true;
}

//清除可视域分析结果
void CDlgLightRegion::OnBnClickedButtonRegionDelete()
{
	//关闭线程
	m_bRunRegion = false;

	//清除可视域绘制图层
	::SendMessage(g_mapHwnd,WM_SEND_CLEARSHAPE,0,0);

	GetDlgItem(IDC_BUTTON_REGIONANAYLSIS)->EnableWindow(TRUE);
}

/*------------------------------------------------------------------------------------------------------------
说明:实时通视检测
-------------------------------------------------------------------------------------------------------------*/

//选中实时通视检测
void CDlgLightRegion::OnBnClickedCheckRealtime()
{
	UpdateData(TRUE);

	if (TRUE == m_bRealTime_Visi)
	{
		//清除实时可视域绘制图层
		::SendMessage(g_mapHwnd,WM_SHOW_VISI_DELETE,0,0);

		g_iRealTime_CurStep = -1;

		//开启线程
		hThreadDetect = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncRealTimeDetection, NULL, 0, &ThreadIDDetect);

		m_bRunDetect = true;
	}
	else
	{
		//关闭线程
		m_bRunDetect = false;

		//清除实时可视域绘制图层
		::SendMessage(g_mapHwnd,WM_SHOW_VISI_DELETE,0,0);
	}
}

//地图上实时绘制检测区域
void CDlgLightRegion::DrawVisiAreaRealTime(double uavAlt, double distanceToGCS, double angleToGCS, double lonGCS, double latGCS)
{
	//若未选中实时通视检测
	if (FALSE == m_bRealTime_Visi)
	{
		return ;
	}

	//当实时检测已终止
	if (-1 == g_iRealTime_CurStep)
	{
		//地面站-飞机距离小于5km,不进行实时检测
		if (distanceToGCS < 5000.0)
		{
			m_bRealTime_Visi = FALSE;
			UpdateData(FALSE);

			//关闭线程
			m_bRunDetect = false;

			BCGPMessageBox(_T("地面站-飞机距离过短!"));

			//清除实时可视域绘制图层
			::SendMessage(g_mapHwnd,WM_SHOW_VISI_DELETE,0,0);

			return ;
		}

		//获取地面站高程信息
		if(!m_mapElevation2.getElevation(g_fRealTime_GCSalt, lonGCS, latGCS))
		{
			m_bRealTime_Visi = FALSE;
			UpdateData(FALSE);

			//关闭线程
			m_bRunDetect = false;

			//未获取到高程值
			BCGPMessageBox(_T("地面站处无高程信息!"));

			//清除实时可视域绘制图层
			::SendMessage(g_mapHwnd,WM_SHOW_VISI_DELETE,0,0);

			return ;
		}

		//地面站位置的高度在地面站高程的基础上加上方舱高度
		g_fRealTime_GCSalt += (float)m_dCabinHgt;

		double _tempAngle = (asin(3000.0/distanceToGCS) * 57.295779513082322864647721871733665466308593750000);

		double _tempMinAngle  = angleToGCS - _tempAngle;

		if (_tempMinAngle < 0)
		{
			_tempMinAngle += 360.0;
		}

		g_dRealTime_GCSlon    = lonGCS;
		g_dRealTime_GCSlat    = latGCS;
		g_dRealTime_UavAlt    = uavAlt;
		g_dRealTime_AngToGCS  = angleToGCS;
		g_dRealTime_DisToGCS  = distanceToGCS;
		g_dRealTime_MinAngle  = _tempMinAngle;
		g_dRealTime_AngleDiff = _tempAngle/6.0;

		//开始绘制实时可视域
		g_iRealTime_CurStep = 0;

		g_iPointNumInLayer = -1;
	}
}

/*------------------------------------------------------------------------------------------------------------
说明:实时碰撞检测
-------------------------------------------------------------------------------------------------------------*/

//选中实时碰撞检测
void CDlgLightRegion::OnBnClickedCheckRtDetection()
{
	UpdateData(TRUE);

	if (TRUE == m_bRealTime_Crash)
	{
		g_bCrashDetection = false;

		//开启线程
		hThreadCrash = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncRealTimeCrash, NULL, 0, &ThreadIDCrash);

		m_bRunCrash = true;
	}
	else
	{
		g_bCrashDetection = false;

		//关闭线程
		m_bRunCrash = false;

		//清除碰撞检测后的结果
		::PostMessage(g_mapHwnd,WM_SHOW_CRASH_REALTIME,0,0);
	}
}

//地图上实时在无人机周边检测高程
void CDlgLightRegion::DrawCrashAreaRealTime(double uavAlt, double uavLon, double uavLat)
{
	//若未选中实时碰撞检测
	if (FALSE == m_bRealTime_Crash)
	{
		return ;
	}

	if (false == g_bCrashDetection)
	{
		g_dCrashUavLon = uavLon;
		g_dCrashUavLat = uavLat;
		g_fCrashUavAlt = (float)uavAlt;

		g_bCrashDetection = true;
	}
}

/*------------------------------------------------------------------------------------------------------------
说明:实时视线分析
-------------------------------------------------------------------------------------------------------------*/

//选中实时视线分析
void CDlgLightRegion::OnBnClickedCheckRtLight()
{
	UpdateData(TRUE);

	if (TRUE == m_bRTlight)
	{
		GetDlgItem(IDC_BUTTON_LOADROUTE)->EnableWindow(FALSE);

		//两点通视分析时,隐藏了pSeries3,实时视线分析时需要显示
		pChart->ShowSeries(TRUE, 2);

		//设置曲线3类型为NO_LINE
		BCGPChartFormatSeries style = pSeries3->GetSeriesFormat();
		style.m_curveType = BCGPChartFormatSeries::CCT_NO_LINE;
		pSeries3->SetSeriesFormat(style);

		pSeries3->ShowMarker(TRUE, 0);
		pSeries3->SetMarkerSize(4, 0);

		pSeries3->m_strSeriesName = _T("UAV Alt");

		//开启线程
		hThreadLight = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncAnalysisLOS, NULL, 0, &ThreadIDLight);

		m_bRunRealTimeLOS = true;
	}
	else
	{
		g_bHandlingLOS = false;

		//关闭线程
		m_bRunRealTimeLOS = false;

		pSeries1->RemoveAllDataPoints();
		pSeries2->RemoveAllDataPoints();
		pSeries3->RemoveAllDataPoints();
		pChart->RemoveAllChartObjects();

		pChart->SetDirty(TRUE, TRUE);
		m_wndChart.RedrawWindow();

		GetDlgItem(IDC_BUTTON_LOADROUTE)->EnableWindow(TRUE);
	}
}

//实时视线分析,地面站-飞机连线,绘制图表
void CDlgLightRegion::AnalysisRealTime(double uavAlt, double distanceToGCS, double angleToGCS, double lonGCS, double latGCS)
{
	//若未选中实时视线分析,返回
	if (FALSE == m_bRTlight)
	{
		return ;
	}

	if (false == g_bHandlingLOS)
	{
		pSeries1->RemoveAllDataPoints();
		pSeries2->RemoveAllDataPoints();
		pSeries3->RemoveAllDataPoints();

		g_dLightGCSlon = lonGCS;  //地面站经度
		g_dLightGCSlat = latGCS;  //地面站纬度
		g_dLightAngle  = angleToGCS;   //地面站-飞机方位
		g_dLightDis    = distanceToGCS;     //地面站-飞机距离
		g_dLightUavAlt = uavAlt;  //飞机高度

		//获取地面站所在位置高程值
		if(!m_mapElevation2.getElevation(g_fLightGCSAlt, g_dLightGCSlon, g_dLightGCSlat))
		{
			//未获取到高程值,取消实时视线分析
			m_bRTlight = FALSE;
			UpdateData(FALSE);

			//关闭线程
			m_bRunRealTimeLOS = false;

			GetDlgItem(IDC_BUTTON_LOADROUTE)->EnableWindow(TRUE);

			BCGPMessageBox(_T("高程信息不全!"));

			return ;
		}

		//地面站位置的高度在地面站高程的基础上加上方舱的高度
		g_fLightGCSAlt += (float)m_dCabinHgt;

		g_bHandlingLOS = true;
	}
}

/*-------------------------------------------------------------------------------------------------------------
说明:航线通视分析
-------------------------------------------------------------------------------------------------------------*/

//加载航线
void CDlgLightRegion::OnBnClickedButtonLoadRoute()
{
	UpdateData(TRUE);

	//弹出文件对话框
	CFileDialog dlg(true, NULL, NULL,OFN_HIDEREADONLY, _T("(*.txt)|*.txt||"), NULL);

	if (dlg.DoModal() == IDOK)
	{
		CString strFile = dlg.GetPathName();

		int ptNum = 0;

		//初始化航线的航点数据
		memset(pts, 0, sizeof(PtStruct)*257);

		FILE *fpReadFlyLine;
		int err;
		err = fopen_s(&fpReadFlyLine,strFile.GetBuffer(), "r");
		strFile.ReleaseBuffer();

		if (fpReadFlyLine != NULL)
		{
			while (!feof(fpReadFlyLine))
			{
				//航路文件是否导入正确的标识
				int redFlag = fscanf_s(fpReadFlyLine, "%d, %d, %lf, %lf, %d, %d, %02X, %02X\n", &pts[ptNum].lineID,&pts[ptNum].ptID, 
					&pts[ptNum].lon, &pts[ptNum].lat, &pts[ptNum].alt,  &pts[ptNum].speed, &pts[ptNum].taskCharacter, &pts[ptNum].lineCharacter);

				if (redFlag != 8)    //航路文件不对,返回
				{
					//关闭文件
					fclose(fpReadFlyLine);

					return ;
				}

				if (0 != pts[ptNum].ptID)
				{
					ptNum ++;
				}
			}

			//关闭文件
			fclose(fpReadFlyLine);

			//航路点个数的有效范围为[0,255]共256个
			//检测的有效范围为【2,256】
			if ((ptNum>257) || (ptNum<2))
			{
				return ;
			}

			//对单个航点的数据进行检查
			for (int i=0; i<ptNum; i++)
			{
				if (   (pts[i].ptID<0)	        || (pts[i].ptID>255)
					|| (pts[i].lon<-180)        || (pts[i].lon>180)
					|| (pts[i].lat<-90)	        || (pts[i].lat>90)
					|| (pts[i].alt<-500)        || (pts[i].alt>10000) 
					|| (pts[i].speed<0)	        || (pts[i].speed>100)
					|| (pts[i].taskCharacter<0)	|| (pts[i].taskCharacter>255) 
					|| (pts[i].lineCharacter<0)	|| (pts[i].lineCharacter>255) ) 
				{
					return ;
				}
			}

			//对航点的航线编号进行严格检查
			//当存在航线编号不一样时,返回false
			int ptLineID = pts[0].lineID;
			for (int i=1; i<ptNum; i++)
			{
				if (ptLineID != pts[i].lineID)
				{
					return ;
				}
			}

			//对航线的航点编号进行严格检查,判断规则为,起点为1,依次递增1
			//当存在航点编号不符合规则时,返回
			if (pts[0].ptID != 1)
			{
				return ;
			}
			int toComparePtId = pts[0].ptID + 1;
			for (int i=1; i<ptNum; i++)
			{
				if (pts[i].ptID != toComparePtId)
				{
					return ;
				}
				else
				{
					toComparePtId++;
				}
			}

			//显示航线
			//::SendMessage(g_mapHwnd, WM_SHOW_LINE, pts[0].lineID, 0);

			pts[ptNum] = pts[0];
			g_iWayPointNum = ptNum + 1;
			g_totalLinePtNum = 0;

			pSeries1->RemoveAllDataPoints();
			pSeries2->RemoveAllDataPoints();
			pSeries3->RemoveAllDataPoints();

			//两点通视分析时,隐藏了pSeries3,航线通视分析时需要显示
			pChart->ShowSeries(TRUE, 2);

			//设置曲线3类型为曲线
			BCGPChartFormatSeries style = pSeries3->GetSeriesFormat();
			style.m_curveType = BCGPChartFormatSeries::CCT_LINE;
			pSeries3->SetSeriesFormat(style);

			pSeries3->m_strSeriesName = _T("Pt Alt");

			pSeries3->ShowMarker(FALSE);

			m_pLineTextIndicator->SetText(_T("正在分析!"));
			m_LineTextContainer.RedrawWindow();

			//计算航线分析时总共需要分析的点数
			g_iTotalInterNum = 0;
			for (int i=0;i<ptNum;i++)
			{
				double _dis;
				if (i != (ptNum-1))
				{
					CalculateTwoPtsDistance(_dis, pts[i].lon, pts[i].lat, pts[i+1].lon, pts[i+1].lat, 3);
				}
				else
				{
					CalculateTwoPtsDistance(_dis, pts[i].lon, pts[i].lat, pts[0].lon, pts[0].lat, 3);
				}
				
				g_iTotalInterNum += (int)(_dis/100) + 1;
			}

			if (g_ptrArraySeries1 != nullptr)
			{
				delete[] g_ptrArraySeries1;
				g_ptrArraySeries1 = nullptr;
			}

			g_ptrArraySeries1 = new double[g_iTotalInterNum];
			memset(g_ptrArraySeries1,0,sizeof(double) * g_iTotalInterNum);

			if (g_ptrArraySeries2 != nullptr)
			{
				delete[] g_ptrArraySeries2;
				g_ptrArraySeries2 = nullptr;
			}

			g_ptrArraySeries2 = new double[g_iTotalInterNum];
			memset(g_ptrArraySeries2,0,sizeof(double) * g_iTotalInterNum);

			if (g_ptrArraySeries3 != nullptr)
			{
				delete[] g_ptrArraySeries3;
				g_ptrArraySeries3 = nullptr;
			}

			g_ptrArraySeries3 = new int[g_iWayPointNum];
			memset(g_ptrArraySeries3,0,sizeof(int) * g_iWayPointNum);

			//获取地面站位置
			g_dRoute_GCSlon = m_dGroundLon;  //地面站经度
			g_dRoute_GCSlat = m_dGroundLat;  //地面站纬度

			//获取插值点的高程
			if(!m_mapElevation2.getElevation(g_fRoute_GCSalt, g_dRoute_GCSlon, g_dRoute_GCSlat))
			{
				//未获取到高程值
				BCGPMessageBox(_T("地面站处无高程信息!"));

				return ;
			}

			//地面站位置的高度在地面站高程的基础上加上方舱高度
			g_fRoute_GCSalt += (float)m_dCabinHgt;

			//开启线程
			hThreadRoute = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncAnalysisRoute, NULL, 0, &ThreadIDRoute);

			m_bRunRoute = true;
		}
		else  //空文件,航点数为0
		{
			BCGPMessageBox(_T( "空文件!" ));

			return ;
		}
	}
}

//停止航线分析
void CDlgLightRegion::OnBnClickedButtonStopRoute()
{
	//关闭线程
	m_bRunRoute = false;

	g_iInterNumSec = 0;
	g_iWayPointNum = 0;
	g_iCurWaypoint = 0;
	g_iTotalInterNum = 0;
	g_totalLinePtNum = 0;

	m_pLineTextIndicator->SetText(_T(""));
	m_LineTextContainer.RedrawWindow();

	pSeries1->RemoveAllDataPoints();
	pSeries2->RemoveAllDataPoints();
	pSeries3->RemoveAllDataPoints();

	pChart->SetDirty(TRUE, TRUE);
	m_wndChart.RedrawWindow();
}

//保存航线通视分析结果
void CDlgLightRegion::OnBnClickedButtonSaveImage()
{
	CFileDialog dlg (FALSE, _T("bmp"), _T(""), OFN_HIDEREADONLY, 
		_T("Bitmap Files (*.bmp)|*.bmp|Png Files (*.png)|*.png|All Files (*.*)|*.*||"), this);
	if (dlg.DoModal () == IDOK)
	{
		m_wndChart.ExportToFile(dlg.GetPathName ());
	}
}

//清除航线通视分析结果
void CDlgLightRegion::OnBnClickedButtonClearResult()
{
	//关闭线程
	m_bRunRoute = false;

	g_iInterNumSec = 0;
	g_iWayPointNum = 0;
	g_iCurWaypoint = 0;
	g_iTotalInterNum = 0;
	g_totalLinePtNum = 0;

	m_pLineTextIndicator->SetText(_T(""));
	m_LineTextContainer.RedrawWindow();

	pSeries1->RemoveAllDataPoints();
	pSeries2->RemoveAllDataPoints();
	pSeries3->RemoveAllDataPoints();

	pChart->SetDirty(TRUE, TRUE);
	m_wndChart.RedrawWindow();

	//清除航线上的点的标绘图层
	::SendMessage(g_mapHwnd, WM_DRAW_LINEPOINT, 0, 0);
}

LRESULT CDlgLightRegion::OnMouseDown(WPARAM /*wp*/, LPARAM lp)
{
	BCGPChartHitInfo* pHitInfo = (BCGPChartHitInfo*)lp;

	switch (pHitInfo->m_hitInfo)
	{
	case BCGPChartHitInfo::HIT_DIAGRAM:
		CBCGPPoint pt = pHitInfo->m_ptHit;

		double dblX = pXAxis->ValueFromPoint(pt);
		double dblY = pYAxis->ValueFromPoint(pt);

		if (g_ptrArraySeries3 != nullptr && g_iWayPointNum > 2)
		{
			for (int i=0;i<(g_iWayPointNum-1);i++)
			{
				if ((dblX >= g_ptrArraySeries3[i]) && (dblX < g_ptrArraySeries3[i+1]))
				{
					double azAngle = 0;
					CalculateTwoPtsAzimuth(azAngle,pts[i].lon, pts[i].lat,pts[i+1].lon,pts[i+1].lat,3);

					structPoint _structPoint;
					CalculatePtCoordinate(_structPoint.lon, _structPoint.lat, pts[i].lon, pts[i].lat, azAngle, (dblX-g_ptrArraySeries3[i]) * 100, 3);

					//发送到地图,标绘曲线上的点在地图上对应的点
					::SendMessage(g_mapHwnd, WM_DRAW_LINEPOINT, (WPARAM)&_structPoint, 1);

					return 0;
				}
			}
		}

		break;
	}

	return 0;
}

/*-------------------------------------------------------------------------------------------------------------
说明:通视等高线
-------------------------------------------------------------------------------------------------------------*/

//通视等高线分析
void CDlgLightRegion::OnBnClickedButtonContourline()
{
	UpdateData(TRUE);

	//获取地面站高程信息
	if(!m_mapElevation2.getElevation(m_fGroudAlt, m_dGroundLon, m_dGroundLat))
	{
		//未获取到高程值
		BCGPMessageBox(_T("地面站处无高程信息!"));

		return ;
	}
	else
	{
		//地面站位置的高度在地面站高程的基础上加上方舱高度
		m_fGroudAlt += (float)m_dCabinHgt;
	}

	g_dGroundLonCountour = m_dGroundLon;
	g_dGroundLatCountour = m_dGroundLat;
	g_fGroundAltCountour = m_fGroudAlt;

	if (m_iMaxLosAlt < m_fGroudAlt)
	{
		BCGPMessageBox(_T("最大高度不允许小于地面站高度!"));

		return ;
	}

	if (m_iMaxLosAlt > 10000)
	{
		BCGPMessageBox(_T("最大高度不允许超过10000!"));

		return ;
	}

	g_iMaxLosAlt = m_iMaxLosAlt;

	GetDlgItem(IDC_BUTTON_CONTOURLINE)->EnableWindow(FALSE);

	//清除通视等高线绘制图层
	::SendMessage(g_mapHwnd,WM_DEL_LINELAYER,0,0);

	//开启线程
	hThreadContour = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFuncAnalysisContour, NULL, 0, &ThreadIDContour);

	m_bRunContour = true;
}

//清除通视等高线
void CDlgLightRegion::OnBnClickedButtonContourDelete()
{
	//关闭线程
	m_bRunContour = false;

	::SendMessage(g_mapHwnd,WM_DEL_LINELAYER,0,0);

	GetDlgItem(IDC_BUTTON_CONTOURLINE)->EnableWindow(TRUE);

	m_pContourTextIndicator->SetText(_T(""));
	m_ContourTextContainer.RedrawWindow();
}

/*-------------------------------------------------------------------------------------------------------------
说明:两点间的通视分析
-------------------------------------------------------------------------------------------------------------*/

//坐标输入分析,根据输入的经纬度获取高程及通视高度
void CDlgLightRegion::OnBnClickedButtonGetAltValue()
{
	CString str;
	double _ptLon = 0.0, _ptLat = 0.0;

	//获取目标点的经度和纬度
	GetDlgItem(IDC_EDIT_POINT_LON)->GetWindowText(str);
	_ptLon = atof(str);

	GetDlgItem(IDC_EDIT_POINT_LAT)->GetWindowText(str);
	_ptLat = atof(str);

	if ((_ptLon == 0) || (_ptLat == 0) || (_ptLon > 180) || (_ptLon < -180) || (_ptLat > 90) || (_ptLat < -90))
	{
		BCGPMessageBox(_T("坐标无效!"));

		return ;
	}

	//获取高程
	float ptAlt = 0.0f;
	if(!m_mapElevation2.getElevation(ptAlt, _ptLon, _ptLat))
	{
		ptAlt = 0.0f;
	}

	str.Format(_T("%.1f"),ptAlt);
	GetDlgItem(IDC_EDIT_POINT_ALT)->SetWindowText(str);

	structPoint _tempPoint;
	_tempPoint.lon = _ptLon;
	_tempPoint.lat = _ptLat;

	//发送到地图,完成标绘
	::SendMessage(g_mapHwnd,WM_SEND_REGIONTOGIS,(WPARAM)3,(LPARAM)&_tempPoint);

	//通视分析
	LosBetweenTwoPoints();
}

//在地图上选点,获取高程并进行通视分析
void CDlgLightRegion::OnBnClickedButtonSelectPtInMap()
{
	::SendMessage(g_mapHwnd,WM_SEND_REGIONTOGIS,(WPARAM)1,0);
}

//在对话框里显示选择点的坐标和高程
void CDlgLightRegion::ShowPointPosition(double ptLon, double ptLat)
{
	CString str;

	str.Format(_T("%.7f"),ptLon);
	GetDlgItem(IDC_EDIT_POINT_LON)->SetWindowText(str);

	str.Format(_T("%.7f"),ptLat);
	GetDlgItem(IDC_EDIT_POINT_LAT)->SetWindowText(str);

	//获取高程
	float ptAlt = 0.0f;
	if(!m_mapElevation2.getElevation(ptAlt, ptLon, ptLat))
	{
		ptAlt = 0.0f;
	}

	str.Format(_T("%.1f"),ptAlt);
	GetDlgItem(IDC_EDIT_POINT_ALT)->SetWindowText(str);
}

//两点间通视分析
void CDlgLightRegion::LosBetweenTwoPoints()
{
	UpdateData(TRUE);

	//获取地面站的高程
	float _fGroundAlt = 0.0f;
	if(!m_mapElevation2.getElevation(_fGroundAlt, m_dGroundLon, m_dGroundLat))
	{
		//未获取到高程值
		BCGPMessageBox(_T("高程信息不全!"));

		return ;
	}
	//地面站位置的高度在地面站高程的基础上加上方舱高度
	_fGroundAlt += (float)m_dCabinHgt;

	pChart->ShowSeries(FALSE,2);
	pSeries1->RemoveAllDataPoints();
	pSeries2->RemoveAllDataPoints();

	CString str;
	double _ptLon = 0.0, _ptLat = 0.0;
	
	//获取目标点的经度和纬度
	GetDlgItem(IDC_EDIT_POINT_LON)->GetWindowText(str);
	_ptLon = atof(str);

	GetDlgItem(IDC_EDIT_POINT_LAT)->GetWindowText(str);
	_ptLat = atof(str);

	//计算地面站和目标点的距离和方位
	double dis = 0.0,angle = 0.0;
	CalculateTwoPtsDistanceAzimuth(dis, angle, m_dGroundLon, m_dGroundLat, _ptLon, _ptLat, 3);

	double _dTanMaxSlope = -1000.0;  //最大斜率
	double _fMinLOSAlt = 0.0;        //最小通视高度
	double _tempSlope = 0.0;         //当前点与地面站的连线的斜率

	//采样点位置
	double interPolLon = 0.0, interPolLat = 0.0;
	float interPolHight = 0.0;

	//以30为采样间距,计算插值个数
	int interPolDis = 30;
	int interPolNum = (int)(dis/interPolDis);

	for(int i = 0; i <= interPolNum; i++)
	{
		CalculatePtCoordinate(interPolLon, interPolLat, m_dGroundLon, m_dGroundLat, angle, i*interPolDis, 3);

		//获取采样点的高程
		if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
		{
			//未获取到高程值
			BCGPMessageBox(_T("高程信息不全!"));

			return ;
		}

		//计算该点与地面站连线的斜率
		_tempSlope = CalSlopeBetweenTwoPoint(m_dGroundLon, m_dGroundLat, _fGroundAlt, interPolLon, interPolLat, interPolHight);

		//与前面所有点的最大斜率比较,取最大值
		_dTanMaxSlope = max(_tempSlope,_dTanMaxSlope);

		//计算该点的最小通视高度
		_fMinLOSAlt   = (float)CalAltFromSlope(m_dGroundLon, m_dGroundLat, _fGroundAlt, interPolLon, interPolLat, _dTanMaxSlope);

		pSeries1->AddDataPoint(interPolHight,i*interPolDis);
		pSeries2->AddDataPoint(_fMinLOSAlt,i*interPolDis);
	}

	pChart->SetAutoDisplayRange(TRUE, TRUE);
	pChart->SetDirty(TRUE, TRUE);
	m_wndChart.RedrawWindow();

	//显示最小通视高度
	str.Format(_T("%.1f"),_fMinLOSAlt);
	GetDlgItem(IDC_EDIT_POINT_LOS)->SetWindowText(str);
}

//清除地面站与目标点连线,以及分析结果
void CDlgLightRegion::OnBnClickedButtonClearLineLayer()
{
	//清除目标点和连线图层
	::SendMessage(g_mapHwnd,WM_SEND_REGIONTOGIS,(WPARAM)2,0);

	//清除分析结果图标
	pSeries1->RemoveAllDataPoints();
	pSeries2->RemoveAllDataPoints();
	pSeries3->RemoveAllDataPoints();
	m_wndChart.RedrawWindow();
}

//反向通视分析
void CDlgLightRegion::OnBnClickedButtonReverse()
{
	UpdateData(TRUE);

	CString str;
	double _ptLon = 0.0, _ptLat = 0.0;

	//获取目标点的经度和纬度
	GetDlgItem(IDC_EDIT_POINT_LON)->GetWindowText(str);
	_ptLon = atof(str);

	GetDlgItem(IDC_EDIT_POINT_LAT)->GetWindowText(str);
	_ptLat = atof(str);

	//获取地面站的高程
	float _fGroundAlt = 0.0f;
	if(!m_mapElevation2.getElevation(_fGroundAlt, _ptLon, _ptLat))
	{
		//未获取到高程值
		BCGPMessageBox(_T("高程信息不全!"));

		return ;
	}
	//地面站位置的高度在地面站高程的基础上加上方舱高度
	_fGroundAlt += (float)m_dCabinHgt;

	pChart->ShowSeries(FALSE,2);
	pSeries1->RemoveAllDataPoints();
	pSeries2->RemoveAllDataPoints();

	//计算地面站和目标点的距离和方位
	double dis = 0.0,angle = 0.0;
	CalculateTwoPtsDistanceAzimuth(dis, angle, _ptLon, _ptLat, m_dGroundLon, m_dGroundLat, 3);

	double _dTanMaxSlope = -1000.0;  //最大斜率
	double _fMinLOSAlt = 0.0;        //最小通视高度
	double _tempSlope = 0.0;         //当前点与地面站的连线的斜率

	//采样点位置
	double interPolLon = 0.0, interPolLat = 0.0;
	float interPolHight = 0.0;

	//以30为采样间距,计算插值个数
	int interPolDis = 30;
	int interPolNum = (int)(dis/interPolDis);

	for(int i = 0; i <= interPolNum; i++)
	{
		CalculatePtCoordinate(interPolLon, interPolLat, _ptLon, _ptLat, angle, i*interPolDis, 3);

		//获取采样点的高程
		if(!m_mapElevation2.getElevation(interPolHight, interPolLon, interPolLat))
		{
			//未获取到高程值
			BCGPMessageBox(_T("高程信息不全!"));

			return ;
		}

		//计算该点与地面站连线的斜率
		_tempSlope = CalSlopeBetweenTwoPoint(_ptLon, _ptLat, _fGroundAlt, interPolLon, interPolLat, interPolHight);

		//与前面所有点的最大斜率比较,取最大值
		_dTanMaxSlope = max(_tempSlope,_dTanMaxSlope);

		//计算该点的最小通视高度
		_fMinLOSAlt   = (float)CalAltFromSlope(_ptLon, _ptLat, _fGroundAlt, interPolLon, interPolLat, _dTanMaxSlope);

		pSeries1->AddDataPoint(interPolHight,i*interPolDis);
		pSeries2->AddDataPoint(_fMinLOSAlt,i*interPolDis);
	}

	pChart->SetAutoDisplayRange(TRUE, TRUE);
	pChart->SetDirty(TRUE, TRUE);
	m_wndChart.RedrawWindow();
}

//标绘作战范围
void CDlgLightRegion::OnBnClickedButtonDrawFight()
{
	UpdateData(TRUE);

	structPoint _structPoint;

	_structPoint.lon = m_dGroundLon;
	_structPoint.lat = m_dGroundLat;

	//发送到地图,绘制作战范围
	::SendMessage(g_mapHwnd, WM_SEND_DRAWFIGHT, WPARAM(&_structPoint), LPARAM(m_iFightRegion*1000));
}

//清除作战范围
void CDlgLightRegion::OnBnClickedButtonDeleteFight()
{
	::SendMessage(g_mapHwnd, WM_SEND_DRAWFIGHT, 0, 0);
}

//标绘高程数据区域
void CDlgLightRegion::OnBnClickedButtonGetDemRegion()
{
	CString _DEMpath = GetSoftwareCurrentDirectory() + _T("\\ElevationData");

	//文件句柄 
	long  hFile  =  0; 
	//文件信息 
	struct _finddata_t fileinfo; 
	string p; 
	if((hFile = _findfirst(p.assign(_DEMpath.GetBuffer()).append("\\*").c_str(),&fileinfo)) != -1) 
	{
		int _fileNum = 0;
		char fileName[3];
		structPoint _structPoint;

		char _flag;

		do
		{  
			if((fileinfo.attrib & _A_SUBDIR)) 
			{ 
				;
			} 
			else
			{
				//处理遍历到的文件名
				memset(fileName,0,3);
				memset(&_structPoint,0,sizeof(structPoint));

				//纬度
				memcpy(fileName, fileinfo.name+8, 2);
				_structPoint.lat = atof(fileName);

				memcpy(&_flag, fileinfo.name+7, 1);
				if ('S' == _flag)
				{
					_structPoint.lat = 0 - _structPoint.lat;
				}

				//经度
				memcpy(fileName, fileinfo.name+11, 3);
				_structPoint.lon = atof(fileName);

				memcpy(&_flag, fileinfo.name+10, 1);
				if ('W' == _flag)
				{
					_structPoint.lon = 0 - _structPoint.lon;
				}

				_fileNum++;
				::SendMessage(g_mapHwnd, WM_SEND_DRAWDEMREGION, WPARAM(&_structPoint), LPARAM(_fileNum));
			}  
		}while(_findnext(hFile, &fileinfo) == 0); 
		_findclose(hFile); 
	} 

	_DEMpath.ReleaseBuffer();
}