了解CLLocation是代表陆地还是海洋

时间:2014-12-28 15:27:46

标签: ios mapkit mapbox geo

我正在尝试构建一个API,以便了解CLLocation是否代表土地。我需要这个离线工作,因为我希望我的大多数用户都没有连接。我正在使用MapBox作为tile服务器,但这仍然是一个MapKit问题,因为我没有使用MapBox SDK。

我已经尝试了几种方法来确定给定坐标是否代表陆地或海洋位置:

  • 大致构成世界海岸线的离线坐标数据库。确定给定点是否在轮廓内部或外部仍然是一个问题。
  • png tile资源的颜色分析(必须有更好的方法!还需要大量离线数据才能成为一种有效的方法)

另外(在上述处理之后)是否有一种有效的方法来决定给定一个瓦片坐标(x,y,z)是否是陆地/海洋/海岸地块?

如果有人一直在努力解决这个问题,我会在此提出一些建议。

4 个答案:

答案 0 :(得分:12)

不用担心,似乎Apple已经考虑过这个问题了!

如果您查看CLGeocoder类(CoreLocation),则会有reverseGeocodeLocation:completionHandler:方法。

在完成处理程序中,您可以检索CLPlacemark个对象

的数组

CLPlacemark有两个有趣的属性:

[placemark inlandWater]

  

对于位于内陆水域的坐标,此属性包含该水体的名称 - 湖泊,溪流,河流或其他水道的名称。

[placemark ocean]

  

坐落在海洋上的坐标,此属性包含海洋的名称。

因此,您只需对您的位置进行反向地理编码,并检查是否在生成的ocean对象上设置了CLPlacemark属性。

答案 1 :(得分:6)

我花了一段时间寻找一个强大的算法来在球体上进行时区查找并且甚至找不到好的伪代码,更不用说c / c ++ 我对。我要经历我所发现的事情。我将完成可以用来将这些资源放在一起的资源。

很容易......在飞机上

问题称为"Point in Polygon"

常用且简单的POP算法是"Ray Casting"。 2D平面上的POP依赖于无穷远处的点。在飞机上这很容易。无穷远处有无数个点。挑选任何一个!但球体上没有这样的观点。

如果在任何给定查询多边形的内部或外部有已知点,则可以使用此方法。根据您的使用案例,这不是一个繁重的要求:您可以轻松地在海中选择任何单个点,这将在所有的陆地多边形之外。< / p>

"Winding Number" POP算​​法也失败了(据我所见),因为在球体上你可以在两个方向中的任何一个方向上接近任何边缘。

算法

我想要一种没有辅助点且没有启发式(用于从边缘数据生成辅助点)的方法。如果我诚实,我想要这个,因为我确信应该是可能的,不,因为我真的需要它。

对于您的用例,您可以使用通常的光线投射算法和已知在海洋中的单点,因此您不需要依赖启发式算法,尽管无论如何,他们可能工作得相当好。

我提出的方法是这样的......

  • 您需要自己遍历多边形。对于每个多边形...
  • 通过查询点和多边形的至少一个找到一个很棒的圆圈(两个角之间的中间点会这样做)。
  • 将大圆与多边形的边相交。
  • 当您按顺序行走其边缘时,多边形的内侧位于您的右侧(如果您愿意,则位于左侧)。这为每个交叉点提供了足够的信息,以了解内侧或外侧的哪一侧。
  • 从最近的交叉点,您可以确定您的查询点是在内部还是外部。

实施提示

如果您计划实施此(或任何其他POP算法),不要尝试使用正弦或余弦。

将您的点(多边形角和查询点)表示为单位矢量。将您的大圆(多边形边和查询点所在的圆)表示为垂直于大平面所在平面的单位向量。使用点积和交叉积。不要在角度思考。在向量中思考。

它不应该太难 - 我并不需要它足以实现它。如果您喜欢自由撰稿,请与我们联系!

您可以构建解决方案的链接

c ++ boost库有POP implementation,我也不喜欢,但这主要是因为我是完美主义者 - 我想它几乎可以满足所有情况下的目的。

tz_world数据库包含陆块的多边形,其中有GeoJSON variant个。您可以使用内置的NSJSONSerialization类很好地解析它。

以下是点数和球体的algorithms by NASA(虽然我不喜欢它们的POP)。

答案 2 :(得分:0)

您可以查看Mapbox的UTFGrid交互,它可以脱机工作(通过缓存网格图块,基本上是文本,或者将它们预先捆绑到MBTiles文件中)。

查看Mapbox iOS Example的第三个标签,如README所示,其中主要编码&amp;检索有关哪个国家/地区的信息。这是在像素分辨率级别完成的,基本上是预先光栅化的,因此您不需要大量数据 - 它不会以更高的分辨率存储,因为您无法以高于a的方式触摸每像素分辨率。

答案 3 :(得分:0)

使用:

mapView.visibleFeatures(at: CGPoint, styleLayerIdentifiers: Set<String>)

请参阅this question