//alter load_map.dev //safety verion 2016/1/12 #include <iostream> #include <fstream> #include <vector> #include <stdlib.h> #include<sstream> //使用istringstream必须包含的头文件 #include<string> #include "string2num.hpp" #include "map.hpp" #include <windows.h> #include <GL/glut.h> using namespace std; void test_map(){ unsigned int sum;double Sa; double north=polys[0]->north(); double south=polys[0]->south(); double east=polys[0]->east(); double west=polys[0]->west(); for(int i=0;i<polys.size();i++){ sum+=polys[i]->points.size(); Sa+=polys[i]->area(); } for(int i=0;i<polys.size();i++){ //比较每一个polygon的边界值,求出整个地图的四个边界值 if(polys[i]->north()>=north)north=polys[i]->north(); if(polys[i]->south()<=south)south=polys[i]->south(); if(polys[i]->east()>=east)east=polys[i]->east(); if(polys[i]->west()<=west)west=polys[i]->west(); } ofstream out("map_para.txt"); if(out.is_open()) { out <<"map parameter: "; out<<"count polygon="<<polys.size()<<endl; out<<"size="<<sum<<endl; out<<"area="<<Sa<<endl; out<<"north="<<north<<endl; out<<"south="<<south<<endl; out<<"east="<<east<<endl; out<<"west="<<west<<endl; out.close(); } } 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 (0, 1.0, 0, 0.0); //初始化观察值 glMatrixMode(GL_PROJECTION); //将矩阵模式设为投影 glLoadIdentity(); //对矩阵进行单位化 glOrtho(110.0, 118.0, 30.0, 38.0, -1.0, 1.0); //构造平行投影矩阵 } int main(int argc, char *argv[]){ //数据文件请到http://files.cnblogs.com/opengl/HenanCounty.rar下载放到D盘根目录下并解压 string filename="HenanCounty.txt";//在当前工程目录下 // ReadData2num(filename); polys=ReadMapData(filename); test_map(); glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); //单缓存和RGB glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow ("Map_henan"); init (); glutDisplayFunc(display); //显示回调函数 glutMainLoop(); return 0; }
"HenanCounty.txt"是一份文本格式的地图:
单个整数代表点数(包含的点可能是某个省内市区的范围),整数n下面紧接着的数据行共有n行,是以经纬度表示的地理坐标。
程序运行结果:
关于地图的信息(多边形数目、总点数、面积、边界)通过test_map()函数写入map_para.txt
目前算得的面积还有问题,这通过边界值就可以看出来,这还有待解决。
string2num.hpp定义了模板函数用于字符串形式的数字向基本数值类型的转化(其实这个定义比较多余<sstream>里面定义的字符串处理类包含此功能)
#ifndef _STRING2NUM_HPP_ #define _STRING2NUM_HPP_ #include<sstream> //使用istringstream必须包含的头文件 #include<string> using namespace std; //模板函数:将string类型变量转换为常用的数值类型 by maowei template <class Type> Type stringToNum(const string& str) { istringstream iss(str); Type num; iss>>num; return num; } #endif
map.hpp包括了基本类的定义,这是在map_origin.cpp的基础上修改得到的,主要是增加了一些获取地图信息相关的函数。其中多边形容器的定义部分值得充分学习消化。
#ifndef _MAP_HPP_ #define _MAP_HPP_ #include <vector> #include <math.h> using namespace std; class MapPoint { public: double longitude;//经度 double latitude;//纬度 MapPoint(){} MapPoint(double x,double y){longitude=x;latitude=y;} }; class Map { public: int mapsize; vector<MapPoint> points; //多边形的顶点序列 Map(){} Map(int i){mapsize=i;} }; //unsigned int count,num; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%translate from origin class Polygon { public: vector<MapPoint> points; //多边形的顶点序列 double area(void){ double A=0;unsigned int N=points.size(); for(int i=0;i<(N-1);i++){ A+=fabs(points[i].longitude*points[i+1].latitude-points[i].latitude*points[i+1].longitude); } A+=fabs(points[N-1].longitude*points[0].latitude-points[N-1].latitude*points[0].longitude); return A/2; } double north(void){ double N=points[0].latitude; for(int i=0;i<points.size();i++){if(points[i].latitude>=N)N=points[i].latitude; } return N; } double south(void){ double S=points[0].latitude; for(int i=0;i<points.size();i++){if(points[i].latitude<=S)S=points[i].latitude; } return S; } double east(void){ double E=points[0].longitude; for(int i=0;i<points.size();i++){if(points[i].longitude>=E)E=points[i].longitude; } return E; } double west(void){ double W=points[0].longitude; for(int i=0;i<points.size();i++){if(points[i].longitude<=W)W=points[i].longitude; } return W; } }; vector<Polygon*> polys; //多边形集合 vector<Polygon*> ReadMapData(const string filename) { int PointCount; vector<Polygon*> polygons; ifstream fs(filename.c_str()); 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; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Map ReadData2num(const string str) //逐行读取 并转化为常用数据类型 by mememagic { cout<<"start read map"<<endl; ifstream fin(str.c_str()); if (! fin.is_open()) { cout << "Error opening file"; exit (1); } string s; Map Imap; int Size=0,i=0;bool flag; while( getline(fin,s) ) { if(i==Size){int s_i=stringToNum<int>(s);Size=s_i+1;i=0;//count+=s_i;num++; //cout << "(vertex num): " << s_i << endl; } else { istringstream is(s);//采用istringstream从string对象str中读取字符 string s1;double x,y; while(is>>s1){ double s_d=stringToNum<double>(s1); if(!flag){x=s_d;flag=!flag; } else{y=s_d;flag=!flag; } //cout<<s_d<<' '; } //cout<<"x="<<x<<' '<<"y="<<y<<endl; MapPoint p(x,y); Imap.points.push_back(p); } i++; } return Imap; } #endif
与Draw_v1相比,这个程序有了不少变化:数据来源不再靠手工在命令窗口输入,而是一个有确定“格式”的简单文本,数据量也较大,程序里面对数据的处理代码自然不同;多边形容器(vector<Polygon*> polys )是对图形(vector<Shape>)容器的拓展;利用OpenGL实现了数据的可视化(关于OpenGL绘图的原理有待进一步学习理解).