图形学课本, 按规矩介绍完矩阵行列式, 第一个算法肯定就是Bresenham画线算法了.

來我们來看看算法

Bresenham是用来画一些不反走样的线段的. 都说了线段肯定有起点和终点, 假设我们:

(xf, yf) ==[LINETO]==> (xt, yt)

按照一些初中(好像是初中吧忘了)的几何, 这条直线的方程是:

yt - yf

y - yf = --------- (x - xf)

xt - xf

好我们來变一下型. 首先恶心的除号就拿掉. 然后令dy = yt - yf, dx = xt - xf:

(y - yf)(xt - xf) = (x - xf)(yt - yf)

y dx - yf dx = x dy - xf dy

到这里我们可以想想这个直线可以怎样画了. 对于一条斜率在1以下的直线, 相邻两点要么是同一行, 要么是斜角. 也就是说, 当前点是(x, y)的话, 下一个点要么是(x+1, y), 要么是(x+1, y+1).

^ ,------ This is the CURRENTLY drawn pixel.

| V _

| _|_|

| |_|_|

|

+-------->

设一个判别式 f(x, y) = x dy - y dx + yf dx - xf dy, 留意到 dx > 0且dy > 0. 所以, 如果f(x, y) < 0, 说明y太大了, (x, y)在直线上方. 反之f(x, y) > 0, 说明x太大了.

^

|

|####/:::

|###/:::: #. Area where f(x, y) < 0

|##/::::: :. Area where f(x, y) > 0

|#/:::::: /. Points on the line meet f(x, y) = 0

+/-------->

/

接下来的就耳熟能详了, 比较右边的点和右上的点的f(x, y), 画小的那个. 包含进上一次 image.h 那个头文件, 然后就写出第一个画线函数:

cppvoid bresenham_1(int xf, int yf, int xt, int yt, const color& c, image& img)

{

auto f = [&](int x, int y) {

int dx = xt - xf;

int dy = yt - yf;

return x*dy - y*dx + yf*dx - xf*dy; };

for(int x = xf, y = yf; x <= xt; x++) {

if(abs(f(x, y)) - abs(f(x, y+1)) < 0)

img(x, y) = c;

else img(x, ++y) = c;

}

}

优化时间

事情说到这里, 算法已经能工作了, 接下来就是优化. 能在什么地方优化呢? Bresenham卖广告总是在说"全程只用加减法, 效率超高~". 但是一个看上去必须要用乘法的直线公式, 怎么都没办法优化到只用加减法吧...

其实乘法是在重复计算 :-)小学时候学乘法, 不都说4x3是四个3加起来吗, 所以乘法本身就是加法组成的啊. 而重复的部分, 就是你已经算了3x3, 你只需要再加上一个3就可以得到4x3了. 同样地, 当前判别式的结果, 我们只需要在上一个判别式的结果基础上加上一点什么就行了. 至于是什么, 就要看推导了:

For x = xf, y = yf: f(xf, yf) = 0

f(x+1, y) = (x+1) dy - y dx + yf dx - xf dy

= f(x, y) + dy * >= 0 *

f(x+1, y+1) = (x+1) dy - (y+1) dx + yf dx - xf dy

= f(x, y) + dy - dx * <= 0 *

这个递推式就是我们需要的. 写下的代码是这样的:

cppvoid bresenham_2(int xf, int yf, int xt, int yt, const color& c, image& img)

{

int f = 0;

int dx = xt - xf;

int dy = yt - yf;

for(int x = xf, y = yf; x <= xt; x++) {

img(x, y) = c;

if((f + dy) + (f + dy - dx) < 0)

f += dy;

else {

f += dy - dx;

y++;

}

}

}

注: 有的同学发现我这个结果跟Computer Graphics 2nd Edition, D. Hearn & M.P. Baker的公式有点不太一样. 其实仔细看一下是一样的, 只不过变了个型. 那本书的公式写出的程序是这个样子的:

