本帖最后由 常见泽1 于 2014-12-15 22:37 编辑
LCD12864 GUI学习
第8篇 画任意线段
From EE: 常见泽
(刚换了工作,都忘记这一篇还没发,发出来大家看看把)
1. 原理图引脚(msp430g2452)
EN —— P2.0
RS —— P2.1
PSB —— P2.2
RW —— P2.3
2. Breshenham算法
基本上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
令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).细化工作完成。
3. 程序介绍
(代码也是改编的ZLG GUI的,具体里面的细节还要读者自己去研究了,我也是大概看懂了,会修改)
- void GUI_Line(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1)
- { unsigned int dx; // 直线x轴差值变量
- unsigned int dy; // 直线y轴差值变量
- unsigned char dx_sym; // x轴增长方向,为-1时减值方向,为1时增值方向
- unsigned char dy_sym; // y轴增长方向,为-1时减值方向,为1时增值方向
- unsigned int dx_x2; // dx*2值变量,用于加快运算速度
- unsigned int dy_x2; // dy*2值变量,用于加快运算速度
- unsigned int di; // 决策变量
-
-
- dx = x1-x0; // 求取两点之间的差值
- dy = y1-y0;
-
- /* 判断增长方向,或是否为水平线、垂直线、点 */
- if(dx>0) // 判断x轴方向
- { dx_sym = 1; // dx>0,设置dx_sym=1
- }
- else
- { if(dx<0)
- { dx_sym = -1; // dx<0,设置dx_sym=-1
- }
- else
- { // dx==0,画垂直线,或一点
- GUI_RLine(x0, y0, y1);
- return;
- }
- }
-
- if(dy>0) // 判断y轴方向
- { dy_sym = 1; // dy>0,设置dy_sym=1
- }
- else
- { if(dy<0)
- { dy_sym = -1; // dy<0,设置dy_sym=-1
- }
- else
- { // dy==0,画水平线,或一点
- GUI_HLine(x0, y0, x1);
- return;
- }
- }
- /* 将dx、dy取绝对值 */
- dx = dx_sym * dx;
- dy = dy_sym * dy;
- /* 计算2倍的dx及dy值 */
- dx_x2 = dx*2;
- dy_x2 = dy*2;
-
- /* 使用Bresenham法进行画直线 */
- if(dx>=dy) // 对于dx>=dy,则使用x轴为基准
- { di = dy_x2 - dx;
- while(x0!=x1)
- { DrawPoint(x0, y0,1);
- x0 += dx_sym;
- if(di<0)
- { di += dy_x2; // 计算出下一步的决策值
- }
- else
- { di += dy_x2 - dx_x2;
- y0 += dy_sym;
- }
- }
- DrawPoint(x0, y0, 1); // 显示最后一点
- }
- else // 对于dx<dy,则使用y轴为基准
- { di = dx_x2 - dy;
- while(y0!=y1)
- { DrawPoint(x0, y0, 1);
- y0 += dy_sym;
- if(di<0)
- { di += dx_x2;
- }
- else
- { di += dx_x2 - dy_x2;
- x0 += dx_sym;
- }
- }
- DrawPoint(x0, y0, 1); // 显示最后一点
- }
- }
复制代码
4. 显示