Генератор роста снежинок (ГРСН)

Тогда тем более начинать со скетча вывода данных с карты на дисплей в виде картинки, иначе как навигацию делать?, не по названиям же картинок :slight_smile:
…изменил координату смены узора и случайный выбор сектора на круговой перебор секторов - узор плавно меняется во всех вариантах картинки (ограничил 32 вариантами на картинку).
VID_20260211_081245 (1)
02

#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
#include <SPI.h>
#include "ris_1.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;
const float Z = 300.0; //от 100.0 до 1000.0 регулировка качества отрисовки пикселей с пропусками и без них
const struct {
  const unsigned char *bitmap;
}
uzor_[] = {ris_1, ris_2, ris_3, ris_4, ris_5, ris_6, ris_7}; // картинки

void setup() {
  // Инициализация генератора случайных чисел
  randomSeed(analogRead(32));
  tft.begin();
  tft.fillScreen(GC9A01A_BLACK);
  // tft.cp437(true);
  tft.setRotation(2);

}

void loop() {
  for (byte ris = 0; ris < 7 ; ris++) {
    for (float f = 0.0; f < 2 * PI - PI / 6.0 ; f += PI / 16) {
      draw_RisSektor(f, uzor_[ris].bitmap );
      delay(500);
    }
  }
}
//////////////////////////////////////
//функция вывода 12 отсимметриченных секторов узора по базовому сектору картинки
void draw_RisSektor(float S, const uint8_t *bitmap) {
  for (float f1 = 0.0; f1 <= PI / 6.0; f1 += PI / Z) {
    for (int r1 = 0; r1 <= 120 ; r1 += 1) {
      int x = CENTER_X + cos(f1 + S) * r1;
      int y = CENTER_Y + sin(f1 + S) * r1;
      for (float i = 0.01; i <= 2 * PI; i += PI / 3.0) {
        int x1 = CENTER_X + cos(f1 + i) * r1;
        int y1 = CENTER_Y + sin(f1 + i) * r1;
        tft.drawPixel(x1, y1, 256 * bitmap[2 * x + 1 + y * 2 * 240] + bitmap[2 * x + y * 2 * 240]);
        int x2 = CENTER_X + cos(2 * PI - f1 + i) * r1;
        int y2 = CENTER_Y + sin(2 * PI - f1 + i) * r1;
        tft.drawPixel(x2, y2, 256 * bitmap[2 * x + 1 + y * 2 * 240] + bitmap[2 * x + y * 2 * 240]);

      }
    }
  }
}
//////////////////////////////////////


Дальше надо как-то скетч писать для обучения нейросети по фрагментам-секторам картинок, чтоб сама генерировала сектор подобный сектору картинки :slight_smile:

не так долго как мне кажется, ведь в один момент времени нам требуется читать 1 текстовый документ построчно, но я еще не проверял)))

#include <TFT_eSPI.h>
#include <SPI.h>

TFT_eSPI tft = TFT_eSPI();

const int CENTER_X = 64;
const int CENTER_Y = 80;
const float Z = 200.0;  // Уменьшено для производительности
const int TFT_BL_PIN = 12;  // Пин подсветки

// Параметры для генерации узоров
float noiseScale = 0.05;
float animationTime = 0.0;  // Переименовано с time

// Цветовая палитра для ST7735 (16-bit цвета)
uint16_t palette[] = {
  TFT_RED, TFT_GREEN, TFT_BLUE,
  TFT_YELLOW, TFT_MAGENTA, TFT_CYAN,
  TFT_WHITE, TFT_ORANGE, TFT_PURPLE,
  TFT_PINK, TFT_LIGHTGREY, TFT_DARKGREY,
  TFT_MAROON, TFT_NAVY, TFT_DARKGREEN
};
const int PALETTE_SIZE = 15;

