对于矩阵中的所有标记区域,找到它们用于绘制的顶点

时间:2016-01-03 11:47:02

标签: algorithm matrix graphics

我正在寻找一种算法,可以获得在3d应用程序中绘制矩阵标记区域所需的数据。

输入如下:

labeled regions in a matrix

对于每个区域,我需要以CCW顺序找到其外边界的顶点。 我已经可以通过查看邻居来找到所有水平或垂直边的顶点,但是我的实现从左到右,从上到下而不是在CCW顺序中找到顶点。这是我的代码。

for (int i = 1; i < columns-1; i++)
    for (int j = 1; j < rows - 1; j++) {
        if (grid[i][j] > 0) { // not background
            if ((grid[i + 1][j] != id) && (grid[i][j - 1] != id)) {
                getCellTopLeftCoord(i, j, &x, &y);
                polyPath[id]->Add(gcnew mPoint(x + width, y));
            }
            if ((grid[i - 1][j] != id) && (grid[i][j - 1] != id)) {
                getCellTopLeftCoord(i, j, &x, &y);
                polyPath[id]->Add(gcnew mPoint(x, y));
            }
            ... // etc..

这是我感兴趣的界限:

Boundaries of the labeled regions I am looking for

1 个答案:

答案 0 :(得分:1)

如果没有任何未连接的表面带有重复标签,则以下步骤应该有效:

  • 从上到下,从左到右遍历矩阵。如果遇到带有尚未处理的标签的非空单元格,请为该标签创建路径。

  • 您发现的观点肯定是东北角。把这一点放在你的道路上。

  • 现在创建一个方向列表,然后从南方开始。因为你逆时针沿着边界走,你应该总是左边有一个被占用的单元,右边有一个未被占用的单元。 (此处占用的是指具有所需标签的单元格。)

  • 当您尝试查找下一个方向时,请继续沿最后一个方向并检查右侧和左侧的单元格。如果两者都未被占用,请向左转。如果至少有一个被占用,请右转。否则,继续直行。

  • 更改方向时,请将当前点附加到路径。

  • 根据当前方向更新坐标。重复,直到达到原始坐标。

此方法不会为您提供草图中标记为4的区域周围的对角线;它将遵循轴对齐的锯齿状轮廓。

这是Javascript中的一个示例实现。单元数据包含在二维数组m中。 cell查找单元格,但会查找超出范围的查找。 path为单个标签创建路径。 paths创建路径列表;它调用path

function cell(x, y) {
    if (y < 0) return 0;
    if (y >= m.length) return 0;

    if (x < 0) return 0;
    if (x >= m[y].length) return 0;

    return m[y][x];
}

function path(x, y, c) {
    var x0 = x;
    var y0 = y;

    var res = [{x: x, y: y}];
    var dir = "s";

    var l, r;

    y++;

    while (x != x0 || y != y0) {
        var old = dir;

        switch (dir) {
        case "n":   l = (cell(x - 1, y - 1) == c) ? 1 : 0;
                    r = (cell(x, y - 1) == c) ? 2 : 0;
                    dir = ["w", "n", "e", "e"][l + r];
                    break;

        case "e":   l = (cell(x, y - 1) == c) ? 1 : 0;
                    r = (cell(x, y) == c) ? 2 : 0;
                    dir = ["n", "e", "s", "s"][l + r];
                    break;

        case "s":   l = (cell(x, y) == c) ? 1 : 0;
                    r = (cell(x - 1, y) == c) ? 2 : 0;
                    dir = ["e", "s", "w", "w"][l + r];
                    break;

        case "w":   l = (cell(x - 1, y) == c) ? 1 : 0;
                    r = (cell(x - 1, y - 1) == c) ? 2 : 0;
                    dir = ["s", "w", "n", "n"][l + r];
                    break;
        }

        if (dir != old) res.push({x: x, y: y});

        switch (dir) {
        case "n":   y--; break;
        case "e":   x++; break;
        case "s":   y++; break;
        case "w":   x--; break;
        }
    }

    return res;
}

function paths() {
    var res = {};

    for (var y = 0; y < m.length; y++) {
        for (var x = 0; x < m[y].length; x++) {
            var c = m[y][x];

            if (c && !(c in res)) {
                res[c] = path(x, y, c);
            }
        }
    }

    return res;
}