中点画线算法:
所需绘制直线的左下端点记为
, 右上端点记为
令
,
,则直线的斜截式为 :
所以,用隐函数表示直线的方程为 :
容易验证,点(x , y)若在直线上,F(x , y)= 0 ; 若在直线上方,F(x , y)> 0 ; 若在直线下方,F(x , y)< 0 。
(1). 斜率在 (0,1)区间:
假定选择了
处的像素 P ,现在必须在 P 的右邻像素 E 和右上方相邻像素 NE 中选取一个像素。
在中点算法中,只需计算
(M表示中点),并测试它的符号即可。
若 F(M)< 0 , 则 M 在直线下方,直线距离点 NE 更近 ,选择 NE ; 若 F(M)> 0 , 则 M 在直线上方,直线距离点 E 更近 ,选择 E .
如果选择的是 E ,应判断:
如果选择的是 NE ,应判断:
因为第一个像素是端点
, 可直接计算 J 的初始值
,以此决定是选 E 还是选 NE。
第一个中点在
处,有
由于
落在线上,因此
,故
值为
.
(2). 斜率在 (-1,0)区间:
假定选择了
处的像素 P ,现在必须在 P 的右邻像素 E 和右下方相邻像素 NE 中选取一个像素。
在中点算法中,只需计算
(M表示中点),并测试它的符号即可。
若 F(M)< 0 , 则 M 在直线下方,直线距离点 E 更近 ,选择 E ; 若 F(M)> 0 , 则 M 在直线上方,直线距离点 NE 更近 ,选择 NE .
如果选择的是 E ,应判断:
如果选择的是 NE ,应判断:
因为第一个像素是端点
, 可直接计算 J 的初始值
,以此决定是选 E 还是选 NE。
第一个中点在
处,有
由于
落在线上,因此
,故
值为
.
(3). 斜率大于 1:
直线的方程用隐函数还可以表示为:
(即上方式子取反)
容易验证,点(x , y)若在直线上,F(x , y)= 0 ; 若在直线左边,F(x , y)< 0 ; 若在直线右边,F(x , y)> 0 。
假定选择了
处的像素 P ,现在必须在 P 的上邻像素 E 和右上方相邻像素 NE 中选取一个像素。
在中点算法中,只需计算
(M表示中点),并测试它的符号即可。
若 F(M)< 0 , 则 M 在直线左边,直线距离点 NE 更近 ,选择 NE ; 若 F(M)> 0 , 则 M 在直线右边,直线距离点 E 更近 ,选择 E .
如果选择的是 E ,应判断:
如果选择的是 NE ,应判断:
因为第一个像素是端点
, 可直接计算 J 的初始值
,以此决定是选 E 还是选 NE。
第一个中点在
处,有
由于
落在线上,因此
,故
值为
.
(4). 斜率小于 -1:
假定选择了
处的像素 P ,现在必须在 P 的上邻像素 E 和左上方相邻像素 NE 中选取一个像素。
在中点算法中,只需计算
(M表示中点),并测试它的符号即可。
若 F(M)< 0 , 则 M 在直线左边,直线距离点 E 更近 ,选择 E ; 若 F(M)> 0 , 则 M 在直线右边,直线距离点 NE 更近 ,选择 NE .
如果选择的是 E ,应判断:
如果选择的是 NE ,应判断:
因为第一个像素是端点
, 可直接计算 J 的初始值
,以此决定是选 E 还是选 NE。
第一个中点在
处,有
由于
落在线上,因此
,故
值为
.
核心代码:
(在实现中,为消除分数部分,将 F 乘以 2 重新定义 F,使每个常量和判断变量均乘以 2 ,但这并不影响判断变量
的符号,因此仍可作为中点检测标准。)
from PySide2.QtCore import *
class Line:
def __init__(self, p):
self.p = p
def points_list_mid(self):
points = []
if self.p[0].y() == self.p[1].y():
if self.p[0].x() > self.p[1].x():
self.p.reverse()
x = self.p[0].x()
y = self.p[0].y()
while x < self.p[1].x():
points.append(QPoint(x, y))
x = x+1
return points
if self.p[0].x() == self.p[1].x():
if self.p[0].y() > self.p[1].y():
self.p.reverse()
x = self.p[0].x()
y = self.p[0].y()
while y < self.p[1].y():
points.append(QPoint(x, y))
y = y+1
return points
m = (self.p[1].y()-self.p[0].y())/(self.p[1].x()-self.p[0].x())
if m > 0 and m <= 1:
if self.p[0].x() > self.p[1].x():
self.p.reverse()
dx = self.p[1].x() - self.p[0].x()
dy = self.p[1].y() - self.p[0].y()
d = dx - 2*dy
dNE = 2*dx - 2*dy
dE = -2*dy
x = self.p[0].x()
y = self.p[0].y()
while x < self.p[1].x():
points.append(QPoint(x, y))
if d < 0:
d = d + dNE
y = y + 1
else:
d = d + dE
x = x+1
elif m >= -1 and m < 0:
if self.p[0].x() > self.p[1].x():
self.p.reverse()
dx = self.p[1].x() - self.p[0].x()
dy = self.p[1].y() - self.p[0].y()
d = -dx - 2*dy
dNE = -2*dx - 2*dy
dE = -2*dy
x = self.p[0].x()
y = self.p[0].y()
while x < self.p[1].x():
points.append(QPoint(x, y))
if d >= 0:
d = d + dNE
y = y - 1
else:
d = d + dE
x = x+1
elif m > 1:
if self.p[0].y() > self.p[1].y():
self.p.reverse()
dx = self.p[1].x() - self.p[0].x()
dy = self.p[1].y() - self.p[0].y()
d = dy - 2*dx
dNE = 2*dy - 2*dx
dE = -2*dx
x = self.p[0].x()
y = self.p[0].y()
while y < self.p[1].y():
points.append(QPoint(x, y))
if d <= 0:
d = d + dNE
x = x + 1
else:
d = d + dE
y = y+1
else:
if self.p[0].y() > self.p[1].y():
self.p.reverse()
dx = self.p[1].x() - self.p[0].x()
dy = self.p[1].y() - self.p[0].y()
d = -dy - 2*dx
dNE = -2*dy - 2*dx
dE = -2*dx
x = self.p[0].x()
y = self.p[0].y()
while y < self.p[1].y():
points.append(QPoint(x, y))
if d >= 0:
d = d + dNE
x = x - 1
else:
d = d + dE
y = y + 1
return points
加上UI界面实现效果:
PS: 如需参考完整代码,请移步:
https://download.csdn.net/download/qq_42185999/11834675
进行下载