【问题标题】:Iterate each point within a polygon迭代多边形内的每个点
【发布时间】:2012-11-15 00:42:13
【问题描述】:

假设我在网格环境中有某个多边形的顶点,我如何遍历它包含的每个单元格(包括边缘上的单元格)?

为了澄清,我有以下顶点(算作左上角是(0, 0)):

//each point is [x, y]
var verts = [
    [1, 1],
    [3, 1],
    [3, 2],
    [4, 2],
    [4, 4],
    [0, 4],
    [0, 3],
    [1, 3]
];

这会定义一个像这样的多边形:

根据上面的顶点,每个绿点都是我想要迭代的点。顶点沿着多边形边缘的方向没有模式,它可以围绕多边形顺时针或逆时针移动。但是,它们将井然有序;也就是说,如果你放下笔并按顺序移动到每个顶点,而不抬起,它会绘制轮廓而不会在多边形内部交叉。

用例是我有来自通过画布 API 加载的 PNG 的 imageData。这个PNG被分成“区域”,我需要迭代当前“区域”的每个像素。每个“区域”都由一个顶点数组定义,如上。

我尝试了类似以下的方法,它将为数组中的每组 4 个顶点创建一个用于迭代的正方形。

for(var v = 0, vl = verts.length - 4; v < vl; ++v) {
    //grabbing the minimum X, Y and maximum X, Y to define a square to iterate in
    var minX = Math.min(verts[v][0], verts[v + 1][0], verts[v + 2][0], verts[v + 3][0]),
        minY = Math.min(verts[v][1], verts[v + 1][1], verts[v + 2][1], verts[v + 3][1]),
        maxX = Math.max(verts[v][0], verts[v + 1][0], verts[v + 2][0], verts[v + 3][0]),
        maxY = Math.min(verts[v][1], verts[v + 1][1], verts[v + 2][1], verts[v + 3][1]);

    for(var x = minX; x < maxX; ++x) {
        for(var y = minY; y < maxY; ++y) {
            //do my checks on this pixel located at X, Y in the PNG
        }
    }
}

这有两个大问题:

  1. 它可以在多边形内重复点,并且
  2. 可以抓取多边形外的点

我可以通过跟踪我检查的点来解决第一个问题,因此我不会重复检查。第二个只能通过对每个点运行PointInPoly 检查来解决,这会使这个解决方案比我想要的要重得多。

编辑
迭代整个图像中的每个像素并对每个像素应用PointInPoly 检查也是不可接受的;它会比上面的算法还要慢。

【问题讨论】:

  • 1:你是对的——遍历画布的 ImageData 中的像素,即使是在屏幕外,也很粗糙。 2:你有一堆你正在定义的矩形,基于你列表中的每4个点,然后你用蛮力穿过像素。相反,为什么不尝试从您的点数据创建最大面积的矩形。这不是一个简单的解决方案,但是如果您获取顶点列表并从这些点创建边界框,这些点保证在这些区域内,并将这些新框推入一个新数组,这就是所有内存,然后是像素每个框都需要修改。
  • @Norguard 我不认为我完全理解你在说什么,或者如何实现它。有什么方法可以获取代码示例(甚至是伪代码)?

标签: javascript canvas polygon


【解决方案1】:

如果你的多边形是凸的,你可以这样做:

  • 为多边形的每条边创建一条线,表示一侧内侧和一侧外侧(这是基于法线,可能取决于缠绕方向)
  • 对于已计算的边界框内的每个像素,检查该像素是否位于线的内侧。如果像素位于任何一条线的外侧,则它位于多边形之外。如果它在所有这些里面,那么它在里面。

基本算法来自这里:https://github.com/thegrandpoobah/voronoi/blob/master/stippler/stippler.cpp#L187

如果您的多边形不是凸的,那么我要做的就是在画布上以已知颜色实际绘制多边形,然后应用iterative flood fill algorithm。这要求您至少知道内部的一个像素,但这不应该是一项昂贵的测试。但这可能不适用于 JavaScript,如果您无法在屏幕外缓冲区中执行此操作(不熟悉 canvas 标签)。

【讨论】:

  • 不,我不知道。这意味着我将迭代整个地图的每个像素并检查每个像素是否在多边形内。我已经为这些区域内的其他检查投射光线,但这不是我想要的。我真的只想击中区域内的像素。对于大型地图(有很多),我在问题中提出的循环会比这快得多。
  • 啊,好吧,我误解了要求。我已将我的答案更新为另一种算法。
  • 创建一个边界框,并对框内的每个点应用某种 PointInPoly 检查是我现在正在做的事情(尽管我正在创建许多较小的边界框,而不是一个大的边界框)。我希望有一种更准确的方法来做到这一点;一些我不知道的属性允许我使用边界框方法。
  • 我不知道。我一直使用迭代泛洪填充创建一个二进制蒙版,并且只是与像素的颜色值进行了简单的乘法运算。这是在 C++ 中,尽管迭代这些像素是可并行化且快速的......
  • 我将把你的方法和 Norgaurd 的一些建议结合起来。
猜你喜欢
  • 2020-12-18
  • 2015-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-28
  • 1970-01-01
  • 2011-12-19
相关资源
最近更新 更多