五子棋里那个画圆的函数一直欠缺没有完成。算法
最开始的想法是根据 x * x + y * y = r *r 函数
由三角函数计算各点的坐标,而后依次点出全部点:code
// 画空心圆弧(效率很低) // 参数:x,y = 圆心坐标;r = 内圆半径;R = 外圆半径;a = 起始弧度;A = 终止弧度(弧度为逆时针方向) void FillCircle(SDL_Renderer *pRen, int x, int y, int r, int R, int a, int A) { const int FINE = 10; // 精细程度 double f; int i, j; _Bool point[2 * R][2 * R]; // 包含圆的最大正方形的全部点 memset(point, 0, sizeof(point)); // 计算点 for(i = r; i <= R; i++) { for(j = FINE*a; j <= FINE*A; j++) { f = 3.14159265359 * j / (FINE * 180); point[(int)(R + i * cosf(f))][(int)(R - i * sinf(f))] = 1; } } // 画点 for(i = 0; i < 2 * R; i++) { for(j = 0; j < 2 * R; j++) { if(point[i][j]) { SDL_RenderDrawPoint(pRen, x - R + i, y - R + j); } } } }
可是因为用到了两次双层循环,循环里还涉及 sin 和 cos 运算,效率很是低!FINE 取值 5 的时候只能画小圆,大了就好多空白。FINE 取 10 的时候,个人电脑配置 E3v3 + 12G 内存都感受到卡了,FINE 取 100 的时候,直接卡到渣!内存
上网搜索了下,发现有高效的 Bresenham 算法,但是看不懂!!数学
只能照葫芦画瓢,抄过来了!class
// 基于 Bresenham 算法画填充圆 // 参数:x,y = 圆心坐标;r = 半径 // 备注:若是没有画线函数,就直接用 for 循环画点线 void FillCircle_Bresenham(SDL_Renderer *pRen, int x, int y, int r) { int tx = 0, ty = r, d = 3 - 2 * r; while(tx < ty) { // 小于 45 度横线 SDL_RenderDrawLine(pRen, x - ty, y - tx, x + ty, y - tx); if(tx != 0) // 防止水平线重复绘制 { SDL_RenderDrawLine(pRen, x - ty, y + tx, x + ty, y + tx); } if(d < 0) // 取上面的点 { d += 4 * tx + 6; } else // 取下面的点 { // 大于 45 度横线 SDL_RenderDrawLine(pRen, x - tx, y - ty, x + tx, y - ty); SDL_RenderDrawLine(pRen, x - tx, y + ty, x + tx, y + ty); d += 4 * (tx - ty) + 10; ty--; } tx++; } if(tx == ty) // 45 度横线 { SDL_RenderDrawLine(pRen, x - ty, y - tx, x + ty, y - tx); SDL_RenderDrawLine(pRen, x - ty, y + tx, x + ty, y + tx); } }
效率却是高了好多,但是这段代码我看不懂!数学没学好啊!效率
用的 SDL 的画线函数,实际上用任何能画线的 API 都行。甚至没有画线的 API,有画点的 API 也同样实现。——本身用点画线就行。配置