AK F.*ing leetcode 流浪计划之Bresenham画线
欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。
文章目录
- 基本变量定义
- Bresenham 推导过程及实现
- 中点法推导
基本变量定义
P1, P2 为要画线段的起终点,P1 = (x1, y1),P2 = (x2, y2)
∆x = x2-x1, ∆y = y2-y1,
m代表直线斜率0<m<1, m = ∆y/∆x
直线方程 y = mx+b
Bresenham 推导过程及实现
假设当前已经画到点Pc(xk,yk),则下一个点只有2种可能(xk+1,yk)或(xk+1,yk+1)假设当前已经画到点 Pc(x_k, y_k), 则下一个点只有2种可能(x_k+1, y_k) 或(x_k+1, y_k+1)假设当前已经画到点Pc(xk,yk),则下一个点只有2种可能(xk+1,yk)或(xk+1,yk+1)
y是直线上xk+1所对应实际的坐标y 是直线上x_k+1 所对应实际的坐标y是直线上xk+1所对应实际的坐标
y=m(xk+1)+by=m (x_k+1)+by=m(xk+1)+b
令dupper=yk+1−y=yk+1−m(xk+1)−b令d_{upper} = y_k+1 - y = y_k+1-m(x_k+1)-b令dupper=yk+1−y=yk+1−m(xk+1)−b
dlower=y−yk=m(xk+1)+b−ykd_{lower} = y-y_k = m (x_k+1)+b-y_kdlower=y−yk=m(xk+1)+b−yk
dlower−dupper=2m(xk+1)−2yk+2b−1d_{lower}-d_{upper} = 2m(x_k+1)-2y_k+2b-1dlower−dupper=2m(xk+1)−2yk+2b−1
pk是决策参数p_k是决策参数pk是决策参数
令pk=∆x(dlower−dupper),由于m=∆y/∆x令p_k = ∆x(d_{lower}-d_{upper}), 由于m = ∆y/∆x令pk=∆x(dlower−dupper),由于m=∆y/∆x
代入式子代入式子代入式子
pk=2∆y(xk+1)−2∆x∗yk+2∆x∗b−∆xp_k = 2∆y(x_k+1)-2∆x*y_k+2∆x*b-∆xpk=2∆y(xk+1)−2∆x∗yk+2∆x∗b−∆x
=2∆y∗xk−2∆x∗yk+2∆y+∆x(2b−1)= 2∆y*x_k-2∆x*y_k+2∆y+∆x(2b-1)=2∆y∗xk−2∆x∗yk+2∆y+∆x(2b−1)
当pk<0时,说明yk离y更近,就取yk;否则,yk+1离y更近,取yk+1.当p_k<0时,说明y_k离y更近,就取y_k; 否则,y_k+1离y更近,取y_k+1.当pk<0时,说明yk离y更近,就取yk;否则,yk+1离y更近,取yk+1.
到此为止我们已经得到下一个点的决策参数。只要依次计算就可以得到所线上的坐标。但是pk的计算中有很多乘法,比较耗时,我们可以通过步进法将其转化成加法来做。具体如下:
将xk+1,yk+1代入式子,可得到将x_{k+1}, y_{k+1}代入式子,可得到将xk+1,yk+1代入式子,可得到
pk+1=2∆y(xk+1)−2∆x∗yk+1+2∆x∗b−∆xp_{k+1}=2∆y(x_{k+1})-2∆x*y_{k+1}+2∆x*b-∆xpk+1=2∆y(xk+1)−2∆x∗yk+1+2∆x∗b−∆x
xk+1=xk+1则pk+1−pk=2∆y−2∆x(yk+1−yk)x_{k+1}=x_k+1则p_{k+1}-p_k = 2∆y-2∆x(y_{k+1}-y_k)xk+1=xk+1则pk+1−pk=2∆y−2∆x(yk+1−yk)
移项得pk+1=pk+2∆y−2∆x(yk+1−yk),移项得p_{k+1} =p_k+ 2∆y-2∆x(y_{k+1}-y_k),移项得pk+1=pk+2∆y−2∆x(yk+1−yk),
这样我们就得到pk的递推式。这样我们就得到p_k的递推式。这样我们就得到pk的递推式。
pk+1=pk+2∆y+{−2∆x,pk>=00,pk<0p_{k+1} =p_k+ 2∆y+\begin{cases} -2∆x, p_k>=0 \\ 0, p_k<0\end{cases}pk+1=pk+2∆y+{−2∆x,pk>=00,pk<0
上述算法中2∆x,2∆y都可以事先算好,后续只要用到加法即可上述算法中2∆x, 2∆y都可以事先算好,后续只要用到加法即可上述算法中2∆x,2∆y都可以事先算好,后续只要用到加法即可
p0计算
将(x0,y0)代入pk表达式得:将(x_0,y_0)代入p_k表达式得:将(x0,y0)代入pk表达式得:
p0=2∆y∗x0−2∆x∗y0+2∆y+∆x(2b−1)p_0 = 2∆y*x_0-2∆x*y_0+2∆y+∆x(2b-1)p0=2∆y∗x0−2∆x∗y0+2∆y+∆x(2b−1)
又因为y0=m∗x0+b=∆y/∆x∗x0+b,代入上式得:又因为 y_0 = m*x_0+b= ∆y/∆x*x_0+b, 代入上式得:又因为y0=m∗x0+b=∆y/∆x∗x0+b,代入上式得:
p0=2∆y∗x0−2∆x∗(∆y/∆x∗x0+b)+2∆y+∆x(2b−1)p_0 = 2∆y*x_0-2∆x*(∆y/∆x*x_0+b)+2∆y+∆x(2b-1)p0=2∆y∗x0−2∆x∗(∆y/∆x∗x0+b)+2∆y+∆x(2b−1)
=2∆y∗x0−2∆y∗x0−2∆x∗b+2∆y+∆x(2b−1)=2∆y*x_0-2∆y*x_0-2∆x*b+2∆y+∆x(2b-1)=2∆y∗x0−2∆y∗x0−2∆x∗b+2∆y+∆x(2b−1)
=2∆y−∆x= 2∆y-∆x=2∆y−∆x
上述只是讲了0<m<1的算法,对于-1<m<0可以直接对称过去。
对于|m|>1的情况可以把x,y 互换。
对于m=0, 无穷大的情况也适用。
代码实现
#include "glew/2.2.0_1/include/GL/glew.h"
#include "glfw/3.3.4/include/GLFW/glfw3.h"
#include <iostream>
using namespace std;void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{//如果按下ESC,把windowShouldClose设置为True,外面的循环会关闭应用if(key==GLFW_KEY_ESCAPE && action == GLFW_PRESS)glfwSetWindowShouldClose(window, GL_TRUE);std::cout<<"ESC"<<mode;
}class Point {public:int x, y;Point(int xx, int yy):x(xx), y(yy){}
};void setPixel(Point p) {// cout<<p.x<<","<<p.y<<endl;glBegin(GL_POINTS);glVertex2i(p.x, p.y);glEnd();glFlush();
}/** 简单Bresenham 算法* 只处理|m|>1*/
void LineBres_2(Point p1, Point p2) {// 保持从下往上画if(p2.y<p1.y) {Point t = p2;p2=p1;p1=t;}int deltaX = abs(p2.x-p1.x), deltaY = abs(p2.y-p1.y);int p0 = 2*deltaX-deltaY;int twDeltaX = 2*deltaX, twDeltaXmTwoDeltaY = 2*deltaX-2*deltaY;int step = 0;if(deltaX>0) step = (p2.x-p1.x) / deltaX;setPixel(p1);for (; p1.y < p2.y;) {p1.y++;if(p0<0) {p0+=twDeltaX;} else {p0+=twDeltaXmTwoDeltaY;p1.x+=step;}setPixel(p1);cout<<p1.x<<","<<p1.y<<endl;}}/** 简单Bresenham 算法* 只处理|m|<=1*/
void LineBres_1(Point p1, Point p2) {// 保持从左到右画if(p2.x<p1.x) {Point t = p2;p2=p1;p1=t;}int deltaX = abs(p2.x-p1.x), deltaY = abs(p2.y-p1.y);if(deltaX<deltaY) {LineBres_2(p1, p2);return;}int p0 = 2*deltaY-deltaX;int twDeltaY = 2*deltaY, twDeltaYmTwoDeltaX = 2*deltaY-2*deltaX;int step = 0;if(deltaY>0) step = (p2.y-p1.y) / deltaY;setPixel(p1);for (; p1.x < p2.x;) {p1.x++;if(p0<0) {p0+=twDeltaY;} else {p0+=twDeltaYmTwoDeltaX;p1.y+=step;}setPixel(p1);cout<<p1.x<<","<<p1.y<<endl;}}int main(void) {//初始化GLFW库if (!glfwInit())return -1;//创建窗口以及上下文GLFWwindow *window = glfwCreateWindow(400, 400, "hello world", NULL, NULL);if (!window) {//创建失败会返回NULLglfwTerminate();}//建立当前窗口的上下文glfwMakeContextCurrent(window);glfwSetKeyCallback(window, key_callback); //注册回调函数//glViewport(0, 0, 400, 400);gluOrtho2D(-200, 200.0, -200, 200.0);//循环,直到用户关闭窗口cout<<123<<endl;while (!glfwWindowShouldClose(window)) {/*******轮询事件*******/glfwPollEvents();// cout<<456<<endl;//选择清空的颜色RGBAglClearColor(0, 0, 0, 1);glClear(GL_COLOR_BUFFER_BIT);// glColor3f(0,0, 0);glMatrixMode(GL_PROJECTION);LineBres_1(Point(0,0),Point(100,70));LineBres_1(Point(0,0),Point(100,-70));LineBres_1(Point(0,0),Point(70,100));LineBres_1(Point(0,0),Point(-70,100));LineBres_1(Point(0,0),Point(-100,70));LineBres_1(Point(0,0),Point(-70,-100));LineBres_1(Point(0,0),Point(-100,-70));LineBres_1(Point(0,0),Point(70,-100));LineBres_1(Point(0,0),Point(0,100));LineBres_1(Point(0,0),Point(0,-100));LineBres_1(Point(0,0),Point(100,0));LineBres_1(Point(0,0),Point(-100,0));LineBres_1(Point(0,0),Point(0,0));/******交换缓冲区,更新window上的内容******/glfwSwapBuffers(window);//break;}glfwTerminate();return 0;
}
中点法推导直线(0<m<1)决策参数,并表示与Bresenham里的参数相同
中点法推导
定义F(x,y)=mx−y+b,m定义与上面相同定义F(x,y) = mx-y+b, m定义与上面相同定义F(x,y)=mx−y+b,m定义与上面相同
根据直线方程定义当F(xk+1,yk+12)>0时,说明中点在线的上方,此时画(xk+1,yk),否则画(xk+1,yk+1)根据直线方程定义当F(x_k+1,y_k+\frac12)>0时,说明中点在线的上方,此时画(x_k+1,y_k), 否则画(x_k+1,y_k+1)根据直线方程定义当F(xk+1,yk+21)>0时,说明中点在线的上方,此时画(xk+1,yk),否则画(xk+1,yk+1)
令决策参数pk=2∆x∗F(xk+1,yk+12)(为什么要乘以2∆x,我先用2∆x推导了一遍发现的)令决策参数p_k=2∆x*F(x_k+1, y_k+\frac{1}{2})(为什么要乘以2∆x, 我先用2∆x推导了一遍发现的)令决策参数pk=2∆x∗F(xk+1,yk+21)(为什么要乘以2∆x,我先用2∆x推导了一遍发现的)
=2∆x∗(m∗(xk+1)−(yk+12)+b)=2∆x*(m*(x_k+1)-(y_k+\frac{1}{2})+b)=2∆x∗(m∗(xk+1)−(yk+21)+b)
=2∆y∗(xk+1)−2∆x∗yk+∆x∗(2b−1)=2∆y*(x_k+1) -2∆x*y_k + ∆x*(2b-1)=2∆y∗(xk+1)−2∆x∗yk+∆x∗(2b−1)
pk+1=2∆y∗(xk+1+1)−2∆x∗yk+1+∆x∗(2b−1)p_{k+1}=2∆y*(x_k+1+1) -2∆x*y_{k+1} + ∆x*(2b-1)pk+1=2∆y∗(xk+1+1)−2∆x∗yk+1+∆x∗(2b−1)
pk+1−pk=2∆y+{−2∆x,pk<=00,pk>0p_{k+1} - p_k = 2∆y+\begin{cases}-2∆x, p_k<=0\\0, p_k>0\end{cases}pk+1−pk=2∆y+{−2∆x,pk<=00,pk>0
p0=2∆y∗(x0+1)−2∆x∗(m∗x0+b)+∆x∗(2b−1)=2∆y−∆xp_0=2∆y*(x_0+1) -2∆x*(m*x_0+b) + ∆x*(2b-1)=2∆y-∆xp0=2∆y∗(x0+1)−2∆x∗(m∗x0+b)+∆x∗(2b−1)=2∆y−∆x
可以看出p_k的增量是与Bresenham相同的。
这也解释了我当时的疑惑:为什么没有中点法画线
AK F.*ing leetcode 流浪计划之Bresenham画线相关推荐
- AK F.*ing leetcode 流浪计划之线段树
欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 文章目录 零.简介 一.算法原理 树的构建 更新 查询 二.数据结构及算法实现 数据结构 构建 更新 查询 复杂度分析 例题题解 ...
- AK F.*ing leetcode 流浪计划之回文串
欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 文章目录 一.简介 二.解题步骤 三.作用 四.经典算法介绍 判断一个串是否为回文串(单次查询) 普通情况 判断指定字符 多次子 ...
- AK F.*ing leetcode 流浪计划之取模
欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 文章目录 一.简介 二.公式证明 公式 1 公式2 公式3 三.作用 四.注意事项及优化 加(减)法取模 乘法取模 五.牛刀小试 ...
- AK F.*ing leetcode 流浪计划之线段求交
欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 本期话题:2条线段求交点 我有两种线段求交方法. 这两种方法在图形中窗口剪裁中应用. 分别是 Cohen-Suther land ...
- 图形学--(中点画线法+Bresenham画线算法)
编程环境:codeblocks+EGE库 用到的函数:putpixel(int x1,int y1,int color) 用某种颜色打亮一个坐标点. 这俩种算法都是用来在计算机上画一条直线的,那么我 ...
- Bresenham画线算法笔记
目录 一.DDA算法和中点画线算法的回顾 二.Bresenham画线算法 一.DDA算法和中点画线算法的回顾 1.DDA算法(Digtal Differential Analyzer) 假设两个端点坐 ...
- Bresenham画线算法的推导
转自:https://www.cnblogs.com/soroman/archive/2006/07/27/509602.html 以前看到Bresenham画线算法,直接拿来用,没有去推导它,近日, ...
- 【计算机图形学】扫面转换算法(DDA算法 中点画线算法 Bresenham画线算法)
模块1 扫描转换算法 一 实验目的 编写直线.弧线的光栅扫描转换算法,并对线宽与线形的算法加以探讨 用DDA算法.中点画线算法.Bresenham画线算法绘制直线(如果键盘输入数据,给出数据值:如果绘 ...
- java bresenham画直线_图形学笔记: Bresenham画线算法
图形学课本, 按规矩介绍完矩阵行列式, 第一个算法肯定就是Bresenham画线算法了. 來我们來看看算法 Bresenham是用来画一些不反走样的线段的. 都说了线段肯定有起点和终点, 假设我们: ...
最新文章
- SQL 2005 中的数据约束
- LeetCode 6. ZigZag Conversion
- 83. Remove Duplicates from Sorted List
- 后台服务器控件点击跳转另一页面显示本页面
- HTML5跑酷网页游戏源码
- 华三防火墙配置端口地址转换_H3C防火墙配置命令
- c#:无限极树形结构
- 重启mysql tomcat_linux下MySQL、Tomcat、Redis、Nginx停止和重启
- no module named pytz(pycharm)
- 验票证明怎么打印_纳税人证明在哪里打印
- 计算机图形学中的抗锯齿
- 矢量绘图工具 Ipe
- OpenCV中踩过的坑系列 01- Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
- IGP LDP同步技术剖析
- 看大品牌如何玩转小程序
- 什么是绿色工厂?什么企业可以申报绿色工厂?
- QGis 使用高德 画KML
- Git进阶:合并提交记录 git merge --squash
- 三、12.13.14.15.编写三角形类Triangle
- jacob 详解 语音_Java系列:Java实现文字转语音
热门文章
- ubuntu下更改时区_技术|如何在 Ubuntu Linux 中设置或更改时区
- 微信小程序(四):通过list列表跳转详情页
- aardio - 利用customPlus库+plus构造一个多按钮组件
- 乐视TV超级电视今日发布 互联网入侵传统电视
- Power BI中使用DAX生动展现人员头像、动态标签——销售数据里的那些商业智能
- 微信小游戏为何fillText绘制的文字是模糊的?
- 于殿泓 图像检测与处理技术_二手图像检测与处理技术 于殿泓 计算机 西安电子科大学出版社...
- Fintech系列(三) -- python对excel操作模块汇总||推荐指数||用法示例
- vc访问远程mysql_vc实现对远程SQL Server数据库的访问
- 图像的处理以及更改图像色彩模式