cppvoid bresenham_3(int xf, int yf, int xt, int yt, const color& c, image& img)

{

int dx = xt - xf;

int dy = yt - yf;

int f = dy + dy - dx;

for(int x = xf, y = yf; x <= xt; x++) {

img(x, y) = c;

if(f < 0) f += dy + dy;

else {

f += dy + dy - dx - dx;

y++;

}

}

}

补充完整

void bresenham_4(int xf, int yf, int xt, int yt, const color& c, image& img)

{

if(xf > xt) {

int t;

t = xf; xf = xt; xt = t;

t = yf; yf = yt; yt = t;

}

int dx = xt - xf;

int dy = yt - yf;

int f = 0;

if(dy >= 0 && dy <= dx) {

for(int x = xf, y = yf; x <= xt; x++) {

img(x, y) = c;

if((f + dy) + (f + dy - dx) < 0)

f += dy;

else { f += dy - dx; y++; }

}

} else if(dy >= 0 && dy > dx) {

for(int x = xf, y = yf; y <= yt; y++) {

img(x, y) = c;

if((f - dx) + (f - dx + dy) > 0)

f += -dx;

else { f += -dx + dy; x++; }

}

} else if(dy <= 0 && -dy <= dx) {

for(int x = xf, y = yf; x <= xt; x++) {

img(x, y) = c;

if((f + dy) + (f + dy + dx) > 0)

f += dy;

else { f += dy + dx; y--; }

}

} else if(dy <= 0 && -dy > dx) {

for(int x = xf, y = yf; y >= yt; y--) {

img(x, y) = c;

if((f + dx) + (f + dy + dx) < 0)

f += dx;

else { f += dy + dx; x++; }

}

}

}

测试一下 :-)

cppint main()

{

image img(800, 600);

bresenham_1(20, 20,

500, 50, color(uint32_t(0x00000000)), img);

bresenham_2(20, 30,

500, 60, color(uint32_t(0x00000000)), img);

bresenham_3(20, 40,

500, 70, color(uint32_t(0x00000000)), img);

// completed line algorithm

for(int i = 0; i < 50; i++) {

bresenham_4(rand() % 800, rand() % 600, rand() % 800, rand() % 600,

color(uint32_t(0x00000000)), img);

}

ofstream f("3-1-line.ppm");

f << img;

f.close();

}

好了有人该警告我不要偷懒用來画图了, 老老实实贴上来吧 (压缩成jpg之后那种漂亮的Minecraft风格的直线变得很模糊糟透了)

