QTは、経度と緯度の画像ピクセル座標への変換を実現します
ニーズの声明
最近、開発中にこの種の需要に遭遇しました。地球の経度と緯度を考慮して、静止画像マップ上で経度と緯度の位置をマークします。
需要分析
地球の緯度と経度は球面座標系です。画像は平面座標系であり、直接変換することはできません。GoogleMapsは、球面を平面に変換するときに「メルカトル投影法」を使用します(興味のある学生はBaidu)。座標系は依然として均一に分布していますが、寸法は均一に分布していません。平面座標系のピクセル座標を取得するには、特別な計算が必要です。
コード
世界地図の例
例として世界地図を取り上げます。最大の世界地図はGoogleマップにキャプチャされます:経度-180度から180度、緯度-85度から85度(メルカトル図法の後、地球の最大緯度は-90から90です。 90度は、無限大では平面を表現できない傾向があります)、アルゴリズムの中核は、不均一な次元を均一な表現に変換することです。
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPainter>
#include <QImage>
namespace Ui {
class Widget;
}
struct MAP_X_Y{
double x;
double y;
};
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void displayPos();//地图显示位置
MAP_X_Y AxesConvert(double lon,double lat);//经纬度转换为像素坐标
public slots:
void slotpushButton();
private:
Ui::Widget *ui;
QImage *m_pImage;//定义QImage绘图设备
QPainter *m_pPainter;//定义画家
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPixmap>
#include <QDebug>
#include <QPainter>
#include <QImage>
#include <cmath>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("世界地图");
m_pImage = new QImage(1024,1024,QImage::Format_ARGB32);
m_pPainter = new QPainter(m_pImage);
m_pPainter->drawImage(0,0,QImage("./images/worldMap.jpg"));
ui->label->setPixmap(QPixmap::fromImage(*m_pImage));//UI控件显示图片
connect(ui->pushButton,SIGNAL(clicked(bool)),this,SLOT(slotpushButton()));
}
Widget::~Widget()
{
delete ui;
}
/**
* @brief 显示位置
*/
void Widget::displayPos()
{
double lon = ui->lineEdit_lon->text().toDouble();
double lat = ui->lineEdit_lat->text().toDouble();
MAP_X_Y t_MAP_X_Y = AxesConvert(lon,lat);//经纬度转换为像素坐标
m_pPainter->drawImage(0,0,QImage("./images/worldMap.jpg"));
for(int i=t_MAP_X_Y.x;i<t_MAP_X_Y.x+5;i++)
for(int j=t_MAP_X_Y.y;j<t_MAP_X_Y.y+5;j++)
{
m_pImage->setPixel(i,j,qRgb(255,0,0));//按像素点修改图片颜色,图片中显示为红色方块
}
ui->label->setPixmap(QPixmap::fromImage(*m_pImage));
}
/**
* @brief 经纬度转换为像素坐标
* @param lon 经度
* @param lat 维度
* @return 像素坐标
*/
MAP_X_Y Widget::AxesConvert(double lon, double lat)
{
const double pixel_Width = 1024;//截取地图像素宽度
const double pixel_Height = 1024;//截取地图像素高度
const double PI = 3.1415926;
const double MaxLon = 180;//截取地图的最大经度
const double MaxLat = 85;//截取地图的最大维度
int pixel_X;
int pixel_Y;
/**
* @brief google地图中能够截取的最大经度是180度,最大维度是85度
* 转换为平面坐标系后经度是均匀分布的,维度不是均匀分布
*经过下面公式计算后,得到的“修正维度”是均匀的,传入MaxLat计算出来的值是修正维度的最大值
*/
double reviseMaxLat = log(tan((90+MaxLat)*PI/360))/(PI/180);//修正后的最大维度
lat = log(tan((90+lat)*PI/360))/(PI/180);//修正后的维度
//平面坐标系可分为4个象限,坐标落在不同象限的计算方式不同
if(lon>=0 && lat>=0)
{
pixel_X = (lon/MaxLon)*(pixel_Width/2)+pixel_Width/2;
pixel_Y = (pixel_Height/2) - (lat/reviseMaxLat)*(pixel_Height/2);
}
else if(lon>=0 && lat<=0)
{
pixel_X = (lon/MaxLon)*(pixel_Width/2)+pixel_Width/2;
pixel_Y = (pixel_Height/2) + (-lat/reviseMaxLat)*(pixel_Height/2);
}
else if(lon<=0 && lat >=0)
{
pixel_X = pixel_Width/2 - (-lon/MaxLon)*(pixel_Width/2);
pixel_Y = (pixel_Height/2) - (lat/reviseMaxLat)*(pixel_Height/2);
}
else if(lon<=0 && lat<=0)
{
pixel_X = pixel_Width/2 - (-lon/MaxLon)*(pixel_Width/2);
pixel_Y = (pixel_Height/2) + (-lat/reviseMaxLat)*(pixel_Height/2);
}
MAP_X_Y t_sMap;
t_sMap.x = pixel_X;
t_sMap.y = pixel_Y;
return t_sMap;
}
void Widget::slotpushButton()
{
displayPos();
}
北京の場所を示すレンダリング
カスタマイズされた地図:中国周辺
以下は、中国周辺の地図をカスタマイズし、経度の範囲を60度から160度、緯度の範囲を0度から60度、および座標変換関数をインターセプトする例です。
/**
* @brief 经纬度转换为像素坐标
* @param lon
* @param lat
* @return
*/
MAP_X_Y China_Map::AxesConvert_Custom(double lon, double lat)
{
const double pixel_Width = 1143;//截取地图像素宽度
const double pixel_Height = 859;//截取地图像素高度
const double PI = 3.1415926;
const double LeftLon = 60;//地图最左侧经度
const double RightLon = 160;//地图最右侧经度
const double TopLat = 60;//地图顶部维度
const double BottomLat = 0;//地图底部维度
int pixel_X;
int pixel_Y;
/**
* @brief google地图中能够截取的最大经度是180度,最大维度是85度
* 转换为平面坐标系后经度是均匀分布的,维度不是均匀分布
*经过下面公式计算后,得到的“修正维度”是均匀的,传入MaxLat计算出来的值是修正维度的最大值
*/
double reviseMaxLat = log(tan((90+(TopLat))*PI/360))/(PI/180);//修正后的最大维度
lat = log(tan((90+lat)*PI/360))/(PI/180);//修正后的维度
//截取的地图经度和维度都大于0,只集中在一个象限
pixel_X = ((lon - LeftLon)/(RightLon - LeftLon))*pixel_Width;
pixel_Y = pixel_Height - (lat - BottomLat)/(reviseMaxLat - BottomLat)*pixel_Height;
MAP_X_Y t_sMap;
t_sMap.x = pixel_X;
t_sMap.y = pixel_Y;
return t_sMap;
}
南京の場所を示すレンダリング