代码之家  ›  专栏  ›  技术社区  ›  horseyguy

如何使用Bresenham创建任意厚度的线条?

  •  23
  • horseyguy  · 技术社区  · 16 年前

    我目前正在使用Bresenham的算法绘制线条,但它们(当然)是一个像素的厚度。我的问题是,画任意厚度的线最有效的方法是什么?

    我使用的语言是C。

    10 回复  |  直到 6 年前
        1
  •  10
  •   Skizz    6 年前

    我认为最好的方法是画一个矩形而不是一条线,因为一条宽的线是一个二维物体。为了避免透支(减少写带宽)和欠原始(丢失像素)而绘制一组平行线的字符串会非常复杂。从起点、终点和宽度计算矩形的角点并不难。

    因此,按照下面的注释,这样做的过程是:

    1. 创建一个与所需线条和宽度相同的矩形,宽度等于所需宽度,因此(0,0)到(宽度,长度)
    2. 使用二维转换将矩形角坐标旋转并转换到所需位置
    3. 使用硬件加速渲染器(例如,OpenGL四元体)或软件光栅器对旋转的矩形进行光栅化。它可以使用四重光栅或作为一对三角形(例如左上和右下)进行渲染。

    注*:如果您使用的是OpenGL,那么您也可以同时执行步骤2。当然,使用OpenGL确实意味着要理解OpenGL(大而复杂),而且这个应用程序可能会使它在开发的如此后期实现成为一件棘手的事情。

        2
  •  17
  •   Armin J.    9 年前

    取另一个Bresenham环,用它来修改原直线在矩形方向的起始和结束位置。 问题是要有效地找到正确的起点,并且在绘制下一行时不要两次绘制任何像素(或跳过一个像素)。

    工作和测试的C代码可从Github获得 C code .

    这里是一个测试页,包含一些由该代码创建的示例行。 黑色像素是算法的起点。

    Test page with bresenham lines with different thickness

        3
  •  9
  •   Martin B    16 年前

    这里是一个 paper and Delphi implementation 一个修改版的布雷森汉姆算法绘制加厚线。

    你也可以看看 Anti-Grain Geometry 一个高质量和高性能的二维图形软件渲染库。看看 demo page 了解它能做什么。

        4
  •  7
  •   Fabel    9 年前

    为了获得最佳的精度,而且对于较粗的线也有良好的性能,尤其是可以将线绘制为多边形。一些伪代码:

    draw_line(x1,y1,x2,y2,thickness)
      Point p[4];
      angle = atan2(y2-y1,x2-x1);
      p[0].x = x1 + thickness*cos(angle+PI/2);
      p[0].y = y1 + thickness*sin(angle+PI/2);
      p[1].x = x1 + thickness*cos(angle-PI/2);
      p[1].y = y1 + thickness*sin(angle-PI/2);
      p[2].x = x2 + thickness*cos(angle-PI/2);
      p[2].y = y2 + thickness*sin(angle-PI/2);
      p[3].x = x2 + thickness*cos(angle+PI/2);
      p[3].y = y2 + thickness*sin(angle+PI/2);
      draw_polygon(p,4)
    

    可以选择在每个端点画一个圆。

        5
  •  4
  •   ShuggyCoUk    16 年前

    一些简单的使用路径:

    1. 对于任何宽度n,其中n是奇数。对于任何绘制的点P,也绘制其上/下的点N/2(如果线为45度角,则绘制边到边)。
      • 不是很合适的粗细线条,更像斜体笔,但速度很快。
    2. 对于起点P(x,y),选取点t0和b,使它们以p为中心,但相距n个像素。对于终点,执行相同的操作,得到T1 b1。从t0->t1、t1->b1、b1->t0、b0->t1绘制线条。填充生成的矩形。
      • 这里的技巧是选择点,使它们看起来与路径方向垂直。
    3. 对于直线上的每个点P,而不是画一个点,画一个圆。
      • 这样做的好处是,无论方向如何,都能使端点“干净”。
      • 除了第一个圆外,不需要渲染任何实心圆。
      • 有点慢
        6
  •  2
  •   dmckee --- ex-moderator kitten    16 年前

    我假设您将绘制从一条边界线到另一条边界线的水平跨度,并在进行(在单个循环中)时使用Bresenham方法计算每一条线的X值。

    还没试过。

    终点可能需要一些注意,以免看起来很奇怪。

        7
  •  1
  •   g023    11 年前

    http://members.chello.at/~easyfilter/bresenham.html

    这个链接底部的例子是javascript,但是应该很容易适应C语言。这是一个相当简单的反锯齿算法,可以绘制不同厚度的线条。

        8
  •  1
  •   2cynykyl    8 年前

    我经常这样做来生成多孔介质模拟中纤维和球体的图像。我有一个很好的简单方法,使用一种非常标准的图像分析技术,叫做“距离变换”。这需要访问一些图像分析包。我把python和scipy结合使用,所以这没问题。下面是一个将随机分布的点转换为球体的演示:

    import scipy as sp
    import scipy.ndimage as spim
    
    im1 = sp.rand(100, 100) < 0.995  # Create random points in space
    dt = spim.distance_transform_edt(im1)
    im2 = dt < 5  # To create sphere with a radius of 5
    

    random seeds, distance map, final spheres

    就这样!对于非常大的图像,距离变换可能会很慢,但有一些有效的版本。例如,imagej有一个平行化的。显然,要创建厚纤维,只需创建薄纤维的图像,然后应用上面的步骤2和3。

        9
  •  0
  •   Krista K    11 年前

    对于我的嵌入式热敏打印机应用程序,使用Bresenham的算法,这条线太细了。我没有GL或任何花哨的东西。最后,我简单地减小了y值,在第一个值下面画了更多的线。每增加一行厚度。非常快速的实现和制作所需的结果打印从单色位图到热。

        10
  •  0
  •   danius    10 年前

    我以前也面临同样的问题。 基于此 paper ,我创建了一个Matlab引用实现,我想与大家分享 GitHub .