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";
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;
cstring转为intfwrite(&shapeType, sizeof(int), 1, m_ShpFile_fp);  //类型
CRect objectRect = polygon->getObjectRect();
double Box[4] = { objectRect.left,objectRect.p,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;
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的创建。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。