读取,表示和渲染地图数据的最佳方法是什么?

我有兴趣将一个简单的导航应用程序编写为宠物项目。 在搜索免费地图数据后,我已经确定了美国人口普查局TIGER 2007 Line / Shapefile地图数据。 数据被分成各个县的zip文件,我已经为我的区域下载了一个县的地图数据。

将此地图数据读入可用格式的最佳方法是什么?

我应该怎么做:

  • 读入这些文件
  • 解析它们 – 正则表达式或某些已经可以解析这些Shapefile的库?
  • 将数据加载到我的应用程序中 – 我应该将这些点直接加载到内存中的某些数据结构中吗? 使用小型数据库? 关闭地图数据的应用程序后,我不需要持久性。 用户可以再次加载Shapefile。

在读取Shapefile数据后,渲染地图的最佳方法是什么?

理想情况下,我希望能够读取县地图数据shapefile并将所有多边形线渲染到屏幕上并允许旋转和缩放。

我应该怎么做:

  • 将lat / lon点转换为屏幕坐标? – 据我所知,Shapefile使用经度和纬度作为其点。 显然,我将不得不以某种方式将这些转换为屏幕坐标以显示地图function。
  • 以我可以轻松旋转和缩放整个地图的方式渲染地图数据(道路,边界等一系列折线)?
  • 将我的整个地图渲染为一系列“图块”,以便只显示查看区域内的要素/线条?

防爆。 作为显示地图呈现的TIGER数据:
alt text http://sofzh.miximages.com/java/ngosjl.png

任何对我在这些文件中阅读的最佳方式有经验和洞察力的人,我应该如何在我的程序中表示它们(数据库,内存数据结构),以及我应该如何渲染(使用旋转/缩放)地图数据在屏幕上将不胜感激。

编辑:澄清一下,我不想使用任何谷歌或雅虎地图API。 同样,我不想使用OpenStreetMap。 我正在寻找一种比使用这些api /程序更实用的方法。 这将是一个桌面应用程序。

首先,我建议您使用2008 TIGER文件 。

其次,正如其他人所指出的那样,现在有很多项目已经读入,解释,转换和使用数据。 但是,为这些数据构建自己的解析器几乎是微不足道的,因此没有理由通过另一个项目的代码并尝试提取您需要的内容,除非您计划将其项目作为一个整体使用。

如果你想从较低级别开始

解析

构建自己的TIGER解析器(相当简单 – 只是一个线段数据库),并在其上构建一个简单的渲染(线,多边形,字母/名称)也将相当容易。 您将要查看渲染阶段的各种地图投影类型 。 最常用的(因此对用户最熟悉)是墨卡托投影 – 它相当简单快速。 你可能想要支持其他预测。

这将在看到如何投影地图方面提供一些“乐趣”,以及如何反转该投影(例如,用户点击地图,您想要查看他们点击的纬度/经度 – 需要反转当前投影方程)。

渲染

当我开发渲染器时,我决定将窗口固定在固定尺寸(嵌入式设备)和固定放大倍率上。 这意味着我可以将地图置于纬度/经度中心,并且在给定的放大率下使用中心像素=中心纬度/经度,并且给定墨卡托投影,我可以计算每个纬度/经度代表哪个像素,反之亦然。

有些程序允许窗口变化,而不是使用放大率和固定点,它们使用两个固定点(通常是定义窗口的矩形的左上角和右下角)。 在这种情况下,确定像素到lat / lon传输变得微不足道 – 它只是一些插值计算。 旋转和缩放使得这种传递函数稍微复杂一些,但不应该如此 – 它仍然是带插值的矩形窗口,但窗口角不需要相对于北方的任何特定方向。 这会增加一些极端情况(例如,您可以将地图内部翻转并像在地球内部一样查看)但这些并不繁琐,可以在处理时进行处理。

完成lat / lon到像素传输后,渲染线和多边形相当简单,除了正常的图形问题(例如线条边缘或多边形重叠不当,抗锯齿等)。 但渲染一个基本的丑陋地图,例如许多开源渲染器完成的地图,相当简单。

