- 浏览: 280709 次
- 性别:
- 来自: 济南
文章分类
最新评论
08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活。此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/details/7747205
直线的DDA算法
【算法介绍】
设直线之起点为(x1,y1),终点为(x2,y2),则斜率m为:
直线中的每一点坐标都可以由前一点坐标变化一个增量(Dx, Dy)而得到,即表示为递归式:
并有关系:Dy = m • Dx。递归式的初值为直线的起点(x1, y1),这样,就可以用加法来生成一条直线。具体方法是:
直线方向的8个象限
按照直线从(x1,y1)到(x2,y2)的方向不同,分为8个象限。对于方向在第1a象限内的直线而言,D x=1,D y=m。对于方向在第1b象限内的直线而言,取值Dy=1,Dx=1/m。各象限中直线生成时Dx, Dy的取值列在下表之中。
- 当|dx|>|dy|时,|D x|=1, |D y|=m;否则:Dx=1/m,|Dy|=1
- Dx, Dy的符号与dx, dy的符号相同
【算法流程图】
【相关代码】
void PaintArea::drawLineDDA(QPainter &painter,int x0, int y0, int xEnd, int yEnd) { int dx=xEnd-x0,dy=yEnd-y0,steps,k; float xIncrement,yIncrement,x=x0,y=y0; if(fabs(dx)>fabs(dy)) steps=fabs(dx); else steps=fabs(dy); xIncrement=float(dx)/float(steps); yIncrement=float(dy)/float(steps); painter.drawPoint(round(x),round(y)); for(k=0;k<steps;k++){ x+=xIncrement; y+=yIncrement; painter.drawPoint(round(x),round(y)); } }
直线的Bresenham算法
这个算法由Bresenham在1965年提出。设直线从起点(x1, y1)到终点(x2, y2)。直线可表示为方程y=mx+b。其中
我们的讨论先将直线方向限于1a象限在这种情况下,当直线光栅化时,x每次都增加1个单元,即
而y的相应增加应当小于1。为了光栅化,yi+1只可能选择如下两种位置之一(如图)。
i+1的位置选择yi-1=yi 或者 yi+1=yi+1
选择的原则是看精确值y与yi及yi+1的距离d1及d2的大小而定。计算式为:
如果d1-d2>0,则yi+1=yi+1,否则yi+1=yi。因此算法的关键在于简便地求出d1-d2的符号。将上公式得
d1-d2=2y-2yi-1=2 (xi+1)-2yi+2b-1
用dx乘等式两边,并以Pi=dx(d1-d2)代入上述等式,得
Pi=2xidy-2yidx+2dy+dx(2b-1)
d1-d2是我们用以判断符号的误差。由于在1a象限,dx总大于0,所以Pi仍旧可以用作判断符号的误差。Pi-1为:
Pi+1=Pi+2dy-2dx(yi+1-yi)
误差的初值P1,可将x1, y1,和b代入式(4)中的xi, yi而得到:
P1=2dy-dx
Bresenham算法的优点是:
-
不用浮点数,只用整数;
-
只做整数加减法和乘2运算,而乘2运算可以用硬件移位实现。
-
Bresenham算法速度很快,并适于用硬件实现。
【算法流程图】
【相关代码】
void PaintArea::drawLineBresenham(QPainter &painter, int x0, int y0, int xEnd, int yEnd) { int x,y,dx,dy,e; if(fabs(x0-xEnd)>fabs(y0-yEnd)){ dx=xEnd-x0; dy=yEnd-y0; e=-dx; x=x0; y=y0; for(int i=0;i<=dx;i++) {painter.drawPoint(x,y); x=x+1; e=e+2*dy; if(e>=0) {y=y+1; e=e-2*dx; }} } else if(fabs(x0-xEnd)>fabs(y0-yEnd)){ dx=xEnd-x0; dy=yEnd-y0; e=-dx; x=x0; y=y0; for(int i=0;i<=dx;i++) { painter.drawPoint(x,y); y=y+1; e=e+2*dx; if(e>=0) {x=x+1; e=e-2*dy; }} } }
中点画线法
假定直线斜率k在0~1之间,当前象素点为(xp,yp),则下一个象素点有两种可选择点(xp+1,yp)或P2(xp+1,yp+1)。若P1与P2的中点(xp+1,yp+0.5)称为M,Q为理想直线与x=xp+1垂线的交点。当M在Q的下方时,则取P2应为下一个象素点;当M在Q的上方时,则取P1为下一个象素点。这就是中点画线法的基本原理。
【算法流程图】
【相关代码】
void PaintArea::drawLineMiddle(QPainter &painter, int x0, int y0, int xEnd, int yEnd) { int a,b,d,x,y; if(fabs(x0-xEnd)>fabs(y0-yEnd)){ a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0; painter.drawPoint(x,y); while(x<xEnd) { if(d<0) {x++;y++;d+=2*(a+b); } else{x++;d+=2*a; } painter.drawPoint(x,y); } } else if(fabs(x0-xEnd)>fabs(y0-yEnd) &&(x0-xEnd))<0)){ a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0; painter.drawPoint(x,y); while(x>xEnd) { if(d<0) {x--;y--; d-=2*(a+b); } else{x--;d-=2*a; } painter.drawPoint(x,y); } } else if(fabs(x0-xEnd)<fabs(y0-yEnd)&&(x0-xEnd)<0){ a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0; painter.drawPoint(x,y); while(y>yEnd) { if(d<0) {y++;x++;d+=2*(a+b); } else{y++;d+=2*a; } painter.drawPoint(x,y); } } else if(fabs(x0-xEnd)<fabs(y0-yEnd) &&(x0-xEnd))>0)){ a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0; painter.drawPoint(x,y); while(x>xEnd) { if(d<0) {x--;y--; d-=2*(a+b); } else{x--;d-=2*a; } painter.drawPoint(x,y); } } else if(fabs(x0-xEnd)<fabs(y0-yEnd)&&(x0-xEnd)>0){ a=y0-yEnd; b=xEnd-x0; d=2*a+b; x=x0; y=y0; painter.drawPoint(x,y); while(y>yEnd) { if(d<0) {y++;x++;d+=2*(a+b); } else{y++;d+=2*a; } painter.drawPoint(x,y); } } }
软件截图
这个绘图软件是用QT写的,我会另外写一篇介绍编程结构,敬请期待~
结果分析
-
此次实验自己真的倾注了很大的心血。
因为很喜欢计算机图形学,所以很想做个像模像样的东西出来,于是就下定决心借实验的机会做个简易的windows画板。也是第一次正式的使用QT开发,摸索的过程使得整个实验拖了很长时间。最终的结果还是比较令自己满意的,至少基本功能都实现了,界面也还看得过去。 -
过于注重表面,算法上功夫不足,有些“舍本逐末”
我是把整个软件做差不多了,才开始细细得来研究图元的基本算法(开始都是调用qt自带的绘制函数)。调试算法的过程才深刻感觉这比整个软件更花时间(可能因为整个软件并没有很复杂的架构)。由于时间有限,很多地方没有细细改进。尤其是对于k的几种情况,就生生的写了很冗余的代码,实在是丑啊。 -
以后再继续改进。
要改进的地方还有很多。比如算法结构重构,不要写那么冗余。然后再尝试一些填充算法自己实现,还有自己会试着做做简单的图像处理,变形拉伸什么的。
总之,坚持动手,学以致用。
转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7762419
发表评论
-
unity基础开发----物体位移和旋转实用代码
2013-11-21 22:46 1270using UnityEngine; using Syst ... -
android 动态时钟 附源码
2013-09-24 12:03 1281自定义View实践 例子代码 自定义动态时钟 ... -
android Dialog 背景问题
2013-08-14 11:22 1206我们在使用自定义的Dialog的时候,喜欢自己 ... -
ScrollView scrollTo 的使用 动画效果
2013-08-05 17:43 4605今天用到了ScrollView scrollTo方法 ... -
Android中View绘制优化之一---- 优化布局层次
2012-09-04 23:00 1074... -
Android中View绘制优化二一---- 使用<include />标签复用布局文件
2012-09-08 13:54 1055... -
Android中View绘制优化之三---- 优化View
2012-09-13 21:00 1083... -
兰林任务管理应用程序雏形版以及概要说明
2012-09-15 21:54 880... -
Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)
2012-10-10 18:14 1167... -
Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)
2012-10-17 20:05 862... -
Android中文件选择器的实现
2012-11-30 08:59 1173... -
【编译原理】使用Lex将C/C++文件输出为HTML文件
2012-07-20 09:37 107008年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【编译原理】正则表达式
2012-07-21 21:49 230508年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【OpenCV】访问Mat图像中每个像素的值
2012-07-22 07:10 1171今天百度搜资料还搜到了自己的。。。《访问图像中每个像素的值 ... -
【编译原理】用Yacc做语法分析
2012-07-23 05:47 177408年9月入学,12年7月毕 ... -
【UML】UML几种图的绘制
2012-07-24 09:49 99108年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大 ... -
【OpenCV】邻域滤波:方框、高斯、中值、双边滤波
2012-07-26 10:52 1460邻域滤波(卷积) 邻域算子值利用给定像素 ... -
【数据结构】排序算法:希尔、归并、快速、堆排序
2012-07-28 06:15 102508年9月入学,12年7月毕 ... -
【OpenCV】角点检测:Harris角点及Shi-Tomasi角点检测
2012-07-31 13:25 1546角点 特征检测与匹配 ... -
【UML】案例分析:机场运作系统
2012-08-01 17:22 313408年9月入学,12年7月毕 ...
相关推荐
5. 直线生成算法:直线生成算法是计算机图形学中的基本算法,包括数值微分法(DDA)、中点画线算法和Bresenham画线算法。这些算法可以生成直线、圆和其他图形。 6. 中点画线算法:中点画线算法是直线生成算法的一种...
计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机图形学 直线DDA算法计算机...
实验的主要目标是掌握3种常见的直线生成算法:数值微分(DDA)算法、中点算法以及Bresenham算法,并能够在MFC环境下正确绘制直线。 **1. DDA(Digital Differential Analyzer)算法** DDA算法基于直线方程y = kx +...
3. **直线生成算法**:Bresenham算法是最常见的直线生成算法,它能在离散的像素网格上近似地绘制出直线。实验可能会要求你实现这个算法,以在屏幕上精确地画出直线。 4. **椭圆和圆的生成**:虽然直线可以通过...
Bresenham算法是计算机图形学中最著名的直线生成算法,由Jack Bresenham于1965年提出。它基于误差累积的思想,以整数坐标为中心,通过比较误差值的大小来决定下一步向哪个方向移动。对于y轴正方向的直线,算法可以...
基本二维图元的生成算法是计算机图形学中最基础的部分,它们是构成图形图像的基本元素。这些图元的生成算法可以分为两步:首先,确定图形对应的象素集合及其颜色;其次,用图形的颜色或其他属性对象素进行写操作。...
2. 掌握几种基本的直线生成算法:DDA 算法、Bresenham 画线法、中点画线法 3. 实现直线生成的,在屏幕上任意生成一条直线 三、实现程序: 本实验使用 C 语言编写,使用 Borland Graphics Interface(BGI)库来实现...
在计算机图形学中,直线生成算法是基础且至关重要的,它使得计算机能够精确地描绘出直线,为复杂的图形渲染和图像处理提供基础。在Windows编程环境中,VC++(Visual C++)常被用于开发图形应用,因此理解并掌握直线...
直线作为最基础的图形元素之一,在计算机图形学中扮演着至关重要的角色。本项目重点介绍了三种经典的直线绘制算法:DDA(Digital Differential Analyzer,数字微分分析器)、Bresenham算法以及中点画线法,这些都是...
图元作为计算机图形学中的基本元素,是构建复杂图形的基础。它们是不可再分的基本图形实体,例如点、直线、圆弧、多边形、字体符号以及位图等。在实际应用中,复杂的图形可以通过这些基本图元的不同组合来实现。 **...
在计算机图形学中,直线和圆是最基本的图形元素,本文将介绍三种直线生成算法和圆的生成算法。 一、DDA 直线生成算法 DDA 直线生成算法是一种简单的直线生成算法。该算法的基本思想是通过计算直线的斜率和截距来...
根据提供的文件信息,我们可以深入探讨计算机图形学中的几个核心算法:直线生成算法、圆生成算法、椭圆生成算法以及剪裁算法。这些算法在计算机图形学领域有着广泛的应用,不仅适用于理论研究,还广泛用于软件开发、...
C语言实现Bresenham直线生成算法可能如下: ```c #include // 假设我们有一个二维数组代表屏幕,(0,0)为左上角 int screen[800][600]; void draw_line(int x0, int y0, int x1, int y1) { int dx = abs(x1 - x0...
总的来说,计算机图形学中的直线和圆生成算法是通过对点、像素和数学关系的理解来实现的。在实际应用中,我们需要根据不同的情况选择合适的算法,以达到理想的视觉效果。随着硬件性能的提升和新的图形处理技术的发展...
在计算机图形学中,线段的绘制通常采用Bresenham算法或DDA(Digital Differential Analyzer)算法,这些算法能高效地在像素级别上近似出直线。 二、圆与椭圆 圆和椭圆的表示通常基于极坐标或者参数方程。例如,可以...
这段时间弄了很多图形学方面的算法,如DDA画直线算法,以及MidpointLine、BresenhamLine、还有画圆的BresenhamCircle、MidpointCircle以及多种 种子填充算法,如Floodfill、ScanlineSeedfill、ET边表的 Polygonfill...
总结来说,直线段裁剪是计算机图形学中的基本技术,通过各种算法实现对图形元素的显示控制。这些算法的理解和掌握对于深入学习计算机图形学至关重要,它们构成了现代图形应用程序的基础。通过相互学习和不断提高,...