单片机屏幕填充任意封闭图形
对于基础的矩形填充来说比较简单,只需找到最大最小坐标然后画线挨行填充即可https://i1.hdslb.com/bfs/article/e80e1347b52dd02d42ded5e1b3806ceac1497a83.png@1192w.webp设定画线接口函数为Draw_Line(int x1,int y1,int x2,int y2,int color);则矩形填充程序为:int maxx, maxy, minx, miny;int i;for (i = miny; i < maxy; i++){Draw_Line(minx,i,maxx i, 0xF800);}填充圆形的方式为:在以圆的外接正方形范围内挨行判断坐标点和圆心的距离,小于等于半径的时候才画点(灰色区域的半径黄色箭头大于半径,不画点,橙色区域半径蓝色箭头小于半径,画点)https://i1.hdslb.com/bfs/article/5897c320cdfe33b7348b260215415bd93cb65fa2.png@624w_630h.webp
不过为了加速绘制速度,减少计算量,一般不使用挨个画点的方式,就像画圆一样不用角度递增挨个画点,加速方式是拆分成画线,一次性绘制一条线,因为屏幕最擅长的就是横平竖直的画线,加速方式如下。707/1000=0.707=1.414/2 ≈ √2 / 2static void draw_hline(uint16_t x0,uint16_t y0,uint16_t len,uint16_t color){ if(len==0)return; Draw_Line(x0,y0,x0+len-1,y0,color);}static void fill_circle(uint16_t x0,uint16_t y0,uint16_t r,uint16_t color){ uint32_t i; uint32_t imax = ((uint32_t)r*707)/1000+1; uint32_t sqmax = (uint32_t)r*(uint32_t)r+(uint32_t)r/2; uint32_t x=r; draw_hline(x0-r,y0,2*r,color); for (i=1; i<=imax; i++) { if ((i*i+x*x)>sqmax)// draw lines from outside { if (x>imax) { draw_hline (x0-i+1,y0+x,2*(i-1),color); draw_hline (x0-i+1,y0-x,2*(i-1),color); } x--; } draw_hline(x0-x,y0+i,2*x,color); draw_hline(x0-x,y0-i,2*x,color); }}更为复杂的图形填充方式有几种,对于凸多边形一般是拆分为三角形,使用三角形填充独立部分,凹多边形等复杂图形还是使用扫描方式判断坐标是否在封闭图形内。
判断程序如下。
uint16_t is_point_in(int nvert, float *vertx, float *verty, float testx, float testy){ uint8_t res; int i, j, c = 0; res = 0; if ((testx > maxx) || (testy > maxy) || (testx < minx) || (testy < miny)) return 1000; for (i = 0, j = nvert - 1; i < nvert; j = i++) { if ( ( (verty > testy) != (verty > testy) ) && (testx < (vertx - vertx) * (testy - verty) / (verty - verty) + vertx) ) c = !c; } return c;}增加原多边形坐标构建和区域显示和填充效果
void draw_shape(int nvert, float *vertx, float *verty){ int i, j; POINT_COLOR = BLUE; for (i = 0; i < nvert - 1; i++) { printf("%5.1f,%5.1f -->> %5.1f,%5.1f\r\n", vertx, verty, vertx, verty); LCD_DrawLine((uint16_t)vertx, (uint16_t)verty, (uint16_t)vertx, (uint16_t)verty); } LCD_DrawLine((uint16_t)vertx, (uint16_t)verty, (uint16_t)vertx, (uint16_t)verty);}void create_five_star(float *vertx, float *verty, float x, float y, float r, float offset_angle){ //生成五角星坐标 int i, j; for (i = 0; i < 10; i++) { if (i % 2) { *(vertx + i) = cos((i * 36 + offset_angle) * 3.1415926 / 180) * r + x; *(verty + i) = sin((i * 36 + offset_angle) * 3.1415926 / 180) * r + y; } else { *(vertx + i) = cos((i * 36 + offset_angle) * 3.1415926 / 180) * r * 0.3 + x; *(verty + i) = sin((i * 36 + offset_angle) * 3.1415926 / 180) * r * 0.3 + y; } }}void fill_shape(uint16_t color){ int i, j; int res; for (i = miny; i < maxy; i++) { for (j = minx; j < maxx; j++) { res = is_point_in(points, pointsx, pointsy, j, i); if (res == 1000) { } else if ((res % 2) == 0) { } else if ((res % 2) == 1) { LCD_Fast_DrawPoint(j, i, color); } } }}调用演示
calc_min_max(points, pointsx, pointsy);draw_shape(points, pointsx, pointsy);fill_shape(BLUE);create_five_star(pointsx,pointsy,240,400,200,-36);calc_min_max(10,pointsx,pointsy);draw_shape(10,pointsx,pointsy);
单片机的内存通常有限,因此在填充图形时需要考虑内存的使用。避免使用过多的临时变量和复杂的算法,以减少内存占用。 对于多边形等复杂图形,可能需要将其拆分为更简单的图形(如三角形)进行填充,或者使用扫描线填充算法等更复杂的算法。 选择合适的填充算法非常重要。常见的填充算法包括种子填充法、边界填充法和扫描线算法。每种算法都有其优缺点,需要根据具体情况选择。 关于GUI的画图这个都是标准函数 对于简单的规则图形,如矩形、圆形等,要精确计算其边界坐标;对于复杂的不规则图形,需要通过合适的算法或工具来获取准确的坐标点集,以便正确地描绘出图形的轮廓。 对于一些精细的图形,可能需要进行抗锯齿处理,以提高填充效果的平滑度。 在填充图形时,可能需要考虑抗锯齿处理以提高图形的视觉质量。这会增加算法的复杂度,但也可能提高用户的满意度。
在图形填充过程中,如果单片机需要处理其他中断事件,要确保中断处理不会影响图形填充的正常进行。可以采用中断优先级管理、中断屏蔽等方法来避免中断干扰。 单片机的计算能力和内存有限,因此填充算法需要尽量高效。例如,可以使用线段绘制来加速填充过程,而不是逐点填充。 根据单片机屏幕的显示能力选择合适的颜色模式和颜色值。如果是彩色屏幕,要考虑颜色的搭配和对比度,以便使填充的图形更加醒目和易于区分;如果是单色或灰度屏幕,则需要通过灰度值的变化来表现图形的不同层次和细节。 图形填充过程可能会消耗较多的电量,特别是在需要频繁更新图形的情况下。要合理控制单片机的功耗,采用低功耗模式或优化算法来降低功耗。 不同的显示屏对驱动信号有不同的要求,要确保单片机的驱动能力能够满足显示屏的需求。如果驱动能力不足,可能会出现显示颜色不准确、亮度不均匀等问题。 最终都是转化为画点操作 根据图形的复杂度选择合适的填充算法。对于简单的图形(如矩形),可以直接逐行填充;对于复杂的图形(如圆形或任意多边形),可能需要使用更高级的算法,如扫描线填充或三角形填充 图形的边界和内部点。通常,这需要图形的数学描述,如多边形的顶点坐标。
对于复杂的图形,可能需要将图形分解为多个简单的形状(如矩形、三角形)进行处理。 注意填充算法对内存的使用情况,避免内存溢出或不必要的内存占用。 如果图形边缘不是垂直或水平线,可能需要考虑抗锯齿技术以平滑边缘。 如果需要实现用户与图形的交互功能,如点击、拖动等,要考虑如何检测用户的输入操作,并及时更新图形的状态和显示。这需要编写相应的交互逻辑代码,并与图形填充功能相结合。 为了提高绘制效率,可以采用一些优化技巧。例如,对于圆形填充,可以拆分成多条水平线进行绘制,而不是逐个像素绘制