Это просто цепочка рандомных отрезков одноцветных, в секторе 30 градусов.
Тут в качестве алгоритма:
- Первоначальный отрезок на каждом шаге рандомно либо продолжает расти либо разветвляется на два отрезка под углом 120 град.
- Каждая ветка на следующем шаге ведет себя независимо и либо продолжается, либо ветвится.
- если ветка выходит за границы сектора, она останавливается (и не отрисовывается)
- каждый сектор повторяется в первоначальном виде, либо в симметрично отображенном, как у Вас.
Собственно Ваш код я и изменял. Переделал под обычный экран st7789 и алгоритм отрисовки внутри одного сектора сделал как выше написал.
Из очевидных минусов - никак не отслеживается пересечение отрезков внутри сектора, поэтому иногда “густой лес“ возникает.
Красиво, а скетч чего не выкладываете? Я б попробовал переделать под GC9A01A. Узоры получаются круглые.
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <SPI.h>
#include <ArxContainer.h>
#define TFT_DC 16
#define TFT_CS 5
#define TFT_RST 26
#define BRANCH 1
#define STRAIGHT 2
Adafruit_ST7789 tft(TFT_CS, TFT_DC, TFT_RST);
// Константы координат смещения центра
constexpr int CENTER_X = 120;
constexpr int CENTER_Y = 120;
constexpr float r = 5.0;
struct Line {
float x1;
float y1;
float x2;
float y2;
};
std::vector<Line> openedLines;
std::vector<Line> nextLines;
constexpr int lineCount = 15;
void setup() {
Serial.begin(115200);
tft.init(240, 320);
tft.fillScreen(ST77XX_BLUE);
tft.setRotation(2);
Serial.println("tft is filled by blue color");
// tft.cp437(true);
// Инициализация генератора случайных чисел
//randomSeed(analogRead(22));
randomSeed(22);
}
void loop() {
openedLines.clear();
tft.fillScreen(ST77XX_BLUE);
// рисуем первые линии
Line firstLine;
firstLine.x1 = 0.0;
firstLine.y1 = 0.0;
firstLine.x2 = r;
firstLine.y2 = 0.0;
openedLines.push_back(firstLine);
//drawLineSnowflake(firstLine.x1, firstLine.y1, firstLine.x2, firstLine.y2);
for (int i = 0; i < lineCount; ++i) {
for (auto& line : openedLines) {
int event = getRandomEvent();
drawNextStep(line, event);
}
nextLines.swap(openedLines);
nextLines.clear();
delay(30);
}
delay(3000);
}
void addLine(float x1, float y1, float x2, float y2)
{
Line newLine;
newLine.x1 = x1;
newLine.y1 = y1;
newLine.x2 = x2;
newLine.y2 = y2;
if (drawLineSnowflake(x1, y1, x2, y2))
nextLines.push_back(newLine);
}
void drawNextStep(Line &l, int event)
{
// const calculation
constexpr float sin60 = sin(PI / 3);
constexpr float cos60 = cos(PI / 3);
constexpr float xStraight = 2*r;
constexpr float yStraight = 0;
constexpr float xTurn = (1 + sin60)*r;
constexpr float yTurn = cos60 * r; // *(-1) for right turn
float tetta = atan((l.y2 - l.y1)/(l.x2 - l.x1));
if (event == STRAIGHT)
{
// turn on tetta:
float tempX = xStraight * cos(tetta) - yStraight * sin(tetta);
float tempY = xStraight * sin(tetta) + yStraight * cos(tetta);
// move to l.x1, l.y1
float x = tempX + l.x1;
float y = tempY + l.y1;
addLine(l.x2, l.y2, x, y);
}
else if (event == BRANCH)
{
float tempXLeft = xTurn * cos(tetta) - yTurn * sin(tetta);
float tempYLeft = xTurn * sin(tetta) + yTurn * cos(tetta);
float tempXRight = xTurn * cos(tetta) + yTurn * sin(tetta);
float tempYRight = xTurn * sin(tetta) - yTurn * cos(tetta);
float xLeft = tempXLeft + l.x1;
float yLeft = tempYLeft + l.y1;
float xRight = tempXRight + l.x1;
float yRight = tempYRight + l.y1;
addLine(l.x2, l.y2, xLeft, yLeft);
addLine(l.x2, l.y2, xRight, yRight);
}
}
int getRandomEvent()
{
long rand = random(60);
if (rand < 30)
return BRANCH;
return STRAIGHT;
}
////////////////////////////////////
//функция построения отрезка в полярных координатах с центром в центре экрана
void drawLinePol(int r1, float f1, int r2, float f2) {
tft.drawLine(
CENTER_X + cos(f1) * r1,
CENTER_Y + sin(f1) * r1,
CENTER_X + cos(f2) * r2,
CENTER_Y + sin(f2) * r2,
ST77XX_WHITE
);
}
//////////////////////////////////
//функция построения 12 отсимметриченных отрезков снежинки по базовому отрезку
void drawLineSnowflake (int r1, float f1, int r2, float f2) {
if (r1 > 120 || r2 > 120 || r1 < 0 || r2 < 0 || f1 < 0.0 || f2 < 0.0 || f1 > PI / 6.0 || f2 > PI / 6) {
return; //условие рисования базового отрезка в допустимых значениях аргументов (0-120 пикселей радиус, 0-PI/6 угол(сектор))
}
for (float i = 0.01; i < 2 * PI; i += PI / 3.0) {
drawLinePol(r1, f1 + i, r2, f2 + i);
drawLinePol(r1, 2 * PI - f1 + i, r2, 2 * PI - f2 + i);
}
}
//////////////////////////////////
bool drawLineSnowflake (float x1, float y1, float x2, float y2) {
float r1 = sqrt(x1*x1 + y1*y1);
float r2 = sqrt(x2*x2 + y2*y2);
float f1 = atan(y1/x1);
float f2 = atan(y2/x2);
if (r1 > 120 || r2 > 120 || r1 < 0 || r2 < 0 || f1 < 0.0 || f2 < 0.0 || f1 > PI / 6.0 || f2 > PI / 6) {
return false; //условие рисования базового отрезка в допустимых значениях аргументов (0-120 пикселей радиус, 0-PI/6 угол(сектор))
}
for (float i = 0.01; i < 2 * PI; i += PI / 3.0) {
drawLinePol(r1, f1 + i, r2, f2 + i);
drawLinePol(r1, 2 * PI - f1 + i, r2, 2 * PI - f2 + i);
}
return true;
}
А мне казалось, что я немного написал)
Рассматривая фото снежинок есть предположение, что направление роста выбирается в сторону с наименьшей плотностью кристаллов. Если в направлении текущего луча пусто, то луч растет.
Но по факту, если смотреть идеальные условия, то в спокойном воздухе есть молекула воды. Она выбирает ближайшую грань призмы льда к ней, чтобы прирасти. К кончику призмы (продолжению луча или только что завязавшемуся отростку) прирасти легче. После прироста в данном месте количество молекул воды в воздухе уменьшается. Для симметричной снежинки на каждом секторе условия одинаковые.
Адаптировал, конечно мало что понимаю в скетче, но выглядит красиво
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
#include <SPI.h>
#define TFT_DC 17
#define TFT_CS 16
/*
SCL --> 18 (SCK)
SDA --> 23 (MOSI)
RST --> EN
*/
Adafruit_GC9A01A tft(TFT_CS, TFT_DC);
#define BRANCH 1
#define STRAIGHT 2
// Константы координат смещения центра
constexpr int CENTER_X = 120;
constexpr int CENTER_Y = 120;
constexpr float r = 5.0;
struct Line {
float x1;
float y1;
float x2;
float y2;
};
std::vector<Line> openedLines;
std::vector<Line> nextLines;
constexpr int lineCount = 17;
void setup() {
// Инициализация генератора случайных чисел
randomSeed(analogRead(32));
tft.begin();
tft.fillScreen(GC9A01A_YELLOW);
// tft.cp437(true);
tft.setRotation(1);
}
void loop() {
openedLines.clear();
tft.fillScreen(GC9A01A_ORANGE);
// рисуем первые линии
Line firstLine;
firstLine.x1 = 0.0;
firstLine.y1 = 0.0;
firstLine.x2 = r;
firstLine.y2 = 0.0;
openedLines.push_back(firstLine);
//drawLineSnowflake(firstLine.x1, firstLine.y1, firstLine.x2, firstLine.y2);
for (int i = 0; i < lineCount; ++i) {
for (auto& line : openedLines) {
int event = getRandomEvent();
drawNextStep(line, event);
}
nextLines.swap(openedLines);
nextLines.clear();
delay(50);
}
delay(3000);
}
void addLine(float x1, float y1, float x2, float y2)
{
Line newLine;
newLine.x1 = x1;
newLine.y1 = y1;
newLine.x2 = x2;
newLine.y2 = y2;
if (drawLineSnowflake(x1, y1, x2, y2))
nextLines.push_back(newLine);
}
void drawNextStep(Line &l, int event)
{
// const calculation
constexpr float sin60 = sin(PI / 3);
constexpr float cos60 = cos(PI / 3);
constexpr float xStraight = 2*r;
constexpr float yStraight = 0;
constexpr float xTurn = (1 + sin60)*r;
constexpr float yTurn = cos60 * r; // *(-1) for right turn
float tetta = atan((l.y2 - l.y1)/(l.x2 - l.x1));
if (event == STRAIGHT)
{
// turn on tetta:
float tempX = xStraight * cos(tetta) - yStraight * sin(tetta);
float tempY = xStraight * sin(tetta) + yStraight * cos(tetta);
// move to l.x1, l.y1
float x = tempX + l.x1;
float y = tempY + l.y1;
addLine(l.x2, l.y2, x, y);
}
else if (event == BRANCH)
{
float tempXLeft = xTurn * cos(tetta) - yTurn * sin(tetta);
float tempYLeft = xTurn * sin(tetta) + yTurn * cos(tetta);
float tempXRight = xTurn * cos(tetta) + yTurn * sin(tetta);
float tempYRight = xTurn * sin(tetta) - yTurn * cos(tetta);
float xLeft = tempXLeft + l.x1;
float yLeft = tempYLeft + l.y1;
float xRight = tempXRight + l.x1;
float yRight = tempYRight + l.y1;
addLine(l.x2, l.y2, xLeft, yLeft);
addLine(l.x2, l.y2, xRight, yRight);
}
}
int getRandomEvent()
{
long rand = random(60);
if (rand < 30)
return BRANCH;
return STRAIGHT;
}
////////////////////////////////////
//функция построения отрезка в полярных координатах с центром в центре экрана
void drawLinePol(int r1, float f1, int r2, float f2) {
tft.drawLine(
CENTER_X + cos(f1) * r1,
CENTER_Y + sin(f1) * r1,
CENTER_X + cos(f2) * r2,
CENTER_Y + sin(f2) * r2,
GC9A01A_BLACK
);
}
//////////////////////////////////
//функция построения 12 отсимметриченных отрезков снежинки по базовому отрезку
void drawLineSnowflake (int r1, float f1, int r2, float f2) {
if (r1 > 120 || r2 > 120 || r1 < 0 || r2 < 0 || f1 < 0.0 || f2 < 0.0 || f1 > PI / 6.0 || f2 > PI / 6) {
return; //условие рисования базового отрезка в допустимых значениях аргументов (0-120 пикселей радиус, 0-PI/6 угол(сектор))
}
for (float i = 0.01; i < 2 * PI; i += PI / 3.0) {
drawLinePol(r1, f1 + i, r2, f2 + i);
drawLinePol(r1, 2 * PI - f1 + i, r2, 2 * PI - f2 + i);
}
}
//////////////////////////////////
bool drawLineSnowflake (float x1, float y1, float x2, float y2) {
float r1 = sqrt(x1*x1 + y1*y1);
float r2 = sqrt(x2*x2 + y2*y2);
float f1 = atan(y1/x1);
float f2 = atan(y2/x2);
if (r1 > 120 || r2 > 120 || r1 < 0 || r2 < 0 || f1 < 0.0 || f2 < 0.0 || f1 > PI / 6.0 || f2 > PI / 6) {
return false; //условие рисования базового отрезка в допустимых значениях аргументов (0-120 пикселей радиус, 0-PI/6 угол(сектор))
}
for (float i = 0.01; i < 2 * PI; i += PI / 3.0) {
drawLinePol(r1, f1 + i, r2, f2 + i);
drawLinePol(r1, 2 * PI - f1 + i, r2, 2 * PI - f2 + i);
}
return true;
}
И по внешнему виду узоры конечно отличаются
Видно что до края не доходит. Можно в 26 строке (Вашего скетча) увеличить размер одного шага (при 8 лучше, вроде)
Еще можно поиграться количеством шагов (в 37 стр), но у меня не сказать что получалось красивее. Либо в конце лес густой с большим количеством шагов, либо с маленьким количеством недоснежинка какая-то.
И с вероятностью ветвления (в 127-128 стр).
Попробовал с настройками. В целом отрисовка отрезками выглядит симпатично, надо попробовать закрашенными треугольниками, подобно вырезки из бумаги снежинок.
А какое это имеет отношение к снежинкам?
Или пора менять название темы на “калейдоскоп”?
Они больше похожи на снежинки. Наверное есть смысл задуматься об отрисовки роста с помощью треугольников, сопоставив пластинам и лучам разные по форме треугольники.
…или дополнительно усилить разными оттенками цвета.
Так вроде и геометрия-симметрия другая
Непонятно, почему порядок просматривается в центре и слабо виден на периферии.
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
#include <SPI.h>
#define TFT_DC 17
#define TFT_CS 16
/*
SCL --> 18 (SCK)
SDA --> 23 (MOSI)
RST --> EN
*/
Adafruit_GC9A01A tft(TFT_CS, TFT_DC);
// Константы координат смещения центра
const int CENTER_X = 120;
const int CENTER_Y = 120;
int r1 = 0;
float f1 = 0;
int delta_r = 15;
int delta_F = 15;
int F1 = 0; //
void setup() {
// Инициализация генератора случайных чисел
randomSeed(analogRead(32));
tft.begin();
tft.fillScreen(GC9A01A_WHITE);
// tft.cp437(true);
tft.setRotation(1);
}
void loop() {
for (int i = 0; i < 200; i++) {
int r1; float f1;
r1 = random(0, 50); f1 = (random(0, 101) / 100.0) * (PI / 6.0);//центр
if (i < 90) { // середина
r1 = random(50, 90);
f1 = (random(0, 101) / 100.0) * (PI / 6.0);
}
if (i < 20) {//периферия
r1 = random(90, 110);
f1 = (random(0, 101) / 100.0) * (PI / 6.0);
}
drawPixelSnowflake ( r1, f1);
delay(20);
}
delay(5000);
tft.fillScreen(GC9A01A_WHITE);
delay(300);
}
////////////////////////////////////
//функция построения точки в полярных координатах с центром в центре экрана
void drawPixelPol(int r1, float f1) {
tft.drawPixel(
CENTER_X + cos(f1) * r1,
CENTER_Y + sin(f1) * r1,
GC9A01A_BLACK
);
}
//////////////////////////////////
//функция построения 12 отсимметриченных точек снежинки по базовой точке
void drawPixelSnowflake (int r1, float f1) {
if (r1 > 120 || r1 < 0 || f1 < 0.0 || f1 > PI / 6.0 ) {
return; //условие рисования базового отрезка в допустимых значениях аргументов (0-120 пикселей радиус, 0-PI/6 угол(сектор))
}
for (float i = 0.01; i < 2 * PI; i += PI / 3.0) {
drawPixelPol(r1, f1 + i);
drawPixelPol(r1, 2 * PI - f1 + i);
}
}
//////////////////////////////////
lilik мне после этих фото пришла мысля, попытаться реализовать эмуляцию работы стола для рисования на песке, с помощью дисплея)))
может снежинку попытаться рисовать движением шарика на экране ?
пока не начал писать код, не знаю реально или нет, и какие сложности возникнут…
кстате преобразование фото в G код на esp у меня так и не вышло…
Проблема в логике вашего цикла for в функции loop(). У вас условия расположены неправильно, что приводит к тому, что точки рисуются только в центральной области. Давайте разберем:
cpp
for (int i = 0; i < 200; i++) {
int r1; float f1;
r1 = random(0, 50); f1 = (random(0, 101) / 100.0) * (PI / 6.0); // центр
if (i < 90) { // середина
r1 = random(50, 90);
f1 = (random(0, 101) / 100.0) * (PI / 6.0);
}
if (i < 20) { // периферия
r1 = random(90, 110);
f1 = (random(0, 101) / 100.0) * (PI / 6.0);
}
drawPixelSnowflake(r1, f1);
delay(20);
}
Проблема:
Сначала вы всегда устанавливаете r1 для центра (0-50)
Потом если i < 90 (первые 90 итераций) - перезаписываете для середины (50-90)
Потом если i < 20 (первые 20 итераций) - перезаписываете для периферии (90-110)
Это значит:
При i = 0..19: срабатывают ВСЕ три условия! Сначала центр, потом середина, потом периферия - остается периферия
При i = 20..89: срабатывают два условия (центр и середина) - остается середина
При i = 90..199: срабатывает только первое условие (центр) - остается центр
Результат: вы получаете только 20 точек периферии, 70 точек середины и 110 точек центра, а не распределенные по всем областям.
Решение: используйте правильную логику распределения:
cpp
void loop() {
for (int i = 0; i < 200; i++) {
int r1;
float f1;
// Равномерное распределение по всем областям
int area = random(0, 3); // 0, 1 или 2
if (area == 0) {
// Центр - 33% точек
r1 = random(0, 50);
}
else if (area == 1) {
// Середина - 33% точек
r1 = random(50, 90);
}
else {
// Периферия - 33% точек
r1 = random(90, 110);
}
f1 = (random(0, 101) / 100.0) * (PI / 6.0);
drawPixelSnowflake(r1, f1);
delay(20);
}
delay(5000);
tft.fillScreen(GC9A01A_WHITE);
delay(300);
}
Альтернативное решение - если вы хотите точно контролировать количество точек в каждой области:
cpp
void loop() {
// Рисуем периферию - 20 точек
for (int i = 0; i < 20; i++) {
int r1 = random(90, 110);
float f1 = (random(0, 101) / 100.0) * (PI / 6.0);
drawPixelSnowflake(r1, f1);
delay(20);
}
// Рисуем середину - 70 точек
for (int i = 0; i < 70; i++) {
int r1 = random(50, 90);
float f1 = (random(0, 101) / 100.0) * (PI / 6.0);
drawPixelSnowflake(r1, f1);
delay(20);
}
// Рисуем центр - 110 точек
for (int i = 0; i < 110; i++) {
int r1 = random(0, 50);
float f1 = (random(0, 101) / 100.0) * (PI / 6.0);
drawPixelSnowflake(r1, f1);
delay(20);
}
delay(5000);
tft.fillScreen(GC9A01A_WHITE);
delay(300);
}
Также обратите внимание, что переменные delta_r = 15 и delta_F = 15, F1 = 0 объявлены, но нигде не используются в коде.
Да, можно попробовать сгенерить.
Именно.
Это уже ближе к бабушкиным кружевным салфеткам. Вывести на телек и “назад в будущее” 8))))
#include <TFT_eSPI.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();
// Начальные координаты круга
int x = TFT_WIDTH / 2;
int y = TFT_HEIGHT / 2;
// Скорость движения
int speedX = 2;
int speedY = 1;
// Цвета
#define DARK_YELLOW 0x7BE0 // Темно-желтый фон
#define CIRCLE_COLOR TFT_RED // Красный круг
#define OUTLINE_COLOR TFT_BLUE // Синий контур
// Радиус круга
#define CIRCLE_RADIUS 8
void setup() {
Serial.begin(115200);
// Инициализация дисплея
tft.init();
tft.setRotation(0); // Ориентация 0 градусов
// Включение подсветки
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
// Заливаем фон темно-желтым
tft.fillScreen(DARK_YELLOW);
// Рисуем первый круг
drawCircleWithOutline(x, y);
Serial.println("Display initialized with circle");
}
void drawCircleWithOutline(int x, int y) {
// Рисуем контур круга (синий)
tft.drawCircle(x, y, CIRCLE_RADIUS + 1, OUTLINE_COLOR);
tft.drawCircle(x, y, CIRCLE_RADIUS, OUTLINE_COLOR);
// Рисуем красный круг
tft.fillCircle(x, y, CIRCLE_RADIUS - 1, CIRCLE_COLOR);
}
void moveCircle() {
// Сохраняем старые координаты
int oldX = x;
int oldY = y;
// Обновляем координаты
x += speedX;
y += speedY;
// Проверка на границы экрана (учитываем радиус с контуром)
if (x <= (CIRCLE_RADIUS + 2) || x >= TFT_WIDTH - (CIRCLE_RADIUS + 2)) {
speedX = -speedX;
x = constrain(x, CIRCLE_RADIUS + 2, TFT_WIDTH - (CIRCLE_RADIUS + 2));
}
if (y <= (CIRCLE_RADIUS + 2) || y >= TFT_HEIGHT - (CIRCLE_RADIUS + 2)) {
speedY = -speedY;
y = constrain(y, CIRCLE_RADIUS + 2, TFT_HEIGHT - (CIRCLE_RADIUS + 2));
}
// Стираем старый круг
int eraseSize = (CIRCLE_RADIUS + 2) * 2;
tft.fillRect(oldX - (CIRCLE_RADIUS + 2), oldY - (CIRCLE_RADIUS + 2),
eraseSize, eraseSize, DARK_YELLOW);
// Рисуем новый круг
drawCircleWithOutline(x, y);
}
void loop() {
// Обновляем координаты
x += speedX;
y += speedY;
// Проверка границ
if (x <= CIRCLE_RADIUS || x >= TFT_WIDTH - CIRCLE_RADIUS) {
speedX = -speedX;
x = constrain(x, CIRCLE_RADIUS, TFT_WIDTH - CIRCLE_RADIUS);
}
if (y <= CIRCLE_RADIUS || y >= TFT_HEIGHT - CIRCLE_RADIUS) {
speedY = -speedY;
y = constrain(y, CIRCLE_RADIUS, TFT_HEIGHT - CIRCLE_RADIUS);
}
// Просто рисуем новый круг (старый не стирается)
tft.drawCircle(x, y, CIRCLE_RADIUS, OUTLINE_COLOR);
tft.fillCircle(x, y, CIRCLE_RADIUS - 1, CIRCLE_COLOR);
delay(50);
}
толи я спать уже хочу, толи не знаю как просто убрать следы от круга без обновления большой области дисплея! что бы рисовать на нем…
надо завтра подумать, вот на тот случай если завтра загрузят и не будет времени))
не знаю еще хорошая ли идея рисовать… вроде как минимальную графику можно сделать картинками….
Способов можно придумать 100500, но самый быстрый - стирание (заполнение цветом фона или фоновым рисунком) изображения на дисплее. По крайней мере, если рисунок составляет больше 10% от соответствующей площади дисплея.
Если меньше - пройтись только по точкам рисунка, заполняя их цветом фона/фоновым рисунком.
Да, надо изменить цвета и алгоритм чуть усложнить.

