画线算法 - Bresenham原理及Java实现
来源:互联网 发布:淘宝联盟的导购推广位 编辑:程序博客网 时间:2024/04/28 18:18
Bresenham是绘制线段最有效率的算法之一,该算法仅仅使用整型加减及字节位操作运算 (省去了用于计算斜率的除法运算),因而计算效率非常高。其实现也非常的简单明了。本文以Java代码为例,一步一步由浅而深的讲解了Bresenham算法的完整实现。
下图所示,二维坐标系统可均分为八个分区,作为本文例子的线段(x,y,x2,y2)位于第二分区。
在实现该算法之前,我们先看看最原始,最直观的做法。该原始算法可以帮助更好的阐述布氏算法,因为布氏算法本身就是该原始算法的扩展和优化。
public void drawLineRaw(int x, int y, int x2, int y2, int color) { int w = x2 - x; int h = y2 - y; double m = h / (double) w; double j = y; for (int i = x; i <= x2; i++) { drawPixel(i, (int) j, color); j += m; } }
该实现尽管效率低,但实现了我们需要的功能。注意!上面代码实际只能画位于第二分区的线条,而不能画位于其它分区的线条。当耐心读完本文,在结尾部分我们会看到覆盖所有分区的完整的实现。
操作m = h / w,j + = m实际上是增加了分子,并保持分母不变。当分子h变得等于或大于分母w,分子减去分母并将j增加1(实现该操作对应的代码为(int) j)。 这阐述了Bresenham算法的基本原理,Bresenham算法用整数加法取代了除法和实数操作。如下代码为Bresenham算法在第二分区的实现。(该部分是理解全文的关键,请仔细体会)
public void drawIn2ndOctant(int x,int y,int x2,int y2,int color) { int w = x2 - x; int h = y2 - y; int dy1 = -1; int fastStep = Math.abs(w); int slowStep =Math.abs(h); int numerator = fastStep>> 1; for (int i = 0; i <=fastStep; i++) { drawPixel(x,y, color); numerator+= slowStep; if (!(numerator <fastStep)) { numerator-= fastStep; y+= dy1; } x++; } }
注意, int numerator = fastStep >> 1; 分子等于快速变量的一半,该步骤让y值的四舍五入在中间点而不是在整数点。
一个完整的画线功能将需要考虑所有的分区, 那我们是否需要8份如上所示的代码呢?答案是不,其它八个分区的实现都十分相似,并很容易通用化。首先,我们来看看在不同的八分区的相似之处。 在第三分区线段只是第二分区线段基于Y方向的镜像,因此只需设置dy1 = 1,而不是dy1=-1。请参见下面的第4行的区别。
public void drawIn3rdOctant(int x,int y,int x2,int y2,int color) { int w = x2 - x; int h = y2 - y; int dy1 = 1; int fastStep = Math.abs(w); int slowStep = Math.abs(h); int numerator = fastStep>> 1; for (int i = 0; i <=fastStep; i++) { drawPixel(x,y, color); numerator+= slowStep; if (!(numerator <fastStep)) { numerator-= fastStep; y+= dy1; } x++; } }
在第六分区和第三分区的实现是基本相同的,除了基于坐标轴的镜像。这可以通过改变代码 x++为x- - 来实现。 简单吧!
public void drawIn6thOctant(int x,int y,int x2,int y2,int color) { int w = x2 - x; int h = y2 - y; int dy1 = 1; int fastStep = Math.abs(w); int slowStep = Math.abs(h); int numerator = fastStep>> 1; for (int i = 0; i <=fastStep; i++) { drawPixel(x,y, color); numerator+= slowStep; if (!(numerator <fastStep)) { numerator-= fastStep; y+= dy1; } x--; } }
这同样适用于第七分区与第二分区。可以通过改变行x ++为x–来实现。
public void drawIn7thOctant(int x,int y,int x2,int y2,int color) { int w = x2 - x; int h = y2 - y; int dy1 = -1; int fastStep = Math.abs(w); int slowStep = Math.abs(h); int numerator = fastStep>> 1; for (int i = 0; i <=fastStep; i++) { drawPixel(x,y, color); numerator+= slowStep; if (!(numerator <fastStep)) { numerator-= fastStep; y+= dy1; } x--; } }
重复,重复… 重构!如下是一个通用于第二,第三,第六和第七分区的线段绘制功能。
public void drawInEvenOctant(int x,int y,int x2,int y2,int color) { int w = x2 - x; int h = y2 - y; int dx1 = w < 0 ? -1: (w > 0 ? 1 : 0); int dy1 = h < 0 ? -1: (h > 0 ? 1 : 0); int dx2 = 0; int dy2 = dx2 = w < 0? -1 : (w > 0 ? 1 : 0); int fastStep = Math.abs(w); int slowStep = Math.abs(h); int numerator = fastStep>> 1; for (int i = 0; i <=fastStep; i++) { drawPixel(x,y, color); numerator+= slowStep; if (!(numerator <fastStep)) { numerator-= fastStep; x+= dx1; y+= dy1; }else { x+= dx2; y+= dy2; } } }
到目前为止,我们实现的第二,第三,第六,第七分区的画线功能。然而,这仍然不完整。我们发现位于第一,第四,第五,和第八分区具有一个共同的区别,其高度的变化快于宽度的变化,而在第二,第三,第六,和第七分区的线段,其宽度的变化快于高度的变化。综合该逻辑,如下是Bresenham算法的对所有的八分区画线的完整实现。
public void drawLine(int x0,int y0,int x1,int y1,int color) { int x = x0; int y = y0; int w = x1 - x0; int h = y1 - y0; int dx1 = w < 0 ? -1: (w > 0 ? 1 : 0); int dy1 = h < 0 ? -1: (h > 0 ? 1 : 0); int dx2 = w < 0 ? -1: (w > 0 ? 1 : 0); int dy2 = 0; int fastStep = Math.abs(w); int slowStep = Math.abs(h); if (fastStep <=slowStep) { fastStep= Math.abs(h); slowStep= Math.abs(w); dx2= 0; dy2= h < 0 ? -1 : (h > 0 ? 1 : 0); } int numerator = fastStep>> 1; for (int i = 0; i <=fastStep; i++) { drawPixel(x,y, color); numerator+= slowStep; if (numerator >=fastStep) { numerator-= fastStep; x+= dx1; y+= dy1; }else { x+= dx2; y+= dy2; } } }
本文主要参考自http://tech-algorithm.com/articles/drawing-line-using-bresenham-algorithm/, 并结合实际的游戏引擎,Java实现代码有一定优化。希望对你有所帮助! 反馈请联系jinbing.peng@yahoo.com.
- 画线算法 - Bresenham原理及Java实现
- 用OPenGL实现 Bresenham画线算法
- 画线算法-Bresenham算法
- Bresenham 画线算法
- Bresenham高效画线算法
- Bresenham 画线算法
- Bresenham 画线算法
- Bresenham 画线算法
- Bresenham画线算法
- Bresenham 画线算法
- Bresenham高效画线算法
- Bresenham高效画线算法
- bresenham 画线算法
- Bresenham画线算法
- Bresenham画线算法
- 中点bresenham算法画线
- Bresenham画线算法详解及其OpenGL编程实现
- Bresenham画线算法详解及其OpenGL编程实现
- Reverse Words in a String ---leetcode 我的java题解
- Sublime Text3打造U盘便携Lua IDE
- UIAlertView点击确定后,如何跳转到storyboard中创建的另一个UIViewController?
- 黑马程序员-JAVASE入门(GUI类)
- lua实现大数运算
- 画线算法 - Bresenham原理及Java实现
- [Leetcode] 87. Scramble String
- [Leetcode] 88. Merge Sorted Array
- LeetCode - Longest Substring Without Repeating Characters
- 黑马程序员-JAVASE入门(多线程)
- 黑马程序员-JAVASE入门(集合)
- [Leetcode] 89. Gray Code
- 黑马程序员-JAVASE入门(枚举)
- 黑马程序员-JAVASE入门( 面向对象、单例设计模式、this、static关键字)