スポンサーリンク

円を描くアルゴリズム(1)

簡単に言うと、あるピクセルを描画した後、次に描画するピクセルはどれかを計算する。これを繰り返して円にする。

この時、例えば円を時計回りで描くなら、あるx,yを描画したら、次の候補は(x-1,y),(x-1,y+1),(x,y+1)のいずれかになる。

どれが正解かというと、中心からの距離が半径に最も近いものが答えとなる。

これが4パターンあり、x,yがそれぞれ前進する場合と後進する場合に分けられる。以下の図の■が現在描いているドット、□は次に描くドットの候補。

ソースコード(1/4)

1/4だけ描画するコード

#pragma warning(disable:4996)

#include <iostream>

#include <vector>

//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む
//! @param [in] fname ファイル名
//! @param [in] vmax 全てのRGBの中の最大値
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void pnmP3_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII

  FILE* fp = fopen(fname, "wb");
  fprintf(fp, "P3\n%d %d\n%d\n", width, height, 255);

  size_t k = 0;
  for (size_t i = 0; i < (size_t)height; i++) {
    for (size_t j = 0; j < (size_t)width; j++) {
      fprintf(fp, "%d %d %d ", p[k], p[k], p[k]);
      k++;
    }
    fprintf(fp, "\n");
  }

  fclose(fp);
}




int width = 500;
int height = 500;
std::vector<unsigned char> img;

void plot(int x, int y) {
  img[y * width + x] = 255;
}

int main()
{
  img.resize(width * height);

  // 中心
  int cx = 250;
  int cy = 250;

  //半径
  int r = 50;
  const int rr = r * r;//半径の二乗

  int x, y;//描画位置
  //初期位置
  x = r;
  y = 0;

  //最初の一点
  plot(x + cx, y + cy);

  //反時計回りに描画していく(1/4)
  // 右下
  // □□
  // □■
  while (x > 0) {

    /////////////////////////
    // 次に描画するポイントを決定

    //次に描画するのは以下のいずれか。
    //1 { x - 1,y     };
    //2 { x - 1,y + 1 };
    //3 { x    ,y + 1 };
    int xy1 = pow(x - 1, 2) + pow(y, 2);
    int xy2 = pow(x - 1, 2) + pow(y + 1, 2);
    int xy3 = pow(x, 2) + pow(y + 1, 2);

    // x*x + y*y == r*rなので
    // 上記各xyのうち最もr*rとの差が少ないx*x+y*yを選択
    xy1 = abs(xy1 - rr);
    xy2 = abs(xy2 - rr);
    xy3 = abs(xy3 - rr);

    if (xy1 < xy2) {
      if (xy1 < xy3) {
        // xy1
        x = x - 1;
        y = y;
      }
      else {
        // xy2
        x = x - 1;
        y = y + 1;
      }
    }
    else {
      if (xy2 < xy3) {
        // xy2
        x = x - 1;
        y = y + 1;
      }
      else {
        // xy3
        x = x;
        y = y + 1;
      }
    }

    /////////////////////////
    // 描画
    plot(x + cx, y + cy);

  }


  pnmP3_Write("a.pgm", width, height, img.data());


}

コメントを残す

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

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: