200×200画素の画像の中心に指定した底辺と高さの三角形を配置したプログラムを作成し
画像は1次元配列でmalloc関数を用いて動的にメモリを確保。
という課題が出たので自分で作ってみたのですが、出来ません( ノД`)シクシク
もしよろしければアドバイスよろしくお願いします。
#include <stdio.h>
#include <stdlib.h>
#define MS 200
main()
{
char fi[50];
int i,j,x0,x1,y,w,h;
FILE *fp;
unsigned short header[13]={0x4d42,54490,1,0,0,26,0,12,0,200,200,1,24};
unsigned char *bmp;
bmp=(unsigned char*)malloc(MS*MS*3);
for(i=0;i<=MS*MS-1;i++)
{
bmp[i*3+0]=255;
bmp[i*3+1]=0;
bmp[i*3+2]=0;
}
printf("Input width : ");
scanf("%s",fi);
w=atoi(fi);
printf("Input height : ");
scanf("%s",fi);
h=atoi(fi);
for(i=100-h/2;i<=100+h/2;i++)
{y=i-MS/2;
for(j=100-w/2;j<=100;j++)
{x0=j-MS/2;
bmp[(i*MS+j)*3+0]>=2*h*x0/w+h/2;
bmp[(i*MS+j)*3+1]<=2*h*x0/w+h/2;
bmp[(i*MS+j)*3+2]=0;
}
}
for(i=100-h/2;i<=100+h/2;i++)
{y=i-MS/2;
for(j=100;j<=100+w/2;j++)
{x1=j-MS/2;
bmp[(i*MS+j)*3+0]>=-2*h*x1/w+h/2;
bmp[(i*MS+j)*3+1]<=-2*h*x1/w+h/2;
bmp[(i*MS+j)*3+2]=0;
}
}
printf("Input file name : ");
scanf("%s",fi);
if((fp=fopen(fi,"wb"))==NULL)
{
fprintf(stderr,"Error : file open[%s].\n",fi);
exit(1);
}
fwrite(header,2,13,fp);
fwrite(bmp,1,200*200*3,fp);
fclose(fp);
}
三角形
Re:三角形
以前から bmpへの描画を行う課題に取り組まれていますよね。
main関数1つで書くのもそろそろ限界でしょうし、bmpへの描画を扱うライブラリ的なものを作られてはどうでしょうか。
こんなかんじで。
main関数1つで書くのもそろそろ限界でしょうし、bmpへの描画を扱うライブラリ的なものを作られてはどうでしょうか。
こんなかんじで。
[color=#d0d0ff" face="monospace]#include <stdio.h>
#include <stdlib.h>
// カラー構造体
typedef struct color
{
unsigned char b;
unsigned char g;
unsigned char r;
} color;
// キャンパス構造体
typedef struct campus_info
{
int width;
int height;
color * pixels;
} campus_info;
// キャンパス作成
static void create_campus(campus_info *info, int width, int height)
{
info->width = width;
info->height = height;
info->pixels = malloc(width * height * 3);
}
// キャンパスを塗りつぶす
static void fill_campus(const campus_info *info, const color *col)
{
int x, y;
if(!info || !col) return;
for(y=0; y<info->height; ++y)
{
int w = y * info->width;
for(x=0; x<info->width; ++x)
info->pixels[w + x] = *col;
}
}
// キャンパスに点を置く
static void put_pixel_campus(const campus_info *info, int x, int y, const color *col)
{
if(!info || !col
|| x < 0 || x >= info->width
|| y < 0 || y >= info->height) return;
info->pixels[(info->height-y-1)*info->width+x] = *col;
}
// キャンパスにラインを引く
static void put_line_campus(const campus_info *info, int sx, int sy, int ex, int ey, const color *col)
{
int x, y, step_x, step_y, fraction, deltaX, deltaY;
deltaX = ex - sx; if(deltaX < 0) deltaX = -deltaX;
deltaY = ey - sy; if(deltaY < 0) deltaY = -deltaY;
step_x = (sx <= ex)? 1: -1;
step_y = (sy <= ey)? 1: -1;
x = sx, y = sy;
if(deltaY >= deltaX)
{
fraction = deltaX * 2 - deltaY;
do
{
put_pixel_campus(info, x, y, col);
if(y == ey)
break;
if(fraction >= 0)
{
x += step_x;
fraction = fraction - deltaY;
}
y += step_y;
fraction = fraction + deltaX;
}while(1);
}
else
{
fraction = deltaY * 2 - deltaX;
do
{
put_pixel_campus(info, x, y, col);
if(x == ex)
break;
if(fraction >= 0)
{
y += step_y;
fraction = fraction - deltaX;
}
x += step_x;
fraction = fraction + deltaY;
}while(1);
}
}
// キャンパスの色を取得
static const color* get_pixel_campus(const campus_info *info, int x, int y)
{
if(!info
|| x < 0 || x >= info->width
|| y < 0 || y >= info->height) return NULL;
return &info->pixels[(info->height-y-1)*info->width+x];
}
// キャンパスを bmp形式で保存する
static void save_bmp_campus(const campus_info *info, const char *filename)
{
unsigned short header[13]
={ 0x4d42,54490,1,0,0,26,0,12,0,info->width,info->height,1,24};
FILE *fp;
if((fp=fopen(filename,"wb"))==NULL)
{
fprintf(stderr,"Error : file open[%s].\n",filename);
exit(1);
}
fwrite(header, 2, 13, fp);
fwrite(info->pixels, 1, info->height * info->width * 3, fp);
fclose(fp);
}
// キャンパスを破棄
static void destroy_campus(campus_info *campus)
{
if(!campus) return;
free(campus->pixels);
}[/color]
Re:三角形
続きです。
このようにキャンパスという抽象的な概念を入れて、上のメイン関数みたいに、キャンパスを生成してからいろな操作を行えるようにしておくと、後々便利です。
これなら好きなところに好きな色で点やラインを描画し更には保存もできるので、三角形の頂点さえわかればなんとかなるでしょう。
塗りつぶしが必要なら、ちょっと工夫が必要ですが・・・。
[color=#d0d0ff" face="monospace]int main(void)
{
campus_info campus;
const color fill_col = { 255, 0, 0 }, // 色
p1_col = { 0, 0, 255 },
p2_col = { 0, 255, 255 },
p3_col = { 255, 0, 255 };
create_campus(&campus, 160, 200); // キャンパスを生成
{
fill_campus(&campus, &fill_col); // 塗りつぶして
put_pixel_campus(&campus, 0, 0, &p1_col); // 点を打って
put_pixel_campus(&campus, 100, 10, &p1_col);
put_line_campus(&campus, 50, 50, 100, 160, &p2_col); // ラインを引く
put_line_campus(&campus, 100, 160, 150, 20, &p3_col);
save_bmp_campus(&campus, "test.bmp"); // 保存
}
destroy_campus(&campus); // キャンパスを破棄
return 0;
}[/color]
上のはサンプルで、点とラインを描画して、bmpで保存しています。このようにキャンパスという抽象的な概念を入れて、上のメイン関数みたいに、キャンパスを生成してからいろな操作を行えるようにしておくと、後々便利です。
これなら好きなところに好きな色で点やラインを描画し更には保存もできるので、三角形の頂点さえわかればなんとかなるでしょう。
塗りつぶしが必要なら、ちょっと工夫が必要ですが・・・。
Re:三角形
塗りつぶしもやってみました。
指定した座標にある色と同じ色の周辺エリアを指定した色で塗っていきます。
で、main関数の方を
指定した座標にある色と同じ色の周辺エリアを指定した色で塗っていきます。
[color=#d0d0ff" face="monospace]static void fill_area_campus_(const campus_info *info, int x, int y, const color *r_col, const color *col)
{
const color *pixel_col = get_pixel_campus(info, x, y);
if(!pixel_col
|| pixel_col->r != r_col->r || pixel_col->g != r_col->g || pixel_col->b != r_col->b)
return;
put_pixel_campus(info, x, y, col);
fill_area_campus_(info, x + 0, y + 1, r_col, col);
fill_area_campus_(info, x + 0, y - 1, r_col, col);
fill_area_campus_(info, x + 1, y + 0, r_col, col);
fill_area_campus_(info, x - 1, y + 0, r_col, col);
}
static void fill_area_campus(const campus_info *info, int x, int y, const color *col)
{
color pixel_col;
const color *ptr_pixel_col = get_pixel_campus(info, x, y);
if(!ptr_pixel_col) return;
pixel_col = *ptr_pixel_col;
fill_area_campus_(info, x, y, &pixel_col, col);
}
[/color]
で、main関数の方を
[color=#d0d0ff" face="monospace] put_line_campus(&campus, 50, 50, 100, 160, &p2_col);
put_line_campus(&campus, 100, 160, 150, 20, &p2_col);
put_line_campus(&campus, 150, 20, 50, 50, &p2_col);
fill_area_campus(&campus, 100, 100, &p3_col); // 中を塗りつぶす[/color]
とすると三角形の中が塗りつぶされます。Re:三角形
[color=#d0d0ff" face="monospace]#include <stdio.h>
#include <stdlib.h>
#define MS 200
int main(void)
{
char fi[256];
int i, j, x, y, w, h, index;
FILE *fp;
static const unsigned short header[13]={0x4d42,54490,1,0,0,26,0,12,0,MS,MS,1,24};
unsigned char *bmp = (unsigned char*)malloc(MS * MS * 3);
// 背景を塗りつぶす
for(i=0;i<=MS*MS;i++)
bmp[i*3+0] = bmp[i*3+1] = bmp[i*3+2]=0;
printf("Input width : ");
scanf("%s",fi);
sscanf(fi, "%d", &w);
printf("Input height : ");
scanf("%s",fi);
sscanf(fi, "%d", &h);
// 底辺のライン
y = - h / 2;
j = y + MS / 2; // ヒント2の座標変換
for(x=-w/2; x<=w/2; ++x)
{
i = x + MS / 2; // ヒント2の座標変換
index = (j * MS + i) * 3;
bmp[index+0] = 255; bmp[index+1] = 0; bmp[index+2] = 0;
}
#if 1 // ヒント2の式をそのまま
// 左辺
for(x=-w/2; x<=0; ++x)
{
y = (2 * h) / w * x + h / 2;
i = x + MS / 2; j = y + MS / 2; // ヒント2の座標変換
index = (j * MS + i) * 3;
bmp[index+0] = 255; bmp[index+1] = 0; bmp[index+2] = 0;
}
// 右辺
for(x=0; x<=w/2; ++x)
{
y = - (2 * h) / w * x + h / 2;
i = x + MS / 2; j = y + MS / 2; // ヒント2の座標変換
index = (j * MS + i) * 3;
bmp[index+0] = 255; bmp[index+1] = 0; bmp[index+2] = 0;
}
#else // ヒント2の式を変換
// 左辺
for(y=-h/2; y<=h/2; ++y)
{
x = (y - h / 2) / ((2 * h) / w);
i = x + MS / 2; j = y + MS / 2; // ヒント2の座標変換
index = (j * MS + i) * 3;
bmp[index+0] = 255; bmp[index+1] = 0; bmp[index+2] = 0;
}
for(y=-h/2; y<=h/2; ++y)
{
x = (y - h / 2) / (- (2 * h) / w);
i = x + MS / 2; j = y + MS / 2; // ヒント2の座標変換
index = (j * MS + i) * 3;
bmp[index+0] = 255; bmp[index+1] = 0; bmp[index+2] = 0;
}
#endif
printf("Input file name : ");
scanf("%s", fi);
if((fp=fopen(fi,"wb"))==NULL)
{
fprintf(stderr,"Error : file open[%s].\n",fi);
exit(1);
}
fwrite(header, 2, 13, fp);
fwrite(bmp, 1, MS*MS*3, fp);
fclose(fp);
return 0;
}[/color]
これでほぼあっているかと思います。考え方としては3回の個別のループで処理しています。
底辺の線を書くループ、左側の辺を書くループ、右側の辺を書くループ。
この問題の場合、y = .... の公式が提供されているので、二重ループの必要はなく、xの値が決まれば自動的に yの値も決まるので1重ループで処理しています。
尚、このコードをテストする時、 "#if 1"と書かれているところを "#if 0"に書き換えたバージョンもテストしてみてください。
"#if 1"の方はヒント2の通りの式を使っていますが、 "#if 0"の方はヒント2の y = ...の式を x = ....に直しています。
Re:三角形
一応習ったことをフル回転させ、解答を参考にさせていただきこのような形に落ち着きました。
分かりやすい解説ありがとうございました!またよろしくお願いします!゜+。:.゜ヽ(*´∀`)ノ゜.:。+゜アリガト
分かりやすい解説ありがとうございました!またよろしくお願いします!゜+。:.゜ヽ(*´∀`)ノ゜.:。+゜アリガト
#include <stdio.h> #include <stdlib.h> #define MS 200 main() { char fi[256]; int i,j,x,y,w,h; FILE *fp; unsigned short header[13]={0x4d42,54490,1,0,0,26,0,12,0,MS,MS,1,24}; unsigned char *bmp; bmp=(unsigned char*)malloc(MS*MS*3); for(i=0;i<=MS*MS;i++) { bmp[i*3+0]=0; bmp[i*3+1]=0; bmp[i*3+2]=0; } printf("Input width : "); scanf("%s",fi); w=atoi(fi); printf("Input height : "); scanf("%s",fi); h=atoi(fi); for(x=-w/2;x<=0;++x) { for(y=-h/2;y<=h/2;++y) { if(y<=(2*h)/w*x+h/2) { i=x+MS/2; j=y+MS/2; bmp[(j*MS+i)*3+0]=0; bmp[(j*MS+i)*3+1]=0; bmp[(j*MS+i)*3+2]=255; } } } for(x=0;x<=w/2;++x) { for(y=-h/2;y<h/2;++y) { if(y<=-(2*h)/w*x+h/2) { i=x+MS/2; j=y+MS/2; bmp[(j*MS+i)*3+0]=0; bmp[(j*MS+i)*3+1]=0; bmp[(j*MS+i)*3+2]=255; } } } printf("Input file name : "); scanf("%s",fi); if((fp=fopen(fi,"wb"))==NULL) { printf(stderr,"Error : file open[%s].\n",fi); exit(1); } fwrite(header,2,13,fp); fwrite(bmp,1,200*200*3,fp); fclose(fp); }