Skip to content

Instantly share code, notes, and snippets.

@Kiterai
Last active January 25, 2024 13:37
Show Gist options
  • Save Kiterai/f604cb222aaa071e1080736cbed806eb to your computer and use it in GitHub Desktop.
Save Kiterai/f604cb222aaa071e1080736cbed806eb to your computer and use it in GitHub Desktop.
syncronous world clock(WIP)
#include <math.h>
#include "GUI_Paint.h"
#include "utils.h"
#include "world.h"
#define SCALE_L1 105
#define SCALE_L2 120
#define DISPLAY_CENTERX 120
#define DISPLAY_CENTERY 120
// for test
void draw_world_mercator() {
for (int y = 0; y < 240; y++) {
for (int x = 0; x < 240; x++) {
Paint_DrawPoint(x, y, world[((y / 2) * IMG_WIDTH) + x], DOT_PIXEL_1X1, DOT_FILL_RIGHTUP);
}
}
}
// azimuthal equidistant projection
void draw_world(float rotate) {
for (int y = 0; y < 240; y++) {
for (int x = 0; x < 240; x++) {
float d = sqrtf((x - 120) * (x - 120) + (y - 120) * (y - 120));
float worldy = d * (IMG_HEIGHT / 120.0f);
float worldx = atan2f(-(y - 120), x - 120) / (2.0f * 3.14159265) + 0.5f; // [0, 1]
worldx += rotate / 360.0f;
worldx *= IMG_WIDTH;
while(worldx >= IMG_WIDTH) worldx -= IMG_WIDTH;
uint16_t code = sampling_bilinear(worldx, worldy);
code = set_brightness_rgb565(code, clamp(115 - x, -10, 0) * 2);
Paint_SetPixel(x, y, code);
}
}
}
// azimuthal equidistant projection with till (WIP)
void draw_world_with_till(float rotate, float center_lat, float center_lon) {
const float sin_phi1 = sinf(center_lat);
const float cos_phi1 = cosf(center_lat);
for (int y = 0; y < 240; y++) {
for (int x = 0; x < 240; x++) {
// https://mathworld.wolfram.com/AzimuthalEquidistantProjection.html
const float nx = (x - DISPLAY_CENTERX) * (3.14159265f / 120);
const float ny = -(y - DISPLAY_CENTERY) * (3.14159265f / 120);
const float c = sqrtf(nx * nx + ny * ny);
const float sin_c = sinf(c);
const float cos_c = cosf(c);
const float phi = asinf(cos_c * sin_phi1 + (ny * sin_c * cos_phi1) / c);
const float lambda = center_lon + atan2f(c * cos_phi1 * cos_c - ny * sin_phi1 * sin_c, nx * sin_c);
float worldy = ((phi / 3.14159265f) + 0.5f) * IMG_HEIGHT;
float worldx = lambda / (2.0f * 3.14159265f) + 0.5f; // [0, 1]
worldx += rotate / 360.0f;
worldx *= IMG_WIDTH;
while(worldx >= IMG_WIDTH) worldx -= IMG_WIDTH;
uint16_t code = sampling_bilinear(worldx, worldy);
code = set_brightness_rgb565(code, clamp(115 - x, -10, 0) * 2);
Paint_SetPixel(x, y, code);
}
}
}
void draw_scale() {
char buf[4];
for(uint16_t i = 0; i < 24; i++) {
float x1 = 110 * cosf((3.141592f / 12.0f) * (i + 0.65f));
float y1 = 110 * sinf((3.141592f / 12.0f) * (i + 0.65f));
uint16_t num = 23 - i;
buf[0] = num >= 10 ? (num / 10 + '0') : ' ';
buf[1] = num % 10 + '0';
buf[2] = '\0';
Paint_DrawString_EN((uint16_t)(DISPLAY_CENTERX + x1 - 7) + 1, DISPLAY_CENTERY + y1 - 6, buf, &Font12, WHITE, WHITE);
Paint_DrawString_EN(DISPLAY_CENTERX + x1 - 7, (uint16_t)(DISPLAY_CENTERY + y1 - 6) + 1, buf, &Font12, WHITE, WHITE);
Paint_DrawString_EN((uint16_t)(DISPLAY_CENTERX + x1 - 7) - 1, DISPLAY_CENTERY + y1 - 6, buf, &Font12, WHITE, WHITE);
Paint_DrawString_EN(DISPLAY_CENTERX + x1 - 7, (uint16_t)(DISPLAY_CENTERY + y1 - 6) - 1, buf, &Font12, WHITE, WHITE);
// Font12 is 7x12 sized font, 2 char->14x12, to centerize->(-7,-6)shift
Paint_DrawString_EN(DISPLAY_CENTERX + x1 - 7, DISPLAY_CENTERY + y1 - 6, buf, &Font12, BLACK, WHITE);
}
for(uint16_t i = 0; i < 24; i++) {
float x1 = SCALE_L1 * cosf(3.141592 / 12 * i);
float y1 = SCALE_L1 * sinf(3.141592 / 12 * i);
float x2 = SCALE_L2 * cosf(3.141592 / 12 * i);
float y2 = SCALE_L2 * sinf(3.141592 / 12 * i);
Paint_DrawLine(
DISPLAY_CENTERX + x1, DISPLAY_CENTERY + y1,
DISPLAY_CENTERX + x2, DISPLAY_CENTERY + y2,
BLACK, DOT_PIXEL_2X2, LINE_STYLE_SOLID);
Paint_DrawLine(
DISPLAY_CENTERX + x1, DISPLAY_CENTERY + y1,
DISPLAY_CENTERX + x2, DISPLAY_CENTERY + y2,
WHITE, DOT_PIXEL_1X1, LINE_STYLE_SOLID);
}
}
void draw_world_mercator();
void draw_world(float rotate);
void draw_world_with_till(float rotate, float center_lat, float center_lon);
void draw_scale();
#include "DEV_Config.h"
#include "GUI_Paint.h"
#include "LCD_1in28.h"
#include "hardware/rtc.h"
#include "pico/stdlib.h"
#include "pico/util/datetime.h"
#include <stdio.h>
#include <math.h>
#include "draw.h"
#include "world.h"
int main(void) {
if (DEV_Module_Init() != 0)
return -1;
LCD_1IN28_Init(HORIZONTAL);
LCD_1IN28_Clear(WHITE);
DEV_SET_PWM(60); // set backlight
UDOUBLE Imagesize = LCD_1IN28_HEIGHT * LCD_1IN28_WIDTH * 2;
UWORD *BlackImage;
if ((BlackImage = (UWORD *)malloc(Imagesize)) == NULL)
{
printf("Failed to apply for black memory...\r\n");
exit(0);
}
Paint_NewImage((UBYTE *)BlackImage, LCD_1IN28.WIDTH, LCD_1IN28.HEIGHT, 0, WHITE);
Paint_SetScale(65);
Paint_Clear(WHITE);
datetime_t t = {
.year = 2024,
.month = 1,
.day = 24,
.dotw = 3, // 0 is Sunday, so 5 is Friday
.hour = 10,
.min = 0,
.sec = 0
};
rtc_init();
rtc_set_datetime(&t);
sleep_us(64);
float rotate = 0.0; // degree
bool k = 0;
while (true)
{
rtc_get_datetime(&t);
rotate = (86400 - t.hour * 3600 + t.min * 60 + t.sec) / 240.0f; // 240 = 86400 sec / 360 deg
draw_world_with_till(rotate, -3.14159265f / 2, 0);
draw_scale();
LCD_1IN28_Display(BlackImage);
}
free(BlackImage);
BlackImage = NULL;
DEV_Module_Exit();
return 0;
}
#include <stdio.h>
#include "world.h"
uint16_t gen_rgb565(uint16_t r, uint16_t g, uint16_t b) {
uint16_t code = 0;
code |= (r & 0b11111);
code <<= 6;
code |= (g & 0b111111);
code <<= 5;
code |= (b & 0b11111);
return code;
}
uint16_t get_r_rgb565(uint16_t code) {
return ((code >> 11) & 0b11111);
}
uint16_t get_g_rgb565(uint16_t code) {
return ((code >> 5) & 0b111111);
}
uint16_t get_b_rgb565(uint16_t code) {
return ((code >> 0) & 0b11111);
}
int clamp(int v, int min, int max) {
if(v < min)
return min;
if(v > max)
return max;
return v;
}
uint16_t set_brightness_rgb565(uint16_t code, int16_t brightness) {
return gen_rgb565(
clamp((get_r_rgb565(code) + brightness / 2), 0, 31),
clamp((get_g_rgb565(code) + brightness), 0, 63),
clamp((get_b_rgb565(code) + brightness / 2), 0, 31)
);
}
uint16_t sampling(uint16_t y, uint16_t x) {
y = clamp(y, 0, IMG_HEIGHT - 1);
if(x >= IMG_WIDTH) x -= 360;
if(x < 0) x += 360;
return world[y * IMG_WIDTH + x];
}
uint16_t sampling_bilinear(float worldx, float worldy) {
uint16_t worldx0 = worldx;
uint16_t worldy0 = worldy;
uint16_t worldx1 = worldx0 + 1;
uint16_t worldy1 = worldy0 + 1;
float dx0 = worldx - worldx0;
float dy0 = worldy - worldy0;
float dx1 = 1 - dx0;
float dy1 = 1 - dy0;
uint16_t c00 = sampling(worldy0, worldx0);
uint16_t c01 = sampling(worldy0, worldx1);
uint16_t c10 = sampling(worldy1, worldx0);
uint16_t c11 = sampling(worldy1, worldx1);
return gen_rgb565(
get_r_rgb565(c00) * dy1 * dx1 + get_r_rgb565(c01) * dy1 * dx0 + get_r_rgb565(c10) * dy0 * dx1 + get_r_rgb565(c11) * dy0 * dx0,
get_g_rgb565(c00) * dy1 * dx1 + get_g_rgb565(c01) * dy1 * dx0 + get_g_rgb565(c10) * dy0 * dx1 + get_g_rgb565(c11) * dy0 * dx0,
get_b_rgb565(c00) * dy1 * dx1 + get_b_rgb565(c01) * dy1 * dx0 + get_b_rgb565(c10) * dy0 * dx1 + get_b_rgb565(c11) * dy0 * dx0
);
}
uint16_t gen_rgb565(uint16_t r, uint16_t g, uint16_t b);
uint16_t get_r_rgb565(uint16_t code);
uint16_t get_g_rgb565(uint16_t code);
uint16_t get_b_rgb565(uint16_t code);
int clamp(int v, int min, int max);
uint16_t set_brightness_rgb565(uint16_t code, int16_t brightness);
uint16_t sampling(uint16_t y, uint16_t x);
uint16_t sampling_bilinear(float worldx, float worldy);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment