绘制地形图

时间:2008-11-04 20:25:30

标签: algorithm language-agnostic visualization bezier topographical-lines

9 个答案:

答案 0 :(得分:9)

gradient是一个可以帮助你的数学运算符。

如果您可以将插值转换为可微函数,则高度的渐变始终指向最陡上升的方向。所有相等高度的曲线都垂直于该点评估的高度梯度。

关于从最高点开始的想法是明智的,但如果有多个局部最大值,可能会错过功能。

我建议

  1. 选择要绘制线条的高度值
  2. 在精细的,规则间隔的网格上创建一堆点,然后在渐变方向上以小步长走向每个点,朝向您想要绘制线条的最近高度
  3. 通过将每个点垂直于渐变来创建曲线;当另一条曲线太靠近它时,通过杀死一个点来消除多余的点 - 但为了避免破坏像沙漏一样的沙漏中心,你可能需要检查垂直于两个点的渐变的定向矢量之间的角度。 (当我说定向时,我的意思是确保你计算的渐变和垂直值之间的角度在同一方向上总是90度。)

答案 1 :(得分:3)

或者,有marching squares算法似乎适合您的问题,但如果使用粗网格,您可能希望平滑结果。

要绘制的地形曲线是2维上标量字段的isosurfaces。对于3维的等值面,有marching cubes算法。

答案 2 :(得分:3)

回应你对@erickson的评论并回答关于计算函数渐变的观点。您可以按照以下方式进行数值区分,而不是计算300项函数的导数。

给定图像中的点[x,y],你可以计算出渐变(最陡的方向)

g={  ( f(x+dx,y)-f(x-dx,y) )/(2*dx), 
  {  ( f(x,y+dy)-f(x,y-dy) )/(2*dy) 

其中dx和dy可以是网格中的间距。轮廓线将垂直于渐变。因此,为了得到轮廓方向c,我们可以将g = [v,w]乘以矩阵,A = [0 -1,1 0]给出

c = [-w,v]

答案 3 :(得分:2)

我自己也想要这样的东西,但还没有找到基于矢量的解决方案。

基于栅格的解决方案并不是那么糟糕,特别是如果您的数据是基于栅格的。如果你的数据也是基于矢量的(换句话说,你有一个表面的3D模型),你应该能够做一些真正的数学运算来找到不同高程水平面的交点曲线。

对于基于光栅的方法,我会查看每对相邻像素。如果一个高于轮廓水平,一个低于轮廓水平,则显然在它们之间运行轮廓线。我用来对轮廓线进行反锯齿的技巧是将轮廓线颜色混合到两个像素中,与它们与理想轮廓线的接近程度成比例。

也许一些例子会有所帮助。假设当前像素处于12英尺的“高度”,邻居处于8英尺的高度,并且轮廓线是每10英尺。然后,在中间有一条轮廓线;使用50%不透明度的轮廓线颜色绘制当前像素。另一个像素位于11英尺处,并且有一个6英尺的邻居。以80%不透明度为当前像素着色。

alpha = (contour - neighbor) / (current - neighbor)

不幸的是,我没有方便的代码,可能会有更多的代码(我依旧回想起对角线的邻居,并按sqrt(2) / 2进行调整)。我希望这足以给你一个要点。

答案 4 :(得分:1)

在我看来,使用轮廓功能在MATLAB中做起来很容易。可以通过对轮廓进行一些相当简单的后处理来完成对轮廓进行低密度近似的操作。

幸运的是,GNU Octave是一个MATLAB克隆,它具有各种轮廓绘图功能的实现。您可以查看该代码的算法和实现几乎肯定在数学上是合理的。或者,您可能只能将处理卸载到Octave。查看interfacing with other languages上的页面,看看是否会更容易。

披露:我没有非常使用Octave,我实际上没有测试它的轮廓绘图。但是,根据我对MATLAB的经验,我可以说,只要你将数据输入MATLAB,它几乎可以为你提供几行所需的一切。

另外,祝贺制作一个非常Vangough风格的斜坡地块。

答案 5 :(得分:0)

我总是先查看http://mathworld.wolfram.com之类的地方,然后才能深入了解:)

也许他们的curves部分有帮助?或者也许是maps上的条目。

答案 6 :(得分:0)

将您渲染的内容与真实世界的地形图进行比较 - 它们看起来与我完全相同!我不会改变一件事......

答案 7 :(得分:0)

将数据写为HGT file(USGS使用的非常简单的数字高程数据格式),并使用免费和开源gdal_contour工具创建轮廓。这对于地面地图非常有效,其限制因素是数据点是16位数字的符号,非常适合以米为单位的地球高度范围,但对于您的数据可能还不够,我认为这些数据不是实际地形图 - 尽管你提到了地形图。

答案 8 :(得分:0)

我建议使用CONREC方法:

  • 创建空行段列表
  • 将数据拆分为常规网格方块
  • 对于每个网格方块,将方块拆分为4个组成三角形:
    • 对于每个三角形,处理案例(a到j):
      • 如果某个线段超过其中一个案例:
        • 计算其终点
        • 将线段存储在列表中
  • 在线段列表中绘制每个线段

如果线条过于锯齿,请使用较小的网格。如果线条足够平滑且算法花费的时间太长,请使用更大的网格。