java bresenham画直线_图形学笔记: Bresenham画线算法
图形学课本, 按规矩介绍完矩阵行列式, 第一个算法肯定就是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画线算法相关推荐
- 画直线_在鸡面前画一条直线,为什么它会晕?西瓜视频这知识好冷告诉答案
为什么世界有那么多的未解之谜,我们无从而知,今天我们来探讨一下在鸡面前画条直线为什么会晕?你们知道吗?今天西瓜视频这知识好冷告诉你们答案,帮助你们掌握生活中所不知道的涨知识,增加我们的知识库. 优秀创 ...
- qcustomplot时间坐标轴画直线_为什么鸡看到画直线会晕?
最近网上流传一个非常火的视频,视频中一人按着鸡,一人在其面前画直线,神奇的是当直线画完时,按着鸡的人把手松开,鸡一动不动,好像中了"定身术". 而把鸡稍微挪动下,离开直线,又生龙活 ...
- java画板中画直线_画图板(画直线)
1.创建一个画图板(界面) public class DrawUI { //显示界面的方法 public void show(){ //创建界面对象 JFrame jframe = new JFram ...
- 画直线_在鸡的面前画直线,鸡为什么会晕呢,西瓜视频带你揭秘
不知道你们有没有看过这样一个视频,把鸡按在地上,然后在它的面前画一条直线,在直线画完的时候,按着鸡的人把手松开,结果鸡一动不动,好像是被催眠了一样.视频一出很多网友都纷纷开始模仿,并且都成功了,这到底 ...
- qgraphicsscene 鼠标画直线_游戏鼠标的进阶玩法,驱动深入打磨
大家都知道,游戏鼠标都有不少的快捷键和功能键,但是不少玩家也就是当普通鼠标用,甚至连DPI键都没按过的玩家一样有. 不吹不黑,玩游戏更多是看天赋和技术的,游戏鼠标只是辅助. 不过,好的游戏鼠标能大大改 ...
- java左手画圆右手画方_作文:左手画圆,右手画方
左手画圆,右手画方 相关内容: 星期天晚上,爸爸叫我在白纸上画几个圆.要我把几个圆画一样大小,还要画的非常圆.我在白纸上连续画了几个圆,可是每个圆的大小都不一样,画出的圆根本不圆.这是怎么回事呢?虽然 ...
- python turtle画烟花_怎么用python3画烟花?代码是什么?
我们可以用python做很多好玩的事情哦~包括制作动态的视频,之前小编就教大写编写过制作内容,现在给大家想到了更好玩的事情,就是编写个烟花代码出来,有兴趣的小伙伴可以看下呢~ 实施步骤: 一.导入海龟 ...
- 游戏原画学习方法_学习游戏原画有什么方法
游戏原画学习步骤,零基础一步步学原画!那么学游戏原画应该怎么学呢?下面咱们针对游戏原画学习做一次详细的步骤说明! 原画插画学习加微心号:wuhongjuan9[备注学习原画插画] 相信很多喜欢 ...
- 计算机图形学第一次上机——中点线算法和中点圆算法
计算机图形学第一次上机实验 课程实验报告 目录 计算机图形学第一次上机实验 课程实验报告 一.实验目的 二.实验环境 三.实验内容 1.中点线算法 2.中点圆算法 四.实验心得 附录:程序源代码 一. ...
最新文章
- windows10 python调用wsl_(亲测!)Windows10用WSL安装Ubuntu远程桌面连接和配置开发环境...
- MySQL-数据库三大范式
- ubuntu开机出现:system program problem detected
- springBoot ajax 报错 Circular view path [xx: would dispatch...
- js页面加载前执行_做一名合格的前端开发工程师:Javascript加载执行问题探索
- 朝鲜 APT37被指发动软件供应链攻击,瞄准股票投资人
- firefox 53支持java_火狐浏览器53.0版
- 女生学Java软件开发好就业吗
- 嵌入式软件可靠性设计
- Spring JdbcTemplate声明式事务
- 旋风系统时间与服务器不一致,更新公告 | 8月15日早8点停服维护
- 数据结构进阶(Go语言)
- MDK JZ2440 SDRAM 复位按钮跳转
- Java 使用Tailer类监听文件
- python 调用剪切板
- 电磁阀单电控与双电控区别
- JAVA毕设项目沙县小吃点餐系统(java+VUE+Mybatis+Maven+Mysql)
- 【学习日记】接口安全
- 关于购买阿里云服务器和域名之后需要做的事
- 如何搭建普通人的自由现金流模型