图形学Bresenham
1 Bresenham直线
1.1 起始条件
终点坐标
起始点坐标
通过终点坐标和起始点坐标可以得到直线方程:
KaTeX parse error: Undefined control sequence: \label at position 8: y=kx+b\̲l̲a̲b̲e̲l̲{1}\tag{1}
然后选定主位移方向:
{X轴∣k∣<1Y轴∣k∣>1(2)\begin{cases} X\text{轴}& \left|k\right|<1\\\tag{2} Y\text{轴}& \left|k\right|>1\\ \end{cases} {X轴Y轴∣k∣<1∣k∣>1(2)
1.2 构造中点误差项
从Pi(xi,yi)P_i(\text{x}_i,\text{y}_i)Pi(xi,yi)点走第一步后为了选取下一个像素点,需将PuP_uPu和PdP_dPd的中点M(xi+1,yi+0.5)M(\text{x}_i+1,\text{y}_i+0.5)M(xi+1,yi+0.5)带入直线的隐函数方程,构造中点误差项did_idi
di=F(xM,yM)=F(xi+1,yi+0.5)=yi+0.5−k(xi+1)−b(3)d_i=F(x_{_M},y_{_M})=F(x_i+1,y_i+0.5)=y_i+0.5-k(x_i+1)-b\tag{3} di=F(xM,yM)=F(xi+1,yi+0.5)=yi+0.5−k(xi+1)−b(3)
根据did_idi判断选择下一个点为PuP_uPu还是PdP_dPd
yi+1={yi+1,di<0yi,di⩾0(4)y_{i+1}= \begin{cases} y_{i}+1,& d_i<0\\\tag{4} y_i,& d_i\geqslant0 \end{cases} yi+1={yi+1,yi,di<0di⩾0(4)
1.3 递推公式☆
1.3.1 中点误差项的递推公式
- 当di<0d_i<0di<0时,下一步进行判断的中点坐标为M(xi+2,yi+1.5)M(x_i+2,y_i+1.5)M(xi+2,yi+1.5)。所以下一步中点误差项为:
di+1=F(xi+2,yi+1.5)=yi+1.5−k(xi+2)−b=yi+0.5−k(xi+1)−b+1−k=di+1−k(5)\begin{aligned} d_{i+1}&=F(x_i+2,y_i+1.5)=y_i+1.5-k(x_i+2)-b\\ &=y_i+0.5-k(x_i+1)-b+1-k\\ &=d_i+1-k \end{aligned}\tag{5} di+1=F(xi+2,yi+1.5)=yi+1.5−k(xi+2)−b=yi+0.5−k(xi+1)−b+1−k=di+1−k(5)
- 当di⩾0d_i\geqslant0di⩾0时,下一步的中点坐标为M(xi+2,yi+0.5)M(x_i+2,y_i+0.5)M(xi+2,yi+0.5)。所以下一步中点误差项为:
di+1=F(xi+2,yi+0.5)=yi+0.5−k(xi+2)−b=yi+0.5−k(xi+1)−b−k=di−k(6)\begin{aligned} d_{i+1}&=F(x_i+2,y_i+0.5)=y_i+0.5-k(x_i+2)-b\\ &=y_i+0.5-k(x_i+1)-b-k\\ &=d_i-k \end{aligned}\tag{6} di+1=F(xi+2,yi+0.5)=yi+0.5−k(xi+2)−b=yi+0.5−k(xi+1)−b−k=di−k(6)
1.3.2 中点误差项的初始值
假设以xxx为主位移方向。因此,第一个中点坐标是(x0+1,y0+0.5)(x_0+1,y_0+0.5)(x0+1,y0+0.5),相应的did_idi的初始值为:
d0=F(x0+1,y0+0.5)=y0+0.5−k(x0+1)−b=y0−kx0−b−k+0.5(7)\begin{aligned} d_0&=F(x_0+1,y_0+0.5)=y_0+0.5-k(x_0+1)-b\\ &=y_0-kx_0-b-k+0.5 \end{aligned}\tag{7} d0=F(x0+1,y0+0.5)=y0+0.5−k(x0+1)−b=y0−kx0−b−k+0.5(7)
其中,因此(x0,y0)(x0,y_0)(x0,y0)在直线上,所以y0−kx0−b=0y_0-kx_0-b=0y0−kx0−b=0,则
di=0.5−k(8)d_i=0.5-k\tag{8} di=0.5−k(8)
1.4 算法流程图
1.5 代码
void CMFCApplication1View::DrawLine(CDC* pDC, int x1, int y1, int x2, int y2)
{// TODO: 在此处添加实现代码.int dx = x2 - x1;int dy = y2 - y1;int deltaY = 0;int middle = dx;int y = y1;for (int i = x1;i < x2;i++) {pDC->SetPixel(i, y, RGB(30, 30, 30));deltaY += 2 * dy;if (deltaY >= middle) {y += 1;middle += 2 * dx;}}pDC->SetPixel(x2, y2, RGB(30, 30, 30));
}
1.6
void CMFCApplication1View::DrawLine(int x1, int y1, int x2, int y2, CDC* pDC){// TODO: 在此处添加实现代码.int dx = x2 - x1;int dy = y2 - y1;int di = 2*dx - 2*dy;int y = y1;for (int i = x1; i < x2; i++) {pDC->SetPixel(i, y, RGB(30, 30, 30));if (di < 0){di = di + 2 * (dx - dy);y++;}else{di = di - 2 * dy;}}
}
2 Bresenham圆
圆只需要画18\frac{1}{8}81的圆弧就行了,剩下的圆弧可以通过对称得到。
2.1 起始条件
- 半径R
- 起始点(x,y)
主位移方向为X轴方向
2.2 构造中点误差项
从Pi(xi,yi)P_i(\text{x}_i,\text{y}_i)Pi(xi,yi)点走第一步后为了选取下一个像素点,需将PuP_uPu和PdP_dPd的中点M(xi+1,yi+0.5)M(\text{x}_i+1,\text{y}_i+0.5)M(xi+1,yi+0.5)带入圆的隐函数方程,构造中点误差项did_idi
di=F(xM,yM)=F(xi+1,yi−0.5)=(xi+1)2+(yi−0.5)2−R2(9)d_i=F(x_{_M},y_{_M})=F(x_i+1,y_i-0.5)=(x_i+1)^2+(y_i-0.5)^2-R^2\tag{9} di=F(xM,yM)=F(xi+1,yi−0.5)=(xi+1)2+(yi−0.5)2−R2(9)
根据did_idi判断选择下一个点为PuP_uPu还是PdP_dPd
yi+1={yi,di<0yi−1,di⩾0(10)y_{i+1}= \begin{cases} y_{i},& d_i<0\\\tag{10} y_i-1,& d_i\geqslant0 \end{cases} yi+1={yi,yi−1,di<0di⩾0(10)
2.3 递推公式☆
2.3.1 中点误差项的递推公式
- 当di<0d_i<0di<0时,下一步进行判断的中点坐标为M(xi+2,yi−0.5)M(x_i+2,y_i-0.5)M(xi+2,yi−0.5)。所以下一步中点误差项为:
di+1=F(xi+2,yi−0.5)=(xi+2)2+(yi−0.5)2−R2=(xi+1)2+(yi−0.5)2−R2+2xi+3=di+2xi+3(11)\begin{aligned} d_{i+1}&=F(x_i+2,y_i-0.5)=(x_i+2)^2+(y_i-0.5)^2-R^2\\ &=(x_i+1)^2+(y_i-0.5)^2-R^2+2x_i+3\\ &=d_i+2x_i+3 \end{aligned}\tag{11} di+1=F(xi+2,yi−0.5)=(xi+2)2+(yi−0.5)2−R2=(xi+1)2+(yi−0.5)2−R2+2xi+3=di+2xi+3(11)
当di⩾0d_i\geqslant0di⩾0时,下一步的中点坐标为M(xi+2,yi−1.5)M(x_i+2,y_i-1.5)M(xi+2,yi−1.5)。所以下一步中点误差项为:
di+1=F(xi+2,yi−1.5)=(xi+2)2+(yi−1.5)2−R2=(xi+1)2+(yi−0.5)2−R2+2xi+3+(−2yi+2)=di+2(xi−yi)+5(12)\begin{aligned} d_{i+1}&=F(x_i+2,y_i-1.5)=(x_i+2)^2+(y_i-1.5)^2-R^2\\ &=(x_i+1)^2+(y_i-0.5)^2-R^2+2x_i+3+(-2y_i+2)\\ &=d_i+2(x_i-y_i)+5 \end{aligned}\tag{12} di+1=F(xi+2,yi−1.5)=(xi+2)2+(yi−1.5)2−R2=(xi+1)2+(yi−0.5)2−R2+2xi+3+(−2yi+2)=di+2(xi−yi)+5(12)
2.3.2 中点误差项的初始值
以xxx为主位移方向。因此,第一个中点坐标是(1,R−0.5)(1,R-0.5)(1,R−0.5),相应的did_idi的初始值为:
d0=F(1,R−0.5)=1+(R−0.5)2−R2=1.25−R(13)\begin{aligned} d_0&=F(1,R-0.5)=1+(R-0.5)^2-R^2=1.25-R \end{aligned}\tag{13} d0=F(1,R−0.5)=1+(R−0.5)2−R2=1.25−R(13)
2.4 算法流程图
2.5 代码
void CMFCApplication1View::BreCircle(int x0, int y0, int R, CDC* pDC)
{// TODO: 在此处添加实现代码.int x = x0;int y = R;float di = 1.25 - R;while (x <= y) {CirclePoint(pDC, x, y);pDC->SetPixel(x, y, RGB(30, 30, 30));if (di <= 0) {di = di + 2 * x + 3;x += 1;}else {di = di + 2 * (x - y) + 5;x += 1;y -= 1;}}
}
3 Bresenham椭圆
3.1 起始条件
- 长半轴a
- 短半轴b
椭圆画出14\frac{1}{4}41的圆弧的就行了,其他三个圆弧可以通过对称得到。但是第一个圆弧的主位移方向会发生变化,需要分情况讨论。我们通过法矢量的两个分量进行讨论。
椭圆上任意一点的处的法矢量:
KaTeX parse error: Undefined control sequence: \symbfit at position 80: …tial{y}}j=2b^2x\̲s̲y̲m̲b̲f̲i̲t̲{i}+2a^2y\symbf…
确定主位移方向:
{X轴,2b2x≥2a2yY轴,2b2x<2a2y(15)\begin{cases} X轴,& 2b^2x≥2a^2y\\ Y轴,& 2b^2x<2a^2y\tag{15} \end{cases} {X轴,Y轴,2b2x≥2a2y2b2x<2a2y(15)
3.2 构造中点误差项及递推式☆
3.2.1 上半部分的中点误差项初始值
上半部分椭圆弧的起点坐标为A(0,b)A(0,b)A(0,b),因此,第一个中点坐标为(1,b−0.5)(1,b-0.5)(1,b−0.5),对应的d1id_1id1i的初始值为:
d1i=F(1,b−0.5)=b2+a2(−b+0.25)(16)d_1i=F(1,b-0.5)=b^2+a^2(-b+0.25)\tag{16} d1i=F(1,b−0.5)=b2+a2(−b+0.25)(16)
3.2.2 上半部分中点误差项递推式
KaTeX parse error: Undefined control sequence: \textless at position 100: …(2x_i+3)&d_{1i}\̲t̲e̲x̲t̲l̲e̲s̲s̲0\tag{17} \end{…
yi+1={yi,di<0yi−1,di⩾0(18)y_{i+1}= \begin{cases} y_{i},& d_i<0\\\tag{18} y_i-1,& d_i\geqslant0 \end{cases} yi+1={yi,yi−1,di<0di⩾0(18)
3.2.1 下半部分的中点误差项初始值
d2i=F(xM,yM)=b2(xi+0.5)2+a2(yi−1)2−a2b2(19)d_{2i}=F(x_{_M},y_{_M})=b^2(x_i+0.5)^2+a^2(y_i-1)^2-a^2b^2\tag{19} d2i=F(xM,yM)=b2(xi+0.5)2+a2(yi−1)2−a2b2(19)
3.2.2 下半部分中点误差项递推式
KaTeX parse error: Undefined control sequence: \textless at position 101: …-2y_i+3)&d_{2i}\̲t̲e̲x̲t̲l̲e̲s̲s̲0\tag{20} \end{…
yi+1={yi,di<0yi−1,di⩾0(21)y_{i+1}= \begin{cases} y_{i},& d_i<0\\\tag{21} y_i-1,& d_i\geqslant0 \end{cases} yi+1={yi,yi−1,di<0di⩾0(21)
3.3 算法流程图
3.4 代码
void CMFCApplication1View::BreEllipse(CDC* pDC,int a,int b) {int x0 = 0;int y0 = b;float di1 = b * b + a * a * (-b + 0.25);int x = x0;int y = y0;int dx = 2 * b * b * x;int dy = 2 * a * a * y;while (dy>=dx){if (di1 < 0) {di1 = di1 + b * b * (2 * x + 3);x = x + 1;y = y;}else {di1 = di1 + b * b * (2 * x + 3) + a * a * (2 - 2 * y);x = x + 1;y = y - 1;}dx = 2 * b * b * x;dy = 2 * a * a * y;EllipsePoint(pDC, x, y);}float di2 = b * b * (x + 0.5) * (x + 0.5) + a * a * (y - 1) * (y - 1) - a * a * b * b;while (y>=0) {if (di2 < 0) {di2 = di2 + b * b * (2 * x + 2) + a * a * (3 - 2 * y);x = x + 1;y = y - 1;}else{di2 = di2 + a * a * (3 - 2 * y);x = x;y = y - 1;}EllipsePoint(pDC, x, y);}
}
4 Wu反走样算法
4.1 原理
对上下的两个点同时绘制,根据距离设置不同亮度
Pu亮度Pd亮度=DistancePuFiDistancePdFi\frac{P_u亮度}{P_d亮度}=\frac{Distance_{_{P_uF_i}}}{Distance_{_{P_dF_i}}} Pd亮度Pu亮度=DistancePdFiDistancePuFi
4.2 算法流程图
4.3 代码
void CMFCApplication1View::WuLine(CDC *pDC,int x1,int y1,int x2,int y2) {float k = (y2 - y1) * 1.0 / (x2 - x1);float deltae = k;int y = y1;pDC->SetPixel(x1, y1, RGB(0, 0, 0));for (int i = x1+1;i <= x2-1;i++) {if (deltae <= 0.5) {y = y;pDC->SetPixel(i, y, RGB(deltae * 255, deltae * 255, deltae * 255));pDC->SetPixel(i, y+1, RGB((1-deltae) * 255, (1 - deltae) * 255, (1 - deltae) * 255));}else {y = y + 1;pDC->SetPixel(i, y, RGB((1 - deltae) * 255, (1 - deltae) * 255, (1 - deltae) * 255));pDC->SetPixel(i, y - 1, RGB(deltae * 255, deltae * 255, deltae * 255));}deltae = deltae + k;if (deltae > 1) {deltae -= 1;}}pDC->SetPixel(x2, y2, RGB(0, 0, 0));}
5 重建坐标系
//将坐标系移到中点
CRect rect;
GetClientRect(rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(), rect.Height());
pDC->SetViewportExt(rect.Width(), -rect.Height());
pDC->OffsetViewportOrg(rect.Width() / 2, rect.Height() / 2);
GetClientRect(rect);//获取指定窗口的客户区域大小
pDC->SetMapMode(MM_ANISOTROPIC);//设备视图和逻辑视图可以任意改变
pDC->SetWindowExt(rect.Width(), rect.Height());//逻辑范围
pDC->SetViewportExt(rect.Width(), -rect.Height());//设备范围,以及Y轴方向
pDC->OffsetViewportOrg(rect.Width() / 2, rect.Height() / 2);//视图中心偏移
//以物理设置坐标原点为基础(显示作用),以逻辑为单位(逻辑用于按比例设置单位)
5.1 参考资料
SetWindowExt和SetViewportExt
SetWindowOrg,SetViewportOrg,SetWindowExt,SetViewportExt
SetWindowExt和SetViewportExt
逻辑坐标,设备坐标,窗口,视口
关于映射方式MM_ANISOTROPIC的几个函数详解
GetClientRect用法
SetWindowExt() 与SetViewportExt()
mfc编程中SetViewportOrg与SetWindowOrg的理解
逻辑坐标与设备坐标——全窗口坐标、屏幕坐标、客户区坐标的总结
6 如何在MFC中添加自定义函数
方法一
在类视图中,选择view,然后添加函数
方法二
在view.h的头文件添加声明
在view.cpp文件中添加函数体定义和调用
的几个函数详解](https://blog.csdn.net/zhandeen/article/details/8223747)
GetClientRect用法
SetWindowExt() 与SetViewportExt()
mfc编程中SetViewportOrg与SetWindowOrg的理解
逻辑坐标与设备坐标——全窗口坐标、屏幕坐标、客户区坐标的总结
6 如何在MFC中添加自定义函数
方法一
在类视图中,选择view,然后添加函数
方法二
在view.h的头文件添加声明
在view.cpp文件中添加函数体定义和调用
图形学Bresenham相关推荐
- 计算机图形学 Bresenham直线生成算法
bresenham算法是一种光栅化的直线生成算法,是计算机图形学目前使用广泛的直线扫描转换算法,具体逻辑很简单,就是描点.所以bresenham的算法研究实际上是研究目标点的选择. 实验环境: ope ...
- 中点Bresenham画圆算法|MFC|计算机图形学
中点Bresenham画圆算法|MFC|计算机图形学 Bresenham中点画圆算法 计算机图形学-基本图元的生成-圆 基于学习直线的生成算法后,又展开了圆.椭圆的讲解: 此次试验是简单的MFC应用, ...
- 布兰森汉姆画圆matlab,bresenham算法画直线
实验一名称:基本图形的生成算法 要求:(1)掌握 DDA 生成线段算法 (2)掌握 Bresenham 生成线段算法 (3)掌握生成圆弧算法 1. 代码 (1) Bresenham 画线算法 v 实验 ...
- 计算机图形学E2——OpenGL Bresenham算法画直线
其他计算机图形学实验见 链接 要求 使用Bresemham算法画直线,并且通过鼠标可以实现交互操作 参考代码: 代码1 代码2 代码3(代码好理解) 代码4(讲解很全面) #include<io ...
- [XJTUSE]计算机图形学第二章作业,使用OpenGL编程实现DDA、中点画线和Bresenham算法和中点画圆法
首先是Windows10 + Visual Studio 2019 搭建OpenGL环境可以查看如下链接: 萌新向!!!Windows10 + Visual Studio 2019 搭建OpenGL环 ...
- 计算机图形学直线线型实验报告,计算机图形学实验报告-直线中点bresenham算法的实现资料.doc...
计算机图形学实验报告-直线中点bresenham算法的实现资料.doc (10页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 29.90 积分 计算机图形 ...
- 计算机图形学 学习笔记(一):概述,直线扫描转换算法:DDA,中点画线算法,Bresenham算法
前言 本笔记基于 http://www.icourse163.org/learn/CAU-45006?tid=1001746004#/learn/announce 感谢中国农大 赵明老师的分享~ 现在 ...
- 计算机图形学学习(一) 直线Bresenham算法讲解及matlab实现
文章目录 Bresenham算法介绍 Bresenham算法实现 matlab代码实现 成果演示 最后 Bresenham算法介绍 Bresenham是计算机图形学领域使用最广泛的直线扫描转换算法,其 ...
- 【计算机图形学】小白谈计算机图形学(二)画圆篇之中点画圆法,Bresenham画圆算法,椭圆实操,线型处理详解
小白谈计算机图形学(二)画圆篇之中点画圆法,Bresenham画圆算法,椭圆实操,线型处理详解 引言 如何画圆 基本思想 中点画圆法 中点画圆基本思路 中点画圆改进 Bresenham画圆算法 Bre ...
最新文章
- 为什么我们要做三份 Webpack 配置文件
- 浅探C指针(一)--初识指针
- C++——《算法分析与设计》实验报告——箱子装载问题
- 赫夫曼编码-译码器(Huffman Coding)
- Flume实操(四)【单数据源多出口案例(选择器)】
- C++描述杭电OJ 2015.偶数求和 ||
- 线性代数拾遗(一):线性方程组、向量方程和矩阵方程
- pythonsocket中tcp通信接收不到数据_TCP 为什么三次握手而不是两次握手(正解版)...
- w10无法连到家庭组计算机,一键W10装机版无法进入家庭组如何处理
- “支付功能”怎么测试?
- endnotex7怎么导入中文文献,EndNote 7.0使用中文详细教程
- “深度学习”是人工智能的一场革命吗?
- heavy dark--读《《暗时间》》
- flask-基于pdf.js的pdf在线阅读
- 怎样解决“在禁用UAC时,无法激活此应用”问题
- 证书与签名(二):数字签名流程与签名认证流程
- SQL Server建库建表命令
- α-IoU | 再助YOLOv5登上巅峰,造就IoU Loss大一统
- 获取招聘网站下的HR-Email信息
- vps虚拟服务器主机,vps虚拟服务器主机
热门文章
- ubuntu kworker占用空间太大
- mysql 聚合函数求平均数_MySQL教程63-MySQL 聚合函数
- OBS如何同步推流多个平台?
- 达梦两个表模糊查询_TableStore:爬虫数据存储和查询利器
- SQLServer入门基础(SQL语句)
- CSS之 块、行内、行内块元素
- 从核心概念和技术层面着眼,系统化认识RPC 2017-09-26 张旭 InfoQ 作者|张旭 编辑|田光 RPC(Remote Procedure Call),即远程过程调用,是一个分布式系统间
- 金山卫士界面源码解读及界面库分离 (5)
- JavaWeb · Servlet 问卷调查填写与统计 (MySQL协同)
- c语言输出7 和7 的倍数