图形用户接口实验报告

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
10 分钟后休眠。前者可通过添加建立触屏设备唤醒。
2.画 点
显示器的坐标系方向一般如右图所示,开发板上的 LCD 坐
标系方向也这样。这与人们从左到右、从上到下的阅读习惯一致。
所画点的坐标(x,y)与相对于 FrameBuffer 首地址的 偏移量 offset 一一对应,计算公式为 offset=(y*vinfo.xres+x)*vinfo.bits_per_pixel/8。
线可一次画出更多的点。比如对斜率为 0<k<1 的直线,斜率 k 越接近于 0,可一次确定的点数
越多。从图形上直观理解,就是直线与坐标轴的夹角越小时,在同一行(列)的点越多。我认为 这种优化的应用范围有限,为避免程序过于凌乱,不如不用。
以上是对斜率为 0<k<1 的直线画法。对其他斜率范围的直线,只需改变坐标的符号或/和
以下方法画出的线段所组成的点数为线段与其夹角较小的坐标轴上的坐标差加 1。比如端点 坐标为( 0 ,0 ) ,(4 , 17 ) 的线段,斜率大于 1,所画的点数为:17+1=18。
对于斜率 k=0,∞,±1 的线段,可以通过简单的坐标递增(减)画点画出来。对于 k 等于 其他值的直线,我在网上搜索到 Bresenham 于 1965 年提出的直线生成算法。下面的内容是
用,将 dp 拿来作为循环的判断变量。令 dp 等于线段与其夹角较小的坐标轴上的端点坐标差的 一半,循环结构为:“while(dp>=0){dp--;......}”。
比如 k>1 时,点数为 y2−y1 +1。令 dp=(y2−y1)/2=dq/2 。这样,所画的点数为: y2−y1 为偶数时,共有奇数个点,(dp+1)*2=y2−y1+2,中点多画一次;或 y2−y1 为奇 数时,共有偶数个点,(dp+1)*2=y2−y1 +1。
坐标不再直接用到。
对不同斜率范围(k≠0,∞,±1)的直线,程序中令 (1) x1<x2,dp=x2−x1,dq=y2−y1; (2) 数组 offset[2] 存放从两端开始所画点的偏移量,令 offset[0] 对应于较小的纵坐标, offset[1] 对应于较大的纵坐标,也就是令初值满足 offset[0] < offset[1] ; (3) d_neg,d_pos 分别是 d 在 d<0,d>0 时的增量; (4) off_neg,off_pos 分别是 offset 在 d<0,d>0 时的增量,offset[0] 总是“+” 增量,offset[1] 总是“−”增量。 画点循环中采用了前面提到的对称画法。进入循环后,dp=x2−x1,dq=y2−y1 不再有
一、实验目的
PXA270 嵌入式实验Fra Baidu bibliotek告 2
101180032
1.了解嵌入式系统图形界面的基本编程方法 2. 学习图形库的制作
二、实验系统
EELIOD 嵌入式开发平台,包括 16 位 TFT LCD,分辨率为 640*480。
三、实验内容
在 Frame Buffer 基础上实现画点/线/圆和 BMP 图像显示,并制作成相应的动态库
为 16、OFF_COL 为(BPP/2)、OFF_ROW 为(XRES*BPP/8),SCREENSIZE 为 (XRES*YRES*BPP/8)。这样可能不利于程序的可移植性,但初次运行时,也只需要改动前
三个宏定义。
配置内核时,在 Multimedia Capabilities Port drivers ---> GUI to be supported 选项下,若选择 Tinyx,LCD 会在 1 分钟后休眠。若选择 Qtopia ,LCD 在
d+=2*dy; }
另外,在网上查到意在利用线段的对称性减少比较次数的改进算法,即从线段两端向线段中 点同时画点。原算法分为奇数点和偶数点进行讨论。我认为无须如此烦琐,直接
以”x<=(x1+x2)/2”作为循环条件,这样在奇数点情况下只是对中点一个点画了两次。 此外,在网上看到有多篇论文指出可进一步优化 Bresenham 算法,对特定斜率范围的直
也可以写作:“*(unsigned short int *)(fbp+offset)=color;”或 “lseek(fbp,offset,SEEK_SET);write(fbp,&color,2);”。至于孰优孰劣,未做探究。
3.画 线
显示器上的像素单元是离散的,无法真正显示出数学上所定义的点、线、圆等几何图形,实 际上显示的是若干在视觉上逼近真实图形的点。
顺序,就可以套用以上程序画出。
我自己认为有效的一种优化是避免重复的计算偏移量。结合程序,说明如下。 入口参数为线段两端点的坐标和颜色值。
offset=(y*XRES+x)*OFF_COL。可见 OFF_COL、OFF_ROW 分别表示换行、 换列时 offset 的增量。因为所画的下一个点总是当前点周围 8 个点之一,这样,计算出端点的 偏移量后,总可以用当前的 offset 与 OFF_COL 和 OFF_ROW 的组合加减来画点。此后,
k
y~ [0]
d init
d
1<k dq>dp
<0 2*dp−dq >0
+
y1
0<k<1 dq<dp
2*dq−dp
<0 >0
k<−1 |dq|>dp
<0 2*dp+dq >0
依上迭代,可以仅由整数加法和乘法运算求得相应的纵坐标,对 d=0 的情况,两个点都任
选其一。程序示意如下:
dy=y2-y1; dx=x2-x1; d=2*dy-dx; for(x=x1,y=y1;x<=x2;x++) {
drawdot(x,y); if(d>0)
{ y++; d+=2*(dy-dx); } else
MAP_SHARED, fd, 0);” “munmap(fbp,screensize);”
若映射成功,mmap()函数返回一段大小为 screensize 的连续内存空间的首地址。 一般情况下,finfo.line_length=vinfo.xres*vinfo.bits_per_pixel/8。如果不等, 将无法正常显示图形和图像。此时 screensize 应按 finfo.line_length*vinfo.yres 计算, 下面的 offset 应按(y*finfo.line_length+x*vinfo.bits_per_pixel/8)计算。 实验中将 vinofo.xres、vinfo.bits_per_pixel 当作已知常数,以避免调用子函数时非 必要的参数传递。在 gui_macro.h 头文件中宏定义 XRES 为 640、YRES 为 480、BPP
相应的关键语句如下:
“fd = open ( "/dev/fb", O_RDWR ); ” “ioctl(fd, FBIOGET_FSCREENINFO, &finfo);” “ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);” “screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; ” ”fbp =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, \
若颜色值不是 565 的 RGB 格式,需先做转化为 RGB 颜色 模型,再取各分量的高位进行组合。16 位的颜色值 color 按地 址高低顺序写到 FrameBuffer 上。主要程序如下,其中 “(unsigned char *)”和“&0xff”可省略不写。
offset=(y*XRES+x)*OFF_COL; *(unsigned char *)(fbp+offset)=color&0xff; *(unsigned char *)(fbp+offset+1)=(color>>8)&0xff;
1.FrameBuffer
FrameBuffer(帧缓冲区)是从 2.2.xx 内核开始出现的一种驱动程序接口,这种接口将 显示设备抽象化,使应用程序无须涉及底层硬件。FrameBuffer 通过/dev/fb0 等设备节点进 行访问。将 FrameBuffer 映射到进程空间之后,可以直接进行读写操作,此时显示屏上的像 素单元按一定的顺序与 FrameBuffer 中的数据一一对应。对 FrameBuffer 的写操作在被 FrameBuffer 和显示屏之间的中间件提取、处理后显示到显示屏上。实验系统中的这一中间件 就是集成在处理器内部的 LCD 控制器。
对该算法的描述和改进。
设线段斜率为 0<k<1,端点坐标为 ( x₁, y₁) ,( x₂ , y₂ ) ,x₁<x₂ ,y₁<y₂ ,记 dy=y₂ −y₁,dx=x₂ −x₁,直线方程为 k*x+b−y=0。画出来的点数为 dx+1。
先画出点 ( x₁, y₁ ) ,由 0<k<1 ,知下一个点必为 ( x₁+1 , y₁ ) 或 ( x₁+1 , y₁+1 ) 。根据这两点的中点 M ( x₁+1 , y₁+1/2 ) 与直线的相对位置来做取舍。记 d=k*x+b−y,M 点坐标代入 d,得
进入画点循环前相关变量的初始化和循环条件如下表所示。其中“y~[0]”栏表示 offset[0]
所对应的(纵)坐标。
对每一条 k≠0,∞,±1 的线段,经过两次判断,即确定了 d、d_neg、d_pos、offset、off_neg、off_pos、dp 五个量的(初)值。之后进入统一的
循环结构。
dq
d=k*(x₁+1)+b−(y₁+1/2)=k*x₁+b−y₁+k−1/2=k−1/2 。 若 d<0,则点 M 在直线上方,取 ( x₁+1 , y₁ ) ;若 d>0,则点 M 在直线下方,取 ( x₁+1 , y₁+1 ) 。 这里起作用的只是 d 的符号,而 k=dy/dx,可以给 d 乘 2*dx(>0),重新定义 d=2*dy*x+2*dx*(b−y)。则上面 d 的初值写为 d=2*dy−dx 。 参照下图,对于一般情况,假设现在已经画出点 ( i , j ) ,则下一个点必为 ( i+1 , j ) 或 ( i+1 , j+1 ) 。用于判断第 (i+1) 个点的 di+1=2*dy*(i+1)+2*dx*[b−(j+1/2)] 。若 di+1<0,则取 ( i+1 , j ) ,若 di+1 >0,则取 ( i+1 , j+1 ) 。 若取 ( i+1 , j),则第(i+1)个点必为( i+2 , j ) 或 ( i+2 , j+1 ), di+2=2*dy*(i+2)+2*dx*[b−(j+1/2)]=di+1+2*dy 。 若取 ( i+1 , j+1) ,则第(i+2)个点必为 ( i+2 , j+1 ) 或 ( i+2 , j+2 ) , di+2=2*dy*(i+2)+2*dx*[b−(j+1+1/2)]=di+1+2*(dy−dx) 。
FrameBuffer 的大小由显示屏的位深、分辨率、显示模式决定。单屏模式下,其大小为 FrameBufferSize=Width*Height*Bits_per_pixel/8 (bytes)。 实验系统中,LCD 的分辨为 640*480,位深为 16,RGB 组合为 565 格式。 清空屏幕可执行:”dd if=/dev/zero of=/dev/fb0 bs=1280 count=480”。显示 文件 temp 到屏幕上可执行:“cat temp > /dev/fb0”。将屏幕内容保存到文件 temp 上可 执行:”cp /dev/fb0 temp”。 应用程序中,操作 FrameBuffer 的一般步骤如下: (1) 打开/dev/fb 设备文件; (2) 用 ioctl 函数获取显示屏的位深、分辨率等信息,两个重要的结构体类型是 fb_fix_screeninfo 和 fb_var_screeninfo ; (3) 用 mmap 函数将 FrameBuffer 映射到用户空间; (4) 应用程序读写 FrameBuffer,进行绘图和图片显示等; (5) 解除映射,关闭/dev/fb 设备文件。
相关文档
最新文档