// Генерация значения пикселя на основе позиции в секторе
uint16_t generatePixelValue(float angle, float radius, float sector, int patternType) {
  // Нормализованные координаты от 0 до 1
  float nx = cos(angle + sector) * radius / 80.0;
  float ny = sin(angle + sector) * radius / 80.0;
  
  // Используем animationTime вместо time
  float t = animationTime * 0.1;
  
  switch(patternType % 8) {
    case 0: // Концентрические круги
      return palette[(int)((sin(radius * 0.3 + sector + t) * 0.5 + 0.5) * PALETTE_SIZE)];
    
    case 1: // Спирали
      {
        float spiral = sin(angle * 8 + radius * 0.15 + t);
        int colorIndex = (int)((spiral * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 2: // Волны
      {
        float wave = sin(nx * 8 + t) * sin(ny * 8 + t * 0.7);
        int colorIndex = (int)((wave * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 3: // Шумоподобный узор
      {
        float noise = 0;
        for(int i = 0; i < 2; i++) {
          float freq = pow(2, i);
          noise += sin((nx * freq + t) * 8) * sin((ny * freq + t * 0.5) * 8) / freq;
        }
        int colorIndex = (int)((noise * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 4: // Мандала
      {
        float mandala = sin(angle * 10) * sin(radius * 0.4) + cos(angle * 6 + t);
        int colorIndex = (int)((mandala * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 5: // Радиальный градиент
      {
        float grad = fmod(angle * 4 + radius * 0.15 + t, 2 * PI) / (2 * PI);
        int colorIndex = (int)(grad * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 6: // Геометрический паттерн
      {
        float geo = sin(angle * 6) * cos(radius * 0.25) + sin(t * 0.5);
        int colorIndex = (int)((geo * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 7: // Пульсирующие кольца
      {
        float pulse = sin(radius * 0.2 - t * 2) * cos(angle * 4 + t);
        int colorIndex = (int)((pulse * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    default:
      return TFT_WHITE;
  }
}

void setup() {
  Serial.begin(115200);
  
  // Настройка пина подсветки
  pinMode(TFT_BL_PIN, OUTPUT);
  analogWrite(TFT_BL_PIN, 255);  // Включить подсветку на максимум
  
  // Инициализация дисплея
  tft.init();
  tft.setRotation(3);  // Поворот для дисплея 128x160
  tft.fillScreen(TFT_BLACK);
  
  // Настройка скорости SPI (опционально)
  // SPI.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
  
  Serial.println("Дисплей инициализирован");
  delay(1000);
}

void loop() {
  static int patternType = 0;
  static unsigned long lastTime = 0;
  
  // Ограничение FPS
  if (millis() - lastTime < 50) {
    return;
  }
  lastTime = millis();
  
  // Очистка экрана
  tft.fillScreen(TFT_BLACK);
  
  // Оптимизация: начинаем пакетную запись
  tft.startWrite();
  
  // Генерация и отрисовка всех секторов для текущего паттерна
  for (float sector = 0.0; sector < 2 * PI - PI / 6.0 ; sector += PI / 12) {
    drawGeneratedSector(sector, patternType);
  }
  
  // Завершаем пакетную запись
  tft.endWrite();
  
  // Увеличиваем время анимации
  animationTime += 0.1;
  
  // Переход к следующему паттерну каждые 5 секунд
  static unsigned long patternChangeTime = 0;
  if (millis() - patternChangeTime > 5000) {
    patternChangeTime = millis();
    patternType = (patternType + 1) % 8;
    
    // Эффект мигания подсветкой при смене паттерна
    for (int i = 255; i >= 150; i -= 10) {
      analogWrite(TFT_BL_PIN, i);
      delay(20);
    }
    for (int i = 150; i <= 255; i += 10) {
      analogWrite(TFT_BL_PIN, i);
      delay(20);
    }
  }
}

// Функция вывода сгенерированных секторов
void drawGeneratedSector(float S, int patternType) {
  // Уменьшаем плотность отрисовки для производительности
  for (float f1 = 0.0; f1 <= PI / 6.0; f1 += PI / Z) {
    for (int r1 = 0; r1 <= 80 ; r1 += 1) {
      // Генерируем цвет для базового пикселя
      uint16_t pixelColor = generatePixelValue(f1, r1, S, patternType);
      
      // Отрисовка 12 симметричных секторов
      for (float i = 0.01; i <= 2 * PI; i += PI / 6.0) {
        // Первый симметричный сектор
        int x1 = CENTER_X + cos(f1 + i) * r1;
        int y1 = CENTER_Y + sin(f1 + i) * r1;
        
        // Проверка границ экрана
        if (x1 >= 0 && x1 < 128 && y1 >= 0 && y1 < 160) {
          tft.drawPixel(x1, y1, pixelColor);
        }
        
        // Второй симметричный сектор (зеркальный)
        int x2 = CENTER_X + cos(2 * PI - f1 + i) * r1;
        int y2 = CENTER_Y + sin(2 * PI - f1 + i) * r1;
        
        if (x2 >= 0 && x2 < 128 && y2 >= 0 && y2 < 160) {
          tft.drawPixel(x2, y2, pixelColor);
        }
      }
    }
  }
}

// Упрощенная функция для быстрой отрисовки
void drawSimplePattern(int patternType) {
  tft.startWrite();
  
  for (int x = 0; x < 128; x++) {
    for (int y = 0; y < 160; y++) {
      // Преобразуем координаты в полярные
      float dx = x - CENTER_X;
      float dy = y - CENTER_Y;
      float radius = sqrt(dx*dx + dy*dy);
      float angle = atan2(dy, dx);
      
      if (radius <= 80) {
        // Простой расчет цвета
        uint16_t color = generatePixelValue(angle, radius, 0, patternType);
        tft.drawPixel(x, y, color);
      }
    }
  }
  
  tft.endWrite();
}

а так же учтите что рисунок меняется очень долго

а еще почему вы не выкладываете свое фото ? а то некоторым может лениво искать несколько фото, потом переводить их в код)))
фото не могу сделать…. времени мало)))

просто присмотритесь, может это то что нужно))) вечером может видео выложу и подправлю…
у меня не было стартового фото… вы это хотели получить или нет ?

Адаптирую скетч, увижу.

не очень фотографичен :slight_smile:

Массив картинки не влезет в сообщение форума скорее всего. Размер массива зависит от разрешения дисплея. К вашему они не подойдут. У вас надо 128х128, а не 240х240.

вот тут не понял))) что вы хотите получить ?
задача получать бесконечное количество новых рисунков ? (и если да не проблема что они не будут похожи на снежинки ?)

я загружал больше изображение, другое дело что его обрезать приходилось при выводе, и не видно рисунок полностью)))

мне легко переделывать ваш код на свою библиотеку кстате, у вас не возникает с этим сложностей ?
а то я могу сделать под вашу, но без проверки на самом дисплее не увижу если что не так…

тут чуть рандомнее

#include <TFT_eSPI.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();
const int CENTER_X = 64;
const int CENTER_Y = 80;
const float Z = 200.0;
const int TFT_BL_PIN = 12;
float noiseScale = 0.05;
float animationTime = 0.0;
uint16_t palette[] = {
TFT_RED, TFT_GREEN, TFT_BLUE,
TFT_YELLOW, TFT_MAGENTA, TFT_CYAN,
TFT_WHITE, TFT_ORANGE, TFT_PURPLE,
TFT_PINK, TFT_LIGHTGREY, TFT_DARKGREY,
TFT_MAROON, TFT_NAVY, TFT_DARKGREEN,
0x7E3C, 0x0418, 0x87F0, 0x7FFF, 0xC618, 0x915C
};
const int PALETTE_SIZE = 21;
float randomOffsets[20];
float randomSpeeds[20];
float randomScales[20];
int lastPatternType = -1;
int patternCounter = 0;
void generateRandomParameters() {
for(int i = 0; i < 20; i++) {
randomOffsets[i] = random(0, 628) / 100.0;
randomSpeeds[i] = random(5, 30) / 100.0;
randomScales[i] = random(3, 15) / 10.0;
}
}
uint16_t generatePixelValue(float angle, float radius, float sector, int patternType) {
float nx = (cos(angle + sector) * radius / 80.0) * randomScales[0];
float ny = (sin(angle + sector) * radius / 80.0) * randomScales[1];
float t = animationTime * randomSpeeds[2];
float r = radius / 80.0;
int basePattern = patternType % 12;
float value = 0;
switch(basePattern) {
case 0:
value = sin(radius * randomScales[3] + sector * randomScales[4] + t + randomOffsets[0]);
break;
case 1:
value = sin(angle * (8 * randomScales[5]) + radius * randomScales[6] + t + randomOffsets[1]);
break;
case 2:
value = sin(nx * (8 * randomScales[7]) + t * randomSpeeds[3]) * 
sin(ny * (8 * randomScales[8]) + t * randomSpeeds[4] * 0.7);
break;
case 3:
value = 0;
for(int i = 0; i < 3; i++) {
float freq = pow(randomScales[9 + i], i);
value += sin((nx * freq + t * randomSpeeds[5]) * 8 * randomScales[12]) * 
sin((ny * freq + t * randomSpeeds[6]) * 8 * randomScales[13]) / freq;
}
break;
case 4:
value = sin(angle * (10 * randomScales[14])) * sin(radius * randomScales[15]) + 
cos(angle * (6 * randomScales[16]) + t * randomSpeeds[7]);
break;
case 5:
value = fmod(angle * (4 * randomScales[17]) + radius * randomScales[18] + t * randomSpeeds[8], 2 * PI) / (2 * PI);
return palette[(int)(value * PALETTE_SIZE) % PALETTE_SIZE];
case 6:
value = sin(angle * (6 * randomScales[19])) * cos(radius * randomScales[0]) + sin(t * randomSpeeds[9]);
break;
case 7:
value = sin(radius * randomScales[1] - t * (2 * randomSpeeds[10])) * cos(angle * (4 * randomScales[2]) + t * randomSpeeds[11]);
break;
case 8:
value = sin(nx * 12 + randomOffsets[2]) * cos(ny * 12 + randomOffsets[3]) + sin(t * randomSpeeds[12]) * 0.5;
break;
case 9:
value = sin(radius * 0.1 + angle * 5 + t) * cos(radius * 0.05 - angle * 3) + sin(t * 0.2);
break;
case 10:
value = sin(nx * 15 + t) + sin(ny * 15 + t * 0.7) + sin((nx + ny) * 10 + t * 0.5);
value = value / 3.0;
break;
case 11:
float vortex = atan2(ny - 0.5, nx - 0.5) + radius * 0.2 + t;
value = sin(vortex * 3) * cos(radius * 0.3);
break;
}
int colorIndex = (int)((value * 0.5 + 0.5) * PALETTE_SIZE);
return palette[colorIndex % PALETTE_SIZE];
}
void setup() {
Serial.begin(115200);
pinMode(TFT_BL_PIN, OUTPUT);
analogWrite(TFT_BL_PIN, 255);
tft.init();
tft.setRotation(3);
tft.fillScreen(TFT_BLACK);
randomSeed(analogRead(0));
generateRandomParameters();
Serial.println("Дисплей инициализирован");
delay(1000);
}
void loop() {
static int patternType = 0;
static unsigned long lastTime = 0;
static unsigned long lastRandomChange = 0;
if (millis() - lastTime < 30) {
return;
}
lastTime = millis();
tft.fillScreen(TFT_BLACK);
tft.startWrite();
for (float sector = 0.0; sector < 2 * PI - PI / 6.0; sector += PI / 12) {
drawGeneratedSector(sector + randomOffsets[4] * 0.1, patternType);
}
tft.endWrite();
animationTime += 0.15;
static unsigned long patternChangeTime = 0;
if (millis() - patternChangeTime > 2000) {
patternChangeTime = millis();
patternType = random(0, 12);
patternCounter++;
if(patternCounter % 3 == 0) {
generateRandomParameters();
}
for (int i = 255; i >= 100; i -= 15) {
analogWrite(TFT_BL_PIN, i);
delay(5);
}
for (int i = 100; i <= 255; i += 15) {
analogWrite(TFT_BL_PIN, i);
delay(5);
}
}
if (millis() - lastRandomChange > 500) {
lastRandomChange = millis();
if(random(0, 100) < 30) {
randomOffsets[random(0, 5)] = random(0, 628) / 100.0;
}
}
}
void drawGeneratedSector(float S, int patternType) {
for (float f1 = 0.0; f1 <= PI / 6.0; f1 += PI / Z) {
for (int r1 = 0; r1 <= 80; r1 += 1) {
uint16_t pixelColor = generatePixelValue(f1, r1, S, patternType);
float symmetryOffset = (randomOffsets[5] * 0.1);
for (float i = symmetryOffset; i <= 2 * PI; i += PI / 6.0) {
int x1 = CENTER_X + cos(f1 + i) * r1;
int y1 = CENTER_Y + sin(f1 + i) * r1;
if (x1 >= 0 && x1 < 128 && y1 >= 0 && y1 < 160) {
tft.drawPixel(x1, y1, pixelColor);
}
int x2 = CENTER_X + cos(2 * PI - f1 + i) * r1;
int y2 = CENTER_Y + sin(2 * PI - f1 + i) * r1;
if (x2 >= 0 && x2 < 128 && y2 >= 0 && y2 < 160) {
tft.drawPixel(x2, y2, pixelColor);
}
}
}
}
}
void drawSimplePattern(int patternType) {
tft.startWrite();
for (int x = 0; x < 128; x++) {
for (int y = 0; y < 160; y++) {
float dx = x - CENTER_X;
float dy = y - CENTER_Y;
float radius = sqrt(dx*dx + dy*dy);
float angle = atan2(dy, dx);
if (radius <= 80) {
uint16_t color = generatePixelValue(angle, radius, randomOffsets[6], patternType);
tft.drawPixel(x, y, color);
}
}
}
tft.endWrite();
}

а тут куча хаоса, настолько что иногда хрень выходит + баги отлавливать еще надо

#include <TFT_eSPI.h>
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();
const int CENTER_X = 64;
const int CENTER_Y = 80;
const float Z = 200.0;
const int TFT_BL_PIN = 12;
float animationTime = 0.0;

// РАСШИРЕННАЯ ПАЛИТРА
uint16_t palette[] = {
0xF800, 0x07E0, 0x001F, 0xFFE0, 0xF81F, 0x07FF, 0xFD20, 0xB8E2,
0x7E3C, 0x0418, 0x87F0, 0x7FFF, 0xC618, 0x915C, 0xFBE0, 0x781F,
0xAFE5, 0x4A49, 0xFFF0, 0xF810, 0x07F0, 0x0010, 0xFC80, 0xFC08,
0xE71C, 0xA514, 0x8C71, 0x73AE, 0x5AEB, 0x4228, 0x2965, 0x10A2
};
const int PALETTE_SIZE = 32;

// МАССИВЫ ДЛЯ РАНДОМА
float randomOffsets[50];
float randomSpeeds[50];
float randomScales[50];
int randomBlendModes[50];
int randomSymmetry[50];
int patternHistory[20];
int patternCounter = 0;

void generateRandomParameters() {
  for(int i = 0; i < 50; i++) {
    randomOffsets[i] = random(0, 628) / 100.0;
    randomSpeeds[i] = random(1, 50) / 100.0;
    randomScales[i] = random(1, 30) / 10.0;
    randomBlendModes[i] = random(0, 5);
    randomSymmetry[i] = random(3, 24); // От 3 до 24 осей симметрии
  }
}

// ОСНОВНАЯ ФУНКЦИЯ ГЕНЕРАЦИИ С МНОЖЕСТВОМ ВАРИАЦИЙ
uint16_t generatePixelValue(float angle, float radius, float sector, int patternType) {
  float nx = cos(angle + sector) * radius / 80.0;
  float ny = sin(angle + sector) * radius / 80.0;
  float t = animationTime * randomSpeeds[0];
  float r = radius / 80.0;
  
  // ИСПОЛЬЗУЕМ КОМБИНАЦИЮ ИЗ 3Х РАЗНЫХ ПАТТЕРНОВ
  int p1 = (patternType * 3) % 40;
  int p2 = (patternType * 7) % 40;
  int p3 = (patternType * 13) % 40;
  
  float v1 = 0, v2 = 0, v3 = 0;
  float blend1 = randomScales[10];
  float blend2 = randomScales[11];
  float blend3 = 1.0 - blend1 - blend2;
  if(blend3 < 0) blend3 = 0.2;
  
  // 40 РАЗНЫХ БАЗОВЫХ ПАТТЕРНОВ
  switch(p1) {
    // Оригинальные паттерны
    case 0: v1 = sin(radius * 0.3 + sector + t); break;
    case 1: v1 = sin(angle * 8 + radius * 0.15 + t); break;
    case 2: v1 = sin(nx * 8 + t) * sin(ny * 8 + t * 0.7); break;
    case 3: v1 = sin(nx * 12) * sin(ny * 12) + sin(t) * 0.3; break;
    case 4: v1 = sin(angle * 10) * sin(radius * 0.4) + cos(angle * 6 + t); break;
    case 5: v1 = fmod(angle * 4 + radius * 0.15 + t, 2 * PI) / (2 * PI); break;
    case 6: v1 = sin(angle * 6) * cos(radius * 0.25) + sin(t * 0.5); break;
    case 7: v1 = sin(radius * 0.2 - t * 2) * cos(angle * 4 + t); break;
    
    // Новые волновые паттерны
    case 8: v1 = sin(nx * 20 + t) + cos(ny * 20 + t * 0.3); break;
    case 9: v1 = sin((nx + ny) * 15 + t) * cos((nx - ny) * 10); break;
    case 10: v1 = sin(nx * nx * 8 + t) * cos(ny * ny * 8); break;
    case 11: v1 = sin(nx * 30) * sin(ny * 30) * sin(t * 0.5); break;
    
    // Фракталоподобные
    case 12: v1 = sin(nx * 4) + sin(ny * 4) * 0.5 + sin((nx + ny) * 8) * 0.25; break;
    case 13: v1 = sin(nx * 16) * cos(ny * 16) + sin((nx + ny) * 32) * 0.3; break;
    case 14: v1 = fmod(nx * ny * 100 + t * 10, 1.0) * 2 - 1; break;
    
    // Геометрические
    case 15: v1 = (fmod(angle * 20, 1.0) > 0.5) ? 1.0 : -1.0; break;
    case 16: v1 = (fmod(radius * 2, 1.0) > 0.5) ? 0.8 : -0.8; break;
    case 17: v1 = sin(floor(nx * 10) + floor(ny * 10) + t); break;
    
    // Звездные/взрывные
    case 18: v1 = sin(radius * 10 - t * 3) / (radius * 2 + 0.1); break;
    case 19: v1 = cos(angle * 12 + radius * 5) * exp(-radius * 0.5); break;
    case 20: v1 = sin(radius * 15 - angle * 8 + t * 2); break;
    
    // Спиральные
    case 21: v1 = sin(angle * 5 + radius * 10 + t); break;
    case 22: v1 = cos(angle * 8 - radius * 8 + t * 1.5); break;
    case 23: v1 = sin(log(radius + 0.1) * 20 + angle * 10 + t); break;
    
    // Кристаллоподобные
    case 24: v1 = sin(nx * 24) * sin(ny * 24) + sin((nx + ny) * 12); break;
    case 25: v1 = cos(nx * 24 + t) + sin(ny * 24 - t); break;
    case 26: v1 = sin(nx * 36) * cos(ny * 36) * 0.5 + 0.5; break;
    
    // Хаотичные
    case 27: v1 = fmod(nx * ny * 50 + t * 5, 1.0); break;
    case 28: v1 = sin(nx * 40 + t) * sin(ny * 40 + t * 0.7) * sin((nx + ny) * 20); break;
    case 29: v1 = (sin(nx * 50) > 0) ? 0.7 : -0.7; break;
    
    // Модулированные
    case 30: v1 = sin(radius * 5 + t) * cos(angle * 15); break;
    case 31: v1 = sin(angle * 20) * (1 - radius * 0.8); break;
    case 32: v1 = sin(radius * 8 + angle * 8) * cos(t * 0.5); break;
    
    // Пульсирующие
    case 33: v1 = sin(radius * 4 - t * 2) * sin(angle * 8 + t); break;
    case 34: v1 = cos(radius * 3 + t) * cos(angle * 6 - t * 0.5); break;
    case 35: v1 = sin(radius * 6 + t * 3) * sin(angle * 12); break;
    
    // Радиальные градиенты
    case 36: v1 = 1.0 - radius / 80.0; break;
    case 37: v1 = radius / 80.0; break;
    case 38: v1 = (sin(radius * 0.5 + t) + 1) * 0.5; break;
    case 39: v1 = fmod(angle * 8 + radius * 0.2 + t, 2 * PI) / (2 * PI); break;
  }
  
  switch(p2) {
    case 0: v2 = cos(radius * 0.25 + sector * 0.5 - t); break;
    case 1: v2 = sin(angle * 12 + radius * 0.2 + t * 0.8); break;
    case 2: v2 = cos(nx * 12 - t) * cos(ny * 12 + t * 0.5); break;
    case 3: v2 = sin(nx * 8) * cos(ny * 8) + cos(t); break;
    case 4: v2 = sin(angle * 8 + radius * 0.6) * cos(angle * 4 - t); break;
    case 5: v2 = fmod(angle * 6 - radius * 0.1 - t, 2 * PI) / (2 * PI); break;
    case 6: v2 = cos(angle * 10) * sin(radius * 0.35) + cos(t * 0.7); break;
    case 7: v2 = cos(radius * 0.3 + t * 1.5) * sin(angle * 6 - t); break;
    case 8: v2 = sin((nx - ny) * 25 + t) * cos((nx + ny) * 15); break;
    case 9: v2 = sin(ny * 30 - t) + cos(nx * 30 + t * 0.4); break;
    case 10: v2 = sin(radius * 0.5) * cos(angle * 20) + sin(t); break;
    case 11: v2 = fmod(radius * 0.3 * angle * 10 + t, 1.0); break;
    case 12: v2 = sin(nx * 12) * sin(ny * 12) + sin((nx - ny) * 24); break;
    case 13: v2 = sin(nx * 20 + t) * 0.7 + sin(ny * 20 - t) * 0.3; break;
    case 14: v2 = sin(nx * ny * 40 + t * 2); break;
    case 15: v2 = (fmod(angle * 30, 1.0) > 0.3) ? 0.9 : -0.9; break;
    case 16: v2 = (fmod(radius * 5, 1.0) < 0.2) ? 1.0 : -0.5; break;
    case 17: v2 = sin(floor(nx * 15) * floor(ny * 15) + t * 2); break;
    case 18: v2 = cos(radius * 12 + t * 2) / (radius + 0.2); break;
    case 19: v2 = sin(angle * 15 - radius * 8 + t * 1.5); break;
    case 20: v2 = cos(radius * 20 - t * 3) * sin(angle * 10); break;
    case 21: v2 = sin(angle * 7 + radius * 12 - t); break;
    case 22: v2 = cos(angle * 9 - radius * 9 + t * 2); break;
    case 23: v2 = sin(log(radius + 0.2) * 30 + angle * 15); break;
    case 24: v2 = cos(nx * 30) * cos(ny * 30) + sin((nx - ny) * 20); break;
    case 25: v2 = sin(nx * 32 - t * 1.5) * cos(ny * 32 + t); break;
    case 26: v2 = sin(nx * 48) * sin(ny * 48) * 0.7; break;
    case 27: v2 = fmod(nx * nx * 80 + ny * ny * 80 + t * 8, 1.0); break;
    case 28: v2 = cos(nx * 60) * sin(ny * 60) * sin(t); break;
    case 29: v2 = (cos(nx * 70) > 0.5) ? 0.8 : -0.8; break;
    case 30: v2 = sin(radius * 7 - t * 1.5) * sin(angle * 20); break;
    case 31: v2 = cos(angle * 25) * (0.7 - radius * 0.6); break;
    case 32: v2 = sin(radius * 10 - angle * 12) * cos(t * 0.8); break;
    case 33: v2 = sin(radius * 5 + t * 2.5) * cos(angle * 10 - t); break;
    case 34: v2 = cos(radius * 4 - t * 1.8) * sin(angle * 8 + t * 0.7); break;
    case 35: v2 = sin(radius * 8 - t * 4) * cos(angle * 16); break;
    case 36: v2 = 0.8 - radius / 100.0; break;
    case 37: v2 = radius / 60.0; break;
    case 38: v2 = (cos(radius * 0.8 - t) + 1) * 0.5; break;
    case 39: v2 = fmod(angle * 12 - radius * 0.3 + t * 2, 2 * PI) / (2 * PI); break;
  }
  
  switch(p3) {
    case 0: v3 = tan(radius * 0.1 + t) * 0.1; break;
    case 1: v3 = sin(angle * 20 + radius * 0.5) * 0.5; break;
    case 2: v3 = cos((nx + ny) * 20 + t * 0.6); break;
    case 3: v3 = sin(nx * 40) * 0.3 + cos(ny * 40) * 0.3; break;
    case 4: v3 = sin(angle * 25) * cos(radius * 0.8) * 0.7; break;
    case 5: v3 = fmod(angle * 10 + t * 3, 1.0); break;
    case 6: v3 = sin(angle * 15) * sin(radius * 0.9) + cos(t); break;
    case 7: v3 = sin(radius * 0.5 - t) * cos(angle * 12 + t * 0.5); break;
    case 8: v3 = sin((nx * 2 + ny) * 40 + t) * 0.4; break;
    case 9: v3 = sin(nx * 50 - t * 0.8) * sin(ny * 50 + t * 0.3); break;
    case 10: v3 = sin(radius * 0.8) * cos(angle * 30) * 0.6; break;
    case 11: v3 = fmod(radius * angle * 200 + t * 5, 1.0) * 2 - 1; break;
    case 12: v3 = sin(nx * 25) * 0.5 + cos(ny * 25) * 0.5; break;
    case 13: v3 = sin((nx + ny) * 35 + t) * 0.6; break;
    case 14: v3 = sin(nx * ny * 60 + t * 3) * 0.4; break;
    case 15: v3 = (fmod(angle * 40, 1.0) > 0.7) ? 0.7 : -0.4; break;
    case 16: v3 = (fmod(radius * 8, 1.0) < 0.1) ? 0.9 : -0.3; break;
    case 17: v3 = cos(floor(nx * 20) + floor(ny * 20) + t); break;
    case 18: v3 = sin(radius * 18 - t * 4) * 0.5; break;
    case 19: v3 = cos(angle * 20 - radius * 12) * 0.7; break;
    case 20: v3 = sin(radius * 25 + t * 2) * cos(angle * 15); break;
    case 21: v3 = sin(angle * 12 + radius * 18 - t * 1.5) * 0.6; break;
    case 22: v3 = cos(angle * 14 - radius * 14 + t) * 0.7; break;
    case 23: v3 = sin(log(radius + 0.3) * 40 + angle * 20) * 0.5; break;
    case 24: v3 = sin(nx * 40) * sin(ny * 40) * 0.5; break;
    case 25: v3 = cos(nx * 45 - t) * 0.6; break;
    case 26: v3 = sin(nx * 60) * cos(ny * 60) * 0.5; break;
    case 27: v3 = fmod(nx * ny * 100 + t * 10, 1.0); break;
    case 28: v3 = sin(nx * 80) * 0.3 + cos(ny * 80) * 0.3; break;
    case 29: v3 = (sin(nx * 90) > 0.7) ? 0.6 : -0.5; break;
    case 30: v3 = sin(radius * 12 - t) * 0.5; break;
    case 31: v3 = cos(angle * 35) * (0.5 - radius * 0.4); break;
    case 32: v3 = sin(radius * 15 + angle * 18) * 0.5; break;
    case 33: v3 = sin(radius * 7 + t * 3) * cos(angle * 14 - t * 0.8); break;
    case 34: v3 = cos(radius * 6 - t * 2.2) * 0.7; break;
    case 35: v3 = sin(radius * 12 - t * 5) * sin(angle * 24) * 0.6; break;
    case 36: v3 = 0.5 - radius / 160.0; break;
    case 37: v3 = radius / 100.0; break;
    case 38: v3 = (sin(radius * 1.2 + t * 2) + 1) * 0.4; break;
    case 39: v3 = fmod(angle * 16 + radius * 0.5 + t * 3, 2 * PI) / (2 * PI); break;
  }
  
  // РАЗНЫЕ СПОСОБЫ СМЕШИВАНИЯ
  float result = 0;
  int blendMode = randomBlendModes[patternType % 50];
  
  switch(blendMode) {
    case 0: result = v1 * blend1 + v2 * blend2 + v3 * blend3; break;
    case 1: result = (v1 + v2 + v3) / 3.0; break;
    case 2: result = max(v1, max(v2, v3)); break;
    case 3: result = min(v1, min(v2, v3)); break;
    case 4: result = v1 * v2 * v3; break;
    case 5: result = sin(v1 * PI) * cos(v2 * PI) + v3 * 0.5; break;
    case 6: result = (v1 > 0 ? v1 : v2) * 0.7 + v3 * 0.3; break;
    case 7: result = fmod(v1 * 10 + v2 * 5 + v3 * 2, 1.0); break;
  }
  
  // ИНВЕРТИРУЕМ ИНОГДА
  if(randomScales[12] > 1.5) result = -result;
  
  int colorIndex = (int)((result * 0.5 + 0.5) * PALETTE_SIZE);
  if(colorIndex < 0) colorIndex = 0;
  if(colorIndex >= PALETTE_SIZE) colorIndex = PALETTE_SIZE - 1;
  
  return palette[colorIndex];
}

void setup() {
  Serial.begin(115200);
  pinMode(TFT_BL_PIN, OUTPUT);
  analogWrite(TFT_BL_PIN, 255);
  tft.init();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);
  randomSeed(analogRead(0));
  generateRandomParameters();
  Serial.println("Дисплей инициализирован");
  delay(1000);
}

void loop() {
  static int patternType = 0;
  static unsigned long lastTime = 0;
  static unsigned long lastRandomChange = 0;
  
  if (millis() - lastTime < 25) {
    return;
  }
  lastTime = millis();
  
  tft.fillScreen(TFT_BLACK);
  tft.startWrite();
  
  // РАЗНОЕ КОЛИЧЕСТВО СЕКТОРОВ ДЛЯ РАЗНООБРАЗИЯ
  int symmetry = randomSymmetry[patternType % 50];
  float sectorStep = 2 * PI / symmetry;
  
  for (float sector = 0.0; sector < 2 * PI; sector += sectorStep) {
    drawGeneratedSector(sector + randomOffsets[4] * 0.2, patternType);
  }
  
  tft.endWrite();
  animationTime += randomSpeeds[1]; // РАЗНАЯ СКОРОСТЬ АНИМАЦИИ
  
  // МЕНЯЕМ ПАТТЕРН БЫСТРО И СЛУЧАЙНО
  static unsigned long patternChangeTime = 0;
  if (millis() - patternChangeTime > 1200) { // Каждые 1.2 секунды
    patternChangeTime = millis();
    patternType = random(0, 200); // ОГРОМНЫЙ ВЫБОР ПАТТЕРНОВ
    patternCounter++;
    
    // ПОЛНОСТЬЮ МЕНЯЕМ ПАРАМЕТРЫ КАЖДЫЙ РАЗ
    if(patternCounter % 2 == 0) {
      generateRandomParameters();
    }
    
    // БЫСТРОЕ МИГАНИЕ
    for (int i = 255; i >= 80; i -= 25) {
      analogWrite(TFT_BL_PIN, i);
      delay(3);
    }
    for (int i = 80; i <= 255; i += 25) {
      analogWrite(TFT_BL_PIN, i);
      delay(3);
    }
  }
  
  // ПОСТОЯННЫЕ СЛУЧАЙНЫЕ ИЗМЕНЕНИЯ
  if (millis() - lastRandomChange > 300) {
    lastRandomChange = millis();
    if(random(0, 100) < 40) {
      int idx = random(0, 20);
      randomOffsets[idx] = random(0, 628) / 100.0;
      randomSpeeds[idx] = random(1, 50) / 100.0;
      randomScales[idx] = random(1, 30) / 10.0;
    }
  }
}

void drawGeneratedSector(float S, int patternType) {
  int symmetry = randomSymmetry[patternType % 50];
  float step = PI / Z;
  
  for (float f1 = 0.0; f1 <= PI / 6.0; f1 += step) {
    for (int r1 = 0; r1 <= 80; r1 += 1) {
      uint16_t pixelColor = generatePixelValue(f1, r1, S, patternType);
      float symmetryOffset = randomOffsets[5] * 0.2;
      
      for (int i = 0; i < symmetry; i++) {
        float angle = (2 * PI / symmetry) * i + symmetryOffset;
        
        int x1 = CENTER_X + cos(f1 + angle) * r1;
        int y1 = CENTER_Y + sin(f1 + angle) * r1;
        if (x1 >= 0 && x1 < 128 && y1 >= 0 && y1 < 160) {
          tft.drawPixel(x1, y1, pixelColor);
        }
        
        int x2 = CENTER_X + cos(2 * PI - f1 + angle) * r1;
        int y2 = CENTER_Y + sin(2 * PI - f1 + angle) * r1;
        if (x2 >= 0 && x2 < 128 && y2 >= 0 && y2 < 160) {
          tft.drawPixel(x2, y2, pixelColor);
        }
      }
    }
  }
}

void drawSimplePattern(int patternType) {
  tft.startWrite();
  for (int x = 0; x < 128; x++) {
    for (int y = 0; y < 160; y++) {
      float dx = x - CENTER_X;
      float dy = y - CENTER_Y;
      float radius = sqrt(dx*dx + dy*dy);
      float angle = atan2(dy, dx);
      if (radius <= 80) {
        uint16_t color = generatePixelValue(angle, radius, randomOffsets[6], patternType);
        tft.drawPixel(x, y, color);
      }
    }
  }
  tft.endWrite();
}

но делать фото что бы показать я не осилю)))

Вот подумал, даже не сектор, а хотя бы слабое подобие таких картинок



Да, переделал, но лучше

VID_20260211_200512
Загрузка: VID_20260211_200645.gif…
Узор как то топчется на месте :slight_smile:

#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;
const float Z = 200.0;  // Уменьшено для производительности

// Параметры для генерации узоров
float noiseScale = 0.05;
float animationTime = 0.0;  // Переименовано с time

// Цветовая палитра (16-bit цвета)
uint16_t palette[] = {
  GC9A01A_GREEN, GC9A01A_BLUE,
 GC9A01A_YELLOW,GC9A01A_MAGENTA, GC9A01A_CYAN,
  GC9A01A_WHITE, GC9A01A_ORANGE, GC9A01A_PURPLE,
  GC9A01A_PINK, GC9A01A_LIGHTGREY,GC9A01A_DARKGREY,
 GC9A01A_MAROON, GC9A01A_NAVY, GC9A01A_DARKGREEN
};
const int PALETTE_SIZE = 15;


void setup() {
 // Инициализация генератора случайных чисел
  randomSeed(analogRead(32));
  tft.begin();
  tft.fillScreen(GC9A01A_BLACK);
  // tft.cp437(true);
  tft.setRotation(2);
}

void loop() {
  static int patternType = 0;
  static unsigned long lastTime = 0;
  
  // Ограничение FPS
  if (millis() - lastTime < 50) {
    return;
  }
  lastTime = millis();
  
  // Очистка экрана
  tft.fillScreen(GC9A01A_BLACK);
  
  // Оптимизация: начинаем пакетную запись
 // tft.startWrite();
  
  // Генерация и отрисовка всех секторов для текущего паттерна
  for (float sector = 0.0; sector < 2 * PI - PI / 6.0 ; sector += PI / 12) {
    drawGeneratedSector(sector, patternType);
    
  }
  
  // Завершаем пакетную запись
  //tft.endWrite();
  
  // Увеличиваем время анимации
  animationTime += 0.1;
  
  // Переход к следующему паттерну каждые 5 секунд
  static unsigned long patternChangeTime = 0;
  if (millis() - patternChangeTime > 5000) {
    patternChangeTime = millis();
    patternType = (patternType + 1) % 8;
    
    
    
  }
}
//////////////////////////////////////////////////
// Генерация значения пикселя на основе позиции в секторе
uint16_t generatePixelValue(float angle, float radius, float sector, int patternType) {
  // Нормализованные координаты от 0 до 1
  float nx = cos(angle + sector) * radius / 120.0;
  float ny = sin(angle + sector) * radius / 120.0;
  
  // Используем animationTime вместо time
  float t = animationTime * 0.1;
  
  switch(patternType % 8) {
    case 0: // Концентрические круги
      return palette[(int)((sin(radius * 0.3 + sector + t) * 0.5 + 0.5) * PALETTE_SIZE)];
    
    case 1: // Спирали ///
      {
        float spiral = sin(angle * 8 + radius * 0.15 + t);
        int colorIndex = (int)((spiral * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 2: // Волны ///
      {
        float wave = sin(nx * 8 + t) * sin(ny * 8 + t * 0.7);
        int colorIndex = (int)((wave * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 3: // Шумоподобный узор ///
      {
        float noise = 0;
        for(int i = 0; i < 2; i++) {
          float freq = pow(2, i);
          noise += sin((nx * freq + t) * 8) * sin((ny * freq + t * 0.5) * 8) / freq;
        }
        int colorIndex = (int)((noise * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 4: // Мандала
      {
        float mandala = sin(angle * 10) * sin(radius * 0.4) + cos(angle * 6 + t);
        int colorIndex = (int)((mandala * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 5: // Радиальный градиент
      {
        float grad = fmod(angle * 4 + radius * 0.15 + t, 2 * PI) / (2 * PI);
        int colorIndex = (int)(grad * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 6: // Геометрический паттерн
      {
        float geo = sin(angle * 6) * cos(radius * 0.25) + sin(t * 0.5);
        int colorIndex = (int)((geo * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    case 7: // Пульсирующие кольца
      {
        float pulse = sin(radius * 0.2 - t * 2) * cos(angle * 4 + t);
        int colorIndex = (int)((pulse * 0.5 + 0.5) * PALETTE_SIZE);
        return palette[colorIndex % PALETTE_SIZE];
      }
    
    default:
      return GC9A01A_WHITE;
  }
}

//////////////////////////////////////////////////
// Функция вывода сгенерированных секторов
void drawGeneratedSector(float S, int patternType) {
  // Уменьшаем плотность отрисовки для производительности
  for (float f1 = 0.0; f1 <= PI / 6.0; f1 += PI / Z) {
    for (int r1 = 0; r1 <= 120 ; r1 += 1) {
      // Генерируем цвет для базового пикселя
      uint16_t pixelColor = generatePixelValue(f1, r1, S, patternType);
      
      // Отрисовка 12 симметричных секторов
      for (float i = 0.01; i <= 2 * PI; i += PI / 6.0) {
        // Первый симметричный сектор
        int x1 = CENTER_X + cos(f1 + i) * r1;
        int y1 = CENTER_Y + sin(f1 + i) * r1;
        
        // Проверка границ экрана
        if (x1 >= 0 && x1 < 240 && y1 >= 0 && y1 < 240) {
          tft.drawPixel(x1, y1, pixelColor);
        }
        
        // Второй симметричный сектор (зеркальный)
        int x2 = CENTER_X + cos(2 * PI - f1 + i) * r1;
        int y2 = CENTER_Y + sin(2 * PI - f1 + i) * r1;
        
        if (x2 >= 0 && x2 < 240 && y2 >= 0 && y2 < 240) {
          tft.drawPixel(x2, y2, pixelColor);
        }
      }
    }
  }
}

// Упрощенная функция для быстрой отрисовки
void drawSimplePattern(int patternType) {
 // tft.startWrite();
  
  for (int x = 0; x < 240; x++) {
    for (int y = 0; y < 240; y++) {
      // Преобразуем координаты в полярные
      float dx = x - CENTER_X;
      float dy = y - CENTER_Y;
      float radius = sqrt(dx*dx + dy*dy);
      float angle = atan2(dy, dx);
      
      if (radius <= 120) {
        // Простой расчет цвета
        uint16_t color = generatePixelValue(angle, radius, 0, patternType);
        tft.drawPixel(x, y, color);
      }
    }
  }
  
 // tft.endWrite();
}

VID_20260211_200645

// ЭТО КОНТРОЛИРУЕТ СКОРОСТЬ АНИМАЦИИ!
animationTime += 0.1;  // ← Чем БОЛЬШЕ число, тем БЫСТРЕЕ анимация
                       //   Чем МЕНЬШЕ число, тем МЕДЛЕННЕЕ

// Например:
animationTime += 0.05;  // В 2 раза медленнее
animationTime += 0.2;   // В 2 раза быстрее
animationTime += 0.5;   // В 5 раз быстрее
animationTime += 1.0;   // В 10 раз быстрее!
// Чем БОЛЬШЕ множитель, тем БЫСТРЕЕ:
float t = animationTime * 0.2;   // В 2 раза быстрее
float t = animationTime * 0.5;   // В 5 раз быстрее
float t = animationTime * 1.0;   // В 10 раз быстрее

а тут даже подписано)) 
 // Переход к следующему паттерну каждые 5 секунд
  static unsigned long patternChangeTime = 0;
  if (millis() - patternChangeTime > 5000) {
    patternChangeTime = millis();

в самих case тоже время стоит * 0.7

const float Z = 200.0;  // Уменьшено для производительности

а вот это наверное можно не трогать

//tft.endWrite();
// tft.endWrite();
уверенны что надо отключить ?

Не в скорости дело, нет динамики в узоре, генерация сектора однообразна и существенно уступает картинке.
… хочу попробовать типа таких



Тут главное, что б в картинке не было симметрий, разные размеры, формы и цвета элементов, тогда генерация с картинки будет разнообразной.

С ней экран чёрный :slight_smile:

… надо функция генерации массива картинки 240х240 в “оперативку”.

То есть картинка у нас хранится в виде текста?

Диаграмма Вороного. Тыц.

По ссылкам интересные примеры других структур.

Даны алгоритмы по генерации.

Для каждого можно найти реализацию. Вобщем, если интересно - делается. У нас в институте раскидывали типа таких алгоритмов как лотерею, кому что достанется. Пыхтели, реализовывали, тогда интернетов особо не было, только описания.

Для затравки, на тачике сделать: тыц

да, в виде координат, вот тут сделал координаты https://alexgyver.github.io/MagicGyver/

вот этим вывожу на дисплей, правда я зарекся верить что все просто на ардуино будет))) из 10 текстовых документов брал данные для программы, но не знаю что будет когда их будут сотни, и документы будут больше

ой, там еще и не факт что памяти хватит… если еще 2 буферизация… экрана еще такого нет, это надо собирать и смотреть))) так не скажу как вывести…

но картинки грузят что бы получить красивую снежинку и выводить анимацию)))
если не нужна красивая снежинка а анимация рисунков, тогда создавать стартовый рисунок мы можем любой, и фото не обязательно…

Тут явно нужен ИИ.

Кстати увеличил вариативность резки базового сектора из картинки


Теперь сектора можно чередовать не только по кругу, но и смещением по радиусу.
Одна картинка в примере ниже даёт около 320 узоров вместо 32.

#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>
#include <SPI.h>
#include "ris_1.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;
const float Z = 300.0; //от 100.0 до 1000.0 регулировка качества отрисовки пикселей с пропусками и без них
const struct {
  const unsigned char *bitmap;
}
uzor_[] = {ris_1, ris_2, ris_3, ris_4, ris_5, ris_6, ris_7}; // картинки


void setup() {
  // Инициализация генератора случайных чисел
  randomSeed(analogRead(32));
  tft.begin();
  tft.fillScreen(GC9A01A_BLACK);
  // tft.cp437(true);
  tft.setRotation(2);

}

void loop() {
  for (byte ris = 0; ris < 7 ; ris++) {
    for (float f = 0.0; f < 2 * PI - PI / 6.0 ; f += PI / 16) {
      for (int dr = 0; dr < 120; dr += 10) {
        draw_RisSektor(f, dr, uzor_[ris].bitmap );
        delay(500);
      }
    }
  }
}
//////////////////////////////////////
//функция вывода 12 отсимметриченных секторов узора по базовому сектору картинки
void draw_RisSektor(float S, int dR, const uint8_t *bitmap) {
  for (float f1 = 0.0; f1 <= PI / 6.0; f1 += PI / Z) {
    for (int r1 = 0; r1 <= 120 ; r1 += 1) {
      int dX; int dY;
      if ( cos(f1 + S) >= 0) {
        dX = -dR;
      } else {
        dX = dR;
      }
      if ( sin(f1 + S) >= 0) {
        dY = -dR;
      } else {
        dY = dR;
      }

      int x = CENTER_X + cos(f1 + S) * r1 + dX ;//координаты данных цвета пикселя в массиве
      int y = CENTER_Y + sin(f1 + S) * r1 + dY ;

      for (float i = 0.01; i <= 2 * PI; i += PI / 3.0) {
        int x1 = CENTER_X + cos(f1 + i) * r1;// координаты точки в базовом секторе
        int y1 = CENTER_Y + sin(f1 + i) * r1;
        tft.drawPixel(x1, y1, 256 * bitmap[2 * x + 1 + y * 2 * 240] + bitmap[2 * x + y * 2 * 240]);
        int x2 = CENTER_X + cos(2 * PI - f1 + i) * r1;//координаты точки в базовом отзеркаленном секторе
        int y2 = CENTER_Y + sin(2 * PI - f1 + i) * r1;
        tft.drawPixel(x2, y2, 256 * bitmap[2 * x + 1 + y * 2 * 240] + bitmap[2 * x + y * 2 * 240]);

      }
    }
  }
}
//////////////////////////////////////


Да, рациональней генерить сектор. Он имеет размер применительно к моему дисплею 120х60 пикселей.

Размер имеет значение :slight_smile:

Блин, как же мы в институте одним только ЕИ обходились? 8))))

имеет по большей части из за того что изображение не помещается даже маленькое, но это на моем 128 на 160

Это было давно.
…пока пишу промпт :slight_smile:

Напиши скетч для круглого дисплея на чипе GC9A01 и платы ESP32. Скетч выводит на экран случайную диаграмму Вороного по алгоритму Форчуна. Закрашивает локусы разными цветами. Число точек, для которых строится локус может меняться.

А вообще как сказал классик нашей форумной современности:

…какая глубокая мысль, пронизывающая всю историю нашей страны.
VID_20260213_151756
…может и нет смысла генерации сектора, картинки выбранные возможно лучше, в анимации интересен именно переход от одного узора к другому. Получается 7 картинок Х 300 вариаций = 2100. А способов псевдослучайного перехода с одного узора на другой не счесть…надо у ИИ спросить.

void loop() {
  //
  byte ris = random(0, 7);
  float f = (random(0, 33) / 32.0) * (2 * PI - PI / 6.0);
  int dr = random(0, 120);
  draw_RisSektor(f, dr, uzor_[ris].bitmap );
  delay(500);
  /*
    for (byte ris = 0; ris < 2 ; ris++) {
    for (float f = 0.0; f < 2 * PI - PI / 6.0 ; f += PI / 16) {
      for (int dr = 0; dr < 120; dr += 10) {
        draw_RisSektor(f, dr, uzor_[ris].bitmap );
        delay(500);
      }
    }
    }
  */
}

Сделал диаграмму Вороного в пределах сектора. Вариант генерации без картинок.

#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;
const float Z = 300.0; //от 100.0 до 1000.0 регулировка качества отрисовки пикселей с пропусками и без них
struct Point {
  float x, y;
  uint16_t color;
};
const int NUM_POINTS = 40; // Количество точек для диаграммы Вороного
Point points[NUM_POINTS];


void setup() {
  // Инициализация генератора случайных чисел
  randomSeed(analogRead(32));
  tft.begin();
  tft.fillScreen(GC9A01A_BLACK);
  // tft.cp437(true);
  tft.setRotation(2);

}

void loop() {

  draw_RisSektor( );
  delay(500);

}
//////////////////////////////////////
//функция вычисления расстояния между двумя точками
float dist(float x1, float y1, float x2, float y2) {
  return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
//////////////////////////////////////
// функция генерации точек (сайтов)для локусов диаграммы Вороного
void ran_Sait() {
  for (int i = 0; i < NUM_POINTS; i++) {
    points[i].x = random(CENTER_X, CENTER_X + 120 );
    points[i].y = random(CENTER_Y, CENTER_Y + 60);
    points[i].color = tft.color565(random(256), random(256), random(256));
  }
}
//////////////////////////////////////
//функция вывода 12 отсимметриченных секторов узора по базовому сектору картинки
void draw_RisSektor() {
  for (float f1 = 0.0; f1 <= PI / 6.0; f1 += PI / Z) {
    for (int r1 = 0; r1 <= 120 ; r1 += 1) {
      int x = CENTER_X + cos(f1) * r1;
      int y = CENTER_Y + sin(f1) * r1;
      int closestPoint = 0;
      float minDist = dist(x, y, points[0].x, points[0].y);

      for (int i = 1; i < NUM_POINTS; i++) {
        float d = dist(x, y, points[i].x, points[i].y);
        if (d < minDist) {
          minDist = d;
          closestPoint = i;
        }
      }

      for (float i = 0.01; i <= 2 * PI; i += PI / 3.0) {
        int x1 = CENTER_X + cos(f1 + i) * r1;
        int y1 = CENTER_Y + sin(f1 + i) * r1;
        tft.drawPixel(x1, y1, points[closestPoint].color);
        int x2 = CENTER_X + cos(2 * PI - f1 + i) * r1;
        int y2 = CENTER_Y + sin(2 * PI - f1 + i) * r1;
        tft.drawPixel(x2, y2, points[closestPoint].color );

      }
    }
  }
  ran_Sait();
}
//////////////////////////////////////