
Demo touching the perimeter of a circle
main.cpp@3:d259be26795b, 2021-04-04 (annotated)
- Committer:
- WiredHome
- Date:
- Sun Apr 04 20:36:33 2021 +0000
- Revision:
- 3:d259be26795b
- Parent:
- 2:3077639f94fa
Disable a debug print
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:f2a6447e607c | 1 | /// |
WiredHome | 0:f2a6447e607c | 2 | /// RA8875 display library example where a user touch on the perimeter |
WiredHome | 0:f2a6447e607c | 3 | /// of a circle should be detected. |
WiredHome | 0:f2a6447e607c | 4 | /// |
WiredHome | 0:f2a6447e607c | 5 | /// |
WiredHome | 0:f2a6447e607c | 6 | /// 0 deg |
WiredHome | 0:f2a6447e607c | 7 | /// -+- |
WiredHome | 0:f2a6447e607c | 8 | /// - - |
WiredHome | 0:f2a6447e607c | 9 | /// |
WiredHome | 0:f2a6447e607c | 10 | /// / \ |
WiredHome | 0:f2a6447e607c | 11 | /// |
WiredHome | 0:f2a6447e607c | 12 | /// |
WiredHome | 0:f2a6447e607c | 13 | /// | | |
WiredHome | 0:f2a6447e607c | 14 | /// -90 deg + + + +90 deg |
WiredHome | 0:f2a6447e607c | 15 | /// | | |
WiredHome | 0:f2a6447e607c | 16 | /// |
WiredHome | 0:f2a6447e607c | 17 | /// |
WiredHome | 0:f2a6447e607c | 18 | /// \ / |
WiredHome | 0:f2a6447e607c | 19 | /// |
WiredHome | 0:f2a6447e607c | 20 | /// |
WiredHome | 0:f2a6447e607c | 21 | /// - - |
WiredHome | 0:f2a6447e607c | 22 | /// -+- |
WiredHome | 0:f2a6447e607c | 23 | /// +180 deg |
WiredHome | 0:f2a6447e607c | 24 | /// |
WiredHome | 0:f2a6447e607c | 25 | /// |
WiredHome | 0:f2a6447e607c | 26 | /// NOTE NOTE NOTE NOTE NOTE NOTE |
WiredHome | 0:f2a6447e607c | 27 | /// |
WiredHome | 0:f2a6447e607c | 28 | /// The code in this example would greatly benefit by refactoring to |
WiredHome | 0:f2a6447e607c | 29 | /// use radians, rather than degrees. Further, the coordinate system |
WiredHome | 0:f2a6447e607c | 30 | /// desired here is more like a clock-face, with 0 degrees is straight |
WiredHome | 0:f2a6447e607c | 31 | /// up and increasing angle in the clockwise direction. |
WiredHome | 0:f2a6447e607c | 32 | /// |
WiredHome | 0:f2a6447e607c | 33 | /// There are a few transformations (direction of rotation and angle |
WiredHome | 0:f2a6447e607c | 34 | /// offset) that didn't "feel right", even with the right result. |
WiredHome | 0:f2a6447e607c | 35 | /// |
WiredHome | 1:e4f92c21e329 | 36 | /// NOTE NOTE NOTE NOTE NOTE NOTE |
WiredHome | 1:e4f92c21e329 | 37 | /// |
WiredHome | 1:e4f92c21e329 | 38 | /// I didn't pay too much attention to managing int, float, and double |
WiredHome | 1:e4f92c21e329 | 39 | /// to avoid unnecessary promotion or math complexity. |
WiredHome | 1:e4f92c21e329 | 40 | /// |
WiredHome | 0:f2a6447e607c | 41 | #include "mbed.h" |
WiredHome | 0:f2a6447e607c | 42 | #include "RA8875.h" |
WiredHome | 0:f2a6447e607c | 43 | |
WiredHome | 1:e4f92c21e329 | 44 | // Display with Capacitive Touch panel on I2C |
WiredHome | 0:f2a6447e607c | 45 | RA8875 lcd(p5,p6,p7,p12,NC, p9,p10,p13, "tft"); // MOSI,MISO,SCK,/ChipSelect,/reset, SDA,SCL,/IRQ, name |
WiredHome | 0:f2a6447e607c | 46 | //RA8875 lcd(p5,p6,p7,p8,NC, p28,p27,p30, "tft"); |
WiredHome | 0:f2a6447e607c | 47 | |
WiredHome | 1:e4f92c21e329 | 48 | // debug serial for printf. |
WiredHome | 1:e4f92c21e329 | 49 | // Some versions of the OS don't support the baud initializer here, then use device.baud(460800) in main. |
WiredHome | 1:e4f92c21e329 | 50 | Serial device(USBTX,USBRX, 460800); // Initialize to a fast baud |
WiredHome | 1:e4f92c21e329 | 51 | //Serial device(p26,p25); |
WiredHome | 0:f2a6447e607c | 52 | |
WiredHome | 0:f2a6447e607c | 53 | // Screen size and color depth |
WiredHome | 0:f2a6447e607c | 54 | #define LCD_W 800 |
WiredHome | 0:f2a6447e607c | 55 | #define LCD_H 480 |
WiredHome | 1:e4f92c21e329 | 56 | #define LCD_C 8 // color - bits per pixel |
WiredHome | 1:e4f92c21e329 | 57 | |
WiredHome | 1:e4f92c21e329 | 58 | #define BL_NORM 100 // Backlight Normal setting (0 to 255) |
WiredHome | 0:f2a6447e607c | 59 | |
WiredHome | 1:e4f92c21e329 | 60 | // |
WiredHome | 0:f2a6447e607c | 61 | // The Circle definition around which touches are relevant |
WiredHome | 1:e4f92c21e329 | 62 | // |
WiredHome | 0:f2a6447e607c | 63 | const point_t center = {200,250}; |
WiredHome | 0:f2a6447e607c | 64 | const dim_t radius = 125; |
WiredHome | 0:f2a6447e607c | 65 | const dim_t touch_tolerance = 30; |
WiredHome | 0:f2a6447e607c | 66 | |
WiredHome | 2:3077639f94fa | 67 | |
WiredHome | 2:3077639f94fa | 68 | // |
WiredHome | 2:3077639f94fa | 69 | // Checkbox to turn on/off the touch-point |
WiredHome | 2:3077639f94fa | 70 | // |
WiredHome | 2:3077639f94fa | 71 | const rect_t check_tonoff = {400, 150, LCD_W-1, 182}; // Height based on double-size font |
WiredHome | 2:3077639f94fa | 72 | const char * check_tonoff_msg = "[%c] Visible touchpoints"; |
WiredHome | 2:3077639f94fa | 73 | bool touchVisible = false; // default hidden |
WiredHome | 2:3077639f94fa | 74 | |
WiredHome | 2:3077639f94fa | 75 | |
WiredHome | 2:3077639f94fa | 76 | // |
WiredHome | 2:3077639f94fa | 77 | // Radio buttons to select between pie pieces |
WiredHome | 2:3077639f94fa | 78 | // and a dial-indent |
WiredHome | 2:3077639f94fa | 79 | // |
WiredHome | 2:3077639f94fa | 80 | const rect_t radio_pie = {400, 250, LCD_W-1, 282}; |
WiredHome | 2:3077639f94fa | 81 | const char * radio_pie_msg = "(%c) Pie-slice rendering"; |
WiredHome | 2:3077639f94fa | 82 | const rect_t radio_dial = {400, 300, LCD_W-1, 332}; |
WiredHome | 2:3077639f94fa | 83 | const char * radio_dial_msg = "(%c) Dial rendering"; |
WiredHome | 2:3077639f94fa | 84 | int renderOption = 0; // pie-slice |
WiredHome | 2:3077639f94fa | 85 | |
WiredHome | 2:3077639f94fa | 86 | color_t edgeColor = BrightBlue; |
WiredHome | 2:3077639f94fa | 87 | color_t fillColor = Black; |
WiredHome | 2:3077639f94fa | 88 | |
WiredHome | 2:3077639f94fa | 89 | void DrawCircle() { |
WiredHome | 2:3077639f94fa | 90 | // Draw a thickened circle |
WiredHome | 2:3077639f94fa | 91 | lcd.fillellipse(center.x, center.y, radius, radius, fillColor); |
WiredHome | 2:3077639f94fa | 92 | for (int r = 0; r <= 3; r++) { |
WiredHome | 2:3077639f94fa | 93 | lcd.ellipse(center.x, center.y, radius + r, radius + r, edgeColor); |
WiredHome | 2:3077639f94fa | 94 | } |
WiredHome | 2:3077639f94fa | 95 | } |
WiredHome | 2:3077639f94fa | 96 | |
WiredHome | 2:3077639f94fa | 97 | void ShowUserControls() { |
WiredHome | 2:3077639f94fa | 98 | lcd.SetTextFontSize(2); // Bigger font; easier to touch |
WiredHome | 2:3077639f94fa | 99 | // |
WiredHome | 2:3077639f94fa | 100 | // [X] Enable visible touch-points |
WiredHome | 2:3077639f94fa | 101 | // |
WiredHome | 2:3077639f94fa | 102 | lcd.foreground(White); |
WiredHome | 2:3077639f94fa | 103 | lcd.SetTextCursor(check_tonoff.p1); |
WiredHome | 2:3077639f94fa | 104 | lcd.printf(check_tonoff_msg, (touchVisible) ? 'X' : ' '); |
WiredHome | 2:3077639f94fa | 105 | lcd.rect(check_tonoff, Gray); |
WiredHome | 2:3077639f94fa | 106 | // |
WiredHome | 2:3077639f94fa | 107 | // (*) Pie-slice rendering |
WiredHome | 2:3077639f94fa | 108 | // ( ) Dial rendering |
WiredHome | 2:3077639f94fa | 109 | // |
WiredHome | 2:3077639f94fa | 110 | lcd.foreground(White); |
WiredHome | 2:3077639f94fa | 111 | lcd.SetTextCursor(radio_pie.p1); |
WiredHome | 2:3077639f94fa | 112 | lcd.printf(radio_pie_msg, (renderOption == 0) ? '*' : ' '); |
WiredHome | 2:3077639f94fa | 113 | lcd.rect(radio_pie, Gray); |
WiredHome | 2:3077639f94fa | 114 | lcd.foreground(White); |
WiredHome | 2:3077639f94fa | 115 | lcd.SetTextCursor(radio_dial.p1); |
WiredHome | 2:3077639f94fa | 116 | lcd.printf(radio_dial_msg, (renderOption == 1) ? '*' : ' '); |
WiredHome | 2:3077639f94fa | 117 | lcd.rect(radio_dial, Gray); |
WiredHome | 2:3077639f94fa | 118 | lcd.SetTextFontSize(); |
WiredHome | 2:3077639f94fa | 119 | } |
WiredHome | 2:3077639f94fa | 120 | |
WiredHome | 2:3077639f94fa | 121 | void DrawInitialScreen() { |
WiredHome | 2:3077639f94fa | 122 | lcd.cls(); |
WiredHome | 2:3077639f94fa | 123 | lcd.foreground(White); // Change to white |
WiredHome | 2:3077639f94fa | 124 | lcd.printf("RA8875 Touch Dial Example - Build " __DATE__ " " __TIME__ "\r\n"); |
WiredHome | 2:3077639f94fa | 125 | lcd.printf("MBED v%d.%d.%d\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION); |
WiredHome | 2:3077639f94fa | 126 | ShowUserControls(); |
WiredHome | 2:3077639f94fa | 127 | DrawCircle(); |
WiredHome | 2:3077639f94fa | 128 | } |
WiredHome | 2:3077639f94fa | 129 | |
WiredHome | 2:3077639f94fa | 130 | void TestToggleHit(point_t t) { |
WiredHome | 2:3077639f94fa | 131 | if (lcd.Intersect(check_tonoff, t)) { |
WiredHome | 2:3077639f94fa | 132 | touchVisible = !touchVisible; |
WiredHome | 2:3077639f94fa | 133 | DrawInitialScreen(); |
WiredHome | 2:3077639f94fa | 134 | } |
WiredHome | 2:3077639f94fa | 135 | } |
WiredHome | 2:3077639f94fa | 136 | |
WiredHome | 2:3077639f94fa | 137 | void TestRenderHit(point_t t) { |
WiredHome | 2:3077639f94fa | 138 | bool update = false; |
WiredHome | 2:3077639f94fa | 139 | if (lcd.Intersect(radio_pie, t)) { |
WiredHome | 2:3077639f94fa | 140 | renderOption = 0; |
WiredHome | 2:3077639f94fa | 141 | edgeColor = BrightBlue; |
WiredHome | 2:3077639f94fa | 142 | fillColor = Black; |
WiredHome | 2:3077639f94fa | 143 | update = true; |
WiredHome | 2:3077639f94fa | 144 | } else if (lcd.Intersect(radio_dial, t)) { |
WiredHome | 2:3077639f94fa | 145 | renderOption = 1; |
WiredHome | 2:3077639f94fa | 146 | edgeColor = BrightBlue; |
WiredHome | 2:3077639f94fa | 147 | fillColor = Gray; |
WiredHome | 2:3077639f94fa | 148 | update = true; |
WiredHome | 2:3077639f94fa | 149 | } |
WiredHome | 2:3077639f94fa | 150 | if (update) { |
WiredHome | 2:3077639f94fa | 151 | DrawInitialScreen(); |
WiredHome | 2:3077639f94fa | 152 | } |
WiredHome | 2:3077639f94fa | 153 | } |
WiredHome | 2:3077639f94fa | 154 | |
WiredHome | 2:3077639f94fa | 155 | |
WiredHome | 0:f2a6447e607c | 156 | #define PI 3.14159265359f |
WiredHome | 0:f2a6447e607c | 157 | |
WiredHome | 0:f2a6447e607c | 158 | // --------------- |
WiredHome | 0:f2a6447e607c | 159 | // radius = \ / x ^ 2 + y ^ 2 |
WiredHome | 0:f2a6447e607c | 160 | // \/ |
WiredHome | 0:f2a6447e607c | 161 | int GetRadius(point_t touch, point_t center) |
WiredHome | 0:f2a6447e607c | 162 | { |
WiredHome | 0:f2a6447e607c | 163 | return sqrt(pow(touch.x - center.x, 2) + pow(touch.y - center.y, 2)); |
WiredHome | 0:f2a6447e607c | 164 | } |
WiredHome | 0:f2a6447e607c | 165 | |
WiredHome | 0:f2a6447e607c | 166 | // (radians * 180) |
WiredHome | 0:f2a6447e607c | 167 | // degrees = --------------- |
WiredHome | 0:f2a6447e607c | 168 | // pi |
WiredHome | 0:f2a6447e607c | 169 | float Degrees(float radians) |
WiredHome | 0:f2a6447e607c | 170 | { |
WiredHome | 0:f2a6447e607c | 171 | return radians * 180 / PI; |
WiredHome | 0:f2a6447e607c | 172 | } |
WiredHome | 0:f2a6447e607c | 173 | |
WiredHome | 0:f2a6447e607c | 174 | // (pi * degrees) |
WiredHome | 0:f2a6447e607c | 175 | // radians = -------------- |
WiredHome | 0:f2a6447e607c | 176 | // 180 |
WiredHome | 0:f2a6447e607c | 177 | float Radians(float degrees) |
WiredHome | 0:f2a6447e607c | 178 | { |
WiredHome | 0:f2a6447e607c | 179 | return (degrees * PI)/180; |
WiredHome | 0:f2a6447e607c | 180 | } |
WiredHome | 0:f2a6447e607c | 181 | |
WiredHome | 0:f2a6447e607c | 182 | int GetAngle(point_t touch, point_t center) |
WiredHome | 0:f2a6447e607c | 183 | { |
WiredHome | 0:f2a6447e607c | 184 | int angle = 180 - Degrees(atan2(touch.x - center.x, touch.y - center.y)); |
WiredHome | 0:f2a6447e607c | 185 | if (angle < 0) |
WiredHome | 0:f2a6447e607c | 186 | angle += 360; |
WiredHome | 0:f2a6447e607c | 187 | return angle; |
WiredHome | 0:f2a6447e607c | 188 | } |
WiredHome | 0:f2a6447e607c | 189 | |
WiredHome | 0:f2a6447e607c | 190 | // From a starting point, and at a given angle (where 0 is straight up), |
WiredHome | 0:f2a6447e607c | 191 | // and clockwise is increasing angle, |
WiredHome | 0:f2a6447e607c | 192 | // project a given distance at that angle and return those coordinates. |
WiredHome | 0:f2a6447e607c | 193 | // |
WiredHome | 0:f2a6447e607c | 194 | point_t ProjectPoint(point_t start, int angle, dim_t distance) |
WiredHome | 0:f2a6447e607c | 195 | { |
WiredHome | 0:f2a6447e607c | 196 | point_t newPoint; |
WiredHome | 0:f2a6447e607c | 197 | float radians = Radians(angle); // radians are rooted in 0 to the right, and increasing counterclockwise |
WiredHome | 0:f2a6447e607c | 198 | radians = -radians + Radians(90); // reverse direction and 0 at the top |
WiredHome | 0:f2a6447e607c | 199 | //device.printf("adj Radians %4.3f\r\n", radians); |
WiredHome | 0:f2a6447e607c | 200 | newPoint.x = start.x + distance * sin(radians); |
WiredHome | 0:f2a6447e607c | 201 | newPoint.y = start.y - distance * cos(radians); |
WiredHome | 0:f2a6447e607c | 202 | return newPoint; |
WiredHome | 0:f2a6447e607c | 203 | } |
WiredHome | 0:f2a6447e607c | 204 | |
WiredHome | 0:f2a6447e607c | 205 | |
WiredHome | 0:f2a6447e607c | 206 | int main() |
WiredHome | 0:f2a6447e607c | 207 | { |
WiredHome | 1:e4f92c21e329 | 208 | //device.baud(460800); |
WiredHome | 1:e4f92c21e329 | 209 | printf("\r\n RA8875 Touch Dial Example - Build " __DATE__ " " __TIME__ "\r\n"); |
WiredHome | 1:e4f92c21e329 | 210 | printf("MBED v%d.%d.%d\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION); |
WiredHome | 0:f2a6447e607c | 211 | |
WiredHome | 0:f2a6447e607c | 212 | lcd.init(LCD_W,LCD_H,LCD_C,BL_NORM); |
WiredHome | 0:f2a6447e607c | 213 | lcd.TouchPanelInit(); |
WiredHome | 0:f2a6447e607c | 214 | |
WiredHome | 2:3077639f94fa | 215 | DrawInitialScreen(); |
WiredHome | 0:f2a6447e607c | 216 | |
WiredHome | 0:f2a6447e607c | 217 | while (1) { |
WiredHome | 0:f2a6447e607c | 218 | TouchCode_t touched; |
WiredHome | 2:3077639f94fa | 219 | static point_t lastTouch = {LCD_W, LCD_H}; // Init off-screen for easy detection |
WiredHome | 0:f2a6447e607c | 220 | touched = lcd.TouchPanelReadable(); |
WiredHome | 0:f2a6447e607c | 221 | if (touched) { |
WiredHome | 0:f2a6447e607c | 222 | point_t Touch = lcd.TouchCoordinates(); |
WiredHome | 0:f2a6447e607c | 223 | |
WiredHome | 2:3077639f94fa | 224 | if (touched == touch) { // Only "on-touch" |
WiredHome | 2:3077639f94fa | 225 | TestToggleHit(Touch); |
WiredHome | 2:3077639f94fa | 226 | TestRenderHit(Touch); |
WiredHome | 2:3077639f94fa | 227 | } |
WiredHome | 2:3077639f94fa | 228 | |
WiredHome | 2:3077639f94fa | 229 | lcd.foreground(White); |
WiredHome | 2:3077639f94fa | 230 | lcd.SetTextCursor(LCD_W - 8 * 9, 0); |
WiredHome | 2:3077639f94fa | 231 | lcd.printf("(%3d,%3d)", Touch.x,Touch.y); |
WiredHome | 2:3077639f94fa | 232 | |
WiredHome | 0:f2a6447e607c | 233 | // If the touch is near the drawn circle (+/- 30 pixels), |
WiredHome | 0:f2a6447e607c | 234 | // compute the angle to the touch from the center of the circle |
WiredHome | 0:f2a6447e607c | 235 | if (abs(GetRadius(Touch, center) - radius) <= touch_tolerance) { |
WiredHome | 0:f2a6447e607c | 236 | int angle = GetAngle(Touch, center); |
WiredHome | 3:d259be26795b | 237 | //printf("Touch at (%4d,%4d) is %3d degrees from (%4d,%4d)\r\n", |
WiredHome | 3:d259be26795b | 238 | // Touch.x, Touch.y, angle, center.x, center.y); |
WiredHome | 0:f2a6447e607c | 239 | |
WiredHome | 2:3077639f94fa | 240 | point_t lastP; |
WiredHome | 2:3077639f94fa | 241 | switch (renderOption) { |
WiredHome | 2:3077639f94fa | 242 | default: |
WiredHome | 2:3077639f94fa | 243 | case 0: |
WiredHome | 2:3077639f94fa | 244 | // Fill the circle using 6° pie slices up to the angle of the touch |
WiredHome | 2:3077639f94fa | 245 | lastP = ProjectPoint(center, 90, radius); // seed it at angle 0 |
WiredHome | 2:3077639f94fa | 246 | for (int a=6; a<=360; a+=6) { |
WiredHome | 2:3077639f94fa | 247 | point_t p = ProjectPoint(center, 90 - a, radius); |
WiredHome | 2:3077639f94fa | 248 | color_t fillColor = (a <= angle) ? Blue : Black; |
WiredHome | 2:3077639f94fa | 249 | //if ((a <= angle)) { // show the triangle coordinates (only the fill) |
WiredHome | 2:3077639f94fa | 250 | // printf(" (%3d,%3d), (%3d,%3d), (%3d,%3d)\r\n", |
WiredHome | 2:3077639f94fa | 251 | // lastP.x,lastP.y, p.x,p.y, center.x,center.y); |
WiredHome | 2:3077639f94fa | 252 | //} |
WiredHome | 2:3077639f94fa | 253 | lcd.filltriangle(center, p, lastP, fillColor); |
WiredHome | 2:3077639f94fa | 254 | lastP = p; |
WiredHome | 2:3077639f94fa | 255 | } |
WiredHome | 2:3077639f94fa | 256 | lastTouch.x = LCD_W; // reset to untouched for a change to the dial |
WiredHome | 2:3077639f94fa | 257 | break; |
WiredHome | 2:3077639f94fa | 258 | case 1: |
WiredHome | 2:3077639f94fa | 259 | lastP = ProjectPoint(center, 90 - angle, 0.75 * radius); |
WiredHome | 2:3077639f94fa | 260 | if (lastTouch.x != LCD_W) { |
WiredHome | 2:3077639f94fa | 261 | lcd.fillellipse(lastTouch, radius/5,radius/5, fillColor); |
WiredHome | 2:3077639f94fa | 262 | } |
WiredHome | 2:3077639f94fa | 263 | lcd.fillellipse(lastP, radius/5,radius/5, Black); |
WiredHome | 2:3077639f94fa | 264 | lastTouch = lastP; |
WiredHome | 2:3077639f94fa | 265 | break; |
WiredHome | 0:f2a6447e607c | 266 | } |
WiredHome | 0:f2a6447e607c | 267 | // Show the touch point (note we're not erasing the old one) |
WiredHome | 2:3077639f94fa | 268 | if (touchVisible) { |
WiredHome | 2:3077639f94fa | 269 | lcd.fillellipse(Touch.x, Touch.y, 5, 5, BrightRed); |
WiredHome | 2:3077639f94fa | 270 | } |
WiredHome | 0:f2a6447e607c | 271 | } |
WiredHome | 0:f2a6447e607c | 272 | } |
WiredHome | 0:f2a6447e607c | 273 | } |
WiredHome | 0:f2a6447e607c | 274 | } |