/* File: Voronoi diagram - animated.
By: Andrew Tuline
Date: June 2021
Slowest implementation in the world of a Voronoi diagram for an Arduino UNO/Nano and the FastLED display library.
Unfortunately, it's not cool looking like the routines made by Stepko or ldirko.
Reference:
https://en.wikipedia.org/wiki/Voronoi_diagram
Caveat: There are probably still one or more bugs in this, but it was a fun exercise.
*/
#include <FastLED.h>
#define matrixWidth 16
#define matrixHeight 16
#define matrixSerpentine true
#define LED_DT 12
#define LED_TYPE WS2812
#define NUM_LEDS matrixWidth*matrixHeight
uint8_t max_bright = 255;
struct CRGB leds[NUM_LEDS];
const uint8_t maxStars = matrixWidth * matrixHeight / 64;
typedef struct star {
uint8_t xStart;
uint8_t yStart;
uint8_t x;
uint8_t y;
uint8_t colr;
} Star;
Star stars[maxStars];
void setup() {
Serial.begin(115200);
LEDS.addLeds<WS2812, LED_DT, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(max_bright);
for (int i = 0; i < maxStars; i++) {
stars[i].xStart = random8(matrixWidth) / 2;
stars[i].yStart = random8(matrixHeight) / 2;
stars[i].colr = random8();
}
} // setup()
void loop() {
voronoi();
Serial.print(LEDS.getFPS());
Serial.println(" FPS.");
FastLED.show();
} // loop()
void voronoi() {
random16_set_seed(4832); // I use this to make repeating random numbers for the phase shift. Think of it as a 0 byte random() array.
for (int i = 0; i < maxStars; i++) {
stars[i].x = stars[i].xStart + beatsin8(7, 0, matrixWidth, 0, random8()) / 2;
stars[i].y = stars[i].yStart + beatsin8(8, 0, matrixHeight, 0, random8()) / 2;
}
for (int x = 0; x < matrixWidth; x++) {
for (int y = 0; y < matrixHeight; y++) {
float dist = 254;
uint8_t scolr = 0;
for (int star = 0; star < maxStars; star++) {
// Get length to each star to the current led.
float thisDist = sqrt(abs(stars[star].x * stars[star].x - x * x) + abs(stars[star].y * stars[star].y - y * y));
// For the closest star, get current x, y and colour of that star's area.
if (thisDist < dist) {
dist = thisDist;
scolr = stars[star].colr;
} // if
} // for star
leds[XY(x, y)] = CHSV(scolr, 255, 128 / (dist / 4));
} // for y
} // for x
for (int star = 0; star < maxStars; star++) leds[XY(stars[star].x, stars[star].y)] = CHSV(0, 0, 255);
} // voronoi()
uint16_t XY( uint8_t x, uint8_t y) { // Returns with the wiring layout.
uint16_t i;
if ( matrixSerpentine == false) {
i = (y * matrixWidth) + x;
}
if ( matrixSerpentine == true) {
if ( y & 0x01) {
uint8_t reverseX = (matrixWidth - 1) - x;
i = (y * matrixWidth) + reverseX;
} else {
i = (y * matrixWidth) + x;
}
}
return i;
} // XY()