DRAW2.C
[目次 | 関数]
1|/**************************************************************************
2| 1. <<< 描画アルゴリズム (Draw2) >>>
3|***************************************************************************/
4|
5|#include "mixer_precomp.h"
6|// #pragma hdrstop ("mixer_precomp")
7|
8|#ifdef USES_MXP_AUTOINC
9| #include <Draw2.ah> /* Auto include header, Look at mixer-... folder */
10|#endif
11|
12|
13|
14|/*---------------------------------------------------------------------*/
15|/* 2. <<<◆(Draw2) 描画アルゴリズム >>> */
16|/*---------------------------------------------------------------------*/
17|
18|
19|/***********************************************************************
20| 3. <<< [Draw2_circle] 円を描画する >>>
21|【引数】
22| ・void* obj; pset コールバック関数の第1引数に渡す値
23| ・Draw2_psetCirF obj_pset8; 描画する座標を渡すコールバック関数(描画関数)
24| ・int cx, cy; 円の中心座標
25| ・int r; 半径
26|【補足】
27|・obj_pset8 は、円の1/8の点の数だけ呼ばれます。1回呼ばれるたびに、
28| すべての 1/8 の弧を描画するようにしてください。
29|【内部補足】
30|・ミッチェナー(Michener) のアルゴリズムの説明:
31| 中心が(0,0) の円を考える。
32| 中心から描画する点0(x,y) との距離と半径 r との差 E' は、式(1)。
33| 図のように円を1/8に区切って考え、円の右から下方向へ進む場合、
34| 次に描画する点は点1(x,y+1) か点2(x-1,y+1) のケースしかなく、
35| その中で、差 E' が小さい方を採用する。
36| 差の大小が採用基準になるので、2乗の距離の差 E、式(2)で計算する。
37| 2乗の距離の差 E に点0、点1、点2を代入すると式(3)。
38| 2乗の距離の差が小さい方を判定するには、式(4)のように、
39| 絶対値の差が0より大きいか小さいかで判定する。
40| 絶対値があるので、点0〜2の位置関係は図(a),(b),(c)によって場合分け。
41| (b)の場合、式(4)のようになる。
42| (a)の場合、F0 は常に0以下、(c)の場合、F0 は常に0以上なので、
43| どの場合でも F の式が使える。
44| F より、点(x,y)から判定式を使って次の点を決めることができる。
45| ただし、まだ掛け算が多いので、F が変化する様子を考える。
46| (5)は、点0(x,y) の判定式 F0 を使って、
47| 点1から次の点を決めるときの判定式 F1、(掛け算は1個)
48| 点2から次の点を決めるときの判定式 F2。(掛け算は2個)
49| これより、x,y から次の Fn を求めて次の点を次々に決めていくことができる。
50| 斜め45度(x < y)になったら、ループを止める。
51|
52|************************************************************************/
53|void Draw2_circle( void* obj, Draw2_psetCirF obj_pset8, int cx, int cy, int r )
54|{
55| int x = r; /* 中心を(0,0)とした座標の、弧上の点 X座標 */
56| int y = 0; /* 中心を(0,0)とした座標の、弧上の点 Y座標 */
57| int f = -2*r+3; /* 判定式の値、式(4), (r,0) より */
58|
59| ASSERT( r > 0 );
60|
61| while ( x >= y ) {
62|
63| obj_pset8( obj, cx, cy, y, x );
64|
65| if ( f > 0 ) { /* (x-1,y+1) の半径誤差 E2 の方が小さいとき */
66| f += -4*x +4*y +10; /* 式(5) F2 */
67| x--;
68| }
69| else { /* (x-1,y+1) の半径誤差 E1 の方が小さいとき */
70| f += 4*y +6; /* 式(5) F1 */
71| }
72|
73| y++;
74| }
75|}
76|
77|
78|
79|/***********************************************************************
80| 4. <<< [Draw2_ellipse] 楕円を描画する >>>
81|【引数】
82| ・void* obj; pset コールバック関数の第1引数に渡す値
83| ・Draw2_psetCirF obj_pset4; 描画する座標を渡すコールバック関数(描画関数)
84| ・int cx, cy; 円の中心座標
85| ・int a, b; 中心を通る水平線a・垂直線bの長さ/2(半径に相当)
86|【内部補足】
87|・楕円のアルゴリズムは次のとおり。
88| 縦長の楕円の場合、横に b/a(=ry/rx) 倍すれば円になるので、弧上のピクセルからの
89| 誤差 E' は、式(2)のようになります。横長の場合は E'' です。
90| 誤差の絶対値の大小で比較するので、正の数で定数倍してもよく、
91| その結果、どちらの場合でも誤差 E の式で表せる。
92| 楕円の場合、(1/8 の対称性ではなく)1/4 で対称性があるため、y++ に対し、
93| x が 1以上で増える可能性がある。そのため、赤い弧と緑の弧で
94| 両方向から走査する必要がある。それぞれの方向について、
95| (3),(4),(5) は、円と同じ方法で導かれる。
96|
97| ただし、赤い弧と緑の弧を分ける点は、x 軸との角度が 45°になる楕円の接線
98| の接点である。その接点は、次の補助直線 s によって求めることができる。
99| (6)は、楕円の接線方程式の一般式である。(7)は、それを y について
100| 変形したもの。(8)は、(7)より 45°になる条件式。(9)は、(8)を y1 について
101| 変形したもの。特に、x1>0, y1>0 のときは (10) となる。
102| つまり、式(10)を満たしたら、赤または緑の弧の描画を終了する。
103|
104|************************************************************************/
105|void Draw2_ellipse( void* obj, Draw2_psetCirF obj_pset4, int cx, int cy,
106| int a, int b )
107|{
108| int x; /* 中心を(0,0)とした座標の、弧上の点 X座標 */
109| int y; /* 中心を(0,0)とした座標の、弧上の点 Y座標 */
110| int f; /* 判定式の値、式(4) より */
111| int over; /* ループ変数の最終値 */
112| int a2 = a*a;
113| int b2 = b*b;
114|
115| if ( a == 0 || b == 0 ) return;
116|
117| ASSERT( a > 0 && b > 0 );
118|
119| /* at Red Line */
120| x = a;
121| y = 0;
122| f = b2*(-2*x +1) + 2*a2; /* 式(4), (a,0) より */
123| over = x*b2/a2; /* y の最終値、x によって変化する */
124|
125| while ( y <= over ) {
126|
127| obj_pset4( obj, cx, cy, x, y );
128| if ( f > 0 ) {
129| f += b2*(-4*x +4)+a2*(4*y +6); /* 式(5) F2 */
130| x--;
131| over = x*b2/a2;
132| }
133| else {
134| f += a2*(4*y +6); /* 式(5) F1 */
135| }
136| y++;
137| }
138|
139| /* at Green Line */
140| x = 0;
141| y = b;
142| f = 2*b2 + a2*(-2*y +1); /* 式(4), (0,b) より */
143| over = y*a2/b2; /* x の最終値、y によって変化する */
144|
145| while ( x <= over ) {
146|
147| obj_pset4( obj, cx, cy, x, y );
148|
149| if ( f > 0 ) {
150| f += b2*(4*x +6)+a2*(-4*y +4); /* 式(5) F2 */
151| y--;
152| over = y*a2/b2;
153| }
154| else {
155| f += b2*(4*x +6); /* 式(5) F1 */
156| }
157| x++;
158| }
159|}
160|
161|