平面解析ジオメトリでは、円の方程式は(x – x 0)2 +(y – y 0)2 = R 2として記述できます。ここで、(x 0、y 0)は円の中心の座標、Rは円の半径です。はい、(x 0、y 0)が座標の中心点である場合、円の方程式はx 2 + y 2 = R 2に簡略化できます。コンピュータグラフィックスでは、直線のような円にもドットマトリックス出力デバイスでの表示または出力の問題があるため、一連のラスタースキャン変換アルゴリズムも必要です。簡単のため、まず原点を中心とする円の生成を考えますが、中心を原点としない円の場合、対応する位置の円は座標の並進変換により求めることができます。
変換をスキャンする前に、円、つまり8番目の円のペアの特性を理解する必要があります。図1に示すように:
図(1)円の8番目の対称性
原点を中心とする円には、4つの対称軸x = 0、y = 0、x = y、x = -yがあります。円弧上の点P(x、y)がわかっている場合、4つの対称軸の7つを取得できます。対称点:(x、-y)、(-x、y)、(-x、-y)、(y、x)、(y、-x)、(-y、x)、(-y、 -x)、このプロパティは8番目の対称性と呼ばれます。したがって、円弧の1/8を描くことができれば、対称性の原理を使用して円全体を取得できます。
円のスキャン変換を取得する簡単な方法がいくつかあります。最初に、直交座標法を導入します。円の方程式x 2 + y 2 = R 2が与えられた場合、xが独立変数として取られ、yが解かれると、次のようになります。
y =
円を生成する場合、最初に円の4分の1をスキャンして変換し、独立変数xを0からRに単位ステップで増加させ、各ステップでyを解いてから、点描画関数を呼び出して円を点ごとに描画します。しかし、そうすることで、ベキ演算と平方根演算、および両方とも浮動小数点演算であるため、アルゴリズムの効率は高くありません。また、xがRの値に近い場合(円の中心は原点にあります)、円周上の点(R、0)の近くでは、円の勾配が無限大になる傾向があるため、浮動小数点数を切り上げて円を大きくする必要がありますギャップ。次に、極座標法を紹介します。点P(x、y)と直交座標系の円弧上のx軸の間の角度をθとすると、円の極座標方程式は次のようになります。
x =Rcosθ
y =Rsinθ
生成された円は、円の8番目の対称性を使用するため、独立変数θの値の範囲は(0、45°)であり、完全な円を描画します。この方法は、三角関数の計算と乗算を含み、大量の計算を必要とします。直交座標法と極座標法はどちらも非効率的なアルゴリズムであるため、理論的な方法としてのみ存在し、これら2つの方法は、基本的にコンピュータグラフィックスで円を生成するために使用されません。以下は、コンピュータグラフィックスにおけるいくつかの実用的な円生成アルゴリズムを紹介しています。
1.中点円法
1つ目は、中点に円を描く方法です。原点の円の中心と、点(0、R)から点(R /、R /)まで時計回りに決定される、第1象限の半径Rの円の1/8の円弧を考えます。この弧。点P I(X I、Y I)が実際の円弧に最も近い円弧上の点であるとすると、次の点Piは、右下の右にあるP1またはP2のどちらかにある可能性があります。図(2)は以下を示しています。
図(2)一点鎖線法の例
判別関数を作成します。
F(x、y)= x 2 + y 2 – R 2
F(x、y)= 0の場合、ポイントは円上にあることを意味します。F(x、y)> 0の場合、ポイントは円の外側にあります。F(x、y)<0の場合、ポイントは円の内側にあります。MがP 1とP 2の中点である場合、M の座標は(x i + 1、y i – 0.5)です。F(x i + 1、y i – 0.5)<0の場合、ポイントMは円内にあります内側では、P 1は実際の円弧に近く、P 1を円の次の点と見なす必要があります。分析同様に、F(X I + 1、Y。I - 0.5)> 0、P 2は、近い実際の円弧にP取るべき2次ポイントとして。F(x i + 1、y i – 0.5)= 0の場合、P 1とP 2の両方を円の次の点として使用でき、アルゴリズムはP 2を次の点と見なすことに同意します。
现在将M点坐标(xi + 1, yi – 0.5)带入判别函数F(x, y),得到判别式d:
d = F(xi + 1, yi – 0.5)= (xi + 1)2 + (yi – 0.5)2 – R2
若d < 0,则取P1为下一个点,此时P1的下一个点的判别式为:
d’ = F(xi + 2, yi – 0.5)= (xi + 2)2 + (yi – 0.5)2 – R2
展开后将d带入可得到判别式的递推关系:
d’ = d + 2xi + 3
若d > 0,则取P2为下一个点,此时P2的下一个点的判别式为:
d’ = F(xi + 2, yi – 1.5)= (xi + 2)2 + (yi – 1.5)2 – R2
展开后将d带入可得到判别式的递推关系:
d’ = d + 2(xi - yi) + 5
特别的,在第一个象限的第一个点(0, R)时,可以推倒出判别式d的初始值d0:
d0 = F(1, R – 0.5) = 1 – (R – 0.5)2 – R2 = 1.25 - R
根据上面的分析,可以写出中点画圆法的算法。考虑到圆心不在原点的情况,需要对计算出来的坐标进行了平移,下面就是通用的中点画圆法的源代码:
26 void MP_Circle(int xc , int yc , int r) 27 { 28 int x, y; 29 double d; 30 31 x = 0; 32 y = r; 33 d = 1.25 - r; 34 CirclePlot(xc , yc , x , y); 35 while(x < y) 36 { 37 if(d < 0) 38 { 39 d = d + 2 * x + 3; 40 } 41 else 42 { 43 d = d + 2 * ( x - y ) + 5; 44 y--; 45 } 46 x++; 47 CirclePlot(xc , yc , x , y); 48 } 49 } |
参数xc和yc是圆心坐标,r是半径,CirclePlot()函数是参照圆的八分对称性完成八个点的位置计算的辅助函数。
2、 改进的中点画圆法-Bresenham算法
中点画圆法中,计算判别式d使用了浮点运算,影响了圆的生成效率。如果能将判别式规约到整数运算,则可以简化计算,提高效率。于是人们针对中点画圆法进行了多种改进,其中一种方式是将d的初始值由1.25 – R改成1 – R,考虑到圆的半径R总是大于2,因此这个修改不会响d的初始值的符号,同时可以避免浮点运算。还有一种方法是将d的计算放大两倍,同时将初始值改成3 – 2R,这样避免了浮点运算,乘二运算也可以用移位快速代替,采用3 – 2R为初始值的改进算法,又称为Bresenham算法:
52 void Bresenham_Circle(int xc , int yc , int r) 53 { 54 int x, y, d; 55 56 x = 0; 57 y = r; 58 d = 3 - 2 * r; 59 CirclePlot(xc , yc , x , y); 60 while(x < y) 61 { 62 if(d < 0) 63 { 64 d = d + 4 * x + 6; 65 } 66 else 67 { 68 d = d + 4 * ( x - y ) + 10; 69 y--; 70 } 71 x++; 72 CirclePlot(xc , yc , x , y); 73 } 74 } |
3、 正负判定画圆法
除了中点画圆算法,还有一种画圆算法也是利用当前点产生的圆函数进行符号判别,利用负反馈调整以决定下一个点的产生来直接生成圆弧,就是正负法,下面就介绍一下正负法的算法实现。
正负法根据圆函数:F(x, y)= x2 + y2 – R2的值,将平面区域分成圆内和圆外,如图(3)所示:
图(3)正负法判定示意图
假设圆弧的生成方向是从A到B方向,当某个点Pi被确定以后,Pi的下一个点Pi+1的取值就根据F(xi, yi)的值进行判定,判定的原则是:
1、当F(xi, yi)≤ 0时:取xi+1 = xi+1,yi+1 = yi。即向右走一步,从圆内走向圆外。对应图(3-a)中的从Pi到Pi+1。
2、当F(xi, yi)> 0时:取xi+1 = xi,yi+1 = yi - 1。即向下走一步,从圆外走向圆内。对应图(3-b)中的从Pi到Pi+1。
由于下一个点的取向到底是向圆内走还是向圆外走取决于F(xi, yi)的正负,因此称为正负法。对于判别式F(xi, yi)的递推公式,也要分两种情况分别推算:
1、当F(xi, yi)≤ 0时,Pi的下一个点Pi+1取xi+1 = xi+1,yi+1 = yi,判别式F(xi+1, yi+1)的推算过程是:
F(xi+1, yi+1)= F(xi+1,yi) = (xi+1)2+yi2-R2 = (xi2+yi2-R2)+2xi+1 = F(xi,yi)+2xi+1
2、当F(xi, yi)> 0时,Pi的下一个点Pi+1取xi+1 = xi,yi+1 = yi - 1,判别式F(xi+1, yi+1)的推算过程是:
F(xi+1, yi+1)= F(xi,yi-1) = xi2+(yi-1)2 - R2 = (xi2+yi2-R2) - 2yi + 1 = F(xi,yi) - 2yi+1
设画圆的初始点是(0,R),判定式的初始值是0,正负法生成圆的算法如下:
105 void Pnar_Circle(int xc, int yc, int r) 106 { 107 int x, y, f; 108 109 x = 0; 110 y = r; 111 f = 0; 112 while(x <= y) 113 { 114 CirclePlot(xc, yc, x, y); 115 if(f <= 0) 116 { 117 f = f + 2 * x + 1; 118 x++; 119 } 120 else 121 { 122 f = f - 2 * y + 1; 123 y--; 124 } 125 } 126 } |
改进的中点划线算法和正负法虽然都避免了浮点运算,并且计算判别式时用到的乘法都是乘2运算,可以用移位代替,但是实际效率缺有很大差别。因为正负法并不是严格按照x方向步进的,因此就会出现在某个点的下一个点在两个位置上重复画点的问题,增加了不必要的计算。此外,从生成圆的质量看,中点画圆法和改进的中点画圆法都比正负法效果好。
4、 快速画圆法
除了中点画圆法和正负法,本文再介绍一种圆的光栅扫描算法,就是快速画圆法。快速画圆法的生成效果和中点画圆法差不多,但是判别式的计算只用了加减法,没有用任何乘法,因此被成为快速画圆法。我找不到快速画圆法的理论依据,只是把算法的实现写出来,供有兴趣的读者参考。以下就是快速画圆法的实现算法:
128 void Fast_Circle(int xc , int yc , int r) 129 { 130 int x, y, d; 131 132 x = 0; 133 y = r; 134 d = -r / 2; 135 CirclePlot(xc , yc , x , y); 136 if(r % 2 == 0) 137 { 138 while(x < y) 139 { 140 x++; 141 if(d < 0) 142 d += x; 143 else 144 { 145 y--; 146 d += x - y; 147 } 148 149 CirclePlot(xc , yc , x , y); 150 } 151 } 152 else 153 { 154 while(x < y) 155 { 156 x++; 157 if(d < 0) 158 d += x + 1; 159 else 160 { 161 y--; 162 d += x - y + 1; 163 } 164 165 CirclePlot(xc , yc , x , y); 166 } 167 } 168 } |
ラウンドラスタースキャン変換アルゴリズムは多数あります。この記事で紹介するものはシンプルで理解しやすいものです。この記事で紹介するいくつかの方法に加えて、ポリゴン近似アルゴリズムなど、多くのラウンドラスター変換アルゴリズムもあります。読者は、コンピュータグラフィックスを参照して、アルゴリズムの実現を研究できます。
参考資料:
[1]計算幾何学:アルゴリズムの設計と分析Zhou Peide、清華大学出版局、2005年
[2]計算幾何学:アルゴリズムとアプリケーションDe Berger(Deng Junhui訳)清華大学出版局、2005年
[3]コンピュータグラフィックスSun Jiaguang、Yang Changgui、清華大学出版局、1995