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 Relation,4 Tag,5 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
#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; }