三角形

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
けいすけ

三角形

#1

投稿記事 by けいすけ » 18年前

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);
}

Justy

Re:三角形

#2

投稿記事 by Justy » 18年前

 以前から 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]

Justy

Re:三角形

#3

投稿記事 by Justy » 18年前

 続きです。
[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で保存しています。

 このようにキャンパスという抽象的な概念を入れて、上のメイン関数みたいに、キャンパスを生成してからいろな操作を行えるようにしておくと、後々便利です。

 これなら好きなところに好きな色で点やラインを描画し更には保存もできるので、三角形の頂点さえわかればなんとかなるでしょう。

 塗りつぶしが必要なら、ちょっと工夫が必要ですが・・・。

Justy

Re:三角形

#4

投稿記事 by Justy » 18年前

 塗りつぶしもやってみました。
 指定した座標にある色と同じ色の周辺エリアを指定した色で塗っていきます。
[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:三角形

#5

投稿記事 by けいすけ » 18年前

大変長いレスありがとうございました。

でも僕は初心者なので習ってないわからないところがいっぱいありました。

これから独学でレスにいただいた部分も理解できるようになりたいです。

一応これが課題のヒントとして出されたフローチャートなのですが・・・・

真ん中の列の下のほうの肝要な部分がわからないのです。

もしよろしければ、これに添った形でのアドバイス、よろしくお願いします。

Justy

Re:三角形

#6

投稿記事 by Justy » 18年前

 なるほど
 えーと、このヒント1は三角形を描く課題のヒントですか?
 一見このヒントは□(四角形)を書くためのヒントに見えますが。

 なので、このフロートの2重ループ部分は当てにはならない気がします。

Justy

Re:三角形

#7

投稿記事 by Justy » 18年前

[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:三角形

#8

投稿記事 by けいすけ » 18年前

ありがとうございます。
一行ずつ理解しながら自分でも書いています。

内側を塗りつぶすのが出来るか心配ですが・・・・・^^;

けいすけ

Re:三角形

#9

投稿記事 by けいすけ » 18年前

一応習ったことをフル回転させ、解答を参考にさせていただきこのような形に落ち着きました。
分かりやすい解説ありがとうございました!またよろしくお願いします!゜+。:.゜ヽ(*´∀`)ノ゜.:。+゜アリガト
#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);
}

閉鎖

“C言語何でも質問掲示板” へ戻る