FastLED 3.9.15
Loading...
Searching...
No Matches
screenmap.cpp
Go to the documentation of this file.
1/* Screenmap maps strip indexes to x,y coordinates. This is used for FastLED Web
2 * to map the 1D strip to a 2D grid. Note that the strip can have arbitrary
3 * size. this was first motivated during the (attempted? Oct. 19th 2024) port of
4 * the Chromancer project to FastLED Web.
5 */
6
7#include "fl/screenmap.h"
8
9#include "fl/json.h"
10#include "fl/map.h"
11#include "fl/math.h"
12#include "fl/math_macros.h"
13#include "fl/namespace.h"
14#include "fl/screenmap.h"
15#include "fl/str.h"
16#include "fl/vector.h"
17#include "fl/warn.h"
18
19namespace fl {
20
21ScreenMap ScreenMap::Circle(int numLeds, float cm_between_leds,
22 float cm_led_diameter, float completion) {
23 ScreenMap screenMap(numLeds);
24
25 // radius from LED spacing
26 float circumference = numLeds * cm_between_leds;
27 float radius = circumference / (2 * PI);
28
29 // how big an arc we light vs leave dark
30 float totalAngle = completion * 2 * PI;
31 float gapAngle = 2 * PI - totalAngle;
32
33 // shift so the dark gap is centered at the bottom (–π/2)
34 float startAngle = -PI / 2 + gapAngle / 2.0f;
35
36 // if partial, land last LED exactly at startAngle+totalAngle
37 float divisor =
38 (completion < 1.0f && numLeds > 1) ? (numLeds - 1) : numLeds;
39
40 for (int i = 0; i < numLeds; ++i) {
41 float angle = startAngle + (i * totalAngle) / divisor;
42 float x = radius * cos(angle) * 2;
43 float y = radius * sin(angle) * 2;
44 screenMap[i] = {x, y};
45 }
46
47 screenMap.setDiameter(cm_led_diameter);
48 return screenMap;
49}
50
51bool ScreenMap::ParseJson(const char *jsonStrScreenMap,
52 FixedMap<Str, ScreenMap, 16> *segmentMaps, Str *err) {
53#if !FASTLED_ENABLE_JSON
54 if (err) {
55 *err = "JSON not enabled";
56 }
57 return false;
58#else
59 JsonDocument doc;
60 Str _err;
61 if (!err) {
62 err = &_err;
63 }
64
65 bool ok = parseJson(jsonStrScreenMap, &doc, err);
66 if (!ok) {
67 FASTLED_WARN("Failed to parse json: " << err->c_str());
68 return false;
69 }
70 auto map = doc["map"];
71 for (auto kv : map.as<FLArduinoJson::JsonObject>()) {
72 auto segment = kv.value();
73 auto x = segment["x"];
74 auto y = segment["y"];
75 auto obj = segment["diameter"];
76 float diameter = -1.0f;
77 if (obj.is<float>()) {
78 float d = obj.as<float>();
79 if (d > 0.0f) {
80 diameter = d;
81 }
82 }
83 auto n = x.size();
84 ScreenMap segment_map(n, diameter);
85 for (uint16_t j = 0; j < n; j++) {
86 segment_map.set(j, vec2f{x[j], y[j]});
87 }
88 segmentMaps->insert(kv.key().c_str(), segment_map);
89 }
90 return true;
91#endif
92}
93
94bool ScreenMap::ParseJson(const char *jsonStrScreenMap,
95 const char *screenMapName, ScreenMap *screenmap,
96 Str *err) {
97#if !FASTLED_ENABLE_JSON
98 if (err) {
99 *err = "JSON not enabled";
100 }
101 return false;
102#else
104 bool ok = ParseJson(jsonStrScreenMap, &segmentMaps, err);
105 if (!ok) {
106 return false;
107 }
108 if (segmentMaps.size() == 0) {
109 return false;
110 }
111 if (segmentMaps.has(screenMapName)) {
112 *screenmap = segmentMaps[screenMapName];
113 return true;
114 }
115 Str _err = "ScreenMap not found: ";
116 _err.append(screenMapName);
117 if (err) {
118 *err = _err;
119 }
120 FASTLED_WARN(_err.c_str());
121 return false;
122#endif
123}
124
126 JsonDocument *_doc) {
127
128#if !FASTLED_ENABLE_JSON
129 return;
130#else
131 auto &doc = *_doc;
132 auto map = doc["map"].to<FLArduinoJson::JsonObject>();
133 for (auto kv : segmentMaps) {
134 auto segment = map[kv.first].to<FLArduinoJson::JsonObject>();
135 auto x_array = segment["x"].to<FLArduinoJson::JsonArray>();
136 auto y_array = segment["y"].to<FLArduinoJson::JsonArray>();
137 for (uint16_t i = 0; i < kv.second.getLength(); i++) {
138 const vec2f &xy = kv.second[i];
139 x_array.add(xy.x);
140 y_array.add(xy.y);
141 }
142 float diameter = kv.second.getDiameter();
143 if (diameter < 0.0f) {
144 diameter = .5f; // 5mm.
145 }
146 if (diameter > 0.0f) {
147 segment["diameter"] = diameter;
148 }
149 }
150#endif
151}
152
154 Str *jsonBuffer) {
155#if !FASTLED_ENABLE_JSON
156 return;
157#else
158 JsonDocument doc;
159 toJson(segmentMaps, &doc);
160 fl::toJson(doc, jsonBuffer);
161#endif
162}
163
166 mLookUpTable = LUTXYFLOATPtr::New(length);
167 LUTXYFLOAT &lut = *mLookUpTable.get();
168 vec2f *data = lut.getDataMutable();
169 for (uint32_t x = 0; x < length; x++) {
170 data[x] = {0, 0};
171 }
172}
173
174ScreenMap::ScreenMap(const vec2f *lut, uint32_t length, float diameter)
175 : length(length), mDiameter(diameter) {
176 mLookUpTable = LUTXYFLOATPtr::New(length);
177 LUTXYFLOAT &lut16xy = *mLookUpTable.get();
178 vec2f *data = lut16xy.getDataMutable();
179 for (uint32_t x = 0; x < length; x++) {
180 data[x] = lut[x];
181 }
182}
183
185 mDiameter = other.mDiameter;
186 length = other.length;
188}
189
190void ScreenMap::set(uint16_t index, const vec2f &p) {
191 if (mLookUpTable) {
192 LUTXYFLOAT &lut = *mLookUpTable.get();
193 auto *data = lut.getDataMutable();
194 data[index] = p;
195 }
196}
197
198void ScreenMap::setDiameter(float diameter) { mDiameter = diameter; }
199
201 if (x >= length || !mLookUpTable) {
202 return {0, 0};
203 }
204 LUTXYFLOAT &lut = *mLookUpTable.get();
205 vec2f screen_coords = lut[x];
206 return screen_coords;
207}
208
209uint32_t ScreenMap::getLength() const { return length; }
210
211float ScreenMap::getDiameter() const { return mDiameter; }
212
214
215 if (length == 0 || !mLookUpTable) {
216 return {0, 0};
217 }
218
219 LUTXYFLOAT &lut = *mLookUpTable.get();
220
221 fl::vec2f* data = lut.getDataMutable();
222 // float minX = lut[0].x;
223 // float maxX = lut[0].x;
224 // float minY = lut[0].y;
225 // float maxY = lut[0].y;
226 float minX = data[0].x;
227 float maxX = data[0].x;
228 float minY = data[0].y;
229 float maxY = data[0].y;
230
231 for (uint32_t i = 1; i < length; i++) {
232 const vec2f &p = lut[i];
233 minX = MIN(minX, p.x);
234 maxX = MAX(maxX, p.x);
235 minY = MIN(minY, p.y);
236 maxY = MAX(maxY, p.y);
237 }
238
239 return {maxX - minX, maxY - minY};
240}
241
243 static const vec2f s_empty = vec2f(0, 0);
244 return s_empty;
245}
246
247const vec2f &ScreenMap::operator[](uint32_t x) const {
248 if (x >= length || !mLookUpTable) {
249 return empty(); // better than crashing.
250 }
251 LUTXYFLOAT &lut = *mLookUpTable.get();
252 return lut[x];
253}
254
256 if (x >= length || !mLookUpTable) {
257 return const_cast<vec2f &>(empty()); // better than crashing.
258 }
259 LUTXYFLOAT &lut = *mLookUpTable.get();
260 auto *data = lut.getDataMutable();
261 return data[x];
262}
263
265 if (this != &other) {
266 mDiameter = other.mDiameter;
267 length = other.length;
269 }
270 return *this;
271}
272
274 vec2f *data = mLookUpTable->getDataMutable();
275 for (uint32_t i = 0; i < length; i++) {
276 vec2f &curr = data[i];
277 curr.x += p.x;
278 curr.y += p.y;
279 }
280}
281
282void ScreenMap::addOffsetX(float x) { addOffset({x, 0}); }
283void ScreenMap::addOffsetY(float y) { addOffset({0, y}); }
284
285} // namespace fl
int y
Definition Audio.ino:72
int x
Definition Audio.ino:71
fl::ScreenMap screenMap
unsigned int xy(unsigned int x, unsigned int y)
Pair< bool, iterator > insert(const Key &key, const Value &value, InsertResult *result=nullptr)
Definition map.h:125
bool has(const Key &it) const
Definition map.h:223
constexpr size_t size() const
Definition map.h:213
T * getDataMutable()
Definition lut.h:52
static void toJsonStr(const FixedMap< Str, ScreenMap, 16 > &, Str *jsonBuffer)
ScreenMap & operator=(const ScreenMap &other)
void setDiameter(float diameter)
float mDiameter
Definition screenmap.h:93
void addOffsetY(float y)
void set(uint16_t index, const vec2f &p)
vec2f mapToIndex(uint32_t x) const
static ScreenMap Circle(int numLeds, float cm_between_leds=1.5f, float cm_led_diameter=0.5f, float completion=1.0f)
Definition screenmap.cpp:21
uint32_t getLength() const
void addOffsetX(float x)
static void toJson(const FixedMap< Str, ScreenMap, 16 > &, JsonDocument *doc)
void addOffset(const vec2f &p)
uint32_t length
Definition screenmap.h:92
ScreenMap()=default
static const vec2f & empty()
LUTXYFLOATPtr mLookUpTable
Definition screenmap.h:94
const vec2f & operator[](uint32_t x) const
static bool ParseJson(const char *jsonStrScreenMap, FixedMap< Str, ScreenMap, 16 > *segmentMaps, Str *err=nullptr)
Definition screenmap.cpp:51
vec2f getBounds() const
float getDiameter() const
Str & append(const T &val)
Definition str.h:439
Definition str.h:388
const char * c_str() const
Definition str.h:272
#define MIN(a, b)
Definition math_macros.h:15
#define PI
Definition math_macros.h:57
#define MAX(a, b)
Definition math_macros.h:11
Implements the FastLED namespace macros.
bool parseJson(const char *json, fl::JsonDocument *doc, Str *_error)
Definition json.cpp:6
LUT< vec2f > LUTXYFLOAT
Definition lut.h:25
vec2< float > vec2f
Definition geometry.h:301
void toJson(const fl::JsonDocument &doc, Str *jsonBuffer)
Definition json.cpp:24
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
static FASTLED_NAMESPACE_BEGIN uint8_t const p[]
Definition noise.cpp:30
#define FASTLED_WARN
Definition warn.h:7