Last active
November 27, 2020 03:11
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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