SDL中文论坛
标题:
如何画圆弧
[打印本页]
作者:
ancientcc
时间:
2016-5-25 09:27
标题:
如何画圆弧
算法描像素法的不足
算法描像素法指的是程序根据预先给出的半径、起始角度、结束角度,通过特定算法计算出圆孤要经过的像素,然后填色这些像素从而画出圆弧。下图是使用了中点圆算法画出10个同心圆弧,从左到右这些圆弧的半径遂个增一。
(, 下载次数: 1880)
上传
点击文件名下载附件
图中使用白色画圆弧,但它们中间有不少像素出现背景色,原因是算法算出的像素没包括它们。
当然有比中点圆更好的算法,或许能使得画满10宽度内的所有像素。——即使能被画满,以算法描像素画圆弧还有个问题,它描画时采用的是纯色,一旦使用纯色,基本就不能避免掉边界会出现锯齿,导致不美观。
综上所述,用算法描像素法画圆弧存在两个问题,1)当要画的圆弧宽度大于1时,圆弧中可能出现漏画的像素;2)由于是纯色填充,边界会出锯齿。
圆环素材+弧外像素变透明
该方法是让美工事先画出包含了希望中圆弧的圆环,要开始画了,程序计算出属于圆环、但不属于圆弧的弧外像素,把这些像素填成全透明,从而间接画出圆弧。用这方法会直接面临的一个问题,如何找出弧外像素。
第一种是用算法是去找。例如还是用以上的中点圆算法,但这种方法就会碰上个问题,“当要画的圆弧宽度大于1时,圆弧中可能出现漏画的像素”,计算弧外像素也可能出现漏计算。
第二种是抛开画弧算法,使用看去简单的逻辑。
一、分析圆环图像,收集出所有不是全透明的像素。制做素材时要求把图中像素分为两类:环中像素是不透明或半透明,环外像素全透明。在分析时,代码用自定义的tarc_pixel存储每个像素。
struct tarc_pixel
{
unsigned short x;
unsigned short y;
unsigned short degree;
};
复制代码
x、y是像素在素材中的坐标,degree是该像素在此圆环中角度。以下是计算角度的公式,在不同象限公式略有不同,总的逻辑是基于x、y,用反正切计算出角度。(circle_calculate_pixels、circle_draw_arc函数来自Rose项目中的<src>/librose/sdl_utils.cpp)
tarc_pixel* circle_calculate_pixels(surface& surf, int* valid_pixels)
{
const int diameter = surf->w;
surface_lock lock(surf);
......
// circle_valid_pixels是圆环图面中的不透明和半透明像素数
int at = 0;
circle_pixels = (tarc_pixel*)malloc(circle_valid_pixels * sizeof(tarc_pixel));
const int originx = diameter / 2;
const int originy = originx;
int diffx, diffy;
for (int row = 0; row < diameter; row ++) {
for (int col = 0; col < diameter; row ++) {
if (beg[row * diameter + col] >> 24) {
tarc_pixel* pixel = circle_pixels + at;
pixel->x = col;
pixel->y = row;
if (col >= originx && row < originy) {
// 第一象限
diffx = col - originx;
diffy = originy - row;
pixel->degree = atan(1.0 * diffx / diffy) * 180 / M_PI;
} else {
// 其它象限
......
}
at ++;
}
}
}
......
}
复制代码
二、根据起、始角度把弧外像素置为透明
void circle_draw_arc(surface& surf, tarc_pixel* circle_pixels, const int circle_valid_pixels, int start, int stop, Uint32 erase_col)
{
// surf是圆环素材图面
const int diameter = surf->w;
surface_lock lock(surf);
Uint32* beg = lock.pixels();
for (int at = 0; at < circle_valid_pixels; at ++) {
const tarc_pixel& coor = circle_pixels[at];
if (start < stop) {
if (!(pixel.degree >= start && pixel.degree <= stop)) {
beg[coor.y * diameter + coor.x] = erase_col;
}
} else {
if (pixel.degree < start && pixel.degree > stop) {
beg[coor.y * diameter + coor.x] = erase_col;
}
}
}
到此生成的surf就是希望中的圆弧图面
...
}
复制代码
欢迎光临 SDL中文论坛 (http://www.libsdl.cn/bbs/)
Powered by Discuz! X3.3