空间数据格式是空间数据的基础,定义了如何在计算机中表达空间数据。各个GIS软件都定义了自己的空间数据格式。OGC定义了空间数据的交换格式,来实现各类GIS软件之间的空间数据交互。主要有WKT、WKB、GML几类,随着Google Earth的普及,KML也成为OGC的规范。
1. 常用的矢量数据格式主要包括以下六类:
- 点(Point)
- 多点(MultiPoint)
- 线(LineString)
- 多线(MultiLineString)
- 面(Polygon)
- 多面(MultiPolygon)
1) 点(Point)
单独一个坐标点构成的空间实体。
2) 多点(MultiPoint)
由多个坐标点构成的一个空间实体。
3) 线(LineString)
由一条线构成的空间实体。
4) 多线(MultiLineString)
有多条线构成的一个空间实体。
5) 面(Polygon)
Polygon和MultiPolygon的结构较为复杂,概念相也容易混淆。Polygon和MultiPolygon都由多个环(Ring)构成的封闭的面状实体。
Polygon具有1个外环和0个或n个内环构成。
MultiPoylgon由多个Plygon构成,Plygon之间的空间关系是相离,因此MultiPolygon并没有外环。
6) 多面(MultiPolygon)
由多个相离的Polygon构成,并没有一个外环。
2. WKT
WKT用文本的方式来表达Geometry,便于人的阅读。
WKT的格式为:Geometry类型(坐标数据)
1) 点(Point)
格式:POINT(x y)
下面是一个Point类型的Geometry的WKT
§ POINT(1 1)
- Point:Geometry类型
- (1 1):几何坐标(x y),x和y之间用空格隔开,不是用逗号。
2) 多点(MultiPoint)
格式:MULTIPOINT(x1 y1,x2 y2,…,xn yn)
3) 线(LineString)
格式:LINESTRING(x1 y1,x2 y2,…,xn yn)
4) 多线(MultiLineString)
格式:MULTILINESTRING((x1 y1,x2 y2,…,xn yn),(x1 y1,x2 y2,…,xm ym),......)
5) 面(Polygon)
格式:POLYGON((x1 y1,x2 y2,…,xn yn),(x1 y1,x2 y2,…,xm ym),......)
其中每一个括号为一个环,其中(x1 y1,x2 y2,…,xn yn)为外环。
6) 多面(MultiPolygon)
格式:MULTIPOLYGON(((x1 y1,x2 y2,…,xn yn),(x1 y1,x2 y2,…,xm ym),......)),(...));
第一层括号为第一个Polygon,每个Polygon之间用逗号隔开。
3. WKB
WKB采用二进制的方式来表达Geometry数据。WKB是一种自描述的数据结构,本身带有Geometry的元数据信息。这里还是介绍常用的6种Geometry。
3.1 WKB的基本结构
下面以Point的来介绍WKB的基本结构,其他类型的Geometry的结构与Point的结构类似。
Point的WKB结构定义如下所示:
1 struct WKBPoint{ 2 unsigned char byteOrder; 3 int wkbType; 4 Point point; 5 };
与之相对应的WKBPoint的内存结构如下图所示:
1) byteOrder(字节序)
字节序描述了数据结构在计算机里面的内存排布。例如,32位系统上int类型数据由4个字节构成,这4个字节可以可以由高地址位向低地址位排列,也可以由低地址位向高地址位排列,由此引出Big Endian和Little Endian两种字节序。
WKBPoint的第1个字节是字节序,描述了WKBPoint内存的排列是Big Endian还是Little Endian。当WKB的字节序与主机字节序不同时,需要将WKB的字节序进行逆序变换,转换为主机字节序,否则WKB无法被正确解析。
2) wkbType
第2~5的四个字节为一个int型变量,描述了WKB的几何类型。
系统根据wkbType描述的几何类型来调用不同的程序来解析WKB结构。
3) Point结构体
对于WKBPoint,从第6个字节开始是一个struct Point类型数据结构,定义了点的坐标结构。
struct Point的定义如下所示:
1 struct Point{ 2 double x; 3 double y; 4 };
可以看出,struct Point定义了一个x,y坐标对,描述了一个平台面上的点的坐标。
WKB的前5个字节,即byteOrder和wkbType是所有WKB拥有的共同结构,用以判断WKB的基本信息。因此,可以定义为通用的结构体,由于WKB的预处理。
1 struct WKBGeometryInfo{ 2 unsigned char byteOrder; 3 int wkbType; 4 };
通过WKBGeometryInfo,可以判断wkb的类型,然后调用不同的处理函数进行处理。
1 unsigned char* wkb; 2 WKBGeometryInfo *info = (WKBGeometryInfo *)wkb; 3 4 switch(info->wkbType) 5 { 6 case wkbPoint: 7 ... 8 break; 9 case wkbLineString: 10 ... 11 break; 12 case wkbPolygon: 13 ... 14 break; 15 .... 16 }
3.2 WKB数据结构的完整定义(C语言)
1) 定义字节序对齐
编译器优化结构体,采用4字节对齐方式。对于不满足4字节对齐的结构体,编译器会填充一些空字节,补足为4字节,来保持对齐方式。WKB的结构体不满足4字节对齐,为了让编译器不进行结构体对齐处理,需要显式地设置为1字节对齐。
1 #pragma pack(1)
2) 定义字节序枚举
1 enum WKBByteOrder { 2 wkbXDR, // Big Endian 3 wkbNDR = 1 // Little Endian 4 };
定义默认字节序
1 #define coDefaultByteOrder wkbNDR
3) 定义几何数据类型枚举
1 enum WKBGeometryType { 2 wkbNull , 3 wkbPoint = 1, 4 wkbLineString = 2, 5 wkbPolygon = 3, 6 wkbMultiPoint = 4, 7 wkbMultiLineString = 5, 8 wkbMultiPolygon = 6, 9 wkbGeometryCollection = 7 10 };
4) 定义坐标点数据结构
1 struct Point{ 2 double x; 3 double y; 4 };
5) 定义环(Ring)数据结构
1 struct LinearRing { 2 int numPoints; 3 Point points[1]; 4 };
至此,完成WKB的基本数据结构及枚举的定义,下面定义6类几何数据结构
6) WKBPoint
1 struct WKBPoint{ 2 unsigned char byteOrder; 3 int wkbType; // = 1; 4 Point point; 5 };
7) WKBLineString
1 struct WKBLineString { 2 unsigned char byteOrder; 3 int wkbType; // = 2; 4 int numPoints; 5 Point points[1]; 6 };
LineString实际上是一个Point序列。由于C语言里面不能定义变长数据,所以WKBLineString里面定义了只有一个元素的数组points。
实际上points指向了一个由numPoints个元素构成的points数组。
前面定义的LinearRing结构与此类似。
8) WKBPolygon
1 struct WKBPolygon { 2 unsigned char byteOrder; 3 int wkbType; // = 3; 4 int numRings; 5 LinearRing rings[1]; 6 }; 7
9) WKBMultiPoint
1 struct WKBMultiPoint { 2 unsigned char byteOrder; 3 int wkbType; //=4; 4 int numPoints; 5 WKBPoint points[1]; 6 };
10) WKBMultiLineString
1 struct WKBMultiLineString { 2 unsigned char byteOrder; 3 int wkbType; // = 5; 4 int numLineStrings; 5 WKBLineString lineStrings[1]; 6 };
11) WKBMultiPolygon
1 struct WKBMultiPolygon { 2 unsigned char byteOrder; 3 int wkbType; // = 6; 4 int numPolygons; 5 WKBPolygon polygons[1]; 6 };
WKB的完整数据结构如下所示
1 #pragma pack(1) 2 3 /* 4 * 定义字节序枚举 5 */ 6 enum WKBByteOrder { 7 wkbXDR, // Big Endian 8 wkbNDR = 1 // Little Endian 9 }; 10 11 /* 12 * 定义默认字节序 13 */ 14 #define coDefaultByteOrder wkbNDR 15 16 /* 17 * 定义几何数据类型枚举 18 */ 19 enum WKBGeometryType { 20 wkbNull , 21 wkbPoint = 1, 22 wkbLineString = 2, 23 wkbPolygon = 3, 24 wkbMultiPoint = 4, 25 wkbMultiLineString = 5, 26 wkbMultiPolygon = 6, 27 wkbGeometryCollection = 7 28 }; 29 30 /* 31 * 定义点数据结构 32 */ 33 struct Point{ 34 double x; 35 double y; 36 }; 37 38 /* 39 * 定义环数据结构 40 */ 41 struct LinearRing { 42 int numPoints; 43 Point points[1]; 44 }; 45 46 /* 47 * 定义几何信息枚举,这个数据结构是所有WKB格式的头部 48 */ 49 struct WKBGeometryInfo{ 50 unsigned char byteOrder; 51 int wkbType; 52 }; 53 54 /* 55 * 定义Point类型WKB数据结构 56 */ 57 struct WKBPoint{ 58 unsigned char byteOrder; 59 int wkbType; // = 1; 60 Point point; 61 }; 62 63 /* 64 * 定义LineString类型WKB数据结构 65 */ 66 struct WKBLineString { 67 unsigned char byteOrder; 68 int wkbType; // = 2; 69 int numPoints; 70 Point points[1]; 71 }; 72 73 /* 74 * 定义Polygon类型WKB数据结构 75 */ 76 struct WKBPolygon { 77 unsigned char byteOrder; 78 int wkbType; // = 3; 79 int numRings; 80 LinearRing rings[1]; 81 }; 82 83 /* 84 * 定义MultiPoint类型WKB数据结构 85 */ 86 struct WKBMultiPoint { 87 unsigned char byteOrder; 88 int wkbType; //=4; 89 int numPoints; 90 WKBPoint points[1]; 91 }; 92 93 /* 94 * 定义MultiLineString类型WKB数据结构 95 */ 96 struct WKBMultiLineString { 97 unsigned char byteOrder; 98 int wkbType; // = 5; 99 int numLineStrings; 100 WKBLineString lineStrings[1]; 101 }; 102 103 /* 104 * 定义BMultiPolygon 类型WKB数据结构 105 */ 106 struct WKBMultiPolygon { 107 unsigned char byteOrder; 108 int wkbType; // = 6; 109 int numPolygons; 110 WKBPolygon polygons[1]; 111 }; 112 113 #pragma pack()
3.3 WKB数据访问
1) WKBPoint
1 unsigned char* wkb; 2 WKBPoint* pWKBPoint = (WKBPoint*)wkb; 3 printf("%f,%f\n", pWKBPoint->point.x pWKBPoint->point.y);
2) WKBMultiPoint
1 unsigned int numPoints = 0; 2 WKBPoint* pWKBPoint = NULL; 3 4 //Point个数 5 numPoints = pWKBMultiPoint->numPoints; 6 //获得points数组的指针 7 pWKBPoint = (WKBPoint*)(&(pWKBMultiPoint->points[0])); 8 //遍历points数组 9 for(unsigned int i=0; i<numPoints; i++, pWKBPoint++) 10 { 11 printf("%f,%f\n", pWKBPoint->point.x pWKBPoint->point.y); 12 }
3) WKBLineString
1 Point* pt=NULL; 2 unsigned int numPoints = 0; 3 4 //Point个数 5 numPoints = pWKBLineString->numPoints; 6 //获得points数组的指针 7 pt = (Point*)(&(pWKBLineString->points[0])); 8 //遍历points数组 9 for(unsigned int i = 0; i<numPoints; i++,pt++, gdiPt++) 10 { 11 printf("%f,%f\n", pt->x pt->y); 12 }
4) WKBMultiLineString
1 Point *pt = NULL; 2 WKBLineString* pWKBLineString = NULL; 3 unsigned int numLineStrings = 0; 4 5 //获得LineString个数 6 numLineStrings = pWKBMultiLineString->numLineStrings; 7 8 //获得LineString数组指针 9 pWKBLineString = &(pWKBMultiLineString->lineStrings[0]); 10 for(unsigned int i=0; i<numLineStrings; i++) 11 { 12 //指向pWKBLineString的points数组首个元素的指针 13 pt = &(pWKBLineString->points[0]); 14 //访问pWKBLineString数据 15 //...... 16 17 //pt指向pWKBLineString的points数组的末尾 18 //即pWKBMultiLineString的下一个pWKBLineString的头部 19 pt += pWKBLineString->numPoints; 20 pWKBLineString = (auge::WKBLineString*)pt; 21 }
5) WKBPolygon
1 unsigned int i=0,j=0; 2 unsigned int numPoints = 0; 3 unsigned int numRings = pWKBPolygon->numRings; 4 Point *pt=NULL; 5 LinearRing *pLinearRing = NULL; 6 7 numRings = pWKBPolygon->numRings; 8 pLinearRing = (auge::LinearRing*)(&(pWKBPolygon->rings[0])); 9 10 for(i=0; i<numRings; i++) 11 { 12 numPoints = pLinearRing->numPoints; 13 //指向pLinearRing的points数组的首个元素 14 pt = (Point*)(&(pLinearRing->points[0])); 15 16 //遍历points数组 17 for(j = 0; j<numPoints; j++,pt++) 18 { 19 printf("%f,%f\n", point->x point->y); 20 } 21 22 //遍历完成后pt指向points数组的末尾,即pLinearRing的末尾,也就是下一个LinearRing的开始 23 pLinearRing = (LinearRing*)pt; 24 }
6) MultiPolygon
1 int numPoints = 0; 2 int numLinearRing = 0; 3 int numPolygons = 0; 4 int i=0, j=0, k=0; 5 6 Point *pt=NULL; 7 LinearRing *pLinearRing = NULL; 8 WKBPolygon *pWKBPolygon = NULL; 9 10 11 numPolygons = pWKBMultiPolygon->numPolygons; 12 pWKBPolygon = (WKBPolygon*)(&(pWKBMultiPolygon->polygons[0])); 13 14 for(i=0; i<numPolygons; i++) 15 { 16 numLinearRing = pWKBPolygon->numRings; 17 pLinearRing = (auge::LinearRing*)(&(pWKBPolygon->rings[0])); 18 19 for(j=0; j<numLinearRing; j++) 20 { 21 numPoints = pLinearRing->numPoints; 22 pt = (Point*)(&(pLinearRing->points[0])); 23 24 for(k = 0; k<numPoints; k++,pt++) 25 { 26 printf("%f,%f\n", pt->x pt->y); 27 } 28 29 pLinearRing = (auge::LinearRing*)pt; 30 } 31 32 pWKBPolygon = (auge::WKBPolygon*)pLinearRing; 33 }