小白谈计算机图形学(二)画圆篇之中点画圆法,Bresenham画圆算法,椭圆实操,线型处理详解
引言
与直线不同,圆上每点的斜率都是变化的,这一讲我们来介绍圆的画法,首先注意到圆具有八对称性,即只需研究
1
8
\frac{1}{8}
81圆周即可。
如何画圆
基本思想
- 隐函数方程: ( x i , y i = r 2 − x i 2 ) (x_i,y_i=\sqrt{r^2-x_i^2} ) (xi,yi=r2−xi2)
- 参数方程:
{ x = r cos θ y = r sin θ \left\{ \begin {aligned} x = r\cos\theta\\ y=r\sin\theta\\ \end {aligned} \right. {x=rcosθy=rsinθ
(But计算量大,不可取)
中点画圆法
中点画圆基本思路
高效的画圆法必须避免三角函数计算和开方乘方计算,用构造函数
F
(
x
,
y
)
=
x
2
+
y
2
−
r
2
F(x,y)=x^2+y^2-r^2
F(x,y)=x2+y2−r2
{
F
(
x
,
y
)
=
0
(
圆
上
的
点
)
F
(
x
,
y
)
>
0
(
圆
外
的
点
)
F
(
x
,
y
)
<
0
(
圆
内
的
点
)
\left\{ \begin {aligned} F(x,y)=0(圆上的点)\\ F(x,y)>0(圆外的点)\\ F(x,y)<0(圆内的点)\\ \end {aligned} \right.
⎩⎪⎨⎪⎧F(x,y)=0(圆上的点)F(x,y)>0(圆外的点)F(x,y)<0(圆内的点)
选取衡量标准,判断下一点是在
(
x
i
+
1
,
y
i
)
(x_i+1,y_i)
(xi+1,yi)还是
(
x
i
+
1
,
y
i
−
1
)
(x_i+1,y_i-1)
(xi+1,yi−1),用
m
(
x
i
+
1
,
y
i
−
0.5
)
m(x_i+1,y_i-0.5)
m(xi+1,yi−0.5)代入得判别式:
d
=
F
(
x
m
,
y
m
)
=
F
(
x
i
+
1
,
y
i
−
0.5
)
=
(
x
i
+
1
)
2
+
(
y
i
−
0.5
)
2
−
R
2
\begin{aligned} d&=F(x_m,y_m)\\ &=F(x_i+1,y_i-0.5) \\ &=(x_i+1)^2+(y_i-0.5)^2-R^2 \end{aligned}
d=F(xm,ym)=F(xi+1,yi−0.5)=(xi+1)2+(yi−0.5)2−R2
-
d ≤ 0 d\leq0 d≤0时,下一点为 P u ( x i + 1 , y i ) P_u(x_i+1,y_i) Pu(xi+1,yi),而我们真正关心的是求出误差项的递推公式,下面来推导:
d n e w = F ( x i + 2 , y i − 0.5 ) = ( x i + 2 ) 2 + ( y i − 0.5 ) 2 − R 2 = ( x i + 1 ) 2 + ( y i − 0.5 ) 2 − R 2 + 2 x i + 3 = d o l d + 2 x i + 3 \begin{aligned} d_{new}&=F(x_i+2,y_i-0.5)\\ &=(x_i+2)^2+(y_i-0.5)^2-R^2\\ &=(x_i+1)^2+(y_i-0.5)^2-R^2+2x_i+3\\ &=d_{old}+2x_i+3 \end{aligned} dnew=F(xi+2,yi−0.5)=(xi+2)2+(yi−0.5)2−R2=(xi+1)2+(yi−0.5)2−R2+2xi+3=dold+2xi+3 -
同理, d > 0 d>0 d>0时:
d n e w = F ( x i + 2 , y i − 1.5 ) = ( x i + 2 ) 2 + ( y i − 1.5 ) 2 − R 2 = ( x i + 1 ) 2 + ( y i − 0.5 ) 2 − R 2 + ( 2 x i + 3 ) + ( 2 − 2 y i ) = d o l d + 2 ( x i − y i ) + 5 \begin{aligned} d_{new}&=F(x_i+2,y_i-1.5)\\ &=(x_i+2)^2+(y_i-1.5)^2-R^2\\ &=(x_i+1)^2+(y_i-0.5)^2-R^2+(2x_i+3)+(2-2y_i)\\ &=d_{old}+2(x_i-y_i)+5 \end{aligned} dnew=F(xi+2,yi−1.5)=(xi+2)2+(yi−1.5)2−R2=(xi+1)2+(yi−0.5)2−R2+(2xi+3)+(2−2yi)=dold+2(xi−yi)+5 -
这里讨论的是按顺时针方向生成第一个八分圆。则第一个象素是: ( 0 , r ) (0,r) (0,r),故得 d 0 d_0 d0:
d 0 = F ( 1 , R − 0.5 ) = 1 + ( R − 0.5 ) 2 − R 2 = 1.25 − R \begin{aligned} d_0&=F(1,R-0.5)\\&=1+(R-0.5)^2-R^2\\&=1.25-R \end{aligned} d0=F(1,R−0.5)=1+(R−0.5)2−R2=1.25−R
中点画圆改进
- 由于只用
d
d
d的正负,因此用
d
−
0.25
d-0.25
d−0.25代替
d
d
d 以摆脱小数,更新后的公式为:
{ d 0 = 1 − R d n e w = d o l d + 2 x i + 3 ( d ≤ 0 ) d n e w = d o l d + 2 ( x i − y i ) + 5 ( d > 0 ) \left\{ \begin{aligned} &d_0= 1-R\\ &d_{new}=d_{old}+2x_i+3(d\leq0) \\ &d_{new}=d_{old}+2(x_i-y_i)+5(d > 0) \end{aligned} \right. ⎩⎪⎨⎪⎧d0=1−Rdnew=dold+2xi+3(d≤0)dnew=dold+2(xi−yi)+5(d>0) - 这里研究的圆心都在
(
0
,
0
)
(0,0)
(0,0)点,画任一
(
x
c
,
y
c
)
(x_c,y_c)
(xc,yc)点即是分别向
x
,
y
x,y
x,y方向进行了平移。
缺点:有一点走样
Bresenham画圆算法
Bresenham基本思路
考虑
1
4
\frac{1}{4}
41 象限的四分圆,此处以第一象限为例,每一点的下一个象素有三种选择,正右方
(
H
)
(H)
(H),右下方
(
D
)
(D)
(D),正下方
(
V
)
(V)
(V)。观察发现以
D
D
D的位置作为讨论依据最为科学。
Bresenham上手计算
判断
D
D
D点(注意是与圆上的距离不是圆心的距离)的位置:
Δ
D
=
(
x
+
1
)
2
+
(
y
+
1
)
2
−
r
2
\Delta D=(x+1)^2+(y+1)^2-r^2
ΔD=(x+1)2+(y+1)2−r2
接着判断D与E,D与F和圆周的相对距离大小判断涂色:
- Δ D < 0 \Delta D<0 ΔD<0, D D D在圆内, δ H D = ∣ Δ H ∣ − ∣ Δ D ∣ = 2 Δ D + 2 y − 1 \delta HD=|\Delta H|-|\Delta D|=2\Delta D+2y-1 δHD=∣ΔH∣−∣ΔD∣=2ΔD+2y−1,若小于等于 0 0 0则选 H H H,大于 0 0 0则选 D D D。
- Δ D > 0 \Delta D>0 ΔD>0, D D D在圆外, δ D V = ∣ Δ D ∣ − ∣ Δ V ∣ = 2 ( Δ D − x ) − 1 \delta DV=|\Delta D|-|\Delta V|=2(\Delta D-x)-1 δDV=∣ΔD∣−∣ΔV∣=2(ΔD−x)−1,若小于等于 0 0 0则选 D D D,大于 0 0 0则选 V V V。
-
Δ
D
(
x
p
+
1
,
y
p
−
1
)
\Delta D(x_p+1,y_p-1)
ΔD(xp+1,yp−1)的初值为
Δ
D
=
1
+
(
1
−
r
)
2
−
r
2
=
2
−
2
r
\Delta D=1+(1-r)^2-r^2=2-2r
ΔD=1+(1−r)2−r2=2−2r
故公式为:
{ Δ D = 2 − 2 r δ H D = 2 Δ D + 2 y − 1 δ D V = 2 Δ D − 2 x − 1 Δ D < 0 { δ H D ≤ 0 ⇒ H 点 : Δ D n e w = Δ D o l d + 2 ( x + 1 ) + 1 δ H D > 0 ⇒ D 点 : Δ D n e w = Δ D o l d + 2 ( x + 1 ) − 2 ( y − 1 ) + 2 Δ D > 0 { δ H D ≤ 0 ⇒ D 点 : Δ D n e w = Δ D o l d + 2 ( x + 1 ) − 2 ( y − 1 ) + 2 δ H D > 0 ⇒ V 点 : Δ D n e w = Δ D o l d + 2 ( y − 1 ) + 1 Δ D = 0 ⇒ D 点 : Δ D n e w = Δ D o l d + 2 ( x + 1 ) − 2 ( y − 1 ) + 2 \left\{ \begin{aligned} &\Delta D=2-2r\\ &\delta HD=2\Delta D+2y-1 \\&\delta DV=2\Delta D-2x-1\\ &\Delta D<0 \left\{ \begin{aligned} &\delta HD\leq0\Rightarrow H点:\Delta D_{new}=\Delta D_{old}+2(x+1)+1 \\ &\delta HD>0\Rightarrow D点:\Delta D_{new}=\Delta D_{old}+2(x+1)-2(y-1)+2 \end{aligned} \right.\\ &\Delta D>0 \left\{ \begin{aligned} &\delta HD\leq0 \Rightarrow D点:\Delta D_{new}=\Delta D_{old}+2(x+1)-2(y-1)+2 \\ &\delta HD>0 \Rightarrow V点:\Delta D_{new}=\Delta D_{old}+2(y-1)+1 \end{aligned} \right.\\ &\Delta D=0\Rightarrow D点:\Delta D_{new}=\Delta D_{old}+2(x+1)-2(y-1)+2 \\ \end{aligned} \right. ⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧ΔD=2−2rδHD=2ΔD+2y−1δDV=2ΔD−2x−1ΔD<0{δHD≤0⇒H点:ΔDnew=ΔDold+2(x+1)+1δHD>0⇒D点:ΔDnew=ΔDold+2(x+1)−2(y−1)+2ΔD>0{δHD≤0⇒D点:ΔDnew=ΔDold+2(x+1)−2(y−1)+2δHD>0⇒V点:ΔDnew=ΔDold+2(y−1)+1ΔD=0⇒D点:ΔDnew=ΔDold+2(x+1)−2(y−1)+2 - 优点:每次在三个点中判断,走样较小,可以一次处理四分之一圆。
缺点:算法复杂。
如何画椭圆
开动脑筋,进行类比~
类同于中点画圆法,区别是画第一象限的四分之一椭圆弧,关键是找到临界点。
椭圆实操
找到切线斜率为
1
1
1的点
p
(
x
p
,
y
p
)
p(x_p,y_p)
p(xp,yp),利用中点画线法进行处理:
{
x
p
=
a
2
a
2
+
b
2
y
p
=
b
2
a
2
+
b
2
\left\{ \begin{aligned} &x_p= \frac{a^2}{\sqrt{a^2+b^2}}\\ &y_p= \frac{b^2}{\sqrt{a^2+b^2}} \end{aligned} \right.
⎩⎪⎪⎪⎨⎪⎪⎪⎧xp=a2+b2a2yp=a2+b2b2
将
1
4
\frac{1}{4}
41椭圆分成
(
0
,
b
)
(0,b)
(0,b)到
p
p
p点,
(
a
,
0
)
(a,0)
(a,0)到
p
p
p点两块,故公式为:
{
(
0
,
b
)
到
p
点
:
{
d
0
=
b
2
+
(
−
b
+
0.25
)
a
2
d
n
e
w
=
d
o
l
d
+
(
2
x
+
3
)
b
2
(
d
≤
0
)
d
n
e
w
=
d
o
l
d
+
(
2
x
+
3
)
b
2
+
(
2
−
2
y
)
a
2
(
d
>
0
)
(
a
,
0
)
到
p
点
:
{
d
0
=
(
−
a
+
0.25
)
b
2
+
a
2
d
n
e
w
=
d
o
l
d
+
(
2
y
+
3
)
a
2
(
d
≤
0
)
d
n
e
w
=
d
o
l
d
+
(
2
y
+
3
)
a
2
+
(
2
−
2
x
)
b
2
(
d
>
0
)
\left\{ \begin{aligned} &(0,b)到p点: \left\{ \begin{aligned} &d_0=b^2+(-b+0.25)a^2\\ &d_{new}=d_{old}+(2x+3)b^2(d\leq0)\\ &d_{new}=d_{old}+(2x+3)b^2+(2-2y)a^2(d>0) \end{aligned} \right.\\ &(a,0)到p点: \left\{ \begin{aligned} &d_0=(-a+0.25)b^2+a^2\\ &d_{new}=d_{old}+(2y+3)a^2(d\leq0)\\ &d_{new}=d_{old}+(2y+3)a^2+(2-2x)b^2(d>0) \end{aligned} \right. \end{aligned} \right.
⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧(0,b)到p点:⎩⎪⎨⎪⎧d0=b2+(−b+0.25)a2dnew=dold+(2x+3)b2(d≤0)dnew=dold+(2x+3)b2+(2−2y)a2(d>0)(a,0)到p点:⎩⎪⎨⎪⎧d0=(−a+0.25)b2+a2dnew=dold+(2y+3)a2(d≤0)dnew=dold+(2y+3)a2+(2−2x)b2(d>0)
线型处理
线画图元的基本属性有线型、宽度和颜色。
线宽处理
线刷子
- 当斜率 k ∈ [ − 1 , 1 ] k∈[-1,1] k∈[−1,1]之间,刷子置成垂直方向(水平方向刷),刷子的中点对准直线一端点,然后让刷子中心往直线的另一端移动,即可刷出具有一定宽度的线。
- 同理,当斜率
k
∉
[
−
1
,
1
]
k\notin [-1,1]
k∈/[−1,1]之间时,把刷子置成水平方向(竖直方向刷)。
-
引起的问题:汇合外角缺口
改进
加圆帽,通过对每个方帽添加一个填充的半圆而得到。圆弧的圆心在线的端点其直径与线宽度相等。
方形刷子
把边宽为指定线宽的正方形的中心沿直线作平行移动,用方形刷子绘制的线条比用线刷子绘制的要粗一些(对角线的原因)。
线刷子与方形刷子的对比:
- 线刷子在45°角附近线条在水平和垂直方向之间切换,最细
- 方形刷子正相反由于线宽正好为对角线而显著变粗
超链接
如果你还想了解其他内容:
小白谈计算机图形学(一)如何画线
小白谈计算机图形学(二)如何画圆
小白谈计算机图形学(三)二维图形裁剪
小白谈计算机图形学(四)二维三维图形变换—1