#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
#include <SPI.h>
#define TFT_DC 17
#define TFT_CS 16
/*
SCL --> 18 (SCK)
SDA --> 23 (MOSI)
RST --> EN
*/
Adafruit_GC9A01A tft(TFT_CS, TFT_DC);
// Константы координат смещения центра
const int CENTER_X = 120;
const int CENTER_Y = 120;
int delta_r = 15;//интервалы расброса координат окрестных точек
int delta_F = 70;//
int F1 = 0; //
void setup() {
// Инициализация генератора случайных чисел
randomSeed(analogRead(32));
tft.begin();
tft.fillScreen(GC9A01A_BLACK);
// tft.cp437(true);
tft.setRotation(1);
}
void loop() {
//
for (int j = 0; j < 7; j++) {// цикл отстройки базовых точек
int r1 = random(0, 110); float f1 = (random(0, 101) / 100.0) * (PI / 6.0);
drawPixelSnowflake(r1, f1);
//
for (int i = 0; i < 15; i++) {//цикл отстройки окрестных точек
//
int r2 = random(r1 - delta_r, r1 + delta_r );
if (r2 < 0) {
r2 = 0;
}
if (r2 > 100) {
r2 = 100;
}
//
int F2 = random(F1 - delta_F, F1 + delta_F);
if (F2 < 0) {
F2 = 0;
}
if (F2 > 100) {
F2 = 100;
}
float f2 = (F2 / 100.0) * (PI / 6.0);
drawPixelSnowflake(r2, f2);
delay(20);
}
}
delay(1000);
tft.fillScreen(GC9A01A_BLACK);
delay(300);
}
////////////////////////////////////
//функция построения точки в полярных координатах с центром в центре экрана
void drawPixelPol(int r1, float f1) {
tft.drawPixel(
CENTER_X + cos(f1) * r1,
CENTER_Y + sin(f1) * r1,
GC9A01A_WHITE
);
}
//////////////////////////////////
//функция построения 12 отсимметриченных точек снежинки по базовой точке
void drawPixelSnowflake (int r1, float f1) {
if (r1 > 120 || r1 < 0 || f1 < 0.0 || f1 > PI / 6.0 ) {
return; //условие рисования базового отрезка в допустимых значениях аргументов (0-120 пикселей радиус, 0-PI/6 угол(сектор))
}
for (float i = 0.01; i < 2 * PI; i += PI / 3.0) {
drawPixelPol(r1, f1 + i);
drawPixelPol(r1, 2 * PI - f1 + i);
}
}
//////////////////////////////////
Что тут думать? Сначала сделай как у меня. Разница в том, что отрисовываются отрезки не в 12 секторах одновременно, а по очереди (по часовой стрелке обход от 0 часов до 12). Понятно, что рисунок это координаты полярные отрезков из первого сектора, их хранить в массиве. При переходе меж секторами зеркалишь (читаешь массив с конца к началу, потом от начала к концу и т.д.).
…ИИ тебе в помощь








