SDL2 で塗りつぶした楕円の回転
塗りつぶした楕円は、回転させなければ、円の塗りつぶしと同様に描くことができます。
void fill_oval(SDL_Renderer *renderer, int sx, int sy, int a, int b, int angle) {
SDL_Point p1, p2;
int x, y;
for( x = -a; x <= a; x++ ) {
y = sqrt(1.0 - (double)(x*x)/(a*a))*b +0.5;
p1.x = x, p1.y = y;
rotate(&p1, angle);
p2.x = x, p2.y = -y;
rotate(&p2, angle);
SDL_RenderDrawLine(renderer, sx + p1.x, sy - p1.y, sx + p2.x, sy - p2.y);
}
}

ところが、回転させると、うまく塗りつぶせません。

別な考え方で塗りつぶします。楕円の方程式は以下です。

ある点が、この楕円の中にあるかどうかを判断し、楕円の中にあれば点を描画し、無ければ描画しない。という手順で塗りつぶしを行います。(x, y) が楕円内にあるかどうかは、次の式で判断できます。

上記の式をちょっと変形しておきます。

これを使い、楕円を塗りつぶしてみます。
void fill_oval(SDL_Renderer *renderer, int cx, int cy, int a, int b)
{
int x, y, result, out;
out = a*a * b*b;
for( x = -a; x <= a; x++ ) {
for( y = -b; y <= b; y++ ) {
result = (x * x)*(b * b) + (y * y)*(a * a);
if( result <= out ) {
SDL_RenderDrawPoint(renderer, cx + x, cy - y);
}
}
}
}

これを回転出来るようにします。考え方としては、楕円を含む矩形を回転させ、調べる領域を求め、各点を調べるときに、逆に回転させ、調べます。
void rotate(SDL_Point *pt, int angle) {
int x, y;
double r;
x = pt->x, y = pt->y;
r = M_PI * angle / 180.;
pt->x = x * cos(r) - y * sin(r);
pt->y = x * sin(r) + y * cos(r);
}
void min_max(SDL_Point *p, SDL_Point *min, SDL_Point *max, int angle) {
rotate(p, angle);
min->x = min->x > p->x ? p->x : min->x;
min->y = min->y > p->y ? p->y : min->y;
max->x = max->x < p->x ? p->x : max->x;
max->y = max->y < p->y ? p->y : max->y;
}
void fill_oval(SDL_Renderer *renderer, int cx, int cy, int a, int b, int angle) {
int x, y, result, out;
SDL_Point p, min, max;
/* 回転後の描画範囲を求める */
min.x = max.x = 0;
min.y = max.y = 0;
p.x = -a, p.y = -b;
min_max(&p, &min, &max, angle);
p.x = -a, p.y = b;
min_max(&p, &min, &max, angle);
p.x = a, p.y = b;
min_max(&p, &min, &max, angle);
p.x = a, p.y = -b;
min_max(&p, &min, &max, angle);
out = a*a * b*b;
for( x = min.x; x <= max.x; x++ ) {
for( y = min.y; y <= max.y; y++ ) {
p.x = x, p.y = y;
rotate(&p, -angle);
result = (p.x * p.x)*(b * b) + (p.y * p.y)*(a * a);
if( result <= out ) {
SDL_RenderDrawPoint(renderer, cx + x, cy - y);
}
}
}
}

これで塗りつぶしがおかしくなることはなくなりました。塗りつぶしの時は、この方法を使ったほうがいいようです。

ディスカッション
コメント一覧
まだ、コメントがありません