187 {
188
189#if FASTLED_NO_JSON
193 FL_WARN(
"ScreenMap::ParseJson called with FASTLED_NO_JSON");
194 if (err) {
195 *err = "JSON is not supported in this build";
196 }
197 return false;
198#else
199
200
201 string _err;
202 if (!err) {
203 err = &_err;
204 }
205
207 if (!jsonDoc.has_value()) {
208 *err = "Failed to parse JSON";
209 FL_WARN(
"Failed to parse JSON");
210 return false;
211 }
212
213 if (!jsonDoc.is_object()) {
214 *err = "JSON root is not an object";
215 FL_WARN(
"JSON root is not an object");
216 return false;
217 }
218
219
220
221
222 bool explicitV2 = false;
223 bool explicitV1 = false;
224 if (jsonDoc.contains("version") && jsonDoc["version"].has_value()) {
225 auto versionOpt = jsonDoc["version"].as_int();
226 if (versionOpt) {
227 int v = static_cast<int>(*versionOpt);
228 if (v == 2) explicitV2 = true;
229 else if (v == 1) explicitV1 = true;
230 }
231 }
232 bool hasSegments = jsonDoc.contains("segments") && jsonDoc["segments"].has_value()
233 && jsonDoc["segments"].is_array();
234 bool hasMap = jsonDoc.contains("map") && jsonDoc["map"].has_value()
235 && jsonDoc["map"].is_object();
236
237 if (explicitV2 || (!explicitV1 && hasSegments && !hasMap)) {
239 }
240
241
242
243 if (!jsonDoc.contains("map")) {
244 *err = "Missing 'map' key in JSON";
245 FL_WARN(
"Missing 'map' key in JSON");
246 return false;
247 }
248
249
250 auto mapObj = jsonDoc["map"];
251 if (!mapObj.has_value() || !mapObj.is_object()) {
252 *err = "Invalid 'map' object in JSON";
253 FL_WARN(
"Invalid 'map' object in JSON");
254 return false;
255 }
256
257 auto jsonMapPtr = mapObj.as_object();
258 if (!jsonMapPtr || jsonMapPtr->empty()) {
259 *err = "Failed to parse map from JSON or map is empty";
260 FL_WARN(
"Failed to parse map from JSON or map is empty");
261 return false;
262 }
263
264 auto& jsonMap = *jsonMapPtr;
265
266
267 for (const auto& kv : jsonMap) {
268 auto name = kv.first;
269
270
271
272 if (!kv.second) {
273 *err = "Null value for segment " + name;
274 return false;
275 }
276
277
278 fl::json val(kv.second);
279 if (!val.has_value()) {
280 *err = "Invalid value for segment " + name;
281 return false;
282 }
283
284 if (!val.is_object()) {
285 *err = "Segment value for " + name + " is not an object";
286 return false;
287 }
288
289
290 if (!val.contains("x")) {
291 *err = "Missing x array for " + name;
292 return false;
293 }
294
295 if (!val["x"].has_value() || !val["x"].is_array()) {
296 *err = "Invalid x array for " + name;
297 return false;
298 }
299
300
302
303
304 if (!val.contains("y")) {
305 *err = "Missing y array for " + name;
306 return false;
307 }
308
309 if (!val["y"].has_value() || !val["y"].is_array()) {
310 *err = "Invalid y array for " + name;
311 return false;
312 }
313
314
316
317
318 float diameter = -1.0f;
319 if (val.contains("diameter") && val["diameter"].has_value()) {
320 auto diameterOpt = val["diameter"].as_float();
321 if (diameterOpt) {
322 diameter = static_cast<float>(*diameterOpt);
323 }
324 }
325
327 if (n != x_array.
size() || n != y_array.
size()) {
328 if (n != x_array.
size()) {
329 }
330 if (n != y_array.
size()) {
331 }
332 }
333
335 for (size_t i = 0; i < n; i++) {
336 segment_map.set(i,
vec2f{x_array[i], y_array[i]});
337 }
338 (*segmentMaps)[name] =
fl::move(segment_map);
339 }
340 return true;
341#endif
342}
static json parse(const fl::string &txt) FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
fl::vector< float > jsonArrayToFloatVector(const fl::json &jsonArray)
static bool parseV2SegmentArray(const fl::json &segmentsArr, fl::flat_map< string, ScreenMap > *segmentMaps, string *err) FL_NOEXCEPT