计算斜率和截距,通过y = kx + b
的直线表达式计算每一个x
对应的y
值
'''基础算法'''
def drawLine_Basic(grid, start, end):
k = (end.y-start.y)/(end.x-start.x)
b = start.y - k * start.x
for xi in range(start.x, end.x): # 栅格的性质
yi = k * xi + b
drawPixel(xi, int(yi+0.5), 1, grid) # y坐标要进行近似
采用**“增量”**的思想
|k|<=1
时,x
每增加1
,y
增加k
|k|>1
时,y
每增加1
,x
增加1/k
证明: (这里只考虑|k|<=1
当情况)
由 x i + 1 = x i + 1 x_{i+1} = x_{i} + 1 xi+1=xi+1
y i + 1 = k ∗ x i + 1 + b = k ∗ ( x i + 1 ) + b = k ∗ x i + b + k = y i + k y_{i+1} = k*x_{i+1} + b = k*(x_{i}+1) + b = k*x_{i} + b + k = y_{i} + k yi+1=k∗xi+1+b=k∗(xi+1)+b=k∗xi+b+k=yi+k
'''数值微分算法(DDA)'''
def drawLine_DDA(grid, start, end):
k = (end.y - start.y) / (end.x - start.x)
xi, yi = start.x, start.y
if(abs(k<=1)):
for xi in range(start.x, end.x):
drawPixel(xi, int(yi+0.5), 1, grid)
yi += k
else:
for yi in range(start.y, end.y):
drawPixel(int(xi+0.5), yi, 1, grid)
xi += 1/k
设直线方程为:ax + by + c =0
a = y0 - y1
b = x1 - x0
c = x0y1 - x1y0
**考核点:**(xp+1, yp+0.5)
判别式: Δ = F ( x p + 1 , y p + 0.5 ) = a ∗ ( x p + 1 ) + b ∗ ( y p + 0.5 ) + c \Delta = F(x_p+1, y_p+0.5) = a*(x_p+1) + b*(y_p+0.5) + c Δ=F(xp+1,yp+0.5)=a∗(xp+1)+b∗(yp+0.5)+c
如果
Δ
<
0
\Delta<0
Δ<0 => Q点在M下方 => 选p2 (x+1, y+1)
else, 选p1 (x+1, y)
'''中点画线法(k<=1)'''
def drwaLine_MidPoint(grid, start, end):
a, b, c = start.y-end.y, end.x-start.x, start.x*end.y-end.x*start.y
xp, yp = start.x, start.y
for xp in range(start.x, end.x):
drawPixel(xp, yp, 1, grid)
delta = a*(xp+1) + b*(yp+0.5) + c # 考核点(xp+1, yp+0.5)
if delta<0:
yp += 1
else:
# yp += 0
pass
p1
,增量为a
p2
,增量为a+b
d0 = a + 0.5*b
d
的符号来判断,可以用2d
代替d
,摆脱浮点数'''中点画线法 with DDA'''
def drawLine_MidPoint_with_DDA(grid, start, end):
a, b = start.y-end.y, end.x-start.x
d = a + (b<<2) # 用2d代替d, 摆脱小数
d1, d2 = a<<2, (a+b)<<2
xp, yp = start.x, start.y
for xp in range(start.x, end.x):
drawPixel(xp, yp, 1, grid)
if d<0:
yp += 1
d += d2
else:
d += d1
(x+1, y+1)
(x+1, y)
k-1
k
-0.5
'''Bresenham画线法(k<=1)'''
def drawLine_Bresenham(grid, start, end):
k = (end.y - start.y) / (end.x - start.x)
x, y = start.x, start.y
e = -0.5
for x in range(start.x, end.x):
drawPixel(x, y, 1, grid)
if e > 0:
e += k - 1
y += 1
else:
e += k
# y += 0
k
的计算2(dy - dx)
2dy
-dx
'''Bresenham画线法(去点浮)(k<=1)'''
def drawLine_Bresenham_nonreal(grid, start, end):
dx, dy = (end.x - start.x), (end.y - start.y)
x, y = start.x, start.y
e = -dx
for x in range(start.x, end.x):
drawPixel(x, y, 1, grid)
if e > 0:
e += (dy - dx) << 2
y += 1
else:
e += (dy) << 2
# y += 0
1/8
圆(第一象限 y>x
部分)F>0
,取正右方 (x+1, y)
(x+1, y-1)
d<0
, 增量为 2*x + 3
2*(x-y) + 5
1.25 - R
e = d - 0.25
代替 d
e = 1-R
d < 0
<=> e < 0.25
<= e
始终为整数 => e < 0
'''中点画圆法(DDA)'''
def drawArc_MidPoint_with_DDA(grid, R):
d = 1 - R
x, y = 0, R
while x < y:
drawPixel_symmetry8(x, y, 1, grid)
if d < 0:
x += 1
d += 2*x + 3
else:
x += 1
y -= 1
d += ((x-y) << 1) + 5
x
递增1,d
递增
Δ
x
=
2
\Delta x = 2
Δx=2y
递减1,d
递增
Δ
y
=
2
\Delta\ y = 2
Δ y=2'''中点画圆法(DDA)(去点浮)'''
def drawArc_MidPoint_with_DDA_nonreal(grid, R):
d = 1 - R
deltax, deltay = 3, 2 - (R << 1)
x, y = 0, R
while x < y:
drawPixel_symmetry8(x, y, 1, grid)
if d < 0:
x += 1
d += deltax
deltax += 2
else:
x += 1
y -= 1
d += (deltax + deltay)
deltax += 2
deltay += 2
选取距离真正的圆曲线近的点进行扩展
如果|OP1| > |OP2|
,则选P2
<=> x 1 2 + y 1 2 − R 2 > R 2 − x 2 2 − y 2 2 \sqrt{x_1^2 + y_1^2 - R^2} > \sqrt{R^2 - x_2^2 - y_2^2} x12+y12−R2>R2−x22−y22
<=> x 1 2 + y 1 2 + x 2 2 + y 2 2 − 2 R 2 > 0 x_1^2 + y_1^2 + x_2^2 + y_2^2 - 2R^2 > 0 x12+y12+x22+y22−2R2>0
当前像素的下一个扩展节点:正右方、右下方、正下方
H
H
、D
中选更近的D
V
、D
中选更近的V
令 Δ H = ∣ O H ∣ \Delta H = |OH| ΔH=∣OH∣, Δ D = ∣ O D ∣ \Delta D = |OD| ΔD=∣OD∣, Δ V = ∣ O V ∣ \Delta V = |OV| ΔV=∣OV∣
令 δ H D = ∣ Δ H ∣ − ∣ Δ D ∣ = ∣ O H ∣ − ∣ O D ∣ \delta HD = |\Delta H| - |\Delta D| = |OH| - |OD| δHD=∣ΔH∣−∣ΔD∣=∣OH∣−∣OD∣, δ D V = ∣ Δ D ∣ − ∣ Δ V ∣ \delta DV = |\Delta D| - |\Delta V| δDV=∣ΔD∣−∣ΔV∣
δ H D = 2 Δ D + 2 y − 1 \delta HD = 2\Delta D + 2y - 1 δHD=2ΔD+2y−1
δ D V = 2 Δ D − 2 x − 1 \delta DV = 2\Delta D - 2x - 1 δDV=2ΔD−2x−1
D
;else取V
H
;else,取D
D
用增量法简化 Δ D \Delta D ΔD,下一个像素取:
H
,增量取2x + 1
D
,增量取2x - 2y + 2
V
,增量取-2y + 1
-2r + 2
'''Bresenham画圆法'''
def drawArc_Bresenham(grid, R):
delta = (1 - R) << 1
x, y = 0, R
while y >= 0:
drawPixel_symmetry4(x, y, 1, grid)
if delta < 0:
delta1 = ((delta + y) << 1) - 1
if delta1 <= 0:
direction = 1
else:
direction = 2
elif delta > 0:
delta2 = ((delta - x) << 1) - 1
if delta2 <= 0:
direction = 2
else:
direction = 3
else:
direction = 2
if direction == 1: # 前进到 正右
x += 1
delta += (x << 1) + 1
elif direction == 2: # 前进到 右下
x += 1
y -= 1
delta += ((x - y) << 1) + 2
else: # 前进到 正下
y -= 1
delta += 1 - (y << 1)
P
在圆内 ->
D
(
x
i
,
y
i
)
<
=
0
D(x_i,y_i) <= 0
D(xi,yi)<=0 -> 向右P
在圆外 ->
D
(
x
i
,
y
i
)
>
0
D(x_i,y_i) > 0
D(xi,yi)>0 -> 向下F<=0
,增量为2x + 1
-2y + 1
0
'''正负法'''
def drawArc_PositiveNegative(grid, R):
F = 0
x, y = 0, R
while x <= y:
drawPixel_symmetry8(x, y, 1, grid)
print(F)
if F <= 0:
F += (x << 1) + 1
x += 1
else:
F += 1 - (y << 1)
y -= 1
l i m n − > ∞ ( n 边正内接多边形 ) = 圆 lim_{n->\infin}(n边正内接多边形) = 圆 limn−>∞(n边正内接多边形)=圆
圆的参数方程:
引入增量思想:
(
x
i
+
1
y
i
+
1
)
=
(
c
o
s
α
−
s
i
n
α
s
i
n
α
c
o
s
α
)
(
x
i
y
i
)
=
(
c
o
s
α
x
i
−
s
i
n
α
y
i
s
i
n
α
x
i
+
c
o
s
α
y
i
)
(
'''圆内接正多边形逼近法'''
def drawArc_InscribedRegularPolygonApproximate(grid, R):
Alpha = 1/R
cosAlpha, sinAlpha = cos(Alpha), sin(Alpha)
x, y = R, 0
while x >= y:
drawPixel_symmetry8(int(x+0.5), int(y+0.5), 1, grid)
x = cosAlpha * x - sinAlpha * y
y = sinAlpha * x + cosAlpha * y