Bresenham 画线算法
Bresenham画线算法
Bresenham画线算法Bresenham画线算法是用来描绘由两点所决定的直线的算法,它会算出一条线段在 n 维光栅上最接近的点。
这个算法只会用到较为快速的整数加法、减法和位元移位,常用于绘制电脑画面中的直线。
是计算机图形学中最先发展出来的算法。
Bresenham画法与中点法相似,都是通过每列象素中确定与理想直线最近的像素来进行直线的扫描的转换的。
通过各行、各列的象素中心构造一组虚拟网格线的交点,然后确定该列象素中与此交点最近的像素。
该算法的巧妙之处在于可以采用增量计算,使得对于每一列,只需要检查一个误差项的符号,就可以确定该列的所有对象。
根据直线的斜率确定选择变量在X方向上或在Y方向上每次递增一个单位,另一变量的增量为0或1,它取决于实际直线与最近网格点位置的距离,这一距离称为误差。
设第k步的误差为ek,选取上面象素点后的积累误差为:ek+1﹦ek﹢(m﹣1)选取下面的象素点后的积累误差为:ek+1﹦ek﹢m/* Bresenham */程序代码如下:#include <graphics.h>#include <conio.h>// 使用 Bresenham 算法画任意斜率的直线(包括起始点,不包括终止点)void Line_Bresenham(int x1, int y1, int x2, int y2, int color){int x = x1;int y = y1;int dx = abs(x2 - x1);int dy = abs(y2 - y1);int s1 = x2 > x1 ? 1 : -1;int s2 = y2 > y1 ? 1 : -1;bool interchange = false; // 默认不互换 dx、dyif (dy > dx) // 当斜率大于 1 时,dx、dy 互换{int temp = dx;dx = dy;dy = temp;interchange = true;}int p = 2 * dy - dx;for(int i = 0; i < dx; i++){putpixel(x, y, color);if (p >= 0){if (!interchange) // 当斜率 < 1 时,选取上下象素点y += s2;else // 当斜率 > 1 时,选取左右象素点x += s1;p -= 2 * dx;}if (!interchange)x += s1; // 当斜率 < 1 时,选取 x 为步长elsey += s2; // 当斜率 > 1 时,选取 y 为步长p += 2 * dy;}}// 主函数void main(){initgraph(640, 480);// 测试画线Line_Bresenham(10, 100, 100, 478,BLUE);Line_Bresenham(10, 478, 638, 1, RED);// 按任意键退出getch();}运行结果如下:。
生成直线的bresenham算法
生成直线的bresenham算法
Bresenham算法是由Jack E. Bresenham在1962年提出的一种用于生成直线图形的算法。
它可以根据两个点的坐标来计算出中间所有点的位置,即通过这两个端点可以确定出整条直线的像素点。
Bresenham算法的核心思想是,沿着已知的两个点之间的点,从起点开始向终点靠近,沿途计算斜率的误差,依据误差大小判断是选择水平方向或者垂直方向上的点,从而确定最终的直线图形。
具体步骤如下:
(1)根据两个点坐标计算出斜率dx和dy;
(2)令x0=x1, y0=y1;
(3)计算当前点处斜率误差p,公式为:p=2dy-dx;
(4)根据p的大小,决定下一步是沿水平方向还是垂直方向:
(a)p>0时,下一步沿垂直方向前进,即y++;
(b)p<=0时,下一步沿水平方向前进,即x++;
(5)重复步骤3、4,直到到达终点。
分别解释直线生成算法dda法,中点画线法和bresenham法的基本原理
分别解释直线生成算法dda法,中点画线法和
bresenham法的基本原理
直线生成算法DDA法、中点画线法和Bresenham法的基本原理如下:
1. DDA直线生成算法:基于差分运算的直线生成算法。
通过将直线分割成
若干个相邻的像素点,并按照一定的步长进行逐点绘制,实现直线的绘制。
算法主要涉及到线性插值的思想,即根据已知的两点坐标,通过计算它们之间的差值,然后根据这个差值和步长来确定新的像素点的位置。
2. 中点画线法:一种线段绘制算法,从线段的起点和终点出发,按照一定的规则向终点逐步逼近,并在途中以控制变量的方式得出每个像素点的坐标,从而绘制出所需的线条。
具体实现中,通过计算线段斜率的变化情况,分为斜率小于1和大于等于1两种情况,并采用Bresenham的对称性原理,以中点的颜色来控制每个像素点的生长方向,从而获得较高的绘制效率和图像质量表现。
3. Bresenham算法:通过一系列的迭代来确定一个像素点是否应该被绘制。
对于一条从点(x1,y1)到点(x2,y2)的直线,首先计算出斜率k。
然后,通过比较每个像素点的y值到直线上的y值,来决定哪些像素点应该被绘制。
当斜率k大于等于1时,在x方向上迭代,而对于每个x值,计算出y值,并将像素点(x,y)绘制。
当斜率k小于1时,在y方向上迭代,而对于每个y值,计算出x值,并将像素点(x,y)绘制。
以上内容仅供参考,如需更多信息,建议查阅相关文献或咨询数学专业人士。
bresenham画线算法详解
给定两个点起点P1(x1, y1), P2(x2, y2),如何画它们直连的直线呢,即是如何得到上图所示的蓝色的点。
假设直线的斜率0<k>0,直线在第一象限,Bresenham算法的过程如下:1.画起点(x1, y1).2.准备画下一个点,X坐标加1,判断如果达到终点,则完成。
否则找下一个点,由图可知要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点。
2.1.如果线段ax+by+c=0与x=x1+1的交点y坐标大于(y+*y+1))/2则选右上那个点2.2.否则选右下那个点。
3.画点4.跳回第2步5.结束具体的算法如下,原理就是比较目标直线与x+1直线交点的纵坐标,哪个离交点近就去哪个void Bresenhamline(int x0, int y0, int x1, int y1, int color){int x, y, dx, dy;float k, e;dx = x1 - x0;dy = y1 - y0;k = dy / dx;e = -0.5;x = x0;y = y0;for (x= x0;x < x1; x++){drawpixel(x, y, color);//这个是画点子函数e = e + k;if (e > 0){y++;e = e - 1;}}}上述Bresenham算法在计算直线斜率与误差项时用到小数与除法。
可以改用整数以避免除法。
等式两边同时乘以2*dx,得到2*e*dx = 2*e*dx + 2dy, 2*e*dx = 2*e*dx - 2*dx.由于算法中只用到误差项的符号,因此可作如下替换:2*e*dx.改进的Bresenham画线算法程序:将e统一乘以2*dx即变成了整数的Bresenhan算法了,^_^void InterBresenhamline (int x0, int y0, int x1, int y1, int color){int dx = x1 - x0;int dy = y1 - y0;int dx2 = dx << 1;//乘2int dy2 = dy << 1;//乘2int e = -dx;int x = x0;int y = y0;for (x = x0; x < x1; x++){drawpixel (x, y, color);e=e + dy2;if (e > 0){y++;e = e - dx2;}}}。
Bresenham 画线算法_计算机图形学实用教程(第3版)_[共2页]
50于是,仅包含整数运算的中点画线算法的步骤如下。
(1)初始化。
令a = y1 − y2,b = x2 − x1,d = 2*a + b,deta1 = 2*a,deta2 = 2*(a + b),x = x1,y = y1。
(2)用颜色color画像素(x , y)。
(3)判断x是否小于x2。
如果x<x2,则继续执行(4),否则算法结束。
(4)如果d<0,则执行x = x + 1,y = y + 1,d = d + deta2;否则执行x = x + 1,d = d + deta1。
(5)用颜色color画像素(x , y),并转(3)。
3.1.5 Bresenham画线算法Bresenham画线算法是由J. E. Bresenham提出的一种直线生成算法。
与中点画线算法类似,它也是通过选择与理想直线最近的像素来完成扫描转换。
先考虑0<m<1时直线的扫描转换过程。
当0<m<1时,x方向为最大位移方向,因此x 方向上每次递增一个像素单位,y方向的增量为0(表示选择位于直线下方的像素)或者为1(表示选择位于直线上方的像素)。
Bresenham画线算法通过比较从理想直线到位于直线上方的像素的距离和相邻的位于直线下方的像素的距离,来确定y的取值,即哪一个像素是与理想直线最近的像素。
如图3-3所示,假设扫描转换已进行到第k步,即当前像素在(x k,y k)已确定为是最佳逼近理想直线的像素,在第k+1步,由于0<m<1,因此x方向递增1(即x k+1 = x k + 1),需要确定y方向的增量为0(即y k+1 = y k)还是为1(即y k+1 = y k + 1),这个问题相当于是确定下一步要绘制的像素是选P1(x k + 1, y k) 还是P2(x k + 1, y k + 1) 的问题。
如图3-4所示,定义P1与理想直线路径的垂直偏移距离为误差e。
误差e的大小决定了下一步要绘制的像素应选P1(x k + 1,y k) 还是选P2(x k + 1,y k+1)。
Bresenham画线
一、实验目标本次实验目标主要是实现绘制各种情况直线的Bresenham 算法。
二、实验内容本次实验要解决的问题主要是Bresenham 画线法在各个方向的画线的问题。
算法原理简述:过各行各列象素中心构造一组虚拟网格线。
按直线从起点到终点的顺序计算直线与各垂直网格线的交点,然后根据误差项的符号确定该列象素中与此交点最近的象素。
设直线方程为: 其中k=dy/dx 。
因为直线的起始点在象素中心,所以误差项d 的初值d0=0。
x 下标每增加1,d 的值相应递增直线的斜率值k ,即d =d +k 。
一旦d>=1,就把它减去1,这样保证d 在0、1之间。
当d>=0.5时,最接近于当前象素的右上方象素( )而当d<0.5时,更接近于右方象素( )。
为方便计算,令e =d-0.5,e 的初值为-0.5,增量为k 。
当e>=0时,取当前象素(xi ,yi )的右上方象素( );而当e<0时,更接近于右方象素( )。
可以改用整数以避免除法。
三、实验步骤一、打开cgdemoMFC 工程ky x x k y y i i i i i +=-+=++)(1111,++i i y x i i y x ,1+11,++i i y x i i y x ,1+d d dd1.打开Microsoft Visual Studio 20082.File-->Open-->cgdemo.sln二、添加菜单1.左侧视图栏中有三个视图:ClassView、ResourceView、FileView,点击ResourceView2.展开cgdemo,展开Menu,双击IDR_MAINFRAME3.在右侧窗口菜单栏中找到“基本图形生成”菜单项,在该菜单项中添加“Bresenham画线法”,在“Bresenham画线法”属性框中找到ID框填:ID_BRESENHAM。
三、创建、编辑函数1.打开cgdemoView.h头文件,在cgdemoView类枚举类型成员变量m_drawstyle中添加LINE_BRESENHAM。
布雷森汉姆直线算法
布雷森汉姆直线算法布雷森汉姆直线算法(Bresenham's Line Algorithm)是一种计算机图形学中常用的直线绘制算法,其通过在离散的像素格上选择最接近实际直线路径的点来实现高效绘制直线的目的。
该算法由Jack Elton Bresenham在1962年首次提出,被广泛应用于图形显示、打印机及数码扫描仪等领域。
布雷森汉姆直线算法的核心思想是利用整数运算来代替浮点运算,从而提高计算效率。
该算法通过仅使用加法、减法和位移等基本运算,不需要乘法运算和浮点数运算,从而适用于资源有限的嵌入式系统和低成本的图形设备。
算法的基本步骤如下:1. 根据起点P1(x1,y1)和终点P2(x2,y2)确定直线斜率k。
2. 如果|k|≤1,则沿x轴方向递增遍历起点P1到终点P2,并在每个像素上绘制。
若k>1,则沿y轴方向递增遍历P1到P2,绘制每个像素。
3. 对于每一步,根据递增的方向选择相应的像素。
4. 根据斜率k来决定误差累积量,调整绘制位置,保证直线的连续性。
该算法的优势在于其简单而高效的原理,使得绘制直线的速度非常快。
与传统的基于浮点运算的算法相比,布雷森汉姆直线算法的计算开销较小,而且能够得到非常接近实际直线路径的结果,几乎没有明显的视觉差异。
这使得该算法在计算资源有限的场景下非常有用,例如在嵌入式系统中,可以利用该算法绘制图形界面的边界、线条等。
然而,布雷森汉姆直线算法也存在一些局限性。
由于只考虑了整数坐标,因此绘制出来的直线可能会有些锯齿状,这在一些高精度要求的场景下可能会表现出明显的视觉噪点。
此外,该算法仅适用于绘制直线,并不能直接应用于曲线、圆等其他形状的绘制。
总之,布雷森汉姆直线算法是一种非常经典和实用的绘制直线的算法。
它通过巧妙地利用整数计算来取代浮点计算,以提高效率和减少计算资源开销。
虽然存在一些局限性,但在大多数场景下,它仍然是一种高效且精确的绘制直线的选择,对于计算机图形学的发展和应用有着重要的指导意义。
Bresenham中点画线算法
先标明这转载自/xxxxxx91116/article/details/6295714直线扫描算法之---bresenham改进算法(任何斜率,任何方向)by zxx图形学神马的全都是数学,看来以后我不能搞这个,伤脑筋,所以先把我现在懂得先记录下来吧。
不过呢,我的水平实在有限,对于算法这种东西实在难以说明白,请大家包涵。
书上讲的实在是太过简略,所以这里我把一些简单的推导过程都记录下来:1.重温bresenham未改进算法(斜率在0-1之间的直线)我想要记录的是bresenham改进算法,所以在讲解改进算法之前,我先用一个简单的例子说明一下未改进算法的思想:这是一个斜率k在0-1之间的一条直线,我就用斜率为0-1之间的直线来重温:首先,如图1所示,假设x列的像素已定,其坐标为(x,y),那么下一个坐标一定是:(x+1,y+1)或者(x+1,y)。
而是哪一个取决于d的值,如果d>0.5那么就是(x+1,y+1),如果d<0.5,那么就是(x+1,y),而d是什么呢?当然是斜率了。
(原因如下:y=kx+b当x增加1时:y=kx+k+b所以当x增加1是,y方向的增量是d。
)所以每次我们只需要让d=d+k(k是斜率)即可,当d>=1时,就让d减一,这样就保证了d在0-1之间。
当d>0.5,下一个点取(x+1,y+1)当d<0.5,下一个点取(x+1,y)然后呢,我们为了判断的方便,让e=d-0.5,这样就变成了:当e>0,下一个点取(x+1,y+1)当e<0,下一个点取(x+1,y)2.过渡,重温之后,我们就想要改进,为什么要改进呢?因为我们这里面有0.5,还有k,k里面有dx/dy,这些除法和小数都不是我们想要的,我们想要的是,只有整数,且只有加法的算法,下面就全面讨论一下改进算法。
3.改进算法篇(不同斜率,不同方向)这里,我们主要分为4个角度来说明:A.斜率在0-1只间B.斜率在1-无穷之间C.斜率在0-(-1)之间D.斜率在(-1)-负无穷之间E.两种特殊情况,两条直线。
计算机图形学--Bresenham完整算法-画直线、椭圆和圆
#include<windows.h>#include<gl/glut.h>#include"stdio.h"int m_PointNumber = 0; //动画时绘制点的数目int m_DrawMode = 1; //绘制模式 1 DDA算法画直线// 2 中点Bresenham算法画直线// 3 改进Bresenham算法画直线// 4 八分法绘制圆// 5 四分法绘制椭圆//绘制坐标线void DrawCordinateLine(void){int i = -250 ;//坐标线为黑色glColor3f(0.0f, 0.0f ,0.0f);glBegin(GL_LINES);for (i=-250;i<=250;i=i+10){glVertex2f((float)(i), -250.0f);glVertex2f((float)(i), 250.0f);glVertex2f(-250.0f, (float)(i));glVertex2f(250.0f, (float)(i));}glEnd();}//绘制一个点,这里用一个正方形表示一个点void putpixel(GLsizei x, GLsizei y){glRectf(10*x,10*y,10*x+10,10*y+10);}/////////////////////////////////////////////////////////////////////DDA画线算法 //// //// //// /////////////////////////////////////////////////////////////////////void DDACreateLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei num) {//设置颜色glColor3f(1.0f,0.0f,0.0f);//对画线动画进行控制if(num == 1)printf("DDA画线算法:各点坐标\n");else if(num==0)return;//画线算法的实现GLsizei dx,dy,epsl,k;GLfloat x,y,xIncre,yIncre;dx = x1-x0;dy = y1-y0;x = x0;y = y0;if(abs(dx) > abs(dy)) epsl = abs(dx);else epsl = abs(dy);xIncre = (float)dx / epsl ;yIncre = (float)dy / epsl ;for(k = 0; k<=epsl; k++){putpixel((int)(x+0.5), (int)(y+0.5));if (k>=num-1) {printf("x=%f , y=%f,取整后 x=%d,y=%d\n", x, y, (int)(x+0.5),(int)(y+0.5));break;}x += xIncre;y += yIncre;if(x >= 25 || y >= 25) break;}}/////////////////////////////////////////////////////////////////////中点Bresenham算法画直线(0<=k<=1) //// //// //// /////////////////////////////////////////////////////////////////////void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei num){glColor3f(1.0f,0.0f,0.0f);if(num == 1)printf("中点Bresenham算法画直线各点坐标及判别式的值\n");else if(num==0)return;//画线算法的实现GLsizei p=0;GLfloat UpIncre,DownIncre,x,y,d,k,dx,dy;if(x0>x1){x=x1;x1=x0;x0=x;y=y1;y1=y0;y0=y;}x=x0;y=y0;dx=x1-x0;dy=y1-y0;k=dy/dx;if(k>=0&&k<=1){d=dx-2*dy;UpIncre=2*dx-2*dy;DownIncre=-2*dy;while(x<=x1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;x++;if(d<0){y++;d+=UpIncre;}else d+=DownIncre;}}if(k>1){d=dy-2*dx;UpIncre=2*dy-2*dx;DownIncre=-2*dx;while(y<=y1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;y++;if(d<0){x++;d+=UpIncre;}else d+=DownIncre;}}if(k<0&&k>=-1){d=dx-2*dy;UpIncre=-2*dy;DownIncre=-2*dx-2*dy;while(x<=x1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;x++;if(d>0){y--;d+=DownIncre;}else d+=UpIncre;}}if(k<-1){d=-dy-2*dx;UpIncre=-2*dx-2*dy;DownIncre=-2*dx;while(y>=y1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;y--;if(d<0){x++;d+=UpIncre;}else d+=DownIncre;}}}/////////////////////////////////////////////////////////////////////改进的Bresenham算法画直线(0<=k<=1) //// //// x1,y1 终点坐标 //// /////////////////////////////////////////////////////////////////////void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei num) {glColor3f(1.0f,0.0f,0.0f);GLsizei x,y,dx,dy,e,k;if(num == 1)printf("改进的Bresenham算法画直线各点坐标及判别式的值\n");else if(num==0)return;//画线算法的实现GLsizei p=0;if(x0>x1){x=x1;x1=x0;x0=x;y=y1;y1=y0;y0=y;}dx=x1-x0;dy=y1-y0;k=dy/dx;if(k>=0&&k<=1){e=-dx;x=x0;y=y0;while(x<=x1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;x++;e=e+2*dy;if(e>0){y++;e=e-2*dx;}}}if(k>1){e=-dy;x=x0;y=y0;while(y<=y1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;y++;e=e+2*dx;if(e>0){x++;e=e-2*dy;}}}if(k<0&&k>=-1){e=-dx;x=x0;y=y0;while(x<=x1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;x++;e=e+2*dy;if(e<0){y--;e=e+2*dx;}}}if(k<-1){e=-dy;x=x0;y=y0;while(y>=y1){putpixel(x,y);if (p>=num-1) {printf("x=%d,y=%d\n", x, y);break;}p++;y--;e=e-2*dx;if(e<0){x++;e=e-2*dy;}}}}///////////////////////////////////////////////////////////Bresenham算法画圆 //// //// //// ///////////////////////////////////////////////////////////void CirclePoint(GLsizei x,GLsizei y){ putpixel(x,y);putpixel(x,-y);putpixel(y,-x);putpixel(-y,-x);putpixel(-x,-y);putpixel(-x,y);putpixel(-y,x);putpixel(y,x);}void BresenhamCircle(GLsizei x, GLsizei y, GLsizei R, GLsizei num) {glColor3f(1.0f,0.0f,0.0f);GLsizei d;x=0;y=R;d=1-R;if(num == 1)printf("Bresenham算法画圆:各点坐标及判别式的值\n");else if(num==0)return;while(x<=y){CirclePoint(x,y);if (x>=num-1) {printf("x=%d,y=%d,d=%d\n", x, y,d);break;}if(d<0)d+=2*x+3;else{d+=2*(x-y)+5;y--;}x++;}}void Bresenham2Circle(GLsizei a,GLsizei b,GLsizei num){glColor3f(1.0f,0.0f,0.0f);if(num==1)printf("Bresenham算法画椭圆:各点坐标及判别式的值\n");else if(num==0)return;GLsizei x,y;float d1,d2;x=0;y=b;d1=b*b+a*a*(-b+0.5);putpixel(x,y); putpixel(-x,-y);putpixel(-x,y);putpixel(x,-y);while(b*b*(x+1)<a*a*(y-0.5)){if (x>=num-1) {printf("x=%d,y=%d,d1=%d\n", x, y,d1);break;}if(d1<=0){d1+=b*b*(2*x+3);x++;}else{d1+=b*b*(2*x+3)+a*a*(-2*y+2);x++;y--;}putpixel(x,y); putpixel(-x,-y);putpixel(-x,y);putpixel(x,-y);}//while上半部分d2=b*b*(x+0.5)*(x+0.5)+a*a*(y-1)*(y-1)-a*a*b*b;while(y>0){if (x>=num-1) {printf("x=%d,y=%d,d2=%d\n", x, y,d2);break;}if(d2<=0){d2+=b*b*(2*x+2)+a*a*(-2*y+3);x++;y--;}else{d2+=a*a*(-2*y+3);y--;}putpixel(x,y); putpixel(-x,-y);putpixel(-x,y);putpixel(x,-y);}}//初始化窗口void Initial(void){// 设置窗口颜色为蓝色glClearColor(0.0f, 0.0f, 1.0f, 1.0f);}// 窗口大小改变时调用的登记函数void ChangeSize(GLsizei w, GLsizei h){if(h == 0) h = 1;// 设置视区尺寸glViewport(0,0, w, h);// 重置坐标系统glMatrixMode(GL_PROJECTION);glLoadIdentity();// 建立修剪空间的范围if (w <= h)glOrtho (-250.0f, 250.0f, -250.0f, 250.0f*h/w, 1.0, -1.0);elseglOrtho (-250.0f, 250.0f*w/h, -250.0f, 250.0f, 1.0, -1.0);}// 在窗口中绘制图形void ReDraw(void){//用当前背景色填充窗口glClear(GL_COLOR_BUFFER_BIT);//画出坐标线DrawCordinateLine();switch(m_DrawMode){case 1:DDACreateLine(0,0,20,15,m_PointNumber);break;case 2:BresenhamLine(0,0,-20,15,m_PointNumber);break;case 3:Bresenham2Line(1,1,8,6,m_PointNumber);break;case 4:BresenhamCircle(0,0,20,m_PointNumber);break;case 5:Bresenham2Circle(10,8,m_PointNumber);default:break;}glFlush();}//设置时间回调函数void TimerFunc(int value){if(m_PointNumber == 0)value = 1;m_PointNumber = value;glutPostRedisplay();glutTimerFunc(500, TimerFunc, value+1);}//设置键盘回调函数void Keyboard(unsigned char key, int x, int y) {if (key == '1') m_DrawMode = 1;if (key == '2') m_DrawMode = 2;if (key == '3') m_DrawMode = 3;if (key == '4') m_DrawMode = 4;if (key == '5') m_DrawMode = 5;m_PointNumber = 0;glutPostRedisplay();}//void main(void)int main(int argc, char* argv[]){glutInit(&argc, argv);//初始化GLUT库OpenGL窗口的显示模式glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowSize(600,600);glutInitWindowPosition(100,100);glutCreateWindow("基本图元绘制程序);glutDisplayFunc(ReDraw);glutReshapeFunc(ChangeSize);glutKeyboardFunc(Keyboard);//键盘响应回调函数glutTimerFunc(500, TimerFunc, 1);// 窗口初始化Initial();glutMainLoop(); //启动事件处理循环return 0;}。
Bresenham画线算法
以前看到Bresenham画线算法,直接拿来用,没有去推导它,近日,参考一些资料,特整理其算法推导过程如下。
各位大虾如果知道其细节,赶紧闪过,不用浪费时间了。
基本上Bresenham画线算法的思路如下:// 假设该线段位于第一象限内且斜率大于0小于1,设起点为(x1,y1),终点为(x2,y2).// 根据对称性,可推导至全象限内的线段.1.画起点(x1,y1).2.准备画下个点。
x坐标增1,判断如果达到终点,则完成。
否则,由图中可知,下个要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点.2.1.如果线段ax+by+c=0与x=x1+1的交点的y坐标大于M点(即中点)的y坐标的话,下个点为U(x1+1,y1+1)2.2.否则,下个点为B(x1+1,y1)3.画点(U或者B).4.跳回第2步.5.结束.这里需要细化的是怎么判断下个要画的点为当前点的右邻接点还是当前点的右上邻接点.设线段方程:ax+by+c=0(x1<x<x2,y1<y<y2)令dx=x2-x1,dy=y2-y1则:斜率-a/b = dy/dx.从第一个点开始,我们有F(x,1,y1) = a*x1+b*y1+c=0下面求线段ax+by+c=0与x=x1+1的交点:由a*(x1+1)+b*y+c = 0, 求出交点坐标y=(-c-a(x1+1))/b所以交点与M的y坐标差值Sub1 = (-c-a(x1+1))/b - (y1+0.5) = -a/b-0.5,即Sub1的初始值为-a/b-0.5。
则可得条件当Sub1 = -a/b-0.5>0时候,即下个点为U.反之,下个点为B.代入a/b,则Sub1 = dy/dx-0.5.因为是个循环中都要判断Sub,所以得求出循环下的Sub表达式,我们可以求出Sub的差值的表达式.下面求x=x1+2时的Sub,即Sub2 1.如果下下个点是下个点的右上邻接点,则Sub2 = (-c-a(x1+2))/b - (y1+1.5) = -2a/b - 1.5故Sub差值Dsub = Sub2 - Sub1 = -2a/b - 1.5 - (-a/b-0.5) = -a/b - 1.代入a/b得Dsub = dy/dx -1;2.如果下下个点是下个点的右邻接点,Sub2 = (-c-a(x1+2))/b - (y1+0.5) = -2a/b - 0.5故Sub差值Dsub = Sub2 - Sub1 = -2a/b - 0.5 - (-a/b-0.5) = -a/b. 代入a/b得Dsub = dy/dx;于是,我们有了Sub的初始值Sub1 = -a/b-0.5 = dy/dx-0.5,又有了Sub的差值的表达式Dsub = dy/dx -1 (当Sub1 > 0)或dy/dx(当Sub1 < 0).细化工作完成。
直线绘制的三个著名的常用算法(三)Bresenham算法
直线绘制的三个著名的常⽤算法(三)Bresenham算法(3)Bresenham算法
——>【画线算法不依赖于直线⽅程】
——>【提供了⼀个更⼀般的算法,不仅有好的效率还有更⼴泛的适⽤范围】
算法思想:通过各⾏、各列象素中⼼构造⼀组虚拟⽹格线,按照直线起点到终
点的顺序,计算直线与各垂直⽹格线的交点,然后根据误差项的符号确定该列
象素中与此交点最近的象素。
每次x+1,y的递增(减)量为0或1,它取决于实际直线与最近光栅⽹格点的距离,这个距离最⼤误差为0.5。
误差项d的初值为0,d=d+k,⼀旦d>=1,就把它减去1,保证d的相对性,且在0、1之间。
将算法效率提⾼——>也处理成整数加法:
改进⼀:令e=d-0.5
Bresenham算法很像DDA算法,都是加斜率,
但DDA算法是每次求⼀个新的y以后取整来画,
⽽Bresenham算法是判断符号来决定上下两个点。
所以Bresenham算法集中了DDA和中点两个算法的优点,⽽且应⽤范围⼴泛。
【⼩结】计算机科学问题的核⼼就是算法。
把⼀个含乘法和⼀个加法的普通直线算法,是如何通过改进和完善其性能,最终变成整数加法的⼀个精彩过程。
Bresenham算法
Bresenham算法⼀ Bresenham 绘直线使⽤ Bresenham 算法,可以在显⽰器上绘制⼀直线段。
该算法主要思想如下:1 给出直线段上两个端点,根据端点求出直线在X,Y⽅向上变化速率;2 当时,X ⽅向上变化速率快于 Y ⽅向上变化速率,选择在 X ⽅向上迭代,在每次迭代中计算 Y 轴上变化;当时,Y ⽅向上变化速率快于 X ⽅向上变化速率,选择在 Y ⽅向上迭代,在每次迭代中计算 X 轴上变化;3 现在仅考虑情形,在情况下仅需要交换变量即可。
直线斜率,当 d = 0 时,为⼀条⽔平直线,当 d > 0 或 d < 0 时,需要分开讨论,如下图:⼆ Bresenham 绘圆使⽤ Bresenham 绘制圆形,只需要绘制四分之⼀圆即可,其他部分通过翻转图形即可得到。
假设圆⼼位于 (0, 0) 点,半径为 R,绘制第⼀象限四分之⼀圆形,如下图:根据图形可知,从出发,下⼀个可能的选择分别为:1)⽔平⽅向上;2)对⾓⽅向上;3)垂直⽅向上;下⾯计算,根据差值可判断⼤致圆弧位置:1)当时,圆环落在与之间,进⼀步计算圆弧到与的距离以判断应该落在哪个点上;2),由于,,上式可化简为,,将改写为得:,已知,可根据上式快速求解出,当时,下⼀点落在上,当时,下⼀点落在上;3)当时,圆环落在与之间,进⼀步计算圆弧到和的距离以判断应该落在哪个点上;4),可化简为:,将改写为得:,已知,可根据上式快速求解出,当时,下⼀点落在上,当时,下⼀点落在上;5)以上推导中,已知可以快速求解,同时,已知也可以快速推导出,以下分类讨论:a. 当时,有:,进⼀步整理得:;b. 当时,有:,进⼀步整理得:;c. 当时,有:,进⼀步整理得:。
以下给出 Bresenham 绘圆实现:1void Bresenham_Circle(PairS center, int radius, std::vector<PairS>& circle)2 {3 PairS start(0, radius);4int Delta = (start.x + 1) * (start.x + 1) +5 (start.y - 1) * (start.y - 1) - radius * radius;67 std::vector<PairS> tmp;8 tmp.push_back(start);910while (start.y > 0)11 {12int state = -1;1314if (Delta < 0)15 {16int delta = (Delta + start.y) * 2 - 1;17if (delta < 0)18 {19 start.x += 1;20 state = 0;21 }22else23 {24 start.x += 1;25 start.y -= 1;26 state = 1;27 }28 }29else30 {31int delta = (Delta - start.x) * 2 - 1;32if (delta < 0)33 {34 start.x += 1;35 start.y -= 1;36 state = 1;37 }38else39 {40 start.y -= 1;41 state = 2;42 }43 }4445if (state == 0)46 Delta = Delta + start.x * 2 + 1;47else if (state == 1)48 Delta = Delta + start.x * 2 - start.y * 2, +2;49else if (state == 2)50 Delta = Delta - start.y * 2 + 1;51else52break;5354 tmp.push_back(start);55 }5657 std::vector<PairS> tmp2;58for (int i = 0; i < tmp.size(); ++i)59 {60 PairS p(tmp[i].x, tmp[i].y);61 tmp2.push_back(p);62 }63for (int i = tmp.size() - 1; i >= 0; --i)64 {65 PairS p(tmp[i].x, -tmp[i].y);66 tmp2.push_back(p);67 }68for (int i = 0; i < tmp2.size(); ++i)69 {70 PairS p(tmp2[i].x, tmp2[i].y);71 circle.push_back(p);72 }7374for (int i = tmp2.size() - 1; i >= 0; --i)75 {76 PairS p(-tmp2[i].x, tmp2[i].y);77 circle.push_back(p);78 }7980for (int i = 0; i < circle.size(); ++i)81 {82 circle[i].x += center.x;83 circle[i].y += center.y;84 }85 }参考资料计算机图形学得算法基础 David E Rogers。
bresenham算法画直线例题
bresenham算法画直线例题摘要:1.介绍Bresenham算法2.Bresenham算法的原理3.使用Bresenham算法画直线的步骤4.Bresenham算法的应用示例5.总结Bresenham算法在计算机图形学中的重要性正文:Bresenham算法是一种计算几何中用于画直线的算法,由英国计算机科学家Jack Bresenham于1965年提出。
该算法广泛应用于计算机图形学、视频游戏和各种嵌入式系统。
Bresenham算法的核心思想是使用简单的加法和减法运算,以及位运算来计算直线上的每个点的坐标,从而实现画直线的目标。
Bresenham算法的原理基于对直线方程y = mx + b的观察。
当m为正数时,直线是从左下到右上的;当m为负数时,直线是从左上到右下的。
根据这个特点,Bresenham算法将画直线的过程分为两个阶段:第一阶段是向上扫描,第二阶段是向下扫描。
在每一阶段,算法仅使用简单的加法和减法运算来更新当前点的坐标。
使用Bresenham算法画直线的步骤如下:1.初始化x和y坐标,以及直线的斜率m和截距b。
2.判断m的正负性。
如果m为正,进入第一阶段;如果m为负,进入第二阶段。
3.在第一阶段,每次将y坐标加b,然后将x坐标加m,直到x坐标达到最大值或y坐标达到最小值。
4.在第二阶段,每次将y坐标加b,然后将x坐标减m,直到x坐标达到最小值或y坐标达到最大值。
5.如果需要,可以将画直线的过程进行迭代,以获得更高的精度。
Bresenham算法在计算机图形学中具有重要应用价值。
它不仅计算简单、速度快,而且可以在各种不同的硬件平台上实现。
下面给出一个使用Bresenham算法画直线的示例:```pythondef bresenham_line(x0, y0, x1, y1):m = (y1 - y0) / (x1 - x0)b = y0 - m * x0x = x0y = y0e = 0if m < 0:y = y0while x < x1:put_pixel(x, y)e = e + abs(m)if e > abs(b):x = x + 1e = e - abs(m)y = y + 1else:x = x0while y < y1:put_pixel(x, y)e = e + abs(m)if e > abs(b):y = y + 1e = e - abs(m)x = x + 1bresenham_line(0, 0, 10, 5)```总之,Bresenham算法是一种简单而有效的计算几何画直线方法。
Bresenham快速画直线算法
Bresenham快速画直线算法⼀、算法原理简介:算法原理的详细描述及部分实现可参考: Fig. 1假设以(x, y)为绘制起点,⼀般情况下的直观想法是先求m = dy /dx(即x每增加1, y的增量),然后逐步递增x, 设新的点为x1 = x + j,则y1 = round(y + j * m)。
可以看到,这个过程涉及⼤量的浮点运算,效率上是⽐较低的(特别是在嵌⼊式应⽤中,DSP可以⼀周期内完成2次乘法,⼀次浮点却要上百个周期)。
下⾯,我们来看⼀下Bresenham算法,如Fig. 1,(x, y +ε)的下⼀个点为(x, y + ε + m),这⾥ε为累加误差。
可以看出,当ε+m < 0.5时,绘制(x + 1, y)点,否则绘制(x + 1, y + 1)点。
每次绘制后,ε将更新为新值:ε = ε + m ,如果(ε + m) <0.5 (或表⽰为2*(ε + m) < 1)ε = ε + m – 1, 其他情况将上述公式都乘以dx, 并将ε*dx⽤新符号ξ表⽰,可得ξ = ξ + dy, 如果2*(ξ + dy) < dxξ = ξ + dy – dx, 其他情况可以看到,此时运算已经全变为整数了。
以下为算法的伪代码:ξ← 0, y ← y1For x ← x1 to x2 doPlot Point at (x, y)If (2(ξ + dy) < dx)ξ←ξ + dyElsey ← y + 1,ξ←ξ + dy – dxEnd IfEnd For⼆、算法的注意点:Fig. 2在实际应⽤中,我们会发现,当dy > dx或出现Fig.2 右图情况时时,便得不到想要的结果,这是由于我们只考虑dx > dy,且x, y的增量均为正的情况所致。
经过分析,需要考虑8种不同的情况,如Fig. 3所⽰:(Fig. 3)当然,如果直接在算法中对8种情况分别枚举,那重复代码便会显得⼗分臃肿,因此在设计算法时必须充分考虑上述各种情况的共性,后⾯将给出考虑了所有情况的实现代码。
Bresenham画线算法
我们若换一个角度来分析Bresenham 画线算法,将得到另外一个更加简短的程序。
新的思路根据直线的斜率来确定或者选择变量在x或y方向上递增1个单位,另一个方向的递增为0或1,它取决于理想直线与最近网格点位置的距离。
这一距离称为“偏差”。
(有的书上称为“误差”)。
我们同样以八分圆域(如图3-1)的1a 区域为例来进行分析。
在这个区域内,直线的斜率在0和1之间。
由下图3-c可见,若通过(0,0)的所求直线的斜率大于1/2,它与x = 1直线的交点离直线y = 1较近,离直线y = 0较远,因此点T比点S更逼近理想直线。
如果直线小于1/2,则正好相反。
当斜率恰好等于1/2时,没有确定的选择标准,我们同样按照书本上的约定,选择S点。
图3-c Bresenham画线算法示意图与中点画线算法类似,我们只要判断偏差项的符号,就可以知道应该选择S点还是T点了。
这很显而易见,我们可以假设偏差项的初值为-1/2,这样设计是因为:如果直线的斜率大于1/2,那么当斜率与偏差项相加得到的结果将大于0,应该取T点,如果斜率小于1/2,那么斜率与偏差项的和将小于0,应该取S点,而当斜率等于1/2时,斜率与偏差项的和也正好为0。
因此,对于偏差项的计算可以有这样一个公式(Bresenham偏差判别式):e = e + k式中e为偏差项,k为直线的斜率。
需注意的是,当误差项≥1时,必须将它减去1,以始终保证误差项在0~1之间。
下面给出1a区域内算法的流程图。
图3-d1a区域内Bresenham算法流程图上面介绍的是算法的思路,而由于算法中含有浮点数的运算,因此,为了提高程序的执行速度,我们采用与书本上相同的办法——用2e代替e,得到整数Bresenham 算法。
这样算法可以避免浮点数运算,使算法更快,更适合硬件与固件的实现。
值得注意的是,图3-d的流程图仍然适合整数Bresenham算法。
同样的,我们也必须将算法推广到其他象限区域,这需要对算法进行适当的修改。
通用整数bresenham算法
通用整数bresenham算法
Bresenham算法是一种用于在计算机屏幕上绘制直线、圆和其
他形状的算法。
在这里,我将重点介绍通用整数Bresenham算法,
用于绘制直线。
通用整数Bresenham算法是一种用于在计算机屏幕上绘制直线
的算法。
它是一种基于整数运算的算法,因此在计算机上执行速度
很快。
该算法通过在每个步骤中选择最接近直线路径的像素来绘制
直线。
该算法的基本原理是利用斜率来确定下一个要绘制的像素。
在
每一步中,根据直线斜率的大小来决定是向横坐标方向移动一个像
素还是向纵坐标方向移动一个像素。
通过适当的取整和判断,Bresenham算法能够以非常高效的方式绘制直线。
通用整数Bresenham算法的优点之一是它不需要使用浮点运算,这使得它非常适合于嵌入式系统和其他资源受限的环境。
此外,该
算法的实现比较简单,适用于各种编程语言和平台。
然而,通用整数Bresenham算法也有一些局限性。
例如,当直
线的斜率非常大或非常小的时候,该算法可能会出现绘制的直线与实际直线有所偏差。
此外,对于对角线上的像素,该算法可能不够精确。
总的来说,通用整数Bresenham算法是一种高效的直线绘制算法,特别适合于需要在计算机屏幕上绘制直线的应用程序。
它的简单性和高效性使得它成为计算机图形学中常用的算法之一。
布兰森汉姆(Bresenham)算法画线
int s1,s2,status,i; int Dx,Dy,sub;
dx=x1-x0; if(dx>=0) s1=1; else s1=-1; dy=y1-y0; if(dy>=0) s2=1; else s2=-1; //判断Y的方向是增加还是降到的 //X的方向是降低的 //X的方向是增加的
( Word Converter - 未滨册 ) http://www.
( Word Converter - 未滨册 ) http://www.
} }
这是在以(63,32)为圆心,32为半径画的圆(帏问题是当圆大后,会有部分画不出来,有待完善)
4、整幏画图部分 这个比较简单,帱直接上程序了 void LCD_fulldisplay_picture_2(const uchar *pic) //全幏显示图片方滕2 { unsigned int x=0; unsigned char i,j; Write_command(0x34); Write_command(0x36); for(i=0;i<32;i++) { Write_command(0x80|i); Write_command(0x80); //列位置 //行位置 //扩幕指令动作 //扩幕指令动作 //上半幏显示
st7920控制的 12864液晶画线,画圆,作图
1、打点部分 该部分已在该论坛发帖,这里不帱重复了 (打点是所有绘图的基础) 2、画线部分 先看程序 /******************************************************** * 名称:GUI_Line() 采用布兰森湉姆(Bresenham)算滕画线 * 功能:任意两点间的直线。根据硬件特点,实现加速。 * 入口参数:x0 * * ‘ y0 x1 y1 直线起点所在行的位置
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。