欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

文章目录

  • 基本变量定义
  • 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画线相关推荐

  1. AK F.*ing leetcode 流浪计划之线段树

    欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 文章目录 零.简介 一.算法原理 树的构建 更新 查询 二.数据结构及算法实现 数据结构 构建 更新 查询 复杂度分析 例题题解 ...

  2. AK F.*ing leetcode 流浪计划之回文串

    欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 文章目录 一.简介 二.解题步骤 三.作用 四.经典算法介绍 判断一个串是否为回文串(单次查询) 普通情况 判断指定字符 多次子 ...

  3. AK F.*ing leetcode 流浪计划之取模

    欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 文章目录 一.简介 二.公式证明 公式 1 公式2 公式3 三.作用 四.注意事项及优化 加(减)法取模 乘法取模 五.牛刀小试 ...

  4. AK F.*ing leetcode 流浪计划之线段求交

    欢迎关注更多精彩 关注我,学习常用算法与数据结构,一题多解,降维打击. 本期话题:2条线段求交点 我有两种线段求交方法. 这两种方法在图形中窗口剪裁中应用. 分别是 Cohen-Suther land ...

  5. 图形学--(中点画线法+Bresenham画线算法)

    编程环境:codeblocks+EGE库 用到的函数:putpixel(int x1,int y1,int color)  用某种颜色打亮一个坐标点. 这俩种算法都是用来在计算机上画一条直线的,那么我 ...

  6. Bresenham画线算法笔记

    目录 一.DDA算法和中点画线算法的回顾 二.Bresenham画线算法 一.DDA算法和中点画线算法的回顾 1.DDA算法(Digtal Differential Analyzer) 假设两个端点坐 ...

  7. Bresenham画线算法的推导

    转自:https://www.cnblogs.com/soroman/archive/2006/07/27/509602.html 以前看到Bresenham画线算法,直接拿来用,没有去推导它,近日, ...

  8. 【计算机图形学】扫面转换算法(DDA算法 中点画线算法 Bresenham画线算法)

    模块1 扫描转换算法 一 实验目的 编写直线.弧线的光栅扫描转换算法,并对线宽与线形的算法加以探讨 用DDA算法.中点画线算法.Bresenham画线算法绘制直线(如果键盘输入数据,给出数据值:如果绘 ...

  9. java bresenham画直线_图形学笔记: Bresenham画线算法

    图形学课本, 按规矩介绍完矩阵行列式, 第一个算法肯定就是Bresenham画线算法了. 來我们來看看算法 Bresenham是用来画一些不反走样的线段的. 都说了线段肯定有起点和终点, 假设我们: ...

最新文章

  1. SQL 2005 中的数据约束
  2. LeetCode 6. ZigZag Conversion
  3. 83. Remove Duplicates from Sorted List
  4. 后台服务器控件点击跳转另一页面显示本页面
  5. HTML5跑酷网页游戏源码
  6. 华三防火墙配置端口地址转换_H3C防火墙配置命令
  7. c#:无限极树形结构
  8. 重启mysql tomcat_linux下MySQL、Tomcat、Redis、Nginx停止和重启
  9. no module named pytz(pycharm)
  10. 验票证明怎么打印_纳税人证明在哪里打印
  11. 计算机图形学中的抗锯齿
  12. 矢量绘图工具 Ipe
  13. OpenCV中踩过的坑系列 01- Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
  14. IGP LDP同步技术剖析
  15. 看大品牌如何玩转小程序
  16. 什么是绿色工厂?什么企业可以申报绿色工厂?
  17. QGis 使用高德 画KML
  18. Git进阶:合并提交记录 git merge --squash
  19. 三、12.13.14.15.编写三角形类Triangle
  20. jacob 详解 语音_Java系列:Java实现文字转语音

热门文章

  1. ubuntu下更改时区_技术|如何在 Ubuntu Linux 中设置或更改时区
  2. 微信小程序(四):通过list列表跳转详情页
  3. aardio - 利用customPlus库+plus构造一个多按钮组件
  4. 乐视TV超级电视今日发布 互联网入侵传统电视
  5. Power BI中使用DAX生动展现人员头像、动态标签——销售数据里的那些商业智能
  6. 微信小游戏为何fillText绘制的文字是模糊的?
  7. 于殿泓 图像检测与处理技术_二手图像检测与处理技术 于殿泓 计算机 西安电子科大学出版社...
  8. Fintech系列(三) -- python对excel操作模块汇总||推荐指数||用法示例
  9. vc访问远程mysql_vc实现对远程SQL Server数据库的访问
  10. 图像的处理以及更改图像色彩模式