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 if (!_doc) {
132 FASTLED_WARN("ScreenMap::toJson called with nullptr _doc");
133 return;
134 }
135 auto &doc = *_doc;
136 auto map = doc["map"].to<FLArduinoJson::JsonObject>();
137 if (!segmentMaps.empty()) {
138 for (auto kv : segmentMaps) {
139 auto segment = map[kv.first].to<FLArduinoJson::JsonObject>();
140 auto x_array = segment["x"].to<FLArduinoJson::JsonArray>();
141 auto y_array = segment["y"].to<FLArduinoJson::JsonArray>();
142 for (uint16_t i = 0; i < kv.second.getLength(); i++) {
143 const vec2f &xy = kv.second[i];
144 x_array.add(xy.x);
145 y_array.add(xy.y);
146 }
147 float diameter = kv.second.getDiameter();
148 if (diameter < 0.0f) {
149 diameter = .5f; // 5mm.
150 }
151 if (diameter > 0.0f) {
152 segment["diameter"] = diameter;
153 }
154 }
155 }
156
157#endif
158}
159
161 Str *jsonBuffer) {
162#if !FASTLED_ENABLE_JSON
163 return;
164#else
165 JsonDocument doc;
166 toJson(segmentMaps, &doc);
167 fl::toJson(doc, jsonBuffer);
168#endif
169}
170
173 mLookUpTable = LUTXYFLOATPtr::New(length);
174 LUTXYFLOAT &lut = *mLookUpTable.get();
175 vec2f *data = lut.getDataMutable();
176 for (uint32_t x = 0; x < length; x++) {
177 data[x] = {0, 0};
178 }
179}
180
181ScreenMap::ScreenMap(const vec2f *lut, uint32_t length, float diameter)
182 : length(length), mDiameter(diameter) {
183 mLookUpTable = LUTXYFLOATPtr::New(length);
184 LUTXYFLOAT &lut16xy = *mLookUpTable.get();
185 vec2f *data = lut16xy.getDataMutable();
186 for (uint32_t x = 0; x < length; x++) {
187 data[x] = lut[x];
188 }
189}
190
192 mDiameter = other.mDiameter;
193 length = other.length;
195}
196
197void ScreenMap::set(uint16_t index, const vec2f &p) {
198 if (mLookUpTable) {
199 LUTXYFLOAT &lut = *mLookUpTable.get();
200 auto *data = lut.getDataMutable();
201 data[index] = p;
202 }
203}
204
205void ScreenMap::setDiameter(float diameter) { mDiameter = diameter; }
206
208 if (x >= length || !mLookUpTable) {
209 return {0, 0};
210 }
211 LUTXYFLOAT &lut = *mLookUpTable.get();
212 vec2f screen_coords = lut[x];
213 return screen_coords;
214}
215
216uint32_t ScreenMap::getLength() const { return length; }
217
218float ScreenMap::getDiameter() const { return mDiameter; }
219
221
222 if (length == 0 || !mLookUpTable) {
223 return {0, 0};
224 }
225
226 LUTXYFLOAT &lut = *mLookUpTable.get();
227
228 fl::vec2f *data = lut.getDataMutable();
229 // float minX = lut[0].x;
230 // float maxX = lut[0].x;
231 // float minY = lut[0].y;
232 // float maxY = lut[0].y;
233 float minX = data[0].x;
234 float maxX = data[0].x;
235 float minY = data[0].y;
236 float maxY = data[0].y;
237
238 for (uint32_t i = 1; i < length; i++) {
239 const vec2f &p = lut[i];
240 minX = MIN(minX, p.x);
241 maxX = MAX(maxX, p.x);
242 minY = MIN(minY, p.y);
243 maxY = MAX(maxY, p.y);
244 }
245
246 return {maxX - minX, maxY - minY};
247}
248
250 static const vec2f s_empty = vec2f(0, 0);
251 return s_empty;
252}
253
254const vec2f &ScreenMap::operator[](uint32_t x) const {
255 if (x >= length || !mLookUpTable) {
256 return empty(); // better than crashing.
257 }
258 LUTXYFLOAT &lut = *mLookUpTable.get();
259 return lut[x];
260}
261
263 if (x >= length || !mLookUpTable) {
264 return const_cast<vec2f &>(empty()); // better than crashing.
265 }
266 LUTXYFLOAT &lut = *mLookUpTable.get();
267 auto *data = lut.getDataMutable();
268 return data[x];
269}
270
272 if (this != &other) {
273 mDiameter = other.mDiameter;
274 length = other.length;
276 }
277 return *this;
278}
279
281 vec2f *data = mLookUpTable->getDataMutable();
282 for (uint32_t i = 0; i < length; i++) {
283 vec2f &curr = data[i];
284 curr.x += p.x;
285 curr.y += p.y;
286 }
287}
288
289void ScreenMap::addOffsetX(float x) { addOffset({x, 0}); }
290void ScreenMap::addOffsetY(float y) { addOffset({0, y}); }
291
292} // namespace fl
uint32_t x[NUM_LAYERS]
Definition Fire2023.ino:82
uint32_t y[NUM_LAYERS]
Definition Fire2023.ino:83
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
constexpr bool empty() const
Definition map.h:215
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:440
Definition str.h:389
const char * c_str() const
Definition str.h:273
fl::ScreenMap screenMap
Definition Corkscrew.h:70
#define MIN(a, b)
Definition math_macros.h:15
#define PI
Definition math_macros.h:63
#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:318
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