前回の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); } struct Image { std::vector<unsigned char> img; int width; int height; }; void resize(Image* img, int w, int h) { img->width = w; img->height = h; img->img.resize(w * h); } //! @brief 画像のピクセルを着色する //! @param [in,out] img 画像 //! @param [in] x 座標 //! @param [in] y 座標 //! @return なし void plot(Image& img, int x, int y) { img.img[y * img.width + x] = 255; } enum class CPOS { left,right,top,bottom };
//! @brief 円の指定した1/4を描画する //! @param [out] img 画像 //! @param [in] cx 中心座標 //! @param [in] cy 中心座標 //! @param [in] r 半径 //! @param [in] bx 円の四分割したエリアの指定 //! @param [in] by 円の四分割したエリアの指定 //! @return なし void calc(Image& img, const int cx, const int cy, const int r, const CPOS bx, const CPOS by) { int x, y;//描画位置 const int rr = r * r;//半径の二乗 int dx, dy; int limx; int limy; if (bx==CPOS::right && by==CPOS::bottom) { // □□ // □■ //初期位置 x = r; y = 0; dx = -1; dy = +1; limx = 0; limy = r; } else if (bx == CPOS::left && by == CPOS::bottom) { // □□ // ■□ x = 0; y = r; dx = -1; dy = -1; limx = -r; limy = 0; } else if (bx == CPOS::left && by == CPOS::top) { // ■□ // □□ x = -r; y = 0; dx = +1; dy = -1; limx = 0; limy = -r; } else if (bx == CPOS::right && by == CPOS::top) { // □■ // □□ x = 0; y = -r; dx = +1; dy = +1; limx = r; limy = 0; } //最初の一点 //plot(img,x + cx, y + cy); while ((x != limx) || (y != limy)) { ///////////////////////// // 次に描画するポイントを決定 //次に描画するのは以下のいずれか。 int xy1 = pow(x + dx, 2) + pow(y , 2); int xy2 = pow(x + dx, 2) + pow(y + dy, 2); int xy3 = pow(x , 2) + pow(y + dy, 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 + dx; y = y; } else { // xy2 x = x + dx; y = y + dy; } } else { if (xy2 < xy3) { // xy2 x = x + dx; y = y + dy; } else { // xy3 x = x; y = y + dy; } } ///////////////////////// // 描画 if ( (img, x + cx < 0) || (img, x + cx >=img.width) || (img, y + cy < 0) || (img, y + cy >= img.height) ) { continue; } plot(img,x + cx, y + cy); } }
//! @brief 円を描画する //! @param [in] img 画像データ //! @param [in] cx 中心座標 //! @param [in] cy 中心座標 //! @param [in] r 半径 //! @return なし void circle(Image& img,const int cx, const int cy, const int r) { // □□ // □■ calc(img,cx, cy, r, CPOS::right, CPOS::bottom); // □□ // ■□ calc(img, cx, cy, r, CPOS::left, CPOS::bottom); // ■□ // □□ calc(img, cx, cy, r, CPOS::left, CPOS::top); // □■ // □□ calc(img, cx, cy, r, CPOS::right, CPOS::top); }
int main() { Image img; resize(&img, 500, 500); // 中心 int cx = 250; int cy = 250; //半径 int r = 50; //円を描画 circle(img,cx, cy, r); pnmP3_Write("a.pgm", img.width, img.height, img.img.data()); }