CodeBus

分享代码,一起进步~

[图形学] 画填充圆(基于 Bresenham 算法)

基于图形学中的 Bresenham 画圆法,设计了填充圆的实现。以下是该实现的 C 语言源码: /////////////////////////////////////////////////// // 程序名称:基于 Bresenham 算法画填充圆 // 编译环境:Visual C++ 6.0 / 2013,EasyX 20140321(beta) // 作  者:yangw80 <yw80@qq.com> // 最后修改:2014-7-14 // #include <graphics.h> #include <conio.h> // 基于 Bresenham 算法画填充圆 void FillCircle_Bresenham(int x, int y, int r, COLORREF color) { int tx = 0, ty = r, d = 3 - 2 * r, i; while( tx < ty) { // 画水平两点连线(<45度) for (i = x - ty; i <= x + ty; i++) { putpixel(i, y - tx, color); if (tx != 0) // 防止水平线重复绘制 putpixel(i, y + tx, color); } if (d < 0) // 取上面的点 d += 4 * tx + 6; else // 取下面的点 { // 画水平两点连线(>45度) for (i = x - tx; i <= x + tx; i++) { putpixel(i, y - ty, color); putpixel(i, y + ty, color); } d += 4 * (tx - ty) + 10, ty--; } tx++; } if (tx == ty) // 画水平两点连线(=45度) for (i = x - ty; i <= x + ty; i++) { putpixel(i, y - tx, color); putpixel(i, y + tx, color); } } // 主函数 void main() { // 创建绘图窗口 initgraph(640, 480); // 测试画填充圆 FillCircle_Bresenham(320, 240, 100, GREEN); // 按任意键退出 getch(); closegraph(); }

计算任意扇形的最小外包矩形

