圈厚度绘制算法厚度、算法

2023-09-11 23:16:53 作者:肆虐ヽ Ragingヽ

目前我使用的布氏圆圈绘制算法,绘制圆圈很好,不过,我想一个比较快速和有效的方式来绘制规定厚度圆(因为布氏方法只绘制单个像素的厚度)。我意识到,我可以简单地绘制多个圆半径不同,但我相信这将是非常低效的(和效率是很重要的,因为这将在一个Arduino,每一个微秒为precious运行)。 我目前正在使用下面的code:

Currently I am using Bresenham's circle drawing algorithm, which draws circles fine, however I would like a relatively fast and efficient way to draw a circle with a specified thickness (since Bresenham's method only draws a single pixel thickness). I realise that I could simply draw multiple circles with different radii, but I believe this would be very inefficient (and efficiency is important because this will be running on an Arduino where every microsecond is precious). I am currently using the following code:

void circle(byte xc, byte yc, int radius, Colour colour) {
  int x = -radius, y = 0, err = 2 - 2 * radius;
  while(x < 0) {
    setPixel(xc - x, yc + y, colour);
    setPixel(xc - y, yc - x, colour);
    setPixel(xc + x, yc - y, colour);
    setPixel(xc + y, yc + x, colour);
    radius = err;
    if(radius <= y) {
      err += ++y * 2 + 1;
    }
    if(radius > x || err > y) {
      err += ++x * 2 + 1;
    }
  }
}

我怎么能修改此,以便规范圆的厚度? PS我不希望使用任何外部库,请!

How could I modify this to allow for specification of the circle's thickness? PS I don't want to use any external libraries, please!

推荐答案

如果你沿着八分圆扫描所解释的的中点画圆算法,你的主要协调将始终由一个增加。然后,您可以得出两个圆一次,因为他们的主要坐标是同步的。

If you scan along octants as explained for the Midpoint circle algorithm, your major coordinate y will always increase by one. You can then draw two circles at once, because their major coordinates are in sync.

不是把像素,你画的内外圆的点,它具有相同的 y之间的水平(垂直)线(或 X )的坐标。你这样做,直到外圆到达角。

Instead of placing pixels, you draw horizontal (and vertical) lines between the points of the inner and outer circle, which have the same y (or x) coordinate. You do so until the outer circle reaches the diagonal.

您使用 X保持状态和 ERR 的两个圆,内圆和外圆 0 。之后,内圆已达到对角,内点位于该对角线。这意味着您绘制8相邻的八分部门。

You keep the state with x and err for two circles, the inner circle i and the outer circle o. After the inner circle has reached the diagonal, the inner point lies on that diagonal. This means you are drawing eight adjoining octant sectors.

此想法是非常相似,@oakad提出的意见,但不需要用于保持的列表。中点圆算法可能比布氏算法慢,所以有可能改进的空间,但低内存占用是一个优势。

This idea is very similar to what @oakad proposed in the comments, but without the need for keeping a list. The Midpoint circle algorithm might be slower than the Bresenham algorithm, so there's probably room for improvement, but the low memory footprint is an advantage.

下面的code将绘制一个空心圆与给定的内,外径。线宽为 RO - RI + 1 ,因此,即使相同的半径将打印一个圆是一个像素宽。如果内半径比外半径小所以它不会输出任何东西。

The code below will draw a hollow circle with the given inner and outer radii. The line width is ro - ri + 1, so that even equal radii will print a circle that is one pixel wide. It won't print anything if the inner radius is smaller than the outer radius.

void xLine(int x1, int x2, int y, int colour)
{
    while (x1 <= x2) setPixel(x1++, y, colour);
}

void yLine(int x, int y1, int y2, int colour)
{
    while (y1 <= y2) setPixel(x, y1++, colour);
}

void circle2(int xc, int yc, int inner, int outer, int colour)
{
    int xo = outer;
    int xi = inner;
    int y = 0;
    int erro = 1 - xo;
    int erri = 1 - xi;

    while(xo >= y) {
        xLine(xc + xi, xc + xo, yc + y,  colour);
        yLine(xc + y,  yc + xi, yc + xo, colour);
        xLine(xc - xo, xc - xi, yc + y,  colour);
        yLine(xc - y,  yc + xi, yc + xo, colour);
        xLine(xc - xo, xc - xi, yc - y,  colour);
        yLine(xc - y,  yc - xo, yc - xi, colour);
        xLine(xc + xi, xc + xo, yc - y,  colour);
        yLine(xc + y,  yc - xo, yc - xi, colour);

        y++;

        if (erro < 0) {
            erro += 2 * y + 1;
        } else {
            xo--;
            erro += 2 * (y - xo + 1);
        }

        if (y > inner) {
            xi = y;
        } else {
            if (erri < 0) {
                erri += 2 * y + 1;
            } else {
                xi--;
                erri += 2 * (y - xi + 1);
            }
        }
    }
}