您还可以使用距离和大圆计算 – 例如,一个很好的经验法则是赤道的每个纬度或纬度大约为111.1KM – 但随着您接近任一极点而变化,另一个继续保持在111.1kM。

存储和结构

但是,如何存储和引用数据在很大程度上取决于您计划使用它的方式。 如果你想在人口统计学与路由选择中使用相同的数据库结构,会出现很多困难问题 – 给定的数据库结构和索引对于一个是快速的,对另一个则是慢的。

使用zipcodes并仅加载附近的zipcodes适用于小型地图渲染项目,但如果您需要遍布全国的路线,则需要使用不同的结构。 一些实现具有“覆盖”数据库,其仅包含主要道路并且捕捉到覆盖的路线(或通过多个覆盖 – 本地,地铁,县,州,国家)。 这导致快速但有时效率低的路由。

平铺

平铺地图实际上并不容易。 在较低的放大倍率下,您可以渲染整个地图并将其剪切。 在更高的放大率下,您无法一次渲染整个事物(由于内存/空间限制),因此您必须将其切片。

在瓷砖边界处切割线条以便渲染单个瓷砖会导致不太理想的结果 – 通常所做的是线条渲染超出瓷砖边界(或者,至少保留线条末端的数据,尽管渲染一旦停止就会停止发现它已经脱离了边缘) – 这减少了线条看起来像它们穿过瓷砖时不完全匹配时发生的错误。

当你解决这个问题时,你会看到我在说什么。

找到进入给定图块的数据并非易事 – 一条线可能在给定图块之外具有两端,但是穿过图块。 你需要咨询有关这方面的图画书 ( Michael Abrash的书是开创性的参考书 ,现在可以在前面的链接免费获得)。 虽然它主要讨论游戏,但窗口,剪裁,多边形边缘,碰撞等都适用于此。

但是,您可能希望在更高级别上玩。

完成上述任务后(通过调整现有项目或自己完成上述项目),您可能希望使用其他方案和算法。

反向地理编码相当容易。 输入lat / lon(或点击地图)并获取最近的地址。 这将教您如何解释TIGER数据中沿线段的地址。

基本的地理编码是一个难题。 编写地址解析器是一个有用且有趣的项目,然后使用TIGER数据将其转换为lat / lon是非常重要的,但是很有趣。 通过要求精确的名称和格式匹配开始简单和小,然后开始研究’喜欢’匹配和语音匹配。 这个领域有很多研究 – 在这里看看搜索引擎项目的一些帮助。

找到两点之间的最短路径是一个非常重要的问题。 有许多很多算法可以做到这一点,其中大部分都是专利的。 我建议如果您尝试使用自己设计的简单算法,然后进行一些研究并将您的设计与现有技术进行比较。 如果你进入图论,这很有趣。

遵循一条道路并先发制人地给出指示并不像第一次脸红那样容易。 给定一组具有相关的lat / lon对数组的指令,使用外部输入(GPS或模拟GPS)“跟踪”该路线,并开发一种算法,在用户接近每个真实交叉点时为其提供指令。 请注意,由于道路弯曲等原因,纬度/经度对比指令多,您需要检测行进方向等。 在尝试实现它之前,您将看不到大量的角落情况。

兴趣点搜索。 这个很有趣 – 你需要找到当前的位置,以及所有感兴趣的点(不是TIGER的一部分,自己制作或获得另一个来源)在一定距离内(如乌鸦飞行或更难驾驶距离)起源。 这个有趣之处在于您必须将POI数据库转换为在这种情况下易于搜索的格式。 您不能花时间浏览数百万条目,进行距离计算(sqrt(x ^ 2 + y ^ 2)),并返回结果。 您需要有一些方法或算法来首先减少数据量。

旅行推销员。 路由多个目的地。 只是一个更难的常规路由版本。

您可以在此处找到许多项目的链接以及有关此主题的信息来源。

祝你好运,请发表你做的任何事情,无论多么简陋或丑陋,所以其他人都可以受益!

-亚当

SharpMap是WinForms和ASP.NET的开源.NET 2.0映射引擎。 这可能会提供您需要的所有function。 它涉及最常见的GIS矢量和栅格数据格式,包括ESRI shapefile。

