这是昨天程序的升级版,增加了缩放、移动、参数显示等功能。一个手指可以拖到图形,两个手指靠近或分开可以缩放。
此外使用了Guess算法减少计算次数,加快显示速度。
目前已知问题,手势识别还不够灵敏,等待进一步改进。
- #include "mbed.h"
- #include "LCD_DISCO_F746NG.h"
- #include "TS_DISCO_F746NG.h"
- #include <math.h>
- #define ITERATION 150
- #define BAILOUT 4
- LCD_DISCO_F746NG lcd;
- TS_DISCO_F746NG ts;
- TS_StateTypeDef TS_State;
- uint8_t ts_nb = 0;
- uint16_t tsx0[2], tsy0[2];
- uint16_t tsx[2], tsy[2];
- uint8_t tscnt = 0;
- double zoom = 1;
- Timer tmr;
- uint8_t msg[20];
- uint16_t screen_width, screen_height;
- double mx1, my1, mx2, my2;
- uint16_t calcMandelBrot(double x, double y)
- {
- uint16_t i;
- double xx, yy, tx, ty;
-
- xx = yy = 0;
- i = 0;
- while((i < ITERATION) && ((xx*xx + yy*yy) < BAILOUT))
- {
- tx = xx*xx - yy*yy + x;
- ty = 2*xx*yy + y;
- xx = tx;
- yy = ty;
- i++;
- }
- return i;
- }
- uint8_t c[150][100];
- void rectMandelBrot(double x1, double y1, double x2, double y2)
- {
- double dx, dy;
- uint16_t i, j, n;
- uint32_t color;
-
- lcd.SetTextColor(LCD_COLOR_BLACK);
- lcd.FillRect(0, 0, screen_width, screen_height);
- lcd.SetTextColor(LCD_COLOR_WHITE);
- sprintf((char *)msg, "%10f", x1);
- lcd.DisplayStringAt(screen_width+5, 224, msg, LEFT_MODE);
- sprintf((char *)msg, "%10f", y1);
- lcd.DisplayStringAt(screen_width+5, 236, msg, LEFT_MODE);
- sprintf((char *)msg, "%10f", x2);
- lcd.DisplayStringAt(screen_width+5, 248, msg, LEFT_MODE);
- sprintf((char *)msg, "%10f", y2);
- lcd.DisplayStringAt(screen_width+5, 260, msg, LEFT_MODE);
- sprintf((char *)msg, " %10f", zoom);
- lcd.DisplayStringAt(screen_width+5, 212, msg, LEFT_MODE);
-
- tmr.reset();
- tmr.start();
-
- dx = (x2 - x1)/screen_width;
- dy = (y2 - y1)/screen_height;
- /*
- for(i = 0; i < screen_width; i++)
- {
- for(j = 0; j < screen_height; j++)
- {
- color = calcMandelBrot(x1 + dx*i, y1 + dy*j);
- lcd.DrawPixel(i, j, 0xFF000000 | (color<<14) | (color <<4));
- }
- }*/
- for(i = 0; i < screen_width/4; i++)
- {
- ts.GetState(&TS_State);
- if (TS_State.touchDetected)
- return;
- for(j = 0; j < screen_height/4; j++)
- {
- c[i][j] = calcMandelBrot(x1 + 4*dx*i, y1 + 4*dy*j);
- lcd.DrawPixel(4*i, 4*j, 0xFF000000 | (c[i][j]<<4));
- }
- }
-
- for(i = 0; i < screen_width/4; i++)
- {
- ts.GetState(&TS_State);
- if (TS_State.touchDetected)
- return;
- for(j = 0; j < screen_height/4; j++)
- {
- if((c[i][j] == c[i+1][j]) && (c[i][j] == c[i+1][j+1]) && (c[i][j] == c[i][j+1]))
- {
- lcd.SetTextColor(0xFF000000 | (c[i][j]<<4));
- lcd.FillRect(i*4, j*4, 4, 4);
- }
- else
- {
- for(n = 1; n < 16; n++)
- {
- color = calcMandelBrot(x1 + dx*(4*i+(n/4)), y1 + dy*(4*j+(n%4)));
- lcd.DrawPixel(4*i+(n/4), 4*j+(n%4), 0xFF000000 | (color<<4));
- }
- }
- }
- }
- tmr.stop();
-
- sprintf((char *)msg, " %6d ms", tmr.read_ms());
- lcd.SetTextColor(LCD_COLOR_WHITE);
- lcd.SetBackColor(LCD_COLOR_BLACK);
- lcd.DisplayStringAt(screen_width+5, 20, msg, LEFT_MODE);
- }
- int main()
- {
- uint8_t status;
- uint8_t prev_nb_touches = 0;
- double cx, cy, lx, ly;
- status = ts.Init(lcd.GetXSize(), lcd.GetYSize());
- if (status != TS_OK) {
- lcd.Clear(LCD_COLOR_RED);
- lcd.SetBackColor(LCD_COLOR_RED);
- lcd.SetTextColor(LCD_COLOR_WHITE);
- lcd.DisplayStringAt(0, LINE(5), (uint8_t *)"TOUCHSCREEN INIT FAIL", CENTER_MODE);
-
- while(1);
- }
-
- lcd.Clear(LCD_COLOR_BLACK);
- lcd.SetFont(&Font12);
- lcd.SetTextColor(LCD_COLOR_WHITE);
- lcd.SetBackColor(LCD_COLOR_BLACK);
- screen_width = lcd.GetXSize() - 120;
- screen_height = lcd.GetYSize();
- lcd.DisplayStringAt(screen_width+5, 0, (uint8_t *)"Elapsed:", LEFT_MODE);
- lcd.DisplayStringAt(screen_width+5, 200, (uint8_t *)"Zoom:", LEFT_MODE);
-
- mx1 = -2.5;
- my1 = -2.5;
- mx2 = 2.5;
- my2 = 2.5;
- rectMandelBrot(mx1, my1, mx2, my2);
-
- status = 0;
- while(1)
- {
- wait(0.01);
- ts.GetState(&TS_State);
- if (TS_State.touchDetected)
- {
- if(TS_State.touchDetected != prev_nb_touches)
- {
- status = 0;
- tscnt = 0;
- prev_nb_touches = TS_State.touchDetected;
- }
-
- if(tscnt < 10)
- {
- tscnt++;
- if(tscnt == 9)
- {
- ts_nb = TS_State.touchDetected;
- lcd.SetTextColor(LCD_COLOR_BLACK);
- lcd.FillRect(screen_width+5, 60, 120, 48);
- }
- continue;
- }
-
- switch(ts_nb)
- {
- case 1:
- if(status == 0)
- {
- status = 1;
- tsx0[0] = TS_State.touchX[0];
- tsy0[0] = TS_State.touchY[0];
- }
- tsx[0] = TS_State.touchX[0];
- tsy[0] = TS_State.touchY[0];
- lcd.SetTextColor(LCD_COLOR_LIGHTBLUE);
- sprintf((char *)msg, "%3d", TS_State.touchX[0]);
- lcd.DisplayStringAt(screen_width+5, 60, msg, LEFT_MODE);
- sprintf((char *)msg, "%3d", TS_State.touchY[0]);
- lcd.DisplayStringAt(screen_width+5, 72, msg, LEFT_MODE);
- break;
- case 2:
- if(status == 0)
- {
- status = 1;
- tsx0[0] = TS_State.touchX[0];
- tsy0[0] = TS_State.touchY[0];
- tsx0[1] = TS_State.touchX[1];
- tsy0[1] = TS_State.touchY[1];
- }
- tsx[0] = TS_State.touchX[0];
- tsy[0] = TS_State.touchY[0];
- tsx[1] = TS_State.touchX[1];
- tsy[1] = TS_State.touchY[1];
- lcd.SetTextColor(LCD_COLOR_LIGHTBLUE);
- sprintf((char *)msg, "%3d", TS_State.touchX[0]);
- lcd.DisplayStringAt(screen_width+5, 60, msg, LEFT_MODE);
- sprintf((char *)msg, "%3d", TS_State.touchY[0]);
- lcd.DisplayStringAt(screen_width+5, 72, msg, LEFT_MODE);
- sprintf((char *)msg, "%3d", TS_State.touchX[1]);
- lcd.DisplayStringAt(screen_width+5, 84, msg, LEFT_MODE);
- sprintf((char *)msg, "%3d", TS_State.touchY[1]);
- lcd.DisplayStringAt(screen_width+5, 96, msg, LEFT_MODE);
- break;
- }
- }
- else
- {
- if(status)
- {
- lcd.SetTextColor(LCD_COLOR_YELLOW);
- status = 0;
- tscnt = 0;
- switch(ts_nb)
- {
- case 1:
- if((abs(tsx[0] - tsx0[0]) > 20) || (abs(tsy[0] - tsy0[0]) > 20))
- {
- lcd.DisplayStringAt(screen_width+41, 200, (uint8_t *)" - ", LEFT_MODE);
- cx = (tsx[0] - tsx0[0])*(mx2 - mx1)/screen_width;
- cy = (tsy[0] - tsy0[0])*(my2 - my1)/screen_height;
- mx1 -= cx;
- mx2 -= cx;
- my1 -= cy;
- my2 -= cy;
- rectMandelBrot(mx1, my1, mx2, my2);
- }
- break;
- case 2:
- if(((tsx[0]-tsx[1])*(tsx[0]-tsx[1]) + 20) < ((tsx0[0]-tsx0[1])*(tsx0[0]-tsx0[1])))
- {
- lcd.DisplayStringAt(screen_width+41, 200, (uint8_t *)"out", LEFT_MODE);
- zoom = zoom /2;
- cx = (tsx0[0] + tsx0[1])/2;
- cy = (tsy0[0] + tsy0[1])/2;
- lx = (mx2 - mx1);
- ly = (my2 - my1);
- cx = cx * (mx2 - mx1) / screen_width + mx1;
- cy = cy * (my2 - my1) / screen_height + my1;
- mx1 = cx - lx;
- mx2 = cx + lx;
- my1 = cy - ly;
- my2 = cy + ly;
- rectMandelBrot(mx1, my1, mx2, my2);
- }
- else if(((tsx[0]-tsx[1])*(tsx[0]-tsx[1])) > ((tsx0[0]-tsx0[1])*(tsx0[0]-tsx0[1]) + 20))
- {
- lcd.DisplayStringAt(screen_width+41, 200, (uint8_t *)"in ", LEFT_MODE);
- zoom = zoom*2;
- cx = (tsx0[0] + tsx0[1])/2;
- cy = (tsy0[0] + tsy0[1])/2;
- lx = (mx2 - mx1)/4;
- ly = (my2 - my1)/4;
- cx = cx * (mx2 - mx1) / screen_width + mx1;
- cy = cy * (my2 - my1) / screen_height + my1;
- mx1 = cx - lx;
- mx2 = cx + lx;
- my1 = cy - ly;
- my2 = cy + ly;
- rectMandelBrot(mx1, my1, mx2, my2);
-
- }
- break;
- }
- }
- }
- }
- }
复制代码
编译后的BIN文件,可以直接下载运行。
DISCO-F746NG_fract.bin.zip
(31.95 KB, 下载次数: 6)
|
这个是曼德布罗特集的图形,茱莉亚集的计算公式略有不同
给你提点意见.
一.迭代收敛的条件是,|z|<=2.写成<2会错过一些点,比如(-2,0)
二.仅靠4角同色不足以判断此矩形内同色.可能会在一些半岛周围漏掉几个点.
正确的做法是:
1.每隔4点计算颜色.
2.将4角颜色不同的小矩形标记为pend.
3.计算所有pend矩形内的每个点的颜色.
将此矩形标记为done.
如此矩形不是纯色,将此矩形的4个邻居标记为pend(已是done的除外)
4.重复第3步,直到没有pend.
三.对于有FPU的单片机可以光明正大的用double,但没有FPU的就惨了,软件浮点算法特慢.
可以用定点数,小数点的位置有讲究,s5p26比较合适.比float精度稍高,也没有溢出问题.
要注意的是判断收敛时要当做u6p26来比较,因为|z|最大能到6,|z|2能到36,超出了s5p26的范围,但不会超出u6p26.
看来也是一个分形高手啊。这个程序的确不严谨,主要目的是为了演示STM32F7DISC开发板的使用,所以有些地方显得有些粗糙了。后续会继续改进,也希望大家一起来讨论和完善。