如何在程序生成的地图中确定海湾和海峡?


40

我有一个使用Voronoi单元程序生成的地图,其中包含定义的海平面和可信的高度图。

当前

到目前为止,我已经成功地标注了某些地理特征:土地,海洋,湖泊,河流,河口,汇合处,山脉和生物群落。生物群落包括苔原,北方森林,草原和温带森林。那里还有其他一些生物群落,但就我的目的而言,它们现在并不重要。

我想标记下海湾和海峡,但我对如何正确执行此操作感到困惑。海湾是一条凹陷的沿海水域,直接与海洋相连。

海峡是自然形成的,狭窄的水路,连接了海洋的两部分。基本上,两片土地几乎相接,两岸都是海洋。也称为“渠道”。

为了确定功能,我可以按以下类型遍历任何功能:

for each (var feature:Object in geography.getFeaturesByType(Geography.LAND))
  // loop through lands
  for each (var cell:Cell in feature.cells)
  // loop through cells
    for each (var neighbor:Cell in cell.neighbors)
    // loop through a cell's neighbors
      trace(neighbor.hasFeatureType(Geography.LAND));

8
我建议使用贝叶斯分类器。
累计

1
@累积这是“海湾”上的一个双关语还是一个严肃的建议?如果是后者,则应为此写一个正确的答案。
菲利普

我喜欢99%的人确定他在开玩笑。
Olin Kirkland

Answers:


29

Dragons Abound 识别海湾的方法是沿着海岸线漫步,在海岸线上找到两个点,这些点之间的直线距离小于两个点之间沿着海岸线的距离。这是两点之间海岸线的弯曲度。通过选择弯曲度极限和光斑之间的直线距离极限,可以识别出狭窄的深湾,宽阔的浅湾等。

在这张照片中,红色和紫色的点表示两个候选点,绿色的线是这些点之间的海岸线。正弦度是这两个长度的比率:

海湾的例子

或者,您可以在海岸上选择两个点并通过连接两个点和两个点之间的海岸线来创建多边形(即,将上面的绿线从红点连接到紫点)。测量此多边形的面积。海湾将比非海湾具有更大的面积。

以我的经验,这两种措施的组合最能可靠地识别人们所看到的海湾。

请注意,这还将检测点。要仅查找海湾,您需要检查海湾的“内部”是否有水且没有着陆。一种快速简便的方法是检查两点之间的线的中点以查看是否为水。(这可以上当,但通常就足够了。)

一个相关的问题是确定海湾的“嘴”,即标记海湾开口的两个点的最佳选择。通常,您会为“嘴巴”准备一堆候选人。在上面的示例地图中,您可以将该托架的嘴向内或向外延伸。一般来说,这可能并不太重要,但是一种相当有效的启发式方法是最小化嘴巴之间的直线距离。

我还没有做过海峡,但是我的直觉是检查海岸线上的点以找到任何其他海岸线上最接近的点。如果在设定的限制之下,那就是海峡。


3
我应该知道《龙腾世纪》会得到我需要的答案。
Olin Kirkland

48

这是一个使用图像处理转换来分离感兴趣特征的粗略想法:

  1. 从海洋细胞中施加洪水填充,以掩盖所有海洋细胞。根据河流的设置方式,您可能需要额外的高程或净空条件,以防止海洋面罩流入内陆。;)

    海洋面具

  2. 在此蒙版的边缘上应用局部平滑处理,以保持连接性/拓扑结构不变,但平滑处理可能分散注意力的小的嘈杂海岸线特征。这使我们可以专注于微小的入口上方的大海湾。您可以使用过滤器内核的宽度/迭代次数来精确控制保留的功能的比例。

    在这里,我几次应用了中值过滤器。元胞自动机是从嘈杂的输入中侵蚀平滑形状的另一种流行方法。

    平滑的海岸线

  3. 将蒙版转换为距离场,每个单元格在其中存储其距平滑海岸线的距离。

    距离场

现在,我们看到了一些很有希望的功能亮点。在一个有符号的距离场中,海湾和海峡都显示为锋利的山脊,距离逐渐下降到两侧。我们可以使用边缘检测过滤器弹出这些山脊:

凸脊

然后,您可以通过跟踪山脊以确定其连通性来区分海湾和海峡。海湾是一条向海岸延伸的山脊,逐渐变得越来越浅(与陆地的距离),直到到达某一点为止。海峡是一个将高距离区域连接到另一个高距离区域的脊,沿途穿过低距离区域。

或者,另一种方法是为每个孤岛分配一个ID(关联组件搜索),然后在创建距离字段时,在距离边界旁边传播“最近的孤岛ID”。那么,海湾或进水口是在两侧与同一陆块相邻的水中的一条脊,而一条河道则是将与两个不同陆块相邻的水分开的脊。

例如,如果您需要排除过窄或过宽的海峡,则可以设置最小和最大岸上距离或山脊长度约束来控制要标注的要素。


9
这看起来真的很酷,可以通过直接使用单元结构来应用各个步骤而不是图形表示来大大加快速度!
昆汀

7
第二种方法(分配每个不同大陆的ID和区分基于它是否对水体的两侧是相同的大陆)似乎是最容易做的事情..
蒙蒂哈德

无论如何,“陆地ID”是一个好主意,因为在地图标签中还需要使用它来生成岛名。
MSalters

6

基本上,您需要考虑海湾或海峡的确切含义,以及为什么要区分它们(是用于AI计算,标记地标还是其他?)。尝试一些定义,找到最适合您的定义。然后,制定条件以检查您的Voronoi细胞。一些建议:

  • 任何仅与单个其他海洋细胞连接的海洋细胞
  • 或:连接到比陆地更多的陆地的任何海洋细胞,且所有海洋细胞彼此相邻
  • 或:与上述相同,但有一个基于边界长度的标准(例如,陆地是水边界的两倍)

海峡

  • 精确连接到彼此不相邻的两个海洋细胞的任何海洋细胞
  • 或:连接到不属于同一陆地的两个陆地单元的任何海洋单元(您需要找出首先连接的陆地单元,并为每个陆地分配ID)
  • 或:在边界附近游行,计算土地/水和水/土地的过渡情况。每个都至少需要两个。
  • 根据您的方法以及对类别的处理方式,您可能希望消除仅导致海湾的海峡,或将其标记为海湾。

2
当海峡通向海湾时,这两个地方可能会被标记为峡湾。
菲利普

1
如果单元格相对于海湾/海峡较小,则可能需要传播该信息以查看紧邻的邻居之外的单元格。
DMGregory

是的,扩展是一个问题,它将影响您定义事物和声明“单元格”的方式。考虑加拿大的地图,并进行以下比较:哈德逊湾,詹姆斯湾,圣劳伦斯湾和芬第湾。您如何可靠地应用这些规则来获得所需的相关名称?-纽芬兰与新斯科舍省之间是否存在“直路”?
TheLuckless
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.