java bresenham画直线_图形学笔记: Bresenham画线算法相关推荐

  1. 画直线_在鸡面前画一条直线,为什么它会晕?西瓜视频这知识好冷告诉答案

    为什么世界有那么多的未解之谜,我们无从而知,今天我们来探讨一下在鸡面前画条直线为什么会晕?你们知道吗?今天西瓜视频这知识好冷告诉你们答案,帮助你们掌握生活中所不知道的涨知识,增加我们的知识库. 优秀创 ...

  2. qcustomplot时间坐标轴画直线_为什么鸡看到画直线会晕?

    最近网上流传一个非常火的视频,视频中一人按着鸡,一人在其面前画直线,神奇的是当直线画完时,按着鸡的人把手松开,鸡一动不动,好像中了"定身术". 而把鸡稍微挪动下,离开直线,又生龙活 ...

  3. java画板中画直线_画图板(画直线)

    1.创建一个画图板(界面) public class DrawUI { //显示界面的方法 public void show(){ //创建界面对象 JFrame jframe = new JFram ...

  4. 画直线_在鸡的面前画直线,鸡为什么会晕呢,西瓜视频带你揭秘

    不知道你们有没有看过这样一个视频,把鸡按在地上,然后在它的面前画一条直线,在直线画完的时候,按着鸡的人把手松开,结果鸡一动不动,好像是被催眠了一样.视频一出很多网友都纷纷开始模仿,并且都成功了,这到底 ...

  5. qgraphicsscene 鼠标画直线_游戏鼠标的进阶玩法,驱动深入打磨

    大家都知道,游戏鼠标都有不少的快捷键和功能键,但是不少玩家也就是当普通鼠标用,甚至连DPI键都没按过的玩家一样有. 不吹不黑,玩游戏更多是看天赋和技术的,游戏鼠标只是辅助. 不过,好的游戏鼠标能大大改 ...

  6. java左手画圆右手画方_作文:左手画圆,右手画方

    左手画圆,右手画方 相关内容: 星期天晚上,爸爸叫我在白纸上画几个圆.要我把几个圆画一样大小,还要画的非常圆.我在白纸上连续画了几个圆,可是每个圆的大小都不一样,画出的圆根本不圆.这是怎么回事呢?虽然 ...

  7. python turtle画烟花_怎么用python3画烟花?代码是什么?

    我们可以用python做很多好玩的事情哦~包括制作动态的视频,之前小编就教大写编写过制作内容,现在给大家想到了更好玩的事情,就是编写个烟花代码出来,有兴趣的小伙伴可以看下呢~ 实施步骤: 一.导入海龟 ...

  8. 游戏原画学习方法_学习游戏原画有什么方法

    游戏原画学习步骤,零基础一步步学原画!那么学游戏原画应该怎么学呢?下面咱们针对游戏原画学习做一次详细的步骤说明!   原画插画学习加微心号:wuhongjuan9[备注学习原画插画]   相信很多喜欢 ...

  9. 计算机图形学第一次上机——中点线算法和中点圆算法

    计算机图形学第一次上机实验 课程实验报告 目录 计算机图形学第一次上机实验 课程实验报告 一.实验目的 二.实验环境 三.实验内容 1.中点线算法 2.中点圆算法 四.实验心得 附录:程序源代码 一. ...

最新文章

  1. windows10 python调用wsl_(亲测!)Windows10用WSL安装Ubuntu远程桌面连接和配置开发环境...
  2. MySQL-数据库三大范式
  3. ubuntu开机出现:system program problem detected
  4. springBoot ajax 报错 Circular view path [xx: would dispatch...
  5. js页面加载前执行_做一名合格的前端开发工程师:Javascript加载执行问题探索
  6. 朝鲜 APT37被指发动软件供应链攻击,瞄准股票投资人
  7. firefox 53支持java_火狐浏览器53.0版
  8. 女生学Java软件开发好就业吗
  9. 嵌入式软件可靠性设计
  10. Spring JdbcTemplate声明式事务
  11. 旋风系统时间与服务器不一致,更新公告 | 8月15日早8点停服维护
  12. 数据结构进阶(Go语言)
  13. MDK JZ2440 SDRAM 复位按钮跳转
  14. Java 使用Tailer类监听文件
  15. python 调用剪切板
  16. 电磁阀单电控与双电控区别
  17. JAVA毕设项目沙县小吃点餐系统(java+VUE+Mybatis+Maven+Mysql)
  18. 【学习日记】接口安全
  19. 关于购买阿里云服务器和域名之后需要做的事
  20. 如何搭建普通人的自由现金流模型

热门文章

  1. kernel kworker debug
  2. 【单片机学习笔记】(33):直流无刷电机基础知识、六步换相控制原理、无刷电机驱动电路
  3. 一个男生走过多少路,才算得上一个男人
  4. webgl的透视投影矩阵
  5. html href链接中文乱码,javascript如何解决url中文乱码?
  6. java获取ie11版本号_判断IE浏览器的版本号
  7. 浅谈视频号对企业运营的作用
  8. webstorm 安装vue
  9. 开机密码错误显示rpc服务器,电脑提示RPC服务器不可用的解决方法
  10. Redis的性能监控指标