FastLED 3.9.7
Loading...
Searching...
No Matches
screenmap.cpp
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_macros.h"
12#include "fl/screenmap.h"
13#include "fl/str.h"
14#include "fl/vector.h"
15#include "fl/warn.h"
16#include "fl/namespace.h"
17#include <math.h>
18
19namespace fl {
20
21ScreenMap ScreenMap::Circle(int numLeds, float cm_between_leds,
22 float cm_led_diameter) {
23 ScreenMap screenMap = ScreenMap(numLeds);
24 float circumference = numLeds * cm_between_leds;
25 float radius = circumference / (2 * PI);
26
27 for (int i = 0; i < numLeds; i++) {
28 float angle = i * 2 * PI / numLeds;
29 float x = radius * cos(angle) * 2;
30 float y = radius * sin(angle) * 2;
31 screenMap[i] = {x, y};
32 }
33 screenMap.setDiameter(cm_led_diameter);
34 return screenMap;
35}
36
37bool ScreenMap::ParseJson(const char *jsonStrScreenMap,
38 FixedMap<Str, ScreenMap, 16> *segmentMaps, Str *err) {
39#if !FASTLED_ENABLE_JSON
40 if (err) {
41 *err = "JSON not enabled";
42 }
43 return false;
44#else
45 JsonDocument doc;
46 Str _err;
47 if (!err) {
48 err = &_err;
49 }
50
51 bool ok = parseJson(jsonStrScreenMap, &doc, err);
52 if (!ok) {
53 FASTLED_WARN("Failed to parse json: " << err->c_str());
54 return false;
55 }
56 auto map = doc["map"];
57 for (auto kv : map.as<FLArduinoJson::JsonObject>()) {
58 auto segment = kv.value();
59 auto x = segment["x"];
60 auto y = segment["y"];
61 auto obj = segment["diameter"];
62 float diameter = -1.0f;
63 if (obj.is<float>()) {
64 float d = obj.as<float>();
65 if (d > 0.0f) {
66 diameter = d;
67 }
68 }
69 auto n = x.size();
70 ScreenMap segment_map(n, diameter);
71 for (uint16_t j = 0; j < n; j++) {
72 segment_map.set(j, pair_xy_float{x[j], y[j]});
73 }
74 segmentMaps->insert(kv.key().c_str(), segment_map);
75 }
76 return true;
77#endif
78}
79
80bool ScreenMap::ParseJson(const char *jsonStrScreenMap,
81 const char *screenMapName, ScreenMap *screenmap,
82 Str *err) {
83#if !FASTLED_ENABLE_JSON
84 if (err) {
85 *err = "JSON not enabled";
86 }
87 return false;
88#else
89 FixedMap<Str, ScreenMap, 16> segmentMaps;
90 bool ok = ParseJson(jsonStrScreenMap, &segmentMaps, err);
91 if (!ok) {
92 return false;
93 }
94 if (segmentMaps.size() == 0) {
95 return false;
96 }
97 if (segmentMaps.has(screenMapName)) {
98 *screenmap = segmentMaps[screenMapName];
99 return true;
100 }
101 Str _err = "ScreenMap not found: ";
102 _err.append(screenMapName);
103 if (err) {
104 *err = _err;
105 }
106 FASTLED_WARN(_err.c_str());
107 return false;
108#endif
109}
110
111void ScreenMap::toJson(const FixedMap<Str, ScreenMap, 16> &segmentMaps,
112 JsonDocument *_doc) {
113
114#if !FASTLED_ENABLE_JSON
115 return;
116#else
117 auto &doc = *_doc;
118 auto map = doc["map"].to<FLArduinoJson::JsonObject>();
119 for (auto kv : segmentMaps) {
120 auto segment = map[kv.first].to<FLArduinoJson::JsonObject>();
121 auto x_array = segment["x"].to<FLArduinoJson::JsonArray>();
122 auto y_array = segment["y"].to<FLArduinoJson::JsonArray>();
123 for (uint16_t i = 0; i < kv.second.getLength(); i++) {
124 const pair_xy_float &xy = kv.second[i];
125 x_array.add(xy.x);
126 y_array.add(xy.y);
127 }
128 float diameter = kv.second.getDiameter();
129 if (diameter < 0.0f) {
130 diameter = .5f; // 5mm.
131 }
132 if (diameter > 0.0f) {
133 segment["diameter"] = diameter;
134 }
135 }
136#endif
137}
138
139void ScreenMap::toJsonStr(const FixedMap<Str, ScreenMap, 16> &segmentMaps,
140 Str *jsonBuffer) {
141#if !FASTLED_ENABLE_JSON
142 return;
143#else
144 JsonDocument doc;
145 toJson(segmentMaps, &doc);
146 fl::toJson(doc, jsonBuffer);
147#endif
148}
149
150ScreenMap::ScreenMap(uint32_t length, float mDiameter)
151 : length(length), mDiameter(mDiameter) {
152 mLookUpTable = LUTXYFLOATPtr::New(length);
153 LUTXYFLOAT &lut = *mLookUpTable.get();
154 pair_xy_float *data = lut.getData();
155 for (uint32_t x = 0; x < length; x++) {
156 data[x] = {0, 0};
157 }
158}
159
160ScreenMap::ScreenMap(const pair_xy_float *lut, uint32_t length, float diameter)
161 : length(length), mDiameter(diameter) {
162 mLookUpTable = LUTXYFLOATPtr::New(length);
163 LUTXYFLOAT &lut16xy = *mLookUpTable.get();
164 pair_xy_float *data = lut16xy.getData();
165 for (uint32_t x = 0; x < length; x++) {
166 data[x] = lut[x];
167 }
168}
169
170ScreenMap::ScreenMap(const ScreenMap &other) {
171 mDiameter = other.mDiameter;
172 length = other.length;
173 mLookUpTable = other.mLookUpTable;
174}
175
176void ScreenMap::set(uint16_t index, const pair_xy_float &p) {
177 if (mLookUpTable) {
178 LUTXYFLOAT &lut = *mLookUpTable.get();
179 auto *data = lut.getData();
180 data[index] = p;
181 }
182}
183
184void ScreenMap::setDiameter(float diameter) { mDiameter = diameter; }
185
186pair_xy_float ScreenMap::mapToIndex(uint32_t x) const {
187 if (x >= length || !mLookUpTable) {
188 return {0, 0};
189 }
190 LUTXYFLOAT &lut = *mLookUpTable.get();
191 pair_xy_float screen_coords = lut[x];
192 return screen_coords;
193}
194
195uint32_t ScreenMap::getLength() const { return length; }
196
197float ScreenMap::getDiameter() const { return mDiameter; }
198
199const pair_xy_float &ScreenMap::empty() {
200 static const pair_xy_float s_empty = pair_xy_float(0, 0);
201 return s_empty;
202}
203
204const pair_xy_float &ScreenMap::operator[](uint32_t x) const {
205 if (x >= length || !mLookUpTable) {
206 return empty(); // better than crashing.
207 }
208 LUTXYFLOAT &lut = *mLookUpTable.get();
209 return lut[x];
210}
211
212pair_xy_float &ScreenMap::operator[](uint32_t x) {
213 if (x >= length || !mLookUpTable) {
214 return const_cast<pair_xy_float &>(empty()); // better than crashing.
215 }
216 LUTXYFLOAT &lut = *mLookUpTable.get();
217 auto *data = lut.getData();
218 return data[x];
219}
220
221ScreenMap &ScreenMap::operator=(const ScreenMap &other) {
222 if (this != &other) {
223 mDiameter = other.mDiameter;
224 length = other.length;
225 mLookUpTable = other.mLookUpTable;
226 }
227 return *this;
228}
229
230} // namespace fl
Implements the FastLED namespace macros.
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16