这几天一直在讨论关于一体化态势图的架构。首先大家明确了基于层次化架构,采用大量功能图层来表示承载不同类型的数据。我要解决的大量的地理信息数据的建模。目前底层的地理信息数据库的处理系统arcGIS等,可以高效管理地理信息数据库中的数据,提供层次化视图,也可以帮助用户轻松筛选所需要的数据,并提供相应的关联分析能力。
刚开始,我准备借鉴arcGIS的思想,将地理信息数据分层显示,每个图层都是功能单一的,例如,河流构成一个河流层,附带对河流操作的函数,路网分成公路网和铁路网,分别形成一个图层。再借鉴costmap_2d的思想,通过三层到master map的投影,构成一个虚拟的图层,对导航提供代价地图。如果将铁路网和公路网到虚拟的路网层做投影,则也可以当成一个路网层,对外提供先关数据。最底层是一个栅格化的空白图层,就是按照实际需要,将态势展示的区域进行栅格化,栅格化带来的好处是减小数据存储和处理的开销(一定面积的区域可以用该栅格的坐标表示)。
这需要说明的是,我在设计地理信息层的时候,是把它当做一个图层的集合来设计的,其下面包含很多子图层集合和基础功能图层。子图层集合也允许嵌套,直到最底层的图层集合只包含基础功能图层为止。对于某一个子图层,我们可以把它当做一个虚拟图层,是由其所有子图层集合和基础功能图层的投影。例如上面的路网层,就是背景轮廓层+公路网+铁路网进行的投影。另外,所有的图层可能都是3D的,只是这里画图不方面罢了。
经过讨论,大家觉得这种采用图层集合和嵌套的方式太复杂了,毕竟地理信息层只是整个态势图的一个部分,或者一个图层,并且我们的目的也不仅仅是可视化,最主要的是为无人系统提供数据支撑,它们不需要可视化,而是需要数据的高效组织。并且如果这么设计,有点重复造轮子,相当于又整出一个简化版的arcGIS。
既然上述方案行不通,那我就想着把地理信息层当成一个类,能够管理地理信息层中的所有类型的数据,那么问题来了,地理信息系统中的数据复杂多样,包括建筑、河流、桥梁、路网、山、等等。主要是我没法穷举里面的所有数据类型啊。如果为每一种数据类型创建一个类,比如河流类、建筑类、桥梁类,那么,(1)我不知道有多少类型要创建,如果后期增加一个类,地理信息层这个类是不是要增加一个成员变量?扩展性不行!(2)这些类存在大量共同的操作,针对每一个类写一批相同的操作,不划算,重用性不强。
那能不能找到一个数据结构来表示地理信息数据库中存在的所有类型的数据呢?
琢磨了一会儿,跟同事又讨论了一会儿,发现不管河流、山川、建筑等,都可以简化成一系列的形状+属性,决定去看看去年调研过的GeoJson,看看这玩意儿能不能表征所有的数据对象。
geojson是用json的语法表达和存储地理数据,可以说是json的子集。
GeoJSON数据解释
它是用于描述地理空间信息的数据格式
- FeatureCollection:特征集合
- type:GeoJSON对象都有type属性,type的值有多种:
Point
,MultiPoint
,LineString
,MultiLineString
,Polygon
,MultiPolygon
,GeometryCollection
,Feature
或FeatureCollection
- Feature:是type的值之一,Feature特征对象必须包含变量geometry,properties
- geometry:几何体
- properties:值可以是任意JSON对象或null
- Polygon:面
GeoJSON对象可能有一个可选的“crs”成员,其值必须是坐标参考系统对象。GeoJSON对象可能有一个“bbox”成员,其值必须是边界框数组。
几何体是一种GeoJSON对象,其中类型成员的值是以下字符串之一: Point
, MultiPoint
, LineString
, MultiLineString
, Polygon
, MultiPolygon
, GeometryCollection
, Feature
或 FeatureCollection
。除“GeometryCollection”外的其他任何类型的GeoJSON几何对象必须有一个名为“coordinates”的成员。“coordinates”成员的值总是一个数组。 此数组中元素的结构由几何的类型来确定。
例如下面就是一个点数据:
{
"type": "FeatureCollection",
"features": [
{"type":"Feature",
"properties":{},
"geometry":{
"type":"Point",
"coordinates":[105.380859375,31.57853542647338]
}
}
]
}
geojson将所有的地理要素分为Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon、GeometryCollection。首先是将这些要素封装到单个的geometry里,然后作为一个个的Feature(也就是要素);要素放到一个要素集合里,从树状结构来理解FeatureCollection就是根节点,表示为:
{
"type": "FeatureCollection",
"features": []
}
所有地理要素放在features的列表里。
点要素Point
点要素是最简单的,类型type对应Point,然后坐标是一个1维的数组,里面有两个元素(如果是立体的坐标就是三维x,y,z),分别为经度和纬度。properties里面可以封装各种属性,例如名称、标识颜色等等。
{"type":"Feature",
"properties":{},
"geometry":{
"type":"Point",
"coordinates":[105.380859375,31.57853542647338]
}
}
多点要素MultiPoint
{"type":"Feature",
"properties":{},
"geometry":{
"type":"MultiPoint",
"coordinates":[[105.380859375,31.57853542647338],
[105.580859375,31.52853542647338]
]
}
}
其核心坐标:
105.380859375,31.57853542647338
105.580859375,31.52853542647338
线要素LineString
线要素就是指线段,记录的是线的端点坐标,可视化时会按照记录顺序联结。对于曲线(如贝塞尔曲线)目前还没有很好的表达,但是在地理数据中,曲线一般会用LineString去拟合,现实地理世界中也没有标准的曲线地理要素。
线要素的坐标coordinates里的二维数组和多点要素基本一样,区别就在type上了。
{"type":"Feature",
"properties":{},
"geometry":{
"type":"LineString",
"coordinates":[[105.6005859375,30.65681556429287],
[107.95166015624999,31.98944183792288],
[109.3798828125,30.031055426540206],
[107.7978515625,29.935895213372444]]
}
}
对应的Kml表达(Keyhole Markup Language缩写,由Google(谷歌)旗下的Keyhole公司发展并维护,用来表达地理标记):
<Placemark>
<ExtendedData></ExtendedData>
<LineString>
<coordinates>108.65753173828125,34.1873818599505 108.72413635253905,34.25154099726973 108.77151489257812,34.16977214177208 108.88481140136719,34.229970811273084
</coordinates>
</LineString>
</Placemark>
MultiLineString
也是一个三维数组(和多边形一样);
{"type":"Feature",
"properties":{},
"geometry":{
"type":"MultiLineString",
"coordinates":
[
[
[105.6005859375,30.65681556429287],
[107.95166015624999,31.98944183792288],
[109.3798828125,30.031055426540206],
[107.7978515625,29.935895213372444]
],
[
[109.3798828125,30.031055426540206],
[107.1978515625,31.235895213372444]
]
]
}
}
多边形Polygon
注:单个多边形是一个3维数组,可以包含多个二维数组,这种情况和MultiPolygon效果很像。
{"type":"Feature",
"properties":{},
"geometry":{
"type":"Polygon",
"coordinates":[
[
[106.10595703125,33.33970700424026],
[106.32568359375,32.41706632846282],
[108.03955078125,32.2313896627376],
[108.25927734375,33.15594830078649],
[106.10595703125,33.33970700424026]
]
]
}
}
多多边形MultiPolygon
type 1 两个不会相交的多边形
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates":
[
[
[
[109.2041015625,30.088107753367257],
[115.02685546875,30.088107753367257],
[115.02685546875,32.7872745269555],
[109.2041015625,32.7872745269555],
[109.2041015625,30.088107753367257]
]
],
[
[
[112.9833984375,26.82407078047018],
[116.69677734375,26.82407078047018],
[116.69677734375,29.036960648558267],
[112.9833984375,29.036960648558267],
[112.9833984375,26.82407078047018]
]
]
]
}
}
两个不相交的多边形
type 2 两个镶套的多边形
小的在前面,范围大的在后面,用上4个中括号,但效果不是有洞的
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates":
[
[
[
[101.6455078125,27.68352808378776],
[114.78515624999999,27.68352808378776],
[114.78515624999999,35.209721645221386],
[101.6455078125,35.209721645221386],
[101.6455078125,27.68352808378776]
]
],
[
[
[104.2822265625,30.107117887092357],
[108.896484375,30.107117887092357],
[108.896484375,33.76088200086917],
[104.2822265625,33.76088200086917],
[104.2822265625,30.107117887092357]
]
]
]
}
}
两个镶套的多边形
type 3 有孔洞的多边形
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates":
[
[
[
[101.6455078125,27.68352808378776],
[114.78515624999999,27.68352808378776],
[114.78515624999999,35.209721645221386],
[101.6455078125,35.209721645221386],
[101.6455078125,27.68352808378776]
],
[
[104.2822265625,30.107117887092357],
[108.896484375,30.107117887092357],
[108.896484375,33.76088200086917],
[104.2822265625,33.76088200086917],
[104.2822265625,30.107117887092357]
]
]
]
}
}
有孔洞的多边形
可以仔细去品味type2和type3的区别。它们对应的kml表达区别是比较大的。
GeometryCollection
GeometryCollection是多种基本地理要素的集合,就是里面可以包含点、线、面要素。
{
"type": "GeometryCollection",
"geometries": [
{
"type": "Point",
"coordinates": [108.62, 31.02819]
}, {
"type": "LineString",
"coordinates": [[108.896484375,30.1071178870],
[108.2184375,30.91717870],
[109.5184375,31.2175780]]
}]
}
GeometryCollection不需要放在FeatureCollection里:
{
"type": "FeatureCollection",
"features": []
}
geojson里面还有其他标签表达其他的属性,如外包矩形等,其中特别重要的是坐标系统,一般里面的坐标默认为WGS84,当然也可以是其他坐标系统的坐标,但是要标识。
最后给出一个表示整个中国区域规划的示例:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "shang_hai",
"properties": {
"name": "上海",
"cp": [121.4648, 31.2891],
"childNum": 19
},
"geometry": {
"type": "Polygon",
"coordinates": [[[120.9375, 31.0254],[121.2012, 31.4648],
[121.377, 31.5088],[121.1133, 31.7285],[121.2012, 31.8604],[121.9922, 31.5967],
[121.9043, 31.1572],[121.9922, 30.8057],[121.2891, 30.6738],[120.9375, 31.0254]
]
]
}
}, {
"type": "Feature",
"id": "xiang_gang",
"properties": {
"name": "香港",
"cp": [114.2578, 22.3242],
"childNum": 1
},
"geometry": {
"type": "Polygon",
"coordinates": [.....]
}
},
......
]
"srcSize": {
"left": 243.4766,
"top": 36.4307,
"width": 61.6113,
"height": 35.4638
}
}