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|