Bresenham's algorithm用于在方形网格上绘制一条线,例如像素一样。
该算法部分基于将平面细分为8个部分,称为八分圆。
诀窍是使用对称来推广算法,无论第二个点位于何处:首先我们将其“移动”到第一个八分圆,然后进行计算,最后将生成的点转换回原始点八分圆。
维基百科提供了一个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_onInput
和switchToOctant_onOutput
(我现在看到的这个问题的明显解决方案)?
答案 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]
。