C言語で円と楕円を描画する

円と楕円描画の解説ページのアイキャッチ

このページではC言語で「円」や「楕円」を描画する方法について解説します。

円を描画するために必要な「ビットマップデータ」や「点の描画方法」については下のページで解説していますので、まだ読んでない方は事前に下のページを読むことをオススメします。

図形描画の解説ページのアイキャッチC言語で図形を描画する

円の描画も結局は線の描画同様に「点」の描画を円の形になるよう座標を制御してに実行するだけです。ですので、特に点の描画については上のページで理解しておいていただけると本ページの内容も理解しやすくなると思います。

円を描画する

まずは「円」を描画します。点の描画さえできれば、円の方程式を使えば簡単に描画可能です!

円を描画する考え方

ある座標 (x, y) が座標 (x1, y1) を中心とした半径 radius の円上に存在するかどうかは下記の式で判断することが可能です。習ったことのある方なら懐かしさを感じるかもしれません。円の方程式というやつです。

(x - x1) * (x - x1) + (y - y1) * (y - y1) = radius * radius

両辺の平方根を計算した場合、左辺では座標 (x, y) と円の中心座標 (x1, y1) との距離が計算されていることになります。その距離が半径 radius と一致する(つまり円の方程式が成り立つ)ということは、中心座標 (x1, y1)、半径 radius とした円上に存在するということになります。

円の方程式の説明図1

またその距離が半径よりも小さい場合は、その座標 (x, y) は円の内側に存在すると言えます。

円の方程式の説明図2

つまり、ビットマップデータ上の全座標 (x, y) に対して下の式が成立するかどうかを確認し、成立する場合にその座標に点を描画することを繰り返せば、内側に色を塗った円を描画することができます。

(x - x1) * (x - x1) + (y - y1) * (y - y1) <= radius * radius

スポンサーリンク

円を描画する関数

円を描画する関数は下記のようになります。

  unsigned char *data, /* ビットマップデータ */
  unsigned int width, /* ビットマップの横幅 */
  unsigned int height, /* ビットマップの高さ */
  unsigned int radius, /* 円の半径 */
  unsigned int x1, /* 始点のx座標 */
  unsigned int y1, /* 始点のy座標 */
  unsigned char r, /* 赤の輝度値 */
  unsigned char g, /* 青の輝度値 */
  unsigned char b /* 緑の輝度値 */
){
  unsigned int x, y;
  int dx, dy;
  unsigned char *p;
  
  for(y = 0; y < height; y++){
    for(x = 0; x < width; x++){
      /* 始点と(x, y)座標の距離を計算 */
      dx = (int)x - (int)x1;
      dy = (int)y - (int)y1;

      /* 円を描画 */
      if((dx * dx) + (dy * dy) <= radius * radius){
        p = data + y * width * 3 + x * 3;
        p[0] = r;
        p[1] = g;
        p[2] = b;
      }
    }
  }
}

例えば、中心座標を (500, 300) とした半径 100 の円を描画するためには下記のように drawCircle 関数を実行します。第4引数で半径を、第5引数と第6引数で中心座標を指定しています。

  drawCircle(
    bitmap.data,
    bitmap.width,
    bitmap.height,
    100,
    500, 300,
    0xFF, 0x00, 0x00
  );
main 関数について

上記の drawCircle 関数のように、このページに載せている関数は、下記ページで紹介した main 関数から呼び出すのがオススメです。

C言語で図形を描画する

libpng をインストールすれば PNG 出力して画像のプレビューも簡単にできます。

このページで紹介する描画結果も上記の main 関数で出力した outpnt.png をプレビューしたものになります。

円の描画結果

上記のように drawCircle を呼び出した際に出力される output.png は下のようになります。

円の描画結果

楕円を描画する

次は「楕円」を描画します。こちらも楕円の方程式を用いれば描画できます。

スポンサーリンク

楕円を描画する考え方

下図のような座標 (0, 0) を中心とし、x 軸上の楕円の線までの距離を rx 、y 軸上の楕円の線までの距離をry について考えてみましょう(この距離 rx と ry は便宜上 x 軸上の半径と y 軸上の半径と呼ばせていただきます)。

原点を中心とした時の楕円の説明図

この時、下記式を満たす座標 (x, y) は、楕円上に存在することになります(楕円の方程式)。

(x * x) / (rx * rx) + (y * y) / (ry * ry) = 1

さらに、楕円の中心を下の図のように (x1, y1) に移動させてみましょう。

原点を座標(x1,y1)を中心とした時の楕円の説明図

この時、下記式を満たす座標 (x, y) は、中心を座標 (x1, y1) とした楕円上に存在することになります。

(x - x1) * (x - x1) / (rx * rx) + (y - y1) * (y - y1) / (ry * ry) = 1

さらに、下記式を満たす座標 (x, y) は中心を座標 (x1, y1) とした楕円内に存在することになります。

(x - x1) * (x - x1) / (rx * rx) + (y - y1) * (y - y1) / (ry * ry) <= 1

つまり、中心を座標 (x1, y1)、x 軸方向の半径を rx 、y 軸方向の半径を ry とした楕円を描画(内側は塗りつぶし)するためには、ビットマップデータ上の全座標 (x, y) に対して上の式が成立するかどうかを確認し、成立する場合にその座標に点を描画すれば良いです。

楕円を描画する関数

楕円を描画する関数は下記のようになります。

void drawEllipse(
  unsigned char *data, /* ビットマップデータ */
  unsigned int width, /* ビットマップの横幅 */
  unsigned int height, /* ビットマップの高さ */
  unsigned int rx, /* x軸状の楕円の半径 */
  unsigned int ry, /* y軸状の楕円の半径 */
  unsigned int x1, /* 始点のx座標 */
  unsigned int y1, /* 始点のy座標 */
  unsigned char r, /* 赤の輝度値 */
  unsigned char g, /* 青の輝度値 */
  unsigned char b /* 緑の輝度値 */
){
  unsigned int x, y;
  int dx, dy;
  unsigned char *p;
  
  for(y = 0; y < height; y++){
    for(x = 0; x < width; x++){
      /* 始点と(x, y)座標の距離を計算 */
      dx = (int)x - (int)x1;
      dy = (int)y - (int)y1;

      /* 楕円を描画 */
      if((double)(dx * dx) / (double)(rx * rx) + (double)(dy * dy) / (double)(ry * ry) <= 1){
        p = data + y * width * 3 + x * 3;
        p[0] = r;
        p[1] = g;
        p[2] = b;
      }
    }
  }
}

例えば、中心座標を (500, 250) 、x 軸上の半径を 200 、y 軸上の半径を 100 の楕円を描画するためには下記のように drawEllipse 関数を実行します。第4引数と第5引数で x 軸上の半径と y 軸上の半径を、第5引数と第6引数で中心座標を指定しています。

  drawEllipse(
    bitmap.data,
    bitmap.width,
    bitmap.height,
    200, 100,
    500, 250,
    0xFF, 0x00, 0x00
  );

楕円の描画結果

上記のように drawEllipse 関数を呼び出した時に出力される output.png は下のようになります。

楕円の描画結果

スポンサーリンク

まとめ

このページでは円と楕円を描画する方法の解説と円を描画する関数、楕円を描画する関数の紹介を行いました。

昔ならった無理やり覚えた円の方程式や楕円の方程式も、プログラミングで実際に円や楕円を描画してみると、楽しみながら方程式を理解できたのではないかと思います。

図形を描画したりするためには数学的要素が必要だったりしますが、プログラミングで実際に図形を描画するとすぐに結果が確認できて楽しいですし、数学についての理解も進んでオススメですよ!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です