解决方案是:

  • 地理空间服务器,如mapserver,geoserver,degree(opensource)。

他们可以阅读和提供shapefile(以及许多其他东西)。 例如,geoserver(安装时)将来自美国人口普查局TIGER shapefile的数据作为演示提供

  • 像openlayers这样的javascript制图库(请参阅链接文本中的示例

使用此解决方案的网络上有很多示例

有趣的问题。 我就是这样做的。

无论我们采用何种格式,我都会收集所需的任何几何体。我一直在从USGS中提取数据,所以这相当于一堆:

  • SHP文件( ESRI Shapefile技术说明 )
  • DBF文件( Xbase数据文件(* .dbf) )

然后我写了一个程序,将这些形状定义“编译”成一个有效渲染的forms。 这意味着要进行有效显示数据所需的任何投影和数据格式转换。 一些细节:

  • 对于2D应用程序,您可以使用所需的任何投影: 地图投影 。
  • 对于3D,您希望将这些纬度/经度转换为3D坐标。 这里有一些关于如何做到这一点的数学: 从球坐标到正常直角坐标的转换 。
  • 将所有基元分解为四叉树/八叉树(2D / 3D)。 此树中的叶节点包含对与该叶节点(轴对齐)边界框相交的所有几何体的引用。 (这意味着可以多次引用一块几何体。)
  • 然后将几何体拆分为顶点表和绘图命令表。 这是OpenGL的理想格式。 可以使用顶点缓冲区( 顶点缓冲区对象 )通过glDrawArrays发出命令。
  • 一般访问者模式用于遍历四叉树/八叉树。 行走涉及测试访问者是否与树的给定节点相交,直到遇到叶节点。 参观者包括:绘图,碰撞检测和选择。 (因为树叶可以包含对几何体的重复引用,所以walker将节点标记为被访问,然后忽略它们。这些标记必须在下次行走之前重置或以其他方式更新。)
  • 使用空间分区系统(树之一)和绘图高效表示对于实现高帧速率至关重要。 我发现在这些类型的应用程序中,您希望帧速率至少为20 fps。 更不用说大量的表现会给你很多机会来创造一个更好看的地图。 (我的目光远非好看,但有一天会到达那里。)
  • 空间分区通过减少发送到处理器的绘图命令的数量来帮助渲染性能。 但是,用户实际上可能想要查看整个数据集(可能是arial视图)。 在这种情况下,您需要一个级别的细节控制系统。 由于我的申请涉及街道,我优先考虑高速公路和较大的道路。 我的绘图代码知道在帧速率下降之前我可以绘制多少个图元。 基元也按此优先级排序。 我只绘制了前x项目,其中x是我可以按照我想要的帧速率绘制的图元数量。

其余的是相机控制和想要显示的任何数据的动画。

以下是我现有实现的一些示例:

图片http://sofzh.miximages.com/java/Picture 5.png 图片http://sofzh.miximages.com/java/Picture 7.png

为了在本地存储老虎数据,我会选择Postgresql和postgis工具。

他们拥有令人印象深刻的工具集,特别是Tiger Geocoder提供了导入和使用老虎数据的好方法。

你需要看看与postgis交互的工具,很可能是某种mapserver

来自http://postgis.refractions.net/documentation/ :

现在有几种与PostGIS一起使用的开源工具。 uDig项目正在开发一个可以直接与PostGIS一起使用的完整读/写桌面环境。 对于互联网映射,明尼苏达大学Mapserver可以使用PostGIS作为数据源。 GeoTools Java GIS工具包支持PostGIS,GeoServer Web Feature Server也支持。 GRASS支持PostGIS作为数据源。 JUMP Java桌面GIS查看器有一个简单的插件,用于读取PostGIS数据,QGIS桌面具有良好的PostGIS支持。 可以使用OGR C ++库和命令行工具(以及带有捆绑的Shape文件转储器的cource)将PostGIS数据导出为多种输出GIS格式。 当然,任何可以与PostgreSQL一起使用的语言都可以与PostGIS一起使用 – 该列表包括Perl,PHP,Python,TCL,C,C ++,Java,C#等。

编辑:depite mapserver在其名称中包含单词SERVER,这将在桌面环境中使用。

虽然您已经决定使用TIGER数据,但您可能对OSM(开放街道地图)感兴趣,因为OSM完全导入了TIGER数据,并丰富了用户贡献的数据。 如果您坚持TIGER格式,您的应用程序对国际用户将毫无用处,OSM您可以立即获得TIGER和其他所有内容。

OSM是一个开放式项目,具有协作编辑的免费世界地图。 您可以获取所有这些数据以及结构良好的XML,可以查询区域,也可以在大文件中下载整个世界。

OSM有一些地图渲染器可用于各种编程语言,其中大多数是开源的,但仍有很多工作要做。

还有一个OSM路由服务可用。 它有一个Web界面,也可以通过Web服务API查询。 再一次,它并非全部完成。 用户肯定可以使用基于此构建的桌面或移动路由应用程序。

即使您不决定参与该项目,您也可以从中获得很多灵感。 只需查看项目维基以及所涉及的各种软件项目的来源(您将在维基内找到它们的链接)。

您还可以使用Microsoft的可视化地球地图应用程序和API或使用Google的api。 我总是使用ESRI产品进行商业编程,并且没有使用开放式api那么多。

此外,您可能想看看Maker! 和Finder! 它们是相对较新的程序,但我认为它们是免费的。 可能仅限于嵌入数据。 制造商可以在这里找到。

问题是空间处理在非商业规模上是相当新的。

如果您不介意购买解决方案, Safe Software会生产一种名为FME的产品。 此工具将帮助您将数据从任何格式转换为几乎任何其他格式。 包括KML Google地球格式或将其渲染为JPEG(或一系列JPEG)。 转换数据后,您可以使用他们的API将google earth嵌入到您的应用程序中,或者只显示平铺图像。

作为一方而非FME是一个非常强大的平台,因此在进行翻译时,您可以添加或删除不一定需要的部分数据。 如果您有多个来源,请合并来源。 转换坐标(我不记得谷歌地球使用的是什么)。 将备份存储在数据库中。 但严重的是,如果你愿意花几块钱,你应该调查一下。

您还可以创建包含位置(放置位置)的标记(与样本图中非常相似)以及有关位置的其他数据/注释。 这些旗帜有许多形状和大小。

对墨卡托或其他投影的一种简化是假设纬度和经度的恒定转换因子。 将纬度乘以69.172英里; 对于经度,选择地图区域的中纬度并乘以(180-经度)乘以余弦(middle_latitude)* 69.172。 转换为里程后,您可以使用另一组转换来获取屏幕坐标。

这对我在1979年有用。

我的每度数英里数。

当我给出这个答案时,问题被贴上了标签

“在.Net中使用折线渲染Shapefile(地图数据)的最佳方法是什么?”

现在这是一个不同的问题,但我将答案留给原来的问题。

我写了一个.net版本,它可以在c#中使用普通的GDI +绘制矢量数据(例如shp文件中的几何)。 这很有趣。

原因是我们需要处理具有大量附加信息的不同版本的几何和属性,因此我们无法使用商业地图组件或开源组件。

这样做的主要方法是建立一个视口并将WGIS84坐标转换/转换为缩小比例和GDI + x,y坐标,如果您甚至需要重新投影,则等待投影。

一种解决方案是使用MapXtreme。 他们有Java和C#的API。 API能够加载这些文件并进行渲染。

对于Java:

http://www.mapinfo.com/products/developer-tools/desktop%2c-mobile-%26-internet-offering/mapxtreme-java

对于.NET:

http://www.mapinfo.com/products/developer-tools/desktop%2c-mobile-%26-internet-offering/mapxtreme-2008

我在桌面应用程序中使用了此解决方案并且运行良好。 它提供了更多只有渲染信息。

现在从头做这个可能需要一段时间。 他们有一个可以下载的评估版本。 我认为它只是在地图上打印“MAPXTREME”作为水印,但它完全可以使用