我在网格上有一个像素 P 。我想知道该像素是否位于 P0 和 P1 之间bresenham生成的行上,而不实际生成该行。这有可能提出这样一个决定因素吗?
答案 0 :(得分:1)
我写这个作为答案,尽管它只是一个非常局部的答案。
我相信答案是肯定的。然而,编写它的证明相当有点工作,至少需要TeX支持是可以理解的。相反,这是开发证据的关键思想。
考虑0到1之间的斜率m。这很通用,你可以通过反射获得其他三个部分。 Brensenham的算法为您提供了一系列水平运行,每个运行上升1.这些运行的长度始终为n或n + 1,其中n <= 1 / m <= n + 1。因此,您可以将Brensenham线视为0和1的二进制序列。这很基本。
更不明显的是,这个序列受m的连续分数扩展支配。考虑上述不等式的误差项m - 1 /(n + 1)。这产生了第一个&#34;校正斜率&#34;通过用斜率1 /(n + 1)从下面近似斜率m。迭代这个过程得到一系列收敛到m的修正斜率。很明显,这些校正斜率只是连续分数序列的变换。您还可以看到上面的0/1序列是一组越来越大的quasisubperiods,其层次结构是连续分数扩展的另一个变换。
为了检验你对此的理解,一个结果是这些关系是如果m是理性的,那么它的连续分数扩展是有限的,Brensenham序列是周期性的。
这为您提供了比谓词测试更强大的功能。您可以使用校正斜率序列来计算任意x坐标的y坐标。简单地将所有修正斜率乘以x。加上足够多的它们直到误差界限间隔(你得到交替的上限和下限)完全具有整数范围,即n <= a&lt; b&lt;的n + 1。
答案 1 :(得分:1)
以Wikipedia: Bresenham's line algorithm为例,用(1,1)到(11,5)中的一行:
和从伪代码样本派生的代码:
Module Module1
Dim chart(15, 9) As String
Class Point
Property X As Double
Property Y As Double
Sub New(x As Double, y As Double)
Me.X = x
Me.Y = y
End Sub
Sub New()
' empty constructor
End Sub
End Class
Sub ClearChart()
For i = 0 To 15
For j = 0 To 9
chart(i, j) = "·"
Next
Next
End Sub
Sub ShowChart(title As String)
If title.Length > 0 Then
Console.WriteLine(title)
End If
For j = 0 To 9
For i = 0 To 15
Console.Write(chart(i, j))
Next
Console.WriteLine()
Next
Console.WriteLine()
End Sub
Sub Plot(p As Point)
Plot(p.X, p.Y)
End Sub
Sub Plot(x As Double, y As Double)
chart(CInt(Math.Round(x, MidpointRounding.AwayFromZero)), CInt(Math.Round(y, MidpointRounding.AwayFromZero))) = "█"
End Sub
Sub DrawLine(p1 As Point, p2 As Point)
' use Bresenham's line algorithm
Dim Δx = p2.X - p1.X
Dim Δy = p2.Y - p1.Y
Dim err As Double = 0.0
Dim Δerr = Math.Abs(Δy / Δx)
Dim y As Integer = CInt(p1.Y)
Dim yDirn = Math.Sign(p2.Y - p1.Y)
For x = CInt(p1.X) To CInt(p2.X)
Plot(x, y)
err += Δerr
While err >= 0.5
Plot(x, y)
y += yDirn
err -= 1.0
End While
Next
End Sub
Function IsOnLine(p1 As Point, p2 As Point, testPoint As Point) As Boolean
' check for bounds
If testPoint.X < p1.X - 0.5 OrElse testPoint.X > p2.X + 0.5 OrElse testPoint.Y < p1.Y - 0.5 OrElse testPoint.Y > p2.Y + 0.5 Then
Return False
End If
Dim Δx = p2.X - p1.X
Dim Δy = p2.Y - p1.Y
Dim m = Δy / Δx
Dim c = p1.Y - m * p1.X
Return Math.Abs((m * Math.Round(testPoint.X, MidpointRounding.AwayFromZero) + c - Math.Round(testPoint.Y, MidpointRounding.AwayFromZero))) <= 0.5
End Function
Sub Main()
ClearChart()
' end-points of the line
Dim p1 = New Point(1, 1)
Dim p2 = New Point(11, 5)
DrawLine(p1, p2)
ShowChart("Bresenham line:")
ClearChart()
For j = 0 To 9
For i = 0 To 15
Dim thisPoint = New Point(i, j)
If IsOnLine(p1, p2, thisPoint) Then
Plot(thisPoint)
End If
Next
Next
ShowChart("Points on the line by brute-force:")
' a couple of points to go with the illustration on SO:
Console.WriteLine(IsOnLine(p1, p2, New Point(7.51, 4.4)))
Console.WriteLine(IsOnLine(p1, p2, New Point(7.51, 4.6)))
Console.ReadLine()
End Sub
End Module
我将这两个像素绘制成算法生成的像素,然后测试每个像素,看它是否会在算法生成的行上:
Bresenham line:
················
·██·············
···██···········
·····███········
········██······
··········██····
················
················
················
················
Points on the line by brute-force:
················
·██·············
···██···········
·····███········
········██······
··········██····
················
················
················
················
(在控制台窗口看起来好多了......咳咳。)
虽然很难证明其正确性,但您可以看到它是否正确确定了是否为所使用的数据样本绘制了点。
回到第一张图片,它正确地确定了(7.51,4.4)被绘制而且(7.51,4.6)不是你将这些值放入IsOnLine()
。
请注意,实线上有一些点不包含在Bresenham线算法生成的像素中,例如本例中的(4.51,2.440)。 IsOnLine()
会为这些积分返回False
。
答案 2 :(得分:0)
对于第一个八分圆线段(Dx > Dy > 0
),像素为
X = X0 + I
Y = Y0 + (I.Dy + R) / Dx
其中R
是舍入常量(通常为Dx / 2
)。
然后检查
就足够了Y == Y0 + ((X - X0).Dy + R) / Dx
您可以重写
之类的标准0 <= (X - X0).Dy + R - (Y - Y0).Dx < Dx
您需要调整其他八分圆的关系。
答案 3 :(得分:0)
我在 python 中尝试了 Andrew Morton 的代码。
仅适用于第一象限 x > y 或 100 > 25 。我仅在 x, y 计算为 bresenham 线时绘制。我知道你说没有绘图,但绘图仅用于演示。还有8个其他象限
def andrew_morton_bresenham(x0,y0,x1,y1,filename):
from PIL import Image, ImageDraw
im = Image.new('1', (100,100))
plot_func = lambda x,y,val: im.putpixel((x,y),val)
for x in range(im.width):
for y in range(im.height):
delta_x = x1-x0 #Dim Δx = p2.X - p1.X
delta_y = y1-y0 #Dim Δy = p2.Y - p1.Y
slope=delta_y / delta_x #m = Δy / Δx
c = y0 - slope * x0 #Dim c = p1.Y - m * p1.X
eval_line = abs(slope * x + c - y)
if (eval_line <= 0.5):
plot_func(x,y,1)
im.save(filename)
andrew_morton_bresenham(0,0, 100,25,'bresenham-functional-copy-stackflow.png')
答案 4 :(得分:-1)
您似乎正在寻找第一种方法来查找 bresenham 线上是否存在点。我正在寻找更好的解决方案,但这是我目前所做的;
使用这种方法,如果该行已经排序并存在,他的搜索应该是O(log2N)