点を打つ関数pset()のみを使用して扇形(円弧)を描くプログラムを作成しました。基本となるアルゴリズム・プログラムはIoT-Kyoto.comの円弧を描いてみようを使わせてもらいました。円だけではなく楕円にも対応させています。グラフィックにはEGGX / ProCALLを使用しています。プログラムの作成はRaspberry Pi4で行っています。
プログラムリスト
#include <stdio.h> #include <math.h> #include <eggx.h> /* EGGX を使う時に必要 */ /************************* * 角度を0〜2πの間に変換する * 引数 double angle: 角度 * 戻り値 0〜2πの間の角度 */ double Rangle(double angle) { while(angle<0) angle += 2*M_PI; while(angle>=2*M_PI) angle -= 2*M_PI; return angle; } /*************************** * 楕円と中心から角度angleで伸びる直線との交点を求める * 引数 int x: 中心のx座標 * int y: 中心のy座標 * int rx: x方向半径 * int ry: y方向半径 * int angle: 角度(0〜2π) * int px: 交点x座標 * int py: 交点y座標 * 戻り値 なし */ void calcArcPoint(int x,int y,int rx,int ry,double angled,int *px,int *py) { double r,a,b; angled = Rangle(angled); r=1.0; a=1.0/((double)rx*(double)rx); b=1.0/((double)ry*(double)ry); if(angled==M_PI/2) { //90度 *px = x; *py = y - ry; } else if(angled==M_PI*3/2) { //270度 *px = x; *py = y + ry; } else { double m = tan(angled); *px = sqrt((r*r)/(a + b * m*m)); *py = sqrt((r*m*r*m)/(a + b * m*m)); if(angled<M_PI/2) { *px = x + *px; *py = y - *py; } else if(angled<M_PI) { *px = x - *px; *py = y - *py; } else if(angled<M_PI*3/2) { *px = x - *px; *py = y + *py; } else { *px = x + *px; *py = y + *py; } } } /************************* * フレームバッファに楕円を描く * 引数 int cx,cy: 円の中心座標 * int rx: x方向の半径 * int ry: y方向の半径 * double Sangle: 描画スタート角度 * double Eangle: 描画終了角度 * 戻り値 なし */ void grArc(int win,int cx, int cy, int rx,int ry, double Sangle,double Eangle) { int dx, dy, s ; int x1, y1, x2, y2, x3, y3, x4, y4 ; int sx,sy,ex,ey; int psx, psy, pex, pey, ss, es, i, j ; unsigned int pass[4] ; calcArcPoint(cx,cy,rx,ry,Sangle,&sx,&sy); calcArcPoint(cx,cy,rx,ry,Eangle,&ex,&ey); psx = sx - cx ; pex = ex - cx ; psy = sy - cy ; pey = ey - cy ; // 始点の象限 if (psx >= 0) { if (psy >= 0) ss = 3 ; else ss = 0 ; } else { if (psy >= 0) ss = 2 ; else ss = 1 ; } // 終点の象限 if (pex >= 0) { if (pey >= 0) es = 3 ; else es = 0 ; } else { if (pey >= 0) es = 2 ; else es = 1 ; } if (ss == es) { // 始点終点の象限が同じ if (((psy < 0) && (psx >= pex)) || ((psy >= 0) && (psx <= pex))) { for (i = 0 ; i < 4 ; i++) pass[i] = 0 ; // 小円( < 90 ) pass[ss] = 5 ; } else { for (i = 0 ; i < 4 ; i++) pass[i] = 1 ; // 大円( > 270 ) pass[ss] = 4 ; } } else { for (i = 0 ; i < 4 ; i++) pass[i] = 0 ; j = ss ; for (i = 0 ; i < 4 ; i++) { pass[j] = 1 ; // 全表示 if (j == es) break ; ++j ; if (j > 3) j = 0 ; } pass[ss] = 2 ; // 始点のみ pass[es] = 3 ; // 終点のみ } if(rx>ry) { dx = rx ; s = rx ; dy = 0 ; while (dx >= dy) { unsigned int flag ; int dxx = dx*ry/rx; int dyy = dy*ry/rx; x1 = cx + dx; x2 = cx - dx; x3 = cx + dy; x4 = cx - dy; y1 = cy + dyy; y2 = cy - dyy; y3 = cy + dxx; y4 = cy - dxx; flag = 0x00 ; // 第1象限 switch (pass[0]) { default: break ; case 1: flag = 0x03 ; break ; case 2: if ((x1 <= sx) && (y2 <= sy)) flag |= 0x01 ; if ((x3 <= sx) && (y4 <= sy)) flag |= 0x02 ; break ; case 3: if ((x1 >= ex) && (y2 >= ey)) flag |= 0x01 ; if ((x3 >= ex) && (y4 >= ey)) flag |= 0x02 ; break ; case 4: if (((x1 <= sx) || (x1 >= ex)) && ((y2 <= sy) || (y2 >= ey))) flag |= 0x01 ; if (((x3 <= sx) || (x3 >= ex)) && ((y4 <= sy) || (y4 >= ey))) flag |= 0x02 ; break ; case 5: if ((x1 <= sx) && (x1 >= ex) && (y2 <= sy) && (y2 >= ey)) flag |= 0x01 ; if ((x3 <= sx) && (x3 >= ex) && (y4 <= sy) && (y4 >= ey)) flag |= 0x02 ; break ; } // 第2象限 switch (pass[1]) { default: break ; case 1: flag |= 0x0C ; break ; case 2: if ((x4 <= sx) && (y4 >= sy)) flag |= 0x04 ; if ((x2 <= sx) && (y2 >= sy)) flag |= 0x08 ; break ; case 3: if ((x4 >= ex) && (y4 <= ey)) flag |= 0x04 ; if ((x2 >= ex) && (y2 <= ey)) flag |= 0x08 ; break ; case 4: if (((x4 <= sx) || (x4 >= ex)) && ((y4 >= sy) || (y4 <= ey))) flag |= 0x04 ; if (((x2 <= sx) || (x2 >= ex)) && ((y2 >= sy) || (y2 <= ey))) flag |= 0x08 ; break ; case 5: if ((x4 <= sx) && (x4 >= ex) && (y4 >= sy) && (y4 <= ey)) flag |= 0x04 ; if ((x2 <= sx) && (x2 >= ex) && (y2 >= sy) && (y2 <= ey)) flag |= 0x08 ; break ; } // 第3象限 switch (pass[2]) { default: break ; case 1: flag |= 0x30 ; break ; case 2: if ((x2 >= sx) && (y1 >= sy)) flag |= 0x10 ; if ((x4 >= sx) && (y3 >= sy)) flag |= 0x20 ; break ; case 3: if ((x2 <= ex) && (y1 <= ey)) flag |= 0x10 ; if ((x4 <= ex) && (y3 <= ey)) flag |= 0x20 ; break ; case 4: if (((x2 >= sx) || (x2 <= ex)) && ((y1 >= sy) || (y1 <= ey))) flag |= 0x10 ; if (((x4 >= sx) || (x4 <= ex)) && ((y3 >= sy) || (y3 <= ey))) flag |= 0x20 ; break ; case 5: if ((x2 >= sx) && (x2 <= ex) && (y1 >= sy) && (y1 <= ey)) flag |= 0x10 ; if ((x4 >= sx) && (x4 <= ex) && (y3 >= sy) && (y3 <= ey)) flag |= 0x20 ; break ; } // 第4象限 switch (pass[3]) { default: break ; case 1: flag |= 0xC0 ; break ; case 2: if ((x3 >= sx) && (y3 <= sy)) flag |= 0x40 ; if ((x1 >= sx) && (y1 <= sy)) flag |= 0x80 ; break ; case 3: if ((x3 <= ex) && (y3 >= ey)) flag |= 0x40 ; if ((x1 <= ex) && (y1 >= ey)) flag |= 0x80 ; break ; case 4: if (((x3 >= sx) || (x3 <= ex)) && ((y3 <= sy) || (y3 >= ey))) flag |= 0x40 ; if (((x1 >= sx) || (x1 <= ex)) && ((y1 <= sy) || (y1 >= ey))) flag |= 0x80 ; break ; case 5: if ((x3 >= sx) && (x3 <= ex) && (y3 <= sy) && (y3 >= ey)) flag |= 0x40 ; if ((x1 >= sx) && (x1 <= ex) && (y1 <= sy) && (y1 >= ey)) flag |= 0x80 ; break ; } if (flag & 0x01) pset(win,x1,y2) ; if (flag & 0x02) pset(win,x3,y4) ; if (flag & 0x04) pset(win,x4,y4) ; if (flag & 0x08) pset(win,x2,y2) ; if (flag & 0x10) pset(win,x2,y1) ; if (flag & 0x20) pset(win,x4,y3) ; if (flag & 0x40) pset(win,x3,y3) ; if (flag & 0x80) pset(win,x1,y1) ; s -= 2 * dy + 1 ; if (s < 0) { --dx ; s += 2 * dx ; } ++dy ; } } else { dx = 0 ; s = ry ; dy = ry ; while (dy >= dx) { unsigned int flag ; int dxx = dx*rx/ry; int dyy = dy*rx/ry; x1 = cx + dxx; x2 = cx - dxx; x3 = cx + dyy; x4 = cx - dyy; y1 = cy + dy; y2 = cy - dy; y3 = cy + dx; y4 = cy - dx; flag = 0x00 ; // 第1象限 switch (pass[0]) { default: break ; case 1: flag = 0x03 ; break ; case 2: if ((x1 <= sx) && (y2 <= sy)) flag |= 0x01 ; if ((x3 <= sx) && (y4 <= sy)) flag |= 0x02 ; break ; case 3: if ((x1 >= ex) && (y2 >= ey)) flag |= 0x01 ; if ((x3 >= ex) && (y4 >= ey)) flag |= 0x02 ; break ; case 4: if (((x1 <= sx) || (x1 >= ex)) && ((y2 <= sy) || (y2 >= ey))) flag |= 0x01 ; if (((x3 <= sx) || (x3 >= ex)) && ((y4 <= sy) || (y4 >= ey))) flag |= 0x02 ; break ; case 5: if ((x1 <= sx) && (x1 >= ex) && (y2 <= sy) && (y2 >= ey)) flag |= 0x01 ; if ((x3 <= sx) && (x3 >= ex) && (y4 <= sy) && (y4 >= ey)) flag |= 0x02 ; break ; } // 第2象限 switch (pass[1]) { default: break ; case 1: flag |= 0x0C ; break ; case 2: if ((x4 <= sx) && (y4 >= sy)) flag |= 0x04 ; if ((x2 <= sx) && (y2 >= sy)) flag |= 0x08 ; break ; case 3: if ((x4 >= ex) && (y4 <= ey)) flag |= 0x04 ; if ((x2 >= ex) && (y2 <= ey)) flag |= 0x08 ; break ; case 4: if (((x4 <= sx) || (x4 >= ex)) && ((y4 >= sy) || (y4 <= ey))) flag |= 0x04 ; if (((x2 <= sx) || (x2 >= ex)) && ((y2 >= sy) || (y2 <= ey))) flag |= 0x08 ; break ; case 5: if ((x4 <= sx) && (x4 >= ex) && (y4 >= sy) && (y4 <= ey)) flag |= 0x04 ; if ((x2 <= sx) && (x2 >= ex) && (y2 >= sy) && (y2 <= ey)) flag |= 0x08 ; break ; } // 第3象限 switch (pass[2]) { default: break ; case 1: flag |= 0x30 ; break ; case 2: if ((x2 >= sx) && (y1 >= sy)) flag |= 0x10 ; if ((x4 >= sx) && (y3 >= sy)) flag |= 0x20 ; break ; case 3: if ((x2 <= ex) && (y1 <= ey)) flag |= 0x10 ; if ((x4 <= ex) && (y3 <= ey)) flag |= 0x20 ; break ; case 4: if (((x2 >= sx) || (x2 <= ex)) && ((y1 >= sy) || (y1 <= ey))) flag |= 0x10 ; if (((x4 >= sx) || (x4 <= ex)) && ((y3 >= sy) || (y3 <= ey))) flag |= 0x20 ; break ; case 5: if ((x2 >= sx) && (x2 <= ex) && (y1 >= sy) && (y1 <= ey)) flag |= 0x10 ; if ((x4 >= sx) && (x4 <= ex) && (y3 >= sy) && (y3 <= ey)) flag |= 0x20 ; break ; } // 第4象限 switch (pass[3]) { default: break ; case 1: flag |= 0xC0 ; break ; case 2: if ((x3 >= sx) && (y3 <= sy)) flag |= 0x40 ; if ((x1 >= sx) && (y1 <= sy)) flag |= 0x80 ; break ; case 3: if ((x3 <= ex) && (y3 >= ey)) flag |= 0x40 ; if ((x1 <= ex) && (y1 >= ey)) flag |= 0x80 ; break ; case 4: if (((x3 >= sx) || (x3 <= ex)) && ((y3 <= sy) || (y3 >= ey))) flag |= 0x40 ; if (((x1 >= sx) || (x1 <= ex)) && ((y1 <= sy) || (y1 >= ey))) flag |= 0x80 ; break ; case 5: if ((x3 >= sx) && (x3 <= ex) && (y3 <= sy) && (y3 >= ey)) flag |= 0x40 ; if ((x1 >= sx) && (x1 <= ex) && (y1 <= sy) && (y1 >= ey)) flag |= 0x80 ; break ; } if (flag & 0x01) pset(win,x1,y2) ; if (flag & 0x02) pset(win,x3,y4) ; if (flag & 0x04) pset(win,x4,y4) ; if (flag & 0x08) pset(win,x2,y2) ; if (flag & 0x10) pset(win,x2,y1) ; if (flag & 0x20) pset(win,x4,y3) ; if (flag & 0x40) pset(win,x3,y3) ; if (flag & 0x80) pset(win,x1,y1) ; s -= 2 * dx + 1 ; if (s < 0) { --dy ; s += 2 * dy ; } ++dx ; } } } int main(int argc, char **argv) { int win; gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/ win = gopen(400,400); /* 400x400 ピクセルのグラフィックス用ウィンドゥを開く */ newrgbcolor(win,255,0,0); grArc(win,200,200,150,80,0,M_PI/3); grArc(win,200,200,160,90,M_PI/3,M_PI*2/3); grArc(win,200,200,170,100,M_PI*2/3,M_PI); grArc(win,200,200,160,90,M_PI,M_PI*4/3); grArc(win,200,200,170,100,M_PI*4/3,M_PI*5/3); grArc(win,200,200,160,90,M_PI*5/3,0); newrgbcolor(win,0,255,0); grArc(win,200,200,100,150,0,M_PI); grArc(win,200,200,50,100,M_PI,0); grArc(win,200,200,75,125,M_PI/2,-M_PI/2); newrgbcolor(win,0,0,200); drawline(win,0,200,400,200); drawline(win,200,0,200,400); ggetch(); /* キー入力があるまで待つ */ gclose(win); /* グラフィックス用ウィンドゥを閉じる */ return 0; }
実行結果
参考
※コメント投稿者のブログIDはブログ作成者のみに通知されます