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

2022-09-04 23:49:44

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

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

我应该如何:

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

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

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

我应该如何:

  • 将纬度/经度点转换为屏幕坐标?- 据我所知,Shapefile使用经度和纬度作为其点。因此,显然我必须以某种方式将这些转换为屏幕坐标以显示地图要素。
  • 以一种可以轻松旋转和缩放整个地图的方式呈现地图数据(道路、边界等的一系列折线)?
  • 将整个地图渲染为一系列“切片”,以便仅渲染查看区域内的要素/线?

例如,呈现为显示地图的 TIGER 数据:
alt text

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

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


答案 1

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

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

如果你想从较低的水平开始

解析

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

这将在查看如何投影地图以及如何反转投影方面提供一些“乐趣”(假设用户单击地图,您希望看到他们单击的纬度/ lon - 需要反转当前的投影方程)。

渲染

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

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

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

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

存储和结构

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

使用邮政编码并仅加载附近的邮政编码适用于小型地图渲染项目,但如果您需要穿越国家/地区的路线,则需要不同的结构。一些实现具有“覆盖”数据库,其中仅包含主要道路并捕捉到覆盖层的路线(或通过多个覆盖层 - 本地,地铁,县,州,国家)。这会导致路由速度快,但有时效率低下。

铺瓷砖

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

在图块边界处剪切线条,以便您可以渲染单个切片,从而导致效果不佳 - 通常要做的是将线条渲染到瓷砖边界之外(或者,至少保留线条末端的数据,尽管渲染一旦发现它从边缘脱落就会停止) - 这可以减少线条在穿过切片时看起来不太匹配时发生的错误。

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

查找进入给定磁贴的数据并非易事 - 一条线的两端可能在给定磁贴之外,但穿过该磁贴。您需要查阅有关这方面的图形书籍(Michael Abrash的书是开创性的参考书,现在可以在前面的链接中免费获得)。虽然它主要谈论游戏,但窗口化,剪裁,多边形边缘,碰撞等都适用于这里。

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

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

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

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

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

遵循一条路径并先发制人地给出指示并不像第一次腮红时看起来那么容易。给定一组具有相关纬度对数组的指令,使用外部输入(GPS或模拟GPS)“跟随”路线,并开发一种算法,在用户接近每个真实交叉点时为用户提供指令。请注意,由于弯曲的道路等原因,纬度/经度对比指令更多,您需要检测行进方向等。很多角落案例,直到你尝试实现它,你才会看到。

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

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

您可以在此处找到许多指向此主题的许多项目和信息源的链接。

祝你好运,无论你做什么,无论多么简陋或丑陋,请发表,这样其他人就可以受益!

-亚当


答案 2

SharpMap是一个开源的.NET 2.0映射引擎,用于WinForms和 ASP.NET。这可以提供您需要的所有功能。它处理最常见的 GIS 矢量和栅格数据格式,包括 ESRI 形状文件。


推荐