shp系列(五)——利用C++进行shp文件的写(创建)
之前介绍了shp文件、dbf文件和shx文件的的读取,接下来将分别介绍它们的创建过程。一般来说,读和写的一一对应的,写出的文件就是为了保存数据供以后读取的。写的文件要符合shapefile的标准。之前读取的时候使用的函数是fread,写的函数对应为fwrite,文件为二进制流文件。
建议本博客和之前shp读取的博客一起看!
建议本博客和之前shp读取的博客一起看!
建议本博客和之前shp读取的博客一起看!
1.位序little转为big
shp文件中部分参数是big类型,读取的时候读取的big要转化为little,写的时候little转化为big,代码如下:
// 将十进制转换成十六进制,并转成big
int OnChangeByteOrderTenToSixteen(int indata)
{
int yushu;
int i = 7;
char ss[8];
if (indata == 0) return 0;
while (indata > 0) {
yushu = indata % 16;
char k;
if (yushu > 9)
k = 'a' + yushu - 10;
else
k = '0' + yushu;
ss[i] = k;
indata = indata / 16;
i--;
} //****进行倒序
for (int j = 0; j<i + 1; j++) {
ss[j] = '0';
}
int t, temp;
t = ss[0]; ss[0] = ss[6]; ss[6] = t;
t = ss[1]; ss[1] = ss[7]; ss[7] = t;
t = ss[2]; ss[2] = ss[4]; ss[4] = t;
t = ss[3]; ss[3] = ss[5]; ss[5] = t;
for (i = 0; i < 8; i++) {
if (ss[i] != '0') {
temp = i;
break;
}
}
int k;
int num = 0;
for (i = temp; i < 8; i++) {
if (ss[i] >= 'a'&&ss[i] <= 'f')
k = 10 + ss[i] - 'a';
else
k = ss[i] - '0';
num = num * 16 + k;
}
return num;
}
2.Shp头文件的创建
Shp头文件参数之前已经介绍很清楚了,按照顺序创建对应类型的变量,赋值,FileCode和FileLength需要转化为big类型。其中FileLength由于刚开始写的时候不确定数值,可以暂时写一个数值(如0或100),后面需要回来修改,因为需要统计所有点的个数和环数等才能得出正确的值。
3.Shp主体信息的创建
主体信息分为记录头和记录信息两部分。
3.1记录头的创建
记录头包括两项,记录的序号RecordNumber和记录长度ContentLength,都是big类型。ContentLength是指本条记录的长度,不包括RecordNumber和ContentLength本身字节数,先暂时写一个值,后面要修改,类似于FileLength。
3.2记录信息的创建
还是以Polygon为例,包括ShapeType,Box[4],NumParts,NumPoints,Parts和Points。各项含义参考shp的读取的博客。
4.FileLength和ContentLength的计算
此二者是shp文件写的最大的难点,需要利用fseek函数(使用方法自行百度),将文件指针移回到FileLength和ContentLength的位置,修改它们的值。每条记录的长度不一样,需要累加每条记录的字节数才能得到所有记录的字节数,然后加上头文件的字节数(100),可以获得FileLength。FileLength和ContentLength的值均为字节数的一半!
- 内容长度 = (4 + 4 * 8 + 4 + 4 + NumParts * 4 + NumPoints * 2 * 8)/2
- 当前总文件量 = (前一条记录时的总文件量 + 当前记录的字节数 + 4(RecordNumber的字节) + 4(ContentLength的字节))/2
5.创建代码
void WriteShp(CString& filename)
{
//****打开对话框,输入文件名
CFileDialog fDLG(false);
if (fDLG.DoModal() != IDOK)
return;
filename = fDLG.GetPathName();
filename = filename + ".shp";
FILE * m_ShpFile_fp = fopen(filename, "wb");//wmj
if (m_ShpFile_fp == NULL)
return; //****写shp文件的文件头
int i;
int FileCode = 9994;
int Unused = 0;
int FileLength = 100; //FileLength是整个shp的,先暂时写一个值,后面要修改
int Version = 1000; //Version默认1000
int ShapeType = 5; //记录保存的图形类型
double Xmin = map->GetMapRect().left;
double Ymin = map->GetMapRect().top;
double Xmax = map->GetMapRect().right;
double Ymax = map->GetMapRect().bottom;
double Zmin = 0;
double Zmax = 0;
double Mmin = 0;
double Mmax = 0; FileCode = OnChangeByteOrderTenToSixteen(FileCode); //转化为big形式
fwrite(&FileCode, sizeof(int), 1, m_ShpFile_fp);
for (i = 0; i < 5; i++)
fwrite(&Unused, sizeof(int), 1, m_ShpFile_fp);
FileLength = OnChangeByteOrderTenToSixteen(FileLength); //转化为big形式
fwrite(&FileLength, sizeof(int), 1, m_ShpFile_fp);
FileLength = OnChangeByteOrder(FileLength); //转回little,便于后面修改
fwrite(&Version, sizeof(int), 1, m_ShpFile_fp);
fwrite(&ShapeType, sizeof(int), 1, m_ShpFile_fp);
fwrite(&Xmin, sizeof(double), 1, m_ShpFile_fp); //边界,上下左右
fwrite(&Ymin, sizeof(double), 1, m_ShpFile_fp);
fwrite(&Xmax, sizeof(double), 1, m_ShpFile_fp);
fwrite(&Ymax, sizeof(double), 1, m_ShpFile_fp);
fwrite(&Zmin, sizeof(double), 1, m_ShpFile_fp);
fwrite(&Zmax, sizeof(double), 1, m_ShpFile_fp);
fwrite(&Mmin, sizeof(double), 1, m_ShpFile_fp);
fwrite(&Mmax, sizeof(double), 1, m_ShpFile_fp);
//****写文件头结束 //****写几何信息,包括记录头和记录信息
int count = map->layer->getObjects.size(); //总记录条数
for (int i = 1; i <= RecordNumber; i++) {
//****写记录头
int RecordNumber = i; //RecordNumber从1开始
RecordNumber = OnChangeByteOrderTenToSixteen(RecordNumber);
fwrite(&id, sizeof(int), 1, m_ShpFile_fp);
int ContentLength = 0; //ContentLength是这条记录的,不包括RecordNumber和ContentLength本身字节数,先暂时写一个值,后面要修改
ContentLength = OnChangeByteOrderTenToSixteen(ContentLength);
fwrite(&ContentLength, sizeof(int), 1, m_ShpFile_fp); //****写记录信息
CGeoPolygon* polygon = (CGeoPolygon*)map->layer->objects[i - 1];
int shapeType = 5;
fwrite(&shapeType, sizeof(int), 1, m_ShpFile_fp); //类型
CRect objectRect = polygon->getObjectRect();
double Box[4] = { objectRect.left,objectRect.right,objectRect.top,objectRect.bottom };
for (int j = 0; j < 4; j++) //多边形的边界
fwrite(Box + j, sizeof(double), 1, m_ShpFile_fp);
int NumParts = polygon->circleNum; //子环个数
fwrite(&NumParts, sizeof(int), 1, m_ShpFile_fp);
int NumPoints = polygon->getAllPointNum(); //表示构成当前面状目标所包含的坐标点个数
fwrite(&NumPoints, sizeof(int), 1, m_ShpFile_fp);
int *Parts = new int[NumParts]; //记录了每个子环的起点在Points数组中的起始位置
*(Parts) = 0; //第一个环的起点在Points数组的位置为0
int temp = 0;
for (int j1 = 0; j1 < NumParts - 1; j1++) {
temp = temp + polygon->circles[j1]->GetSize(); //下一个环的起点的位置=上一个环的起点位置+上一个环的点数
*(Parts + j1 + 1) = temp; //每一个环的起点位置存在数组中
}
for (int j2 = 0; j2 < NumParts; j2++)
fwrite(Parts + j2, sizeof(int), 1, m_ShpFile_fp); for (int j3 = 0; j3 < NumParts; j3++) { //记录每个环的每一个点
vector<CPoint*> pts = polygon->circles[j3]->pts;
for (int m = 0; m < pts.size; m++) {
double x = (double)pts[m]->Getx();
double y = (double)pts[m]->Gety();
fwrite(&x, sizeof(double), 1, m_ShpFile_fp);
fwrite(&y, sizeof(double), 1, m_ShpFile_fp);
}
} int temp_CL = 4 + 4 * 8 + 4 + 4 + NumParts * 4 + NumPoints * 2 * 8; //不包含ID和FileLength
ContentLength = temp_CL / 2; //ContentLength为字节数的一般
recordLength.push_back(ContentLength); //recordLength是一个vector变量,记录每条记录的长度,供写shx时使用
FileLength = FileLength + temp_CL + 8; //当前总文件量 = 前一条记录的总文件量 + 当前记录的字节数 + 4(RecordNumber) + 4(ContentLength)
long offset = temp_CL + 4; //偏移量
fseek(m_ShpFile_fp, -offset, SEEK_CUR); //将文件指针移到ContentLength的位置,修改ContentLength的数字
ContentLength = OnChangeByteOrderTenToSixteen(ContentLength);
fwrite(&ContentLength, sizeof(int), 1, m_ShpFile_fp);
fseek(m_ShpFile_fp, 0, SEEK_END); //移到文件最后,以继续写下一个
}
//****几何信息写的过程结束 //****返回去写FileLength
fseek(m_ShpFile_fp, 24, SEEK_SET); //移到FileLength的位置,初始为后移24个字节
FileLength = FileLength / 2; // FileLength为字节数的一半
FileLength = OnChangeByteOrderTenToSixteen(FileLength);
fwrite(&FileLength, sizeof(int), 1, m_ShpFile_fp);
fclose(m_ShpFile_fp);
}
下一篇博客介绍dbf的创建。
shp系列(五)——利用C++进行shp文件的写(创建)的更多相关文章
- shp系列(七)——利用C++进行Shx文件的写(创建)
之前介绍了Shp文件和Dbf的写(创建),最后来介绍一下Shx文件的写(创建).Shx文件是三者之中最简单的一个,原因有两个:第一是Shx文件的头文件与Shp文件的头文件几乎一样(除了FileLeng ...
- shp系列(六)——利用C++进行Dbf文件的写(创建)
上一篇介绍了shp文件的创建,接下来介绍dbf的创建. 推荐结合读取dbf的博客一起看! 推荐结合读取dbf的博客一起看! 推荐结合读取dbf的博客一起看! 1.Dbf头文件的创建 Dbf头文件的结构 ...
- python常识系列07-->python利用xlwt写入excel文件
前言 读书之法,在循序而渐进,熟读而精思.--朱熹 抽空又来写一篇,毕竟知识在于分享! 一.xlwt模块是什么 python第三方工具包,用于往excel中写入数据:(ps:只能创建新表格,不能修改表 ...
- 快学Scala 第十五课 (二进制读取文件,写文件,访问目录,序列化)
二进制读取文件: val file = new File("F:\\scalaWorkspace\\ScalaLearning\\files\\test.txt") val in ...
- python 利用 ogr 写入shp文件,数据格式
python 利用 ogr 写入 shp 文件, 定义shp文件中的属性字段(field)的数据格式为: OFTInteger # 整型 OFTIntegerList # 整型list OFTReal ...
- arcgis api 3.x for js 入门开发系列批量叠加 zip 压缩 SHP 图层优化篇(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- (数据科学学习手札65)利用Python实现Shp格式向GeoJSON的转换
一.简介 Shp格式是GIS中非常重要的数据格式,主要在Arcgis中使用,但在进行很多基于网页的空间数据可视化时,通常只接受GeoJSON格式的数据,众所周知JSON(JavaScript Obje ...
- 读CSV文件并写arcgis shp文件
一.在这里我用到的csv文件是包含x,y坐标及高程.降雨量数据的文件.如下图所示. 二.SF简介 简单要素模型(Simple Feature,SF),是 OGC 国际组织定义的面向对象的矢量数据模型. ...
- JVM系列五:JVM监测&工具
JVM系列五:JVM监测&工具[整理中] http://www.cnblogs.com/redcreen/archive/2011/05/09/2040977.html 前几篇篇文章介绍了介 ...
- Hexo系列(五) 撰写文章
在利用 Hexo 框架搭建一个属于我们自己的博客网站后,下面我们就来谈谈怎样在网站上书写我们的第一篇博客吧 一.创建文章 在站点文件夹中打开 git bash,输入如下命令创建文章,其中 title ...
随机推荐
- OC对象的本质及分类
Object-C的底层都是通过C/C++来实现的,所以OC中的对象也会转化成C/C++中的某一个数据结构, 我们在终端里通过指令 xcrun -sdk iphoneos clang -arch arm ...
- 【Linux】Ubuntu输入法不能开机自启的解决方法
操作系统:Ubuntu Kylin 16.10 自从操作系统安装了搜狗输入法以后,每次重启电脑都需要手动启动Fcitx,才能启动搜狗输入法.下面给大家介绍输入法开机自启的解决方法: 操作系统的用户家目 ...
- jQueryAjax模拟按键消抖(可设置抖动延迟时间)
在硬件中,按键等都会有抖动现象,如何消除抖动,不重复触发事件呢,这就要用到消抖机制了. 这是我用jQuery模拟硬件消抖原理,额,可能是吧...又不对的地方,希望有高手指点指点. <!DOCTY ...
- 三维重建:多点透视cvSolvePNP的替代函数(Code)
在调试JNI程序时,所有的Shell都已经加载完成,而唯一真正核心的cv::SolvePnP却不能在JNI里面获得通行证,经过反复测试都不能运行,因此只能忍痛舍弃,自行编写一个具有相 ...
- 浅谈 Unserscore.js 中 _.throttle 和 _.debounce 的差异
来源:http://blog.coding.net/blog/the-difference-between-throttle-and-debounce-in-underscorejs Unsersco ...
- 移动APP 微信支付完整过程(wxPay 方案一)
apicloud.weixinpay官方提供了两种方案. 本模块封装了两套支付方案: 方案一:开发者通过 getOrderId.payOrder 自己处理签名过程(微信开放平台建议把 getOrder ...
- Day3 分支结构
if语句的使用 在Python中,要构造分支结构可以使用if.elif和else关键字.所谓关键字就是有特殊含义的单词,像if和else就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名 ...
- PY简易爬虫
然而,实用性很差,仅仅是能用而已. 已知bug: 由于土啬的问题,经常会炸掉.网络不稳定导致各种Connection Aborted/SSLError: EOF occurred in violati ...
- nyoj29-求置转换问题
求转置矩阵问题 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述 求一个三行三列的转置矩阵. 输入 第一行一个整数n<20,表示有n组测试数据,下面是n组数据;每组测 ...
- [bzoj3029] 守卫者的挑战 (概率期望dp)
传送门 Description 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地.突然,眼前一道亮光闪过."我,Nizem,是黑魔法圣殿的守 ...