SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 4919|回复: 0
打印 上一主题 下一主题

[Plot] 如何画圆弧

[复制链接]

149

主题

331

帖子

2445

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2445
跳转到指定楼层
楼主
发表于 2016-5-25 09:27:02 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
算法描像素法的不足
算法描像素法指的是程序根据预先给出的半径、起始角度、结束角度,通过特定算法计算出圆孤要经过的像素,然后填色这些像素从而画出圆弧。下图是使用了中点圆算法画出10个同心圆弧,从左到右这些圆弧的半径遂个增一。

图中使用白色画圆弧,但它们中间有不少像素出现背景色,原因是算法算出的像素没包括它们。

当然有比中点圆更好的算法,或许能使得画满10宽度内的所有像素。——即使能被画满,以算法描像素画圆弧还有个问题,它描画时采用的是纯色,一旦使用纯色,基本就不能避免掉边界会出现锯齿,导致不美观。

综上所述,用算法描像素法画圆弧存在两个问题,1)当要画的圆弧宽度大于1时,圆弧中可能出现漏画的像素;2)由于是纯色填充,边界会出锯齿。

圆环素材+弧外像素变透明
该方法是让美工事先画出包含了希望中圆弧的圆环,要开始画了,程序计算出属于圆环、但不属于圆弧的弧外像素,把这些像素填成全透明,从而间接画出圆弧。用这方法会直接面临的一个问题,如何找出弧外像素。

第一种是用算法是去找。例如还是用以上的中点圆算法,但这种方法就会碰上个问题,“当要画的圆弧宽度大于1时,圆弧中可能出现漏画的像素”,计算弧外像素也可能出现漏计算。

第二种是抛开画弧算法,使用看去简单的逻辑。

一、分析圆环图像,收集出所有不是全透明的像素。制做素材时要求把图中像素分为两类:环中像素是不透明或半透明,环外像素全透明。在分析时,代码用自定义的tarc_pixel存储每个像素。
  1. struct tarc_pixel
  2. {
  3.         unsigned short x;
  4.         unsigned short y;
  5.         unsigned short degree;
  6. };
复制代码

x、y是像素在素材中的坐标,degree是该像素在此圆环中角度。以下是计算角度的公式,在不同象限公式略有不同,总的逻辑是基于x、y,用反正切计算出角度。(circle_calculate_pixels、circle_draw_arc函数来自Rose项目中的<src>/librose/sdl_utils.cpp)

  1. tarc_pixel* circle_calculate_pixels(surface& surf, int* valid_pixels)
  2. {
  3.         const int diameter = surf->w;
  4.         surface_lock lock(surf);
  5.         ......
  6.         // circle_valid_pixels是圆环图面中的不透明和半透明像素数

  7.         int at = 0;
  8.         circle_pixels = (tarc_pixel*)malloc(circle_valid_pixels * sizeof(tarc_pixel));
  9.         const int originx = diameter / 2;
  10.         const int originy = originx;
  11.         int diffx, diffy;
  12.         for (int row = 0; row < diameter; row ++) {
  13.                 for (int col = 0; col < diameter; row ++) {
  14.                         if (beg[row * diameter + col] >> 24) {
  15.                                 tarc_pixel* pixel = circle_pixels + at;
  16.                                 pixel->x = col;
  17.                                 pixel->y = row;
  18.                                 if (col >= originx && row < originy) {
  19.                                         // 第一象限
  20.                                         diffx = col - originx;
  21.                                         diffy = originy - row;
  22.                                         pixel->degree = atan(1.0 * diffx / diffy) * 180 / M_PI;
  23.                                 } else {
  24.                                         // 其它象限
  25.                                         ......
  26.                                 }
  27.                                 at ++;
  28.                         }
  29.                 }
  30.         }
  31.         ......
  32. }
复制代码


二、根据起、始角度把弧外像素置为透明
  1. void circle_draw_arc(surface& surf, tarc_pixel* circle_pixels, const int circle_valid_pixels, int start, int stop, Uint32 erase_col)
  2. {
  3.         // surf是圆环素材图面
  4.         const int diameter = surf->w;
  5.         surface_lock lock(surf);
  6.         Uint32* beg = lock.pixels();
  7.         for (int at = 0; at < circle_valid_pixels; at ++) {
  8.                 const tarc_pixel& coor = circle_pixels[at];
  9.                 if (start < stop) {
  10.                         if (!(pixel.degree >= start && pixel.degree <= stop)) {
  11.                                 beg[coor.y * diameter + coor.x] = erase_col;
  12.                         }       

  13.                 } else {
  14.                         if (pixel.degree < start && pixel.degree > stop) {
  15.                                 beg[coor.y * diameter + coor.x] = erase_col;
  16.                         }
  17.                 }
  18.         }
  19.         到此生成的surf就是希望中的圆弧图面
  20.         ...
  21. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2025-5-2 00:15 , Processed in 0.049369 second(s), 23 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表