MFC显示墨卡托海图投影栅格

可能是专业比较冷门,网上没找到比较系统的墨卡托海图的投影画法,故此自己按照《电子海图的数学和算法基础》一书的公式写了一套简单的算例,供参考,转载请标明出处。

实现效果

最后实现的效果如下,只是做了练手的,界面比较粗糙。

 

 代码

直接上代码!!

1.没什么特别的头文件

#include "pch.h"
#include "framework.h"
#include "MFCMercator.h"
#include "MFCMercatorDlg.h"
#include "afxdialogex.h"

2.绘制底图

按照建立的窗口大小,一定自适应地绘制墨卡托投影的基本线,线间距可以自行设定。

void CMFCMercatorDlg::LocalPaint(CDC* pDC)
{
    // TODO: 在此处为本机数据添加绘制代码
	CRect rect;	//定义一个矩形对象
	GetClientRect(rect);//初始化(rect不是一个数值,很多属性)
	//使用映射模式函数
	pDC->SetMapMode(8);
	int lat = rect.Width();//窗口宽度
	int lon = rect.Height();//窗口高度
	pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口宽度和高度,使用rect的方法
	//pDC->SetWindowExt(2000, 1000);//设置窗口宽度和高度,使用rect的方法
	pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区大小
	//得到一个x轴水平向右,y轴垂直向上,原点位于视区左下顶点的坐标轴
	pDC->SetViewportOrg(rect.Width() / 2 - 0, rect.Height() / 2);//设置原点位置

	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//将矩形移回框内

	//绘制墨卡托经线
	float lonprecision = 180 / 20;
	float londelta = x / lonprecision;
	for (int j = 0; j <= 2 * lonprecision; j++)
	{
		CPoint P5(-x + j * londelta, -y1);
		pDC->MoveTo(P5);
		CPoint P6(-x + j * londelta, y1);
		pDC->LineTo(P6);
	}
	//绘制墨卡托纬线

	for (int i = 0; i <= 80; i = i + 20)
	{
		//北纬
		CPoint P1(-x, latlocation / latlen * 400);
		pDC->MoveTo(P1);
		CPoint P2(x, latlocation / latlen * 400);
		pDC->LineTo(P2);
		//南纬
		CPoint P3(-x, -latlocation / latlen * 400);
		pDC->MoveTo(P3);
		CPoint P4(x, -latlocation / latlen * 400);
		pDC->LineTo(P4);
		latlocation = latlocation + DistanceCal(i, i + 20);
	}

	GetDlgItem(IDC_BUTTON_Draw)->EnableWindow(false);
	GetDlgItem(IDC_STATIC_now)->ShowWindow(true);
	GetDlgItem(IDC_EDIT_Location)->ShowWindow(true);
	SetDlgItemText(IDC_BUTTON_Draw, _T("已绘制墨卡托投影"));
}

更新墨卡托投影中纬线的位置。

float CMFCMercatorDlg::DistanceCal(float lat_0, float lat_1)
{

	//e2 = (pow(a, 2) - pow(b, 2)) / pow(a, 2);
	//e = sqrt(e2);//第一偏心率

	lat_0 = (M_PI / 180) * lat_0;//纬度弧度
	lat_1 = (M_PI / 180) * lat_1;

	//计算纬度圈半径
	//float r0;
	//r0 = a * cos(lat_0) / sqrt(1 - e * e * pow(sin(lat_0), 2));

	float x;
	x = r0 * (Qcal(lat_1, e) - Qcal(lat_0, e));
	return x;
}

 3.显示所在经纬度

获取鼠标的位置,在label中显示。 

void CMFCMercatorDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CRect rect;	//定义一个矩形对象
	GetClientRect(rect);//初始化(rect不是一个数值,很多属性)

	CString str, str1, str2;
	float lon, lat;
	lon = (point.x - rect.Width() / 2 + 0);
	lat = -(point.y - rect.Height() / 2);
	if (lon <= x1 && lon >= -x1 && lat >= -438 && lat <= 438)
	{
		lon = 180 * lon / x1;//经度显示
		//lat = lat * latlen / 400;//纬度显示
		lat = AntiCal(lat * latlen / 400);//纬度显示
		str1 = CString((to_string(lon).c_str()));
		str2 = CString((to_string(lat).c_str()));
		str.Format(_T("[%s,%s]"), str1, str2);
		//str.Format(_T("[%d,%d]"), 180 * lon / x1, 180 / M_PI * asin(lat * 10000000 / 400 / b));
		//获得程序状态栏对象的指针,AFX_IDW_STATUS_BAR就是状态栏的ID
		//它的功能是通过指定的ID来获得子孙窗口
		GetDlgItem(IDC_EDIT_Location)->SetWindowText(str);
	}
	else
	{
		SetDlgItemText(IDC_EDIT_Location, _T("超出地图范围"));
	}
	CDialogEx::OnMouseMove(nFlags, point);
}

反解计算鼠标所在位置对应投影图的经纬度值。

float CMFCMercatorDlg::AntiCal(double latdis)
{
	double qtemp;
	qtemp = latdis / a + Qcal(0, sqrt((pow(a, 2) - pow(b, 2)) / pow(a, 2)));

	//q= Qcal(lat_1, e)
	//直接反解法
	double B2 = 0.33560695588 * 1e-2, B4 = 0.65700353 * 1e-5, B6 = 0.176221 * 1e-7, B8 = 0.608 * 1e-10;
	double phi, phi_;

	phi_ = 2 * atan(pow(M_E, qtemp)) - M_PI / 2;
	phi = phi_ + B2 * sin(2 * phi_) + B4 * sin(4 * phi_) + B6 * sin(6 * phi_) + B8 * sin(8 * phi_);
	return (180 / M_PI) * phi;
}

4.窗口外观设置

	// TODO: 在此添加额外的初始化代码
		//设置样式
	//改按钮样式
	CFont* font = new CFont();//开一个空间
	font->CreateFont(24,                       // nHeight
		0,                        // nWidth
		0,                        // nEscapement
		0,                        // nOrientation
		FW_NORMAL,                // nWeight
		FALSE,                    // bItalic
		FALSE,                    // bUnderline
		0,                        // cStrikeOut
		ANSI_CHARSET,             // nCharSet
		OUT_DEFAULT_PRECIS,       // nOutPrecision
		CLIP_DEFAULT_PRECIS,      // nClipPrecision
		DEFAULT_QUALITY,          // nQuality
		DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
		_T("黑体"));
	GetDlgItem(IDC_EDIT_Location)->SetFont(font);//放入字体格式
	GetDlgItem(IDC_BUTTON_Draw)->SetFont(font);//放入字体格式
	GetDlgItem(IDC_EDIT_PLocation)->SetFont(font);//放入字体格式

	this->MoveWindow(100, 100, 1800, 1200, true);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值