【问题标题】:Bentley-Ottmann Algorithm in LuaLua 中的 Bentley-Ottmann 算法
【发布时间】:2012-09-20 12:47:43
【问题描述】:

我正在 Lua 中实现 Bentley-Ottmann 算法,以使用位于 here 的伪代码查找多边形中的交叉点。

我对实现算法比较陌生,所以我无法理解它的所有部分。到目前为止,这是我的代码:

local function getPolygonIntersectingVertices( poly )
  -- initializing and sorting X
  local X = {}
  for i = 1, table.getn( poly ) do
    if i == 1 then
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'left' } )
    elseif i == table.getn( poly ) then
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'right' } )
    else
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'right' })
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'left' })
    end
  end

  local sortxy = function( a, b )
    if a.x < b.x then return true
    elseif a.x > b.x then return false
    elseif a.y <= b.y then return true
    else return false end
  end
  table.sort( X, sortxy )

  -- Main loop
  local SL = {}
  local L = {}
  local E
  local i = 1
  while next(X) ~= nil do
    E = { x = X[i].x, y = X[i].y, endpoint = X[i].endpoint }
    if E.endpoint == 'left' then
      -- left endpoint code here
    elseif E.endpoint == 'right' then
      -- right endpoint code here
    else
    end
    table.remove( X, i )
  end

  return L
end

我的多边形是一个使用这种结构的表格:{ { x = 1, y = 3 }, { x = 5, y = 6 }, ... }

如何确定“SL 中 segE 上方的线段;”和“SL 中 segE 下方的线段;”以及如果扫描线 (SL) 为空?另外,在将 I 插入 X 时,是否应该用 endpoint = 'intersect' 标记它并将其附加到末尾,以便当循环到达这部分时进入主循环的“else”语句或我把整个算法弄错了吗?

如果有人可以向我展示一个包含 Python、Ruby 等简单实现的链接,那将是完美的,因为我发现很难遵循伪代码并将其与 C++ 示例相匹配。

【问题讨论】:

  • 您的代码甚至无法编译。其中有几个基本的语法错误(有趣的函数前向声明,在sortxyelseif 之后缺少then,在同一函数中缺少end,使用不存在的运算符!= 而不是~= )。在请求帮助之前,你应该多学习一点 Lua。
  • prapin,我还没有测试它,因为还没有什么要测试的。我的问题更笼统。当我有东西要测试时,我会修复一些小东西,这只是我快速写的东西,以显示我的进步并更容易地解释我的问题。还是谢谢...
  • 好的,我已经修复了错误,现在编译代码只是为了让真正可以帮助解决问题的人回答问题。
  • 这段代码适用于哪个 Lua 版本? table.getn 早已被弃用。
  • 这是一个在 Python 中工作的 Bentley-Ottmann 实现,您可能有兴趣将其用作参考:stackoverflow.com/a/33199826/432509

标签: algorithm math lua polygons


【解决方案1】:

您的参考链接在我的位置失败。我会参考the Wikipedia article,这是相当不错的。

如何确定“SL 中 segE 以上的段;”和“SL 中 segE 以下的段;”

该算法需要一个 BST 用于当前扫描线交叉点,按 y 键排序,即按垂直顺序。所以上面的部分是 BST 的后继者,下面的部分是 BST 的前身。在 BST 中查找给定节点的前任和后继是标准的东西。密钥 K 的前任是 K 的最右边的节点。后继是 K 的最左边的节点。有几种计算方法。最简单的方法是使用父指针从 K 向上然后向下遍历树。基于堆栈的迭代器是另一种。

如果扫描线(SL)为空怎么办?

继续处理事件队列。一条空的扫描线仅表示在其当前 x 位置没有任何线段相交。

另外,在将 I 插入 X 时,我是否应该将其标记为 endpoint = 'intersect' 并将其附加到末尾...?

事件队列必须保持按点的 x 坐标排序。插入交点时,它也必须按 x 坐标顺序。必须将其标记为交叉点,因为交叉点的处理方式与端点不同。当它是x顺序中的第一个剩余项目时,它将在适当的时候处理。

请注意,Bentley Ottman - 就像几乎所有几何算法一样 - 由于浮点不准确性而众所周知会遭受可怕的失败。此外,该算法通常带有“一般位置”假设,它排除了垂直边缘、点边缘重合、边缘边缘重叠等所有令人讨厌的情况。我最强烈的建议是使用理性算术。即便如此,获得一个完全健壮、正确的实现也是一项重大成就。您可以通过极少数的免费实现来判断这一点!

【讨论】:

  • 感谢您迟到的答复。我最终自己明白了。 :)
  • 我支持有理算术的使用。我们尝试了各种技巧来使浮点工作,但是由于有数千条边的交集,总是会出现由于舍入错误而导致的失败案例。有理算术虽然速度较慢,但​​总是正确的。
猜你喜欢
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多