
Demo touching the perimeter of a circle
main.cpp
- Committer:
- WiredHome
- Date:
- 2021-04-04
- Revision:
- 3:d259be26795b
- Parent:
- 2:3077639f94fa
File content as of revision 3:d259be26795b:
/// /// RA8875 display library example where a user touch on the perimeter /// of a circle should be detected. /// /// /// 0 deg /// -+- /// - - /// /// / \ /// /// /// | | /// -90 deg + + + +90 deg /// | | /// /// /// \ / /// /// /// - - /// -+- /// +180 deg /// /// /// NOTE NOTE NOTE NOTE NOTE NOTE /// /// The code in this example would greatly benefit by refactoring to /// use radians, rather than degrees. Further, the coordinate system /// desired here is more like a clock-face, with 0 degrees is straight /// up and increasing angle in the clockwise direction. /// /// There are a few transformations (direction of rotation and angle /// offset) that didn't "feel right", even with the right result. /// /// NOTE NOTE NOTE NOTE NOTE NOTE /// /// I didn't pay too much attention to managing int, float, and double /// to avoid unnecessary promotion or math complexity. /// #include "mbed.h" #include "RA8875.h" // Display with Capacitive Touch panel on I2C RA8875 lcd(p5,p6,p7,p12,NC, p9,p10,p13, "tft"); // MOSI,MISO,SCK,/ChipSelect,/reset, SDA,SCL,/IRQ, name //RA8875 lcd(p5,p6,p7,p8,NC, p28,p27,p30, "tft"); // debug serial for printf. // Some versions of the OS don't support the baud initializer here, then use device.baud(460800) in main. Serial device(USBTX,USBRX, 460800); // Initialize to a fast baud //Serial device(p26,p25); // Screen size and color depth #define LCD_W 800 #define LCD_H 480 #define LCD_C 8 // color - bits per pixel #define BL_NORM 100 // Backlight Normal setting (0 to 255) // // The Circle definition around which touches are relevant // const point_t center = {200,250}; const dim_t radius = 125; const dim_t touch_tolerance = 30; // // Checkbox to turn on/off the touch-point // const rect_t check_tonoff = {400, 150, LCD_W-1, 182}; // Height based on double-size font const char * check_tonoff_msg = "[%c] Visible touchpoints"; bool touchVisible = false; // default hidden // // Radio buttons to select between pie pieces // and a dial-indent // const rect_t radio_pie = {400, 250, LCD_W-1, 282}; const char * radio_pie_msg = "(%c) Pie-slice rendering"; const rect_t radio_dial = {400, 300, LCD_W-1, 332}; const char * radio_dial_msg = "(%c) Dial rendering"; int renderOption = 0; // pie-slice color_t edgeColor = BrightBlue; color_t fillColor = Black; void DrawCircle() { // Draw a thickened circle lcd.fillellipse(center.x, center.y, radius, radius, fillColor); for (int r = 0; r <= 3; r++) { lcd.ellipse(center.x, center.y, radius + r, radius + r, edgeColor); } } void ShowUserControls() { lcd.SetTextFontSize(2); // Bigger font; easier to touch // // [X] Enable visible touch-points // lcd.foreground(White); lcd.SetTextCursor(check_tonoff.p1); lcd.printf(check_tonoff_msg, (touchVisible) ? 'X' : ' '); lcd.rect(check_tonoff, Gray); // // (*) Pie-slice rendering // ( ) Dial rendering // lcd.foreground(White); lcd.SetTextCursor(radio_pie.p1); lcd.printf(radio_pie_msg, (renderOption == 0) ? '*' : ' '); lcd.rect(radio_pie, Gray); lcd.foreground(White); lcd.SetTextCursor(radio_dial.p1); lcd.printf(radio_dial_msg, (renderOption == 1) ? '*' : ' '); lcd.rect(radio_dial, Gray); lcd.SetTextFontSize(); } void DrawInitialScreen() { lcd.cls(); lcd.foreground(White); // Change to white lcd.printf("RA8875 Touch Dial Example - Build " __DATE__ " " __TIME__ "\r\n"); lcd.printf("MBED v%d.%d.%d\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION); ShowUserControls(); DrawCircle(); } void TestToggleHit(point_t t) { if (lcd.Intersect(check_tonoff, t)) { touchVisible = !touchVisible; DrawInitialScreen(); } } void TestRenderHit(point_t t) { bool update = false; if (lcd.Intersect(radio_pie, t)) { renderOption = 0; edgeColor = BrightBlue; fillColor = Black; update = true; } else if (lcd.Intersect(radio_dial, t)) { renderOption = 1; edgeColor = BrightBlue; fillColor = Gray; update = true; } if (update) { DrawInitialScreen(); } } #define PI 3.14159265359f // --------------- // radius = \ / x ^ 2 + y ^ 2 // \/ int GetRadius(point_t touch, point_t center) { return sqrt(pow(touch.x - center.x, 2) + pow(touch.y - center.y, 2)); } // (radians * 180) // degrees = --------------- // pi float Degrees(float radians) { return radians * 180 / PI; } // (pi * degrees) // radians = -------------- // 180 float Radians(float degrees) { return (degrees * PI)/180; } int GetAngle(point_t touch, point_t center) { int angle = 180 - Degrees(atan2(touch.x - center.x, touch.y - center.y)); if (angle < 0) angle += 360; return angle; } // From a starting point, and at a given angle (where 0 is straight up), // and clockwise is increasing angle, // project a given distance at that angle and return those coordinates. // point_t ProjectPoint(point_t start, int angle, dim_t distance) { point_t newPoint; float radians = Radians(angle); // radians are rooted in 0 to the right, and increasing counterclockwise radians = -radians + Radians(90); // reverse direction and 0 at the top //device.printf("adj Radians %4.3f\r\n", radians); newPoint.x = start.x + distance * sin(radians); newPoint.y = start.y - distance * cos(radians); return newPoint; } int main() { //device.baud(460800); printf("\r\n RA8875 Touch Dial Example - Build " __DATE__ " " __TIME__ "\r\n"); printf("MBED v%d.%d.%d\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION); lcd.init(LCD_W,LCD_H,LCD_C,BL_NORM); lcd.TouchPanelInit(); DrawInitialScreen(); while (1) { TouchCode_t touched; static point_t lastTouch = {LCD_W, LCD_H}; // Init off-screen for easy detection touched = lcd.TouchPanelReadable(); if (touched) { point_t Touch = lcd.TouchCoordinates(); if (touched == touch) { // Only "on-touch" TestToggleHit(Touch); TestRenderHit(Touch); } lcd.foreground(White); lcd.SetTextCursor(LCD_W - 8 * 9, 0); lcd.printf("(%3d,%3d)", Touch.x,Touch.y); // If the touch is near the drawn circle (+/- 30 pixels), // compute the angle to the touch from the center of the circle if (abs(GetRadius(Touch, center) - radius) <= touch_tolerance) { int angle = GetAngle(Touch, center); //printf("Touch at (%4d,%4d) is %3d degrees from (%4d,%4d)\r\n", // Touch.x, Touch.y, angle, center.x, center.y); point_t lastP; switch (renderOption) { default: case 0: // Fill the circle using 6° pie slices up to the angle of the touch lastP = ProjectPoint(center, 90, radius); // seed it at angle 0 for (int a=6; a<=360; a+=6) { point_t p = ProjectPoint(center, 90 - a, radius); color_t fillColor = (a <= angle) ? Blue : Black; //if ((a <= angle)) { // show the triangle coordinates (only the fill) // printf(" (%3d,%3d), (%3d,%3d), (%3d,%3d)\r\n", // lastP.x,lastP.y, p.x,p.y, center.x,center.y); //} lcd.filltriangle(center, p, lastP, fillColor); lastP = p; } lastTouch.x = LCD_W; // reset to untouched for a change to the dial break; case 1: lastP = ProjectPoint(center, 90 - angle, 0.75 * radius); if (lastTouch.x != LCD_W) { lcd.fillellipse(lastTouch, radius/5,radius/5, fillColor); } lcd.fillellipse(lastP, radius/5,radius/5, Black); lastTouch = lastP; break; } // Show the touch point (note we're not erasing the old one) if (touchVisible) { lcd.fillellipse(Touch.x, Touch.y, 5, 5, BrightRed); } } } } }