目录

3.6 编程实例 - 地图绘制

3.6.1 地图绘制方法

3.6.2 基于OpenGL的地图绘制

3.6.3 代码


3.6 编程实例 - 地图绘制

显示漂亮的地图是地理信息系统软件的基本功能。事实上,借助基本图元的绘制函数,可以很容易地编写一个可以显示地图的程序。在地里信息系统中,地图数据可以分为两类,一类是矢量数据,它是以点、线、多边形三种图元形式表示地图的图形数据,比如行政区、湖泊可以用多边形表示,河流、道路用折线表示。另一类叫做栅格数据,它是以点阵形式表示的图像数据。利用计算机图形学的知识和编程技术,不难将这两种数据绘制出来。

3.6.1 地图绘制方法

以河南省为例,可以用多边形表示县级行政区边界的形状,即每个县表示为一个多边形,如果这个省包括多个岛,则每个岛屿也是独立的多边形,而每个多边形是由组成它边界顶点序列表示的。假定图形数据用经纬网坐标系表达。

显示这样的各县地图的步骤如下:

(1)读入数据。把每个多边形的边界顶点序列从磁盘中读入存放在一个点数组中,再把所有表示多边形的点数组指针存放进一个容器对象中,该容器可以是数组、链表或任何动态数据结构。多边形和折线可分别用两个容器存放。

地图中每个岛屿与省份多边形的数据在文本文件中的存储方式为,先在一行中用一个数表示多边形的顶点个数,接着按一顶顺序列举各顶点的坐标,每个点的坐标占据一行。如图所示。

注:所用数据基于国家测绘局发布的标准地理信息

<figcaption> 数据文件格式 </figcaption>

(2)变换图形。河南省大致在东经110°~117°和北纬31°~36°范围内,当用GDI以经度(x轴)和纬度(y轴)对屏幕坐标1:1绘制时,则会得到一幅很小的地图,几乎看不清楚。先将所有顶点经度值减去110、纬度值减去31,再将纬度值和经度值乘以一个因子,得到放大了的地图数据。当用OpenGL绘制时,只需设置glOrtho的平行投影参数来控制显示范围,因而无需做上述变换。

(3)采用循环的方式,分别遍历两个图元容器中的所有数据,调用多边形及折线的图元绘制功能将上述变换后的数据在屏幕上绘出。利用区域填充功能,还可以将所有多边形以某种颜色填充,得到彩色的地图。

3.6.2 基于OpenGL的地图绘制

虽然OpenGL中提供了GL_POLYGON指令用于创建多边形,但它只支持凸多边形,无法正确绘制任意多边形。可将任意多边形分割为多个凸多边形,但这个分割过程通常由人工来完成,因此不适合用来批量绘制任意多边形。为了简便处理,这里使用GL_LINE_LOOP指令来绘制多边形的闭合边界,而不再绘制用颜色填充的多边形。使用OpenGL绘制的河南省各县地图效果如图所示。

<figcaption> 使用OpenGL绘制的河南省地图 </figcaption>

3.6.3 代码

完整工程及数据文件下载:https://download.csdn.net/download/me__we/10821480

#include "stdafx.h"

#include <iostream>
#include <fstream>
#include<vector>
#include <GL/glut.h>
using namespace std;

class MapPoint
{
public:
	double longitude;
	double latitude;
};

class Polygon
{
public:
	vector<MapPoint> points; //多边形的顶点序列
};

vector<Polygon*> polys; //多边形集合
vector<Polygon*> ReadMapData(const char* filename)
{
	int PointCount;
	vector<Polygon*> polygons;
	ifstream fs(filename);
	while (fs.eof() != true)
	{
		Polygon* poly = new Polygon;
		fs >> PointCount;
		cout << PointCount << endl;
		for (int i = 0; i<PointCount; i++)
		{
			MapPoint p;
			fs >> p.longitude >> p.latitude;
			poly->points.push_back(p);
		}
		polygons.push_back(poly);

	}
	return polygons;
}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	//用蓝***绘制各省边界
	glColor3f(0.0, 0.0, 1.0);
	glPolygonMode(GL_BACK, GL_LINE);
	for (int i = 0; i<polys.size(); i++)
	{
		vector<MapPoint> points = polys[i]->points;
		glBegin(GL_LINE_STRIP);
		for (int j = 0; j<points.size(); j++)
		{
			glVertex3f(points[j].longitude, points[j].latitude, 0.0);
		}
		glEnd();
	}
	glFlush();
}

void init(void)
{
	//设置背景颜色
	glClearColor(1.0, 1.0, 1.0, 0.0);
	//初始化观察值
	glMatrixMode(GL_PROJECTION);			//将矩阵模式设为投影
	glLoadIdentity();						//对矩阵进行单位化
	glOrtho(110.0, 117.0, 31.0, 37.0, -1.0, 1.0);		//构造平行投影矩阵
}

int main(int argc, char** argv)
{
	const char* filename = "F:/HenanCounty.txt";		//根据自己下载的文件位置更改
	polys = ReadMapData(filename);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);		//单缓存和RGB
	glutInitWindowSize(700, 700);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("河南地图");
	init();
	glutDisplayFunc(display);			//显示回调函数
	glutMainLoop();
	return 0;
}