Skip to content

Instantly share code, notes, and snippets.

@adammhaile
Last active November 27, 2020 03:11
Show Gist options
  • Save adammhaile/a769f3ff87ff61f22ace to your computer and use it in GitHub Desktop.
Save adammhaile/a769f3ff87ff61f22ace to your computer and use it in GitHub Desktop.
Examples of using angle and radius to select pixels on a circular pixel layout using FastLED
#include "FastLED.h"
#define NUM_LEDS 255
#define DATA_PIN SPI_DATA
#define CLOCK_PIN SPI_CLOCK
// Define the array of leds
CRGB leds[NUM_LEDS];
#define ringCount 10 //Total Number of Rings. AdaFruit Disk has 10
//Map rings on disk to indicies.
//This is where all the magic happens.
//Each represents one of the concentric rings.
uint8_t rings[ringCount][2] = {
{254,254}, //0 Center Point
{248,253}, //1
{236,247}, //2
{216,235}, //3
{192,215}, //4
{164,191}, //5
{132,163}, //6
{92,131}, //7
{48,91}, //8
{0,47}, //9 Outter Ring
};
//For convenience, last ring index
uint8_t lastRing = ringCount - 1;
//Arrays containing degrees between each pixel for each ring.
//This is to speed up later calculations by doing these ahead of time.
//I've given everything with the option of using 360 degres per cirlce
//or 256. The latter fits nicer into a single byte and *should* be a bit
//faster since it's only doing single byte math and not having to deal with
//negative angles since uint8_t already rolls around to a positive value.
//In the 256 degree per circle methods, 64 is equivalent to 90, 128 to 180,
//and 192 to 270
float * ringSteps360;
float * ringSteps256;
//360 Degree Helper function to map angle and ring index to pixel
uint16_t angleToPixel360(int16_t angle, uint8_t ring)
{
if(ring >= ringCount) return 0;
angle = angle%360;
if(angle < 0) angle = 360 + angle;
return rings[ring][0] + int(angle/ringSteps360[ring]);
}
//256 Degree Helper function to map angle and ring index to pixel
uint16_t angleToPixel256(uint8_t angle, uint8_t ring)
{
if(ring >= ringCount) return 0;
return rings[ring][0] + int(angle/ringSteps256[ring]);
}
//Fill in the ringSteps arrays for later use.
inline void setupRings()
{
ringSteps360 = (float*)malloc(ringCount * sizeof(float));
uint8_t count = 0;
for(int r=0; r<ringCount; r++)
{
count = (rings[r][1] - rings[r][0] + 1);
ringSteps360[r] = (360.0/float(count));
}
ringSteps256 = (float*)malloc(ringCount * sizeof(float));
count = 0;
for(int r=0; r<ringCount; r++)
{
count = (rings[r][1] - rings[r][0] + 1);
ringSteps256[r] = (256.0/float(count));
}
}
//360 Degree helper to set a pixel, given angle and ring index
void setPixel360(int16_t angle, uint8_t ring, CRGB color)
{
uint16_t pixel = angleToPixel360(angle, ring);
leds[pixel] = color;
}
//256 Degree helper to set a pixel, given angle and ring index
void setPixel256(uint8_t angle, uint8_t ring, CRGB color)
{
uint16_t pixel = angleToPixel256(angle, ring);
leds[pixel] = color;
}
//360 Degree function to draw a line along a given angle from one ring to another
void drawRadius360(int16_t angle, CRGB color, uint8_t startRing, uint8_t endRing)
{
if(startRing > lastRing) startRing = 0;
if(endRing > lastRing) endRing = lastRing;
for(uint8_t r=startRing; r<=endRing; r++)
{
setPixel360(angle, r, color);
}
}
//256 Degree function to draw a line along a given angle from one ring to another
void drawRadius256(uint8_t angle, CRGB color, uint8_t startRing, uint8_t endRing)
{
if(startRing > lastRing) startRing = 0;
if(endRing > lastRing) endRing = lastRing;
for(uint8_t r=startRing; r<=endRing; r++)
{
setPixel256(angle, r, color);
}
}
//360 Degree function to fill a ring from one angle to another (draw an arc)
void fillRing360(uint8_t ring, CRGB color, int16_t startAngle, int16_t endAngle)
{
uint8_t start = angleToPixel360(startAngle, ring);
uint8_t end = angleToPixel360(endAngle, ring);
if(start > end)
{
for(int i=start; i<=rings[ring][1]; i++)
{
leds[i] = color;
}
for(int i=rings[ring][0]; i<=end; i++)
{
leds[i] = color;
}
}
else if(start == end)
{
for(int i=rings[ring][0]; i<=rings[ring][1]; i++)
{
leds[i] = color;
}
}
else
{
for(int i=start; i<=end; i++)
{
leds[i] = color;
}
}
}
//256 Degree function to fill a ring from one angle to another (draw an arc)
void fillRing256(uint8_t ring, CRGB color, uint8_t startAngle, uint8_t endAngle)
{
uint8_t start = angleToPixel256(startAngle, ring);
uint8_t end = angleToPixel256(endAngle, ring);
if(start > end)
{
for(int i=start; i<=rings[ring][1]; i++)
{
leds[i] = color;
}
for(int i=rings[ring][0]; i<=end; i++)
{
leds[i] = color;
}
}
else if(start == end)
{
for(int i=rings[ring][0]; i<=rings[ring][1]; i++)
{
leds[i] = color;
}
}
else
{
for(int i=start; i<=end; i++)
{
leds[i] = color;
}
}
}
void setup() {
setupRings();
Serial.begin(115200);
LEDS.addLeds<APA102,DATA_PIN,CLOCK_PIN,BGR>(leds,NUM_LEDS);
LEDS.setBrightness(64);
}
uint16_t pixel = 0;
uint8_t angle256 = 0;
void loop() {
//Chase a single pixel around the outer ring
for(int angle360 = 0; angle360 < 360; angle360++)
{
FastLED.clear();
setPixel360(angle360, lastRing, CRGB::Red);
FastLED.show();
}
//Chase a single pixel around the outer ring using 256 degrees per circle.
//Note that this will appear faster because there are less steps in the circle.
angle256 = 0;
while(true)
{
FastLED.clear();
setPixel256(angle256, lastRing, CRGB::Green);
FastLED.show();
angle256++;
if(angle256 == 0) break;
}
//Chase radius line using 360 degrees per circle
for(int angle360 = 0; angle360 < 360; angle360++)
{
FastLED.clear();
drawRadius360(angle360, CRGB::Blue, 0, lastRing);
FastLED.show();
}
//Chase radius line using 256 degrees per circle
angle256 = 0;
while(true)
{
FastLED.clear();
drawRadius256(angle256, CRGB::Purple, 0, lastRing);
FastLED.show();
angle256++;
if(angle256 == 0) break;
}
//Draw a half circle (180 degree) rainbow using 360 degrees per circle
for(int angle360 = 0; angle360 < 360; angle360++)
{
FastLED.clear();
fillRing360(9, CRGB::Red, angle360 - 90, angle360 + 90);
fillRing360(8, CRGB::Orange, angle360 - 90, angle360 + 90);
fillRing360(7, CRGB::Yellow, angle360 - 90, angle360 + 90);
fillRing360(6, CRGB::Green, angle360 - 90, angle360 + 90);
fillRing360(5, CRGB::Blue, angle360 - 90, angle360 + 90);
fillRing360(4, CRGB::Purple, angle360 - 90, angle360 + 90);
FastLED.show();
}
//Draw a half circle (128 degree) rainbow using 256 degrees per circle
angle256 = 0;
while(true)
{
FastLED.clear();
fillRing256(9, CRGB::Purple, angle256 - 64, angle256 + 64);
fillRing256(8, CRGB::Blue, angle256 - 64, angle256 + 64);
fillRing256(7, CRGB::Green, angle256 - 64, angle256 + 64);
fillRing256(6, CRGB::Yellow, angle256 - 64, angle256 + 64);
fillRing256(5, CRGB::Orange, angle256 - 64, angle256 + 64);
fillRing256(4, CRGB::Red, angle256 - 64, angle256 + 64);
FastLED.show();
angle256++;
if(angle256 == 0) break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment