Algorithm 如何使用Bresenham创建任意厚度的线?
我目前正在使用Bresenham的算法来绘制线条,但它们(当然)的厚度只有一个像素。我的问题是,画任意厚度的线最有效的方法是什么Algorithm 如何使用Bresenham创建任意厚度的线?,algorithm,graphics,Algorithm,Graphics,我目前正在使用Bresenham的算法来绘制线条,但它们(当然)的厚度只有一个像素。我的问题是,画任意厚度的线最有效的方法是什么 我使用的语言是C。我认为最好的方法是画一个矩形,而不是一条线,因为一条有宽度的线是一个二维对象。尝试绘制一组平行线以避免过度绘制(减少写入带宽)和欠绘制(缺少像素)将非常复杂。从起点、终点和宽度计算矩形的角点并不难 因此,在下面的评论之后,这样做的过程是:- 创建一个矩形,长度与所需线条相同,宽度等于所需宽度,因此(0,0)到(宽度,长度) 使用二维变换将矩形角坐标旋
我使用的语言是C。我认为最好的方法是画一个矩形,而不是一条线,因为一条有宽度的线是一个二维对象。尝试绘制一组平行线以避免过度绘制(减少写入带宽)和欠绘制(缺少像素)将非常复杂。从起点、终点和宽度计算矩形的角点并不难 因此,在下面的评论之后,这样做的过程是:-
那篇关于墨菲修改后的布列森厄姆线条图的论文看起来很有用,但只有链接的答案在这里的价值有限,所以这里有一点小结
有厚度的线是矩形。该算法使用外部Bresenham循环沿矩形的一条边单步走,而不实际绘制它。Bresenham环在外环的每一步绘制一条垂直线。通过将(x,y)坐标和误差项从外环传递到内环,它确保所有垂直线“同相”,确保矩形填充时没有间隙。每个像素集只设置一次。一些简单的使用方法:
- 这不是一条正确的线条,更像是一支斜体笔,但速度非常快
- 这里的技巧是拾取点,使它们看起来与路径方向正交
- 这样做的好处是,无论方向如何,端点都“干净”
- 除了第一个圆外,不需要渲染任何实心圆李>
- 有点慢
我假设您将绘制从一条边界线到另一条边界线的水平跨距,并使用Bresenham的方法(在单个循环中)计算每条边界线的x值 我没试过
端点可能需要注意,以免它们看起来奇怪地被切断。对于我的嵌入式热敏打印机应用程序,使用Bresenham的算法,线条太细了。我没有GL或任何花哨的东西。最后,我简单地减小了Y值,并在第一个值下画了更多的线。每增加一行厚度。从单色位图打印到热敏位图,实现效果非常快。使用另一个Bresenham循环,在矩形方向上修改原始行的起始和结束位置。 问题是要有效地找到正确的起点,在画下一行时不要画任何像素两次(或跳过一个像素) Github提供了可运行和测试的C代码 这里是一个测试页面,其中包含一些由该代码创建的示例行。 黑色像素是算法的起点
此链接底部的示例是javascript,但应该很容易适应C。这是一种相当简单的抗锯齿算法,用于绘制可变厚度的线。为了获得最佳精度,并且对于较厚的线也具有良好的性能,尤其是,您可以将线绘制为多边形。一些伪代码:
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)
也可以选择在每个端点画一个圆。我不久前也遇到过同样的问题。
基于此,我创建了一个Matlab参考实现,我想与大家分享一下 我经常这样做是为了生成用于多孔介质模拟的纤维和球体的图像。我有一个非常简单的方法,使用一种非常标准的图像分析技术,称为“距离变换”。这需要访问一些图像分析软件包。我将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
将scipy作为sp导入
将scipy.ndimage作为spim导入
im1=sp.rand(100100)<0.995#在空间中创建随机点
dt=spim.距离\u变换\u edt(im1)
im2=dt<5#创建半径为5的球体
就这样!对于非常大的图像,距离变换可能会很慢,但是有一种有效的版本。例如,ImageJ有一个并行的。显然,要创建厚纤维,只需创建薄纤维的图像,然后应用上面的步骤2和步骤3。最简单的创建方法
0 1 0
1 1 1
0 1 0
def drawline(x1,y1,x2,y2,**kwargs):
if kwargs.get('thickness')==None:
thickness=1
else:
thickness=kwargs['thickness']
if kwargs.get('roundcap')==None:
roundcap=False
else:
roundcap=True
angle = np.arctan2(y2-y1,x2-x1)
xx = np.zeros(4)
yy = np.zeros(4)
xx[0] = np.round(x1 + thickness*np.cos(angle+np.pi/2))
yy[0] = np.round(y1 + thickness*np.sin(angle+np.pi/2))
xx[1] = np.round(x1 + thickness*np.cos(angle-np.pi/2))
yy[1] = np.round(y1 + thickness*np.sin(angle-np.pi/2))
xx[2] = np.round(x2 + thickness*np.cos(angle-np.pi/2))
yy[2] = np.round(y2 + thickness*np.sin(angle-np.pi/2))
xx[3] = np.round(x2 + thickness*np.cos(angle+np.pi/2))
yy[3] = np.round(y2 + thickness*np.sin(angle+np.pi/2))
u,v=polygon(xx,yy)
if roundcap:
temp1x, temp1y = circle(x1,y1,thickness)
temp2x, temp2y = circle(x1,y1,thickness)
u = np.append(u,temp1x,temp2x)
v = np.append(v,temp1y,temp2y)
return u,v
drawline(10,10,50,50,thickness=3,roundcap=False)