今天很偶然需要这样一个东西: 求任意扇形的最小包围矩形,要求矩形的边是水平、垂直的。 这个东西看似很简单,但是仔细一想,需要注意的地方蛮多的,还真有点不好下手。再回想一下,好像没有那本书里面讲过。然后百度了一下,似乎也没找到有效的方法。于是我就花了点时间搞定了这个东西,然后顺手写了一个例子演示效果。 如果您有更好的方法,十分期待交流一下。 以下代码除了包含必要的求解任意扇形的最小包围函数之外,还加上了鼠标操作:按下左键移动鼠标,可以调整终止角的弧度;同时按下 Shift 键移动,可以调整起始角的弧度。 执行效果如图: 完整代码如下: /////////////////////////////////////////////////// // 程序名称:计算扇形的最小包围矩形 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2013霜降版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2013-11-14 // #include <graphics.h> #include <math.h> #include <conio.h> #define PI 3.141592653589 // 求扇形的最小包围矩形 // 参数: // x, y: 圆心 // r: 半径 // a1, a2: 起始角、终止角的弧度 RECT GetPieMinimumRect(int x, int y, int r, double a1, double a2) { // 定义变量 int i; double a; // 规范化弧度,确保起始角小于终止角 if (a1 > a2) a2 += PI * 2; // 计算扇形区域的最小包围矩形 // 方法:获得 7 个点的最大最小值,得到最小包围矩形 // 7 个点包括:圆心、圆弧两端、圆弧与坐标轴的交点(最多 4 个) // 第一步:初始化 7 个点 POINT pt[7]; pt[0].x = x; pt[0].y = y; pt[1].x = int(x + r * cos(a1) + 0.5); pt[1].y = int(y - r * sin(a1) + 0.5); pt[2].x = int(x + r * cos(a2) + 0.5); pt[2].y = int(y - r * sin(a2) + 0.5); for (a = ceil(a1 * 4 / (2 * PI)) * (PI / 2), i = 3; a < a2; a += PI / 2, i++) { pt[i].x = int(x + r * cos(a) + 0.5); pt[i].y = int(y - r * sin(a) + 0.5); } // 第二步:获取 7 个点的最大最小值,得到最小包围矩形 i--; RECT rect = {pt[i].x, pt[i].y, pt[i].x, pt[i].y}; for (--i; i >= 0; i--) { if (pt[i].x < rect.left) rect.left = pt[i].x; if (pt[i].x > rect.right) rect.right = pt[i].x; if (pt[i].y < rect.top) rect.top = pt[i].y; if (pt[i].y > rect.bottom) rect.bottom = pt[i].y; } // 返回最小包围矩形 return rect; } // 获取指定坐标的角度 double GetAngle(int x, int y) { int dx = x - 320; int dy = 240 - y; double a; if (dx == 0 && dy == 0) a = 0; else if (dx != 0 && dy != 0) a = atan((double)(dy) / dx); else if (dx == 0) a = (dy > 0) ? PI / 2 : PI * 3 / 2; else a = 0; if (dx < 0) a += PI; if (a < 0) a += PI * 2; return a; } // 绘制扇形及最小包围矩形 void Draw(double a1, double a2, int r) { cleardevice(); // 绘制扇形 setlinecolor(GREEN); setfillcolor(GREEN); setfillstyle(BS_HATCHED, HS_BDIAGONAL); fillpie(320 - 100, 240 - 100, 320 + 100, 240 + 100, a1, a2); // 绘制矩形 RECT rect = GetPieMinimumRect(320, 240, r, a1, a2); setlinecolor(YELLOW); rectangle(rect.left, rect.top, rect.right, rect.bottom); } // 主程序 void main() { // 创建绘图窗口 initgraph(640, 480); // 初始化 double a1 = 0; // 扇形起始角的弧度 double a2 = PI * 3 / 4; // 扇形终止角的弧度 int r = 100; // 扇形半径 Draw(a1, a2, r); // 绘制初始状态 BeginBatchDraw(); // 启用批量绘图防止闪烁 MOUSEMSG msg; do { // 获取鼠标消息 msg = GetMouseMsg(); if (msg.mkLButton) // 左键按下调整终止角的角度 { // 计算鼠标角度 if (msg.mkShift) // 按下 Shift 键调整起始角的角度 a1 = GetAngle(msg.x, msg.y); else a2 = GetAngle(msg.x, msg.y); // 绘制扇形和最小包围矩形 Draw(a1, a2, r); // 刷新显示 FlushBatchDraw(); } } while(msg.uMsg != WM_RBUTTONUP); // 按鼠标右键退出 // 关闭图形窗口 EndBatchDraw(); closegraph(); }

[图形学] 画圆(基于 Bresenham 算法)

图形学中的 Bresenham 画圆法,以下是该算法的 C 语言实现: /////////////////////////////////////////////////// // 程序名称:基于 Bresenham 算法画圆 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2011惊蛰版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2011-5-3 // #include <graphics.h> #include <conio.h> // 使用 Bresenham 画圆法 void Circle_Bresenham(int x, int y, int r, int color) { int tx = 0, ty = r, d = 3 - 2 * r; while( tx <= ty) { // 利用圆的八分对称性画点 putpixel(x + tx, y + ty, color); putpixel(x + tx, y - ty, color); putpixel(x - tx, y + ty, color); putpixel(x - tx, y - ty, color); putpixel(x + ty, y + tx, color); putpixel(x + ty, y - tx, color); putpixel(x - ty, y + tx, color); putpixel(x - ty, y - tx, color); if (d < 0) // 取上面的点 d += 4 * tx + 6; else // 取下面的点 d += 4 * (tx - ty) + 10, ty--; tx++; } } // 主函数 void main() { initgraph(640, 480); // 测试画圆 Circle_Bresenham(320, 240, 200, RED); Circle_Bresenham(320, 240, 101, RED); // 按任意键退出 getch(); closegraph(); }

[图形学] 画圆(基于正负算法)

