Refactor trig functions into LUT (#476)

Replaced the use of the standard library trig functions with a LUT-based
implementation instead. The standard library implementations produce
more accurate results but the usage here doesn't need that. This ends up
saving nearly 7kB of binary size.
This commit is contained in:
Jonathan Vander Mey 2021-07-11 14:18:07 -04:00 committed by GitHub
parent 7fee2c2589
commit 4f378e8726
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,27 +5,44 @@
#include "Symbols.h" #include "Symbols.h"
#include "NotificationIcon.h" #include "NotificationIcon.h"
#include <cmath>
LV_IMG_DECLARE(bg_clock); LV_IMG_DECLARE(bg_clock);
using namespace Pinetime::Applications::Screens; using namespace Pinetime::Applications::Screens;
#define HOUR_LENGTH 70 namespace {
#define MINUTE_LENGTH 90
#define SECOND_LENGTH 110
#define PI 3.14159265358979323846
// ## constexpr auto HOUR_LENGTH = 70;
static int16_t coordinate_x_relocate(int16_t x) { constexpr auto MINUTE_LENGTH = 90;
return ((x) + LV_HOR_RES / 2); constexpr auto SECOND_LENGTH = 110;
// sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor
const auto LV_TRIG_SCALE = _lv_trigo_sin(90);
int16_t cosine(int16_t angle) {
return _lv_trigo_sin(angle + 90);
} }
// ## int16_t sine(int16_t angle) {
static int16_t coordinate_y_relocate(int16_t y) { return _lv_trigo_sin(angle);
return (((y) -LV_HOR_RES / 2) < 0) ? (0 - ((y) -LV_HOR_RES / 2)) : ((y) -LV_HOR_RES / 2);
} }
int16_t coordinate_x_relocate(int16_t x) {
return (x + LV_HOR_RES / 2);
}
int16_t coordinate_y_relocate(int16_t y) {
return std::abs(y - LV_HOR_RES / 2);
}
lv_point_t coordinate_relocate(int16_t radius, int16_t angle) {
return lv_point_t{
.x = coordinate_x_relocate(radius * static_cast<int32_t>(sine(angle)) / LV_TRIG_SCALE),
.y = coordinate_y_relocate(radius * static_cast<int32_t>(cosine(angle)) / LV_TRIG_SCALE)
};
}
} // namespace
WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app,
Controllers::DateTime& dateTimeController, Controllers::DateTime& dateTimeController,
Controllers::Battery& batteryController, Controllers::Battery& batteryController,
@ -123,15 +140,12 @@ void WatchFaceAnalog::UpdateClock() {
second = dateTimeController.Seconds(); second = dateTimeController.Seconds();
if (sMinute != minute) { if (sMinute != minute) {
minute_point[0].x = coordinate_x_relocate(30 * sin(minute * 6 * PI / 180)); auto const angle = minute * 6;
minute_point[0].y = coordinate_y_relocate(30 * cos(minute * 6 * PI / 180)); minute_point[0] = coordinate_relocate(30, angle);
minute_point[1].x = coordinate_x_relocate(MINUTE_LENGTH * sin(minute * 6 * PI / 180)); minute_point[1] = coordinate_relocate(MINUTE_LENGTH, angle);
minute_point[1].y = coordinate_y_relocate(MINUTE_LENGTH * cos(minute * 6 * PI / 180));
minute_point_trace[0].x = coordinate_x_relocate(5 * sin(minute * 6 * PI / 180)); minute_point_trace[0] = coordinate_relocate(5, angle);
minute_point_trace[0].y = coordinate_y_relocate(5 * cos(minute * 6 * PI / 180)); minute_point_trace[1] = coordinate_relocate(31, angle);
minute_point_trace[1].x = coordinate_x_relocate(31 * sin(minute * 6 * PI / 180));
minute_point_trace[1].y = coordinate_y_relocate(31 * cos(minute * 6 * PI / 180));
lv_line_set_points(minute_body, minute_point, 2); lv_line_set_points(minute_body, minute_point, 2);
lv_line_set_points(minute_body_trace, minute_point_trace, 2); lv_line_set_points(minute_body_trace, minute_point_trace, 2);
@ -140,15 +154,13 @@ void WatchFaceAnalog::UpdateClock() {
if (sHour != hour || sMinute != minute) { if (sHour != hour || sMinute != minute) {
sHour = hour; sHour = hour;
sMinute = minute; sMinute = minute;
hour_point[0].x = coordinate_x_relocate(30 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180)); auto const angle = (hour * 30 + minute / 2);
hour_point[0].y = coordinate_y_relocate(30 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point[1].x = coordinate_x_relocate(HOUR_LENGTH * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point[1].y = coordinate_y_relocate(HOUR_LENGTH * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point_trace[0].x = coordinate_x_relocate(5 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180)); hour_point[0] = coordinate_relocate(30, angle);
hour_point_trace[0].y = coordinate_y_relocate(5 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180)); hour_point[1] = coordinate_relocate(HOUR_LENGTH, angle);
hour_point_trace[1].x = coordinate_x_relocate(31 * sin((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180));
hour_point_trace[1].y = coordinate_y_relocate(31 * cos((((hour > 12 ? hour - 12 : hour) * 30) + (minute * 0.5)) * PI / 180)); hour_point_trace[0] = coordinate_relocate(5, angle);
hour_point_trace[1] = coordinate_relocate(31, angle);
lv_line_set_points(hour_body, hour_point, 2); lv_line_set_points(hour_body, hour_point, 2);
lv_line_set_points(hour_body_trace, hour_point_trace, 2); lv_line_set_points(hour_body_trace, hour_point_trace, 2);
@ -156,10 +168,10 @@ void WatchFaceAnalog::UpdateClock() {
if (sSecond != second) { if (sSecond != second) {
sSecond = second; sSecond = second;
second_point[0].x = coordinate_x_relocate(20 * sin((180 + second * 6) * PI / 180)); auto const angle = second * 6;
second_point[0].y = coordinate_y_relocate(20 * cos((180 + second * 6) * PI / 180));
second_point[1].x = coordinate_x_relocate(SECOND_LENGTH * sin(second * 6 * PI / 180)); second_point[0] = coordinate_relocate(-20, angle);
second_point[1].y = coordinate_y_relocate(SECOND_LENGTH * cos(second * 6 * PI / 180)); second_point[1] = coordinate_relocate(SECOND_LENGTH, angle);
lv_line_set_points(second_body, second_point, 2); lv_line_set_points(second_body, second_point, 2);
} }
} }