填充多边形

时间:2015-08-04 00:53:56

标签: c graphics geometry drawing trigonometry

我创建了这个函数,用 n 个顶点绘制一个简单的多边形:

void polygon (int n)
{
    double pI = 3.141592653589;
    double area = min(width / 2, height / 2);
    int X = 0, Y = area - 1;
    double offset = Y;
    int lastx, lasty;

    double radius = sqrt(X * X + Y * Y);
    double quadrant = atan2(Y, X);

    int i;

    for (i = 1; i <= n; i++)
    {
        lastx = X; lasty = Y;
        quadrant = quadrant + pI * 2.0 / n;

        X = round((double)radius * cos(quadrant));
        Y = round((double)radius * sin(quadrant));

        setpen((i * 255) / n, 0, 0, 0.0, 1); // r(interval) g b, a, size

        moveto(offset + lastx, offset + lasty); // Moves line offset
        lineto(offset + X, offset + Y); // Draws a line from offset
    }
}

如何用纯色填充? 我不知道如何修改我的代码以便填充它。

4 个答案:

答案 0 :(得分:1)

填充形状的常用方法是找到多边形的边缘与每个 x 或每个 y 坐标交叉的位置。通常,使用 y 坐标,以便可以使用水平线完成填充。 (在VGA等帧缓冲设备上,水平线比垂直线快,因为它们使用连续的内存/帧缓冲地址。)

就是这样,

void fill_regular_polygon(int center_x, int center_y, int vertices, int radius)
{
    const double a = 2.0 * 3.14159265358979323846 / (double)vertices;
    int i = 1;
    int y, px, py, nx, ny;

    if (vertices < 3 || radius < 1)
        return;

    px = 0;
    py = -radius;
    nx = (int)(0.5 + radius * sin(a));
    ny = (int)(0.5 - radius * cos(a));
    y  = -radius;

    while (y <= ny || ny > py) {
        const int x = px + (nx - px) * (y - py) / (ny - py);
        if (center_y + y >= 0 && center_y + y < height) {
            if (center_x - x >= 0)
                moveto(center_x - x, center_y + y);
            else
                moveto(0, center_y + y);
            if (center_x + x < width)
                lineto(center_x + x, center_y + y);
            else
                lineto(width - 1, center_y + y);
        }
        y++;
        while (y > ny) {
            if (nx < 0)
                return;
            i++;
            px = nx;
            py = ny;
            nx = (int)(0.5 + radius * sin(a * (double)i));
            ny = (int)(0.5 - radius * cos(a * (double)i));
        }
    }
}

请注意,我只使用简单的SVG生成器测试了上述内容,并将绘制的线条与多边形进行了比较。似乎工作正常,但使用风险自负;没有保证。

对于一般形状,使用您最喜欢的搜索引擎来查找&#34;多边形填充&#34;算法。例如,thisthisthisthis

答案 1 :(得分:1)

实施解决方案有两种不同的方法:

扫描线

从位于顶部的坐标(最小y值)开始,继续逐行扫描(递增y)并查看哪些边与线相交。

  • 对于凸多边形,您会找到2个点,(x1,y)和(x2,y)。只需在每条扫描线上划一条线即可。
  • 对于凹多边形,这也可以是2的倍数。只需在每对之间绘制线条。在一对之后,转到下一个2坐标。这将在该扫描线上创建填充/未填充/填充/未填充图案,该图案将解析为正确的整体解决方案。

如果您有自相交的多边形,您还会找到与某些多边形点相等的坐标,并且必须将它们过滤掉。在那之后,您应该处于上述情况之一。

如果在扫描衬里期间过滤掉多边形点,请不要忘记绘制它们。

洪水填充

另一种选择是使用洪水填充。它必须在每个像素的每个步骤中执行更多的工作来评估边界情况,因此这往往会变成较慢的版本。我们的想法是在多边形内选择一个种子点,并且基本上递归地逐像素地向上/向下/向左/向右延伸,直到你碰到边界。

算法必须读取和写入多边形的整个表面,并且不跨越自相交点。对于大型表面,可能存在相当大的堆积(对于至少天真的实现),并且对于边界条件的灵活性降低是基于像素的(例如,当在多边形顶部绘制其他东西时溢入间隙)。从这个意义上讲,这不是一个数学上正确的解决方案,但它适用于许多应用程序。

答案 2 :(得分:0)

最有效的解决方案是通过分解梯形中的正多边形(以及一个或两个三角形)。

通过对称,顶点垂直对齐,找到限制性横坐标(X + R cos(2πn/N)X + R cos(2π(+1)N))很容易。

您还有纵坐标(Y + R sin(2πn/N)Y + R sin(2π(+1)N)),它足以按Y = Y0 + (Y1 - Y0) (X - X0) / (X1 - X0)在两个顶点间线性插值。

水平运行填充稍微复杂一些,因为顶点可能没有水平对齐,而且有更多的梯形。

答案 3 :(得分:-1)

无论如何,在没有依赖援助(或任何尝试)的情况下,似乎我/我自己再次/解决了这个问题。

void polygon (int n)
{
    double pI = 3.141592653589;
    double area = min(width / 2, height / 2);
    int X = 0, Y = area - 1;
    double offset = Y;
    int lastx, lasty;

    while(Y-->0) {
    double radius = sqrt(X * X + Y * Y);
    double quadrant = atan2(Y, X);

    int i;


   for (i = 1; i <= n; i++)
    {
        lastx = X; lasty = Y;
        quadrant = quadrant + pI * 2.0 / n;

        X = round((double)radius * cos(quadrant));
        Y = round((double)radius * sin(quadrant));

        //setpen((i * 255) / n, 0, 0, 0.0, 1);
        setpen(255, 0, 0, 0.0, 1); // just red

        moveto(offset + lastx, offset + lasty);
        lineto(offset + X, offset + Y);
    } }
}

正如您所看到的,它并不复杂,这意味着它可能不是最有效的解决方案......但它足够接近。 它减小半径并通过其较小的半径较小的版本填充它。 在这种情况下,精确度起着重要的作用,而 n 越高,准确度越低。