Open Street Map维基世界地图初探--概念、开发


1. 什么是open street map(osm)?

2. 开发者应该知道哪些概念?包括地图的内容、格式等

3. OSM开发有哪些环境?

4. libosmscout环境的搭建

5. libosmscout的使用示例、配置文件


1. 什么是OSM?

Open Street Map 维基世界地图,一个开源的在线地图项目,包括软件和地图数据。

官网介绍

http://wiki.openstreetmap.org/wiki/Zh-hans:Main_Page

中文网页

http://wiki.openstreetmap.org/wiki/Main_Page

OSM与其他地图 如google地图的区别在哪里?

正如官网所说,它提供了一种方式,让任何人能编辑地图,能为OSM增加地图数据(当然如果是错误的,别人是有权修改的)。而且,其他地图大部分都不是免费的,或者需要授权使用, google地图是免费的,但它也是被别人授权的,无法随意编辑或在自己的软件中使用的。

所以,人们也可以免费地使用OSM数据,包括开发等。


对OSM的常见问题,可以浏览

http://wiki.openstreetmap.org/wiki/FAQ


对于大部分人而言,为OSM绘图是比较有趣的事。

有关为地图增加数据(绘图)的详细介绍如下:

http://wiki.openstreetmap.org/wiki/Zh-hans:Map_Making_Overview


而对于开发者而言,更关心如何使用OSM数据,用于开发,一个必要的开发介绍和资源入口:

http://wiki.openstreetmap.org/wiki/Develop

里面介绍了 OSM的API, 如何下载map data,map data的数据格式和数据结构,常用的开发工具(已经开发好的小工具),地图要素(有哪些数据),与OSM相关的支持的框架(库和组件)。


OSM自身的框架描述:

http://wiki.openstreetmap.org/wiki/Component_overview


下面先介绍一些与开发相关的概念和环境。

2. OSM相关的一些概念

地图数据的存储方式是xml结构,后缀名可以是xml或osm。


地图的数据结构,即地图要素包括1 Node, 2 Way, 3 Relation4 Tag5 Common attributes

这些地图要素,与普通的地图或导航要素概念相同

Node是空间点,包括经纬坐标,或高度信息。其他一些可选信息,如name等,在tag子数据中表示。类似于shape point 或attribution point

way表示线或区域,能包含2-2000个node点信息。它道路与区域描述的主要形式。类似于link、edge的概念

relation表示不同的元素间的关系,将不同元素间的关系描述出来。类似于connection的概念

tag表示一个元素中包含的一个特征,或者说是包含的一小块数据,如highway=residential,住宅区内的道路。类似于attribution的概念,不过tag的作用远不止attribution的描述。

Common attributes就是node、way、relation的共同属性,包括id, usr, version, timestamp等meta的信息。

更详细的描述参见:

http://wiki.openstreetmap.org/wiki/Data_Primitives

及每个元素的子链接。


有关tag类型的详细介绍和分类在这里有介绍:

http://wiki.openstreetmap.org/wiki/Map_Features


3. 开发框架

OSM目前提供了API 0.6版本的开发接口,xapi是extended api扩展的接口。而这些接口是用于web或java应用开发的。如下介绍

http://wiki.openstreetmap.org/wiki/Databases_and_data_access_APIs

如果是使用其他语言开发,就必须使用其他的库或组件,这里列举了各种语言支持的库和组件。

http://wiki.openstreetmap.org/wiki/Develop/Frameworks


对于我而言,我采用的c++开发语言,目的是读取OSM数据,并解析,选取一些数据,我就选用libosmscout库。

所以,下面我就介绍libosmscout的开发环境设置。


4. libosmscout环境的搭建

我使用JOSM用于查看和下载地图数据,JOSM只能查看较小的地图数据,其内存支持400多MB,对于更大的数据不支持。OSMOSIS用于数据转换或分割等。

地图数据下载,以下链接里包括各个地区或整个地图的下载路径:

http://wiki.openstreetmap.org/wiki/Planet.osm


libosmscout各个模块的介绍: 

http://wiki.openstreetmap.org/wiki/Libosmscout

闲话少说,环境搭建(非qt版部分):

a. 使用git从sourceforge上把源码都下载下来

http://sourceforge.net/projects/libosmscout/

b. libosmscout支持windows版本,我使用的是vs2008,所以首先查看README.VisualStudio.txt,里面包含了详细的build windows版本的步骤。

c. 依据readme,将zlib、libxml2、google protocol buffers、protoc.exe下载下来,并配置好。其中zlib、libxml2的版本要匹配,否则会有很因为版本不匹配的链接错误。

d. 依据readme,设置环境变量EXTRALIBS_HEADERS、EXTRALIBS_DEBUGLIBS。

e. 然后编译,这时,若有与DECLARE_COEFFS(SINECOEFF_SSE)相关的编译错误,就查看SSEMath.cpp中,有关math的一系列代码是否是有效的,若无效,加入#define OSMSCOUT_HAVE_SSE2。这个是我遇到的其vs工程中自带的问题,可能是个小bug吧。

f. 此时libosmscout工程、libosmscout-import工程、import工程、demo_AddressLookup工程都能编译通过。有关qt部分的工程我没编译,这里就不写了。


订阅邮件列表,用于知晓它的修改变换,及咨询问题:

https://lists.sourceforge.net/lists/listinfo/libosmscout-development


5. libosmscout使用示例与配置

在使用demo_AddressLookup之前,要获取OSM地图数据及将osm地图数据转换为libosmscout需要的binary数据。

