是否可以测试像素是否在bresenham生成的线上而不生成线?

时间:2015-12-18 08:29:36

标签: geometry

我在网格上有一个像素 P 。我想知道该像素是否位于 P0 P1 之间bresenham生成的行上,而不实际生成该行。这有可能提出这样一个决定因素吗?

5 个答案:

答案 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)中的一行:

Pixels drawn with Bresenham's line algorithm

和从伪代码样本派生的代码:

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')

enter image description here

答案 4 :(得分:-1)

您似乎正在寻找第一种方法来查找 bresenham 线上是否存在点。我正在寻找更好的解决方案,但这是我目前所做的;

  1. 实际生成线像素并将它们存储在列表或向量中。如果您制作自己的 point() 或 pixel() 类或结构,则最好。 那个类应该有你写的比较功能。 线像素或点应在该列表中排序。
  2. 只需对该行执行自定义(亲自编写)二分搜索即可找到像素。

使用这种方法,如果该行已经排序并存在,他的搜索应该是O(log2N)