Skip to content

Commit

Permalink
lib: update docs on display transforms & pivots
Browse files Browse the repository at this point in the history
  • Loading branch information
and3rson committed Mar 12, 2024
1 parent 4654304 commit 3e572d7
Showing 1 changed file with 36 additions and 11 deletions.
47 changes: 36 additions & 11 deletions sdk/lib/lilka/src/lilka/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ class Display : public Arduino_ST7789 {

/// Намалювати зображення.
/// @param image Вказівник на зображення (об'єкт класу `lilka::Image`).
/// @param x Координата X лівого верхнього кута зображення.
/// @param y Координата Y лівого верхнього кута зображення.
/// @param x Координата X осі зображення.
/// @param y Координата Y осі зображення.
///
/// Приклад використання:
///
Expand All @@ -194,8 +194,8 @@ class Display : public Arduino_ST7789 {
void drawImage(Image* image, int16_t x, int16_t y);
/// Намалювати зображення з афінними перетвореннями.
/// @param image Вказівник на зображення (об'єкт класу `lilka::Image`).
/// @param x Координата X лівого верхнього кута зображення.
/// @param y Координата Y лівого верхнього кута зображення.
/// @param x Координата X осі зображення.
/// @param y Координата Y осі зображення.
/// @param transform Об'єкт класу `lilka::Transform`, який містить матрицю перетворення.
/// @note Зверніть увагу, що перетворення - це повільніше, ніж звичайне малювання зображення, оскільки обчислює координати пікселів "на льоту". Використовуйте його лише тоді, коли не можете заздалегідь створити обернені копії зображеня за допомогою методів `lilka::Image::rotate`, `lilka::Image::flipX` та `lilka::Image::flipY`.
/// @see lilka::Transform
Expand Down Expand Up @@ -251,14 +251,15 @@ class Display : public Arduino_ST7789 {

/// Клас для роботи з графічним буфером.
///
/// При частому перемальовуванні екрану без використання буфера, може спостерігатися мерехтіння.
/// При частому перемальовуванні екрану без використання буфера може спостерігатися мерехтіння.
/// Наприклад, якщо використовувати метод `fillScreen` для очищення екрану перед кожним викликом `print`,
/// то текст буде мерехтіти.
///
/// Щоб уникнути цього, можна використовувати буфер. Цей клас дозволяє малювати графічні об'єкти на буфері,
/// а потім відобразити його на екрані за допомогою методу `lilka::display.renderCanvas`.
///
/// Такий підхід дозволяє зменшити мерехтіння, але збільшує використання пам'яті. Він називається "буферизація".
/// Такий підхід дозволяє зменшити мерехтіння, але збільшує використання пам'яті. Він називається "буферизація",
/// оскільки ми спершу малюємо на буфері, а тоді відображаємо буфер на екрані.
///
/// Цей клас, як і `Display`, є підкласом `Arduino_GFX` з бібліотеки `Arduino_GFX_Library`.
/// Це означає, що майже всі методи, які доступні в `Display`, також доступні в `Canvas`.
Expand All @@ -273,11 +274,11 @@ class Display : public Arduino_ST7789 {
/// }
///
/// void loop() {
/// lilka::Canvas canvas;
/// lilka::Canvas canvas; // Створити новий Canvas зі стандартним розміром (розмір дисплею)
/// int y = 100;
/// while (1) {
/// canvas.fillScreen(lilka::display.color565(0, 0, 0)); // Заповнити буфер чорним кольором
/// canvas.setCursor(32, 0);
/// canvas.setCursor(32, y);
/// canvas.setTextColor(lilka::display.color565(0, 0, 0)); // Білий текст
/// canvas.print("Привіт, Лілка!");
/// lilka::display.renderCanvas(&canvas); // Відобразити буфер на екрані - жодного мерехтіння!
Expand Down Expand Up @@ -312,13 +313,19 @@ class Canvas : public Arduino_Canvas {
/// Містить розміри, прозорий колір та пікселі зображення (в 16-бітному форматі, 5-6-5).
/// Пікселі зберігаються в рядку зліва направо, зверху вниз.
///
/// Вісь зображення - це точка, яка вказує на центр зображення. Це дозволяє вам встановити точку, відносно якої буде відображатися зображення, а також навколо якої буде відбуватися перетворення зображення.
///
/// @note Основна відмінність Image від поняття "bitmap" погялає в тому, що Image містить масив пікселів, розміри зображення і прозорий колір, в той час як "bitmap" - це просто масив пікселів.
class Image {
public:
Image(uint32_t width, uint32_t height, int32_t transparentColor = -1, int16_t pivotX = 0, int16_t pivotY = 0);
~Image();
/// Обернути зображення на заданий кут (в градусах) і записати результат в `dest`.
///
/// Цей метод, а також методи `flipX` та `flipY`, зручно використовувати для створення обернених та віддзеркалених копій зображення, якщо ви заздалегідь знаєте, які варіанти зображення вам знадобляться.
///
/// Замість них можна використовувати клас `lilka::Transform` та його методи, які дозволяють виконувати та комбінувати складніші перетворення "на льоту", але такі перетворення є повільнішими.
///
/// @param angle Кут обертання в градусах.
/// @param dest Вказівник на Image, в яке буде записано обернуте зображення.
/// @param blankColor 16-бітний колір (5-6-5), який буде використаний для заповнення пікселів, які виходять за межі зображення.
Expand All @@ -339,6 +346,7 @@ class Image {
/// delete image;
/// delete rotatedImage;
/// @endcode
/// @see Display::drawImageTransformed, Canvas::drawImageTransformed, Transform
void rotate(int16_t angle, Image* dest, int32_t blankColor);
/// Віддзеркалити зображення по горизонталі і записати результат в `dest`.
void flipX(Image* dest);
Expand All @@ -358,7 +366,9 @@ class Image {
/// Афінні перетворення - це перетворення, які зберігають паралельність ліній.
/// Вони включають в себе обертання, масштабування та віддзеркалення.
///
/// Наприклад, ось цей код обертає зображення на 30 градусів та віддзеркалює його по горизонталі:
/// Перетворення - це всього лиш матриця 2x2. Застосування перетворення до вектора - це множення цього вектора на матрицю перетворення. Магія!
///
/// Наприклад, ось цей код обертає зображення на 30 градусів і тоді віддзеркалює його по горизонталі:
///
/// @code
/// lilka::Transform transform = lilka::Transform().rotate(30).flipX();
Expand All @@ -374,23 +384,38 @@ class Transform {
///
/// Оскільки на екрані вісь Y вказує вниз, обертання буде здійснено за годинниковою стрілкою.
/// @param angle Кут обертання в градусах.
/// @return Нове перетворення.
Transform rotate(int16_t angle);
/// Масштабувати по X та Y.
///
/// Щоб віддзеркалити зображення, використайте від'ємні значення (наприклад, -1).
/// @param scaleX Масштаб по X.
/// @param scaleY Масштаб по Y.
/// @return Нове перетворення.
Transform scale(float scaleX, float scaleY);

/// Застосувати інше перетворення до цього.
/// Помножити це перетворення на інше.
///
/// @note Зверніть увагу: при комбінації перетворень порядок важливий, і він є оберненим до порядку множення матриць! В результаті цього, перетворення other буде виконано **перед** поточним перетворенням. Тобто якщо в вас є деякі перетворення `A` та `B`, то перетворення `A.multiply(B)` утворить нове перетворення, в якому спочатку виконається перетворення `B`, а потім `A`.
/// @note Для уникнення плутанини рекомендуємо використовувати більш високорівневі методи, такі як `rotate` та `scale`.
/// @param other Інше перетворення.
/// @return Перетворення, яке є результатом застосування цього перетворення після `other` перетворення.
/// @code
/// lilka::Transform rotate30 = lilka::Transform().rotate(30); // обернути на 30 градусів
/// lilka::Transform scale2x = lilka::Transform().scale(2, 2); // збільшити в 2 рази
/// lilka::Transform scaleThenRotate = rotate30.multiply(scale2x); // результат - це перетворення "спочатку збільшити, а потім обернути", а не навпаки!
/// @endcode
Transform multiply(Transform other);

/// Інвертувати перетворення.
/// @note Інвертне перетворення - це таке перетворення, яке скасує це перетворення, тобто є зворотнім до цього.
/// @return Інвертоване перетворення.
Transform inverse();

int_vector_t apply(int_vector_t vector);
/// Перетворити вектор, використовуючи це перетворення.
/// @param vector Вхідний вектор.
/// @return Результат перетворення.
int_vector_t transform(int_vector_t vector);

// Матриця перетворення
float matrix[2][2]; // [рядок][стовпець]
Expand Down

0 comments on commit 3e572d7

Please sign in to comment.