图形学中的正负画圆法,以下是该算法的 C 语言实现: /////////////////////////////////////////////////// // 程序名称:基于正负算法画圆 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2011惊蛰版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2011-5-3 // #include <graphics.h> #include <conio.h> // 正负画圆法 void Circle_PN(int x, int y, int r, int color) { int tx = 0, ty = r, f = 0; while(tx <= ty) { // 利用圆的八分对称性画点 putpixel(x + tx, y + ty, color); putpixel(x + tx, y - ty, color); putpixel(x - tx, y + ty, color); putpixel(x - tx, y - ty, color); putpixel(x + ty, y + tx, color); putpixel(x + ty, y - tx, color); putpixel(x - ty, y + tx, color); putpixel(x - ty, y - tx, color); if(f <= 0) f = f + 2 * tx + 1, tx++; else f = f - 2 * ty + 1, ty--; } } // 主函数 void main() { initgraph(640, 480); // 测试画圆 Circle_PN(320, 240, 200, RED); Circle_PN(320, 240, 101, RED); // 按任意键退出 getch(); closegraph(); }

[图形学] 画圆(基于中点算法)

图形学中的中点画圆法,以下是该算法的 C 语言实现: /////////////////////////////////////////////////// // 程序名称:基于中点算法画圆 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2011惊蛰版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2011-4-29 // #include <graphics.h> #include <conio.h> // 中点画圆法 void Circle_Midpoint(int x, int y, int r, int color) { int tx = 0, ty = r, d = 1 - r; while(tx <= ty) { // 利用圆的八分对称性画点 putpixel(x + tx, y + ty, color); putpixel(x + tx, y - ty, color); putpixel(x - tx, y + ty, color); putpixel(x - tx, y - ty, color); putpixel(x + ty, y + tx, color); putpixel(x + ty, y - tx, color); putpixel(x - ty, y + tx, color); putpixel(x - ty, y - tx, color); if(d < 0) d += 2 * tx + 3; else d += 2 * (tx - ty) + 5, ty--; tx++; } } // 主函数 void main() { initgraph(640, 480); // 测试画圆 Circle_Midpoint(320, 240, 200, RED); Circle_Midpoint(320, 240, 101, RED); // 按任意键退出 getch(); closegraph(); }

[图形学] 画任意斜率的直线(基于 Bresenham 算法)

图形学中的 Bresenham 画直线算法,以下是该算法的 C 语言实现: /////////////////////////////////////////////////// // 程序名称:基于 Bresenham 算法画任意斜率的直线 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2011惊蛰版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2011-4-26 // #include <graphics.h> #include <conio.h> // 使用 Bresenham 算法画任意斜率的直线(包括起始点,不包括终止点) void Line_Bresenham(int x1, int y1, int x2, int y2, int color) { int x = x1; int y = y1; int dx = abs(x2 - x1); int dy = abs(y2 - y1); int s1 = x2 > x1 ? 1 : -1; int s2 = y2 > y1 ? 1 : -1; bool interchange = false; // 默认不互换 dx、dy if (dy > dx) // 当斜率大于 1 时,dx、dy 互换 { int temp = dx; dx = dy; dy = temp; interchange = true; } int p = 2 * dy - dx; for(int i = 0; i < dx; i++) { putpixel(x, y, color); if (p >= 0) { if (!interchange) // 当斜率 < 1 时,选取上下象素点 y += s2; else // 当斜率 > 1 时,选取左右象素点 x += s1; p -= 2 * dx; } if (!interchange) x += s1; // 当斜率 < 1 时,选取 x 为步长 else y += s2; // 当斜率 > 1 时,选取 y 为步长 p += 2 * dy; } } // 主函数 void main() { initgraph(640, 480); // 测试画线 Line_Bresenham(100, 1, 1, 478, GREEN); Line_Bresenham(1, 478, 638, 1, GREEN); // 按任意键退出 getch(); closegraph(); }

[图形学] 画任意斜率的直线(基于直线的中点算法)

图形学中的直线的中点算法,以下是该算法的 C 语言实现: /////////////////////////////////////////////////// // 程序名称:基于中点算法画任意斜率的直线 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2011惊蛰版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2011-4-26 // #include <graphics.h> #include <conio.h> // 使用中点算法画任意斜率的直线(包括起始点,不包括终止点) void Line_Midpoint(int x1, int y1, int x2, int y2, int color) { int x = x1, y = y1; int a = y1 - y2, b = x2 - x1; int cx = (b >= 0 ? 1 : (b = -b, -1)); int cy = (a <= 0 ? 1 : (a = -a, -1)); putpixel(x, y, color); int d, d1, d2; if (-a <= b) // 斜率绝对值 <= 1 { d = 2 * a + b; d1 = 2 * a; d2 = 2 * (a + b); while(x != x2) { if (d < 0) y += cy, d += d2; else d += d1; x += cx; putpixel(x, y, color); } } else // 斜率绝对值 > 1 { d = 2 * b + a; d1 = 2 * b; d2 = 2 * (a + b); while(y != y2) { if(d < 0) d += d1; else x += cx, d += d2; y += cy; putpixel(x, y, color); } } } // 主函数 void main() { initgraph(640, 480); // 测试画线 Line_Midpoint(100, 1, 1, 478, GREEN); Line_Midpoint(1, 478, 638, 1, GREEN); // 按任意键退出 getch(); closegraph(); }

[图形学] 画任意斜率的直线(基于 DDA 算法)

图形学中的 DDA 画直线算法,以下是该算法的 C 语言实现: /////////////////////////////////////////////////// // 程序名称:基于 DDA 算法画任意斜率的直线 // 编译环境:Visual C++ 6.0 / 2010,EasyX 2011惊蛰版 // 作  者:yangw80 <yw80@qq.com> // 最后修改:2011-4-26 // #include <graphics.h> #include <conio.h> // 四舍五入 int Round(float x) { return (int)(x < 0 ? x - 0.5 : x + 0.5); } // 使用 DDA 算法画任意斜率的直线(包括起始点,不包括终止点) void Line_DDA(int x1, int y1, int x2, int y2, int color) { float x, y; // 当前坐标点 float cx, cy; // x、y 方向上的增量 int steps = abs(x2 - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1); x = (float)x1; y = (float)y1; cx = (float)(x2 - x1) / steps; cy = (float)(y2 - y1) / steps; for(int i = 0; i < steps; i++) { putpixel(Round(x), Round(y), color); // 在坐标 (x, y) 处画一个 color 颜色的点 x += cx; y += cy; } } // 主函数 void main() { initgraph(640, 480); // 测试画线 Line_DDA(100, 1, 1, 478, GREEN); Line_DDA(1, 478, 638, 1, GREEN); // 按任意键退出 getch(); closegraph(); }

[分形学] Julia Set (茱莉亚集) VC 源代码

