MFC读shapefile线或面文件画地图

本文介绍使用MFC从Shapefile文件读取线或面数据并绘制地图的方法。通过解析Shapefile文件结构,利用内存画布进行地图绘制,最终在客户区显示绘制结果。代码实现包括初始化画布、读取Shapefile数据、绘制地图及显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MFC读shapefile线或面文件画地图

源代码

头文件声明成员变量

	RECT m_clientRECT;
	CDC *m_Province_Boundary_memDC;
	CBitmap *m_Province_Boundary_memBmp;
	//最小经度与最大纬度
	float m_minlon;
	float m_maxlat;
	//画图比例
	int m_ratio;

oncreate函数定义变量,内存画图

	GetParentFrame()->GetClientRect(&m_clientRECT);
	m_clientDC = GetDC();

	m_Province_Boundary_memBmp = new CBitmap();
	m_Province_Boundary_memDC = new CDC();
	m_Province_Boundary_memDC->CreateCompatibleDC(m_clientDC);
	m_Province_Boundary_memBmp->CreateCompatibleBitmap(m_clientDC,memw,memh);
	m_Province_Boundary_memDC->SelectObject(*m_Province_Boundary_memBmp);
	
	m_minlon = 73;
	m_maxlat = 54; 
	m_ratio = 3600 / 40;

画图函数

	CString strFilePath;//shapefile文件路径
	CString strName = _T("Province_Boundary.shp");//shapefile文件名
	strFilePath.Format(_T(".\\Map\\%s"), strName);//shapefile文件放在项目目录创建的Map文件夹中
	
	CPen pen(PS_SOLID, 2, clr);//创建画笔,2为线宽,clr是颜色
	CPen *pen_Old = m_Province_Boundary_memDC->SelectObject(&pen);//选择画笔

	FILE* fp = fopen(strFilePath, _T("rb"));
    if (fp == NULL) {
        AfxMessageBox(_T"打开shapefile文件失败");
        exit(0);
    }
	//读取文件头
	int fc;                  //File Code:9994
	int ud;                  //Unused
    int fl;                  //文件的实际长度
    int vr;                  //版本号
    int ft;                  //几何类型
	                         //0 Null Shape 表示这个 Shapefile 文件不含坐标
                             //1 Point 表示 Shapefile 文件记录的是点状目标,但不是多点
                             //3 PolyLine 表示 Shapefile 文件记录的是线状目标
                             //5 Polygon 表示 Shapefile 文件记录的是面状目标
    double xi;               //空间数据所占空间范围的 X 方向最小值
    double yi;               //空间数据所占空间范围的 Y 方向最小值
    double xa;               //空间数据所占空间范围的 X 方向最大值
    double ya;               //空间数据所占空间范围的 Y 方向最大值
    double zi;               //空间数据所占空间范围的 Z 方向最小值
    double za;               //空间数据所占空间范围的 Z 方向最大值
    double mi;               //Measure最小值
    double ma;               //Meature最大值

	fread(&fc, sizeof(int), 1, fp);     //读取File Code
	for(int i=0;i<5;i++) fread(&ud, sizeof(int), 1, fp); //读取Unused
	fread(&fl, sizeof(int), 1, fp);     //读取文件的实际长度
    fread(&vr, sizeof(int), 1, fp);     //读取版本号
    fread(&ft, sizeof(int), 1, fp);     //读取几何类型
    fread(&xi, sizeof(double), 1, fp);
    fread(&yi, sizeof(double), 1, fp);
    fread(&xa, sizeof(double), 1, fp);
    fread(&ya, sizeof(double), 1, fp);
    fread(&zi, sizeof(double), 1, fp);
    fread(&za, sizeof(double), 1, fp);
    fread(&mi, sizeof(double), 1, fp);
    fread(&ma, sizeof(double), 1, fp);

	//读取实体内容
	if(ft == 3||ft == 5){       //线类型或者面类型
		int num;                 //记录序号
		int len;                 //记录长度
		while((fread(&num, sizeof(int), 1, fp) != 0)){  //逐条读记录
			fread(&len, sizeof(int), 1, fp);         //读取当前记录长度
			int ftp;                                 //当前记录类型记录
            double area[4];                          //当前记录坐标范围
			int partnum;                             //当前记录包含的子线段/子环个数
            int pointnum;                            //当前记录坐标点数
            int *part;                               //每个子线段/子环的第一个坐标点在所有坐标中的位置
			fread(&ftp, sizeof(int), 1, fp);         //读ftp
            for(int i = 0; i < 4; i++) fread(area + i, sizeof(double), 1, fp); //读area
            fread(&partnum, sizeof(int), 1, fp);      //读partnum
            fread(&pointnum, sizeof(int), 1, fp);     //读pointnum
            part = new int[partnum];                 //根据子线段/子环个数动态分配part数组内存
            
			for(int i = 0; i < partnum; i++) fread(part + i, sizeof(int), 1, fp);

			int pointnum1 = 0;//真实点数

			for(int i = 0; i < partnum; i++){
				if(i != partnum - 1) pointnum1 =  part[i + 1] - part[i];//每个子环的长度 ,非最后一个环
				else pointnum1 = pointnum - part[i];	//最后一个环
				double *pointsx;                         //x坐标临时存储数组
				double *pointsy;                         //y坐标临时存储数组
				pointsx = new double[pointnum1];           //动态分配内存
				pointsy = new double[pointnum1];

				for(int j = 0; j < pointnum1; j++){
					 fread(pointsx + j, sizeof(double), 1, fp);
					 fread(pointsy + j, sizeof(double), 1, fp);
				}

				//非闭环(首尾两个点不一致),跳过
				if(pointsx[0] != pointsx[pointnum1 - 1] || pointsy[0] != pointsy[pointnum1 - 1]){
					delete []pointsx;
					delete []pointsy;
					continue;
				}

				for(int j = 0; j < pointnum1; j++){
					pointsx[j] = (pointsx[j] - m_minlon) * m_ratio;
					pointsy[j] = (m_maxlat - pointsy[j]) * m_ratio;
					if(j > 0){
						//此处在内存画布中画地图
						m_Province_Boundary_memDC->MoveTo(pointsx[j - 1], pointsy[j - 1]);
						m_Province_Boundary_memDC->LineTo(pointsx[j], pointsy[j]);
					}
				}
				delete []pointsx;
				delete []pointsy;
			}
		}
	}

	m_Province_Boundary_memDC->SelectObject(pen_Old);
	DeleteObject(pen);
	fclose(fp);

在客户区显示

CClientDC dc(this);
dc.BitBlt(0, 0, m_clientRECT.right, m_clientRECT.bottom, m_Province_Boundary_memDC, 0, 0, SRCCOPY);

注意

m_ratio; 决定地图大小
m_minlon; m_maxlat;两者确定左上角的经纬度

显示结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值