维基百科的Bresenham算法是否存在错误?

时间:2015-07-10 19:26:17

标签: algorithm geometry bresenham line-drawing

Bresenham's algorithm用于在方形网格上绘制一条线,例如像素一样。

该算法部分基于将平面细分为8个部分,称为八分圆。

Octants

诀窍是使用对称来推广算法,无论第二个点位于何处:首先我们将其“移动”到第一个八分圆,然后进行计算,最后将生成的点转换回原始点八分圆。

维基百科提供了一个basic function来执行这个技巧。

 function switchToOctantZeroFrom(octant, x, y) 
   switch(octant)  
     case 1: return (x, y)
     case 2: return (y, x)
     case 3: return (y, -x)
     case 4: return (-x, y)
     case 5: return (-x, -y)
     case 6: return (-y, -x)
     case 7: return (-y, x)
     case 8: return (x, -y)

此外,我们只需要写道:

  

在输入和输出上翻转坐标系

这是基于这些转置实际上是involutions的事实:f(f(x)) = x

如果不太注意它,我首先想到它会起作用。

但对于案例3和案例7,它不起作用,因为它不是一种内卷。

例如:

Case 4: (-5, 1) => (5, 1) => (-5, 1) // Good
Case 3: (-1, 5) => (5, 1) => (1, -5) // Not good

我们必须再次采取行动:

Case 3: (-1, 5) => (5, 1) => (1, -5) => (-5, -1) => (-1, 5) // Good

那么,我误解了什么吗?

或者它实际上在维基百科上的文章起草方面缺乏准确性,是否有人会对其进行改进?

如果没有更好的方法来进行这些转换,我需要使用两个函数switchToOctant_onInputswitchToOctant_onOutput(我现在看到的这个问题的明显解决方案)?

2 个答案:

答案 0 :(得分:2)

通过对合的反射(自反)将八分之一2,4,6,8映射到八分圆1。通过180度旋转将八聚体5映射到八分圆1,该旋转也是对合的。然而,八分数7和3被映射到八分圆1 + -90度旋转,这不是对合的。映射根本不是对合,所以你无能为力。如果你想要一个反函数,你必须写它。

维基百科页面具有误导性,因为它说该功能是一个“翻转”,暗示了一种内卷。

我可以想到三种方法来解决这个问题:1)创建一个非常相似的反函数,除了交换3和7的情况(不重命名现有函数); 2)为负八面体添加表示反函数的情况,使switchOctant(3,x,y)的倒数为switchOctant(-3,x,y),与switchOctant(7,x,y)相同(但如果你需要仔细考虑八分之一0)做这个);或者3)通过增强线条绘制功能来减少或消除对几何变换功能的需要。特别是,如果您增强线条绘制功能来处理第一象限中的任何线条(而不仅仅是第一个八分圆!),您可以使用几何变换将任何象限映射到 对合的第一个象限。 / p>

<强>更新

我只是想到了这个问题上的另一个“角度”(可以这么说):可以通过反射将你的第三个八分圆映射到第一个八分圆。通过具有倾斜θ的原点的线的反射由

给出
x' = x * cos(2*theta) + y * sin(2*theta)
y' = x * sin(2*theta) - y * cos(2*theta)

第1和第3个八分圆之间的反射线倾角为theta = 45 + 45/2.0度,所以2*theta = 135度,我们有

x' = -sqrt(2)/2 * x + sqrt(2)/2 * y
y' =  sqrt(2)/2 * x + sqrt(2)/2 * y

类似的公式可用于将第7个八分圆映射到第1个。因此,有可能找到一个将每个八分圆映射到第一个八分圆的对合。但是,这种映射存在两个问题:1)它不是连续的,而维基百科文章中给出的映射是连续的(意味着当点在平面上移动时(x,y)的图像中没有突然跳跃); 2)目前尚不清楚如何使用整数运算来实现映射。

连续性不仅仅是一个理论问题。当您考虑如何在两个八分圆之间的边界上绘制点时,它变得切实可行。如果你不仔细地使用不连续的地图,你肯定会得到不正确的结果。

所以这个想法并不好,但我只是觉得为了完整起见我会提到它。

答案 1 :(得分:1)

Bresenham算法中的八分圆讨论基于相对于中位数和对角线的明显轴对称性。不需要内卷属性。 (如果你需要f的倒数,那么,使用...... f的倒数;但这并不是明确要求的。)

一个简单的变体是该行的参数方程的数字版本:

X = X0 + (k.(X1 - X0)) / D
Y = Y0 + (k.(Y1 - Y0)) / D

,其中

D = Max(|X1 - X0|, |Y1 - Y0|)
范围k中的

[0..D]