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

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

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

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

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

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

円を描画する

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

円を描画する考え方

「円内の座標に点を描画する」のが円の描画の考え方です。

つまり、円の原点からの距離が円の半径以内である座標に点を描画していきます。では具体的にその座標はどの座標になるのでしょうか?ここについて解説していきます。

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

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

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

円の方程式の説明図1

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

円の方程式の説明図2

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

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

スポンサーリンク

円を描画する関数

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

円を描画する関数
void drawCircle(
  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の呼び出し
  drawCircle(
    bitmap.data,
    bitmap.width,
    bitmap.height,
    100,
    500, 300,
    0xFF, 0x00, 0x00
  );
main 関数について

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

C言語で図形を描画する

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

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

円の描画結果

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

円の描画結果

楕円を描画する

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

スポンサーリンク

楕円を描画する考え方

楕円の描画の考え方も、基本的には円の描画と同じです。要は、楕円の内側に存在する座標に点を描画します。

下図のような、座標 (0, 0) を中心とし、x 軸上の楕円の線までの距離を rxy 軸上の楕円の線までの距離を ry とした楕円について考えてみましょう(この距離 rxry は便宜上 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 軸方向の半径を rxy 軸方向の半径を 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 軸上の半径を 200y 軸上の半径を 100 の楕円を描画するためには下記のように drawEllipse 関数を実行します。第4引数と第5引数で x 軸上の半径と y 軸上の半径を、第5引数と第6引数で楕円の中心座標を指定しています。

drawEllipseの呼び出し
  drawEllipse(
    bitmap.data,
    bitmap.width,
    bitmap.height,
    200, 100,
    500, 250,
    0xFF, 0x00, 0x00
  );

楕円の描画結果

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

楕円の描画結果

スポンサーリンク

まとめ

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

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

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

コメントを残す

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