Demo touching the perimeter of a circle

Dependencies:   RA8875

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 ///
00002 /// RA8875 display library example where a user touch on the perimeter
00003 /// of a circle should be detected.
00004 ///
00005 ///
00006 ///                           0 deg
00007 ///                          -+-
00008 ///                    -             -
00009 ///        
00010 ///              /                         \
00011 ///        
00012 ///        
00013 ///            |                             |
00014 /// -90 deg    +              +              + +90 deg
00015 ///            |                             |
00016 ///         
00017 ///         
00018 ///              \                         /
00019 ///         
00020 ///                   
00021 ///                    -             -
00022 ///                          -+-
00023 ///                        +180 deg
00024 ///
00025 ///
00026 /// NOTE NOTE NOTE NOTE NOTE NOTE
00027 ///
00028 /// The code in this example would greatly benefit by refactoring to 
00029 /// use radians, rather than degrees. Further, the coordinate system
00030 /// desired here is more like a clock-face, with 0 degrees is straight 
00031 /// up and increasing angle in the clockwise direction.
00032 ///
00033 /// There are a few transformations (direction of rotation and angle
00034 /// offset) that didn't "feel right", even with the right result.
00035 ///
00036 /// NOTE NOTE NOTE NOTE NOTE NOTE
00037 ///
00038 /// I didn't pay too much attention to managing int, float, and double
00039 /// to avoid unnecessary promotion or math complexity.
00040 ///
00041 #include "mbed.h"
00042 #include "RA8875.h"
00043 
00044 // Display with Capacitive Touch panel on I2C
00045 RA8875 lcd(p5,p6,p7,p12,NC, p9,p10,p13, "tft"); // MOSI,MISO,SCK,/ChipSelect,/reset, SDA,SCL,/IRQ, name
00046 //RA8875 lcd(p5,p6,p7,p8,NC, p28,p27,p30, "tft");
00047 
00048 // debug serial for printf. 
00049 // Some versions of the OS don't support the baud initializer here, then use device.baud(460800) in main.
00050 Serial device(USBTX,USBRX, 460800);    // Initialize to a fast baud
00051 //Serial device(p26,p25);
00052 
00053 // Screen size and color depth
00054 #define LCD_W 800
00055 #define LCD_H 480
00056 #define LCD_C 8             // color - bits per pixel
00057 
00058 #define BL_NORM 100         // Backlight Normal setting (0 to 255)
00059 
00060 //
00061 // The Circle definition around which touches are relevant
00062 //
00063 const point_t center = {200,250};
00064 const dim_t radius = 125;
00065 const dim_t touch_tolerance = 30;
00066 
00067 
00068 // 
00069 // Checkbox to turn on/off the touch-point
00070 //
00071 const rect_t check_tonoff = {400, 150, LCD_W-1, 182};     // Height based on double-size font
00072 const char * check_tonoff_msg = "[%c] Visible touchpoints";
00073 bool touchVisible = false;   // default hidden
00074 
00075 
00076 //
00077 // Radio buttons to select between pie pieces
00078 // and a dial-indent
00079 //
00080 const rect_t radio_pie = {400, 250, LCD_W-1, 282};
00081 const char * radio_pie_msg = "(%c) Pie-slice rendering";
00082 const rect_t radio_dial = {400, 300, LCD_W-1, 332};
00083 const char * radio_dial_msg = "(%c) Dial rendering";
00084 int renderOption = 0;   // pie-slice
00085 
00086 color_t edgeColor = BrightBlue;
00087 color_t fillColor = Black;
00088 
00089 void DrawCircle() {
00090     // Draw a thickened circle
00091     lcd.fillellipse(center.x, center.y, radius, radius, fillColor);
00092     for (int r = 0; r <= 3; r++) {
00093         lcd.ellipse(center.x, center.y, radius + r, radius + r, edgeColor);
00094     }
00095 }
00096 
00097 void ShowUserControls() {
00098     lcd.SetTextFontSize(2); // Bigger font; easier to touch
00099     //
00100     //      [X] Enable visible touch-points
00101     //
00102     lcd.foreground(White);
00103     lcd.SetTextCursor(check_tonoff.p1);
00104     lcd.printf(check_tonoff_msg, (touchVisible) ? 'X' : ' ');
00105     lcd.rect(check_tonoff, Gray);
00106     //
00107     //      (*) Pie-slice rendering
00108     //      ( ) Dial rendering
00109     //
00110     lcd.foreground(White);
00111     lcd.SetTextCursor(radio_pie.p1);
00112     lcd.printf(radio_pie_msg, (renderOption == 0) ? '*' : ' ');
00113     lcd.rect(radio_pie, Gray);
00114     lcd.foreground(White);
00115     lcd.SetTextCursor(radio_dial.p1);
00116     lcd.printf(radio_dial_msg, (renderOption == 1) ? '*' : ' ');
00117     lcd.rect(radio_dial, Gray);
00118     lcd.SetTextFontSize();
00119 }
00120 
00121 void DrawInitialScreen() {
00122     lcd.cls();
00123     lcd.foreground(White);          // Change to white
00124     lcd.printf("RA8875 Touch Dial Example - Build " __DATE__ " " __TIME__ "\r\n");
00125     lcd.printf("MBED v%d.%d.%d\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
00126     ShowUserControls();
00127     DrawCircle();
00128 }
00129 
00130 void TestToggleHit(point_t t) {
00131     if (lcd.Intersect(check_tonoff, t)) {
00132         touchVisible = !touchVisible;
00133         DrawInitialScreen();
00134     }
00135 }
00136 
00137 void TestRenderHit(point_t t) {
00138     bool update = false;
00139     if (lcd.Intersect(radio_pie, t)) {
00140         renderOption = 0;
00141         edgeColor = BrightBlue;
00142         fillColor = Black;
00143         update = true;
00144     } else if (lcd.Intersect(radio_dial, t)) {
00145         renderOption = 1;
00146         edgeColor = BrightBlue;
00147         fillColor = Gray;
00148         update = true;
00149     }
00150     if (update) {
00151         DrawInitialScreen();
00152     }
00153 }
00154 
00155 
00156 #define PI 3.14159265359f
00157 
00158 //              ---------------
00159 // radius = \  / x ^ 2 + y ^ 2
00160 //           \/
00161 int GetRadius(point_t touch, point_t center)
00162 {
00163     return sqrt(pow(touch.x - center.x, 2) + pow(touch.y - center.y, 2));
00164 }
00165 
00166 //           (radians * 180)
00167 // degrees = ---------------
00168 //               pi
00169 float Degrees(float radians)
00170 {
00171     return radians * 180 / PI;
00172 }
00173 
00174 //           (pi * degrees)
00175 // radians = --------------
00176 //                180
00177 float Radians(float degrees)
00178 {
00179     return (degrees * PI)/180;
00180 }
00181 
00182 int GetAngle(point_t touch, point_t center)
00183 {
00184     int angle = 180 - Degrees(atan2(touch.x - center.x, touch.y - center.y));
00185     if (angle < 0)
00186         angle += 360;
00187     return angle;
00188 }
00189 
00190 // From a starting point, and at a given angle (where 0 is straight up),
00191 // and clockwise is increasing angle,
00192 // project a given distance at that angle and return those coordinates.
00193 //
00194 point_t ProjectPoint(point_t start, int angle, dim_t distance)
00195 {
00196     point_t newPoint;
00197     float radians = Radians(angle);     // radians are rooted in 0 to the right, and increasing counterclockwise
00198     radians = -radians + Radians(90);   // reverse direction and 0 at the top
00199     //device.printf("adj Radians %4.3f\r\n", radians);
00200     newPoint.x = start.x + distance * sin(radians);
00201     newPoint.y = start.y - distance * cos(radians);
00202     return newPoint;
00203 }
00204 
00205 
00206 int main()
00207 {
00208     //device.baud(460800);
00209     printf("\r\n   RA8875 Touch Dial Example - Build " __DATE__ " " __TIME__ "\r\n");
00210     printf("MBED v%d.%d.%d\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
00211 
00212     lcd.init(LCD_W,LCD_H,LCD_C,BL_NORM);
00213     lcd.TouchPanelInit();
00214 
00215     DrawInitialScreen();
00216     
00217     while (1) {
00218         TouchCode_t touched;
00219         static point_t lastTouch = {LCD_W, LCD_H};     // Init off-screen for easy detection
00220         touched = lcd.TouchPanelReadable();
00221         if (touched) {
00222             point_t Touch = lcd.TouchCoordinates();
00223 
00224             if (touched == touch) {     // Only "on-touch"
00225                 TestToggleHit(Touch);
00226                 TestRenderHit(Touch);
00227             }
00228 
00229             lcd.foreground(White);
00230             lcd.SetTextCursor(LCD_W - 8 * 9, 0);
00231             lcd.printf("(%3d,%3d)", Touch.x,Touch.y);
00232 
00233             // If the touch is near the drawn circle (+/- 30 pixels),
00234             // compute the angle to the touch from the center of the circle
00235             if (abs(GetRadius(Touch, center) - radius) <= touch_tolerance) {
00236                 int angle = GetAngle(Touch, center);
00237                 //printf("Touch at (%4d,%4d) is %3d degrees from (%4d,%4d)\r\n", 
00238                 //    Touch.x, Touch.y, angle, center.x, center.y);
00239                 
00240                 point_t lastP;
00241                 switch (renderOption) {
00242                     default:
00243                     case 0:
00244                         // Fill the circle using 6° pie slices up to the angle of the touch
00245                         lastP = ProjectPoint(center, 90, radius);  // seed it at angle 0
00246                         for (int a=6; a<=360; a+=6) {
00247                             point_t p = ProjectPoint(center, 90 - a, radius);
00248                             color_t fillColor = (a <= angle) ? Blue : Black;
00249                             //if ((a <= angle)) {     // show the triangle coordinates (only the fill)
00250                             //    printf("    (%3d,%3d), (%3d,%3d), (%3d,%3d)\r\n",
00251                             //        lastP.x,lastP.y, p.x,p.y, center.x,center.y);
00252                             //}
00253                             lcd.filltriangle(center, p, lastP, fillColor);
00254                             lastP = p;
00255                         }
00256                         lastTouch.x = LCD_W;    // reset to untouched for a change to the dial
00257                         break;
00258                     case 1:
00259                         lastP = ProjectPoint(center, 90 - angle, 0.75 * radius);
00260                         if (lastTouch.x != LCD_W) {
00261                             lcd.fillellipse(lastTouch, radius/5,radius/5, fillColor);
00262                         }
00263                         lcd.fillellipse(lastP, radius/5,radius/5, Black);
00264                         lastTouch = lastP;
00265                         break;
00266                 }
00267                 // Show the touch point (note we're not erasing the old one)
00268                 if (touchVisible) {
00269                     lcd.fillellipse(Touch.x, Touch.y, 5, 5, BrightRed);
00270                 }
00271             }
00272         }
00273     }
00274 }