-
Notifications
You must be signed in to change notification settings - Fork 0
/
NeoPixelCircularDisplay.h
173 lines (153 loc) · 4.79 KB
/
NeoPixelCircularDisplay.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#ifndef NEOPIXELCIRCULARDISPLAY_H
#define NEOPIXELCIRCULARDISPLAY_H
#include "ExternalLibsInc.h"
#include "Vect3d.h"
#include "AbstractLog.h"
namespace Tinker{
/**********************************************************************
* NeoPixelCircularDisplay - Circular display for Adafruit Pixel Ring
**********************************************************************/
template <uint16_t NPXL = 16>
class NeoPixelCircularDisplay{
public:
typedef Vect3d<float> fp_color_type;
typedef Vect3d<uint8_t> color_type;
public:
NeoPixelCircularDisplay(uint8_t pin, uint8_t type=NEO_GRB+NEO_KHZ800);
void init(); //initialize circular display
void show(); //show current colors on display
void reset();
void setBrightness(uint8_t b);
void setColor(color_type color, bool blend = false);
void setColor(uint16_t idx, color_type color, bool blend = false);
void setColorFp(float rad, color_type color, float sigma, bool blend = false);
static float radBetweenPixels();
private:
uint16_t radToIdx(float rad)const;
float radToFpIdx(float rad)const;
float idxToRad(uint16_t idx)const;
float idxToRad(uint16_t idx, float radRef)const;
static float gauss(float x, float m, float s);
private:
fp_color_type _color[NPXL];
bool _toUpdate[NPXL];
Adafruit_NeoPixel _ring;
public:
AbstractLog* _log;
};
/****************************************************/
template <uint16_t NPXL>
NeoPixelCircularDisplay<NPXL>::NeoPixelCircularDisplay(uint8_t pin, uint8_t type):
_log(0),
_ring(NPXL,pin,type)
{
for(int i = 0; i < NPXL; ++i){
_color[i] = 0;
_toUpdate[i] = true;
}
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::init(){
SECURE_LOG(_log,"Circular display initialization");
_ring.begin();
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::show(){
SECURE_LOG(_log,"Circular display show");
uint16_t updated(0);
for(int i = 0; i < NPXL; ++i)
if(_toUpdate[i]){
_ring.setPixelColor(NPXL-i-1, min(_color[i][0],255), min(_color[i][1],255), min(_color[i][2],255));
_toUpdate[i] = false;
++updated;
}
_ring.show();
SECURE_LOG_VAL(_log,"Updated pixels",updated);
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::reset(){
SECURE_LOG(_log,"Circular display reset");
for(int i = 0; i < NPXL; ++i){
_color[i] = color_type(0);
_toUpdate[i] = true;
}
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::setBrightness(uint8_t b){
SECURE_LOG_VAL(_log,"Circular display brightness",b);
_ring.setBrightness(b);
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::setColor(color_type color, bool blend){
SECURE_LOG(_log,"Set color for a circular display");
if(_log!=0){
LOG::displayVect3d(color,_log); _log->endline();
}
for(int i = 0; i < NPXL; ++i){
if(blend)
_color[i] += color;
else
_color[i] = color;
_toUpdate[i] = true;
}
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::setColor(uint16_t idx, color_type color, bool blend){
SECURE_LOG_VAL(_log,"Set color for a circular display - idx",idx);
if(_log!=0){
LOG::displayVect3d(color,_log); _log->endline();
}
if(blend)
_color[idx] += color;
else
_color[idx] = color;
_toUpdate[idx] = true;
}
template <uint16_t NPXL>
void NeoPixelCircularDisplay<NPXL>::setColorFp(float rad, color_type color, float sigma, bool blend){
//TODO - Optimization
SECURE_LOG_VAL(_log,"Set color for a circular display - rad",rad);
const uint16_t nearestPxlIdx(radToIdx(rad));
SECURE_LOG_VAL(_log,"Nearest pixel idx",nearestPxlIdx);
const float nearestPxlRad(idxToRad(nearestPxlIdx));
SECURE_LOG_VAL(_log,"Nearest pixel rad",nearestPxlRad);
for(int i = 0; i < NPXL; ++i){
const float w(gauss(idxToRad(i,rad),rad,sigma));
SECURE_LOG_VAL(_log,"W",w);
if(blend)
_color[i] += color*w;
else
_color[i] = color*w;
_toUpdate[i] = true;
}
}
template <uint16_t NPXL>
uint16_t NeoPixelCircularDisplay<NPXL>::radToIdx(float rad)const{
return static_cast<uint16_t>(rad/radBetweenPixels()+0.5)%NPXL;
}
template <uint16_t NPXL>
float NeoPixelCircularDisplay<NPXL>::radToFpIdx(float rad)const{
return rad/radBetweenPixels();
}
template <uint16_t NPXL>
float NeoPixelCircularDisplay<NPXL>::radBetweenPixels(){
return 2*PI/NPXL;
}
template <uint16_t NPXL>
float NeoPixelCircularDisplay<NPXL>::gauss(float x, float m, float s){
return exp(-(x-m)*(x-m)/(2*s*s));
}
template <uint16_t NPXL>
float NeoPixelCircularDisplay<NPXL>::idxToRad(uint16_t idx)const{
return idx*radBetweenPixels();
}
template <uint16_t NPXL>
float NeoPixelCircularDisplay<NPXL>::idxToRad(uint16_t idx, float radRef)const{
// return idx*radBetweenPixels();
float rad = idx*radBetweenPixels();
if(rad-radRef>PI)return rad-2*PI;
if(rad-radRef<-PI)return rad+2*PI;
return rad;
}
}
#endif