如果手上拿的的有xml格式的数据,可以使用osmosis工具将xml格式的数据转换为osm格式。转换命令示例:

osmosis --read-xml file="planetin.xml" --write-xml file="planetout.osm"
更丰富的,强大的示例在

http://wiki.openstreetmap.org/wiki/Osmosis#Example_Usage

或使用JOSM工具从服务器上下载地图数据,并保存为osm格式,这种方法能直接打开地图数据并查看。


然后,使用编译好的import.exe,将osm格式的数据转换为binary数据。在运行程序之前,将libosmscout\map.ost复制到程序当前目录下,因为import需要默认的map.ost参数文件。建立一个用于输出结果的文件夹(libosmscout的binary地图作为输入或输出都是文件夹的形式),如转换planet.xml,运行命令Import.exe planetout.osm --destinationDirectory planet

更详尽的命令参数,请参看源码或import的命令提示。

import的输出会包含很多dat和idx文件,dat是数据文件,idx是dat的索引文件,更详细的说明在libosmscout\libosmscout\ProcessResult.txt中,libosmscout\libosmscout\Resource.txt是一些算法和程序所占资源的说明。

并且map.ost是可以编辑的,可以增加或删除一些选项,如以下一些必要类型保留,其他我都删除,并添加了highway_crossing类型。这样能减少自己不需要的生成的binary数据,当然就会提高效率。

OST

TYPES
  TYPE "highway_crossing" = NODE ("highway"=="crossing") 

  // Do not delete the following type, they are required by the GenCityStreet import step
  TYPE "boundary_administrative" = WAY AREA ("boundary"=="administrative") OR
                                   RELATION ("type"=="boundary" AND "boundary"=="administrative") OPTIONS MULTIPOLYGON IGNORESEALAND

  // Do not delete the following types, they are required by the GenCityStreet import step
  TYPE "place_city" = NODE AREA ("place"=="city")
  TYPE "place_town" = NODE AREA ("place"=="town")
  TYPE "place_village" = NODE AREA ("place"=="village")
  TYPE "place_hamlet" = NODE AREA ("place"=="hamlet")
  TYPE "place_suburb" = NODE AREA ("place"=="suburb")

END

自己的一个小的demo,打印地图中highway_crossing的node(前提:自己生成的输入地图中有highway_crossing的数据)。

#include <iostream>
#include <iomanip>
#include <vector>

#include <osmscout/Database.h>
#include <osmscout/TypeConfigLoader.h>

using namespace std;
const static size_t RESULT_SET_MAX_SIZE = 1000;

int main(int argc, char* argv[])
{
  std::string                      map;
  map=argv[1];

  osmscout::DatabaseParameter databaseParameter;
  //databaseParameter.SetDebugPerformance(true);
  osmscout::Database          database(databaseParameter);

  if (!database.Open(map.c_str())) {
    std::cerr << "Cannot open database" << std::endl;

    return 1;
  }

  double minlat = 0.f;
  double minlon = 0.f;
  double maxlat = 0.f;
  double maxlon = 0.f;
  database.GetBoundingBox(minlat, minlon, maxlat, maxlon);

  std::cout << " " << minlat << " " << minlon << " " << maxlat << " " << maxlon << std::endl;

  std::vector<osmscout::NodeRef> nodes;
  std::vector<osmscout::WayRef> ways;
  std::vector<osmscout::WayRef> areas;
  std::vector<osmscout::RelationRef> relationWays;
  std::vector<osmscout::RelationRef> relationAreas;

  osmscout::TypeConfig typeConfig;

  clock_t startTime = clock();

  if (!osmscout::LoadTypeData(map,typeConfig)) {
      std::cerr << "Cannot load 'types.dat'!" << std::endl;
      return false;
    }
    std::cout << "typeID:" << typeConfig.GetTypeId("highway_crossing") << endl;

  osmscout::TypeSet types;
  types.SetType(typeConfig.GetTypeId("highway_crossing"));
  std::cout << types.HasTypes() << std::endl;

  database.GetObjects(minlon, minlat, maxlon, maxlat,types, nodes, ways, areas, relationWays, relationAreas);
  clock_t endTime = clock();

  std::cout << "Time:" << (endTime - startTime) << std::endl;

  std::cout << "nodes: " << nodes.size() << " ways:" << ways.size() << " areas:" << areas.size() << std::endl  
      << "relationWays:" << relationWays.size() << " relationAreas:" << relationAreas.size() << std::endl;

  for (unsigned int i=0; i<nodes.size(); ++i)
  {
      std::cout << i << "GetLat:" << nodes[i].Get()->GetLat() << std::endl;
      std::cout << i << "GetLon:" << nodes[i].Get()->GetLon() << std::endl;
      std::cout << i << "GetId:         " << nodes[i].Get()->GetId() << std::endl;
      if (nodes[i].Get()->GetTagCount() > 0)
      {
          std::cout << i << "GetTagCount:" << nodes[i].Get()->GetTagCount() << std::endl;
          std::cout << i << "GetTagKey:" << nodes[i].Get()->GetTagKey(0) << std::endl;
          std::cout << i << "GetTagValue:" << nodes[i].Get()->GetTagValue(0) << std::endl;
      }
      std::cout << i << "GetType:" << nodes[i].Get()->GetType() << std::endl;
  }

  database.Close();

  std::cout << "database close ..." << std::endl;

  return 0;
}

你可能感兴趣的:(Open Street Map维基世界地图初探--概念、开发)