关于 Julia Set (茱莉亚集) 的介绍什么的我就不多说了,网上一大堆。执行效果如图: 关于 Julia Set,可以通过设置复数 c 的初值,显示出不同的图案,比如,大家可以试试以下几组: c.re = 0.45, c.im = -0.1428;c.re = 0.285, c.im = 0.01;c.re = 0.285, c.im = 0;c.re = -0.8, c.im = 0.156;c.re = -0.835, c.im = -0.2321;c.re = -0.70176, c.im = -0.3842; 随便用哪行替换掉源程序中的“c.re = -0.75, c.im = 0;”就可以看到不同的图案了。循环变量 k 是迭代次数,在某些参数下需要高一些会更精细。为了美观,还需要修改一下颜色部分,目前代码中的颜色是这样的: HSLtoRGB((float)((k<<5) % 360), 1.0, 0.5)这行代码中的 k 的取值范围是 0~180,将其映射到 HSL 颜色空间中的色相上(360 度)。 全部 VC 源代码如下: // 程序名称:分形学 - Julia Set (茱莉亚集) // 编译环境:Visual C++ 6.0,EasyX 2011惊蛰版 // 最后更新:2010-9-9 // #include <graphics.h> #include <conio.h> ///////////////////////////////////////////////// // 定义复数及乘、加运算 ///////////////////////////////////////////////// // 定义复数 struct COMPLEX { double re; double im; }; // 定义复数“乘”运算 COMPLEX operator * (COMPLEX a, COMPLEX b) { COMPLEX c; c.re = a.re * b.re - a.im * b.im; c.im = a.im * b.re + a.re * b.im; return c; } // 定义复数“加”运算 COMPLEX operator + (COMPLEX a, COMPLEX b) { COMPLEX c; c.re = a.re + b.re; c.im = a.im + b.im; return c; } ///////////////////////////////////////////////// // 主函数 ///////////////////////////////////////////////// void main() { // 初始化绘图窗口 initgraph(640, 480); ///////////////////////////////////////////////// // 绘制 Julia Set (茱莉亚集) ///////////////////////////////////////////////// COMPLEX z, c; c.re = -0.75, c.im = 0; // 设置迭代初值 int x, y, k; // 定义循环变量 for(x = 0; x < 640; x++) { for(y = 0; y < 480; y++) { z.re = -1.6 + 3.2 * (x / 640.0); z.im = -1.2 + 2.4 * (y / 480.0); for(k = 0; k < 180; k++) { if ( z.re * z.re + z.im * z.im > 4.0 ) break; z = z * z + c; } putpixel(x, y, (k >= 180) ? 0 : HSLtoRGB((float)((k << 5) % 360), 1.0, 0.5)); } } // 按任意键退出 getch(); closegraph(); }

[分形学] Mandelbrot Set (曼德布洛特集) VC 源代码

关于 Mandelbrot Set (曼德布洛特集) 的介绍什么的我就不多说了,网上一大堆。执行效果如图: 为了美观,可以修改一下颜色部分,目前代码中的颜色是这样的: HSLtoRGB((float)((k<<5) % 360), 1.0, 0.5) 这行代码中的 k 的取值范围是 0~180,将其映射到 HSL 颜色空间中的色相上(360 度)。 全部 VC 源代码如下: // 程序名称:分形学 - Mandelbrot Set (曼德布洛特集) // 编译环境:Visual C++ 6.0,EasyX 2011惊蛰版 // 最后更新:2010-9-9 // #include <graphics.h> #include <conio.h> ///////////////////////////////////////////////// // 定义复数及乘、加运算 ///////////////////////////////////////////////// // 定义复数 struct COMPLEX { double re; double im; }; // 定义复数“乘”运算 COMPLEX operator * (COMPLEX a, COMPLEX b) { COMPLEX c; c.re = a.re * b.re - a.im * b.im; c.im = a.im * b.re + a.re * b.im; return c; } // 定义复数“加”运算 COMPLEX operator + (COMPLEX a, COMPLEX b) { COMPLEX c; c.re = a.re + b.re; c.im = a.im + b.im; return c; } ///////////////////////////////////////////////// // 主函数 ///////////////////////////////////////////////// void main() { // 初始化绘图窗口 initgraph(640, 480); ///////////////////////////////////////////////// // 绘制 Mandelbrot Set (曼德布洛特集) ///////////////////////////////////////////////// COMPLEX z, c; int x, y, k; // 定义循环变量 for(x = 0; x < 640; x++) { c.re = -2.1 + (1.1 - -2.1) * (x / 640.0); for(y = 0; y < 480; y++) { c.im = -1.2 + (1.2 - -1.2) * (y / 480.0); z.re = z.im = 0; for(k = 0; k < 180; k++) { if ( z.re * z.re + z.im * z.im > 4.0 ) break; z = z * z + c; } putpixel(x, y, (k >= 180) ? 0 : HSLtoRGB((float)((k << 5) % 360), 1.0, 0.5)); } } // 按任意键退出 getch(); closegraph(); }